x86_64: Handle I/O APIC probing failure
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 15 May 2011 06:50:30 +0000 (14:50 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 15 May 2011 07:04:47 +0000 (15:04 +0800)
If I/O APIC does not exist:
- Reset apic_io_enable and reinitialize ICU if necessary; mainly for
  ICU's auto EOI setting.
- Enable LAPIC LINT0 and disable LAPIC LINT1

While I'm here, add hw.ioapic_probe tunable to test this feature (again,
just don't it :)

sys/platform/pc64/apic/ioapic.c
sys/platform/pc64/apic/ioapic.h
sys/platform/pc64/apic/lapic.c
sys/platform/pc64/apic/lapic.h
sys/platform/pc64/x86_64/mp_machdep.c

index 28e45f5..dcaeae0 100644 (file)
@@ -84,13 +84,13 @@ static struct ioapic_conf   ioapic_conf;
 static TAILQ_HEAD(, ioapic_enumerator) ioapic_enumerators =
        TAILQ_HEAD_INITIALIZER(ioapic_enumerators);
 
-void
+int
 ioapic_config(void)
 {
        struct ioapic_enumerator *e;
        struct ioapic_info *info;
        int start_apic_id = 0;
-       int error, i;
+       int error, i, probe;
        register_t ef = 0;
 
        TAILQ_INIT(&ioapic_conf.ioc_list);
@@ -98,18 +98,21 @@ ioapic_config(void)
        for (i = 0; i < 16; ++i)
                ioapic_conf.ioc_intsrc[i].int_gsi = -1;
 
+       probe = 1;
+       TUNABLE_INT_FETCH("hw.ioapic_probe", &probe);
+       if (!probe) {
+               kprintf("IOAPIC: warning I/O APIC will not be probed\n");
+               return ENXIO;
+       }
+
        TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
                error = e->ioapic_probe(e);
                if (!error)
                        break;
        }
        if (e == NULL) {
-#ifdef notyet
-               panic("can't config I/O APIC\n");
-#else
-               kprintf("no I/O APIC\n");
-               return;
-#endif
+               kprintf("IOAPIC: can't find I/O APIC\n");
+               return ENXIO;
        }
 
        crit_enter();
@@ -206,6 +209,8 @@ ioapic_config(void)
        MachIntrABI.cleanup();
 
        crit_exit();
+
+       return 0;
 }
 
 void
index 5b12f0e..ff22fea 100644 (file)
@@ -51,7 +51,7 @@ struct ioapic_enumerator {
 #define IOAPIC_ENUM_PRIO_MPTABLE       20
 #define IOAPIC_ENUM_PRIO_MADT          40
 
-void   ioapic_config(void);
+int    ioapic_config(void);
 void   ioapic_enumerator_register(struct ioapic_enumerator *);
 void   ioapic_add(void *, int, int);
 void   ioapic_intsrc(int, int, enum intr_trigger, enum intr_polarity);
index d57221a..d0e5b05 100644 (file)
@@ -764,3 +764,21 @@ lapic_set_cpuid(int cpu_id, int apic_id)
        CPUID_TO_APICID(cpu_id) = apic_id;
        APICID_TO_CPUID(apic_id) = cpu_id;
 }
+
+void
+lapic_fixup_noioapic(void)
+{
+       u_int   temp;
+
+       /* Only allowed on BSP */
+       KKASSERT(mycpuid == 0);
+       KKASSERT(!apic_io_enable);
+
+       temp = lapic->lvt_lint0;
+       temp &= ~APIC_LVT_MASKED;
+       lapic->lvt_lint0 = temp;
+
+       temp = lapic->lvt_lint1;
+       temp |= APIC_LVT_MASKED;
+       lapic->lvt_lint1 = temp;
+}
index 5859a35..4e6e03d 100644 (file)
@@ -87,5 +87,6 @@ all_but_self_ipi(int vector)
 
 void   lapic_map(vm_offset_t /* XXX should be vm_paddr_t */);
 int    lapic_unused_apic_id(int);
+void   lapic_fixup_noioapic(void);
 
 #endif /* _ARCH_APIC_LAPIC_H_ */
index 44a9745..c4c8c53 100644 (file)
@@ -363,8 +363,14 @@ mp_enable(u_int boot_addr)
        /* start each Application Processor */
        start_all_aps(boot_addr);
 
-       if (apic_io_enable)
-               ioapic_config();
+       if (apic_io_enable) {
+               error = ioapic_config();
+               if (error) {
+                       apic_io_enable = 0;
+                       icu_reinit_noioapic();
+                       lapic_fixup_noioapic();
+               }
+       }
 }
 
 /*