From patchwork Mon Jun 6 05:49:13 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Herrenschmidt X-Patchwork-Id: 850792 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p565ne6e008556 for ; Mon, 6 Jun 2011 05:49:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752769Ab1FFFtj (ORCPT ); Mon, 6 Jun 2011 01:49:39 -0400 Received: from gate.crashing.org ([63.228.1.57]:50089 "EHLO gate.crashing.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751703Ab1FFFtj (ORCPT ); Mon, 6 Jun 2011 01:49:39 -0400 Received: from [IPv6:::1] (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.13.8) with ESMTP id p565nDp3004234; Mon, 6 Jun 2011 00:49:14 -0500 Subject: Re: [PATCH v3] PCI: Max Payload Size BIOS workaround From: Benjamin Herrenschmidt To: Pratyush Anand Cc: Jon Mason , Jesse Barnes , Jordan_Hargrave@dell.com, linux-pci@vger.kernel.org, gallatin@myri.com In-Reply-To: References: <20110525190120.GB18356@myri.com> <5B3AAEAF6B46EA4D955DF7AD46C2C4858E6C931A@AUSX7MCPS303.AMER.DELL.COM> <5B3AAEAF6B46EA4D955DF7AD46C2C4858E7371E1@AUSX7MCPS303.AMER.DELL.COM> <20110527213924.GA32258@myri.com> <20110531094826.6b972abb@jbarnes-desktop> <20110601191010.GA30216@myri.com> <1307232857.23876.82.camel@pasglop> Date: Mon, 06 Jun 2011 15:49:13 +1000 Message-ID: <1307339353.2874.134.camel@pasglop> Mime-Version: 1.0 X-Mailer: Evolution 2.30.3 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 06 Jun 2011 05:49:40 +0000 (UTC) On Mon, 2011-06-06 at 10:08 +0530, Pratyush Anand wrote: > I do not know, how will it be implemented as a generic for all the > architecture. > I have implemented it for SPEAr( Its an ARM based SOC). ARM architecture > provides a postinit hook. I have implemented these modifications using > this hook. > This will also not work for hotplug case. > Since patch is still to be sent to main line for review, I am posting relevant > part of code here: And here's my ppc variant :-) A bit different as you can see, the whole thing gets only triggered if the platform populates the "pcie_settings" pointer in our arch-specific "pci_controller" structure (one per host bridge). This is typically static, and contains the capabilities (payload and max read req. size) of the host controller. Here too I don't handle hotplug (yet) as currently my only hotplug capable machines do that in IBM proprietary hypervisor but I will eventually have to. Cheers, Ben. commit 4d38c68f402ebc7810e21347885904c1b621b9c8 Author: Benjamin Herrenschmidt Date: Tue Mar 29 09:35:06 2011 +1100 powerpc/pci: Add generic mechanism to configure PCIe device settings Settings such as MaxPayload and MaxReadRequestSize must be configured properly for devices to work. Linux generic PCIe code doesn't really touch them unless asked to by drivers (which is generally bogus btw), so we add a mechanism in arch/powerpc, under control of a new flag, that allows the platform to specify some "max" values for those settings. Currently we support those two: - MaxPayload : We set all devices to a value which is the min of the platform value and the capabilities of all devices under the PHB - MaxReadRqSize : We set all devices to the platform value (since there is no capability involved here) Signed-off-by: Benjamin Herrenschmidt --- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index b90dbf8..7ad3526 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -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; diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 893af2a..3c00752 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -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); }