[kvm-unit-tests PATCH] x86: APIC IDs might not be consecutive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



APIC IDs do not have to be consecutive. Crease a map between logical CPU
identifiers and the physical APIC IDs for this matter and add a level of
indirection.

During boot, save in a bitmap the APIC IDs of the enabled CPU and use it
later when sending IPIs.

Signed-off-by: Nadav Amit <nadav.amit@xxxxxxxxx>
---
 lib/x86/apic-defs.h |  7 +++++++
 lib/x86/apic.c      | 13 +++++++++++++
 lib/x86/apic.h      |  3 +++
 lib/x86/smp.c       | 10 +++++++---
 x86/apic.c          | 10 +++++-----
 x86/cstart64.S      | 16 +++++++++++++++-
 6 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/lib/x86/apic-defs.h b/lib/x86/apic-defs.h
index e7c3e92..7107f0f 100644
--- a/lib/x86/apic-defs.h
+++ b/lib/x86/apic-defs.h
@@ -1,6 +1,13 @@
 #ifndef _ASM_X86_APICDEF_H
 #define _ASM_X86_APICDEF_H
 
+/*
+ * Abuse this header file to hold the number of max-cpus, making it available
+ * both in C and ASM
+ */
+
+#define MAX_TEST_CPUS (64)
+
 /*
  * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
  *
diff --git a/lib/x86/apic.c b/lib/x86/apic.c
index d4528bd..bc2706e 100644
--- a/lib/x86/apic.c
+++ b/lib/x86/apic.c
@@ -5,6 +5,7 @@
 
 void *g_apic = (void *)0xfee00000;
 void *g_ioapic = (void *)0xfec00000;
+u8 id_map[MAX_TEST_CPUS];
 
 struct apic_ops {
     u32 (*reg_read)(unsigned reg);
@@ -228,3 +229,15 @@ void mask_pic_interrupts(void)
     outb(0xff, 0x21);
     outb(0xff, 0xa1);
 }
+
+extern unsigned char online_cpus[256 / 8];
+
+void init_apic_map(void)
+{
+	unsigned int i, j = 0;
+
+	for (i = 0; i < sizeof(online_cpus) * 8; i++) {
+		if ((1ul << (i % 8)) & (online_cpus[i / 8]))
+			id_map[j++] = i;
+	}
+}
diff --git a/lib/x86/apic.h b/lib/x86/apic.h
index 651124d..537fdfb 100644
--- a/lib/x86/apic.h
+++ b/lib/x86/apic.h
@@ -4,6 +4,8 @@
 #include <stdint.h>
 #include "apic-defs.h"
 
+extern u8 id_map[MAX_TEST_CPUS];
+
 extern void *g_apic;
 extern void *g_ioapic;
 
@@ -55,6 +57,7 @@ uint32_t apic_id(void);
 int enable_x2apic(void);
 void disable_apic(void);
 void reset_apic(void);
+void init_apic_map(void);
 
 /* Converts byte-addressable APIC register offset to 4-byte offset. */
 static inline u32 apic_reg_index(u32 reg)
diff --git a/lib/x86/smp.c b/lib/x86/smp.c
index 2e98de8..30bd1a0 100644
--- a/lib/x86/smp.c
+++ b/lib/x86/smp.c
@@ -68,8 +68,10 @@ static void setup_smp_id(void *data)
 static void __on_cpu(int cpu, void (*function)(void *data), void *data,
                      int wait)
 {
+    unsigned int target = id_map[cpu];
+
     spin_lock(&ipi_lock);
-    if (cpu == smp_id())
+    if (target == smp_id())
 	function(data);
     else {
 	atomic_inc(&active_cpus);
@@ -78,8 +80,7 @@ static void __on_cpu(int cpu, void (*function)(void *data), void *data,
 	ipi_data = data;
 	ipi_wait = wait;
 	apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED
-                       | IPI_VECTOR,
-                       cpu);
+                       | IPI_VECTOR, target);
 	while (!ipi_done)
 	    ;
     }
@@ -112,6 +113,8 @@ int cpus_active(void)
     return atomic_read(&active_cpus);
 }
 
+extern unsigned long long online_cpus;
+
 void smp_init(void)
 {
     int i;
@@ -120,6 +123,7 @@ void smp_init(void)
     _cpu_count = fwcfg_get_nb_cpus();
 
     setup_idt();
+    init_apic_map();
     set_idt_entry(IPI_VECTOR, ipi_entry, 0);
 
     setup_smp_id(0);
diff --git a/x86/apic.c b/x86/apic.c
index 7ef4a27..83cae0c 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -272,7 +272,7 @@ static void test_self_ipi(void)
     handle_irq(vec, self_ipi_isr);
     irq_enable();
     apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec,
-                   0);
+                   id_map[0]);
 
     do {
         pause();
@@ -336,7 +336,7 @@ static void test_sti_nmi(void)
     on_cpu_async(1, sti_loop, 0);
     while (nmi_counter < 30000) {
 	old_counter = nmi_counter;
-	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1);
+	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[1]);
 	while (nmi_counter == old_counter) {
 	    ;
 	}
@@ -365,10 +365,10 @@ static void kick_me_nmi(void *blah)
 	if (nmi_done) {
 	    return;
 	}
-	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
+	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]);
 	/* make sure the NMI has arrived by sending an IPI after it */
 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT
-		       | 0x44, 0);
+		       | 0x44, id_map[0]);
 	++cpu1_nmi_ctr2;
 	while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) {
 	    pause();
@@ -402,7 +402,7 @@ static void test_multiple_nmi(void)
 	while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) {
 	    pause();
 	}
-	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
+	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]);
 	while (!nmi_flushed) {
 	    pause();
 	}
diff --git a/x86/cstart64.S b/x86/cstart64.S
index 31e41cc..a4b55c5 100644
--- a/x86/cstart64.S
+++ b/x86/cstart64.S
@@ -7,10 +7,11 @@ boot_idt = 0
 .globl idt_descr
 .globl tss_descr
 .globl gdt64_desc
+.globl online_cpus
 
 ipi_vector = 0x20
 
-max_cpus = 64
+max_cpus = MAX_TEST_CPUS
 
 .bss
 
@@ -208,9 +209,18 @@ ap_start32:
 	ljmpl $8, $ap_start64
 
 .code64
+save_id:
+	mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax
+	mov (%rax), %eax
+	shr $24, %eax
+	movzx %ax, %rax
+	lock btsq %rax, online_cpus
+	retq
+
 ap_start64:
 	call load_tss
 	call enable_apic
+	call save_id
 	call enable_x2apic
 	sti
 	nop
@@ -223,6 +233,7 @@ start64:
 	call load_tss
 	call mask_pic_interrupts
 	call enable_apic
+	call save_id
 	call smp_init
 	call enable_x2apic
 	mov mb_boot_info(%rip), %rbx
@@ -256,6 +267,9 @@ idt_descr:
 	.word 16 * 256 - 1
 	.quad boot_idt
 
+online_cpus:
+	.quad 0
+
 load_tss:
 	lidtq idt_descr
 	mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax
-- 
2.17.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux