PCI: dwc: Support multiple ATU memory regions
[linux-2.6-microblaze.git] / drivers / pci / controller / dwc / pcie-designware-host.c
index 674f32d..a6ffab9 100644 (file)
@@ -464,9 +464,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
                type = PCIE_ATU_TYPE_CFG1;
 
 
-       dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
-                                 type, pp->cfg0_base,
-                                 busdev, pp->cfg0_size);
+       dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
 
        return pp->va_cfg0_base + where;
 }
@@ -480,9 +478,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
 
        ret = pci_generic_config_read(bus, devfn, where, size, val);
 
-       if (!ret && pci->num_viewport <= 2)
-               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
-                                         PCIE_ATU_TYPE_IO, pp->io_base,
+       if (!ret && pci->io_cfg_atu_shared)
+               dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
                                          pp->io_bus_addr, pp->io_size);
 
        return ret;
@@ -497,9 +494,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
 
        ret = pci_generic_config_write(bus, devfn, where, size, val);
 
-       if (!ret && pci->num_viewport <= 2)
-               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
-                                         PCIE_ATU_TYPE_IO, pp->io_base,
+       if (!ret && pci->io_cfg_atu_shared)
+               dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
                                          pp->io_bus_addr, pp->io_size);
 
        return ret;
@@ -586,17 +582,35 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
         * ATU, so we should not program the ATU here.
         */
        if (pp->bridge->child_ops == &dw_child_pcie_ops) {
-               struct resource_entry *entry =
-                       resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM);
-
-               dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
-                                         PCIE_ATU_TYPE_MEM, entry->res->start,
-                                         entry->res->start - entry->offset,
-                                         resource_size(entry->res));
-               if (pci->num_viewport > 2)
-                       dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
-                                                 PCIE_ATU_TYPE_IO, pp->io_base,
-                                                 pp->io_bus_addr, pp->io_size);
+               int atu_idx = 0;
+               struct resource_entry *entry;
+
+               /* Get last memory resource entry */
+               resource_list_for_each_entry(entry, &pp->bridge->windows) {
+                       if (resource_type(entry->res) != IORESOURCE_MEM)
+                               continue;
+
+                       if (pci->num_viewport <= ++atu_idx)
+                               break;
+
+                       dw_pcie_prog_outbound_atu(pci, atu_idx,
+                                                 PCIE_ATU_TYPE_MEM, entry->res->start,
+                                                 entry->res->start - entry->offset,
+                                                 resource_size(entry->res));
+               }
+
+               if (pp->io_size) {
+                       if (pci->num_viewport > ++atu_idx)
+                               dw_pcie_prog_outbound_atu(pci, atu_idx,
+                                                         PCIE_ATU_TYPE_IO, pp->io_base,
+                                                         pp->io_bus_addr, pp->io_size);
+                       else
+                               pci->io_cfg_atu_shared = true;
+               }
+
+               if (pci->num_viewport <= atu_idx)
+                       dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
+                                pci->num_viewport);
        }
 
        dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);