diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-02-14 11:23:57 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-23 17:35:12 -0500 |
commit | bbe8f9a3e76c551973ee739de10b26581d78b45f (patch) | |
tree | 757788e67781a3eaee3453af79abf6bb50b3a681 | |
parent | 92c05fc1a32e5ccef5e0e8201f32dcdab041524c (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.c | 15 |
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 | ||
602 | out: | ||
603 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); | ||
604 | |||
604 | return max; | 605 | return max; |
605 | } | 606 | } |
606 | 607 | ||