aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2006-02-14 11:23:57 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-23 17:35:12 -0500
commitbbe8f9a3e76c551973ee739de10b26581d78b45f (patch)
tree757788e67781a3eaee3453af79abf6bb50b3a681
parent92c05fc1a32e5ccef5e0e8201f32dcdab041524c (diff)
[PATCH] PCI: Avoid leaving MASTER_ABORT disabled permanently when returning from pci_scan_bridge.
> On Mon, Feb 13, 2006 at 05:13:21PM -0800, David S. Miller wrote: > > > > In drivers/pci/probe.c:pci_scan_bridge(), if this is not the first > > pass (pass != 0) we don't restore the PCI_BRIDGE_CONTROL_REGISTER and > > thus leave PCI_BRIDGE_CTL_MASTER_ABORT off: > > > > int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) > > { > > ... > > /* Disable MasterAbortMode during probing to avoid reporting > > of bus errors (in some architectures) */ > > pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl); > > pci_write_config_word(dev, PCI_BRIDGE_CONTROL, > > bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); > > ... > > if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) { > > unsigned int cmax, busnr; > > /* > > * Bus already configured by firmware, process it in the first > > * pass and just note the configuration. > > */ > > if (pass) > > return max; > > ... > > } > > > > pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); > > ... > > > > This doesn't seem intentional. Agreed, looks like an accident. The patch [1] originally came from Kip Walker (Broadcom back then) between 2.6.0-test3 and 2.6.0-test4. As I recall it was supposed to fix an issue with with PCI aborts being signalled by the PCI bridge of the Broadcom BCM1250 family of SOCs when probing behind pci_scan_bridge. It is undeseriable to disable PCI_BRIDGE_CTL_MASTER_ABORT in pci_{read,write)_config_* and the behaviour wasn't considered a bug in need of a workaround, so this was put in probe.c. I don't have an affected system at hand, so can't really test but I propose something like the below patch. [1] http://www.linux-mips.org/git?p=linux.git;a=commit;h=599457e0cb702a31a3247ea6a5d9c6c99c4cf195 [PCI] Avoid leaving MASTER_ABORT disabled permanently when returning from pci_scan_bridge. Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/pci/probe.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 63751a283817..3bc0fcd71d03 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -456,7 +456,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
456 * pass and just note the configuration. 456 * pass and just note the configuration.
457 */ 457 */
458 if (pass) 458 if (pass)
459 return max; 459 goto out;
460 busnr = (buses >> 8) & 0xFF; 460 busnr = (buses >> 8) & 0xFF;
461 461
462 /* 462 /*
@@ -466,12 +466,12 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
466 if (pci_find_bus(pci_domain_nr(bus), busnr)) { 466 if (pci_find_bus(pci_domain_nr(bus), busnr)) {
467 printk(KERN_INFO "PCI: Bus %04x:%02x already known\n", 467 printk(KERN_INFO "PCI: Bus %04x:%02x already known\n",
468 pci_domain_nr(bus), busnr); 468 pci_domain_nr(bus), busnr);
469 return max; 469 goto out;
470 } 470 }
471 471
472 child = pci_add_new_bus(bus, dev, busnr); 472 child = pci_add_new_bus(bus, dev, busnr);
473 if (!child) 473 if (!child)
474 return max; 474 goto out;
475 child->primary = buses & 0xFF; 475 child->primary = buses & 0xFF;
476 child->subordinate = (buses >> 16) & 0xFF; 476 child->subordinate = (buses >> 16) & 0xFF;
477 child->bridge_ctl = bctl; 477 child->bridge_ctl = bctl;
@@ -496,7 +496,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
496 bus ranges. */ 496 bus ranges. */
497 pci_write_config_dword(dev, PCI_PRIMARY_BUS, 497 pci_write_config_dword(dev, PCI_PRIMARY_BUS,
498 buses & ~0xffffff); 498 buses & ~0xffffff);
499 return max; 499 goto out;
500 } 500 }
501 501
502 /* Clear errors */ 502 /* Clear errors */
@@ -505,7 +505,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
505 /* Prevent assigning a bus number that already exists. 505 /* Prevent assigning a bus number that already exists.
506 * This can happen when a bridge is hot-plugged */ 506 * This can happen when a bridge is hot-plugged */
507 if (pci_find_bus(pci_domain_nr(bus), max+1)) 507 if (pci_find_bus(pci_domain_nr(bus), max+1))
508 return max; 508 goto out;
509 child = pci_add_new_bus(bus, dev, ++max); 509 child = pci_add_new_bus(bus, dev, ++max);
510 buses = (buses & 0xff000000) 510 buses = (buses & 0xff000000)
511 | ((unsigned int)(child->primary) << 0) 511 | ((unsigned int)(child->primary) << 0)
@@ -581,8 +581,6 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
581 pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); 581 pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
582 } 582 }
583 583
584 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
585
586 sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number); 584 sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
587 585
588 while (bus->parent) { 586 while (bus->parent) {
@@ -601,6 +599,9 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
601 bus = bus->parent; 599 bus = bus->parent;
602 } 600 }
603 601
602out:
603 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
604
604 return max; 605 return max;
605} 606}
606 607