qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] Reworking MIPS interrupts handling


From: Aurelien Jarno
Subject: [Qemu-devel] [PATCH] Reworking MIPS interrupts handling
Date: Tue, 23 Jan 2007 19:42:20 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

Hi all,

Please find below a patch to fix the IRQ issue on the MIPS platform. I
have tested it on both 2.4 and 2.6 kernel and it works fine.

Here are a few comments on the patch to understand how it works.

- The CPU hardware interrupt (CPU_INTERRUPT_HARD) is not deasserted by
  the CPU anymore, but rather by the interrupt controller. I think it
  should be the case for other targets too, but I don't want to change
  the code of other targets without some more tests, that's why I use a
  condition in the i8259.c file.

- The gt64120 now uses pic_read_irq() instead of pic_intack_read() so
  that the interrupt state of the i8259 is recomputed and propagated if
  needed.

- I changed the way the CPU hardware interrupt (CPU_INTERRUPT_HARD) is
  asserted. It appears that the MIPS CPU can have more than one
  interrupt, 6 hardware and 2 software interrupt. The
  cpu_mips_update_irq() subroutine computes the state of the hardware
  interrupt and issue and harware interrupt, deassert it or do nothing
  in function of the mode of the CPU, the CP0 cause register (status
  of the interrupt lines) and the CP0 status register (interrupt masks).

- The software interrupt are now handled using... a hardware interrupt.
  From our point of view, hardware and software interrupts are actually
  the same, they use the same vector, they use the same registers, the
  only difference is that the bit in the CP0 cause register is set to
  one by software instead of hardware.

Bye,
Aurelien

--- hw/mips_int.c       2007-01-18 20:37:29.623079789 +0100
+++ hw/mips_int.c       2007-01-23 18:47:42.000000000 +0100
@@ -0,0 +1,31 @@
+#include "vl.h"
+
+/* Raise IRQ to CPU if necessary. It must be called every time the active
+   IRQ may change. */
+void cpu_mips_update_irq(CPUState *env)
+{
+    if ((env->CP0_Status & env->CP0_Cause & 0x0000ff00) &&
+        (env->CP0_Status & 0x00000001) &&
+        !(env->hflags & MIPS_HFLAG_EXL) &&
+        !(env->hflags & MIPS_HFLAG_ERL) &&
+        !(env->hflags & MIPS_HFLAG_DM)) {
+        if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) {
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+void cpu_mips_irq_request(void *opaque, int irq, int level)
+{
+    CPUState *env = first_cpu;
+    
+    if (level) {
+        env->CP0_Cause |= (irq & 0x0000ff00);
+    } else {
+        env->CP0_Cause &= ~(irq & 0x0000ff00);
+    }
+    cpu_mips_update_irq(env);
+}
+
Index: Makefile.target
===================================================================
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.140
diff -u -d -p -r1.140 Makefile.target
--- Makefile.target     21 Jan 2007 22:40:04 -0000      1.140
+++ Makefile.target     23 Jan 2007 18:14:39 -0000
@@ -376,7 +376,7 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_
 CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_ARCH), mips)
-VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o dma.o vga.o serial.o i8254.o 
i8259.o
+VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o 
i8254.o i8259.o
 VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o
 VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
 DEFINES += -DHAS_AUDIO
Index: cpu-exec.c
===================================================================
RCS file: /sources/qemu/qemu/cpu-exec.c,v
retrieving revision 1.88
diff -u -d -p -r1.88 cpu-exec.c
--- cpu-exec.c  7 Dec 2006 18:28:42 -0000       1.88
+++ cpu-exec.c  23 Jan 2007 18:14:40 -0000
@@ -535,7 +535,6 @@ int cpu_exec(CPUState *env1)
                         env->exception_index = EXCP_EXT_INTERRUPT;
                         env->error_code = 0;
                         do_interrupt(env);
-                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
                         tmp_T0 = 0;
 #else
Index: vl.h
===================================================================
RCS file: /sources/qemu/qemu/vl.h,v
retrieving revision 1.175
diff -u -d -p -r1.175 vl.h
--- vl.h        21 Jan 2007 16:47:01 -0000      1.175
+++ vl.h        23 Jan 2007 18:14:44 -0000
@@ -1067,6 +1067,9 @@ extern QEMUMachine mips_machine;
 /* mips_malta.c */
 extern QEMUMachine mips_malta_machine;
 
+/* mips_int */
+extern void cpu_mips_irq_request(void *opaque, int irq, int level);
+
 /* mips_timer.c */
 extern void cpu_mips_clock_init(CPUState *);
 extern void cpu_mips_irqctrl_init (void);
Index: hw/gt64xxx.c
===================================================================
RCS file: /sources/qemu/qemu/hw/gt64xxx.c,v
retrieving revision 1.2
diff -u -d -p -r1.2 gt64xxx.c
--- hw/gt64xxx.c        17 Jan 2007 23:35:01 -0000      1.2
+++ hw/gt64xxx.c        23 Jan 2007 18:14:45 -0000
@@ -1,7 +1,7 @@
 /*
  * QEMU GT64120 PCI host
  *
- * Copyright (c) 2006 Aurelien Jarno
+ * Copyright (c) 2006, 2007 Aurelien Jarno
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to 
deal
@@ -433,7 +436,8 @@ static uint32_t gt64120_readl (void *opa
         val = s->regs[saddr];
         break;
     case GT_PCI0_IACK:
-       val = pic_intack_read(isa_pic);
+        /* Read the IRQ number */ 
+        val = pic_read_irq(isa_pic);
         break;
 
     /* SDRAM Parameters */
Index: hw/i8259.c
===================================================================
RCS file: /sources/qemu/qemu/hw/i8259.c,v
retrieving revision 1.19
diff -u -d -p -r1.19 i8259.c
--- hw/i8259.c  25 Jun 2006 18:15:31 -0000      1.19
+++ hw/i8259.c  23 Jan 2007 18:14:45 -0000
@@ -161,6 +161,10 @@ void pic_update_irq(PicState2 *s)
 #endif
         s->irq_request(s->irq_request_opaque, 1);
     }
+#if defined(TARGET_MIPS)
+    else
+        s->irq_request(s->irq_request_opaque, 0);
+#endif
 }
 
 #ifdef DEBUG_IRQ_LATENCY
Index: hw/mips_malta.c
===================================================================
RCS file: /sources/qemu/qemu/hw/mips_malta.c,v
retrieving revision 1.4
diff -u -d -p -r1.4 mips_malta.c
--- hw/mips_malta.c     20 Jan 2007 00:29:01 -0000      1.4
+++ hw/mips_malta.c     23 Jan 2007 18:14:45 -0000
@@ -56,14 +56,7 @@ static PITState *pit;
 
 static void pic_irq_request(void *opaque, int level)
 {
-    CPUState *env = first_cpu;
-    if (level) {
-        env->CP0_Cause |= 0x00000400;
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-       env->CP0_Cause &= ~0x00000400;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
+    cpu_mips_irq_request(opaque, 0x00000400, level);
 }
 
 /* Malta FPGA */
Index: hw/mips_r4k.c
===================================================================
RCS file: /sources/qemu/qemu/hw/mips_r4k.c,v
retrieving revision 1.31
diff -u -d -p -r1.31 mips_r4k.c
--- hw/mips_r4k.c       6 Jan 2007 02:24:15 -0000       1.31
+++ hw/mips_r4k.c       23 Jan 2007 18:14:45 -0000
@@ -38,14 +38,7 @@ static PITState *pit; /* PIT i8254 */
 /*The PIC is attached to the MIPS CPU INT0 pin */
 static void pic_irq_request(void *opaque, int level)
 {
-    CPUState *env = first_cpu;
-    if (level) {
-        env->CP0_Cause |= 0x00000400;
-        cpu_interrupt(env, CPU_INTERRUPT_HARD);
-    } else {
-       env->CP0_Cause &= ~0x00000400;
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
+    cpu_mips_irq_request(opaque, 0x00000400, level);
 }
 
 static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
Index: hw/mips_timer.c
===================================================================
RCS file: /sources/qemu/qemu/hw/mips_timer.c,v
retrieving revision 1.1
diff -u -d -p -r1.1 mips_timer.c
--- hw/mips_timer.c     6 Dec 2006 21:38:37 -0000       1.1
+++ hw/mips_timer.c     23 Jan 2007 18:14:45 -0000
@@ -57,8 +57,7 @@ void cpu_mips_store_count (CPUState *env
 void cpu_mips_store_compare (CPUState *env, uint32_t value)
 {
     cpu_mips_update_count(env, cpu_mips_get_count(env), value);
-    env->CP0_Cause &= ~0x00008000;
-    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_mips_irq_request(env, 0x00008000, 0);
 }
 
 static void mips_timer_cb (void *opaque)
@@ -73,7 +72,7 @@ static void mips_timer_cb (void *opaque)
 #endif
     cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
     env->CP0_Cause |= 0x00008000;
-    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    cpu_mips_irq_request(opaque, 0x00008000, 1);
 }
 
 void cpu_mips_clock_init (CPUState *env)
Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.15
diff -u -d -p -r1.15 exec.h
--- target-mips/exec.h  3 Jan 2007 15:18:08 -0000       1.15
+++ target-mips/exec.h  23 Jan 2007 18:14:45 -0000
@@ -164,6 +164,7 @@ uint32_t cpu_mips_get_random (CPUState *
 uint32_t cpu_mips_get_count (CPUState *env);
 void cpu_mips_store_count (CPUState *env, uint32_t value);
 void cpu_mips_store_compare (CPUState *env, uint32_t value);
+void cpu_mips_update_irq(CPUState *env);
 void cpu_mips_clock_init (CPUState *env);
 void cpu_mips_tlb_flush (CPUState *env, int flush_global);
 
Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.19
diff -u -d -p -r1.19 op.c
--- target-mips/op.c    1 Jan 2007 20:35:21 -0000       1.19
+++ target-mips/op.c    23 Jan 2007 18:14:45 -0000
@@ -1368,21 +1368,9 @@ void op_mtc0_status (void)
     else
         env->hflags &= ~MIPS_HFLAG_EXL;
     env->CP0_Status = val;
-    /* If we unmasked an asserted IRQ, raise it */
-    mask = 0x0000FF00;
     if (loglevel & CPU_LOG_TB_IN_ASM)
        CALL_FROM_TB2(do_mtc0_status_debug, old, val);
-    if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
-        !(env->hflags & MIPS_HFLAG_EXL) &&
-        !(env->hflags & MIPS_HFLAG_ERL) &&
-        !(env->hflags & MIPS_HFLAG_DM) &&
-        (env->CP0_Status & env->CP0_Cause & mask)) {
-        env->interrupt_request |= CPU_INTERRUPT_HARD;
-       if (logfile)
-           CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
-    } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
-        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-    }
+    CALL_FROM_TB1(cpu_mips_update_irq, env);
     RETURN();
 }
 
@@ -1402,22 +1390,13 @@ void op_mtc0_srsctl (void)
 
 void op_mtc0_cause (void)
 {
-    uint32_t val, old;
+    env->CP0_Cause = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300);
 
-    val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300);
-    old = env->CP0_Cause;
-    env->CP0_Cause = val;
-#if 0
-    {
-        int i, mask;
-       /* Check if we ever asserted a software IRQ */
-        for (i = 0; i < 2; i++) {
-            mask = 0x100 << i;
-            if ((val & mask) & !(old & mask))
-                CALL_FROM_TB1(mips_set_irq, i);
-        }
+    /* Handle the software interrupt as an hardware one, as they
+       are very similar */
+    if (T0 & 0x0000ff00) {
+        CALL_FROM_TB1(cpu_mips_update_irq, env);
     }
-#endif
     RETURN();
 }
 
@@ -1928,36 +1907,17 @@ void op_pmon (void)
 
 void op_di (void)
 {
-    uint32_t val;
-
     T0 = env->CP0_Status;
-    val = T0 & ~(1 << CP0St_IE);
-    if (val != T0) {
-        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-        env->CP0_Status = val;
-    }
+    env->CP0_Status = T0 & ~(1 << CP0St_IE);
+    CALL_FROM_TB1(cpu_mips_update_irq, env);
     RETURN();
 }
 
 void op_ei (void)
 {
-    uint32_t val;
-
     T0 = env->CP0_Status;
-    val = T0 | (1 << CP0St_IE);
-    if (val != T0) {
-       const uint32_t mask = 0x0000FF00;
-
-       env->CP0_Status = val;
-       if (!(env->hflags & MIPS_HFLAG_EXL) &&
-           !(env->hflags & MIPS_HFLAG_ERL) &&
-           !(env->hflags & MIPS_HFLAG_DM) &&
-           (env->CP0_Status & env->CP0_Cause & mask)) {
-               env->interrupt_request |= CPU_INTERRUPT_HARD;
-               if (logfile)
-                   CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
-       }
-    }
+    env->CP0_Status = T0 | (1 << CP0St_IE);
+    CALL_FROM_TB1(cpu_mips_update_irq, env);
     RETURN();
 }
 
Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v
retrieving revision 1.26
diff -u -d -p -r1.26 op_helper.c
--- target-mips/op_helper.c     22 Jan 2007 20:50:42 -0000      1.26
+++ target-mips/op_helper.c     23 Jan 2007 18:14:46 -0000
@@ -265,6 +265,11 @@ void cpu_mips_store_compare(CPUState *en
     cpu_abort(env, "mtc0 compare\n");
 }
 
+void cpu_mips_update_irq(CPUState *env)
+{
+    cpu_abort(env, "mtc0 status / mtc0 cause\n");
+}
+
 void do_mtc0_status_debug(uint32_t old, uint32_t val)
 {
     cpu_abort(env, "mtc0 status debug\n");

-- 
  .''`.  Aurelien Jarno             | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   address@hidden         | address@hidden
   `-    people.debian.org/~aurel32 | www.aurel32.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]