patch-2.2.3 linux/arch/i386/kernel/bios32.c
Next file: linux/arch/i386/kernel/time.c
Previous file: linux/arch/i386/defconfig
Back to the patch index
Back to the overall index
- Lines: 273
- Date:
Mon Mar 8 11:08:02 1999
- Orig file:
v2.2.2/linux/arch/i386/kernel/bios32.c
- Orig date:
Wed Jan 20 23:14:04 1999
diff -u --recursive --new-file v2.2.2/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
@@ -14,7 +14,7 @@
* Hannover, Germany
* hm@ix.de
*
- * Copyright 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
@@ -71,6 +71,10 @@
* a large gallery of common hardware bug workarounds (watch the comments)
* -- the PCI specs themselves are sane, but most implementors should be
* hit hard with \hammer scaled \magstep5. [mj]
+ *
+ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
+ *
+ * Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj]
*/
#include <linux/config.h>
@@ -171,6 +175,7 @@
#define PCI_NO_SORT 0x100
#define PCI_BIOS_SORT 0x200
#define PCI_NO_CHECKS 0x400
+#define PCI_NO_PEER_FIXUP 0x800
static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
@@ -521,6 +526,8 @@
unsigned short segment;
} pci_indirect = { 0, __KERNEL_CS };
+static int pci_bios_present;
+
__initfunc(static int check_pcibios(void))
{
u32 signature, eax, ebx, ecx;
@@ -803,7 +810,7 @@
* which used BIOS ordering, we are bound to do this...
*/
-__initfunc(void pcibios_sort(void))
+static void __init pcibios_sort(void)
{
struct pci_dev *dev = pci_devices;
struct pci_dev **last = &pci_devices;
@@ -856,7 +863,7 @@
static int pci_last_io_addr __initdata = 0x5800;
-__initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx))
+static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx)
{
unsigned short cmd;
unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx;
@@ -868,13 +875,16 @@
printk("PCI: Unassigned I/O space for %02x:%02x\n", bus, devfn);
return;
}
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) {
+ if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+ (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
/*
* In case the BIOS didn't assign an address 0--3 to an IDE
* controller, we don't try to fix it as it means "use default
* addresses" at least with several broken chips and the IDE
* driver needs the original settings to recognize which devices
* correspond to the primary controller.
+ *
+ * We don't assign VGA I/O ranges as well.
*/
return;
}
@@ -914,7 +924,7 @@
* expected to be unique) and remove the ghost devices.
*/
-__initfunc(void pcibios_fixup_ghosts(struct pci_bus *b))
+static void __init pcibios_fixup_ghosts(struct pci_bus *b)
{
struct pci_dev *d, *e, **z;
int mirror = PCI_DEVFN(16,0);
@@ -954,12 +964,17 @@
* the reality doesn't pass this test and the bus number is usually
* set by BIOS to the first free value.
*/
-__initfunc(void pcibios_fixup_peer_bridges(void))
+static void __init pcibios_fixup_peer_bridges(void)
{
struct pci_bus *b = &pci_root;
int i, n, cnt=-1;
struct pci_dev *d;
+#ifdef CONFIG_VISWS
+ pci_scan_peer_bridge(1);
+ return;
+#endif
+
#ifdef CONFIG_PCI_DIRECT
/*
* Don't search for peer host bridges if we use config type 2
@@ -969,6 +984,7 @@
if (access_pci == &pci_direct_conf2)
return;
#endif
+
for(d=b->devices; d; d=d->sibling)
if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
cnt++;
@@ -979,6 +995,20 @@
for(i=0; i<256; i += 8)
if (!pcibios_read_config_word(n, i, PCI_VENDOR_ID, &l) &&
l != 0x0000 && l != 0xffff) {
+#ifdef CONFIG_PCI_BIOS
+ if (pci_bios_present) {
+ int succ, idx = 0;
+ u8 bios_bus, bios_dfn;
+ u16 d;
+ pcibios_read_config_word(n, i, PCI_DEVICE_ID, &d);
+ DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, i, l, d);
+ while ((succ = pci_bios_find_device(l, d, idx, &bios_bus, &bios_dfn)) &&
+ (bios_bus != n || bios_dfn != i))
+ idx++;
+ if (!succ)
+ break;
+ }
+#endif
DBG("Found device at %02x:%02x\n", n, i);
found++;
if (!pcibios_read_config_word(n, i, PCI_CLASS_DEVICE, &l) &&
@@ -989,13 +1019,7 @@
break;
if (found) {
printk("PCI: Discovered primary peer bus %02x\n", n);
- b = kmalloc(sizeof(*b), GFP_KERNEL);
- memset(b, 0, sizeof(*b));
- b->next = pci_root.next;
- pci_root.next = b;
- b->number = b->secondary = n;
- b->subordinate = 0xff;
- b->subordinate = pci_scan_bus(b);
+ b = pci_scan_peer_bridge(n);
n = b->subordinate;
}
n++;
@@ -1003,11 +1027,75 @@
}
/*
+ * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
+ */
+
+static void __init pci_fixup_i450nx(struct pci_dev *d)
+{
+ /*
+ * i450NX -- Find and scan all secondary buses on all PXB's.
+ */
+ int pxb, reg;
+ u8 busno, suba, subb;
+ reg = 0xd0;
+ for(pxb=0; pxb<2; pxb++) {
+ pci_read_config_byte(d, reg++, &busno);
+ pci_read_config_byte(d, reg++, &suba);
+ pci_read_config_byte(d, reg++, &subb);
+ DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+ if (busno)
+ pci_scan_peer_bridge(busno); /* Bus A */
+ if (suba < subb)
+ pci_scan_peer_bridge(suba+1); /* Bus B */
+ }
+ pci_probe |= PCI_NO_PEER_FIXUP;
+}
+
+static void __init pci_fixup_umc_ide(struct pci_dev *d)
+{
+ /*
+ * UM8886BF IDE controller sets region type bits incorrectly,
+ * therefore they look like memory despite of them being I/O.
+ */
+ int i;
+
+ for(i=0; i<4; i++)
+ d->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
+}
+
+struct dev_ex {
+ u16 vendor, device;
+ void (*handler)(struct pci_dev *);
+ char *comment;
+};
+
+static struct dev_ex __initdata dev_ex_table[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx, "Scanning peer host bridges" },
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide, "Working around UM8886BF bugs" }
+};
+
+static void __init pcibios_scan_buglist(struct pci_bus *b)
+{
+ struct pci_dev *d;
+ int i;
+
+ for(d=b->devices; d; d=d->sibling)
+ for(i=0; i<sizeof(dev_ex_table)/sizeof(dev_ex_table[0]); i++) {
+ struct dev_ex *e = &dev_ex_table[i];
+ if (e->vendor == d->vendor && e->device == d->device) {
+ printk("PCI: %02x:%02x [%04x/%04x]: %s\n",
+ b->number, d->devfn, d->vendor, d->device, e->comment);
+ e->handler(d);
+ }
+ }
+}
+
+/*
* Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds
* for buggy PCI BIOS'es :-[).
*/
-__initfunc(void pcibios_fixup_devices(void))
+static void __init pcibios_fixup_devices(void)
{
struct pci_dev *dev;
int i, has_io, has_mem;
@@ -1099,7 +1187,8 @@
__initfunc(void pcibios_fixup(void))
{
- pcibios_fixup_peer_bridges();
+ if (!(pci_probe & PCI_NO_PEER_FIXUP))
+ pcibios_fixup_peer_bridges();
pcibios_fixup_devices();
#ifdef CONFIG_PCI_BIOS
@@ -1111,6 +1200,7 @@
__initfunc(void pcibios_fixup_bus(struct pci_bus *b))
{
pcibios_fixup_ghosts(b);
+ pcibios_scan_buglist(b);
}
/*
@@ -1126,8 +1216,10 @@
struct pci_access *dir = NULL;
#ifdef CONFIG_PCI_BIOS
- if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios())))
+ if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
pci_probe |= PCI_BIOS_SORT;
+ pci_bios_present = 1;
+ }
#endif
#ifdef CONFIG_PCI_DIRECT
if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
@@ -1139,10 +1231,6 @@
access_pci = bios;
}
-#if !defined(CONFIG_PCI_BIOS) && !defined(CONFIG_PCI_DIRECT)
-#error PCI configured with neither PCI BIOS or PCI direct access support.
-#endif
-
__initfunc(char *pcibios_setup(char *str))
{
if (!strcmp(str, "off")) {
@@ -1178,5 +1266,9 @@
return NULL;
}
#endif
+ else if (!strcmp(str, "nopeer")) {
+ pci_probe |= PCI_NO_PEER_FIXUP;
+ return NULL;
+ }
return str;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)