Commit 64cf9d07ef1f5ed6abc6ed8a2420eb2849f7f444

Authored by Krzysztof Hałasa
Committed by Arnd Bergmann
1 parent 75efba8151

CNS3xxx: Fix PCIe early iotable_init().

This patch fixes the following BUG:

> kernel BUG at mm/vmalloc.c:1132!
> PC is at vm_area_add_early+0x20/0x84
> LR is at add_static_vm_early+0xc/0x60
>
> The problem is cns3xxx_pcie_init() (device_initcall) calls the "early"
> iotable_init().

Instead of merely calling the PCIe iotable_init() from
machine_desc->map_io(), this patch adds the required mappings to the
main CNS3xxx mapping table. This means we don't convert .pfn back to
virtual addresses in pcie.c. The size of the address space consumed for
PCIe control is reduced from 96 MiB (6 * 16 MiB) to about 32 MiB (this
doesn't include MMIO address space required by PCI devices):

- Size of the PCIe "host" mapping is reduced from 16 MiB to 4 KiB.
  It's a PCI configuration address space for the local (on-chip) PCIe
  bridge.

- Size of the "CFG0" mapping is reduced from 16 MiB to 64 KiB. It's for
  Type 0 Configuration accesses, i.e., accesses to the single device
  (with possible "functions") on the other end of the PCIe link.
  We really only need a 4 KiB page at 0x8000 (see the offset
  calculation in cns3xxx_pci_cfg_base()). There is still a potential
  problem with PCI bus numbers > 0xF, are they supported?

- The code in cns3xxx_pci_cfg_base() and cns3xxx_pcie_hw_init() should
  be clearer now.

- The maximum address space allocated for PCI MMIO is now correctly
  shown in /proc/iomem as 176 MiB (per each of the two PCI "domains"
  - previously only 16 MiB were reserved).

This patch has been tested on Gateworks Laguna board, masqueraded as
CNS3420VB.

Signed-off-by: Krzysztof Ha?asa <khalasa@piap.pl>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Showing 2 changed files with 64 additions and 73 deletions Side-by-side Diff

arch/arm/mach-cns3xxx/core.c
... ... @@ -47,6 +47,38 @@
47 47 .pfn = __phys_to_pfn(CNS3XXX_PM_BASE),
48 48 .length = SZ_4K,
49 49 .type = MT_DEVICE,
  50 +#ifdef CONFIG_PCI
  51 + }, {
  52 + .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT,
  53 + .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE),
  54 + .length = SZ_4K,
  55 + .type = MT_DEVICE,
  56 + }, {
  57 + .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT,
  58 + .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE),
  59 + .length = SZ_64K, /* really 4 KiB at offset 32 KiB */
  60 + .type = MT_DEVICE,
  61 + }, {
  62 + .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT,
  63 + .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE),
  64 + .length = SZ_16M,
  65 + .type = MT_DEVICE,
  66 + }, {
  67 + .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT,
  68 + .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE),
  69 + .length = SZ_4K,
  70 + .type = MT_DEVICE,
  71 + }, {
  72 + .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT,
  73 + .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE),
  74 + .length = SZ_64K, /* really 4 KiB at offset 32 KiB */
  75 + .type = MT_DEVICE,
  76 + }, {
  77 + .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT,
  78 + .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE),
  79 + .length = SZ_16M,
  80 + .type = MT_DEVICE,
  81 +#endif
