diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-08-18 11:59:26 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-08-18 11:59:27 +0100 |
commit | da398fcc256b226217c92c8a83abf3a6ff247e8b (patch) | |
tree | e9d8ec4f6ff1b43933644fa8d5b422c05f46380e /hw/ide/ahci.c | |
parent | 142f4ac5d5e024670ef4725e8943702b027e4218 (diff) | |
parent | 39ba3bf69c4ef4d8a8b683ee7282efd25b3f01ff (diff) | |
download | qemu-da398fcc256b226217c92c8a83abf3a6ff247e8b.tar.gz |
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
Block pull request
# gpg: Signature made Fri 15 Aug 2014 18:04:23 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>"
* remotes/stefanha/tags/block-pull-request: (55 commits)
qcow2: fix new_blocks double-free in alloc_refcount_block()
image-fuzzer: Reduce number of generator functions in __init__
image-fuzzer: Add generators of L1/L2 tables
image-fuzzer: Add fuzzing functions for L1/L2 table entries
docs: Expand the list of supported image elements with L1/L2 tables
image-fuzzer: Public API for image-fuzzer/runner/runner.py
image-fuzzer: Generator of fuzzed qcow2 images
image-fuzzer: Fuzzing functions for qcow2 images
image-fuzzer: Tool for fuzz tests execution
docs: Specification for the image fuzzer
ide: only constrain read/write requests to drive size, not other types
virtio-blk: Correct bug in support for flexible descriptor layout
libqos: Change free function called in malloc
libqos: Correct mask to align size to PAGE_SIZE in malloc-pc
libqtest: add QTEST_LOG for debugging qtest testcases
ide: Fix segfault when flushing a device that doesn't exist
qemu-options: add missing -drive discard option to cmdline help
parallels: 2TB+ parallels images support
parallels: split check for parallels format in parallels_open
parallels: replace tabs with spaces in block/parallels.c
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/ide/ahci.c')
-rw-r--r-- | hw/ide/ahci.c | 115 |
1 files changed, 73 insertions, 42 deletions
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 604152a823..4cda0d0075 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -584,7 +584,72 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) s->dev[port].finished |= finished; *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished); - ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS); + ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_SDB_FIS); +} + +static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) +{ + AHCIPortRegs *pr = &ad->port_regs; + uint8_t *pio_fis, *cmd_fis; + uint64_t tbl_addr; + dma_addr_t cmd_len = 0x80; + + if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) { + return; + } + + /* map cmd_fis */ + tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr); + cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len, + DMA_DIRECTION_TO_DEVICE); + + if (cmd_fis == NULL) { + DPRINTF(ad->port_no, "dma_memory_map failed in ahci_write_fis_pio"); + ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR); + return; + } + + if (cmd_len != 0x80) { + DPRINTF(ad->port_no, + "dma_memory_map mapped too few bytes in ahci_write_fis_pio"); + dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len, + DMA_DIRECTION_TO_DEVICE, cmd_len); + ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR); + return; + } + + pio_fis = &ad->res_fis[RES_FIS_PSFIS]; + + pio_fis[0] = 0x5f; + pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); + pio_fis[2] = ad->port.ifs[0].status; + pio_fis[3] = ad->port.ifs[0].error; + + pio_fis[4] = cmd_fis[4]; + pio_fis[5] = cmd_fis[5]; + pio_fis[6] = cmd_fis[6]; + pio_fis[7] = cmd_fis[7]; + pio_fis[8] = cmd_fis[8]; + pio_fis[9] = cmd_fis[9]; + pio_fis[10] = cmd_fis[10]; + pio_fis[11] = cmd_fis[11]; + pio_fis[12] = cmd_fis[12]; + pio_fis[13] = cmd_fis[13]; + pio_fis[14] = 0; + pio_fis[15] = ad->port.ifs[0].status; + pio_fis[16] = len & 255; + pio_fis[17] = len >> 8; + pio_fis[18] = 0; + pio_fis[19] = 0; + + if (pio_fis[2] & ERR_STAT) { + ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR); + } + + ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS); + + dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len, + DMA_DIRECTION_TO_DEVICE, cmd_len); } static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) @@ -629,7 +694,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) } if (d2h_fis[2] & ERR_STAT) { - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES); + ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR); } ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS); @@ -969,11 +1034,6 @@ static int handle_cmd(AHCIState *s, int port, int slot) /* We're ready to process the command in FIS byte 2. */ ide_exec_cmd(&s->dev[port].port, cmd_fis[2]); - - if ((s->dev[port].port.ifs[0].status & (READY_STAT|DRQ_STAT|BUSY_STAT)) == - READY_STAT) { - ahci_write_fis_d2h(&s->dev[port], cmd_fis); - } } out: @@ -991,7 +1051,7 @@ out: } /* DMA dev <-> ram */ -static int ahci_start_transfer(IDEDMA *dma) +static void ahci_start_transfer(IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); IDEState *s = &ad->port.ifs[0]; @@ -1038,11 +1098,9 @@ out: s->end_transfer_func(s); if (!(s->status & DRQ_STAT)) { - /* done with DMA */ - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS); + /* done with PIO send/receive */ + ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status)); } - - return 0; } static void ahci_start_dma(IDEDMA *dma, IDEState *s, @@ -1104,28 +1162,11 @@ static int ahci_dma_set_unit(IDEDMA *dma, int unit) return 0; } -static int ahci_dma_add_status(IDEDMA *dma, int status) -{ - AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - DPRINTF(ad->port_no, "set status: %x\n", status); - - if (status & BM_STATUS_INT) { - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS); - } - - return 0; -} - -static int ahci_dma_set_inactive(IDEDMA *dma) -{ - return 0; -} - -static int ahci_async_cmd_done(IDEDMA *dma) +static void ahci_cmd_done(IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - DPRINTF(ad->port_no, "async cmd done\n"); + DPRINTF(ad->port_no, "cmd done\n"); /* update d2h status */ ahci_write_fis_d2h(ad, NULL); @@ -1135,8 +1176,6 @@ static int ahci_async_cmd_done(IDEDMA *dma) ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); qemu_bh_schedule(ad->check_bh); } - - return 0; } static void ahci_irq_set(void *opaque, int n, int level) @@ -1147,22 +1186,14 @@ static void ahci_dma_restart_cb(void *opaque, int running, RunState state) { } -static int ahci_dma_reset(IDEDMA *dma) -{ - return 0; -} - static const IDEDMAOps ahci_dma_ops = { .start_dma = ahci_start_dma, .start_transfer = ahci_start_transfer, .prepare_buf = ahci_dma_prepare_buf, .rw_buf = ahci_dma_rw_buf, .set_unit = ahci_dma_set_unit, - .add_status = ahci_dma_add_status, - .set_inactive = ahci_dma_set_inactive, - .async_cmd_done = ahci_async_cmd_done, + .cmd_done = ahci_cmd_done, .restart_cb = ahci_dma_restart_cb, - .reset = ahci_dma_reset, }; void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports) |