patch-2.3.44 linux/arch/i386/kernel/pci-pc.c
Next file: linux/arch/i386/kernel/setup.c
Previous file: linux/arch/i386/kernel/mpparse.c
Back to the patch index
Back to the overall index
- Lines: 156
- Date:
Sat Feb 12 09:27:14 2000
- Orig file:
v2.3.43/linux/arch/i386/kernel/pci-pc.c
- Orig date:
Thu Feb 10 17:11:03 2000
diff -u --recursive --new-file v2.3.43/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
@@ -883,6 +883,18 @@
}
}
+static void __init pci_fixup_i450gx(struct pci_dev *d)
+{
+ /*
+ * i450GX and i450KX -- Find and scan all secondary buses.
+ * (called separately for each PCI bridge found)
+ */
+ u8 busno;
+ pci_read_config_byte(d, 0x4a, &busno);
+ printk("PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
+ pci_scan_bus(busno, pci_root_ops, NULL);
+}
+
static void __init pci_fixup_rcc(struct pci_dev *d)
{
/*
@@ -954,6 +966,7 @@
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_HE, pci_fixup_rcc },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_LE, pci_fixup_rcc },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq },
@@ -1036,6 +1049,18 @@
* table, but unfortunately we have to know the interrupt router chip.
*/
+/*
+ * Never use: 0, 1, 2 (timer, keyboard, and cascade)
+ * Avoid using: 13, 14 and 15 (FP error and IDE).
+ * Penalize: 3, 4, 7, 12 (known ISA uses: serial, parallel and mouse)
+ */
+static unsigned int pcibios_irq_mask = 0xfff8;
+
+static unsigned pcibios_irq_penalty[16] = {
+ 1000, 1000, 1000, 10, 10, 0, 0, 10,
+ 0, 0, 0, 0, 10, 100, 100, 100
+};
+
static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign)
{
struct irq_info *q;
@@ -1043,6 +1068,7 @@
int i, pirq, newirq;
u32 rtrid, mask;
u8 x;
+ char *msg = NULL;
pin--;
DBG("IRQ for %s(%d)", dev->slot_name, pin);
@@ -1066,10 +1092,15 @@
return NULL;
}
DBG(" -> PIRQ %02x, mask %04x", pirq, mask);
- if (!assign || (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- newirq = 0;
- else for(newirq = 13; newirq && !(mask & (1 << newirq)); newirq--)
- ;
+ newirq = 0;
+ if (assign && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+ for (i = 0; i < 16; i++) {
+ if (!(mask & pcibios_irq_mask & (1 << i)))
+ continue;
+ if (pcibios_irq_penalty[i] < pcibios_irq_penalty[newirq])
+ newirq = i;
+ }
+ }
if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
DBG(" -> router not found\n");
return NULL;
@@ -1094,27 +1125,30 @@
pci_read_config_byte(router, pirq, &x);
if (x < 16) {
DBG(" -> [PIIX] %02x\n", x);
- dev->irq = x;
- return "PIIX";
+ newirq = x;
+ msg = "PIIX";
} else if (newirq) {
DBG(" -> [PIIX] set to %02x\n", newirq);
pci_write_config_byte(router, pirq, newirq);
- dev->irq = newirq;
- return "PIIX-NEW";
- }
- DBG(" -> [PIIX] sink\n");
- return NULL;
+ msg = "PIIX-NEW";
+ } else
+ DBG(" -> [PIIX] sink\n");
+ break;
case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
default:
DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
if (newirq && mask == (1 << newirq)) {
/* Only one IRQ available -> use it */
- dev->irq = newirq;
- return "guess";
+ msg = "guess";
}
- return NULL;
}
#undef ID
+
+ if (msg) {
+ dev->irq = newirq;
+ pcibios_irq_penalty[newirq]++;
+ }
+ return msg;
}
static void __init pcibios_fixup_irqs(void)
@@ -1134,6 +1168,18 @@
pcibios_irq_peer_trick(rtable);
pci_for_each_dev(dev) {
+ /*
+ * If the BIOS has set an out of range IRQ number, just ignore it.
+ * Also keep track of which IRQ's are already in use.
+ */
+ if (dev->irq >= 16) {
+ DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
+ dev->irq = 0;
+ }
+ pcibios_irq_penalty[dev->irq]++;
+ }
+
+ pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
#if defined(CONFIG_X86_IO_APIC)
/*
@@ -1171,10 +1217,8 @@
}
#endif
/*
- * Fix out-of-range IRQ numbers and missing IRQs.
+ * Still no IRQ? Try to assign one...
*/
- if (dev->irq >= NR_IRQS)
- dev->irq = 0;
if (pin && !dev->irq && pirq_table) {
char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 0);
if (msg)
@@ -1279,6 +1323,9 @@
return NULL;
} else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
+ return NULL;
+ } else if (!strncmp(str, "irqmask=", 8)) {
+ pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
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)