From patchwork Mon Aug 25 11:30:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 4773871 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9DF9D9F2E8 for ; Mon, 25 Aug 2014 11:34:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8DB4B20103 for ; Mon, 25 Aug 2014 11:34:15 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8843A200CF for ; Mon, 25 Aug 2014 11:34:14 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XLsU7-0000Re-TK; Mon, 25 Aug 2014 11:30:51 +0000 Received: from mout.kundenserver.de ([212.227.17.24]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XLsU3-0000FN-H1 for linux-arm-kernel@lists.infradead.org; Mon, 25 Aug 2014 11:30:48 +0000 Received: from wuerfel.localnet (HSI-KBW-134-3-133-35.hsi14.kabel-badenwuerttemberg.de [134.3.133.35]) by mrelayeu.kundenserver.de (node=mreue102) with ESMTP (Nemesis) id 0MVteq-1WoxOS0L0a-00X0pG; Mon, 25 Aug 2014 13:30:24 +0200 From: Arnd Bergmann To: linux-arm-kernel@lists.infradead.org Subject: Re: [PATCH] ARM: cns3xxx: Don't allocate PCI addresses on stack Date: Mon, 25 Aug 2014 13:30:22 +0200 Message-ID: <2791908.V6o8lplUAt@wuerfel> User-Agent: KMail/4.11.5 (Linux/3.11.0-26-generic; KDE/4.11.5; x86_64; ; ) In-Reply-To: <2492333.HstnrugmgL@wuerfel> References: <1408927894-30858-1-git-send-email-broonie@kernel.org> <2492333.HstnrugmgL@wuerfel> MIME-Version: 1.0 X-Provags-ID: V02:K0:dAKWb4+EY9+dDbksfC/CIydBVydzA4vBGC85iLKUHdx 03+DVnyeXIdCdYnJ+0UVhqaYA5wE3xExrk0svkk1ciz2Ekj7zo wUPf80XmvmoE8xA8b+q7l+6p1jd7aKOMHycfkiGuSSdsyoxVZR KWniCn9mW6H6LgcV9ypI3BScU3bgaxSna6QS6HegW145bpmd20 YyO3p32FVrKOOzJoglN7zZ8ErfqPuEOWCqbm0UofQui0LKnNcd ykTORmWsK+KgzgfvseSj2JlC8EgTlU1qHq9/r5vxEiIQZGFp/F ea6BgXUOBsJU9P63PT2j98pipaVAWxXitiyXTUmePvv85Tnbjg wvqgP1FHPqfE8cObP7b4= X-UI-Out-Filterresults: notjunk:1; X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140825_043047_937186_E470448F X-CRM114-Status: GOOD ( 24.60 ) X-Spam-Score: -0.1 (/) Cc: Mark Brown , Anton Vorontsov , linaro-kernel@lists.linaro.org, Mark Brown X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Monday 25 August 2014 12:34:25 Arnd Bergmann wrote: > On Sunday 24 August 2014 19:51:34 Mark Brown wrote: > > From: Mark Brown > > > > The cns3xxx PCIe code allocates a PCI bus structure on the stack, causing > > warnings due to the excessibe size of the resulting stack frame: > > > > arch/arm/mach-cns3xxx/pcie.c:311:1: warning: the frame size of 1072 bytes is larger than 1024 bytes [-Wframe-larger-than=] > > > > Avoid this by dynamically allocating the structure, though I am not > > convinced that we should be locally creating the struct pci_bus in the > > first place. > > > > Signed-off-by: Mark Brown > > > > We should certainly not make up a pci_bus here just for the purpose > of calling a common code function that comes back through a callback > to the locally defined cns3xxx_pci_read_config/cns3xxx_pci_write_config. > > However, refactoring the code to do it right seems like actual work > and I'm not sure we can find anybody to do it, so your hack seems > like the best approximation. I may have spoken too fast. Here is a patch that should deal with the problem more cleanly, and also help prepare that code for a potential move to the changed PCI probing infrastructure that is getting done for arm64. Completely untested. Signed-off-by: Arnd Bergmann diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 413134c54452..5b26b574bcbe 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -55,7 +55,7 @@ static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus) } static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus, - unsigned int devfn, int where) + unsigned int devfn) { struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus); int busno = bus->number; @@ -86,61 +86,87 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus, } else /* remote PCI bus */ base = cnspci->cfg1_regs; - offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc); + offset = ((busno & 0xf) << 20) | (devfn << 12); return base + offset; } -static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) +static u32 cns3xxx_pci_raw_read_config(void __iomem *base, int where, + int size) +{ + u32 v; + u32 mask = (0x1ull << (size * 8)) - 1; + int shift = (where % 4) * 8; + + v = __raw_readl(base + (where & 0xffc)); + + return (v >> shift) & mask; +} + +static u32 cns3xxx_pci_fake_read_config(void __iomem *base, int where, + int size) { u32 v; - void __iomem *base; u32 mask = (0x1ull << (size * 8)) - 1; int shift = (where % 4) * 8; - base = cns3xxx_pci_cfg_base(bus, devfn, where); + v = __raw_readl(base + (where & 0xffc)); + + /* + * RC's class is 0xb, but Linux PCI driver needs 0x604 + * for a PCIe bridge. So we must fixup the class code + * to 0x604 here. + */ + v &= 0xff; + v |= 0x604 << 16; + + return (v >> shift) & mask; +} + +static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + void __iomem *base; + + base = cns3xxx_pci_cfg_base(bus, devfn); if (!base) { *val = 0xffffffff; return PCIBIOS_SUCCESSFUL; } - v = __raw_readl(base); - if (bus->number == 0 && devfn == 0 && - (where & 0xffc) == PCI_CLASS_REVISION) { - /* - * RC's class is 0xb, but Linux PCI driver needs 0x604 - * for a PCIe bridge. So we must fixup the class code - * to 0x604 here. - */ - v &= 0xff; - v |= 0x604 << 16; - } - - *val = (v >> shift) & mask; + (where & 0xffc) == PCI_CLASS_REVISION) + *val = cns3xxx_pci_fake_read_config(base, where, size); + else + *val = cns3xxx_pci_raw_read_config(base, where, size); return PCIBIOS_SUCCESSFUL; } -static int cns3xxx_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) +static void cns3xxx_pci_raw_write_config(void __iomem *base, int where, + int size, u32 val) { u32 v; - void __iomem *base; u32 mask = (0x1ull << (size * 8)) - 1; int shift = (where % 4) * 8; - base = cns3xxx_pci_cfg_base(bus, devfn, where); - if (!base) - return PCIBIOS_SUCCESSFUL; - - v = __raw_readl(base); + v = __raw_readl(base + (where & 0xffc)); v &= ~(mask << shift); v |= (val & mask) << shift; - __raw_writel(v, base); + __raw_writel(v, base + (where & 0xffc)); +} + +static int cns3xxx_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + void __iomem *base; + base = cns3xxx_pci_cfg_base(bus, devfn); + if (!base) + return PCIBIOS_SUCCESSFUL; + + cns3xxx_pci_raw_write_config(base, where, size, val); return PCIBIOS_SUCCESSFUL; } @@ -262,47 +288,42 @@ static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci) static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) { + void __iomem *regs = cnspci->host_regs; int port = cnspci->hw_pci.domain; - struct pci_sys_data sd = { - .domain = port, - }; - struct pci_bus bus = { - .number = 0, - .ops = &cns3xxx_pcie_ops, - .sysdata = &sd, - }; u16 mem_base = cnspci->res_mem.start >> 16; u16 mem_limit = cnspci->res_mem.end >> 16; u16 io_base = cnspci->res_io.start >> 16; u16 io_limit = cnspci->res_io.end >> 16; - u32 devfn = 0; - u8 tmp8; u16 pos; u16 dc; - pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0); - pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1); - pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1); + cns3xxx_pci_raw_write_config(regs, PCI_PRIMARY_BUS, 1, 0); + cns3xxx_pci_raw_write_config(regs, PCI_SECONDARY_BUS, 1, 1); + cns3xxx_pci_raw_write_config(regs, PCI_SUBORDINATE_BUS, 1, 1); - pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8); - pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8); - pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8); + cns3xxx_pci_raw_read_config(regs, PCI_PRIMARY_BUS, 1); + cns3xxx_pci_raw_read_config(regs, PCI_SECONDARY_BUS, 1); + cns3xxx_pci_raw_read_config(regs, PCI_SUBORDINATE_BUS, 1); - pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base); - pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit); - pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base); - pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit); + cns3xxx_pci_raw_write_config(regs, PCI_MEMORY_BASE, 2, mem_base); + cns3xxx_pci_raw_write_config(regs, PCI_MEMORY_LIMIT, 2, mem_limit); + cns3xxx_pci_raw_write_config(regs, PCI_IO_BASE_UPPER16, 2, io_base); + cns3xxx_pci_raw_write_config(regs, PCI_IO_LIMIT_UPPER16, 2, io_limit); if (!cnspci->linked) return; + regs = cnspci->cfg0_regs + (PCI_DEVFN(1, 0) << 12); + /* Set Device Max_Read_Request_Size to 128 byte */ - devfn = PCI_DEVFN(1, 0); - pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP); - pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc); + pos = cns3xxx_pci_raw_read_config(regs, PCI_CAPABILITY_LIST, 1); + while (cns3xxx_pci_raw_read_config(regs, pos, 1) != PCI_CAP_ID_EXP) + pos = cns3xxx_pci_raw_read_config(regs, pos + PCI_CAP_LIST_NEXT, 1); + + dc = cns3xxx_pci_raw_read_config(regs, pos + PCI_EXP_DEVCTL, 2); dc &= ~(0x3 << 12); /* Clear Device Control Register [14:12] */ - pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc); - pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc); + cns3xxx_pci_raw_write_config(regs, pos + PCI_EXP_DEVCTL, 2, dc); + dc = cns3xxx_pci_raw_read_config(regs, pos + PCI_EXP_DEVCTL, 2); if (!(dc & (0x3 << 12))) pr_info("PCIe: Set Device Max_Read_Request_Size to 128 byte\n");