patch-2.4.0-test2 linux/arch/i386/kernel/pci-irq.c
Next file: linux/arch/i386/kernel/pci-pc.c
Previous file: linux/arch/i386/kernel/pci-i386.h
Back to the patch index
Back to the overall index
- Lines: 197
- Date:
Fri Jun 23 19:50:50 2000
- Orig file:
v2.4.0-test1/linux/arch/i386/kernel/pci-irq.c
- Orig date:
Tue May 23 15:31:33 2000
diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
@@ -14,11 +14,11 @@
#include <linux/irq.h>
#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/io_apic.h>
#include "pci-i386.h"
-extern int skip_ioapic_setup;
-
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
@@ -27,13 +27,13 @@
/*
* 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)
+ * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
*/
unsigned int pcibios_irq_mask = 0xfff8;
-static unsigned pirq_penalty[16] = {
- 10000, 10000, 10000, 100, 100, 0, 0, 100,
- 0, 0, 0, 0, 100, 1000, 1000, 1000
+static int pirq_penalty[16] = {
+ 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
+ 0, 0, 0, 0, 1000, 100000, 100000, 100000
};
struct irq_router {
@@ -128,14 +128,13 @@
static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+ u8 x;
+ unsigned reg;
+
pirq--;
- if (pirq < 8) {
- u8 x;
- unsigned reg = 0x48 + (pirq >> 1);
- pci_read_config_byte(router, reg, &x);
- return irqmap[(pirq & 1) ? (x >> 4) : (x & 0x0f)];
- }
- return 0;
+ reg = 0x48 + (pirq >> 1);
+ pci_read_config_byte(router, reg, &x);
+ return irqmap[(pirq & 1) ? (x >> 4) : (x & 0x0f)];
}
static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -143,7 +142,7 @@
static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
unsigned int val = irqmap[irq];
pirq--;
- if (val && pirq < 8) {
+ if (val) {
u8 x;
unsigned reg = 0x48 + (pirq >> 1);
pci_read_config_byte(router, reg, &x);
@@ -222,7 +221,7 @@
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
- { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82440MX_1, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
@@ -287,7 +286,11 @@
return NULL;
}
-int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
struct irq_info *info;
int i, pirq, pin, newirq;
@@ -323,19 +326,24 @@
/* Find the best IRQ to assign */
newirq = 0;
- for (i = 0; i < 16; i++) {
- if (!(mask & (1 << i)))
- continue;
- if (pirq_penalty[i] < pirq_penalty[newirq])
- newirq = i;
+ if (assign) {
+ for (i = 0; i < 16; i++) {
+ if (!(mask & (1 << i)))
+ continue;
+ if (pirq_penalty[i] < pirq_penalty[newirq] &&
+ !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
+ free_irq(i, dev);
+ newirq = i;
+ }
+ }
+ DBG(" -> newirq=%d", newirq);
}
- DBG(" -> newirq=%d", newirq);
/* Try to get current IRQ */
if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) {
DBG(" -> got IRQ %d\n", irq);
msg = "Found";
- } else if (assign && newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+ } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
DBG(" -> assigning IRQ %d", newirq);
if (r->set(pirq_router_dev, d, pirq, newirq)) {
DBG(" ... OK\n");
@@ -346,7 +354,7 @@
if (!irq) {
DBG(" ... failed\n");
- if (assign && newirq && mask == (1 << newirq)) {
+ if (newirq && mask == (1 << newirq)) {
msg = "Guessed";
irq = newirq;
} else
@@ -379,6 +387,15 @@
if (pirq_table) {
pirq_peer_trick();
pirq_find_router();
+ if (pirq_table->exclusive_irqs) {
+ int i;
+ for (i=0; i<16; i++)
+ if (!(pirq_table->exclusive_irqs & (1 << i)))
+ pirq_penalty[i] += 100;
+ }
+ /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
+ if (io_apic_assign_pci_irqs)
+ pirq_table = NULL;
}
}
@@ -397,16 +414,19 @@
DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
dev->irq = 0;
}
+ /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
+ if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
+ pirq_penalty[dev->irq] = 0;
pirq_penalty[dev->irq]++;
}
pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-#if defined(CONFIG_X86_IO_APIC)
+#ifdef CONFIG_X86_IO_APIC
/*
* Recalculate IRQ numbers if we use the I/O APIC.
*/
- if (!skip_ioapic_setup)
+ if (io_apic_assign_pci_irqs)
{
int irq;
@@ -441,5 +461,33 @@
*/
if (pin && !dev->irq)
pcibios_lookup_irq(dev, 0);
+ }
+}
+
+void __init pcibios_penalize_isa_irq(int irq)
+{
+ /*
+ * If any ISAPnP device reports an IRQ in its list of possible
+ * IRQ's, we try to avoid assigning it to PCI devices.
+ */
+ pirq_penalty[irq] += 100;
+}
+
+void pcibios_enable_irq(struct pci_dev *dev)
+{
+ if (!dev->irq) {
+ u8 pin;
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin && !pcibios_lookup_irq(dev, 1)) {
+ char *msg;
+ if (io_apic_assign_pci_irqs)
+ msg = " Probably buggy MP table.";
+ else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+ msg = "";
+ else
+ msg = " Please try using pci=biosirq.";
+ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+ 'A' + pin - 1, dev->slot_name, msg);
+ }
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)