diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-06-21 21:18:47 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-24 02:15:07 -0400 |
commit | e87dc35020bc555969810452f44bceaf8394eafa (patch) | |
tree | b58f14d41f8e147f6ddc2d9657a88813fdb73bdf /arch/sparc64/kernel/pci_sabre.c | |
parent | aaf7cec2769942035985716452107fc5ba0b11f6 (diff) |
[SPARC64]: Use in-kernel OBP device tree for PCI controller probing.
It can be pushed even further down, but this is a first step.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_sabre.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sabre.c | 192 |
1 files changed, 82 insertions, 110 deletions
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index b7d997b55f0a..91d1aa44efc1 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/irq.h> | 19 | #include <asm/irq.h> |
20 | #include <asm/smp.h> | 20 | #include <asm/smp.h> |
21 | #include <asm/oplib.h> | 21 | #include <asm/oplib.h> |
22 | #include <asm/prom.h> | ||
22 | 23 | ||
23 | #include "pci_impl.h" | 24 | #include "pci_impl.h" |
24 | #include "iommu_common.h" | 25 | #include "iommu_common.h" |
@@ -1160,7 +1161,7 @@ static void sabre_scan_bus(struct pci_controller_info *p) | |||
1160 | 1161 | ||
1161 | pbus->sysdata = pbm; | 1162 | pbus->sysdata = pbm; |
1162 | pbm->pci_bus = pbus; | 1163 | pbm->pci_bus = pbus; |
1163 | pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); | 1164 | pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node->node); |
1164 | pci_record_assignments(pbm, pbus); | 1165 | pci_record_assignments(pbm, pbus); |
1165 | pci_assign_unassigned(pbm, pbus); | 1166 | pci_assign_unassigned(pbm, pbus); |
1166 | pci_fixup_irq(pbm, pbus); | 1167 | pci_fixup_irq(pbm, pbus); |
@@ -1173,7 +1174,7 @@ static void sabre_scan_bus(struct pci_controller_info *p) | |||
1173 | pbm = &p->pbm_A; | 1174 | pbm = &p->pbm_A; |
1174 | sabre_bus->sysdata = pbm; | 1175 | sabre_bus->sysdata = pbm; |
1175 | pbm->pci_bus = sabre_bus; | 1176 | pbm->pci_bus = sabre_bus; |
1176 | pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node); | 1177 | pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node->node); |
1177 | pci_record_assignments(pbm, sabre_bus); | 1178 | pci_record_assignments(pbm, sabre_bus); |
1178 | pci_assign_unassigned(pbm, sabre_bus); | 1179 | pci_assign_unassigned(pbm, sabre_bus); |
1179 | pci_fixup_irq(pbm, sabre_bus); | 1180 | pci_fixup_irq(pbm, sabre_bus); |
@@ -1306,34 +1307,36 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p, | |||
1306 | &pbm->mem_space); | 1307 | &pbm->mem_space); |
1307 | } | 1308 | } |
1308 | 1309 | ||
1309 | static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dma_begin) | 1310 | static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin) |
1310 | { | 1311 | { |
1311 | struct pci_pbm_info *pbm; | 1312 | struct pci_pbm_info *pbm; |
1312 | char namebuf[128]; | 1313 | struct device_node *node; |
1313 | u32 busrange[2]; | 1314 | struct property *prop; |
1314 | int node, simbas_found; | 1315 | u32 *busrange; |
1316 | int len, simbas_found; | ||
1315 | 1317 | ||
1316 | simbas_found = 0; | 1318 | simbas_found = 0; |
1317 | node = prom_getchild(sabre_node); | 1319 | node = dp->child; |
1318 | while ((node = prom_searchsiblings(node, "pci")) != 0) { | 1320 | while (node != NULL) { |
1319 | int err; | 1321 | if (strcmp(node->name, "pci")) |
1320 | |||
1321 | err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); | ||
1322 | if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) | ||
1323 | goto next_pci; | 1322 | goto next_pci; |
1324 | 1323 | ||
1325 | err = prom_getproperty(node, "bus-range", | 1324 | prop = of_find_property(node, "model", NULL); |
1326 | (char *)&busrange[0], sizeof(busrange)); | 1325 | if (!prop || strncmp(prop->value, "SUNW,simba", prop->length)) |
1327 | if (err == 0 || err == -1) { | 1326 | goto next_pci; |
1328 | prom_printf("APB: Error, cannot get PCI bus-range.\n"); | ||
1329 | prom_halt(); | ||
1330 | } | ||
1331 | 1327 | ||
1332 | simbas_found++; | 1328 | simbas_found++; |
1329 | |||
1330 | prop = of_find_property(node, "bus-range", NULL); | ||
1331 | busrange = prop->value; | ||
1333 | if (busrange[0] == 1) | 1332 | if (busrange[0] == 1) |
1334 | pbm = &p->pbm_B; | 1333 | pbm = &p->pbm_B; |
1335 | else | 1334 | else |
1336 | pbm = &p->pbm_A; | 1335 | pbm = &p->pbm_A; |
1336 | |||
1337 | pbm->name = node->full_name; | ||
1338 | printk("%s: SABRE PCI Bus Module\n", pbm->name); | ||
1339 | |||
1337 | pbm->chip_type = PBM_CHIP_TYPE_SABRE; | 1340 | pbm->chip_type = PBM_CHIP_TYPE_SABRE; |
1338 | pbm->parent = p; | 1341 | pbm->parent = p; |
1339 | pbm->prom_node = node; | 1342 | pbm->prom_node = node; |
@@ -1341,83 +1344,68 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm | |||
1341 | pbm->pci_first_busno = busrange[0]; | 1344 | pbm->pci_first_busno = busrange[0]; |
1342 | pbm->pci_last_busno = busrange[1]; | 1345 | pbm->pci_last_busno = busrange[1]; |
1343 | 1346 | ||
1344 | prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name)); | 1347 | prop = of_find_property(node, "ranges", &len); |
1345 | err = prom_getproperty(node, "ranges", | 1348 | if (prop) { |
1346 | (char *)pbm->pbm_ranges, | 1349 | pbm->pbm_ranges = prop->value; |
1347 | sizeof(pbm->pbm_ranges)); | ||
1348 | if (err != -1) | ||
1349 | pbm->num_pbm_ranges = | 1350 | pbm->num_pbm_ranges = |
1350 | (err / sizeof(struct linux_prom_pci_ranges)); | 1351 | (len / sizeof(struct linux_prom_pci_ranges)); |
1351 | else | 1352 | } else { |
1352 | pbm->num_pbm_ranges = 0; | 1353 | pbm->num_pbm_ranges = 0; |
1354 | } | ||
1353 | 1355 | ||
1354 | err = prom_getproperty(node, "interrupt-map", | 1356 | prop = of_find_property(node, "interrupt-map", &len); |
1355 | (char *)pbm->pbm_intmap, | 1357 | if (prop) { |
1356 | sizeof(pbm->pbm_intmap)); | 1358 | pbm->pbm_intmap = prop->value; |
1357 | if (err != -1) { | 1359 | pbm->num_pbm_intmap = |
1358 | pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); | 1360 | (len / sizeof(struct linux_prom_pci_intmap)); |
1359 | err = prom_getproperty(node, "interrupt-map-mask", | 1361 | |
1360 | (char *)&pbm->pbm_intmask, | 1362 | prop = of_find_property(node, "interrupt-map-mask", |
1361 | sizeof(pbm->pbm_intmask)); | 1363 | NULL); |
1362 | if (err == -1) { | 1364 | pbm->pbm_intmask = prop->value; |
1363 | prom_printf("APB: Fatal error, no interrupt-map-mask.\n"); | ||
1364 | prom_halt(); | ||
1365 | } | ||
1366 | } else { | 1365 | } else { |
1367 | pbm->num_pbm_intmap = 0; | 1366 | pbm->num_pbm_intmap = 0; |
1368 | memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); | ||
1369 | } | 1367 | } |
1370 | 1368 | ||
1371 | pbm_register_toplevel_resources(p, pbm); | 1369 | pbm_register_toplevel_resources(p, pbm); |
1372 | 1370 | ||
1373 | next_pci: | 1371 | next_pci: |
1374 | node = prom_getsibling(node); | 1372 | node = node->sibling; |
1375 | if (!node) | ||
1376 | break; | ||
1377 | } | 1373 | } |
1378 | if (simbas_found == 0) { | 1374 | if (simbas_found == 0) { |
1379 | int err; | ||
1380 | |||
1381 | /* No APBs underneath, probably this is a hummingbird | 1375 | /* No APBs underneath, probably this is a hummingbird |
1382 | * system. | 1376 | * system. |
1383 | */ | 1377 | */ |
1384 | pbm = &p->pbm_A; | 1378 | pbm = &p->pbm_A; |
1385 | pbm->parent = p; | 1379 | pbm->parent = p; |
1386 | pbm->prom_node = sabre_node; | 1380 | pbm->prom_node = dp; |
1387 | pbm->pci_first_busno = p->pci_first_busno; | 1381 | pbm->pci_first_busno = p->pci_first_busno; |
1388 | pbm->pci_last_busno = p->pci_last_busno; | 1382 | pbm->pci_last_busno = p->pci_last_busno; |
1389 | 1383 | ||
1390 | prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name)); | 1384 | prop = of_find_property(dp, "ranges", &len); |
1391 | err = prom_getproperty(sabre_node, "ranges", | 1385 | if (prop) { |
1392 | (char *) pbm->pbm_ranges, | 1386 | pbm->pbm_ranges = prop->value; |
1393 | sizeof(pbm->pbm_ranges)); | ||
1394 | if (err != -1) | ||
1395 | pbm->num_pbm_ranges = | 1387 | pbm->num_pbm_ranges = |
1396 | (err / sizeof(struct linux_prom_pci_ranges)); | 1388 | (len / sizeof(struct linux_prom_pci_ranges)); |
1397 | else | 1389 | } else { |
1398 | pbm->num_pbm_ranges = 0; | 1390 | pbm->num_pbm_ranges = 0; |
1391 | } | ||
1399 | 1392 | ||
1400 | err = prom_getproperty(sabre_node, "interrupt-map", | 1393 | prop = of_find_property(dp, "interrupt-map", &len); |
1401 | (char *) pbm->pbm_intmap, | 1394 | if (prop) { |
1402 | sizeof(pbm->pbm_intmap)); | 1395 | pbm->pbm_intmap = prop->value; |
1403 | 1396 | pbm->num_pbm_intmap = | |
1404 | if (err != -1) { | 1397 | (len / sizeof(struct linux_prom_pci_intmap)); |
1405 | pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); | 1398 | |
1406 | err = prom_getproperty(sabre_node, "interrupt-map-mask", | 1399 | prop = of_find_property(dp, "interrupt-map-mask", |
1407 | (char *)&pbm->pbm_intmask, | 1400 | NULL); |
1408 | sizeof(pbm->pbm_intmask)); | 1401 | pbm->pbm_intmask = prop->value; |
1409 | if (err == -1) { | ||
1410 | prom_printf("Hummingbird: Fatal error, no interrupt-map-mask.\n"); | ||
1411 | prom_halt(); | ||
1412 | } | ||
1413 | } else { | 1402 | } else { |
1414 | pbm->num_pbm_intmap = 0; | 1403 | pbm->num_pbm_intmap = 0; |
1415 | memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); | ||
1416 | } | 1404 | } |
1417 | 1405 | ||
1406 | pbm->name = dp->full_name; | ||
1407 | printk("%s: SABRE PCI Bus Module\n", pbm->name); | ||
1418 | 1408 | ||
1419 | sprintf(pbm->name, "SABRE%d PBM%c", p->index, | ||
1420 | (pbm == &p->pbm_A ? 'A' : 'B')); | ||
1421 | pbm->io_space.name = pbm->mem_space.name = pbm->name; | 1409 | pbm->io_space.name = pbm->mem_space.name = pbm->name; |
1422 | 1410 | ||
1423 | /* Hack up top-level resources. */ | 1411 | /* Hack up top-level resources. */ |
@@ -1443,14 +1431,15 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm | |||
1443 | } | 1431 | } |
1444 | } | 1432 | } |
1445 | 1433 | ||
1446 | void sabre_init(int pnode, char *model_name) | 1434 | void sabre_init(struct device_node *dp, char *model_name) |
1447 | { | 1435 | { |
1448 | struct linux_prom64_registers pr_regs[2]; | 1436 | struct linux_prom64_registers *pr_regs; |
1449 | struct pci_controller_info *p; | 1437 | struct pci_controller_info *p; |
1450 | struct pci_iommu *iommu; | 1438 | struct pci_iommu *iommu; |
1451 | int tsbsize, err; | 1439 | struct property *prop; |
1452 | u32 busrange[2]; | 1440 | int tsbsize; |
1453 | u32 vdma[2]; | 1441 | u32 *busrange; |
1442 | u32 *vdma; | ||
1454 | u32 upa_portid, dma_mask; | 1443 | u32 upa_portid, dma_mask; |
1455 | u64 clear_irq; | 1444 | u64 clear_irq; |
1456 | 1445 | ||
@@ -1458,13 +1447,15 @@ void sabre_init(int pnode, char *model_name) | |||
1458 | if (!strcmp(model_name, "pci108e,a001")) | 1447 | if (!strcmp(model_name, "pci108e,a001")) |
1459 | hummingbird_p = 1; | 1448 | hummingbird_p = 1; |
1460 | else if (!strcmp(model_name, "SUNW,sabre")) { | 1449 | else if (!strcmp(model_name, "SUNW,sabre")) { |
1461 | char compat[64]; | 1450 | prop = of_find_property(dp, "compatible", NULL); |
1451 | if (prop) { | ||
1452 | const char *compat = prop->value; | ||
1462 | 1453 | ||
1463 | if (prom_getproperty(pnode, "compatible", | 1454 | if (!strcmp(compat, "pci108e,a001")) |
1464 | compat, sizeof(compat)) > 0 && | 1455 | hummingbird_p = 1; |
1465 | !strcmp(compat, "pci108e,a001")) { | 1456 | } |
1466 | hummingbird_p = 1; | 1457 | if (!hummingbird_p) { |
1467 | } else { | 1458 | char compat[64]; |
1468 | int cpu_node; | 1459 | int cpu_node; |
1469 | 1460 | ||
1470 | /* Of course, Sun has to encode things a thousand | 1461 | /* Of course, Sun has to encode things a thousand |
@@ -1491,7 +1482,10 @@ void sabre_init(int pnode, char *model_name) | |||
1491 | } | 1482 | } |
1492 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; | 1483 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; |
1493 | 1484 | ||
1494 | upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); | 1485 | upa_portid = 0xff; |
1486 | prop = of_find_property(dp, "upa-portid", NULL); | ||
1487 | if (prop) | ||
1488 | upa_portid = *(u32 *) prop->value; | ||
1495 | 1489 | ||
1496 | p->next = pci_controller_root; | 1490 | p->next = pci_controller_root; |
1497 | pci_controller_root = p; | 1491 | pci_controller_root = p; |
@@ -1509,13 +1503,9 @@ void sabre_init(int pnode, char *model_name) | |||
1509 | /* | 1503 | /* |
1510 | * Map in SABRE register set and report the presence of this SABRE. | 1504 | * Map in SABRE register set and report the presence of this SABRE. |
1511 | */ | 1505 | */ |
1512 | err = prom_getproperty(pnode, "reg", | 1506 | |
1513 | (char *)&pr_regs[0], sizeof(pr_regs)); | 1507 | prop = of_find_property(dp, "reg", NULL); |
1514 | if(err == 0 || err == -1) { | 1508 | pr_regs = prop->value; |
1515 | prom_printf("SABRE: Error, cannot get U2P registers " | ||
1516 | "from PROM.\n"); | ||
1517 | prom_halt(); | ||
1518 | } | ||
1519 | 1509 | ||
1520 | /* | 1510 | /* |
1521 | * First REG in property is base of entire SABRE register space. | 1511 | * First REG in property is base of entire SABRE register space. |
@@ -1523,9 +1513,6 @@ void sabre_init(int pnode, char *model_name) | |||
1523 | p->pbm_A.controller_regs = pr_regs[0].phys_addr; | 1513 | p->pbm_A.controller_regs = pr_regs[0].phys_addr; |
1524 | p->pbm_B.controller_regs = pr_regs[0].phys_addr; | 1514 | p->pbm_B.controller_regs = pr_regs[0].phys_addr; |
1525 | 1515 | ||
1526 | printk("PCI: Found SABRE, main regs at %016lx\n", | ||
1527 | p->pbm_A.controller_regs); | ||
1528 | |||
1529 | /* Clear interrupts */ | 1516 | /* Clear interrupts */ |
1530 | 1517 | ||
1531 | /* PCI first */ | 1518 | /* PCI first */ |
@@ -1544,16 +1531,9 @@ void sabre_init(int pnode, char *model_name) | |||
1544 | /* Now map in PCI config space for entire SABRE. */ | 1531 | /* Now map in PCI config space for entire SABRE. */ |
1545 | p->pbm_A.config_space = p->pbm_B.config_space = | 1532 | p->pbm_A.config_space = p->pbm_B.config_space = |
1546 | (p->pbm_A.controller_regs + SABRE_CONFIGSPACE); | 1533 | (p->pbm_A.controller_regs + SABRE_CONFIGSPACE); |
1547 | printk("SABRE: Shared PCI config space at %016lx\n", | 1534 | |
1548 | p->pbm_A.config_space); | 1535 | prop = of_find_property(dp, "virtual-dma", NULL); |
1549 | 1536 | vdma = prop->value; | |
1550 | err = prom_getproperty(pnode, "virtual-dma", | ||
1551 | (char *)&vdma[0], sizeof(vdma)); | ||
1552 | if(err == 0 || err == -1) { | ||
1553 | prom_printf("SABRE: Error, cannot get virtual-dma property " | ||
1554 | "from PROM.\n"); | ||
1555 | prom_halt(); | ||
1556 | } | ||
1557 | 1537 | ||
1558 | dma_mask = vdma[0]; | 1538 | dma_mask = vdma[0]; |
1559 | switch(vdma[1]) { | 1539 | switch(vdma[1]) { |
@@ -1577,21 +1557,13 @@ void sabre_init(int pnode, char *model_name) | |||
1577 | 1557 | ||
1578 | sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); | 1558 | sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); |
1579 | 1559 | ||
1580 | printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); | 1560 | prop = of_find_property(dp, "bus-range", NULL); |
1581 | 1561 | busrange = prop->value; | |
1582 | err = prom_getproperty(pnode, "bus-range", | ||
1583 | (char *)&busrange[0], sizeof(busrange)); | ||
1584 | if(err == 0 || err == -1) { | ||
1585 | prom_printf("SABRE: Error, cannot get PCI bus-range " | ||
1586 | " from PROM.\n"); | ||
1587 | prom_halt(); | ||
1588 | } | ||
1589 | |||
1590 | p->pci_first_busno = busrange[0]; | 1562 | p->pci_first_busno = busrange[0]; |
1591 | p->pci_last_busno = busrange[1]; | 1563 | p->pci_last_busno = busrange[1]; |
1592 | 1564 | ||
1593 | /* | 1565 | /* |
1594 | * Look for APB underneath. | 1566 | * Look for APB underneath. |
1595 | */ | 1567 | */ |
1596 | sabre_pbm_init(p, pnode, vdma[0]); | 1568 | sabre_pbm_init(p, dp, vdma[0]); |
1597 | } | 1569 | } |