Print this page
8620 pcplusmp shouldn't support x2APIC mode
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>

@@ -219,10 +219,13 @@
  * Maximum number of vectors in a CPU that can be used for interrupt
  * allocation (including IPIs and the reserved vectors).
  */
 int apix_cpu_nvectors = APIX_NVECTOR;
 
+/* number of CPUs in power-on transition state */
+static int apic_poweron_cnt = 0;
+
 /* gcpu.h */
 
 extern void apic_do_interrupt(struct regs *rp, trap_trace_rec_t *ttp);
 extern void apic_change_eoi();
 

@@ -2558,10 +2561,49 @@
         vecp = apix_intx_get_vector(irqno);
 
         return (vecp);
 }
 
+/*
+ * Switch between safe and x2APIC IPI sending method.
+ * The CPU may power on in xapic mode or x2apic mode. If the CPU needs to send
+ * an IPI to other CPUs before entering x2APIC mode, it still needs to use the
+ * xAPIC method. Before sending a StartIPI to the target CPU, psm_send_ipi will
+ * be changed to apic_common_send_ipi, which detects current local APIC mode and
+ * use the right method to send an IPI. If some CPUs fail to start up,
+ * apic_poweron_cnt won't return to zero, so apic_common_send_ipi will always be
+ * used. psm_send_ipi can't be simply changed back to x2apic_send_ipi if some
+ * CPUs failed to start up because those failed CPUs may recover itself later at
+ * unpredictable time.
+ */
+void
+apic_switch_ipi_callback(boolean_t enter)
+{
+        ulong_t iflag;
+        struct psm_ops *pops = psmops;
+
+        iflag = intr_clear();
+        lock_set(&apic_mode_switch_lock);
+        if (enter) {
+                ASSERT(apic_poweron_cnt >= 0);
+                if (apic_poweron_cnt == 0) {
+                        pops->psm_send_ipi = apic_common_send_ipi;
+                        send_dirintf = pops->psm_send_ipi;
+                }
+                apic_poweron_cnt++;
+        } else {
+                ASSERT(apic_poweron_cnt > 0);
+                apic_poweron_cnt--;
+                if (apic_poweron_cnt == 0) {
+                        pops->psm_send_ipi = x2apic_send_ipi;
+                        send_dirintf = pops->psm_send_ipi;
+                }
+        }
+        lock_clear(&apic_mode_switch_lock);
+        intr_restore(iflag);
+}
+
 /* stub function */
 int
 apix_loaded(void)
 {
         return (apix_is_enabled);