Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- hw/ide/core.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/ide/internal.h | 2 ++ hw/ide/pci.c | 68 ------------------------------------------------------- hw/ide/pci.h | 1 - 4 files changed, 67 insertions(+), 70 deletions(-)
diff --git a/hw/ide/core.c b/hw/ide/core.c index 5820fad..256f62a 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2193,9 +2193,73 @@ static const IDEDMAOps ide_dma_nop_ops = { .restart_cb = ide_nop_restart, }; +static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd) +{ + s->bus->dma->ops->restart_dma(s->bus->dma); + s->io_buffer_index = 0; + s->io_buffer_size = 0; + s->dma_cmd = dma_cmd; + ide_start_dma(s, ide_dma_cb); +} + +static void ide_restart_bh(void *opaque) +{ + IDEBus *bus = opaque; + IDEState *s; + bool is_read; + int error_status; + + qemu_bh_delete(bus->bh); + bus->bh = NULL; + + error_status = bus->error_status; + if (bus->error_status == 0) { + return; + } + + s = idebus_active_if(bus); + is_read = (bus->error_status & IDE_RETRY_READ) != 0; + + /* The error status must be cleared before resubmitting the request: The + * request may fail again, and this case can only be distinguished if the + * called function can set a new error status. */ + bus->error_status = 0; + + if (error_status & IDE_RETRY_DMA) { + if (error_status & IDE_RETRY_TRIM) { + ide_restart_dma(s, IDE_DMA_TRIM); + } else { + ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE); + } + } else if (error_status & IDE_RETRY_PIO) { + if (is_read) { + ide_sector_read(s); + } else { + ide_sector_write(s); + } + } else if (error_status & IDE_RETRY_FLUSH) { + ide_flush_cache(s); + } +} + +static void ide_restart_cb(void *opaque, int running, RunState state) +{ + IDEBus *bus = opaque; + + if (!running) + return; + + if (!bus->bh) { + bus->bh = qemu_bh_new(ide_restart_bh, bus); + qemu_bh_schedule(bus->bh); + } +} + void ide_register_restart_cb(IDEBus *bus) { - qemu_add_vm_change_state_handler(bus->dma->ops->restart_cb, bus); + if (bus->dma->ops->restart_dma) { + qemu_add_vm_change_state_handler(ide_restart_cb, bus); + } } static IDEDMA ide_dma_nop = { diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 678b33c..e24f6cb 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -452,6 +452,8 @@ struct IDEBus { IDEDevice *master; IDEDevice *slave; IDEState ifs[2]; + QEMUBH *bh; + int bus_id; int max_units; IDEDMA *dma; diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 9d26a26..7568f1e 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -185,73 +185,6 @@ static void bmdma_restart_dma(IDEDMA *dma) bm->cur_addr = bm->addr; } -static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd) -{ - if (s->bus->dma->ops->restart_dma) { - s->bus->dma->ops->restart_dma(s->bus->dma); - } - s->io_buffer_index = 0; - s->io_buffer_size = 0; - s->dma_cmd = dma_cmd; - ide_start_dma(s, ide_dma_cb); -} - -/* TODO This should be common IDE code */ -static void bmdma_restart_bh(void *opaque) -{ - IDEBus *bus = opaque; - BMDMAState *bm = DO_UPCAST(BMDMAState, dma, bus->dma); - IDEState *s; - bool is_read; - int error_status; - - qemu_bh_delete(bm->bh); - bm->bh = NULL; - - error_status = bus->error_status; - if (bus->error_status == 0) { - return; - } - - s = idebus_active_if(bus); - is_read = (bus->error_status & IDE_RETRY_READ) != 0; - - /* The error status must be cleared before resubmitting the request: The - * request may fail again, and this case can only be distinguished if the - * called function can set a new error status. */ - bus->error_status = 0; - - if (error_status & IDE_RETRY_DMA) { - if (error_status & IDE_RETRY_TRIM) { - ide_restart_dma(s, IDE_DMA_TRIM); - } else { - ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE); - } - } else if (error_status & IDE_RETRY_PIO) { - if (is_read) { - ide_sector_read(s); - } else { - ide_sector_write(s); - } - } else if (error_status & IDE_RETRY_FLUSH) { - ide_flush_cache(s); - } -} - -static void bmdma_restart_cb(void *opaque, int running, RunState state) -{ - IDEBus *bus = opaque; - BMDMAState *bm = DO_UPCAST(BMDMAState, dma, bus->dma); - - if (!running) - return; - - if (!bm->bh) { - bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma); - qemu_bh_schedule(bm->bh); - } -} - static void bmdma_cancel(BMDMAState *bm) { if (bm->status & BM_STATUS_DMAING) { @@ -520,7 +453,6 @@ static const struct IDEDMAOps bmdma_ops = { .restart_dma = bmdma_restart_dma, .trigger_irq = bmdma_trigger_irq, .set_inactive = bmdma_set_inactive, - .restart_cb = bmdma_restart_cb, .reset = bmdma_reset, }; diff --git a/hw/ide/pci.h b/hw/ide/pci.h index 517711f..78e5550 100644 --- a/hw/ide/pci.h +++ b/hw/ide/pci.h @@ -28,7 +28,6 @@ typedef struct BMDMAState { uint32_t nsector; MemoryRegion addr_ioport; MemoryRegion extra_io; - QEMUBH *bh; qemu_irq irq; /* Bit 0-2 and 7: BM status register -- 1.8.3.1