patch-2.4.0-test7 linux/arch/i386/kernel/apic.c

Next file: linux/arch/i386/kernel/entry.S
Previous file: linux/arch/i386/defconfig
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
@@ -7,7 +7,8 @@
  *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs;
  *					thanks to Eric Gilmore
  *					and Rolf G. Tews
- *					for testing these extensively
+ *					for testing these extensively.
+ *	Maciej W. Rozycki	:	Various updates and fixes.
  */
 
 #include <linux/config.h>
@@ -127,6 +128,67 @@
 	apic_write_around(APIC_SPIV, value);
 }
 
+/*
+ * This is to verify that we're looking at a real local APIC.
+ * Check these against your board if the CPUs aren't getting
+ * started for no apparent reason.
+ */
+int __init verify_local_APIC(void)
+{
+	unsigned int reg0, reg1;
+
+	/*
+	 * The version register is read-only in a real APIC.
+	 */
+	reg0 = apic_read(APIC_LVR);
+	Dprintk("Getting VERSION: %x\n", reg0);
+	apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK);
+	reg1 = apic_read(APIC_LVR);
+	Dprintk("Getting VERSION: %x\n", reg1);
+
+	/*
+	 * The two version reads above should print the same
+	 * numbers.  If the second one is different, then we
+	 * poke at a non-APIC.
+	 */
+	if (reg1 != reg0)
+		return 0;
+
+	/*
+	 * Check if the version looks reasonably.
+	 */
+	reg1 = GET_APIC_VERSION(reg0);
+	if (reg1 == 0x00 || reg1 == 0xff)
+		return 0;
+	reg1 = get_maxlvt();
+	if (reg1 < 0x02 || reg1 == 0xff)
+		return 0;
+
+	/*
+	 * The ID register is read/write in a real APIC.
+	 */
+	reg0 = apic_read(APIC_ID);
+	Dprintk("Getting ID: %x\n", reg0);
+	apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
+	reg1 = apic_read(APIC_ID);
+	Dprintk("Getting ID: %x\n", reg1);
+	apic_write(APIC_ID, reg0);
+	if (reg1 != (reg0 ^ APIC_ID_MASK))
+		return 0;
+
+	/*
+	 * The next two are just to see if we have sane values.
+	 * They're only really relevant if we're in Virtual Wire
+	 * compatibility mode, but most boxes are anymore.
+	 */
+	reg0 = apic_read(APIC_LVT0);
+	Dprintk("Getting LVT0: %x\n", reg0);
+	reg1 = apic_read(APIC_LVT1);
+	Dprintk("Getting LVT1: %x\n", reg1);
+
+	return 1;
+}
+
 void __init sync_Arb_IDs(void)
 {
 	/*
@@ -682,46 +744,28 @@
  * This interrupt should never happen with our APIC/SMP architecture
  */
 
-static spinlock_t err_lock = SPIN_LOCK_UNLOCKED;
-
 asmlinkage void smp_error_interrupt(void)
 {
-	unsigned long v;
-
-	spin_lock(&err_lock);
+	unsigned long v, v1;
 
+	/* First tickle the hardware, only then report what went on. -- REW */
 	v = apic_read(APIC_ESR);
-	printk(KERN_INFO "APIC error interrupt on CPU#%d, should never happen.\n",
-			smp_processor_id());
-	printk(KERN_INFO "... APIC ESR0: %08lx\n", v);
-
 	apic_write(APIC_ESR, 0);
-	v |= apic_read(APIC_ESR);
-	printk(KERN_INFO "... APIC ESR1: %08lx\n", v);
-	/*
-	 * Be a bit more verbose. (multiple bits can be set)
-	 */
-	if (v & 0x01)
-		printk(KERN_INFO "... bit 0: APIC Send CS Error (hw problem).\n");
-	if (v & 0x02)
-		printk(KERN_INFO "... bit 1: APIC Receive CS Error (hw problem).\n");
-	if (v & 0x04)
-		printk(KERN_INFO "... bit 2: APIC Send Accept Error.\n");
-	if (v & 0x08)
-		printk(KERN_INFO "... bit 3: APIC Receive Accept Error.\n");
-	if (v & 0x10)
-		printk(KERN_INFO "... bit 4: Reserved!.\n");
-	if (v & 0x20)
-		printk(KERN_INFO "... bit 5: Send Illegal Vector (kernel bug).\n");
-	if (v & 0x40)
-		printk(KERN_INFO "... bit 6: Received Illegal Vector.\n");
-	if (v & 0x80)
-		printk(KERN_INFO "... bit 7: Illegal Register Address.\n");
-
+	v1 = apic_read(APIC_ESR);
 	ack_APIC_irq();
-
 	irq_err_count++;
 
-	spin_unlock(&err_lock);
+	/* Here is what the APIC error bits mean:
+	   0: Send CS error
+	   1: Receive CS error
+	   2: Send accept error
+	   3: Receive accept error
+	   4: Reserved
+	   5: Send illegal vector
+	   6: Received illegal vector
+	   7: Illegal register address
+	*/
+	printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n",
+	        smp_processor_id(), v , v1);
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)