diff mbox

[2/2] x86: extend IOAPIC tests

Message ID 1431482143-28018-2-git-send-email-srutherford@google.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve Rutherford May 13, 2015, 1:55 a.m. UTC
Add tests for fundamental behaviors of the IOAPIC:
     Edge & level triggered interrupts
     Level triggered interrupt coalescing
     Level triggered EOIs
     Interrupt masking

Passes with most recent version of KVM on Intel x86.

Signed-off-by: Steve Rutherford <srutherford@google.com>
---
 config/config-x86_64.mak |   4 +-
 x86/ioapic.c             | 186 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 181 insertions(+), 9 deletions(-)
diff mbox

Patch

diff --git a/config/config-x86_64.mak b/config/config-x86_64.mak
index dfdeed6..7d4eb34 100644
--- a/config/config-x86_64.mak
+++ b/config/config-x86_64.mak
@@ -6,10 +6,10 @@  CFLAGS += -mno-red-zone
 tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
 	  $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \
 	  $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \
-	  $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat
+	  $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat \
+	  $(TEST_DIR)/ioapic.flat
 tests += $(TEST_DIR)/svm.flat
 tests += $(TEST_DIR)/vmx.flat
 tests += $(TEST_DIR)/tscdeadline_latency.flat
-tests += $(TEST_DIR)/ioapic.flat
 
 include config/config-x86-common.mak
diff --git a/x86/ioapic.c b/x86/ioapic.c
index 2afdaa2..1fcf67e 100644
--- a/x86/ioapic.c
+++ b/x86/ioapic.c
@@ -30,21 +30,87 @@  static void toggle_irq_line(unsigned line)
 	set_irq_line(line, 0);
 }
 
+static void ioapic_reg_version(void)
+{
+	u8 version_offset;
+	uint32_t data_read, data_write;
+
+	version_offset = 0x01;
+	data_read = ioapic_read_reg(version_offset);
+	data_write = data_read ^ 0xffffffff;
+
+	ioapic_write_reg(version_offset, data_write);
+	report("version register read only test",
+	       data_read == ioapic_read_reg(version_offset));
+}
+
+static void ioapic_reg_id(void)
+{
+	u8 id_offset;
+	uint32_t data_read, data_write, diff;
+
+	id_offset = 0x0;
+	data_read = ioapic_read_reg(id_offset);
+	data_write = data_read ^ 0xffffffff;
+
+	ioapic_write_reg(id_offset, data_write);
+
+	diff = data_read ^ ioapic_read_reg(id_offset);
+	report("id register only bits [24:27] writable",
+	       diff == 0x0f000000);
+}
+
+static void ioapic_arbitration_id(void)
+{
+	u8 id_offset, arb_offset;
+	uint32_t write;
+
+	id_offset = 0x0;
+	arb_offset = 0x2;
+	write = 0x0f000000;
+
+	ioapic_write_reg(id_offset, write);
+	report("arbitration register set by id",
+	       ioapic_read_reg(arb_offset) == write);
+
+	ioapic_write_reg(arb_offset, 0x0);
+	report("arbtration register read only",
+               ioapic_read_reg(arb_offset) == write);
+}
+
+static volatile int g_isr_76;
+
+static void ioapic_isr_76(isr_regs_t *regs)
+{
+	++g_isr_76;
+	eoi();
+}
+
+static void test_ioapic_edge_intr(void)
+{
+	handle_irq(0x76, ioapic_isr_76);
+	set_ioapic_redir(0x0e, 0x76, EDGE_TRIGGERED);
+	toggle_irq_line(0x0e);
+	asm volatile ("nop");
+	report("edge triggered intr", g_isr_76 == 1);
+}
+
 static volatile int g_isr_77;
 
 static void ioapic_isr_77(isr_regs_t *regs)
 {
 	++g_isr_77;
+	set_irq_line(0x0e, 0);
 	eoi();
 }
 
