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