Commit 4abbb75b authored by Olof Johansson's avatar Olof Johansson

Merge tag 'of_pci-3.11' of git://git.infradead.org/users/jcooper/linux into next/cleanup

From Jason Cooper, of/pci changes for v3.11.

The patches had Reviewed-by: from Rob Herring on the lists, but seems to
have been missed from the commit messages. These will be required as a base
for some of the other functionality in this merge window, so taking it through
arm-soc.
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>

* tag 'of_pci-3.11' of git://git.infradead.org/users/jcooper/linux:
  of/pci: Add of_pci_parse_bus_range() function
  of/pci: Add of_pci_get_devfn() function
  of/pci: Provide support for parsing PCI DT ranges property
parents b54338b3 4e23d3f5
...@@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, ...@@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
return __of_address_to_resource(dev, addrp, size, flags, NULL, r); return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
} }
EXPORT_SYMBOL_GPL(of_pci_address_to_resource); EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
{
const int na = 3, ns = 2;
int rlen;
parser->node = node;
parser->pna = of_n_addr_cells(node);
parser->np = parser->pna + na + ns;
parser->range = of_get_property(node, "ranges", &rlen);
if (parser->range == NULL)
return -ENOENT;
parser->end = parser->range + rlen / sizeof(__be32);
return 0;
}
EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
struct of_pci_range *range)
{
const int na = 3, ns = 2;
if (!range)
return NULL;
if (!parser->range || parser->range + parser->np > parser->end)
return NULL;
range->pci_space = parser->range[0];
range->flags = of_bus_pci_get_flags(parser->range);
range->pci_addr = of_read_number(parser->range + 1, ns);
range->cpu_addr = of_translate_address(parser->node,
parser->range + na);
range->size = of_read_number(parser->range + parser->pna + na, ns);
parser->range += parser->np;
/* Now consume following elements while they are contiguous */
while (parser->range + parser->np <= parser->end) {
u32 flags, pci_space;
u64 pci_addr, cpu_addr, size;
pci_space = be32_to_cpup(parser->range);
flags = of_bus_pci_get_flags(parser->range);
pci_addr = of_read_number(parser->range + 1, ns);
cpu_addr = of_translate_address(parser->node,
parser->range + na);
size = of_read_number(parser->range + parser->pna + na, ns);
if (flags != range->flags)
break;
if (pci_addr != range->pci_addr + range->size ||
cpu_addr != range->cpu_addr + range->size)
break;
range->size += size;
parser->range += parser->np;
}
return range;
}
EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/* /*
......
...@@ -5,14 +5,15 @@ ...@@ -5,14 +5,15 @@
#include <asm/prom.h> #include <asm/prom.h>
static inline int __of_pci_pci_compare(struct device_node *node, static inline int __of_pci_pci_compare(struct device_node *node,
unsigned int devfn) unsigned int data)
{ {
unsigned int size; int devfn;
const __be32 *reg = of_get_property(node, "reg", &size);
if (!reg || size < 5 * sizeof(__be32)) devfn = of_pci_get_devfn(node);
if (devfn < 0)
return 0; return 0;
return ((be32_to_cpup(&reg[0]) >> 8) & 0xff) == devfn;
return devfn == data;
} }
struct device_node *of_pci_find_child_device(struct device_node *parent, struct device_node *of_pci_find_child_device(struct device_node *parent,
...@@ -40,3 +41,51 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, ...@@ -40,3 +41,51 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(of_pci_find_child_device); EXPORT_SYMBOL_GPL(of_pci_find_child_device);
/**
* of_pci_get_devfn() - Get device and function numbers for a device node
* @np: device node
*
* Parses a standard 5-cell PCI resource and returns an 8-bit value that can
* be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device
* and function numbers respectively. On error a negative error code is
* returned.
*/
int of_pci_get_devfn(struct device_node *np)
{
unsigned int size;
const __be32 *reg;
reg = of_get_property(np, "reg", &size);
if (!reg || size < 5 * sizeof(__be32))
return -EINVAL;
return (be32_to_cpup(reg) >> 8) & 0xff;
}
EXPORT_SYMBOL_GPL(of_pci_get_devfn);
/**
* of_pci_parse_bus_range() - parse the bus-range property of a PCI device
* @node: device node
* @res: address to a struct resource to return the bus-range
*
* Returns 0 on success or a negative error-code on failure.
*/
int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
{
const __be32 *values;
int len;
values = of_get_property(node, "bus-range", &len);
if (!values || len < sizeof(*values) * 2)
return -EINVAL;
res->name = node->name;
res->start = be32_to_cpup(values++);
res->end = be32_to_cpup(values);
res->flags = IORESOURCE_BUS;
return 0;
}
EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
...@@ -4,6 +4,36 @@ ...@@ -4,6 +4,36 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/of.h> #include <linux/of.h>
struct of_pci_range_parser {
struct device_node *node;
const __be32 *range;
const __be32 *end;
int np;
int pna;
};
struct of_pci_range {
u32 pci_space;
u64 pci_addr;
u64 cpu_addr;
u64 size;
u32 flags;
};
#define for_each_of_pci_range(parser, range) \
for (; of_pci_range_parser_one(parser, range);)
static inline void of_pci_range_to_resource(struct of_pci_range *range,
struct device_node *np,
struct resource *res)
{
res->flags = range->flags;
res->start = range->cpu_addr;
res->end = range->cpu_addr + range->size - 1;
res->parent = res->child = res->sibling = NULL;
res->name = np->full_name;
}
#ifdef CONFIG_OF_ADDRESS #ifdef CONFIG_OF_ADDRESS
extern u64 of_translate_address(struct device_node *np, const __be32 *addr); extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
extern bool of_can_translate_address(struct device_node *dev); extern bool of_can_translate_address(struct device_node *dev);
...@@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } ...@@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
#define pci_address_to_pio pci_address_to_pio #define pci_address_to_pio pci_address_to_pio
#endif #endif
extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node);
extern struct of_pci_range *of_pci_range_parser_one(
struct of_pci_range_parser *parser,
struct of_pci_range *range);
#else /* CONFIG_OF_ADDRESS */ #else /* CONFIG_OF_ADDRESS */
#ifndef of_address_to_resource #ifndef of_address_to_resource
static inline int of_address_to_resource(struct device_node *dev, int index, static inline int of_address_to_resource(struct device_node *dev, int index,
...@@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, ...@@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
{ {
return NULL; return NULL;
} }
static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
{
return -1;
}
static inline struct of_pci_range *of_pci_range_parser_one(
struct of_pci_range_parser *parser,
struct of_pci_range *range)
{
return NULL;
}
#endif /* CONFIG_OF_ADDRESS */ #endif /* CONFIG_OF_ADDRESS */
......
...@@ -10,5 +10,7 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq); ...@@ -10,5 +10,7 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq);
struct device_node; struct device_node;
struct device_node *of_pci_find_child_device(struct device_node *parent, struct device_node *of_pci_find_child_device(struct device_node *parent,
unsigned int devfn); unsigned int devfn);
int of_pci_get_devfn(struct device_node *np);
int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment