]> err.no Git - linux-2.6/blobdiff - arch/powerpc/sysdev/indirect_pci.c
[POWERPC] Added indirect quirk to handle PCIe PHB that have issue w/no link
[linux-2.6] / arch / powerpc / sysdev / indirect_pci.c
index e71488469704bbea18077cbf903871b72d34afeb..bc5b4e22fa5d16c74ae2006f6dd0abc9addb60cd 100644 (file)
@@ -33,18 +33,34 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
        struct pci_controller *hose = bus->sysdata;
        volatile void __iomem *cfg_data;
        u8 cfg_type = 0;
+       u32 bus_no, reg;
+
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
+               if (bus->number != hose->first_busno)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
 
        if (ppc_md.pci_exclude_device)
-               if (ppc_md.pci_exclude_device(bus->number, devfn))
+               if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
                        return PCIBIOS_DEVICE_NOT_FOUND;
-       
-       if (hose->set_cfg_type)
+
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
                if (bus->number != hose->first_busno)
                        cfg_type = 1;
 
-       PCI_CFG_OUT(hose->cfg_addr,                                      
-                (0x80000000 | ((bus->number - hose->bus_offset) << 16)
-                 | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+       bus_no = (bus->number == hose->first_busno) ?
+                       hose->self_busno : bus->number;
+
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
+               reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+       else
+               reg = offset & 0xfc;
+
+       PCI_CFG_OUT(hose->cfg_addr,
+                (0x80000000 | (bus_no << 16)
+                 | (devfn << 8) | reg | cfg_type));
 
        /*
         * Note: the caller has already checked that offset is
@@ -72,18 +88,40 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
        struct pci_controller *hose = bus->sysdata;
        volatile void __iomem *cfg_data;
        u8 cfg_type = 0;
+       u32 bus_no, reg;
+
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
+               if (bus->number != hose->first_busno)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
 
        if (ppc_md.pci_exclude_device)
-               if (ppc_md.pci_exclude_device(bus->number, devfn))
+               if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
                        return PCIBIOS_DEVICE_NOT_FOUND;
 
-       if (hose->set_cfg_type)
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
                if (bus->number != hose->first_busno)
                        cfg_type = 1;
 
-       PCI_CFG_OUT(hose->cfg_addr,                                      
-                (0x80000000 | ((bus->number - hose->bus_offset) << 16)
-                 | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+       bus_no = (bus->number == hose->first_busno) ?
+                       hose->self_busno : bus->number;
+
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
+               reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+       else
+               reg = offset & 0xfc;
+
+       PCI_CFG_OUT(hose->cfg_addr,
+                (0x80000000 | (bus_no << 16)
+                 | (devfn << 8) | reg | cfg_type));
+
+       /* surpress setting of PCI_PRIMARY_BUS */
+       if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+               if ((offset == PCI_PRIMARY_BUS) &&
+                       (bus->number == hose->first_busno))
+               val &= 0xffffff00;
 
        /*
         * Note: the caller has already checked that offset is