qemu-devel
[Top][All Lists]
Advanced

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

Re: [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator


From: Laurent Vivier
Subject: Re: [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device
Date: Tue, 2 Mar 2021 23:02:16 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.0

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> PDMA as implemented on the Quadra 800 uses DREQ to load data into the FIFO
> up to a maximum of 16 bytes at a time. The MacOS toolbox ROM requires this
> because it mixes FIFO and PDMA transfers whilst checking the FIFO status
> and counter registers to ensure success.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 109 ++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 75 insertions(+), 34 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index b7ab5a5592..5dcd4cd651 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -134,13 +134,8 @@ static void set_pdma(ESPState *s, enum pdma_origin_id 
> origin)
>  
>  static uint8_t esp_pdma_read(ESPState *s)
>  {
> -    uint32_t dmalen = esp_get_tc(s);
>      uint8_t val;
>  
> -    if (dmalen == 0) {
> -        return 0;
> -    }
> -
>      switch (s->pdma_origin) {
>      case TI:
>          if (s->do_cmd) {
> @@ -160,10 +155,6 @@ static uint8_t esp_pdma_read(ESPState *s)
>          g_assert_not_reached();
>      }
>  
> -    s->ti_size--;
> -    dmalen--;
> -    esp_set_tc(s, dmalen);
> -
>      return val;
>  }
>  
> @@ -194,7 +185,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>          g_assert_not_reached();
>      }
>  
> -    s->ti_size++;
>      dmalen--;
>      esp_set_tc(s, dmalen);
>  }
> @@ -290,6 +280,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, 
> uint8_t busid)
>      s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>      s->rregs[ESP_RSEQ] = SEQ_CD;
>      esp_raise_irq(s);
> +    esp_lower_drq(s);
>  }
>  
>  static void do_cmd(ESPState *s)
> @@ -447,28 +438,71 @@ static void esp_dma_done(ESPState *s)
>  static void do_dma_pdma_cb(ESPState *s)
>  {
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
> +    int len;
>  
>      if (s->do_cmd) {
>          s->ti_size = 0;
>          s->cmdlen = 0;
>          s->do_cmd = 0;
>          do_cmd(s);
> +        esp_lower_drq(s);
>          return;
>      }
> -    if (s->async_len == 0) {
> -        scsi_req_continue(s->current_req);
> -        /*
> -         * If there is still data to be read from the device then
> -         * complete the DMA operation immediately.  Otherwise defer
> -         * until the scsi layer has completed.
> -         */
> -        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
> +
> +    if (to_device) {
> +        /* Copy FIFO data to device */
> +        len = MIN(s->ti_wptr, TI_BUFSZ);
> +        memcpy(s->async_buf, s->ti_buf, len);
> +        s->ti_wptr = 0;
> +        s->ti_rptr = 0;
> +        s->async_buf += len;
> +        s->async_len -= len;
> +        s->ti_size += len;
> +        if (s->async_len == 0) {
> +            scsi_req_continue(s->current_req);
>              return;
>          }
> -    }
>  
> -    /* Partially filled a scsi buffer. Complete immediately.  */
> -    esp_dma_done(s);
> +        if (esp_get_tc(s) == 0) {
> +            esp_lower_drq(s);
> +            esp_dma_done(s);
> +        }
> +
> +        return;
> +    } else {
> +        if (s->async_len == 0) {
> +            if (s->current_req) {
> +                scsi_req_continue(s->current_req);
> +            }
> +
> +            /*
> +             * If there is still data to be read from the device then
> +             * complete the DMA operation immediately.  Otherwise defer
> +             * until the scsi layer has completed.
> +             */
> +            if (esp_get_tc(s) != 0 || s->ti_size == 0) {
> +                return;
> +            }
> +        }
> +
> +        if (esp_get_tc(s) != 0) {
> +            /* Copy device data to FIFO */
> +            s->ti_wptr = 0;
> +            s->ti_rptr = 0;
> +            len = MIN(s->async_len, TI_BUFSZ);
> +            memcpy(s->ti_buf, s->async_buf, len);
> +            s->ti_wptr += len;
> +            s->async_buf += len;
> +            s->async_len -= len;
> +            s->ti_size -= len;
> +            esp_set_tc(s, esp_get_tc(s) - len);
> +            return;
> +        }
> +
> +        /* Partially filled a scsi buffer. Complete immediately.  */
> +        esp_lower_drq(s);
> +        esp_dma_done(s);
> +    }
>  }
>  
>  static void esp_do_dma(ESPState *s)
> @@ -511,7 +545,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC);
> +            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -520,9 +554,20 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_write) {
>              s->dma_memory_write(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC);
> +            /* Copy device data to FIFO */
> +            len = MIN(len, TI_BUFSZ - s->ti_wptr);
> +            memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len);
> +            s->ti_wptr += len;
> +            s->async_buf += len;
> +            s->async_len -= len;
> +            s->ti_size -= len;
> +            esp_set_tc(s, esp_get_tc(s) - len);
> +            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
> +
> +            /* Indicate transfer to FIFO is complete */
> +            s->rregs[ESP_RSTAT] |= STAT_TC;
>              return;
>          }
>      }
> @@ -548,6 +593,7 @@ static void esp_do_dma(ESPState *s)
>  
>      /* Partially filled a scsi buffer. Complete immediately.  */
>      esp_dma_done(s);
> +    esp_lower_drq(s);
>  }
>  
>  static void esp_report_command_complete(ESPState *s, uint32_t status)
> @@ -564,6 +610,7 @@ static void esp_report_command_complete(ESPState *s, 
> uint32_t status)
>      s->status = status;
>      s->rregs[ESP_RSTAT] = STAT_ST;
>      esp_dma_done(s);
> +    esp_lower_drq(s);
>      if (s->current_req) {
>          scsi_req_unref(s->current_req);
>          s->current_req = NULL;
> @@ -606,6 +653,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>           * completion interrupt is deferred to here.
>           */
>          esp_dma_done(s);
> +        esp_lower_drq(s);
>      }
>  }
>  
> @@ -977,10 +1025,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr 
> addr,
>          break;
>      }
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0 && s->pdma_cb) {
> -        esp_lower_drq(s);
> +    if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) {
>          s->pdma_cb(s);
> -        s->pdma_cb = NULL;
>      }
>  }
>  
> @@ -989,14 +1035,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, 
> hwaddr addr,
>  {
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
> -    uint32_t dmalen = esp_get_tc(s);
>      uint64_t val = 0;
>  
>      trace_esp_pdma_read(size);
>  
> -    if (dmalen == 0) {
> -        return 0;
> -    }
>      switch (size) {
>      case 1:
>          val = esp_pdma_read(s);
> @@ -1006,11 +1048,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, 
> hwaddr addr,
>          val = (val << 8) | esp_pdma_read(s);
>          break;
>      }
> -    dmalen = esp_get_tc(s);
> -    if (dmalen == 0 && s->pdma_cb) {
> -        esp_lower_drq(s);
> +    if (s->ti_rptr == s->ti_wptr) {
> +        s->ti_wptr = 0;
> +        s->ti_rptr = 0;
>          s->pdma_cb(s);
> -        s->pdma_cb = NULL;
>      }
>      return val;
>  }
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>



reply via email to

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