ide: Ignore double DMA transfer starts/stops

You can only start a DMA transfer if it's not running yet, and you can only
cancel it if it's running.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
This commit is contained in:
Kevin Wolf 2010-11-26 16:44:53 +01:00
parent e3982b3cf6
commit c29947bbb0

View File

@ -39,38 +39,42 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
#ifdef DEBUG_IDE #ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val); printf("%s: 0x%08x\n", __func__, val);
#endif #endif
if (!(val & BM_CMD_START)) {
/* /* Ignore writes to SSBM if it keeps the old value */
* We can't cancel Scatter Gather DMA in the middle of the if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
* operation or a partial (not full) DMA transfer would reach if (!(val & BM_CMD_START)) {
* the storage so we wait for completion instead (we beahve /*
* like if the DMA was completed by the time the guest trying * We can't cancel Scatter Gather DMA in the middle of the
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not * operation or a partial (not full) DMA transfer would reach
* set). * the storage so we wait for completion instead (we beahve
* * like if the DMA was completed by the time the guest trying
* In the future we'll be able to safely cancel the I/O if the * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
* whole DMA operation will be submitted to disk with a single * set).
* aio operation with preadv/pwritev. *
*/ * In the future we'll be able to safely cancel the I/O if the
if (bm->aiocb) { * whole DMA operation will be submitted to disk with a single
qemu_aio_flush(); * aio operation with preadv/pwritev.
*/
if (bm->aiocb) {
qemu_aio_flush();
#ifdef DEBUG_IDE #ifdef DEBUG_IDE
if (bm->aiocb) if (bm->aiocb)
printf("ide_dma_cancel: aiocb still pending"); printf("ide_dma_cancel: aiocb still pending");
if (bm->status & BM_STATUS_DMAING) if (bm->status & BM_STATUS_DMAING)
printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
#endif #endif
}
} else {
if (!(bm->status & BM_STATUS_DMAING)) {
bm->status |= BM_STATUS_DMAING;
/* start dma transfer if possible */
if (bm->dma_cb)
bm->dma_cb(bm, 0);
}
} }
bm->cmd = val & 0x09;
} else {
if (!(bm->status & BM_STATUS_DMAING)) {
bm->status |= BM_STATUS_DMAING;
/* start dma transfer if possible */
if (bm->dma_cb)
bm->dma_cb(bm, 0);
}
bm->cmd = val & 0x09;
} }
bm->cmd = val & 0x09;
} }
static void bmdma_addr_read(IORange *ioport, uint64_t addr, static void bmdma_addr_read(IORange *ioport, uint64_t addr,