1977e1244SGerd Hoffmann /* 2977e1244SGerd Hoffmann * QEMU IDE Emulation: PCI Bus support. 3977e1244SGerd Hoffmann * 4977e1244SGerd Hoffmann * Copyright (c) 2003 Fabrice Bellard 5977e1244SGerd Hoffmann * Copyright (c) 2006 Openedhand Ltd. 6977e1244SGerd Hoffmann * 7977e1244SGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy 8977e1244SGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal 9977e1244SGerd Hoffmann * in the Software without restriction, including without limitation the rights 10977e1244SGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11977e1244SGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is 12977e1244SGerd Hoffmann * furnished to do so, subject to the following conditions: 13977e1244SGerd Hoffmann * 14977e1244SGerd Hoffmann * The above copyright notice and this permission notice shall be included in 15977e1244SGerd Hoffmann * all copies or substantial portions of the Software. 16977e1244SGerd Hoffmann * 17977e1244SGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18977e1244SGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19977e1244SGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20977e1244SGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21977e1244SGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22977e1244SGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23977e1244SGerd Hoffmann * THE SOFTWARE. 24977e1244SGerd Hoffmann */ 2559f2a787SGerd Hoffmann #include <hw/hw.h> 2659f2a787SGerd Hoffmann #include <hw/pc.h> 2759f2a787SGerd Hoffmann #include <hw/pci.h> 28feef3102SGerd Hoffmann #include <hw/isa.h> 29977e1244SGerd Hoffmann #include "block.h" 30977e1244SGerd Hoffmann #include "block_int.h" 31977e1244SGerd Hoffmann #include "sysemu.h" 32977e1244SGerd Hoffmann #include "dma.h" 3359f2a787SGerd Hoffmann 3465c0f135SJuan Quintela #include <hw/ide/pci.h> 35977e1244SGerd Hoffmann 363e7e1558SJuan Quintela void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) 37977e1244SGerd Hoffmann { 38977e1244SGerd Hoffmann BMDMAState *bm = opaque; 39977e1244SGerd Hoffmann #ifdef DEBUG_IDE 40977e1244SGerd Hoffmann printf("%s: 0x%08x\n", __func__, val); 41977e1244SGerd Hoffmann #endif 42977e1244SGerd Hoffmann if (!(val & BM_CMD_START)) { 43953844d1SAndrea Arcangeli /* 44953844d1SAndrea Arcangeli * We can't cancel Scatter Gather DMA in the middle of the 45953844d1SAndrea Arcangeli * operation or a partial (not full) DMA transfer would reach 46953844d1SAndrea Arcangeli * the storage so we wait for completion instead (we beahve 47953844d1SAndrea Arcangeli * like if the DMA was completed by the time the guest trying 48953844d1SAndrea Arcangeli * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not 49953844d1SAndrea Arcangeli * set). 50953844d1SAndrea Arcangeli * 51953844d1SAndrea Arcangeli * In the future we'll be able to safely cancel the I/O if the 52953844d1SAndrea Arcangeli * whole DMA operation will be submitted to disk with a single 53953844d1SAndrea Arcangeli * aio operation with preadv/pwritev. 54953844d1SAndrea Arcangeli */ 55953844d1SAndrea Arcangeli if (bm->aiocb) { 56953844d1SAndrea Arcangeli qemu_aio_flush(); 57953844d1SAndrea Arcangeli #ifdef DEBUG_IDE 58953844d1SAndrea Arcangeli if (bm->aiocb) 59953844d1SAndrea Arcangeli printf("ide_dma_cancel: aiocb still pending"); 60953844d1SAndrea Arcangeli if (bm->status & BM_STATUS_DMAING) 61953844d1SAndrea Arcangeli printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); 62953844d1SAndrea Arcangeli #endif 63953844d1SAndrea Arcangeli } 64977e1244SGerd Hoffmann bm->cmd = val & 0x09; 65977e1244SGerd Hoffmann } else { 66977e1244SGerd Hoffmann if (!(bm->status & BM_STATUS_DMAING)) { 67977e1244SGerd Hoffmann bm->status |= BM_STATUS_DMAING; 68977e1244SGerd Hoffmann /* start dma transfer if possible */ 69977e1244SGerd Hoffmann if (bm->dma_cb) 70977e1244SGerd Hoffmann bm->dma_cb(bm, 0); 71977e1244SGerd Hoffmann } 72977e1244SGerd Hoffmann bm->cmd = val & 0x09; 73977e1244SGerd Hoffmann } 74977e1244SGerd Hoffmann } 75977e1244SGerd Hoffmann 76*9fbef1acSAvi Kivity static void bmdma_addr_read(IORange *ioport, uint64_t addr, 77*9fbef1acSAvi Kivity unsigned width, uint64_t *data) 78977e1244SGerd Hoffmann { 79*9fbef1acSAvi Kivity BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); 80*9fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 81*9fbef1acSAvi Kivity 82*9fbef1acSAvi Kivity *data = (bm->addr >> (addr * 8)) & mask; 83977e1244SGerd Hoffmann #ifdef DEBUG_IDE 84*9fbef1acSAvi Kivity printf("%s: 0x%08x\n", __func__, (unsigned)*data); 85977e1244SGerd Hoffmann #endif 86977e1244SGerd Hoffmann } 87977e1244SGerd Hoffmann 88*9fbef1acSAvi Kivity static void bmdma_addr_write(IORange *ioport, uint64_t addr, 89*9fbef1acSAvi Kivity unsigned width, uint64_t data) 90977e1244SGerd Hoffmann { 91*9fbef1acSAvi Kivity BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); 92*9fbef1acSAvi Kivity int shift = addr * 8; 93*9fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 94*9fbef1acSAvi Kivity 95977e1244SGerd Hoffmann #ifdef DEBUG_IDE 96*9fbef1acSAvi Kivity printf("%s: 0x%08x\n", __func__, (unsigned)data); 97977e1244SGerd Hoffmann #endif 98*9fbef1acSAvi Kivity bm->addr &= ~(mask << shift); 99*9fbef1acSAvi Kivity bm->addr |= ((data & mask) << shift) & ~3; 100977e1244SGerd Hoffmann bm->cur_addr = bm->addr; 101977e1244SGerd Hoffmann } 102977e1244SGerd Hoffmann 103*9fbef1acSAvi Kivity const IORangeOps bmdma_addr_ioport_ops = { 104*9fbef1acSAvi Kivity .read = bmdma_addr_read, 105*9fbef1acSAvi Kivity .write = bmdma_addr_write, 106*9fbef1acSAvi Kivity }; 107977e1244SGerd Hoffmann 1085ee84c33SJuan Quintela static bool ide_bmdma_current_needed(void *opaque) 1095ee84c33SJuan Quintela { 1105ee84c33SJuan Quintela BMDMAState *bm = opaque; 1115ee84c33SJuan Quintela 1125ee84c33SJuan Quintela return (bm->cur_prd_len != 0); 1135ee84c33SJuan Quintela } 1145ee84c33SJuan Quintela 1155ee84c33SJuan Quintela static const VMStateDescription vmstate_bmdma_current = { 1165ee84c33SJuan Quintela .name = "ide bmdma_current", 1175ee84c33SJuan Quintela .version_id = 1, 1185ee84c33SJuan Quintela .minimum_version_id = 1, 1195ee84c33SJuan Quintela .minimum_version_id_old = 1, 1205ee84c33SJuan Quintela .fields = (VMStateField []) { 1215ee84c33SJuan Quintela VMSTATE_UINT32(cur_addr, BMDMAState), 1225ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_last, BMDMAState), 1235ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_addr, BMDMAState), 1245ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_len, BMDMAState), 1255ee84c33SJuan Quintela VMSTATE_END_OF_LIST() 1265ee84c33SJuan Quintela } 1275ee84c33SJuan Quintela }; 1285ee84c33SJuan Quintela 1295ee84c33SJuan Quintela 130407a4f30SJuan Quintela static const VMStateDescription vmstate_bmdma = { 131407a4f30SJuan Quintela .name = "ide bmdma", 13257338424SJuan Quintela .version_id = 3, 133407a4f30SJuan Quintela .minimum_version_id = 0, 134407a4f30SJuan Quintela .minimum_version_id_old = 0, 135407a4f30SJuan Quintela .fields = (VMStateField []) { 136407a4f30SJuan Quintela VMSTATE_UINT8(cmd, BMDMAState), 137407a4f30SJuan Quintela VMSTATE_UINT8(status, BMDMAState), 138407a4f30SJuan Quintela VMSTATE_UINT32(addr, BMDMAState), 139407a4f30SJuan Quintela VMSTATE_INT64(sector_num, BMDMAState), 140407a4f30SJuan Quintela VMSTATE_UINT32(nsector, BMDMAState), 141407a4f30SJuan Quintela VMSTATE_UINT8(unit, BMDMAState), 142407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 1435ee84c33SJuan Quintela }, 1445ee84c33SJuan Quintela .subsections = (VMStateSubsection []) { 1455ee84c33SJuan Quintela { 1465ee84c33SJuan Quintela .vmsd = &vmstate_bmdma_current, 1475ee84c33SJuan Quintela .needed = ide_bmdma_current_needed, 1485ee84c33SJuan Quintela }, { 1495ee84c33SJuan Quintela /* empty */ 1505ee84c33SJuan Quintela } 151407a4f30SJuan Quintela } 152407a4f30SJuan Quintela }; 153407a4f30SJuan Quintela 154407a4f30SJuan Quintela static int ide_pci_post_load(void *opaque, int version_id) 155977e1244SGerd Hoffmann { 156977e1244SGerd Hoffmann PCIIDEState *d = opaque; 157977e1244SGerd Hoffmann int i; 158977e1244SGerd Hoffmann 159977e1244SGerd Hoffmann for(i = 0; i < 2; i++) { 160407a4f30SJuan Quintela /* current versions always store 0/1, but older version 161407a4f30SJuan Quintela stored bigger values. We only need last bit */ 162407a4f30SJuan Quintela d->bmdma[i].unit &= 1; 163977e1244SGerd Hoffmann } 164977e1244SGerd Hoffmann return 0; 165977e1244SGerd Hoffmann } 166977e1244SGerd Hoffmann 167407a4f30SJuan Quintela const VMStateDescription vmstate_ide_pci = { 168407a4f30SJuan Quintela .name = "ide", 16957338424SJuan Quintela .version_id = 3, 170407a4f30SJuan Quintela .minimum_version_id = 0, 171407a4f30SJuan Quintela .minimum_version_id_old = 0, 172407a4f30SJuan Quintela .post_load = ide_pci_post_load, 173407a4f30SJuan Quintela .fields = (VMStateField []) { 174407a4f30SJuan Quintela VMSTATE_PCI_DEVICE(dev, PCIIDEState), 175407a4f30SJuan Quintela VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, 176407a4f30SJuan Quintela vmstate_bmdma, BMDMAState), 177407a4f30SJuan Quintela VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), 178407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState), 179407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState), 180407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 181407a4f30SJuan Quintela } 182407a4f30SJuan Quintela }; 183407a4f30SJuan Quintela 1843e7e1558SJuan Quintela void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table) 185feef3102SGerd Hoffmann { 186feef3102SGerd Hoffmann PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); 187feef3102SGerd Hoffmann static const int bus[4] = { 0, 0, 1, 1 }; 188feef3102SGerd Hoffmann static const int unit[4] = { 0, 1, 0, 1 }; 189feef3102SGerd Hoffmann int i; 190feef3102SGerd Hoffmann 191feef3102SGerd Hoffmann for (i = 0; i < 4; i++) { 192feef3102SGerd Hoffmann if (hd_table[i] == NULL) 193feef3102SGerd Hoffmann continue; 1941f850f10SGerd Hoffmann ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]); 195feef3102SGerd Hoffmann } 196feef3102SGerd Hoffmann } 197