50 82 },
51 83 };
52 84  
arch/arm/mach-cns3xxx/pcie.c
... ... @@ -23,15 +23,10 @@
23 23 #include "cns3xxx.h"
24 24 #include "core.h"
25 25  
26   -enum cns3xxx_access_type {
27   - CNS3XXX_HOST_TYPE = 0,
28   - CNS3XXX_CFG0_TYPE,
29   - CNS3XXX_CFG1_TYPE,
30   - CNS3XXX_NUM_ACCESS_TYPES,
31   -};
32   -
33 26 struct cns3xxx_pcie {
34   - struct map_desc cfg_bases[CNS3XXX_NUM_ACCESS_TYPES];
  27 + void __iomem *host_regs; /* PCI config registers for host bridge */
  28 + void __iomem *cfg0_regs; /* PCI Type 0 config registers */
  29 + void __iomem *cfg1_regs; /* PCI Type 1 config registers */
35 30 unsigned int irqs[2];
36 31 struct resource res_io;
37 32 struct resource res_mem;
... ... @@ -66,7 +61,6 @@
66 61 int busno = bus->number;
67 62 int slot = PCI_SLOT(devfn);
68 63 int offset;
69   - enum cns3xxx_access_type type;
70 64 void __iomem *base;
71 65  
72 66 /* If there is no link, just show the CNS PCI bridge. */
73 67  
74 68  
... ... @@ -78,17 +72,21 @@
78 72 * we still want to access it. For this to work, we must place
79 73 * the first device on the same bus as the CNS PCI bridge.
80 74 */
81   - if (busno == 0) {
82   - if (slot > 1)
83   - return NULL;
84   - type = slot;
85   - } else {
86   - type = CNS3XXX_CFG1_TYPE;
87   - }
  75 + if (busno == 0) { /* directly connected PCIe bus */
  76 + switch (slot) {
  77 + case 0: /* host bridge device, function 0 only */
  78 + base = cnspci->host_regs;
  79 + break;
  80 + case 1: /* directly connected device */
  81 + base = cnspci->cfg0_regs;
  82 + break;
  83 + default:
  84 + return NULL; /* no such device */
  85 + }
  86 + } else /* remote PCI bus */
  87 + base = cnspci->cfg1_regs;
88 88  
89   - base = (void __iomem *)cnspci->cfg_bases[type].virtual;
90 89 offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
91   -
92 90 return base + offset;
93 91 }
94 92  
95 93  
96 94  
... ... @@ -180,36 +178,19 @@
180 178  
181 179 static struct cns3xxx_pcie cns3xxx_pcie[] = {
182 180 [0] = {
183   - .cfg_bases = {
184   - [CNS3XXX_HOST_TYPE] = {
185   - .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT,
186   - .pfn = __phys_to_pfn(CNS3XXX_PCIE0_HOST_BASE),
187   - .length = SZ_16M,
188   - .type = MT_DEVICE,
189   - },
190   - [CNS3XXX_CFG0_TYPE] = {
191   - .virtual = CNS3XXX_PCIE0_CFG0_BASE_VIRT,
192   - .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG0_BASE),
193   - .length = SZ_16M,
194   - .type = MT_DEVICE,
195   - },
196   - [CNS3XXX_CFG1_TYPE] = {
197   - .virtual = CNS3XXX_PCIE0_CFG1_BASE_VIRT,
198   - .pfn = __phys_to_pfn(CNS3XXX_PCIE0_CFG1_BASE),
199   - .length = SZ_16M,
200   - .type = MT_DEVICE,
201   - },
202   - },
  181 + .host_regs = (void __iomem *)CNS3XXX_PCIE0_HOST_BASE_VIRT,
  182 + .cfg0_regs = (void __iomem *)CNS3XXX_PCIE0_CFG0_BASE_VIRT,
  183 + .cfg1_regs = (void __iomem *)CNS3XXX_PCIE0_CFG1_BASE_VIRT,
203 184 .res_io = {
204 185 .name = "PCIe0 I/O space",
205 186 .start = CNS3XXX_PCIE0_IO_BASE,
206   - .end = CNS3XXX_PCIE0_IO_BASE + SZ_16M - 1,
  187 + .end = CNS3XXX_PCIE0_CFG0_BASE - 1, /* 16 MiB */
207 188 .flags = IORESOURCE_IO,
208 189 },
209 190 .res_mem = {
210 191 .name = "PCIe0 non-prefetchable",
211 192 .start = CNS3XXX_PCIE0_MEM_BASE,
212   - .end = CNS3XXX_PCIE0_MEM_BASE + SZ_16M - 1,
  193 + .end = CNS3XXX_PCIE0_HOST_BASE - 1, /* 176 MiB */
213 194 .flags = IORESOURCE_MEM,
214 195 },
215 196 .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, },
216 197  
217 198  
... ... @@ -222,36 +203,19 @@
222 203 },
223 204 },
224 205 [1] = {
225   - .cfg_bases = {
226   - [CNS3XXX_HOST_TYPE] = {
227   - .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT,
228   - .pfn = __phys_to_pfn(CNS3XXX_PCIE1_HOST_BASE),
229   - .length = SZ_16M,
230   - .type = MT_DEVICE,
231   - },
232   - [CNS3XXX_CFG0_TYPE] = {
233   - .virtual = CNS3XXX_PCIE1_CFG0_BASE_VIRT,
234   - .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG0_BASE),
235   - .length = SZ_16M,
236   - .type = MT_DEVICE,
237   - },
238   - [CNS3XXX_CFG1_TYPE] = {
239   - .virtual = CNS3XXX_PCIE1_CFG1_BASE_VIRT,
240   - .pfn = __phys_to_pfn(CNS3XXX_PCIE1_CFG1_BASE),
241   - .length = SZ_16M,
242   - .type = MT_DEVICE,
243   - },
244   - },
  206 + .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT,
  207 + .cfg0_regs = (void __iomem *)CNS3XXX_PCIE1_CFG0_BASE_VIRT,
  208 + .cfg1_regs = (void __iomem *)CNS3XXX_PCIE1_CFG1_BASE_VIRT,
