ESP: fix irq handling
PATCH 1/1 ESP: fix irq handling
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é
esp.c +33 -15
@@ -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 :