Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/4xx: Add support for ISA holes on 4xx PCI/X/E

This adds support for ISA memory holes on the PCI, PCI-X and
PCI-E busses of the 4xx platforms. The patch includes changes
to the Bamboo and Canyonlands device-trees to add such a hole,
others can be updated separately.

The ISA memory hole is an additional outbound window configured
in the bridge to generate PCI cycles in the low memory addresses,
thus allowing to access things such as the hard-decoded VGA
aperture at 0xa0000..0xbffff or other similar things. It's made
accessible to userspace via the new legacy_mem file in sysfs for
which support was added by a previous patch.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>

authored by

Benjamin Herrenschmidt and committed by
Josh Boyer
84d727a1 9d2421e8

+210 -96
+2 -1
arch/powerpc/boot/dts/bamboo.dts
··· 269 269 * later cannot be changed. Chip supports a second 270 270 * IO range but we don't use it for now 271 271 */ 272 - ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x20000000 272 + ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x40000000 273 + 0x02000000 0x00000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00100000 273 274 0x01000000 0x00000000 0x00000000 0x00000000 0xe8000000 0x00000000 0x00010000>; 274 275 275 276 /* Inbound 2GB range starting at 0 */
+3
arch/powerpc/boot/dts/canyonlands.dts
··· 343 343 * later cannot be changed 344 344 */ 345 345 ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000 346 + 0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000 346 347 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>; 347 348 348 349 /* Inbound 2GB range starting at 0 */ ··· 374 373 * later cannot be changed 375 374 */ 376 375 ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 376 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000 377 377 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; 378 378 379 379 /* Inbound 2GB range starting at 0 */ ··· 416 414 * later cannot be changed 417 415 */ 418 416 ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 417 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000 419 418 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; 420 419 421 420 /* Inbound 2GB range starting at 0 */
+205 -95
arch/powerpc/sysdev/ppc4xx_pci.c
··· 194 194 * 4xx PCI 2.x part 195 195 */ 196 196 197 + static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, 198 + void __iomem *reg, 199 + u64 plb_addr, 200 + u64 pci_addr, 201 + u64 size, 202 + unsigned int flags, 203 + int index) 204 + { 205 + u32 ma, pcila, pciha; 206 + 207 + if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || 208 + size < 0x1000 || (plb_addr & (size - 1)) != 0) { 209 + printk(KERN_WARNING "%s: Resource out of range\n", 210 + hose->dn->full_name); 211 + return -1; 212 + } 213 + ma = (0xffffffffu << ilog2(size)) | 1; 214 + if (flags & IORESOURCE_PREFETCH) 215 + ma |= 2; 216 + 217 + pciha = RES_TO_U32_HIGH(pci_addr); 218 + pcila = RES_TO_U32_LOW(pci_addr); 219 + 220 + writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index)); 221 + writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index)); 222 + writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index)); 223 + writel(ma, reg + PCIL0_PMM0MA + (0x10 * index)); 224 + 225 + return 0; 226 + } 227 + 197 228 static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, 198 229 void __iomem *reg) 199 230 { 200 - u32 la, ma, pcila, pciha; 201 - int i, j; 231 + int i, j, found_isa_hole = 0; 202 232 203 233 /* Setup outbound memory windows */ 204 234 for (i = j = 0; i < 3; i++) { ··· 243 213 break; 244 214 } 245 215 246 - /* Calculate register values */ 247 - la = res->start; 248 - pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); 249 - pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 216 + /* Configure the resource */ 217 + if (ppc4xx_setup_one_pci_PMM(hose, reg, 218 + res->start, 219 + res->start - hose->pci_mem_offset, 220 + res->end + 1 - res->start, 221 + res->flags, 222 + j) == 0) { 223 + j++; 250 224 251 - ma = res->end + 1 - res->start; 252 - if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { 253 - printk(KERN_WARNING "%s: Resource out of range\n", 254 - hose->dn->full_name); 255 - continue; 225 + /* If the resource PCI address is 0 then we have our 226 + * ISA memory hole 227 + */ 228 + if (res->start == hose->pci_mem_offset) 229 + found_isa_hole = 1; 256 230 } 257 - ma = (0xffffffffu << ilog2(ma)) | 0x1; 258 - if (res->flags & IORESOURCE_PREFETCH) 259 - ma |= 0x2; 260 - 261 - /* Program register values */ 262 - writel(la, reg + PCIL0_PMM0LA + (0x10 * j)); 263 - writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j)); 264 - writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j)); 265 - writel(ma, reg + PCIL0_PMM0MA + (0x10 * j)); 266 - j++; 267 231 } 232 + 233 + /* Handle ISA memory hole if not already covered */ 234 + if (j <= 2 && !found_isa_hole && hose->isa_mem_size) 235 + if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0, 236 + hose->isa_mem_size, 0, j) == 0) 237 + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", 238 + hose->dn->full_name); 268 239 } 269 240 270 241 static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, ··· 383 352 * 4xx PCI-X part 384 353 */ 385 354 355 + static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose, 356 + void __iomem *reg, 357 + u64 plb_addr, 358 + u64 pci_addr, 359 + u64 size, 360 + unsigned int flags, 361 + int index) 362 + { 363 + u32 lah, lal, pciah, pcial, sa; 364 + 365 + if (!is_power_of_2(size) || size < 0x1000 || 366 + (plb_addr & (size - 1)) != 0) { 367 + printk(KERN_WARNING "%s: Resource out of range\n", 368 + hose->dn->full_name); 369 + return -1; 370 + } 371 + 372 + /* Calculate register values */ 373 + lah = RES_TO_U32_HIGH(plb_addr); 374 + lal = RES_TO_U32_LOW(plb_addr); 375 + pciah = RES_TO_U32_HIGH(pci_addr); 376 + pcial = RES_TO_U32_LOW(pci_addr); 377 + sa = (0xffffffffu << ilog2(size)) | 0x1; 378 + 379 + /* Program register values */ 380 + if (index == 0) { 381 + writel(lah, reg + PCIX0_POM0LAH); 382 + writel(lal, reg + PCIX0_POM0LAL); 383 + writel(pciah, reg + PCIX0_POM0PCIAH); 384 + writel(pcial, reg + PCIX0_POM0PCIAL); 385 + writel(sa, reg + PCIX0_POM0SA); 386 + } else { 387 + writel(lah, reg + PCIX0_POM1LAH); 388 + writel(lal, reg + PCIX0_POM1LAL); 389 + writel(pciah, reg + PCIX0_POM1PCIAH); 390 + writel(pcial, reg + PCIX0_POM1PCIAL); 391 + writel(sa, reg + PCIX0_POM1SA); 392 + } 393 + 394 + return 0; 395 + } 396 + 386 397 static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, 387 398 void __iomem *reg) 388 399 { 389 - u32 lah, lal, pciah, pcial, sa; 390 - int i, j; 400 + int i, j, found_isa_hole = 0; 391 401 392 402 /* Setup outbound memory windows */ 393 403 for (i = j = 0; i < 3; i++) { ··· 443 371 break; 444 372 } 445 373 446 - /* Calculate register values */ 447 - lah = RES_TO_U32_HIGH(res->start); 448 - lal = RES_TO_U32_LOW(res->start); 449 - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); 450 - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 451 - sa = res->end + 1 - res->start; 452 - if (!is_power_of_2(sa) || sa < 0x100000 || 453 - sa > 0xffffffffu) { 454 - printk(KERN_WARNING "%s: Resource out of range\n", 455 - hose->dn->full_name); 456 - continue; 457 - } 458 - sa = (0xffffffffu << ilog2(sa)) | 0x1; 374 + /* Configure the resource */ 375 + if (ppc4xx_setup_one_pcix_POM(hose, reg, 376 + res->start, 377 + res->start - hose->pci_mem_offset, 378 + res->end + 1 - res->start, 379 + res->flags, 380 + j) == 0) { 381 + j++; 459 382 460 - /* Program register values */ 461 - if (j == 0) { 462 - writel(lah, reg + PCIX0_POM0LAH); 463 - writel(lal, reg + PCIX0_POM0LAL); 464 - writel(pciah, reg + PCIX0_POM0PCIAH); 465 - writel(pcial, reg + PCIX0_POM0PCIAL); 466 - writel(sa, reg + PCIX0_POM0SA); 467 - } else { 468 - writel(lah, reg + PCIX0_POM1LAH); 469 - writel(lal, reg + PCIX0_POM1LAL); 470 - writel(pciah, reg + PCIX0_POM1PCIAH); 471 - writel(pcial, reg + PCIX0_POM1PCIAL); 472 - writel(sa, reg + PCIX0_POM1SA); 383 + /* If the resource PCI address is 0 then we have our 384 + * ISA memory hole 385 + */ 386 + if (res->start == hose->pci_mem_offset) 387 + found_isa_hole = 1; 473 388 } 474 - j++; 475 389 } 390 + 391 + /* Handle ISA memory hole if not already covered */ 392 + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) 393 + if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0, 394 + hose->isa_mem_size, 0, j) == 0) 395 + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", 396 + hose->dn->full_name); 476 397 } 477 398 478 399 static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, ··· 1382 1317 .write = ppc4xx_pciex_write_config, 1383 1318 }; 1384 1319 1320 + static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, 1321 + struct pci_controller *hose, 1322 + void __iomem *mbase, 1323 + u64 plb_addr, 1324 + u64 pci_addr, 1325 + u64 size, 1326 + unsigned int flags, 1327 + int index) 1328 + { 1329 + u32 lah, lal, pciah, pcial, sa; 1330 + 1331 + if (!is_power_of_2(size) || 1332 + (index < 2 && size < 0x100000) || 1333 + (index == 2 && size < 0x100) || 1334 + (plb_addr & (size - 1)) != 0) { 1335 + printk(KERN_WARNING "%s: Resource out of range\n", 1336 + hose->dn->full_name); 1337 + return -1; 1338 + } 1339 + 1340 + /* Calculate register values */ 1341 + lah = RES_TO_U32_HIGH(plb_addr); 1342 + lal = RES_TO_U32_LOW(plb_addr); 1343 + pciah = RES_TO_U32_HIGH(pci_addr); 1344 + pcial = RES_TO_U32_LOW(pci_addr); 1345 + sa = (0xffffffffu << ilog2(size)) | 0x1; 1346 + 1347 + /* Program register values */ 1348 + switch (index) { 1349 + case 0: 1350 + out_le32(mbase + PECFG_POM0LAH, pciah); 1351 + out_le32(mbase + PECFG_POM0LAL, pcial); 1352 + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); 1353 + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); 1354 + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); 1355 + /* Note that 3 here means enabled | single region */ 1356 + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); 1357 + break; 1358 + case 1: 1359 + out_le32(mbase + PECFG_POM1LAH, pciah); 1360 + out_le32(mbase + PECFG_POM1LAL, pcial); 1361 + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); 1362 + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); 1363 + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); 1364 + /* Note that 3 here means enabled | single region */ 1365 + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); 1366 + break; 1367 + case 2: 1368 + out_le32(mbase + PECFG_POM2LAH, pciah); 1369 + out_le32(mbase + PECFG_POM2LAL, pcial); 1370 + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); 1371 + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); 1372 + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); 1373 + /* Note that 3 here means enabled | IO space !!! */ 1374 + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); 1375 + break; 1376 + } 1377 + 1378 + return 0; 1379 + } 1380 + 1385 1381 static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, 1386 1382 struct pci_controller *hose, 1387 1383 void __iomem *mbase) 1388 1384 { 1389 - u32 lah, lal, pciah, pcial, sa; 1390 - int i, j; 1385 + int i, j, found_isa_hole = 0; 1391 1386 1392 1387 /* Setup outbound memory windows */ 1393 1388 for (i = j = 0; i < 3; i++) { ··· 1462 1337 break; 1463 1338 } 1464 1339 1465 - /* Calculate register values */ 1466 - lah = RES_TO_U32_HIGH(res->start); 1467 - lal = RES_TO_U32_LOW(res->start); 1468 - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); 1469 - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 1470 - sa = res->end + 1 - res->start; 1471 - if (!is_power_of_2(sa) || sa < 0x100000 || 1472 - sa > 0xffffffffu) { 1473 - printk(KERN_WARNING "%s: Resource out of range\n", 1474 - port->node->full_name); 1475 - continue; 1476 - } 1477 - sa = (0xffffffffu << ilog2(sa)) | 0x1; 1340 + /* Configure the resource */ 1341 + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, 1342 + res->start, 1343 + res->start - hose->pci_mem_offset, 1344 + res->end + 1 - res->start, 1345 + res->flags, 1346 + j) == 0) { 1347 + j++; 1478 1348 1479 - /* Program register values */ 1480 - switch (j) { 1481 - case 0: 1482 - out_le32(mbase + PECFG_POM0LAH, pciah); 1483 - out_le32(mbase + PECFG_POM0LAL, pcial); 1484 - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); 1485 - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); 1486 - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); 1487 - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); 1488 - break; 1489 - case 1: 1490 - out_le32(mbase + PECFG_POM1LAH, pciah); 1491 - out_le32(mbase + PECFG_POM1LAL, pcial); 1492 - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); 1493 - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); 1494 - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); 1495 - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); 1496 - break; 1349 + /* If the resource PCI address is 0 then we have our 1350 + * ISA memory hole 1351 + */ 1352 + if (res->start == hose->pci_mem_offset) 1353 + found_isa_hole = 1; 1497 1354 } 1498 - j++; 1499 1355 } 1500 1356 1501 - /* Configure IO, always 64K starting at 0 */ 1502 - if (hose->io_resource.flags & IORESOURCE_IO) { 1503 - lah = RES_TO_U32_HIGH(hose->io_base_phys); 1504 - lal = RES_TO_U32_LOW(hose->io_base_phys); 1505 - out_le32(mbase + PECFG_POM2LAH, 0); 1506 - out_le32(mbase + PECFG_POM2LAL, 0); 1507 - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); 1508 - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); 1509 - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); 1510 - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); 1511 - } 1357 + /* Handle ISA memory hole if not already covered */ 1358 + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) 1359 + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, 1360 + hose->isa_mem_phys, 0, 1361 + hose->isa_mem_size, 0, j) == 0) 1362 + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", 1363 + hose->dn->full_name); 1364 + 1365 + /* Configure IO, always 64K starting at 0. We hard wire it to 64K ! 1366 + * Note also that it -has- to be region index 2 on this HW 1367 + */ 1368 + if (hose->io_resource.flags & IORESOURCE_IO) 1369 + ppc4xx_setup_one_pciex_POM(port, hose, mbase, 1370 + hose->io_base_phys, 0, 1371 + 0x10000, IORESOURCE_IO, 2); 1512 1372 } 1513 1373 1514 1374 static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,