diff options
author | Avi Kivity <avi@redhat.com> | 2012-09-09 16:21:39 +0300 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-09-09 16:21:39 +0300 |
commit | 3505aa6bec1a3bb474d81c495515b44654659a38 (patch) | |
tree | bf0f5f9e1a76159752047cdb239c62cbbd1f2ace /hw/ide/ahci.c | |
parent | 7fa12eb15f95c269f488fce4096093c96dbaffab (diff) | |
parent | 4ce5bc2dd1914a706725186c6563e8f92eedfc84 (diff) |
Merge tag 'v1.1.2' into stable-1.1qemu-kvm-1.1.2stable-1.1
* tag 'v1.1.2': (74 commits)
update VERSION for 1.1.2
console: bounds check whenever changing the cursor due to an escape code
qemu-timer: properly arm alarm timer for timers set by device initialization
target-xtensa: return ENOSYS for unimplemented simcalls
target-xtensa: fix big-endian BBS/BBC implementation
ehci: Fix NULL ptr deref when unplugging an USB dev with an iso stream active
msix: make [un]use vectors on reset/load optional
reset PMBA and PMREGMISC PIIX4 registers.
qemu_rearm_alarm_timer: do not call rearm if the next deadline is INT64_MAX
qemu-ga: Fix null pointer passed to unlink in failure branch
memory: Fix copy&paste mistake in memory_region_iorange_write
ivshmem: remove redundant ioeventfd configuration
hw/arm_gic.c: Define .class_size in arm_gic_info TypeInfo
tcg/mips: fix broken CONFIG_TCG_PASS_AREG0 code
audio/winwave: previous audio buffer should be flushed
target-mips: allow microMIPS SWP and SDP to have RD equal to BASE
target-mips: add privilege level check to several Cop0 instructions
mips-linux-user: Always support rdhwr.
target-mips: Streamline indexed cp1 memory addressing.
Fix order of CVT.PS.S operands
...
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'hw/ide/ahci.c')
-rw-r--r-- | hw/ide/ahci.c | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 2d7d03d77..267198e52 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -634,7 +634,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) } } -static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist) +static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset) { AHCICmdHdr *cmd = ad->cur_cmd; uint32_t opts = le32_to_cpu(cmd->opts); @@ -645,6 +645,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist) uint8_t *prdt; int i; int r = 0; + int sum = 0; + int off_idx = -1; + int off_pos = -1; + int tbl_entry_size; if (!sglist_alloc_hint) { DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts); @@ -666,10 +670,31 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist) /* Get entries in the PRDT, init a qemu sglist accordingly */ if (sglist_alloc_hint > 0) { AHCI_SG *tbl = (AHCI_SG *)prdt; - - qemu_sglist_init(sglist, sglist_alloc_hint); + sum = 0; for (i = 0; i < sglist_alloc_hint; i++) { /* flags_size is zero-based */ + tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1); + if (offset <= (sum + tbl_entry_size)) { + off_idx = i; + off_pos = offset - sum; + break; + } + sum += tbl_entry_size; + } + if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) { + DPRINTF(ad->port_no, "%s: Incorrect offset! " + "off_idx: %d, off_pos: %d\n", + __func__, off_idx, off_pos); + r = -1; + goto out; + } + + qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx)); + qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos), + le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos); + + for (i = off_idx + 1; i < sglist_alloc_hint; i++) { + /* flags_size is zero-based */ qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr), le32_to_cpu(tbl[i].flags_size) + 1); } @@ -741,7 +766,7 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2, s->dev[port].port.ifs[0].nb_sectors - 1); - ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist); + ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0); ncq_tfs->tag = tag; switch(ncq_fis->command) { @@ -964,7 +989,7 @@ static int ahci_start_transfer(IDEDMA *dma) goto out; } - if (!ahci_populate_sglist(ad, &s->sg)) { + if (!ahci_populate_sglist(ad, &s->sg, 0)) { has_sglist = 1; } @@ -1009,6 +1034,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s, DPRINTF(ad->port_no, "\n"); ad->dma_cb = dma_cb; ad->dma_status |= BM_STATUS_DMAING; + s->io_buffer_offset = 0; dma_cb(s, 0); } @@ -1017,7 +1043,7 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); IDEState *s = &ad->port.ifs[0]; - ahci_populate_sglist(ad, &s->sg); + ahci_populate_sglist(ad, &s->sg, 0); s->io_buffer_size = s->sg.size; DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size); @@ -1031,7 +1057,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) uint8_t *p = s->io_buffer + s->io_buffer_index; int l = s->io_buffer_size - s->io_buffer_index; - if (ahci_populate_sglist(ad, &s->sg)) { + if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) { return 0; } @@ -1041,9 +1067,13 @@ 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); + /* 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; DPRINTF(ad->port_no, "len=%#x\n", l); |