mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
of/pci changes for v3.11
- parse DT ranges property - add of_pci_get_devfn() - add of_pci_parse_bus_range() Note: - mvebu/pcie will depend on this branch - work by LinusW and possibly Arnd will depend on this branch -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQEcBAABAgAGBQJRmoSvAAoJEAi3KVZQDZAenyUH/Az/DhvlEJ5iYBqTvdOFZn7i boPfjU8qX5vqkbCPc4SIEO1j2WmnpOXN7M+CWQuaBflg2VYcRBLnuFq1YF7JlJSR AtCHFd3J40h7dqrV4A3u1oMZCtDNF/0t7wGwxllpw3GxOlE2aVSok2Pp8p21BVTl HisCNHGOrD6f5/DoCS9Use46DX48pQkSkq7uaAk2XW6gK7Y+34nLJrNYU4eTFtWf fvAblN1w2TkPX0zFEFvhEU0ezIO7hfSeqYIIZJiu/wNrOhv80o3TO448t5g5J/iV dRk+bXJ1B3omB2oWiCTSLhuLsiOM42nQ+BiRtGkyitoeSOMcNj4gAxdAFSMGfsk= =OwxD -----END PGP SIGNATURE----- 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: Olof 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
This commit is contained in:
commit
4abbb75b6d
4 changed files with 171 additions and 5 deletions
|
@ -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);
|
||||
}
|
||||
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 */
|
||||
|
||||
/*
|
||||
|
|
|
@ -5,14 +5,15 @@
|
|||
#include <asm/prom.h>
|
||||
|
||||
static inline int __of_pci_pci_compare(struct device_node *node,
|
||||
unsigned int devfn)
|
||||
unsigned int data)
|
||||
{
|
||||
unsigned int size;
|
||||
const __be32 *reg = of_get_property(node, "reg", &size);
|
||||
int devfn;
|
||||
|
||||
if (!reg || size < 5 * sizeof(__be32))
|
||||
devfn = of_pci_get_devfn(node);
|
||||
if (devfn < 0)
|
||||
return 0;
|
||||
return ((be32_to_cpup(®[0]) >> 8) & 0xff) == devfn;
|
||||
|
||||
return devfn == data;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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 @@
|
|||
#include <linux/errno.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
|
||||
extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
|
||||
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; }
|
|||
#define pci_address_to_pio pci_address_to_pio
|
||||
#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 */
|
||||
#ifndef of_address_to_resource
|
||||
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,
|
|||
{
|
||||
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 */
|
||||
|
||||
|
||||
|
|
|
@ -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 *of_pci_find_child_device(struct device_node *parent,
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue