PCI patches

Martin Mares (mj@albireo.ucw.cz)
Fri, 17 Jul 1998 15:27:34 +0200


Hello,

Here are some more PCI bugfixes:

o Some PC motherboards decode only lower 4 bits of device ID (although
they support conf type 1 which should have 5-bit ID's), therefore all
devices except for those behind bridges get detected twice. We now try
to detect such "ghost devices" and get rid of them before they manage
to cause lots of troubles. In order to accomplish this, I've added a new
arch-dependent fixup (pcibios_fixup_bus) which is called for each
bus after all devices on that bus are identified, but before any bridges
residing on that bus are scanned.

o Base addresses of PCI-to-CardBus bridges are handled correctly.

o CardBus bridge header (type 2) layout description in pci.h updated.
(I still don't have CardBus standard, but specs for most bridge chips
describe header layout well enough).

o Yet another fix for BIOSes reporting non-existent devices or reporting
the same device twice.

Martin

--- /usr/src/linux-2.1/arch/alpha/kernel/bios32.c Fri Jul 17 00:24:52 1998
+++ arch/alpha/kernel/bios32.c Sun Jul 12 18:34:30 1998
@@ -1946,8 +1946,8 @@
}


-void __init
-pcibios_fixup(void)
+__initfunc(void
+pcibios_fixup(void))
{
struct pci_bus *cur;

@@ -2019,6 +2019,12 @@
#else
# error "You must tell me what kind of platform you want."
#endif
+}
+
+
+__initfunc(void
+pcibios_fixup_bus(struct pci_bus *bus))
+{
}


--- /usr/src/linux-2.1/arch/i386/kernel/bios32.c Fri Jul 17 00:25:15 1998
+++ arch/i386/kernel/bios32.c Fri Jul 17 00:39:18 1998
@@ -1,7 +1,7 @@
/*
* bios32.c - Low-Level PCI Access
*
- * $Id: bios32.c,v 1.37 1998/06/19 17:11:37 mj Exp $
+ * $Id: bios32.c,v 1.40 1998/07/16 21:16:03 mj Exp $
*
* Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing
@@ -80,7 +80,6 @@
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/smp.h>
#include <asm/spinlock.h>

@@ -795,7 +794,7 @@
break;
}
}
- if (!idx) {
+ if (e == dev) {
printk("PCI: Device %02x:%02x not found by BIOS\n",
dev->bus->number, dev->devfn);
d = dev;
@@ -870,6 +869,46 @@
}

/*
+ * Several buggy motherboards address only 16 devices and mirror
+ * them to next 16 IDs. We try to detect this `feature' on all
+ * primary busses (those containing host bridges as they are
+ * expected to be unique) and remove the ghost devices.
+ */
+
+__initfunc(void pcibios_fixup_ghosts(struct pci_bus *b))
+{
+ struct pci_dev *d, *e, **z;
+ int mirror = PCI_DEVFN(16,0);
+ int seen_host_bridge = 0;
+
+ DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
+ for(d=b->devices; d && d->devfn < mirror; d=d->sibling) {
+ if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ seen_host_bridge++;
+ for(e=d->next; e; e=e->sibling)
+ if (e->devfn == d->devfn + mirror &&
+ e->vendor == d->vendor &&
+ e->device == d->device &&
+ e->class == d->class &&
+ !memcmp(e->base_address, d->base_address, sizeof(e->base_address)))
+ break;
+ if (!e)
+ return;
+ }
+ if (!seen_host_bridge)
+ return;
+ printk("PCI: Ignoring ghost devices on bus %d\n", b->number);
+ for(e=b->devices; e->sibling != d; e=e->sibling);
+ e->sibling = NULL;
+ for(z=&pci_devices; (d=*z);)
+ if (d->bus == b && d->devfn >= mirror) {
+ *z = d->next;
+ kfree_s(d, sizeof(*d));
+ } else
+ z = &d->next;
+}
+
+/*
* In case there are peer host bridges, scan bus behind each of them.
* Although several sources claim that the host bridges should have
* header type 1 and be assigned a bus number as for PCI2PCI bridges,
@@ -962,7 +1001,7 @@
}
#endif
/*
- * Fix out-of-range IRQ numbers and report bogus IRQ.
+ * Fix out-of-range IRQ numbers
*/
if (dev->irq >= NR_IRQS)
dev->irq = 0;
@@ -982,6 +1021,11 @@
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
#endif
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *b))
+{
+ pcibios_fixup_ghosts(b);
}