-static void test_ioapic_intr(void)
+static void test_ioapic_level_intr(void)
 {
 	handle_irq(0x77, ioapic_isr_77);
-	set_ioapic_redir(0x0e, 0x77, EDGE_TRIGGERED);
-	toggle_irq_line(0x0e);
+	set_ioapic_redir(0x0e, 0x77, LEVEL_TRIGGERED);
+	set_irq_line(0x0e, 1);
 	asm volatile ("nop");
-	report("ioapic interrupt", g_isr_77 == 1);
+	report("level triggered intr", g_isr_77 == 1);
 }
 
 static int g_78, g_66, g_66_after_78;
@@ -77,10 +143,106 @@  static void test_ioapic_simultaneous(void)
 	toggle_irq_line(0x0e);
 	irq_enable();
 	asm volatile ("nop");
-	report("ioapic simultaneous interrupt",
-		g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip);
+	report("ioapic simultaneous edge interrupts",
+	       g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip);
 }
 
+static int g_isr_98;
+
+static void ioapic_isr_98(isr_regs_t *regs)
+{
+	++g_isr_98;
+	if (g_isr_98 == 1) {
+		set_irq_line(0x0e, 0);
+		set_irq_line(0x0e, 1);
+	}
+	set_irq_line(0x0e, 0);
+	eoi();
+}
+
+static void test_ioapic_level_coalesce(void)
+{
+	handle_irq(0x98, ioapic_isr_98);
+	set_ioapic_redir(0x0e, 0x98, LEVEL_TRIGGERED);
+	set_irq_line(0x0e, 1);
+	asm volatile ("nop");
+	report("coalesce simultaneous level interrupts", g_isr_98 == 1);
+}
+
+static int g_isr_99;
+
+static void ioapic_isr_99(isr_regs_t *regs)
+{
+	++g_isr_99;
+	set_irq_line(0x0e, 0);
+	eoi();
+}
+
+static void test_ioapic_level_sequential(void)
+{
+	handle_irq(0x99, ioapic_isr_99);
+	set_ioapic_redir(0x0e, 0x99, LEVEL_TRIGGERED);
+	set_irq_line(0x0e, 1);
+	set_irq_line(0x0e, 1);
+	asm volatile ("nop");
+	report("sequential level interrupts", g_isr_99 == 2);
+}
+
+static volatile int g_isr_81;
+
+static void ioapic_isr_81(isr_regs_t *regs)
+{
+	++g_isr_81;
+	set_irq_line(0x0e, 0);
+	eoi();
+}
+
+static void test_ioapic_edge_mask(void)
+{
+	handle_irq(0x81, ioapic_isr_81);
+	set_ioapic_redir(0x0e, 0x81, EDGE_TRIGGERED);
+
+	set_mask(0x0e, true);
+	set_irq_line(0x0e, 1);
+	set_irq_line(0x0e, 0);
+
+	asm volatile ("nop");
+	report("masked level interrupt", g_isr_81 == 0);
+
+	set_mask(0x0e, false);
+	set_irq_line(0x0e, 1);
+
+	asm volatile ("nop");
+	report("unmasked level interrupt", g_isr_81 == 1);
+}
+
+static volatile int g_isr_82;
+
+static void ioapic_isr_82(isr_regs_t *regs)
+{
+	++g_isr_82;
+	set_irq_line(0x0e, 0);
+	eoi();
+}
+
+static void test_ioapic_level_mask(void)
+{
+	handle_irq(0x82, ioapic_isr_82);
+	set_ioapic_redir(0x0e, 0x82, LEVEL_TRIGGERED);
+
+	set_mask(0x0e, true);
+	set_irq_line(0x0e, 1);
+
+	asm volatile ("nop");
+	report("masked level interrupt", g_isr_82 == 0);
+
+	set_mask(0x0e, false);
+
+	asm volatile ("nop");
+	report("unmasked level interrupt", g_isr_82 == 1);
+}
+
+
 int main(void)
 {
 	setup_vm();
@@ -92,8 +254,18 @@  int main(void)
 
 	irq_enable();
 
-	test_ioapic_intr();
+	ioapic_reg_version();
+	ioapic_reg_id();
+	ioapic_arbitration_id();
+
+	test_ioapic_edge_intr();
+	test_ioapic_level_intr();
 	test_ioapic_simultaneous();
+	test_ioapic_level_coalesce();
+	test_ioapic_level_sequential();
+
+	test_ioapic_edge_mask();
+	test_ioapic_level_mask();
 
 	return report_summary();
 }