aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-cns3xxx/pcie.c
diff options
context:
space:
mode:
authorKrzysztof HaƂasa <khalasa@piap.pl>2014-03-04 02:37:10 -0500
committerArnd Bergmann <arnd@arndb.de>2014-03-17 10:35:21 -0400
commit64cf9d07ef1f5ed6abc6ed8a2420eb2849f7f444 (patch)
tree9717d8e049dd2212ec827dab744517af0706360d /arch/arm/mach-cns3xxx/pcie.c
parent75efba81513133fdd2f9c1ac9213bf86cc622f62 (diff)
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>
Diffstat (limited to 'arch/arm/mach-cns3xxx/pcie.c')
-rw-r--r--arch/arm/mach-cns3xxx/pcie.c105
1 files changed, 32 insertions, 73 deletions
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index c7b204bff386..413134c54452 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -23,15 +23,10 @@
23#include "cns3xxx.h" 23#include "cns3xxx.h"
24#include "core.h" 24#include "core.h"
25 25
26enum cns3xxx_access_type {
27 CNS3XXX_HOST_TYPE = 0,
28 CNS3XXX_CFG0_TYPE,
29 CNS3XXX_CFG1_TYPE,
30 CNS3XXX_NUM_ACCESS_TYPES,
31};
32
33struct cns3xxx_pcie { 26struct 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 unsigned int irqs[2]; 30 unsigned int irqs[2];
36 struct resource res_io; 31 struct resource res_io;
37 struct resource res_mem; 32 struct resource res_mem;
@@ -66,7 +61,6 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
66 int busno = bus->number; 61 int busno = bus->number;
67 int slot = PCI_SLOT(devfn); 62 int slot = PCI_SLOT(devfn);
68 int offset; 63 int offset;
69 enum cns3xxx_access_type type;
70 void __iomem *base; 64 void __iomem *base;
71 65
72 /* If there is no link, just show the CNS PCI bridge. */ 66 /* If there is no link, just show the CNS PCI bridge. */
@@ -78,17 +72,21 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus,
78 * we still want to access it. For this to work, we must place 72 * we still want to access it. For this to work, we must place
79 * the first device on the same bus as the CNS PCI bridge. 73 * the first device on the same bus as the CNS PCI bridge.
80 */ 74 */
81 if (busno == 0) { 75 if (busno == 0) { /* directly connected PCIe bus */
82 if (slot > 1) 76 switch (slot) {
83 return NULL; 77 case 0: /* host bridge device, function 0 only */
84 type = slot; 78 base = cnspci->host_regs;
85 } else { 79 break;
86 type = CNS3XXX_CFG1_TYPE; 80 case 1: /* directly connected device */
87 } 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 offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc); 89 offset = ((busno & 0xf) << 20) | (devfn << 12) | (where & 0xffc);
91
92 return base + offset; 90 return base + offset;
93} 91}
94 92
@@ -180,36 +178,19 @@ static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
180 178
181static struct cns3xxx_pcie cns3xxx_pcie[] = { 179static struct cns3xxx_pcie cns3xxx_pcie[] = {
182 [0] = { 180 [0] = {
183 .cfg_bases = { 181 .host_regs = (void __iomem *)CNS3XXX_PCIE0_HOST_BASE_VIRT,
184 [CNS3XXX_HOST_TYPE] = { 182 .cfg0_regs = (void __iomem *)CNS3XXX_PCIE0_CFG0_BASE_VIRT,
185 .virtual = CNS3XXX_PCIE0_HOST_BASE_VIRT, 183 .cfg1_regs = (void __iomem *)CNS3XXX_PCIE0_CFG1_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 },
203 .res_io = { 184 .res_io = {
204 .name = "PCIe0 I/O space", 185 .name = "PCIe0 I/O space",
205 .start = CNS3XXX_PCIE0_IO_BASE, 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 .flags = IORESOURCE_IO, 188 .flags = IORESOURCE_IO,
208 }, 189 },
209 .res_mem = { 190 .res_mem = {
210 .name = "PCIe0 non-prefetchable", 191 .name = "PCIe0 non-prefetchable",
211 .start = CNS3XXX_PCIE0_MEM_BASE, 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 .flags = IORESOURCE_MEM, 194 .flags = IORESOURCE_MEM,
214 }, 195 },
215 .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, }, 196 .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, },
@@ -222,36 +203,19 @@ static struct cns3xxx_pcie cns3xxx_pcie[] = {
222 }, 203 },
223 }, 204 },
224 [1] = { 205 [1] = {
225 .cfg_bases = { 206 .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT,
226 [CNS3XXX_HOST_TYPE] = { 207 .cfg0_regs = (void __iomem *)CNS3XXX_PCIE1_CFG0_BASE_VIRT,
227 .virtual = CNS3XXX_PCIE1_HOST_BASE_VIRT, 208 .cfg1_regs = (void __iomem *)CNS3XXX_PCIE1_CFG1_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 },
245 .res_io = { 209 .res_io = {
246 .name = "PCIe1 I/O space", 210 .name = "PCIe1 I/O space",
247 .start = CNS3XXX_PCIE1_IO_BASE, 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 .flags = IORESOURCE_IO, 213 .flags = IORESOURCE_IO,
250 }, 214 },
251 .res_mem = { 215 .res_mem = {
252 .name = "PCIe1 non-prefetchable", 216 .name = "PCIe1 non-prefetchable",
253 .start = CNS3XXX_PCIE1_MEM_BASE, 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 .flags = IORESOURCE_MEM, 219 .flags = IORESOURCE_MEM,
256 }, 220 },
257 .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, }, 221 .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, },
@@ -307,18 +271,15 @@ static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
307 .ops = &cns3xxx_pcie_ops, 271 .ops = &cns3xxx_pcie_ops,
308 .sysdata = &sd, 272 .sysdata = &sd,
309 }; 273 };
310 u32 io_base = cnspci->res_io.start >> 16; 274 u16 mem_base = cnspci->res_mem.start >> 16;
311 u32 mem_base = cnspci->res_mem.start >> 16; 275 u16 mem_limit = cnspci->res_mem.end >> 16;
312 u32 host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].pfn; 276 u16 io_base = cnspci->res_io.start >> 16;
313 u32 cfg0_base = cnspci->cfg_bases[CNS3XXX_CFG0_TYPE].pfn; 277 u16 io_limit = cnspci->res_io.end >> 16;
314 u32 devfn = 0; 278 u32 devfn = 0;
315 u8 tmp8; 279 u8 tmp8;
316 u16 pos; 280 u16 pos;
317 u16 dc; 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 pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0); 283 pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
323 pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1); 284 pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
324 pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1); 285 pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);
@@ -328,9 +289,9 @@ static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
328 pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8); 289 pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);
329 290
330 pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base); 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 pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base); 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 if (!cnspci->linked) 296 if (!cnspci->linked)
336 return; 297 return;
@@ -368,8 +329,6 @@ static int __init cns3xxx_pcie_init(void)
368 "imprecise external abort"); 329 "imprecise external abort");
369 330
370 for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) { 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 cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i)); 332 cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
374 cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i)); 333 cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
375 cns3xxx_pcie_check_link(&cns3xxx_pcie[i]); 334 cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);