/*
--- /usr/src/linux-2.1/arch/m68k/kernel/bios32.c Thu Jun 25 21:49:10 1998
+++ arch/m68k/kernel/bios32.c Sun Jul 12 18:34:39 1998
@@ -587,6 +587,10 @@
hades_fixup();
}

+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
+
__initfunc(char *pcibios_setup(char *str))
{
return str;
--- /usr/src/linux-2.1/arch/mips/kernel/pci.c Tue May 12 09:59:40 1998
+++ arch/mips/kernel/pci.c Wed Jul 15 23:50:05 1998
@@ -127,6 +79,15 @@
unsigned char where, unsigned int val)
{
return pci_ops->pcibios_write_config_dword(bus, dev_fn, where, val);
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
+
+__initfunc(char *pcibios_setup(char *str))
+{
+ return str;
}

#endif /* defined(CONFIG_PCI) */
--- /usr/src/linux-2.1/arch/ppc/kernel/pci.c Tue May 12 09:59:42 1998
+++ arch/ppc/kernel/pci.c Wed Jul 15 23:50:20 1998
@@ -243,6 +281,10 @@
}
break;
}
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
}

__initfunc(char *pcibios_setup(char *str))
--- /usr/src/linux-2.1/arch/sparc64/kernel/psycho.c Tue May 12 09:59:44 1998
+++ arch/sparc64/kernel/psycho.c Wed Jul 15 23:50:20 1998
@@ -2379,6 +2419,10 @@
unlock_kernel();

return err;
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
}

__initfunc(char *pcibios_setup(char *str))
--- /usr/src/linux-2.1/arch/arm/kernel/dec21285.c Sat Jun 6 11:29:40 1998
+++ arch/arm/kernel/dec21285.c Sun Jul 12 18:36:57 1998
@@ -138,6 +138,10 @@
printk("DEC21285 PCI revision %02X\n", rev);
}

+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
+
__initfunc(char *pcibios_setup(char *str))
{
return str;
--- /usr/src/linux-2.1/drivers/pci/pci.c Sat Jun 6 11:30:07 1998
+++ drivers/pci/pci.c Wed Jul 15 23:50:22 1998
@@ -1,5 +1,5 @@
/*
- * $Id: pci.c,v 1.85 1998/05/12 07:36:01 mj Exp $
+ * $Id: pci.c,v 1.86 1998/07/15 20:34:47 mj Exp $
*
* PCI Bus Services, see include/linux/pci.h for further explanation.
*
@@ -232,10 +232,7 @@
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
if (class != PCI_CLASS_BRIDGE_CARDBUS)
goto bad;
- for (reg = 0; reg < 2; reg++) {
- pcibios_read_config_dword(bus->number, devfn, PCI_CB_MEMORY_BASE_0 + (reg << 3), &l);
- dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
- }
+ pci_read_bases(dev, 1);
break;
default: /* unknown header */
bad:
@@ -274,12 +271,20 @@
if (tmp < 32)
pcibios_write_config_byte(bus->number, dev->devfn, PCI_LATENCY_TIMER, 32);
#endif
+ }

