[PATCH] ARM: cns3xxx: Don't allocate PCI addresses on stack

Arnd Bergmann arnd at arndb.de
Mon Aug 25 04:30:22 PDT 2014


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 <broonie at linaro.org>
> > 
> > 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 <broonie at linaro.org>
> > 
> 
> 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 <arnd at arndb.de>

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");
 




More information about the linux-arm-kernel mailing list