patch-2.1.75 linux/drivers/pci/pci.c
Next file: linux/drivers/pci/quirks.c
Previous file: linux/drivers/pci/Makefile
Back to the patch index
Back to the overall index
- Lines: 467
- Date:
Sun Dec 21 17:27:18 1997
- Orig file:
v2.1.74/linux/drivers/pci/pci.c
- Orig date:
Fri Dec 19 15:52:59 1997
diff -u --recursive --new-file v2.1.74/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
@@ -1,10 +1,10 @@
/*
- * $Id: pci.c,v 1.44 1997/09/03 05:08:22 richard Exp $
+ * $Id: pci.c,v 1.51 1997/12/03 06:18:11 davem Exp $
*
* PCI services that are built on top of the BIOS32 service.
*
- * Copyright 1993, 1994, 1995 Drew Eckhardt, Frederic Potter,
- * David Mosberger-Tang
+ * Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter,
+ * David Mosberger-Tang, Martin Mares
*/
#include <linux/config.h>
#include <linux/ptrace.h>
@@ -20,20 +20,10 @@
struct pci_bus pci_root;
struct pci_dev *pci_devices = 0;
-/*
- * The bridge_id field is an offset of an item into the array
- * BRIDGE_MAPPING_TYPE. 0xff indicates that the device is not a PCI
- * bridge, or that we don't know for the moment how to configure it.
- * I'm trying to do my best so that the kernel stays small. Different
- * chipset can have same optimization structure. i486 and pentium
- * chipsets from the same manufacturer usually have the same
- * structure.
- */
-#define DEVICE(vid,did,name) \
- {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name), 0xff}
+#undef DEBUG
-#define BRIDGE(vid,did,name,bridge) \
- {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name), (bridge)}
+#define DEVICE(vid,did,name) \
+ {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name)}
/*
* Sorted in ascending order by vendor and device.
@@ -87,7 +77,7 @@
DEVICE( TSENG, TSENG_ET6000, "ET6000"),
DEVICE( WEITEK, WEITEK_P9000, "P9000"),
DEVICE( WEITEK, WEITEK_P9100, "P9100"),
- BRIDGE( DEC, DEC_BRD, "DC21050", 0x00),
+ DEVICE( DEC, DEC_BRD, "DC21050"),
DEVICE( DEC, DEC_TULIP, "DC21040"),
DEVICE( DEC, DEC_TGA, "TGA"),
DEVICE( DEC, DEC_TULIP_FAST, "DC21140"),
@@ -180,10 +170,10 @@
DEVICE( N9, N9_I128, "Imagine 128"),
DEVICE( N9, N9_I128_2, "Imagine 128v2"),
DEVICE( UMC, UMC_UM8673F, "UM8673F"),
- BRIDGE( UMC, UMC_UM8891A, "UM8891A", 0x01),
+ DEVICE( UMC, UMC_UM8891A, "UM8891A"),
DEVICE( UMC, UMC_UM8886BF, "UM8886BF"),
DEVICE( UMC, UMC_UM8886A, "UM8886A"),
- BRIDGE( UMC, UMC_UM8881F, "UM8881F", 0x02),
+ DEVICE( UMC, UMC_UM8881F, "UM8881F"),
DEVICE( UMC, UMC_UM8886F, "UM8886F"),
DEVICE( UMC, UMC_UM9017F, "UM9017F"),
DEVICE( UMC, UMC_UM8886N, "UM8886N"),
@@ -206,7 +196,7 @@
DEVICE( OLICOM, OLICOM_OC6151, "OC-6151/6152"),
DEVICE( SUN, SUN_EBUS, "EBUS"),
DEVICE( SUN, SUN_HAPPYMEAL, "Happy Meal"),
- BRIDGE( SUN, SUN_PBM, "PCI Bus Module", 0x02),
+ DEVICE( SUN, SUN_PBM, "PCI Bus Module"),
DEVICE( CMD, CMD_640, "640 (buggy)"),
DEVICE( CMD, CMD_643, "643"),
DEVICE( CMD, CMD_646, "646"),
@@ -382,10 +372,10 @@
DEVICE( S3, S3_ViRGE_DXGX, "ViRGE/DX or /GX"),
DEVICE( S3, S3_ViRGE_GX2, "ViRGE/GX2"),
DEVICE( INTEL, INTEL_82375, "82375EB"),
- BRIDGE( INTEL, INTEL_82424, "82424ZX Saturn", 0x00),
+ DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"),
DEVICE( INTEL, INTEL_82378, "82378IB"),
DEVICE( INTEL, INTEL_82430, "82430ZX Aries"),
- BRIDGE( INTEL, INTEL_82434, "82434LX Mercury/Neptune", 0x00),
+ DEVICE( INTEL, INTEL_82434, "82434LX Mercury/Neptune"),
DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"),
DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"),
DEVICE( INTEL, INTEL_7116, "SAA7116"),
@@ -436,81 +426,6 @@
};
-#ifdef CONFIG_PCI_OPTIMIZE
-
-/*
- * An item of this structure has the following meaning:
- * for each optimization, the register address, the mask
- * and value to write to turn it on.
- * There are 5 optimizations for the moment:
- * Cache L2 write back best than write through
- * Posted Write for CPU to PCI enable
- * Posted Write for CPU to MEMORY enable
- * Posted Write for PCI to MEMORY enable
- * PCI Burst enable
- *
- * Half of the bios I've meet don't allow you to turn that on, and you
- * can gain more than 15% on graphic accesses using those
- * optimizations...
- */
-struct optimization_type {
- const char *type;
- const char *off;
- const char *on;
-} bridge_optimization[] = {
- {"Cache L2", "write through", "write back"},
- {"CPU-PCI posted write", "off", "on"},
- {"CPU-Memory posted write", "off", "on"},
- {"PCI-Memory posted write", "off", "on"},
- {"PCI burst", "off", "on"}
-};
-
-#define NUM_OPTIMIZATIONS \
- (sizeof(bridge_optimization) / sizeof(bridge_optimization[0]))
-
-struct bridge_mapping_type {
- unsigned char addr; /* config space address */
- unsigned char mask;
- unsigned char value;
-} bridge_mapping[] = {
- /*
- * Intel Neptune/Mercury/Saturn:
- * If the internal cache is write back,
- * the L2 cache must be write through!
- * I've to check out how to control that
- * for the moment, we won't touch the cache
- */
- {0x0 ,0x02 ,0x02 },
- {0x53 ,0x02 ,0x02 },
- {0x53 ,0x01 ,0x01 },
- {0x54 ,0x01 ,0x01 },
- {0x54 ,0x02 ,0x02 },
-
- /*
- * UMC 8891A Pentium chipset:
- * Why did you think UMC was cheaper ??
- */
- {0x50 ,0x10 ,0x00 },
- {0x51 ,0x40 ,0x40 },
- {0x0 ,0x0 ,0x0 },
- {0x0 ,0x0 ,0x0 },
- {0x0 ,0x0 ,0x0 },
-
- /*
- * UMC UM8881F
- * This is a dummy entry for my tests.
- * I have this chipset and no docs....
- */
- {0x0 ,0x1 ,0x1 },
- {0x0 ,0x2 ,0x0 },
- {0x0 ,0x0 ,0x0 },
- {0x0 ,0x0 ,0x0 },
- {0x0 ,0x0 ,0x0 }
-};
-
-#endif /* CONFIG_PCI_OPTIMIZE */
-
-
/*
* device_info[] is sorted so we can use binary search
*/
@@ -784,52 +699,6 @@
/*
- * Turn on/off PCI bridge optimization. This should allow benchmarking.
- */
-__initfunc(static void burst_bridge(unsigned char bus, unsigned char devfn,
- unsigned char pos, int turn_on))
-{
-#ifdef CONFIG_PCI_OPTIMIZE
- struct bridge_mapping_type *bmap;
- unsigned char val;
- int i;
-
- pos *= NUM_OPTIMIZATIONS;
- printk("PCI bridge optimization.\n");
- for (i = 0; i < NUM_OPTIMIZATIONS; i++) {
- printk(" %s: ", bridge_optimization[i].type);
- bmap = &bridge_mapping[pos + i];
- if (!bmap->addr) {
- printk("Not supported.");
- } else {
- pcibios_read_config_byte(bus, devfn, bmap->addr, &val);
- if ((val & bmap->mask) == bmap->value) {
- printk("%s.", bridge_optimization[i].on);
- if (!turn_on) {
- pcibios_write_config_byte(bus, devfn,
- bmap->addr,
- (val | bmap->mask)
- - bmap->value);
- printk("Changed! Now %s.", bridge_optimization[i].off);
- }
- } else {
- printk("%s.", bridge_optimization[i].off);
- if (turn_on) {
- pcibios_write_config_byte(bus, devfn,
- bmap->addr,
- (val & (0xff - bmap->mask))
- + bmap->value);
- printk("Changed! Now %s.", bridge_optimization[i].on);
- }
- }
- }
- printk("\n");
- }
-#endif /* CONFIG_PCI_OPTIMIZE */
-}
-
-
-/*
* Convert some of the configuration space registers of the device at
* address (bus,devfn) into a string (possibly several lines each).
* The configuration string is stored starting at buf[len]. If the
@@ -1010,42 +879,35 @@
{
void *mem;
-#ifdef DEBUG
- printk("...pci_malloc(size=%ld,mem=%p)", size, (void *)*mem_startp);
-#endif
mem = (void*) *mem_startp;
*mem_startp += (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
memset(mem, 0, size);
return mem;
}
-
unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
{
- unsigned int devfn, l, max;
- unsigned char cmd, tmp, irq, hdr_type = 0;
+ unsigned int devfn, l, max, class;
+ unsigned char cmd, irq, tmp, hdr_type = 0;
struct pci_dev_info *info;
struct pci_dev *dev;
struct pci_bus *child;
int reg;
#ifdef DEBUG
- printk("...pci_scan_bus(busno=%d,mem=%p)\n", bus->number,
- (void *)*mem_startp);
+ printk("pci_scan_bus for bus %d\n", bus->number);
#endif
max = bus->secondary;
for (devfn = 0; devfn < 0xff; ++devfn) {
if (PCI_FUNC(devfn) == 0) {
- pcibios_read_config_byte(bus->number, devfn,
- PCI_HEADER_TYPE, &hdr_type);
+ pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type);
} else if (!(hdr_type & 0x80)) {
/* not a multi-function device */
continue;
}
- pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID,
- &l);
+ pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l);
/* some broken boards return 0 if a slot is empty: */
if (l == 0xffffffff || l == 0x00000000) {
hdr_type = 0;
@@ -1054,14 +916,6 @@
dev = pci_malloc(sizeof(*dev), mem_startp);
dev->bus = bus;
- /*
- * Put it into the simple chain of devices on this
- * bus. It is used to find devices once everything is
- * set up.
- */
- dev->next = pci_devices;
- pci_devices = dev;
-
dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
@@ -1075,47 +929,62 @@
if (!info) {
printk("PCI: Warning: Unknown PCI device (%x:%x). Please read include/linux/pci.h\n",
dev->vendor, dev->device);
- } else {
- /* Some BIOS' are lazy. Let's do their job: */
- if (info->bridge_type != 0xff) {
- burst_bridge(bus->number, devfn,
- info->bridge_type, 1);
- }
}
/* non-destructively determine if device can be a master: */
- pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND,
- &cmd);
- pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND,
- cmd | PCI_COMMAND_MASTER);
- pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND,
- &tmp);
+ pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd);
+ pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+ pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp);
dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
- pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND,
- cmd);
+ pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd);
+
+ pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class);
+ class >>= 8; /* upper 3 bytes */
+ dev->class = class;
+
+ switch (hdr_type & 0x7f) { /* header type */
+ case 0: /* standard header */
+ if (class >> 8 == PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ /* read irq level (may be changed during pcibios_fixup()): */
+ pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
+ dev->irq = irq;
+ /*
+ * read base address registers, again pcibios_fixup() can
+ * tweak these
+ */
+ for (reg = 0; reg < 6; reg++) {
+ pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+ dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
+ }
+ break;
+ case 1: /* bridge header */
+ if (class >> 8 != PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ for (reg = 0; reg < 2; reg++) {
+ pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+ dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
+ }
+ break;
+ default: /* unknown header */
+ bad:
+ printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
+ bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
+ continue;
+ }
- /* read irq level (may be changed during pcibios_fixup()): */
- pcibios_read_config_byte(bus->number, devfn,
- PCI_INTERRUPT_LINE, &irq);
- dev->irq = irq;
+#ifdef DEBUG
+ printk("PCI: %02x:%02x [%04x/%04x]\n",
+ bus->number, dev->devfn, dev->vendor, dev->device);
+#endif
- /* read base address registers, again pcibios_fixup() can
- * tweak these
+ /*
+ * Put it into the global PCI device chain. It's used to
+ * find devices once everything is set up.
*/
- for (reg = 0; reg < 6; reg++) {
- pcibios_read_config_dword(bus->number, devfn,
- PCI_BASE_ADDRESS_0 + (reg << 2), &l);
- if (l == 0xffffffff)
- dev->base_address[reg] = 0;
- else
- dev->base_address[reg] = l;
- }
+ dev->next = pci_devices;
+ pci_devices = dev;
- /* check to see if this device is a PCI-PCI bridge: */
- pcibios_read_config_dword(bus->number, devfn,
- PCI_CLASS_REVISION, &l);
- l = l >> 8; /* upper 3 bytes */
- dev->class = l;
/*
* Now insert it into the list of devices held
* by the parent bus.
@@ -1123,7 +992,10 @@
dev->sibling = bus->devices;
bus->devices = dev;
- if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
+ /*
+ * If it's a bridge, scan the bus behind it.
+ */
+ if (class >> 8 == PCI_CLASS_BRIDGE_PCI) {
unsigned int buses;
unsigned short cr;
@@ -1131,7 +1003,7 @@
* Insert it into the tree of buses.
*/
child = pci_malloc(sizeof(*child), mem_startp);
- child->next = bus->children;
+ child->next = bus->children;
bus->children = child;
child->self = dev;
child->parent = bus;
@@ -1147,20 +1019,16 @@
* Clear all status bits and turn off memory,
* I/O and master enables.
*/
- pcibios_read_config_word(bus->number, devfn,
- PCI_COMMAND, &cr);
- pcibios_write_config_word(bus->number, devfn,
- PCI_COMMAND, 0x0000);
- pcibios_write_config_word(bus->number, devfn,
- PCI_STATUS, 0xffff);
+ pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
+ pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
+ pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
/*
* Read the existing primary/secondary/subordinate bus
* number configuration to determine if the PCI bridge
* has already been configured by the system. If so,
* do not modify the configuration, merely note it.
*/
- pcibios_read_config_dword(bus->number, devfn, 0x18,
- &buses);
+ pcibios_read_config_dword(bus->number, devfn, 0x18, &buses);
if ((buses & 0xFFFFFF) != 0)
{
child->primary = buses & 0xFF;
@@ -1179,8 +1047,7 @@
(((unsigned int)(child->primary) << 0) |
((unsigned int)(child->secondary) << 8) |
((unsigned int)(child->subordinate) << 16));
- pcibios_write_config_dword(bus->number, devfn, 0x18,
- buses);
+ pcibios_write_config_dword(bus->number, devfn, 0x18, buses);
/*
* Now we can scan all subordinate buses:
*/
@@ -1192,11 +1059,9 @@
child->subordinate = max;
buses = (buses & 0xff00ffff)
| ((unsigned int)(child->subordinate) << 16);
- pcibios_write_config_dword(bus->number, devfn, 0x18,
- buses);
+ pcibios_write_config_dword(bus->number, devfn, 0x18, buses);
}
- pcibios_write_config_word(bus->number, devfn,
- PCI_COMMAND, cr);
+ pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
}
}
/*
@@ -1206,6 +1071,9 @@
*
* Return how far we've got finding sub-buses.
*/
+#ifdef DEBUG
+ printk("PCI: pci_scan_bus returning with max=%02x\n", max);
+#endif
return max;
}
@@ -1236,5 +1104,10 @@
}
}
#endif
+
+#ifdef CONFIG_PCI_OPTIMIZE
+ pci_quirks_init();
+#endif
+
return mem_start;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov