aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/pci.c')
-rw-r--r--arch/sparc64/kernel/pci.c80
1 files changed, 74 insertions, 6 deletions
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 425e883e7e3b..b63341c2a334 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -26,6 +26,7 @@
26#include <asm/ebus.h> 26#include <asm/ebus.h>
27#include <asm/isa.h> 27#include <asm/isa.h>
28#include <asm/prom.h> 28#include <asm/prom.h>
29#include <asm/apb.h>
29 30
30#include "pci_impl.h" 31#include "pci_impl.h"
31 32
@@ -372,6 +373,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
372 struct dev_archdata *sd; 373 struct dev_archdata *sd;
373 struct pci_dev *dev; 374 struct pci_dev *dev;
374 const char *type; 375 const char *type;
376 u32 class;
375 377
376 dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); 378 dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
377 if (!dev) 379 if (!dev)
@@ -409,7 +411,15 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
409 411
410 sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), 412 sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
411 dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); 413 dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
412 dev->class = of_getintprop_default(node, "class-code", 0); 414
415 /* dev->class = of_getintprop_default(node, "class-code", 0); */
416 /* We can't actually use the firmware value, we have to read what
417 * is in the register right now. One reason is that in the case
418 * of IDE interfaces the firmware can sample the value before the
419 * the IDE interface is programmed into native mode.
420 */
421 pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
422 dev->class = class >> 8;
413 423
414 printk(" class: 0x%x\n", dev->class); 424 printk(" class: 0x%x\n", dev->class);
415 425
@@ -440,6 +450,53 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
440 return dev; 450 return dev;
441} 451}
442 452
453static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
454{
455 u32 idx, first, last;
456
457 first = 8;
458 last = 0;
459 for (idx = 0; idx < 8; idx++) {
460 if ((map & (1 << idx)) != 0) {
461 if (first > idx)
462 first = idx;
463 if (last < idx)
464 last = idx;
465 }
466 }
467
468 *first_p = first;
469 *last_p = last;
470}
471
472/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
473 * a proper 'ranges' property.
474 */
475static void __init apb_fake_ranges(struct pci_dev *dev,
476 struct pci_bus *bus,
477 struct pci_pbm_info *pbm)
478{
479 struct resource *res;
480 u32 first, last;
481 u8 map;
482
483 pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
484 apb_calc_first_last(map, &first, &last);
485 res = bus->resource[0];
486 res->start = (first << 21);
487 res->end = (last << 21) + ((1 << 21) - 1);
488 res->flags = IORESOURCE_IO;
489 pbm->parent->resource_adjust(dev, res, &pbm->io_space);
490
491 pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
492 apb_calc_first_last(map, &first, &last);
493 res = bus->resource[1];
494 res->start = (first << 21);
495 res->end = (last << 21) + ((1 << 21) - 1);
496 res->flags = IORESOURCE_MEM;
497 pbm->parent->resource_adjust(dev, res, &pbm->mem_space);
498}
499
443static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, 500static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
444 struct device_node *node, 501 struct device_node *node,
445 struct pci_bus *bus); 502 struct pci_bus *bus);
@@ -452,7 +509,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
452{ 509{
453 struct pci_bus *bus; 510 struct pci_bus *bus;
454 const u32 *busrange, *ranges; 511 const u32 *busrange, *ranges;
455 int len, i; 512 int len, i, simba;
456 struct resource *res; 513 struct resource *res;
457 unsigned int flags; 514 unsigned int flags;
458 u64 size; 515 u64 size;
@@ -467,10 +524,16 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
467 return; 524 return;
468 } 525 }
469 ranges = of_get_property(node, "ranges", &len); 526 ranges = of_get_property(node, "ranges", &len);
527 simba = 0;
470 if (ranges == NULL) { 528 if (ranges == NULL) {
471 printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", 529 char *model = of_get_property(node, "model", NULL);
472 node->full_name); 530 if (model && !strcmp(model, "SUNW,simba")) {
473 return; 531 simba = 1;
532 } else {
533 printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
534 node->full_name);
535 return;
536 }
474 } 537 }
475 538
476 bus = pci_add_new_bus(dev->bus, dev, busrange[0]); 539 bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
@@ -484,7 +547,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
484 bus->subordinate = busrange[1]; 547 bus->subordinate = busrange[1];
485 bus->bridge_ctl = 0; 548 bus->bridge_ctl = 0;
486 549
487 /* parse ranges property */ 550 /* parse ranges property, or cook one up by hand for Simba */
488 /* PCI #address-cells == 3 and #size-cells == 2 always */ 551 /* PCI #address-cells == 3 and #size-cells == 2 always */
489 res = &dev->resource[PCI_BRIDGE_RESOURCES]; 552 res = &dev->resource[PCI_BRIDGE_RESOURCES];
490 for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { 553 for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) {
@@ -492,6 +555,10 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
492 bus->resource[i] = res; 555 bus->resource[i] = res;
493 ++res; 556 ++res;
494 } 557 }
558 if (simba) {
559 apb_fake_ranges(dev, bus, pbm);
560 goto simba_cont;
561 }
495 i = 1; 562 i = 1;
496 for (; len >= 32; len -= 32, ranges += 8) { 563 for (; len >= 32; len -= 32, ranges += 8) {
497 struct resource *root; 564 struct resource *root;
@@ -529,6 +596,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
529 */ 596 */
530 pbm->parent->resource_adjust(dev, res, root); 597 pbm->parent->resource_adjust(dev, res, root);
531 } 598 }
599simba_cont:
532 sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), 600 sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
533 bus->number); 601 bus->number);
534 printk(" bus name: %s\n", bus->name); 602 printk(" bus name: %s\n", bus->name);