[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 08/53] ahci: Update byte count after DMA completion
From: |
Stefan Hajnoczi |
Subject: |
[Qemu-devel] [PULL 08/53] ahci: Update byte count after DMA completion |
Date: |
Mon, 3 Nov 2014 11:50:11 +0000 |
From: John Snow <address@hidden>
Currently, DMA read/write operations neglect to update
the byte count after a successful transfer like ATAPI
DMA read or PIO read/write operations do.
We correct this oversight by adding another callback into
the IDEDMAOps structure. The commit callback is called
whenever we are cleaning up a scatter-gather list.
AHCI can register this callback in order to update post-
transfer information such as byte count updates.
We use this callback in AHCI to consolidate where we delete
the SGlist as generated from the PRDT, as well as update the
byte count after the transfer is complete.
The QEMUSGList structure has an init flag added to it in order
to make qemu_sglist_destroy a nop if it is called when
there is no sglist, which simplifies cleanup and error paths.
This patch fixes several AHCI problems, notably Non-NCQ modes
of operation for Windows 7 as well as Hibernate support for Windows 7.
Signed-off-by: John Snow <address@hidden>
Reviewed-by: Paolo Bonzini <address@hidden>
Tested-by: Michael S. Tsirkin <address@hidden>
Message-id: address@hidden
Signed-off-by: Stefan Hajnoczi <address@hidden>
---
hw/ide/ahci.c | 41 +++++++++++++++++++++++++++++++----------
hw/ide/core.c | 11 +++++++----
hw/ide/internal.h | 2 ++
3 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 03df462..d80ddd2 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -49,6 +49,9 @@ static int handle_cmd(AHCIState *s,int port,int slot);
static void ahci_reset_port(AHCIState *s, int port);
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
static void ahci_init_d2h(AHCIDevice *ad);
+static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write);
+static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
+
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
{
@@ -1105,16 +1108,12 @@ static void ahci_start_transfer(IDEDMA *dma)
}
}
- /* update number of transferred bytes */
- ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size);
-
out:
/* declare that we processed everything */
s->data_ptr = s->data_end;
- if (has_sglist) {
- qemu_sglist_destroy(&s->sg);
- }
+ /* Update number of transferred bytes, destroy sglist */
+ ahci_commit_buf(dma, size);
s->end_transfer_func(s);
@@ -1135,6 +1134,11 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
dma_cb(s, 0);
}
+/**
+ * Called in DMA R/W chains to read the PRDT, utilizing ahci_populate_sglist.
+ * Not currently invoked by PIO R/W chains,
+ * which invoke ahci_populate_sglist via ahci_start_transfer.
+ */
static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
@@ -1147,6 +1151,24 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int
is_write)
return s->io_buffer_size != 0;
}
+/**
+ * Destroys the scatter-gather list,
+ * and updates the command header with a bytes-read value.
+ * called explicitly via ahci_dma_rw_buf (ATAPI DMA),
+ * and ahci_start_transfer (PIO R/W),
+ * and called via callback from ide_dma_cb for DMA R/W paths.
+ */
+static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes)
+{
+ AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+ IDEState *s = &ad->port.ifs[0];
+
+ tx_bytes += le32_to_cpu(ad->cur_cmd->status);
+ ad->cur_cmd->status = cpu_to_le32(tx_bytes);
+
+ qemu_sglist_destroy(&s->sg);
+}
+
static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
@@ -1164,11 +1186,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
dma_buf_write(p, l, &s->sg);
}
- /* free sglist that was created in ahci_populate_sglist() */
- qemu_sglist_destroy(&s->sg);
+ /* free sglist, update byte count */
+ ahci_commit_buf(dma, l);
- /* update number of transferred bytes */
- ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
s->io_buffer_index += l;
s->io_buffer_offset += l;
@@ -1211,6 +1231,7 @@ static const IDEDMAOps ahci_dma_ops = {
.start_dma = ahci_start_dma,
.start_transfer = ahci_start_transfer,
.prepare_buf = ahci_dma_prepare_buf,
+ .commit_buf = ahci_commit_buf,
.rw_buf = ahci_dma_rw_buf,
.set_unit = ahci_dma_set_unit,
.cmd_done = ahci_cmd_done,
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 44e3d50..d316ccf 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -634,8 +634,11 @@ void ide_sector_read(IDEState *s)
ide_sector_read_cb, s);
}
-static void dma_buf_commit(IDEState *s)
+static void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
{
+ if (s->bus->dma->ops->commit_buf) {
+ s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
+ }
qemu_sglist_destroy(&s->sg);
}
@@ -650,6 +653,7 @@ void ide_set_inactive(IDEState *s, bool more)
void ide_dma_error(IDEState *s)
{
+ dma_buf_commit(s, 0);
ide_abort_command(s);
ide_set_inactive(s, false);
ide_set_irq(s->bus);
@@ -665,7 +669,6 @@ static int ide_handle_rw_error(IDEState *s, int error, int
op)
s->bus->error_status = op;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
if (op & IDE_RETRY_DMA) {
- dma_buf_commit(s);
ide_dma_error(s);
} else {
ide_rw_error(s);
@@ -709,7 +712,8 @@ void ide_dma_cb(void *opaque, int ret)
sector_num = ide_get_sector(s);
if (n > 0) {
- dma_buf_commit(s);
+ assert(s->io_buffer_size == s->sg.size);
+ dma_buf_commit(s, s->io_buffer_size);
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -740,7 +744,6 @@ void ide_dma_cb(void *opaque, int ret)
if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
!ide_sect_range_ok(s, sector_num, n)) {
- dma_buf_commit(s);
ide_dma_error(s);
return;
}
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 68ac610..907493d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -322,6 +322,7 @@ typedef void EndTransferFunc(IDEState *);
typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *);
typedef void DMAVoidFunc(IDEDMA *);
typedef int DMAIntFunc(IDEDMA *, int);
+typedef void DMAu32Func(IDEDMA *, uint32_t);
typedef void DMAStopFunc(IDEDMA *, bool);
typedef void DMARestartFunc(void *, int, RunState);
@@ -430,6 +431,7 @@ struct IDEDMAOps {
DMAStartFunc *start_dma;
DMAVoidFunc *start_transfer;
DMAIntFunc *prepare_buf;
+ DMAu32Func *commit_buf;
DMAIntFunc *rw_buf;
DMAIntFunc *set_unit;
DMAStopFunc *set_inactive;
--
1.9.3
- [Qemu-devel] [PULL 00/53] Block patches, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 02/53] BlockLimits: introduce max_transfer_length, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 01/53] util: introduce MIN_NON_ZERO, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 03/53] block/iscsi: set max_transfer_length, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 04/53] block: avoid creating oversized writes in multiwrite_merge, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 05/53] block/iscsi: use sector_limits_lun2qemu throughout iscsi_refresh_limits, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 06/53] block/iscsi: check for oversized requests, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 07/53] ahci: Correct PIO/D2H FIS responses, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 08/53] ahci: Update byte count after DMA completion,
Stefan Hajnoczi <=
- [Qemu-devel] [PULL 09/53] ahci: Fix SDB FIS Construction, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 10/53] snapshot: Reset err to NULL to avoid double free, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 11/53] iotests: replace fake parallels image with authentic one, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 12/53] iotests: add v2 parallels sample image and simple test for it, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 13/53] block/parallels: fix access to not initialized memory in catalog_bitmap, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 14/53] rbd: Add support for bdrv_invalidate_cache, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 15/53] block.c: Fix type of IoOperationType variable in send_qmp_error_event(), Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 17/53] block/curl: Improve type safety of s->timeout., Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 16/53] snapshot: add bdrv_drain_all() to bdrv_snapshot_delete() to avoid concurrency problem, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 18/53] raw-posix: Fix raw_co_get_block_status() after EOF, Stefan Hajnoczi, 2014/11/03