From nobody Thu Nov 6 10:38:35 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1540820934679682.8509698439714; Mon, 29 Oct 2018 06:48:54 -0700 (PDT) Received: from localhost ([::1]:45695 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gH7uX-0004Xn-3f for importer@patchew.org; Mon, 29 Oct 2018 09:48:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:32906) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gH7mU-00059E-HZ for qemu-devel@nongnu.org; Mon, 29 Oct 2018 09:40:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gH7mS-0006eG-5J for qemu-devel@nongnu.org; Mon, 29 Oct 2018 09:40:34 -0400 Received: from chuckie.co.uk ([82.165.15.123]:38065 helo=s16892447.onlinehome-server.info) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gH7mR-0006cu-Ma; Mon, 29 Oct 2018 09:40:32 -0400 Received: from host109-147-184-151.range109-147.btcentralplus.com ([109.147.184.151] helo=kentang.home) by s16892447.onlinehome-server.info with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.76) (envelope-from ) id 1gH7md-0000jE-GZ; Mon, 29 Oct 2018 13:40:46 +0000 From: Mark Cave-Ayland To: qemu-devel@nongnu.org, kwolf@redhat.com, famz@redhat.com, qemu-block@nongnu.org, jasowang@redhat.com, dgilbert@redhat.com, mreitz@redhat.com, hpoussin@reactos.org, kraxel@redhat.com, pbonzini@redhat.com, afaerber@suse.de, aurelien@aurel32.net, laurent@vivier.eu Date: Mon, 29 Oct 2018 13:39:55 +0000 Message-Id: <20181029134000.11157-7-mark.cave-ayland@ilande.co.uk> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20181029134000.11157-1-mark.cave-ayland@ilande.co.uk> References: <20181029134000.11157-1-mark.cave-ayland@ilande.co.uk> X-SA-Exim-Connect-IP: 109.147.184.151 X-SA-Exim-Mail-From: mark.cave-ayland@ilande.co.uk X-SA-Exim-Version: 4.2.1 (built Sun, 08 Jan 2012 02:45:44 +0000) X-SA-Exim-Scanned: Yes (on s16892447.onlinehome-server.info) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 82.165.15.123 Subject: [Qemu-devel] [PATCH v5 06/11] esp: add pseudo-DMA as used by Macintosh X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Laurent Vivier Co-developed-by: Mark Cave-Ayland Signed-off-by: Mark Cave-Ayland Signed-off-by: Laurent Vivier --- hw/scsi/esp.c | 292 +++++++++++++++++++++++++++++++++++++++++++++-= ---- include/hw/scsi/esp.h | 7 ++ 2 files changed, 270 insertions(+), 29 deletions(-) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 630d923623..57589cd69d 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -35,6 +35,8 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C1= 00.txt * and * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9= X.txt + * + * On Macintosh Quadra it is a NCR53C96. */ =20 static void esp_raise_irq(ESPState *s) @@ -55,6 +57,16 @@ static void esp_lower_irq(ESPState *s) } } =20 +static void esp_raise_drq(ESPState *s) +{ + qemu_irq_raise(s->irq_data); +} + +static void esp_lower_drq(ESPState *s) +{ + qemu_irq_lower(s->irq_data); +} + void esp_dma_enable(ESPState *s, int irq, int level) { if (level) { @@ -81,29 +93,11 @@ void esp_request_cancelled(SCSIRequest *req) } } =20 -static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) +static int get_cmd_cb(ESPState *s) { - uint32_t dmalen; int target; =20 target =3D s->wregs[ESP_WBUSID] & BUSID_DID; - if (s->dma) { - dmalen =3D s->rregs[ESP_TCLO]; - dmalen |=3D s->rregs[ESP_TCMID] << 8; - dmalen |=3D s->rregs[ESP_TCHI] << 16; - if (dmalen > buflen) { - return 0; - } - s->dma_memory_read(s->dma_opaque, buf, dmalen); - } else { - dmalen =3D s->ti_size; - if (dmalen > TI_BUFSZ) { - return 0; - } - memcpy(buf, s->ti_buf, dmalen); - buf[0] =3D buf[2] >> 5; - } - trace_esp_get_cmd(dmalen, target); =20 s->ti_size =3D 0; s->ti_rptr =3D 0; @@ -122,8 +116,48 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uin= t8_t buflen) s->rregs[ESP_RINTR] =3D INTR_DC; s->rregs[ESP_RSEQ] =3D SEQ_0; esp_raise_irq(s); + return -1; + } + return 0; +} + +static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen) +{ + int target; + uint32_t dmalen; + + target =3D s->wregs[ESP_WBUSID] & BUSID_DID; + if (s->dma) { + dmalen =3D s->rregs[ESP_TCLO]; + dmalen |=3D s->rregs[ESP_TCMID] << 8; + dmalen |=3D s->rregs[ESP_TCHI] << 16; + if (dmalen > buflen) { + return 0; + } + if (s->dma_memory_read) { + s->dma_memory_read(s->dma_opaque, buf, dmalen); + } else { + memcpy(s->pdma_buf, buf, dmalen); + s->pdma_len =3D dmalen; + s->pdma_start =3D s->pdma_buf; + s->pdma_cur =3D s->pdma_buf; + esp_raise_drq(s); + return 0; + } + } else { + dmalen =3D s->ti_size; + if (dmalen > TI_BUFSZ) { + return 0; + } + memcpy(buf, s->ti_buf, dmalen); + buf[0] =3D buf[2] >> 5; + } + trace_esp_get_cmd(dmalen, target); + + if (get_cmd_cb(s) < 0) { return 0; } + return dmalen; } =20 @@ -162,6 +196,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) do_busid_cmd(s, &buf[1], busid); } =20 +static void satn_pdma_cb(ESPState *s) +{ + if (get_cmd_cb(s) < 0) { + return; + } + if (s->pdma_cur !=3D s->pdma_start) + do_cmd(s, s->pdma_start); +} + static void handle_satn(ESPState *s) { uint8_t buf[32]; @@ -171,11 +214,21 @@ static void handle_satn(ESPState *s) s->dma_cb =3D handle_satn; return; } + s->pdma_cb =3D satn_pdma_cb; len =3D get_cmd(s, buf, sizeof(buf)); if (len) do_cmd(s, buf); } =20 +static void s_without_satn_pdma_cb(ESPState *s) +{ + if (get_cmd_cb(s) < 0) { + return; + } + if (s->pdma_cur !=3D s->pdma_start) + do_busid_cmd(s, s->pdma_start, 0); +} + static void handle_s_without_atn(ESPState *s) { uint8_t buf[32]; @@ -185,18 +238,36 @@ static void handle_s_without_atn(ESPState *s) s->dma_cb =3D handle_s_without_atn; return; } + s->pdma_cb =3D s_without_satn_pdma_cb; len =3D get_cmd(s, buf, sizeof(buf)); if (len) { do_busid_cmd(s, buf, 0); } } =20 +static void satn_stop_pdma_cb(ESPState *s) +{ + if (get_cmd_cb(s) < 0) { + return; + } + s->cmdlen =3D s->pdma_cur - s->pdma_start; + if (s->cmdlen) { + trace_esp_handle_satn_stop(s->cmdlen); + s->do_cmd =3D 1; + s->rregs[ESP_RSTAT] =3D STAT_TC | STAT_CD; + s->rregs[ESP_RINTR] =3D INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] =3D SEQ_CD; + esp_raise_irq(s); + } +} + static void handle_satn_stop(ESPState *s) { if (s->dma && !s->dma_enabled) { s->dma_cb =3D handle_satn_stop; return; } + s->pdma_cb =3D satn_stop_pdma_cb;; s->cmdlen =3D get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf)); if (s->cmdlen) { trace_esp_handle_satn_stop(s->cmdlen); @@ -208,16 +279,33 @@ static void handle_satn_stop(ESPState *s) } } =20 +static void write_response_pdma_cb(ESPState *s) +{ + s->rregs[ESP_RSTAT] =3D STAT_TC | STAT_ST; + s->rregs[ESP_RINTR] =3D INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] =3D SEQ_CD; + esp_raise_irq(s); +} + static void write_response(ESPState *s) { trace_esp_write_response(s->status); s->ti_buf[0] =3D s->status; s->ti_buf[1] =3D 0; if (s->dma) { - s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); - s->rregs[ESP_RSTAT] =3D STAT_TC | STAT_ST; - s->rregs[ESP_RINTR] =3D INTR_BS | INTR_FC; - s->rregs[ESP_RSEQ] =3D SEQ_CD; + if (s->dma_memory_write) { + s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); + s->rregs[ESP_RSTAT] =3D STAT_TC | STAT_ST; + s->rregs[ESP_RINTR] =3D INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] =3D SEQ_CD; + } else { + s->pdma_len =3D 2; + s->pdma_start =3D s->ti_buf; + s->pdma_cur =3D s->ti_buf; + s->pdma_cb =3D write_response_pdma_cb; + esp_raise_drq(s); + return; + } } else { s->ti_size =3D 2; s->ti_rptr =3D 0; @@ -239,6 +327,39 @@ static void esp_dma_done(ESPState *s) esp_raise_irq(s); } =20 +static void do_dma_pdma_cb(ESPState *s) +{ + int to_device =3D (s->ti_size < 0); + int len =3D s->pdma_cur - s->pdma_start; + if (s->do_cmd) { + s->ti_size =3D 0; + s->cmdlen =3D 0; + s->do_cmd =3D 0; + do_cmd(s, s->cmdbuf); + return; + } + s->dma_left -=3D len; + s->async_buf +=3D len; + s->async_len -=3D len; + if (to_device) { + s->ti_size +=3D len; + } else { + s->ti_size -=3D len; + } + if (s->async_len =3D=3D 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 || s->dma_left !=3D 0 || s->ti_size =3D=3D 0) { + return; + } + } + + /* Partially filled a scsi buffer. Complete immediately. */ + esp_dma_done(s); +} + static void esp_do_dma(ESPState *s) { uint32_t len; @@ -249,10 +370,26 @@ static void esp_do_dma(ESPState *s) trace_esp_do_dma(s->cmdlen, len); assert (s->cmdlen <=3D sizeof(s->cmdbuf) && len <=3D sizeof(s->cmdbuf) - s->cmdlen); - s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); + if (s->dma_memory_read) { + s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); + } else { + s->pdma_len =3D len; + s->pdma_start =3D &s->cmdbuf[s->cmdlen]; + s->pdma_cur =3D &s->cmdbuf[s->cmdlen]; + s->pdma_cb =3D do_dma_pdma_cb; + esp_raise_drq(s); + return; + } + s->ti_size =3D 0; + s->cmdlen =3D 0; + s->do_cmd =3D 0; + do_cmd(s, s->cmdbuf); return; } if (s->async_len =3D=3D 0) { + if (s->dma_left =3D=3D 0) { + esp_dma_done(s); + } /* Defer until data is available. */ return; } @@ -261,9 +398,27 @@ static void esp_do_dma(ESPState *s) } to_device =3D (s->ti_size < 0); if (to_device) { - s->dma_memory_read(s->dma_opaque, s->async_buf, len); + if (s->dma_memory_read) { + s->dma_memory_read(s->dma_opaque, s->async_buf, len); + } else { + s->pdma_len =3D len; + s->pdma_start =3D s->async_buf; + s->pdma_cur =3D s->async_buf; + s->pdma_cb =3D do_dma_pdma_cb; + esp_raise_drq(s); + return; + } } else { - s->dma_memory_write(s->dma_opaque, s->async_buf, len); + if (s->dma_memory_write) { + s->dma_memory_write(s->dma_opaque, s->async_buf, len); + } else { + s->pdma_len =3D len; + s->pdma_start =3D s->async_buf; + s->pdma_cur =3D s->async_buf; + s->pdma_cb =3D do_dma_pdma_cb; + esp_raise_drq(s); + return; + } } s->dma_left -=3D len; s->async_buf +=3D len; @@ -356,8 +511,7 @@ static void handle_ti(ESPState *s) s->dma_left =3D minlen; s->rregs[ESP_RSTAT] &=3D ~STAT_TC; esp_do_dma(s); - } - if (s->do_cmd) { + } else if (s->do_cmd) { trace_esp_handle_ti_cmd(s->cmdlen); s->ti_size =3D 0; s->cmdlen =3D 0; @@ -384,6 +538,7 @@ void esp_hard_reset(ESPState *s) static void esp_soft_reset(ESPState *s) { qemu_irq_lower(s->irq); + qemu_irq_lower(s->irq_data); esp_hard_reset(s); } =20 @@ -409,6 +564,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) s->ti_size--; s->rregs[ESP_FIFO] =3D s->ti_buf[s->ti_rptr++]; } + esp_raise_irq(s); if (s->ti_rptr =3D=3D s->ti_wptr) { s->ti_rptr =3D 0; s->ti_wptr =3D 0; @@ -619,6 +775,80 @@ static const MemoryRegionOps sysbus_esp_mem_ops =3D { .valid.accepts =3D esp_mem_accepts, }; =20 +static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, + uint64_t val, unsigned int size) +{ + SysBusESPState *sysbus =3D opaque; + ESPState *s =3D &sysbus->esp; + uint32_t dmalen; + + dmalen =3D s->rregs[ESP_TCLO]; + dmalen |=3D s->rregs[ESP_TCMID] << 8; + dmalen |=3D s->rregs[ESP_TCHI] << 16; + if (dmalen =3D=3D 0 || s->pdma_len =3D=3D 0) { + return; + } + switch (size) { + case 1: + *s->pdma_cur++ =3D val; + s->pdma_len--; + dmalen--; + break; + case 2: + *s->pdma_cur++ =3D val >> 8; + *s->pdma_cur++ =3D val; + s->pdma_len -=3D 2; + dmalen -=3D 2; + break; + } + s->rregs[ESP_TCLO] =3D dmalen & 0xff; + s->rregs[ESP_TCMID] =3D dmalen >> 8; + s->rregs[ESP_TCHI] =3D dmalen >> 16; + if (s->pdma_len =3D=3D 0 && s->pdma_cb) { + esp_lower_drq(s); + s->pdma_cb(s); + s->pdma_cb =3D NULL; + } +} + +static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, + unsigned int size) +{ + SysBusESPState *sysbus =3D opaque; + ESPState *s =3D &sysbus->esp; + uint64_t val =3D 0; + + if (s->pdma_len =3D=3D 0) { + return 0; + } + switch (size) { + case 1: + val =3D *s->pdma_cur++; + s->pdma_len--; + break; + case 2: + val =3D *s->pdma_cur++; + val =3D (val << 8) | *s->pdma_cur++; + s->pdma_len -=3D 2; + break; + } + + if (s->pdma_len =3D=3D 0 && s->pdma_cb) { + esp_lower_drq(s); + s->pdma_cb(s); + s->pdma_cb =3D NULL; + } + return val; +} + +static const MemoryRegionOps sysbus_esp_pdma_ops =3D { + .read =3D sysbus_esp_pdma_read, + .write =3D sysbus_esp_pdma_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid.min_access_size =3D 1, + .valid.max_access_size =3D 2, +}; + static const struct SCSIBusInfo esp_scsi_info =3D { .tcq =3D false, .max_target =3D ESP_MAX_DEVS, @@ -651,12 +881,16 @@ static void sysbus_esp_realize(DeviceState *dev, Erro= r **errp) ESPState *s =3D &sysbus->esp; =20 sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->irq_data); assert(sysbus->it_shift !=3D -1); =20 s->chip_id =3D TCHI_FAS100A; memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_= ops, - sysbus, "esp", ESP_REGS << sysbus->it_shift); + sysbus, "esp-regs", ESP_REGS << sysbus->it_shift= ); sysbus_init_mmio(sbd, &sysbus->iomem); + memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_= ops, + sysbus, "esp-pdma", 2); + sysbus_init_mmio(sbd, &sysbus->pdma); =20 qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); =20 diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h index 682a0d2de0..5e94917ef8 100644 --- a/include/hw/scsi/esp.h +++ b/include/hw/scsi/esp.h @@ -18,6 +18,7 @@ struct ESPState { uint8_t rregs[ESP_REGS]; uint8_t wregs[ESP_REGS]; qemu_irq irq; + qemu_irq irq_data; uint8_t chip_id; bool tchi_written; int32_t ti_size; @@ -46,6 +47,11 @@ struct ESPState { ESPDMAMemoryReadWriteFunc dma_memory_write; void *dma_opaque; void (*dma_cb)(ESPState *s); + uint8_t pdma_buf[32]; + uint32_t pdma_len; + uint8_t *pdma_start; + uint8_t *pdma_cur; + void (*pdma_cb)(ESPState *s); }; =20 #define TYPE_ESP "esp" @@ -57,6 +63,7 @@ typedef struct { /*< public >*/ =20 MemoryRegion iomem; + MemoryRegion pdma; uint32_t it_shift; ESPState esp; } SysBusESPState; --=20 2.11.0