245 209 .res_io = {
246 210 .name = "PCIe1 I/O space",
247 211 .start = CNS3XXX_PCIE1_IO_BASE,
248   - .end = CNS3XXX_PCIE1_IO_BASE + SZ_16M - 1,
  212 + .end = CNS3XXX_PCIE1_CFG0_BASE - 1, /* 16 MiB */
249 213 .flags = IORESOURCE_IO,
250 214 },
251 215 .res_mem = {
252 216 .name = "PCIe1 non-prefetchable",
253 217 .start = CNS3XXX_PCIE1_MEM_BASE,
254   - .end = CNS3XXX_PCIE1_MEM_BASE + SZ_16M - 1,
  218 + .end = CNS3XXX_PCIE1_HOST_BASE - 1, /* 176 MiB */
255 219 .flags = IORESOURCE_MEM,
256 220 },
257 221 .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, },
258 222  
... ... @@ -307,18 +271,15 @@
307 271 .ops = &cns3xxx_pcie_ops,
308 272 .sysdata = &sd,
309 273 };
310   - u32 io_base = cnspci->res_io.start >> 16;
311   - u32 mem_base = cnspci->res_mem.start >> 16;
312   - u32 host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].pfn;
313   - u32 cfg0_base = cnspci->cfg_bases[CNS3XXX_CFG0_TYPE].pfn;
  274 + u16 mem_base = cnspci->res_mem.start >> 16;
  275 + u16 mem_limit = cnspci->res_mem.end >> 16;
  276 + u16 io_base = cnspci->res_io.start >> 16;
  277 + u16 io_limit = cnspci->res_io.end >> 16;
314 278 u32 devfn = 0;
315 279 u8 tmp8;
316 280 u16 pos;
317 281 u16 dc;
318 282  
319   - host_base = (__pfn_to_phys(host_base) - 1) >> 16;
320   - cfg0_base = (__pfn_to_phys(cfg0_base) - 1) >> 16;
321   -
322 283 pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
323 284 pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
324 285 pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);
325 286  
... ... @@ -328,9 +289,9 @@
328 289 pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);
329 290  
330 291 pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base);
331   - pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, host_base);
  292 + pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit);
332 293 pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base);
333   - pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, cfg0_base);
  294 + pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit);
334 295  
335 296 if (!cnspci->linked)
336 297 return;
... ... @@ -368,8 +329,6 @@
368 329 "imprecise external abort");
369 330  
370 331 for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
371   - iotable_init(cns3xxx_pcie[i].cfg_bases,
372   - ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases));
373 332 cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
374 333 cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
375 334 cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);