[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 23/25] esp: use FIFO for PDMA transfers between initiator and dev
From: |
Mark Cave-Ayland |
Subject: |
[PATCH 23/25] esp: use FIFO for PDMA transfers between initiator and device |
Date: |
Wed, 30 Dec 2020 15:37:43 +0000 |
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 | 104 +++++++++++++++++++++++++++++++++++---------------
1 file changed, 73 insertions(+), 31 deletions(-)
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 69c03e59f0..d2a70998aa 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) {
@@ -161,8 +156,6 @@ static uint8_t esp_pdma_read(ESPState *s)
}
s->ti_size--;
- dmalen--;
- esp_set_tc(s, dmalen);
return val;
}
@@ -447,28 +440,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, s->cmdbuf);
+ 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;
+ 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.
+ */
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) {
+ 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) {
+ 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;
+ 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 +547,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 +556,19 @@ 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;
+ 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 +594,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 +611,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;
@@ -607,6 +655,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
* completion interrupt is deferred to here.
*/
esp_dma_done(s);
+ esp_lower_drq(s);
}
}
@@ -944,10 +993,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;
}
}
@@ -956,14 +1003,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque,
hwaddr addr,
{
SysBusESPState *sysbus = opaque;
ESPState *s = &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);
@@ -973,11 +1016,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;
}
--
2.20.1
- [PATCH 14/25] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write(), (continued)
- [PATCH 14/25] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write(), Mark Cave-Ayland, 2020/12/30
- [PATCH 13/25] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write(), Mark Cave-Ayland, 2020/12/30
- [PATCH 16/25] esp: remove redundant pdma_start from ESPState, Mark Cave-Ayland, 2020/12/30
- [PATCH 15/25] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf, Mark Cave-Ayland, 2020/12/30
- [PATCH 17/25] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write(), Mark Cave-Ayland, 2020/12/30
- [PATCH 18/25] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA, Mark Cave-Ayland, 2020/12/30
- [PATCH 19/25] esp: use in-built TC to determine PDMA transfer length, Mark Cave-Ayland, 2020/12/30
- [PATCH 20/25] esp: remove CMD pdma_origin, Mark Cave-Ayland, 2020/12/30
- [PATCH 21/25] esp: rename get_cmd_cb() to esp_select(), Mark Cave-Ayland, 2020/12/30
- [PATCH 22/25] esp: fix PDMA target selection, Mark Cave-Ayland, 2020/12/30
- [PATCH 23/25] esp: use FIFO for PDMA transfers between initiator and device,
Mark Cave-Ayland <=
- [PATCH 24/25] esp: remove pdma_origin from ESPState, Mark Cave-Ayland, 2020/12/30
- [PATCH 25/25] esp: add 4 byte PDMA read and write transfers, Mark Cave-Ayland, 2020/12/30