From: Greg KH <greg@kroah.com>
To: linux-kernel@vger.kernel.org
Subject: [PATCH] fixes for 2.6.0-test9
Date: Wed, 29 Oct 2003 16:50:38 -0800 [thread overview]
Message-ID: <10674750381029@kroah.com> (raw)
In-Reply-To: <20031030004852.GA2042@kroah.com>
ChangeSet 1.1384, 2003/10/29 15:20:38-08:00, ink@jurassic.park.msu.ru
[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.
drivers/pci/setup-bus.c | 30 +++++++++++++++++++++---------
1 files changed, 21 insertions(+), 9 deletions(-)
diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
--- a/drivers/pci/setup-bus.c Wed Oct 29 16:45:17 2003
+++ b/drivers/pci/setup-bus.c Wed Oct 29 16:45:17 2003
@@ -132,13 +132,19 @@
PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
requires that if there is no I/O ports or memory behind the
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
pci_setup_bridge(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
- u32 l;
+ u32 l, io_upper16;
DBGC((KERN_INFO "PCI: Bus %d, bridge: %s\n",
bus->number, pci_name(bridge)));
@@ -151,20 +157,22 @@
l |= (region.start >> 8) & 0x00f0;
l |= region.end & 0xf000;
/* Set up upper 16 bits of I/O base/limit. */
- pci_write_config_word(bridge, PCI_IO_BASE_UPPER16,
- region.start >> 16);
- pci_write_config_word(bridge, PCI_IO_LIMIT_UPPER16,
- region.end >> 16);
+ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
DBGC((KERN_INFO " IO window: %04lx-%04lx\n",
region.start, region.end));
}
else {
/* Clear upper 16 bits of I/O base/limit. */
- pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+ io_upper16 = 0;
l = 0x00f0;
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);
+ /* 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
for this bus. */
@@ -181,8 +189,9 @@
}
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
- /* Clear out the upper 32 bits of PREF base/limit. */
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+ /* Clear out the upper 32 bits of PREF limit.
+ 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);
/* Set up PREF base/limit. */
@@ -198,6 +207,9 @@
DBGC((KERN_INFO " PREFETCH window: disabled.\n"));
}
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.
Enable ISA in either case (FIXME!). */
next prev parent reply other threads:[~2003-10-30 0:51 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-10-30 0:48 [BK PATCH] fixes for 2.6.0-test9 Greg KH
2003-10-30 0:50 ` Greg KH [this message]
2003-10-30 0:50 ` [PATCH] " Greg KH
2003-10-30 0:50 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=10674750381029@kroah.com \
--to=greg@kroah.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.