+ /*
+ * After performing arch-dependent fixup of the bus, look behind
+ * all PCI-to-PCI bridges on this bus.
+ */
+ pcibios_fixup_bus(bus);
+ for(dev=bus->devices; dev; dev=dev->sibling)
/*
* If it's a bridge, scan the bus behind it.
*/
- if (class == PCI_CLASS_BRIDGE_PCI) {
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
unsigned int buses;
+ unsigned int devfn = dev->devfn;
unsigned short cr;

/*
@@ -350,7 +355,7 @@
}
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
}
- }
+
/*
* We've scanned the bus and so we know all about what's on
* the other side of any bridges that may be on this bus plus
--- /usr/src/linux-2.1/include/linux/pci.h Fri Jul 17 13:57:00 1998
+++ include/linux/pci.h Wed Jul 15 23:50:30 1998
@@ -1,5 +1,5 @@
/*
- * $Id: pci.h,v 1.72 1998/05/12 07:35:54 mj Exp $
+ * $Id: pci.h,v 1.76 1998/07/15 20:34:50 mj Exp $
*
* PCI defines and function prototypes
* Copyright 1994, Drew Eckhardt
@@ -76,7 +76,7 @@
* 1 bits are decoded.
*/
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
-#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
@@ -146,16 +146,12 @@
#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */

-/* Header type 2 (CardBus bridges) -- detailed info welcome */
+/* Header type 2 (CardBus bridges) */
-#define PCI_CB_CARDBUS_BASE 0x10 /* CardBus Socket/ExCa base address */
-#define PCI_CB_CARDBUS_BASE_TYPE_MASK 0xfff
-#define PCI_CB_CARDBUS_BASE_MASK ~0xfff
-#define PCI_CB_CAPABILITIES 0x14 /* Offset of list of capabilities in cfg space */
-/* 0x15 reserved */
+/* 0x14-0x15 reserved */
#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
-#define PCI_CB_BUS_NUMBER 0x18 /* PCI bus number */
-#define PCI_CB_CARDBUS_NUMBER 0x19 /* CardBus bus number */
+#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
+#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
-#define PCI_CB_CARDBUS_LATENCY 0x1b /* CardBus latency timer */
+#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
#define PCI_CB_MEMORY_BASE_0 0x1c
#define PCI_CB_MEMORY_LIMIT_0 0x20
#define PCI_CB_MEMORY_BASE_1 0x24
@@ -168,8 +164,19 @@
#define PCI_CB_IO_BASE_1_HI 0x36
#define PCI_CB_IO_LIMIT_1 0x38
#define PCI_CB_IO_LIMIT_1_HI 0x3a
+#define PCI_CB_IO_RANGE_MASK ~0x03
/* 0x3c-0x3d are same as for htype 0 */
-/* 0x3e-0x3f are same as for htype 1 */
+#define PCI_CB_BRIDGE_CONTROL 0x3e
+#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
+#define PCI_CB_BRIDGE_CTL_SERR 0x02
+#define PCI_CB_BRIDGE_CTL_ISA 0x04
+#define PCI_CB_BRIDGE_CTL_VGA 0x08
+#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
+#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
+#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
#define PCI_CB_SUBSYSTEM_ID 0x42
#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
@@ -1037,43 +1043,6 @@
#include <linux/types.h>

/*
- * Error values that may be returned by the PCI bios.
- */
-#define PCIBIOS_SUCCESSFUL 0x00
-#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
-#define PCIBIOS_BAD_VENDOR_ID 0x83
-#define PCIBIOS_DEVICE_NOT_FOUND 0x86
-#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
-#define PCIBIOS_SET_FAILED 0x88
-#define PCIBIOS_BUFFER_TOO_SMALL 0x89
-
-/* Direct configuration space access */
-
-int pcibios_present (void);
-void pcibios_init(void);
-void pcibios_fixup(void);
-char *pcibios_setup (char *str);
-int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned char *val);
-int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned short *val);
-int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned int *val);
-int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned char val);
-int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned short val);
-int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
- unsigned char where, unsigned int val);
-
-/* Don't use these in new code, use pci_find_... instead */
-
-int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn);
-int pcibios_find_device (unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus,
- unsigned char *dev_fn);
-
-/*
* There is one pci_dev structure for each slot-number/function-number
* combination:
*/
@@ -1130,6 +1099,46 @@

extern struct pci_bus pci_root; /* root bus */
extern struct pci_dev *pci_devices; /* list of all devices */
+
+/*
+ * Error values that may be returned by the PCI bios.
+ */
+#define PCIBIOS_SUCCESSFUL 0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
+#define PCIBIOS_BAD_VENDOR_ID 0x83
+#define PCIBIOS_DEVICE_NOT_FOUND 0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
+#define PCIBIOS_SET_FAILED 0x88
+#define PCIBIOS_BUFFER_TOO_SMALL 0x89
+
+/* Low-level architecture-dependent routines */
+
+int pcibios_present (void);
+void pcibios_init(void);
+void pcibios_fixup(void);
+void pcibios_fixup_bus(struct pci_bus *);
+char *pcibios_setup (char *str);
+int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned char *val);
+int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned short *val);
+int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned int *val);
+int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned char val);
+int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned short val);
+int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned int val);
+
+/* Don't use these in new code, use pci_find_... instead */
+
+int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn);
+int pcibios_find_device (unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *dev_fn);
+
+/* Generic PCI interface functions */

void pci_init(void);
void pci_setup(char *str, int *ints);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html