patch-2.4.0-test12 linux/arch/i386/kernel/pci-irq.c
Next file: linux/arch/i386/kernel/process.c
Previous file: linux/arch/i386/kernel/mtrr.c
Back to the patch index
Back to the overall index
- Lines: 217
- Date:
Mon Dec 11 17:45:09 2000
- Orig file:
v2.4.0-test11/linux/arch/i386/kernel/pci-irq.c
- Orig date:
Sun Nov 19 18:44:03 2000
diff -u --recursive --new-file v2.4.0-test11/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
@@ -176,7 +176,6 @@
pci_read_config_byte(router, reg, &x);
x = (x & 0xe0) | val; /* clear the level->edge transform */
pci_write_config_byte(router, reg, x);
- eisa_set_level_irq(irq);
}
static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -196,7 +195,6 @@
pirq_ali_ide_interrupt(router, 0x75, val, irq);
break;
}
- eisa_set_level_irq(irq);
return 1;
}
return 0;
@@ -279,6 +277,54 @@
return 1;
}
+static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ u8 x;
+ int reg = 0x41 + (pirq - 'A') ;
+
+ pci_read_config_byte(router, reg, &x);
+ return (x & 0x80) ? 0 : (x & 0x0f);
+}
+
+static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+ u8 x;
+ int reg = 0x41 + (pirq - 'A') ;
+
+ pci_read_config_byte(router, reg, &x);
+ x = (pirq & 0x20) ? 0 : (irq & 0x0f);
+ pci_write_config_byte(router, reg, x);
+
+ return 1;
+}
+
+/*
+ * VLSI: nibble offset 0x74 - educated guess due to routing table and
+ * config space of VLSI 82C534 PCI-bridge/router (1004:0102)
+ * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
+ * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
+ * for the busbridge to the docking station.
+ */
+
+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ if (pirq > 8) {
+ printk("VLSI router pirq escape (%d)\n", pirq);
+ return 0;
+ }
+ return read_config_nybble(router, 0x74, pirq-1);
+}
+
+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+ if (pirq > 8) {
+ printk("VLSI router pirq escape (%d)\n", pirq);
+ return 0;
+ }
+ write_config_nybble(router, 0x74, pirq-1, irq);
+ return 1;
+}
+
#ifdef CONFIG_PCI_BIOS
static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -309,7 +355,8 @@
{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
-
+ { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
+ { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
{ "default", 0, 0, NULL, NULL }
};
@@ -355,7 +402,7 @@
pirq_router_dev->slot_name);
}
-static struct irq_info *pirq_get_info(struct pci_dev *dev, int pin)
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
{
struct irq_routing_table *rt = pirq_table;
int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
@@ -373,25 +420,28 @@
static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
+ u8 pin;
struct irq_info *info;
- int i, pirq, pin, newirq;
+ int i, pirq, newirq;
int irq = 0;
u32 mask;
struct irq_router *r = pirq_router;
- struct pci_dev *dev2, *d;
+ struct pci_dev *dev2;
char *msg = NULL;
if (!pirq_table)
return 0;
/* Find IRQ routing entry */
- pin = pci_get_interrupt_pin(dev, &d);
- if (pin < 0) {
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (!pin) {
DBG(" -> no interrupt pin\n");
return 0;
}
- DBG("IRQ for %s(%d) via %s", dev->slot_name, pin, d->slot_name);
- info = pirq_get_info(d, pin);
+ pin = pin - 1;
+
+ DBG("IRQ for %s:%d", dev->slot_name, pin);
+ info = pirq_get_info(dev);
if (!info) {
DBG(" -> not found in routing table\n");
return 0;
@@ -405,9 +455,12 @@
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
mask &= pcibios_irq_mask;
- /* Find the best IRQ to assign */
- newirq = 0;
- if (assign) {
+ /*
+ * Find the best IRQ to assign: use the one
+ * reported by the device if possible.
+ */
+ newirq = dev->irq;
+ if (!newirq && assign) {
for (i = 0; i < 16; i++) {
if (!(mask & (1 << i)))
continue;
@@ -417,16 +470,22 @@
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))) {
+ if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {
DBG(" -> got IRQ %d\n", irq);
msg = "Found";
+ /* We refuse to override the dev->irq information. Give a warning! */
+ if (dev->irq && dev->irq != irq) {
+ printk("IRQ routing conflict in pirq table! Try 'pci=autoirq'\n");
+ return 0;
+ }
} 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)) {
+ if (r->set(pirq_router_dev, dev, pirq, newirq)) {
+ eisa_set_level_irq(newirq);
DBG(" ... OK\n");
msg = "Assigned";
irq = newirq;
@@ -445,9 +504,14 @@
/* Update IRQ for all devices with the same pirq value */
pci_for_each_dev(dev2) {
- if ((pin = pci_get_interrupt_pin(dev2, &d)) >= 0 &&
- (info = pirq_get_info(d, pin)) &&
- info->irq[pin].link == pirq) {
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
+ if (!pin)
+ continue;
+ pin--;
+ info = pirq_get_info(dev2);
+ if (!info)
+ continue;
+ if (info->irq[pin].link == pirq) {
dev2->irq = irq;
pirq_penalty[irq]++;
if (dev != dev2)
@@ -556,19 +620,17 @@
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);
- }
+ u8 pin;
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+ 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)