[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-smp
Subject:    Re: Level Mode PCI interrupts on SMP
From:       James Bottomley <James.Bottomley () columbiasc ! ncr ! com>
Date:       1999-03-29 15:59:16
[Download RAW message or body]

This is a multipart MIME message.


> The SMP machine (dual pentium very old) configures the interrupt into
> edge mode (as far as I can tell from /proc/interrupts see below)
> however the card uses level mode interrupts.

There may be a problem with edge/level interrupts if you have an EISA 
motherboard, which I see you do:

> Bus #0 is EISA
> Bus #1 is PCI

The problem is that a 16 pin IO-APIC may choose to set up the PCI interrupts 
as EISA conforming.  In that case Linux currently sets them all to edge 
instead of reading the EISA Level Control Register to see what they should be. 
 The attached patch (against Linux-2.2.4) should fix this.

James Bottomley



["eisa_2.2.4.diff" (text/plain)]

Index: linux/arch/i386/kernel/io_apic.c
===================================================================
RCS file: /home/jejb/CVSROOT/linux/arch/i386/kernel/io_apic.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 io_apic.c
--- io_apic.c	1999/03/18 18:33:35	1.1.1.1
+++ io_apic.c	1999/03/29 15:52:38
@@ -293,7 +293,8 @@
 	for (i = 0; i < mp_irq_entries; i++) {
 		int lbus = mp_irqs[i].mpc_srcbus;
 
-		if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA) &&
+		if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
+		     mp_bus_id_to_type[lbus] == MP_BUS_EISA) &&
 		    (mp_irqs[i].mpc_irqtype == type) &&
 		    (mp_irqs[i].mpc_srcbusirq == 0x00))
 
@@ -326,20 +327,7 @@
 }
 
 /*
- * Unclear documentation on what a "conforming ISA interrupt" means.
- *
- * Should we, or should we not, take the ELCR register into account?
- * It's part of the EISA specification, but maybe it should only be
- * used if the interrupt is actually marked as EISA?
- *
- * Oh, well. Don't do it until somebody tells us what the right thing
- * to do is..
- */
-#undef USE_ELCR_TRIGGER_LEVEL
-#ifdef USE_ELCR_TRIGGER_LEVEL
-
-/*
- * ISA Edge/Level control register, ELCR
+ * EISA Edge/Level control register, ELCR
  */
 static int __init EISA_ELCR(unsigned int irq)
 {
@@ -349,18 +337,22 @@
 	}
 	printk("Broken MPtable reports ISA irq %d\n", irq);
 	return 0;
-}	
+}
 
-#define default_ISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_dstirq))
-#define default_ISA_polarity(idx)	(0)
+/* EISA interrupts are always polarity zero and can be edge or level
+ * trigger depending on the ELCR value.  If an interrupt is listed as
+ * EISA conforming in the MP table, that means its trigger type must
+ * be read in from the ELCR */
 
-#else
+#define default_EISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_dstirq))
+#define default_EISA_polarity(idx)	(0)
+
+/* ISA interrupts are always polarity zero edge triggered, even when
+ * listed as conforming in the MP table. */
 
 #define default_ISA_trigger(idx)	(0)
 #define default_ISA_polarity(idx)	(0)
 
-#endif
-
 static int __init MPBIOS_polarity(int idx)
 {
 	int bus = mp_irqs[idx].mpc_srcbus;
@@ -380,6 +372,11 @@
 					polarity = default_ISA_polarity(idx);
 					break;
 				}
+				case MP_BUS_EISA:
+				{
+					polarity = default_EISA_polarity(idx);
+					break;
+				}
 				case MP_BUS_PCI: /* PCI pin */
 				{
 					polarity = 1;
@@ -439,6 +436,11 @@
 					trigger = default_ISA_trigger(idx);
 					break;
 				}
+				case MP_BUS_EISA:
+				{
+					trigger = default_EISA_trigger(idx);
+					break;
+				}
 				case MP_BUS_PCI: /* PCI pin, level */
 				{
 					trigger = 1;
@@ -503,6 +505,7 @@
 	switch (mp_bus_id_to_type[bus])
 	{
 		case MP_BUS_ISA: /* ISA pin */
+		case MP_BUS_EISA:
 		{
 			irq = mp_irqs[idx].mpc_srcbusirq;
 			break;
@@ -910,6 +913,8 @@
 static void __init construct_default_ISA_mptable(void)
 {
 	int i, pos = 0;
+	const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 ||
+			      mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA;
 
 	for (i = 0; i < 16; i++) {
 		if (!IO_APIC_IRQ(i))
@@ -917,14 +922,14 @@
 
 		mp_irqs[pos].mpc_irqtype = mp_INT;
 		mp_irqs[pos].mpc_irqflag = 0;		/* default */
-		mp_irqs[pos].mpc_srcbus = MP_BUS_ISA;
+		mp_irqs[pos].mpc_srcbus = bus_type;
 		mp_irqs[pos].mpc_srcbusirq = i;
 		mp_irqs[pos].mpc_dstapic = 0;
 		mp_irqs[pos].mpc_dstirq = i;
 		pos++;
 	}
 	mp_irq_entries = pos;
-	mp_bus_id_to_type[0] = MP_BUS_ISA;
+	mp_bus_id_to_type[0] = bus_type;
 
 	/*
 	 * MP specification 1.4 defines some extra rules for default
Index: linux/arch/i386/kernel/irq.h
===================================================================
RCS file: /home/jejb/CVSROOT/linux/arch/i386/kernel/irq.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 irq.h
--- irq.h	1999/03/18 18:33:35	1.1.1.1
+++ irq.h	1999/03/29 15:52:38
@@ -115,6 +115,7 @@
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
 	MP_BUS_ISA,
+	MP_BUS_EISA,
 	MP_BUS_PCI
 };
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
Index: linux/arch/i386/kernel/smp.c
===================================================================
RCS file: /home/jejb/CVSROOT/linux/arch/i386/kernel/smp.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 smp.c
--- smp.c	1999/03/24 13:46:27	1.1.1.2
+++ smp.c	1999/03/29 15:52:38
@@ -345,11 +345,13 @@
 				SMP_PRINTK(("Bus #%d is %s\n",
 					m->mpc_busid,
 					str));
-				if ((strncmp(m->mpc_bustype,"ISA",3) == 0) ||
-					(strncmp(m->mpc_bustype,"EISA",4) == 0))
+				if (strncmp(m->mpc_bustype,"ISA",3) == 0)
 					mp_bus_id_to_type[m->mpc_busid] =
 						MP_BUS_ISA;
 				else
+				if (strncmp(m->mpc_bustype,"EISA",4) == 0)
+					mp_bus_id_to_type[m->mpc_busid] =
+						MP_BUS_EISA;
 				if (strncmp(m->mpc_bustype,"PCI",3) == 0) {
 					mp_bus_id_to_type[m->mpc_busid] =
 						MP_BUS_PCI;

-
Linux SMP list: FIRST see FAQ at http://www.irisa.fr/prive/mentre/smp-faq/
To Unsubscribe: send "unsubscribe linux-smp" to majordomo@vger.rutgers.edu


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic