aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@ultra5.davemloft.net>2007-03-04 15:53:19 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 04:55:10 -0400
commit01f94c4a6ced476ce69b895426fc29bfc48c69bd (patch)
tree68866108644a1e90ae7688d2e35cb8462ab6a07c /arch/sparc64/kernel/pci.c
parenta378fd0ee8ea6af5dafd0ab3d634f22b926b5ac4 (diff)
[SPARC64]: Fix sabre pci controllers with new probing scheme.
The SIMBA APB bridge is strange, it is a PCI bridge but it lacks some standard OF properties, in particular it lacks a 'ranges' property. What you have to do is read the IO and MEM range registers in the APB bridge to determine the ranges handled by each bridge. So fill in the bus resources by doing that. Since we now handle this quirk in the generic PCI and OF device probing layers, we can flat out eliminate all of that code from the sabre pci controller driver. In fact we can thus eliminate completely another quirk of the sabre driver. It tried to make the two APB bridges look like PBMs but that makes zero sense now (and it's questionable whether it ever made sense). So now just use pbm_A and probe the whole PCI hierarchy using that as the root. This simplification allows many future cleanups to occur. Also, I've found yet another quirk that needs to be worked around while testing this. You can't use the 'class-code' OF firmware property, especially for IDE controllers. We have to read the value out of PCI config space or else we'll see the value the device was showing before it was programmed into native mode. I'm starting to think it might be wise to just read all of the values out of PCI config space instead of using the OF properties. :-/ Signed-off-by: David S. Miller <davem@davemloft.net>
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);