]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/pci/of.c
Merge branch 'remotes/lorenzo/pci/uniphier'
[linux.git] / drivers / pci / of.c
index 36891e7deee34da58c79083d99b75ed5113d236c..81ceeaa6f1d5a2c5a66e6f1b3c4d67e8a0bfb16b 100644 (file)
@@ -236,7 +236,6 @@ void of_pci_check_probe_only(void)
 }
 EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
 
-#if defined(CONFIG_OF_ADDRESS)
 /**
  * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI
  *                                           host bridge resources from DT
@@ -255,16 +254,18 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
  * It returns zero if the range parsing has been successful or a standard error
  * value if it failed.
  */
-int devm_of_pci_get_host_bridge_resources(struct device *dev,
+static int devm_of_pci_get_host_bridge_resources(struct device *dev,
                        unsigned char busno, unsigned char bus_max,
-                       struct list_head *resources, resource_size_t *io_base)
+                       struct list_head *resources,
+                       struct list_head *ib_resources,
+                       resource_size_t *io_base)
 {
        struct device_node *dev_node = dev->of_node;
        struct resource *res, tmp_res;
        struct resource *bus_range;
        struct of_pci_range range;
        struct of_pci_range_parser parser;
-       char range_type[4];
+       const char *range_type;
        int err;
 
        if (io_base)
@@ -298,12 +299,12 @@ int devm_of_pci_get_host_bridge_resources(struct device *dev,
        for_each_of_pci_range(&parser, &range) {
                /* Read next ranges element */
                if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
-                       snprintf(range_type, 4, " IO");
+                       range_type = "IO";
                else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
-                       snprintf(range_type, 4, "MEM");
+                       range_type = "MEM";
                else
-                       snprintf(range_type, 4, "err");
-               dev_info(dev, "  %s %#010llx..%#010llx -> %#010llx\n",
+                       range_type = "err";
+               dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx\n",
                         range_type, range.cpu_addr,
                         range.cpu_addr + range.size - 1, range.pci_addr);
 
@@ -340,14 +341,54 @@ int devm_of_pci_get_host_bridge_resources(struct device *dev,
                pci_add_resource_offset(resources, res, res->start - range.pci_addr);
        }
 
+       /* Check for dma-ranges property */
+       if (!ib_resources)
+               return 0;
+       err = of_pci_dma_range_parser_init(&parser, dev_node);
+       if (err)
+               return 0;
+
+       dev_dbg(dev, "Parsing dma-ranges property...\n");
+       for_each_of_pci_range(&parser, &range) {
+               struct resource_entry *entry;
+               /*
+                * If we failed translation or got a zero-sized region
+                * then skip this range
+                */
+               if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) ||
+                   range.cpu_addr == OF_BAD_ADDR || range.size == 0)
+                       continue;
+
+               dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx\n",
+                        "IB MEM", range.cpu_addr,
+                        range.cpu_addr + range.size - 1, range.pci_addr);
+
+
+               err = of_pci_range_to_resource(&range, dev_node, &tmp_res);
+               if (err)
+                       continue;
+
+               res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL);
+               if (!res) {
+                       err = -ENOMEM;
+                       goto failed;
+               }
+
+               /* Keep the resource list sorted */
+               resource_list_for_each_entry(entry, ib_resources)
+                       if (entry->res->start > res->start)
+                               break;
+
+               pci_add_resource_offset(&entry->node, res,
+                                       res->start - range.pci_addr);
+       }
+
        return 0;
 
 failed:
        pci_free_resource_list(resources);
        return err;
 }
-EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources);
-#endif /* CONFIG_OF_ADDRESS */
 
 #if IS_ENABLED(CONFIG_OF_IRQ)
 /**
@@ -482,6 +523,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci);
 
 int pci_parse_request_of_pci_ranges(struct device *dev,
                                    struct list_head *resources,
+                                   struct list_head *ib_resources,
                                    struct resource **bus_range)
 {
        int err, res_valid = 0;
@@ -489,8 +531,10 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
        struct resource_entry *win, *tmp;
 
        INIT_LIST_HEAD(resources);
+       if (ib_resources)
+               INIT_LIST_HEAD(ib_resources);
        err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
-                                                   &iobase);
+                                                   ib_resources, &iobase);
        if (err)
                return err;
 
@@ -530,6 +574,7 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
        pci_free_resource_list(resources);
        return err;
 }
+EXPORT_SYMBOL_GPL(pci_parse_request_of_pci_ranges);
 
 #endif /* CONFIG_PCI */