From patchwork Thu Apr 19 05:42:09 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhi Hui Li X-Patchwork-Id: 153653 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id CC393B6FAA for ; Thu, 19 Apr 2012 16:04:35 +1000 (EST) Received: from localhost ([::1]:51856 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SKkTm-0007fg-Il for incoming@patchwork.ozlabs.org; Thu, 19 Apr 2012 02:04:30 -0400 Received: from eggs.gnu.org ([208.118.235.92]:38658) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SKkTe-0007fW-Bf for qemu-devel@nongnu.org; Thu, 19 Apr 2012 02:04:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SKkTY-0003aC-S7 for qemu-devel@nongnu.org; Thu, 19 Apr 2012 02:04:21 -0400 Received: from e23smtp06.au.ibm.com ([202.81.31.148]:32925) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SKkTJ-0003Yh-IH for qemu-devel@nongnu.org; Thu, 19 Apr 2012 02:04:16 -0400 Received: from /spool/local by e23smtp06.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 19 Apr 2012 05:37:30 +1000 Received: from d23relay03.au.ibm.com (202.81.31.245) by e23smtp06.au.ibm.com (202.81.31.212) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 19 Apr 2012 05:37:23 +1000 Received: from d23av02.au.ibm.com (d23av02.au.ibm.com [9.190.235.138]) by d23relay03.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q3J5gHuA37683416 for ; Thu, 19 Apr 2012 15:42:17 +1000 Received: from d23av02.au.ibm.com (loopback [127.0.0.1]) by d23av02.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q3J5gHKr014530 for ; Thu, 19 Apr 2012 15:42:17 +1000 Received: from mm.cn.ibm.com (mm.cn.ibm.com [9.115.125.0]) by d23av02.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q3J5gC61014397; Thu, 19 Apr 2012 15:42:16 +1000 From: Li Zhi Hui To: qemu-devel@nongnu.org Date: Thu, 19 Apr 2012 13:42:09 +0800 Message-Id: <1334814129-26465-2-git-send-email-zhihuili@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1334814129-26465-1-git-send-email-zhihuili@linux.vnet.ibm.com> References: <1334814129-26465-1-git-send-email-zhihuili@linux.vnet.ibm.com> x-cbid: 12041819-7014-0000-0000-000000EF8119 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.81.31.148 Cc: Li Zhi Hui Subject: [Qemu-devel] [PATCH 2/2 v5] Replace bdrv_* to bdrv_aio_* functions in DMA mode in fdc.c. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Replace bdrv_* to bdrv_aio_* functions in DMA mode in fdc.c. Signed-off-by: Li Zhi Hui --- change log: v3: correct some mistakes about memory v4: change the return value of function fdctrl_transfer_handler v5: introduce a flag to avoid re-enter function fdctrl_transfer_handler hw/fdc.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 206 insertions(+), 71 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index a0236b7..cf3e0ba 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -429,6 +429,9 @@ struct FDCtrl { /* Timers state */ uint8_t timer0; uint8_t timer1; + bool idle_flag; + QEMUIOVector qiov; + struct iovec iov; }; typedef struct FDCtrlSysBus { @@ -443,6 +446,12 @@ typedef struct FDCtrlISABus { int32_t bootindexB; } FDCtrlISABus; +typedef struct FDC_opaque { + FDCtrl *fdctrl; + int nchan; + int dma_len; +} FDC_opaque; + static uint32_t fdctrl_read (void *opaque, uint32_t reg) { FDCtrl *fdctrl = opaque; @@ -1153,8 +1162,8 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) /* Now, we just have to wait for the DMA controller to * recall us... */ + fdctrl->idle_flag = true; DMA_hold_DREQ(fdctrl->dma_chann); - DMA_schedule(fdctrl->dma_chann); return; } else { FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction); @@ -1181,6 +1190,123 @@ static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction) fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); } +static void fdctrl_read_DMA_cb(void *opaque, int ret) +{ + FDC_opaque *opaque_cb = opaque; + FDCtrl *fdctrl = opaque_cb->fdctrl; + int nchan = opaque_cb->nchan; + int dma_len = opaque_cb->dma_len; + FDrive *cur_drv; + int len, start_pos, rel_pos; + uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; + + if (ret < 0) { + FLOPPY_DPRINTF("Floppy: error getting sector %d\n", + fd_sector(cur_drv)); + /* Sure, image size is too small... */ + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); + goto error; + } + + cur_drv = get_cur_drv(fdctrl); + rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; + for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) { + len = dma_len - fdctrl->data_pos; + if (len + rel_pos > FD_SECTOR_LEN) { + len = FD_SECTOR_LEN - rel_pos; + } + + if (fdctrl->data_dir == FD_DIR_READ) { + /* READ commands */ + DMA_write_memory(nchan, + (char *)(fdctrl->qiov.iov->iov_base) + + fdctrl->data_pos + rel_pos, fdctrl->data_pos, len); + } else { + /* SCAN commands */ + uint8_t tmpbuf[FD_SECTOR_LEN]; + int ret; + DMA_read_memory(nchan, tmpbuf, fdctrl->data_pos, len); + ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); + if (ret == 0) { + status2 = FD_SR2_SEH; + } + if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) || + (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) { + status2 = 0x00; + } + goto end_transfer; + } + fdctrl->data_pos += len; + rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; + if (rel_pos == 0) { + /* Seek to next sector */ + if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) { + break; + } + } + } +end_transfer: + len = fdctrl->data_pos - start_pos; + FLOPPY_DPRINTF("end transfer %d %d %d\n", + fdctrl->data_pos, len, fdctrl->data_len); + if ((fdctrl->data_dir == FD_DIR_SCANE) || + (fdctrl->data_dir == FD_DIR_SCANL) || + (fdctrl->data_dir == FD_DIR_SCANH)) { + status2 = FD_SR2_SEH; + } + + if (FD_DID_SEEK(fdctrl->data_state)) { + status0 |= FD_SR0_SEEK; + } + fdctrl->data_len -= len; + DMA_set_return(len, nchan); + fdctrl_stop_transfer(fdctrl, status0, status1, status2); + +error: + qemu_vfree(fdctrl->iov.iov_base); + g_free(opaque_cb); + DMA_schedule(fdctrl->dma_chann); + return; +} + +static void fdctrl_write_DMA_cb(void *opaque, int ret) +{ + FDC_opaque *opaque_cb = opaque; + FDCtrl *fdctrl = opaque_cb->fdctrl; + int nchan = opaque_cb->nchan; + int dma_len = opaque_cb->dma_len; + uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; + + if (ret < 0) { + FLOPPY_DPRINTF("Floppy: error getting sector %d\n", + fd_sector(cur_drv)); + /* Sure, image size is too small... */ + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); + goto error; + } + + FLOPPY_DPRINTF("end transfer %d %d %d\n", + fdctrl->data_pos, dma_len, fdctrl->data_len); + if ((fdctrl->data_dir == FD_DIR_SCANE) || + (fdctrl->data_dir == FD_DIR_SCANL) || + (fdctrl->data_dir == FD_DIR_SCANH)) { + status2 = FD_SR2_SEH; + } + + if (FD_DID_SEEK(fdctrl->data_state)) { + status0 |= FD_SR0_SEEK; + } + fdctrl->data_len -= dma_len; + DMA_set_return(dma_len, nchan); + fdctrl_stop_transfer(fdctrl, status0, status1, status2); + +error: + qemu_vfree(fdctrl->iov.iov_base); + g_free(opaque_cb); + DMA_schedule(fdctrl->dma_chann); + return; +} + /* handlers for DMA transfers */ static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len) @@ -1189,116 +1315,124 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, FDrive *cur_drv; int len, start_pos, rel_pos; uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; + int fdc_sector_num = 0; + uint8_t *pfdc_string = NULL; + FDC_opaque *opaque_cb; + bool write_flag = false; + int write_sector = 0; fdctrl = opaque; + + if (true == fdctrl->idle_flag) { + fdctrl->idle_flag = false; + } else { + return 0; + } + if (fdctrl->msr & FD_MSR_RQM) { FLOPPY_DPRINTF("Not in DMA transfer mode !\n"); return 0; } cur_drv = get_cur_drv(fdctrl); - if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || - fdctrl->data_dir == FD_DIR_SCANH) + if ((fdctrl->data_dir == FD_DIR_SCANE) || + (fdctrl->data_dir == FD_DIR_SCANL) || + (fdctrl->data_dir == FD_DIR_SCANH)) { status2 = FD_SR2_SNS; - if (dma_len > fdctrl->data_len) + } + if (dma_len > fdctrl->data_len) { dma_len = fdctrl->data_len; + } if (cur_drv->bs == NULL) { - if (fdctrl->data_dir == FD_DIR_WRITE) - fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); - else + if (fdctrl->data_dir == FD_DIR_WRITE) { + fdctrl_stop_transfer(fdctrl, + FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); + } else { fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); + } len = 0; goto transfer_error; } + + if ((fdctrl->data_dir != FD_DIR_WRITE) && (fdctrl->data_pos < dma_len)) { + fdc_sector_num = (dma_len + FD_SECTOR_LEN - 1) / FD_SECTOR_LEN; + opaque_cb = g_malloc0(sizeof(FDC_opaque)); + pfdc_string = qemu_blockalign(cur_drv->bs, + fdc_sector_num * FD_SECTOR_LEN); + opaque_cb->fdctrl = fdctrl; + opaque_cb->nchan = nchan; + opaque_cb->dma_len = dma_len; + + fdctrl->iov.iov_base = pfdc_string; + fdctrl->iov.iov_len = fdc_sector_num * FD_SECTOR_LEN; + qemu_iovec_init_external(&fdctrl->qiov, &fdctrl->iov, 1); + bdrv_aio_readv(cur_drv->bs, fd_sector(cur_drv), + &fdctrl->qiov, fdc_sector_num, fdctrl_read_DMA_cb, opaque_cb); + return 0; + } + + if ((fdctrl->data_dir == FD_DIR_WRITE) && (fdctrl->data_pos < dma_len)) { + fdc_sector_num = (dma_len + FD_SECTOR_LEN - 1) / FD_SECTOR_LEN; + pfdc_string = qemu_blockalign(cur_drv->bs, + fdc_sector_num * FD_SECTOR_LEN); + write_flag = TRUE; + write_sector = fd_sector(cur_drv); + } + rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) { len = dma_len - fdctrl->data_pos; - if (len + rel_pos > FD_SECTOR_LEN) + if (len + rel_pos > FD_SECTOR_LEN) { len = FD_SECTOR_LEN - rel_pos; + } FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x " "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos, fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), fd_sector(cur_drv) * FD_SECTOR_LEN); - if (fdctrl->data_dir != FD_DIR_WRITE || - len < FD_SECTOR_LEN || rel_pos != 0) { - /* READ & SCAN commands and realign to a sector for WRITE */ - if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, 1) < 0) { - FLOPPY_DPRINTF("Floppy: error getting sector %d\n", - fd_sector(cur_drv)); - /* Sure, image size is too small... */ - memset(fdctrl->fifo, 0, FD_SECTOR_LEN); - } - } - switch (fdctrl->data_dir) { - case FD_DIR_READ: - /* READ commands */ - DMA_write_memory (nchan, fdctrl->fifo + rel_pos, - fdctrl->data_pos, len); - break; - case FD_DIR_WRITE: - /* WRITE commands */ - if (cur_drv->ro) { - /* Handle readonly medium early, no need to do DMA, touch the - * LED or attempt any writes. A real floppy doesn't attempt - * to write to readonly media either. */ - fdctrl_stop_transfer(fdctrl, - FD_SR0_ABNTERM | FD_SR0_SEEK, FD_SR1_NW, - 0x00); - goto transfer_error; - } - DMA_read_memory (nchan, fdctrl->fifo + rel_pos, + /* WRITE commands */ + DMA_read_memory(nchan, pfdc_string + fdctrl->data_pos + rel_pos, fdctrl->data_pos, len); - if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv)); - fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); - goto transfer_error; - } - break; - default: - /* SCAN commands */ - { - uint8_t tmpbuf[FD_SECTOR_LEN]; - int ret; - DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len); - ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); - if (ret == 0) { - status2 = FD_SR2_SEH; - goto end_transfer; - } - if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) || - (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) { - status2 = 0x00; - goto end_transfer; - } - } - break; - } fdctrl->data_pos += len; rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; if (rel_pos == 0) { /* Seek to next sector */ - if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) + if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) { break; + } } } - end_transfer: + + if (true == write_flag) { + opaque_cb = g_malloc0(sizeof(FDC_opaque)); + opaque_cb->fdctrl = fdctrl; + opaque_cb->nchan = nchan; + opaque_cb->dma_len = dma_len; + + fdctrl->iov.iov_base = pfdc_string; + fdctrl->iov.iov_len = fdc_sector_num * FD_SECTOR_LEN; + qemu_iovec_init_external(&fdctrl->qiov, &fdctrl->iov, 1); + bdrv_aio_writev(cur_drv->bs, write_sector, + &fdctrl->qiov, fdc_sector_num, fdctrl_write_DMA_cb, opaque_cb); + return 0; + } + len = fdctrl->data_pos - start_pos; FLOPPY_DPRINTF("end transfer %d %d %d\n", fdctrl->data_pos, len, fdctrl->data_len); - if (fdctrl->data_dir == FD_DIR_SCANE || - fdctrl->data_dir == FD_DIR_SCANL || - fdctrl->data_dir == FD_DIR_SCANH) + if ((fdctrl->data_dir == FD_DIR_SCANE) || + (fdctrl->data_dir == FD_DIR_SCANL) || + (fdctrl->data_dir == FD_DIR_SCANH)) { status2 = FD_SR2_SEH; - if (FD_DID_SEEK(fdctrl->data_state)) + } + if (FD_DID_SEEK(fdctrl->data_state)) { status0 |= FD_SR0_SEEK; + } fdctrl->data_len -= len; fdctrl_stop_transfer(fdctrl, status0, status1, status2); - transfer_error: +transfer_error: - return len; + return 0; } /* Data register : 0x05 */ @@ -1955,6 +2089,7 @@ static int fdctrl_init_common(FDCtrl *fdctrl) fdctrl->version = 0x90; /* Intel 82078 controller */ fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */ fdctrl->num_floppies = MAX_FD; + fdctrl->idle_flag = false; if (fdctrl->dma_chann != -1) DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);