i386: Always set LINTEN for AMD CPUs if their family >= 0xF
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 19 Dec 2011 11:33:30 +0000 (19:33 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 19 Dec 2011 11:38:15 +0000 (19:38 +0800)
Since LINTEN will take effect when LAPIC is hardware enabled,
so we defer the LINTEN turning on when we know LAPIC will be
software enabled.

This fixes the recent MI per-cpu interrupt information array
support on AMD CPUs when IOAPIC is disabled on SMP system.

sys/platform/pc32/apic/lapic.c
sys/platform/pc32/i386/initcpu.c

index 80ebd58..4c39d27 100644 (file)
@@ -35,6 +35,7 @@
 #include <machine/cputypes.h>
 #include <machine/md_var.h>
 #include <machine/pmap.h>
+#include <machine/specialreg.h>
 #include <machine_base/apic/lapic.h>
 #include <machine_base/apic/ioapic.h>
 #include <machine_base/apic/ioapic_abi.h>
@@ -110,6 +111,40 @@ lapic_init(boolean_t bsp)
         * only need to be installed once; we do it on BSP.
         */
        if (bsp) {
+               if (cpu_vendor_id == CPU_VENDOR_AMD &&
+                   CPUID_TO_FAMILY(cpu_id) >= 0xf) {
+                       uint32_t tcr;
+
+                       /*
+                        * Set the LINTEN bit in the HyperTransport
+                        * Transaction Control Register.
+                        *
+                        * This will cause EXTINT and NMI interrupts
+                        * routed over the hypertransport bus to be
+                        * fed into the LAPIC LINT0/LINT1.  If the bit
+                        * isn't set, the interrupts will go to the
+                        * general cpu INTR/NMI pins.  On a dual-core
+                        * cpu the interrupt winds up going to BOTH cpus.
+                        * The first cpu that does the interrupt ack
+                        * cycle will get the correct interrupt.  The
+                        * second cpu that does it will get a spurious
+                        * interrupt vector (typically IRQ 7).
+                        */
+                       outl(0x0cf8,
+                           (1 << 31) | /* enable */
+                           (0 << 16) | /* bus */
+                           (0x18 << 11) | /* dev (cpu + 0x18) */
+                           (0 << 8) |  /* func */
+                           0x68        /* reg */
+                           );
+                       tcr = inl(0xcfc);
+                       if ((tcr & 0x00010000) == 0) {
+                               kprintf("LAPIC: AMD LINTEN on\n");
+                               outl(0xcfc, tcr|0x00010000);
+                       }
+                       outl(0x0cf8, 0);
+               }
+
                /* Install a 'Spurious INTerrupt' vector */
                setidt(XSPURIOUSINT_OFFSET, Xspuriousint,
                    SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
index 1ad772a..8e7df82 100644 (file)
@@ -619,37 +619,6 @@ init_686_amd(void)
                cpu_feature = regs[3];
        }
 #endif
-#ifdef CPU_AMD64X2_INTR_SPAM
-       /*
-        * Set the LINTEN bit in the HyperTransport Transaction
-        * Control Register.
-        *
-        * This will cause EXTINT and NMI interrupts routed over the
-        * hypertransport bus to be fed into the LAPIC LINT0/LINT1.  If
-        * the bit isn't set, the interrupts will go to the general cpu
-        * INTR/NMI pins.  On a dual-core cpu the interrupt winds up
-        * going to BOTH cpus.  The first cpu that does the interrupt ack
-        * cycle will get the correct interrupt.  The second cpu that does
-        * it will get a spurious interrupt vector (typically IRQ 7).
-        */
-       if ((cpu_id & 0xff0) == 0xf30) {
-           int32_t tcr;
-           outl(0x0cf8,
-                   (1 << 31) | /* enable */
-                   (0 << 16) | /* bus */
-                   (24 << 11) |        /* dev (cpu + 24) */
-                   (0 << 8) |  /* func */
-                   0x68                /* reg */
-           );
-           tcr = inl(0xcfc);
-           if ((tcr & 0x00010000) == 0) {
-                   outl(0xcfc, tcr|0x00010000);
-                   additional_cpu_info("AMD: Rerouting HyperTransport "
-                                       "EXTINT/NMI to APIC");
-           }
-           outl(0x0cf8, 0);
-       }
-#endif
 }
 #endif /* I686_CPU */