@@ -61,6 +61,11 @@ static inline int ppc_pci_has_flag(int flag)
}
#endif
+/* A bunch of settings to apply to all devices on PCIe */
+struct pcie_settings {
+ int max_payload;
+ int max_read_size;
+};
/*
* Structure of a PCI controller (host bridge)
@@ -135,6 +140,9 @@ struct pci_controller {
resource_size_t dma_window_base_cur;
resource_size_t dma_window_size;
+ /* Optional pointer to PCIe settings to apply */
+ const struct pcie_settings *pcie_settings;
+
#ifdef CONFIG_PPC64
unsigned long buid;
@@ -1685,6 +1685,55 @@ int early_find_capability(struct pci_controller *hose, int bus, int devfn,
return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
}
+static int __devinit __fixup_pcie_scan_caps(struct pci_dev *dev, void *data)
+{
+ struct pcie_settings *set = data;
+ int pcie_cap, max_payload;
+ u32 devcap;
+
+ pcie_cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pcie_cap == 0)
+ return 0;
+
+ pci_read_config_dword(dev, pcie_cap + PCI_EXP_DEVCAP, &devcap);
+ max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD;
+ if (max_payload < set->max_payload)
+ set->max_payload = max_payload;
+ return 0;
+}
+
+static int __devinit __fixup_pcie_settings(struct pci_dev *dev, void *data)
+{
+ struct pcie_settings *set = data;
+ int pcie_cap;
+ u16 devctl;
+
+ pcie_cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pcie_cap == 0)
+ return 0;
+
+ pci_read_config_word(dev, pcie_cap + PCI_EXP_DEVCTL, &devctl);
+ devctl &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ);
+ devctl |= (set->max_read_size << 12) | (set->max_payload << 5);
+ pci_write_config_word(dev, pcie_cap + PCI_EXP_DEVCTL, devctl);
+ return 0;
+}
+
+static void __devinit fixup_pcie_settings(struct pci_controller *hose)
+{
+ struct pcie_settings set = *hose->pcie_settings;
+
+ pci_walk_bus(hose->bus, __fixup_pcie_scan_caps, &set);
+ pr_info("pci %04x: Capabilities for all devices:\n",
+ hose->global_number);
+ pr_info("pci %04x: Max payload : %d bytes\n",
+ hose->global_number, 1 << (set.max_payload + 7));
+ pr_info("pci %04x: Max read rq size : %d bytes\n",
+ hose->global_number, 1 << (set.max_read_size + 7));
+ pci_walk_bus(hose->bus, __fixup_pcie_settings, &set);
+}
+
+
/**
* pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
* @hose: Pointer to the PCI host controller instance structure
@@ -1727,4 +1776,8 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
if (mode == PCI_PROBE_NORMAL)
hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+
+ /* Fixup max payload sizes etc... */
+ if (hose->pcie_settings)
+ fixup_pcie_settings(hose);
}