patch-2.4.19 linux-2.4.19/arch/i386/kernel/pci-pc.c
Next file: linux-2.4.19/arch/i386/kernel/process.c
Previous file: linux-2.4.19/arch/i386/kernel/pci-irq.c
Back to the patch index
Back to the overall index
- Lines: 348
- Date:
Fri Aug 2 17:39:42 2002
- Orig file:
linux-2.4.18/arch/i386/kernel/pci-pc.c
- Orig date:
Mon Feb 25 11:37:53 2002
diff -urN linux-2.4.18/arch/i386/kernel/pci-pc.c linux-2.4.19/arch/i386/kernel/pci-pc.c
@@ -14,6 +14,7 @@
#include <asm/segment.h>
#include <asm/io.h>
+#include <asm/smp.h>
#include "pci-i386.h"
@@ -26,6 +27,16 @@
int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
+#ifdef CONFIG_MULTIQUAD
+#define BUS2QUAD(global) (mp_bus_id_to_node[global])
+#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
+#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
+#else
+#define BUS2QUAD(global) (0)
+#define BUS2LOCAL(global) (global)
+#define QUADLOCAL2BUS(quad,local) (local)
+#endif
+
/*
* This interrupt-safe spinlock protects all accesses to PCI
* configuration space.
@@ -39,10 +50,71 @@
#ifdef CONFIG_PCI_DIRECT
+#ifdef CONFIG_MULTIQUAD
+#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
+ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
+
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
+{
+ unsigned long flags;
+
+ if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ return -EINVAL;
+
+ spin_lock_irqsave(&pci_config_lock, flags);
+
+ outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+ switch (len) {
+ case 1:
+ *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+ break;
+ case 2:
+ *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+ break;
+ case 4:
+ *value = inl_quad(0xCFC, BUS2QUAD(bus));
+ break;
+ }
+
+ spin_unlock_irqrestore(&pci_config_lock, flags);
+
+ return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
+{
+ unsigned long flags;
+
+ if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ return -EINVAL;
+
+ spin_lock_irqsave(&pci_config_lock, flags);
+
+ outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+ switch (len) {
+ case 1:
+ outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+ break;
+ case 2:
+ outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+ break;
+ case 4:
+ outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+ break;
+ }
+
+ spin_unlock_irqrestore(&pci_config_lock, flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_MULTIQUAD */
#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */
{
unsigned long flags;
@@ -70,7 +142,7 @@
return 0;
}
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* !CONFIG_MULTIQUAD */
{
unsigned long flags;
@@ -98,6 +170,8 @@
return 0;
}
+#endif /* CONFIG_MULTIQUAD */
+
#undef PCI_CONF1_ADDRESS
static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
@@ -347,7 +421,7 @@
pci_sanity_check(&pci_direct_conf1)) {
outl (tmp, 0xCF8);
__restore_flags(flags);
- printk("PCI: Using configuration type 1\n");
+ printk(KERN_INFO "PCI: Using configuration type 1\n");
request_region(0xCF8, 8, "PCI conf1");
return &pci_direct_conf1;
}
@@ -364,7 +438,7 @@
if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
pci_sanity_check(&pci_direct_conf2)) {
__restore_flags(flags);
- printk("PCI: Using configuration type 2\n");
+ printk(KERN_INFO "PCI: Using configuration type 2\n");
request_region(0xCF8, 4, "PCI conf2");
return &pci_direct_conf2;
}
@@ -472,10 +546,10 @@
case 0:
return address + entry;
case 0x80: /* Not present */
- printk("bios32_service(0x%lx): not present\n", service);
+ printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
return 0;
default: /* Shouldn't happen */
- printk("bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
+ printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
service, return_code);
return 0;
}
@@ -525,7 +599,7 @@
status, signature);
return 0;
}
- printk("PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
+ printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
#ifdef CONFIG_PCI_DIRECT
if (!(hw_mech & PCIBIOS_HW_TYPE1))
@@ -827,7 +901,7 @@
}
}
if (ln == &pci_devices) {
- printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+ printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
/*
* We must not continue scanning as several buggy BIOSes
* return garbage after the last device. Grr.
@@ -836,7 +910,7 @@
}
}
if (!found) {
- printk("PCI: Device %02x:%02x not found by BIOS\n",
+ printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
dev->bus->number, dev->devfn);
list_del(&dev->global_list);
list_add_tail(&dev->global_list, &sorted_devices);
@@ -896,7 +970,7 @@
rt->size = opt.size + sizeof(struct irq_routing_table);
rt->exclusive_irqs = map;
memcpy(rt->slots, (void *) page, opt.size);
- printk("PCI: Using BIOS Interrupt Routing Table\n");
+ printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
}
}
free_page(page);
@@ -961,7 +1035,7 @@
}
if (!seen_host_bridge)
return;
- printk("PCI: Ignoring ghost devices on bus %02x\n", b->number);
+ printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
ln = &b->devices;
while (ln->next != &b->devices) {
@@ -999,7 +1073,7 @@
if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
l != 0x0000 && l != 0xffff) {
DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
- printk("PCI: Discovered peer bus %02x\n", n);
+ printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
pci_scan_bus(n, pci_root_ops, NULL);
break;
}
@@ -1017,6 +1091,9 @@
*/
int pxb, reg;
u8 busno, suba, subb;
+#ifdef CONFIG_MULTIQUAD
+ int quad = BUS2QUAD(d->bus->number);
+#endif
printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
reg = 0xd0;
for(pxb=0; pxb<2; pxb++) {
@@ -1025,9 +1102,9 @@
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
- pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */
+ pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL); /* Bus A */
if (suba < subb)
- pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */
+ pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL); /* Bus B */
}
pcibios_last_bus = -1;
}
@@ -1040,7 +1117,7 @@
*/
u8 busno;
pci_read_config_byte(d, 0x4a, &busno);
- printk("PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
+ printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
pci_scan_bus(busno, pci_root_ops, NULL);
pcibios_last_bus = -1;
}
@@ -1053,11 +1130,23 @@
*/
int i;
- printk("PCI: Fixing base address flags for device %s\n", d->slot_name);
+ printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name);
for(i=0; i<4; i++)
d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
}
+static void __devinit pci_fixup_ncr53c810(struct pci_dev *d)
+{
+ /*
+ * NCR 53C810 returns class code 0 (at least on some systems).
+ * Fix class to be PCI_CLASS_STORAGE_SCSI
+ */
+ if (!d->class) {
+ printk("PCI: fixing NCR 53C810 class code for %s\n", d->slot_name);
+ d->class = PCI_CLASS_STORAGE_SCSI << 8;
+ }
+}
+
static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
@@ -1110,27 +1199,48 @@
/*
* Addresses issues with problems in the memory write queue timer in
- * certain VIA Northbridges. This bugfix is per VIA's specifications.
- *
+ * certain VIA Northbridges. This bugfix is per VIA's specifications,
+ * except for the KL133/KM133: clearing bit 5 on those Northbridges seems
+ * to trigger a bug in its integrated ProSavage video card, which
+ * causes screen corruption. We only clear bits 6 and 7 for that chipset,
+ * until VIA can provide us with definitive information on why screen
+ * corruption occurs, and what exactly those bits do.
+ *
* VIA 8363,8622,8361 Northbridges:
* - bits 5, 6, 7 at offset 0x55 need to be turned off
* VIA 8367 (KT266x) Northbridges:
* - bits 5, 6, 7 at offset 0x95 need to be turned off
+ * VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges:
+ * - bits 6, 7 at offset 0x55 need to be turned off
*/
+
+#define VIA_8363_KL133_REVISION_ID 0x81
+#define VIA_8363_KM133_REVISION_ID 0x84
+
static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
{
u8 v;
+ u8 revision;
int where = 0x55;
+ int mask = 0x1f; /* clear bits 5, 6, 7 by default */
+ pci_read_config_byte(d, PCI_REVISION_ID, &revision);
+
if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
where = 0x95; /* the memory write queue timer register is
- different for the kt266x's: 0x95 not 0x55 */
+ different for the KT266x's: 0x95 not 0x55 */
+ } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
+ (revision == VIA_8363_KL133_REVISION_ID ||
+ revision == VIA_8363_KM133_REVISION_ID)) {
+ mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5
+ causes screen corruption on the KL133/KM133 */
}
pci_read_config_byte(d, where, &v);
- if (v & 0xe0) {
- printk("Disabling VIA memory write queue: [%02x] %02x->%02x\n", where, v, v & 0x1f);
- v &= 0x1f; /* clear bits 5, 6, 7 */
+ if (v & ~mask) {
+ printk("Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
+ d->device, revision, where, v, mask, v & mask);
+ v &= mask;
pci_write_config_byte(d, where, v);
}
}
@@ -1148,6 +1258,7 @@
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 },
{ 0 }
};
@@ -1199,15 +1310,25 @@
void __init pcibios_init(void)
{
+ int quad;
+
if (!pci_root_ops)
pcibios_config_init();
if (!pci_root_ops) {
- printk("PCI: System does not support PCI\n");
+ printk(KERN_WARNING "PCI: System does not support PCI\n");
return;
}
- printk("PCI: Probing PCI hardware\n");
+ printk(KERN_INFO "PCI: Probing PCI hardware\n");
pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+ if (clustered_apic_mode && (numnodes > 1)) {
+ for (quad = 1; quad < numnodes; ++quad) {
+ printk("Scanning PCI bus %d for quad %d\n",
+ QUADLOCAL2BUS(quad,0), quad);
+ pci_scan_bus(QUADLOCAL2BUS(quad,0),
+ pci_root_ops, NULL);
+ }
+ }
pcibios_irq_init();
pcibios_fixup_peer_bridges();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)