Commit 530ca2f1 authored by Ivan Kokshaysky's avatar Ivan Kokshaysky Committed by Greg Kroah-Hartman

[PATCH] PCI: fix bug in pci_setup_bridge()

This bug prevents Alphas with older firmware from booting if there
is a card with PCI-PCI bridge that supports 32-bit IO.
This has happened on AS2100 with a quad-tulip card, for example:
 - initially, the I/O window of 21152 bridge was 0x10000-0x10fff,
   as set up by firmware;
 - pci_setup_bridge() is going to change this, say, to 0xa000-0xafff:
   first, it updates PCI_IO_BASE_UPPER16 and PCI_IO_LIMIT_UPPER16
   registers, so that IO window temporarily is at 0x0000-0x0fff,
   which effectively blocks up all legacy IO ports in the lower
   4K range, such as serial, floppy, RTC an so on;
   does debugging printk - machine dies here with recursive
   machine checks as the serial console has gone.

Moving (or disabling) the debugging printk is not a solution -
there is possibility that timer interrupt (which might access RTC
ports) occurs between writes to lower and upper parts of the
base/limit registers.

The patch temporarily disables the IO window of the bridge by
setting PCI_IO_BASE_UPPER16 > PCI_IO_LIMIT_UPPER16 before doing
an update. It's safe, as we don't have any active IO behind
the bridge at this point. Also, it's a NOP for bridges with
16-bit-only IO.
Similar (but simpler, as we always clear upper 32 bits) fix
for 64-bit prefetchable MMIO range.
parent c303d64b
...@@ -132,13 +132,19 @@ pci_setup_cardbus(struct pci_bus *bus) ...@@ -132,13 +132,19 @@ pci_setup_cardbus(struct pci_bus *bus)
PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998) PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
requires that if there is no I/O ports or memory behind the requires that if there is no I/O ports or memory behind the
bridge, corresponding range must be turned off by writing base bridge, corresponding range must be turned off by writing base
value greater than limit to the bridge's base/limit registers. */ value greater than limit to the bridge's base/limit registers.
Note: care must be taken when updating I/O base/limit registers
of bridges which support 32-bit I/O. This update requires two
config space writes, so it's quite possible that an I/O window of
the bridge will have some undesirable address (e.g. 0) after the
first write. Ditto 64-bit prefetchable MMIO. */
static void __devinit static void __devinit
pci_setup_bridge(struct pci_bus *bus) pci_setup_bridge(struct pci_bus *bus)
{ {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
struct pci_bus_region region; struct pci_bus_region region;
u32 l; u32 l, io_upper16;
DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n", DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
bus->number, pci_name(bridge))); bus->number, pci_name(bridge)));
...@@ -151,20 +157,22 @@ pci_setup_bridge(struct pci_bus *bus) ...@@ -151,20 +157,22 @@ pci_setup_bridge(struct pci_bus *bus)
l |= (region.start >> 8) & 0x00f0; l |= (region.start >> 8) & 0x00f0;
l |= region.end & 0xf000; l |= region.end & 0xf000;
/* Set up upper 16 bits of I/O base/limit. */ /* Set up upper 16 bits of I/O base/limit. */
pci_write_config_word(bridge, PCI_IO_BASE_UPPER16, io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
region.start >> 16);
pci_write_config_word(bridge, PCI_IO_LIMIT_UPPER16,
region.end >> 16);
DBGC((KERN_INFO " IO window: %04lx-%04lx\n", DBGC((KERN_INFO " IO window: %04lx-%04lx\n",
region.start, region.end)); region.start, region.end));
} }
else { else {
/* Clear upper 16 bits of I/O base/limit. */ /* Clear upper 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0); io_upper16 = 0;
l = 0x00f0; l = 0x00f0;
DBGC((KERN_INFO " IO window: disabled.\n")); DBGC((KERN_INFO " IO window: disabled.\n"));
} }
/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
/* Update lower 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE, l); pci_write_config_dword(bridge, PCI_IO_BASE, l);
/* Update upper 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
/* Set up the top and bottom of the PCI Memory segment /* Set up the top and bottom of the PCI Memory segment
for this bus. */ for this bus. */
...@@ -181,8 +189,9 @@ pci_setup_bridge(struct pci_bus *bus) ...@@ -181,8 +189,9 @@ pci_setup_bridge(struct pci_bus *bus)
} }
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
/* Clear out the upper 32 bits of PREF base/limit. */ /* Clear out the upper 32 bits of PREF limit.
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0); If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
disables PREF range, which is ok. */
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */ /* Set up PREF base/limit. */
...@@ -199,6 +208,9 @@ pci_setup_bridge(struct pci_bus *bus) ...@@ -199,6 +208,9 @@ pci_setup_bridge(struct pci_bus *bus)
} }
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
/* Clear out the upper 32 bits of PREF base. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
/* Check if we have VGA behind the bridge. /* Check if we have VGA behind the bridge.
Enable ISA in either case (FIXME!). */ Enable ISA in either case (FIXME!). */
l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04; l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment