All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] ESP: fix irq handling
@ 2008-04-24  7:44 Hervé Poussineau
  0 siblings, 0 replies; only message in thread
From: Hervé Poussineau @ 2008-04-24  7:44 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 410 bytes --]

Hi,

In ESP SCSI adapter, IRQ line state should always be in sync with the 
STAT_INT bit. This patch enforces this, by creating functions to raise 
or lower the irq level.
This fixes bugs in do_cmd(), write_response(), esp_mem_readb(), 
esp_mem_writeb(), where it was not handled properly.
Also adds IRQ line deassertion at reset.
Finally, rename STAT_IN to STAT_INT, according to datasheet.

Hervé

[-- Attachment #2: esp_interrupt.diff --]
[-- Type: text/plain, Size: 4074 bytes --]

Index: hw/esp.c
===================================================================
--- hw/esp.c	(revision 4244)
+++ hw/esp.c	(working copy)
@@ -127,7 +127,7 @@
 #define STAT_TC 0x10
 #define STAT_PE 0x20
 #define STAT_GE 0x40
-#define STAT_IN 0x80
+#define STAT_INT 0x80
 
 #define INTR_FC 0x08
 #define INTR_BS 0x10
@@ -143,6 +143,22 @@
 
 #define TCHI_FAS100A 0x4
 
+static void esp_raise_irq(ESPState *s)
+{
+    if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
+        s->rregs[ESP_RSTAT] |= STAT_INT;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static void esp_lower_irq(ESPState *s)
+{
+    if (s->rregs[ESP_RSTAT] & STAT_INT) {
+        s->rregs[ESP_RSTAT] &= ~STAT_INT;
+        qemu_irq_lower(s->irq);
+    }
+}
+
 static int get_cmd(ESPState *s, uint8_t *buf)
 {
     uint32_t dmalen;
@@ -171,10 +187,10 @@
 
     if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) {
         // No such drive
-        s->rregs[ESP_RSTAT] = STAT_IN;
+        s->rregs[ESP_RSTAT] = 0;
         s->rregs[ESP_RINTR] = INTR_DC;
         s->rregs[ESP_RSEQ] = SEQ_0;
-        qemu_irq_raise(s->irq);
+        esp_raise_irq(s);
         return 0;
     }
     s->current_dev = s->scsi_dev[target];
@@ -191,7 +207,7 @@
     datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
     s->ti_size = datalen;
     if (datalen != 0) {
-        s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC;
+        s->rregs[ESP_RSTAT] = STAT_TC;
         s->dma_left = 0;
         s->dma_counter = 0;
         if (datalen > 0) {
@@ -204,7 +220,7 @@
     }
     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
     s->rregs[ESP_RSEQ] = SEQ_CD;
-    qemu_irq_raise(s->irq);
+    esp_raise_irq(s);
 }
 
 static void handle_satn(ESPState *s)
@@ -223,10 +239,10 @@
     if (s->cmdlen) {
         DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
         s->do_cmd = 1;
-        s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_CD;
+        s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
-        qemu_irq_raise(s->irq);
+        esp_raise_irq(s);
     }
 }
 
@@ -237,7 +253,7 @@
     s->ti_buf[1] = 0;
     if (s->dma) {
         s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
-        s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_ST;
+        s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
     } else {
@@ -246,18 +262,18 @@
         s->ti_wptr = 0;
         s->rregs[ESP_RFLAGS] = 2;
     }
-    qemu_irq_raise(s->irq);
+    esp_raise_irq(s);
 }
 
 static void esp_dma_done(ESPState *s)
 {
-    s->rregs[ESP_RSTAT] |= STAT_IN | STAT_TC;
+    s->rregs[ESP_RSTAT] |= STAT_TC;
     s->rregs[ESP_RINTR] = INTR_BS;
     s->rregs[ESP_RSEQ] = 0;
     s->rregs[ESP_RFLAGS] = 0;
     s->rregs[ESP_TCLO] = 0;
     s->rregs[ESP_TCMID] = 0;
-    qemu_irq_raise(s->irq);
+    esp_raise_irq(s);
 }
 
 static void esp_do_dma(ESPState *s)
@@ -381,6 +397,8 @@
 {
     ESPState *s = opaque;
 
+    esp_lower_irq(s);
+
     memset(s->rregs, 0, ESP_REGS);
     memset(s->wregs, 0, ESP_REGS);
     s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
@@ -415,7 +433,7 @@
             } else {
                 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
             }
-            qemu_irq_raise(s->irq);
+            esp_raise_irq(s);
         }
         if (s->ti_size == 0) {
             s->ti_rptr = 0;
@@ -424,8 +442,8 @@
         break;
     case ESP_RINTR:
         // Clear interrupt/error status bits
-        s->rregs[ESP_RSTAT] &= ~(STAT_IN | STAT_GE | STAT_PE);
-        qemu_irq_lower(s->irq);
+        s->rregs[ESP_RSTAT] &= ~(STAT_GE | STAT_PE);
+        esp_lower_irq(s);
         break;
     default:
         break;
@@ -487,7 +505,7 @@
             DPRINTF("Bus reset (%2.2x)\n", val);
             s->rregs[ESP_RINTR] = INTR_RST;
             if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
-                qemu_irq_raise(s->irq);
+                esp_raise_irq(s);
             }
             break;
         case CMD_TI:

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-04-24  8:17 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-24  7:44 [Qemu-devel] [PATCH] ESP: fix irq handling Hervé Poussineau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.