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:
Olof Johansson 2013-05-31 22:56:35 -07:00
commit 4abbb75b6d
4 changed files with 171 additions and 5 deletions

View File

@ -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 */
/*

View File

@ -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(&reg[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);

View File

@ -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 */

View File

@ -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