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 */ 250b8fa32fSMarkus Armbruster 2653239262SPeter Maydell #include "qemu/osdep.h" 27da9f1172SPhilippe Mathieu-Daudé #include "hw/irq.h" 28a9c94277SMarkus Armbruster #include "hw/pci/pci.h" 29d6454270SMarkus Armbruster #include "migration/vmstate.h" 309c17d615SPaolo Bonzini #include "sysemu/dma.h" 313251bdcfSJohn Snow #include "qemu/error-report.h" 320b8fa32fSMarkus Armbruster #include "qemu/module.h" 33a9c94277SMarkus Armbruster #include "hw/ide/pci.h" 343eee2611SJohn Snow #include "trace.h" 35977e1244SGerd Hoffmann 3640a6238aSAlexander Graf #define BMDMA_PAGE_SIZE 4096 3740a6238aSAlexander Graf 387e2648dfSPaolo Bonzini #define BM_MIGRATION_COMPAT_STATUS_BITS \ 39fd648f10SPaolo Bonzini (IDE_RETRY_DMA | IDE_RETRY_PIO | \ 40fd648f10SPaolo Bonzini IDE_RETRY_READ | IDE_RETRY_FLUSH) 417e2648dfSPaolo Bonzini 4298d98912SJohn Snow static uint64_t pci_ide_status_read(void *opaque, hwaddr addr, unsigned size) 43c9ebc75dSBALATON Zoltan { 44c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 45c9ebc75dSBALATON Zoltan 46c9ebc75dSBALATON Zoltan if (addr != 2 || size != 1) { 47c9ebc75dSBALATON Zoltan return ((uint64_t)1 << (size * 8)) - 1; 48c9ebc75dSBALATON Zoltan } 49c9ebc75dSBALATON Zoltan return ide_status_read(bus, addr + 2); 50c9ebc75dSBALATON Zoltan } 51c9ebc75dSBALATON Zoltan 5298d98912SJohn Snow static void pci_ide_ctrl_write(void *opaque, hwaddr addr, 53c9ebc75dSBALATON Zoltan uint64_t data, unsigned size) 54c9ebc75dSBALATON Zoltan { 55c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 56c9ebc75dSBALATON Zoltan 57c9ebc75dSBALATON Zoltan if (addr != 2 || size != 1) { 58c9ebc75dSBALATON Zoltan return; 59c9ebc75dSBALATON Zoltan } 6098d98912SJohn Snow ide_ctrl_write(bus, addr + 2, data); 61c9ebc75dSBALATON Zoltan } 62c9ebc75dSBALATON Zoltan 63c9ebc75dSBALATON Zoltan const MemoryRegionOps pci_ide_cmd_le_ops = { 6498d98912SJohn Snow .read = pci_ide_status_read, 6598d98912SJohn Snow .write = pci_ide_ctrl_write, 66c9ebc75dSBALATON Zoltan .endianness = DEVICE_LITTLE_ENDIAN, 67c9ebc75dSBALATON Zoltan }; 68c9ebc75dSBALATON Zoltan 69c9ebc75dSBALATON Zoltan static uint64_t pci_ide_data_read(void *opaque, hwaddr addr, unsigned size) 70c9ebc75dSBALATON Zoltan { 71c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 72c9ebc75dSBALATON Zoltan 73c9ebc75dSBALATON Zoltan if (size == 1) { 74c9ebc75dSBALATON Zoltan return ide_ioport_read(bus, addr); 75c9ebc75dSBALATON Zoltan } else if (addr == 0) { 76c9ebc75dSBALATON Zoltan if (size == 2) { 77c9ebc75dSBALATON Zoltan return ide_data_readw(bus, addr); 78c9ebc75dSBALATON Zoltan } else { 79c9ebc75dSBALATON Zoltan return ide_data_readl(bus, addr); 80c9ebc75dSBALATON Zoltan } 81c9ebc75dSBALATON Zoltan } 82c9ebc75dSBALATON Zoltan return ((uint64_t)1 << (size * 8)) - 1; 83c9ebc75dSBALATON Zoltan } 84c9ebc75dSBALATON Zoltan 85c9ebc75dSBALATON Zoltan static void pci_ide_data_write(void *opaque, hwaddr addr, 86c9ebc75dSBALATON Zoltan uint64_t data, unsigned size) 87c9ebc75dSBALATON Zoltan { 88c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 89c9ebc75dSBALATON Zoltan 90c9ebc75dSBALATON Zoltan if (size == 1) { 91c9ebc75dSBALATON Zoltan ide_ioport_write(bus, addr, data); 92c9ebc75dSBALATON Zoltan } else if (addr == 0) { 93c9ebc75dSBALATON Zoltan if (size == 2) { 94c9ebc75dSBALATON Zoltan ide_data_writew(bus, addr, data); 95c9ebc75dSBALATON Zoltan } else { 96c9ebc75dSBALATON Zoltan ide_data_writel(bus, addr, data); 97c9ebc75dSBALATON Zoltan } 98c9ebc75dSBALATON Zoltan } 99c9ebc75dSBALATON Zoltan } 100c9ebc75dSBALATON Zoltan 101c9ebc75dSBALATON Zoltan const MemoryRegionOps pci_ide_data_le_ops = { 102c9ebc75dSBALATON Zoltan .read = pci_ide_data_read, 103c9ebc75dSBALATON Zoltan .write = pci_ide_data_write, 104c9ebc75dSBALATON Zoltan .endianness = DEVICE_LITTLE_ENDIAN, 105c9ebc75dSBALATON Zoltan }; 106c9ebc75dSBALATON Zoltan 1073e5f247eSBernhard Beschow static IDEState *bmdma_active_if(BMDMAState *bmdma) 1083e5f247eSBernhard Beschow { 1093e5f247eSBernhard Beschow assert(bmdma->bus->retry_unit != (uint8_t)-1); 1103e5f247eSBernhard Beschow return bmdma->bus->ifs + bmdma->bus->retry_unit; 1113e5f247eSBernhard Beschow } 1123e5f247eSBernhard Beschow 113ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_start_dma(const IDEDMA *dma, IDEState *s, 114097310b5SMarkus Armbruster BlockCompletionFunc *dma_cb) 11540a6238aSAlexander Graf { 11640a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 11740a6238aSAlexander Graf 11840a6238aSAlexander Graf bm->dma_cb = dma_cb; 11940a6238aSAlexander Graf bm->cur_prd_last = 0; 12040a6238aSAlexander Graf bm->cur_prd_addr = 0; 12140a6238aSAlexander Graf bm->cur_prd_len = 0; 12240a6238aSAlexander Graf 12340a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 12440a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 12540a6238aSAlexander Graf } 12640a6238aSAlexander Graf } 12740a6238aSAlexander Graf 1283251bdcfSJohn Snow /** 129a718978eSJohn Snow * Prepare an sglist based on available PRDs. 130a718978eSJohn Snow * @limit: How many bytes to prepare total. 131a718978eSJohn Snow * 132a718978eSJohn Snow * Returns the number of bytes prepared, -1 on error. 133a718978eSJohn Snow * IDEState.io_buffer_size will contain the number of bytes described 134a718978eSJohn Snow * by the PRDs, whether or not we added them to the sglist. 1353251bdcfSJohn Snow */ 136ae0cebd7SPhilippe Mathieu-Daudé static int32_t bmdma_prepare_buf(const IDEDMA *dma, int32_t limit) 13740a6238aSAlexander Graf { 13840a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 13940a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 140f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 14140a6238aSAlexander Graf struct { 14240a6238aSAlexander Graf uint32_t addr; 14340a6238aSAlexander Graf uint32_t size; 14440a6238aSAlexander Graf } prd; 14540a6238aSAlexander Graf int l, len; 14640a6238aSAlexander Graf 147f6c11d56SAndreas Färber pci_dma_sglist_init(&s->sg, pci_dev, 1484a13980bSPhilippe Mathieu-Daudé s->nsector / (BMDMA_PAGE_SIZE / BDRV_SECTOR_SIZE) + 1); 14940a6238aSAlexander Graf s->io_buffer_size = 0; 15040a6238aSAlexander Graf for(;;) { 15140a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 15240a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 15340a6238aSAlexander Graf if (bm->cur_prd_last || 1543251bdcfSJohn Snow (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) { 155a718978eSJohn Snow return s->sg.size; 1563251bdcfSJohn Snow } 157f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 15840a6238aSAlexander Graf bm->cur_addr += 8; 15940a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 16040a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 16140a6238aSAlexander Graf len = prd.size & 0xfffe; 16240a6238aSAlexander Graf if (len == 0) 16340a6238aSAlexander Graf len = 0x10000; 16440a6238aSAlexander Graf bm->cur_prd_len = len; 16540a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 16640a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 16740a6238aSAlexander Graf } 16840a6238aSAlexander Graf l = bm->cur_prd_len; 16940a6238aSAlexander Graf if (l > 0) { 170a718978eSJohn Snow uint64_t sg_len; 171a718978eSJohn Snow 172a718978eSJohn Snow /* Don't add extra bytes to the SGList; consume any remaining 173a718978eSJohn Snow * PRDs from the guest, but ignore them. */ 174a718978eSJohn Snow sg_len = MIN(limit - s->sg.size, bm->cur_prd_len); 175a718978eSJohn Snow if (sg_len) { 176a718978eSJohn Snow qemu_sglist_add(&s->sg, bm->cur_prd_addr, sg_len); 177a718978eSJohn Snow } 1783251bdcfSJohn Snow 17940a6238aSAlexander Graf bm->cur_prd_addr += l; 18040a6238aSAlexander Graf bm->cur_prd_len -= l; 18140a6238aSAlexander Graf s->io_buffer_size += l; 18240a6238aSAlexander Graf } 18340a6238aSAlexander Graf } 1843251bdcfSJohn Snow 1853251bdcfSJohn Snow qemu_sglist_destroy(&s->sg); 1863251bdcfSJohn Snow s->io_buffer_size = 0; 1873251bdcfSJohn Snow return -1; 18840a6238aSAlexander Graf } 18940a6238aSAlexander Graf 19040a6238aSAlexander Graf /* return 0 if buffer completed */ 191ae0cebd7SPhilippe Mathieu-Daudé static int bmdma_rw_buf(const IDEDMA *dma, bool is_write) 19240a6238aSAlexander Graf { 19340a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 19440a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 195f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 19640a6238aSAlexander Graf struct { 19740a6238aSAlexander Graf uint32_t addr; 19840a6238aSAlexander Graf uint32_t size; 19940a6238aSAlexander Graf } prd; 20040a6238aSAlexander Graf int l, len; 20140a6238aSAlexander Graf 20240a6238aSAlexander Graf for(;;) { 20340a6238aSAlexander Graf l = s->io_buffer_size - s->io_buffer_index; 20440a6238aSAlexander Graf if (l <= 0) 20540a6238aSAlexander Graf break; 20640a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 20740a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 20840a6238aSAlexander Graf if (bm->cur_prd_last || 20940a6238aSAlexander Graf (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) 21040a6238aSAlexander Graf return 0; 211f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 21240a6238aSAlexander Graf bm->cur_addr += 8; 21340a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 21440a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 21540a6238aSAlexander Graf len = prd.size & 0xfffe; 21640a6238aSAlexander Graf if (len == 0) 21740a6238aSAlexander Graf len = 0x10000; 21840a6238aSAlexander Graf bm->cur_prd_len = len; 21940a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 22040a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 22140a6238aSAlexander Graf } 22240a6238aSAlexander Graf if (l > bm->cur_prd_len) 22340a6238aSAlexander Graf l = bm->cur_prd_len; 22440a6238aSAlexander Graf if (l > 0) { 22540a6238aSAlexander Graf if (is_write) { 226f6c11d56SAndreas Färber pci_dma_write(pci_dev, bm->cur_prd_addr, 22740a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 22840a6238aSAlexander Graf } else { 229f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_prd_addr, 23040a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 23140a6238aSAlexander Graf } 23240a6238aSAlexander Graf bm->cur_prd_addr += l; 23340a6238aSAlexander Graf bm->cur_prd_len -= l; 23440a6238aSAlexander Graf s->io_buffer_index += l; 23540a6238aSAlexander Graf } 23640a6238aSAlexander Graf } 23740a6238aSAlexander Graf return 1; 23840a6238aSAlexander Graf } 23940a6238aSAlexander Graf 240ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_set_inactive(const IDEDMA *dma, bool more) 24140a6238aSAlexander Graf { 24240a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 24340a6238aSAlexander Graf 24440a6238aSAlexander Graf bm->dma_cb = NULL; 2450e7ce54cSPaolo Bonzini if (more) { 2460e7ce54cSPaolo Bonzini bm->status |= BM_STATUS_DMAING; 2470e7ce54cSPaolo Bonzini } else { 2480e7ce54cSPaolo Bonzini bm->status &= ~BM_STATUS_DMAING; 2490e7ce54cSPaolo Bonzini } 25040a6238aSAlexander Graf } 25140a6238aSAlexander Graf 252ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_restart_dma(const IDEDMA *dma) 25340a6238aSAlexander Graf { 25440a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 25540a6238aSAlexander Graf 25606b95b1eSPaolo Bonzini bm->cur_addr = bm->addr; 25740a6238aSAlexander Graf } 25840a6238aSAlexander Graf 25940a6238aSAlexander Graf static void bmdma_cancel(BMDMAState *bm) 26040a6238aSAlexander Graf { 26140a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 26240a6238aSAlexander Graf /* cancel DMA request */ 2630e7ce54cSPaolo Bonzini bmdma_set_inactive(&bm->dma, false); 26440a6238aSAlexander Graf } 26540a6238aSAlexander Graf } 26640a6238aSAlexander Graf 267ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_reset(const IDEDMA *dma) 26840a6238aSAlexander Graf { 26940a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 27040a6238aSAlexander Graf 2713eee2611SJohn Snow trace_bmdma_reset(); 27240a6238aSAlexander Graf bmdma_cancel(bm); 27340a6238aSAlexander Graf bm->cmd = 0; 27440a6238aSAlexander Graf bm->status = 0; 27540a6238aSAlexander Graf bm->addr = 0; 27640a6238aSAlexander Graf bm->cur_addr = 0; 27740a6238aSAlexander Graf bm->cur_prd_last = 0; 27840a6238aSAlexander Graf bm->cur_prd_addr = 0; 27940a6238aSAlexander Graf bm->cur_prd_len = 0; 28040a6238aSAlexander Graf } 28140a6238aSAlexander Graf 28240a6238aSAlexander Graf static void bmdma_irq(void *opaque, int n, int level) 28340a6238aSAlexander Graf { 28440a6238aSAlexander Graf BMDMAState *bm = opaque; 28540a6238aSAlexander Graf 28640a6238aSAlexander Graf if (!level) { 28740a6238aSAlexander Graf /* pass through lower */ 28840a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 28940a6238aSAlexander Graf return; 29040a6238aSAlexander Graf } 29140a6238aSAlexander Graf 29240a6238aSAlexander Graf bm->status |= BM_STATUS_INT; 29340a6238aSAlexander Graf 29440a6238aSAlexander Graf /* trigger the real irq */ 29540a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 29640a6238aSAlexander Graf } 29740a6238aSAlexander Graf 298a9deb8c6SAvi Kivity void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) 299977e1244SGerd Hoffmann { 3003eee2611SJohn Snow trace_bmdma_cmd_writeb(val); 301c29947bbSKevin Wolf 302c29947bbSKevin Wolf /* Ignore writes to SSBM if it keeps the old value */ 303c29947bbSKevin Wolf if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { 304977e1244SGerd Hoffmann if (!(val & BM_CMD_START)) { 3052c50207fSPhilippe Mathieu-Daudé ide_cancel_dma_sync(ide_bus_active_if(bm->bus)); 306b39f9612SKevin Wolf bm->status &= ~BM_STATUS_DMAING; 307977e1244SGerd Hoffmann } else { 308b76876e6SKevin Wolf bm->cur_addr = bm->addr; 309977e1244SGerd Hoffmann if (!(bm->status & BM_STATUS_DMAING)) { 310977e1244SGerd Hoffmann bm->status |= BM_STATUS_DMAING; 311977e1244SGerd Hoffmann /* start dma transfer if possible */ 312977e1244SGerd Hoffmann if (bm->dma_cb) 31340a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 314977e1244SGerd Hoffmann } 315977e1244SGerd Hoffmann } 316977e1244SGerd Hoffmann } 317977e1244SGerd Hoffmann 318c29947bbSKevin Wolf bm->cmd = val & 0x09; 319c29947bbSKevin Wolf } 320c29947bbSKevin Wolf 321a8170e5eSAvi Kivity static uint64_t bmdma_addr_read(void *opaque, hwaddr addr, 322a9deb8c6SAvi Kivity unsigned width) 323977e1244SGerd Hoffmann { 324a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 3259fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 326a9deb8c6SAvi Kivity uint64_t data; 3279fbef1acSAvi Kivity 328a9deb8c6SAvi Kivity data = (bm->addr >> (addr * 8)) & mask; 3293eee2611SJohn Snow trace_bmdma_addr_read(data); 330a9deb8c6SAvi Kivity return data; 331977e1244SGerd Hoffmann } 332977e1244SGerd Hoffmann 333a8170e5eSAvi Kivity static void bmdma_addr_write(void *opaque, hwaddr addr, 334a9deb8c6SAvi Kivity uint64_t data, unsigned width) 335977e1244SGerd Hoffmann { 336a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 3379fbef1acSAvi Kivity int shift = addr * 8; 3389fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 3399fbef1acSAvi Kivity 3403eee2611SJohn Snow trace_bmdma_addr_write(data); 3419fbef1acSAvi Kivity bm->addr &= ~(mask << shift); 3429fbef1acSAvi Kivity bm->addr |= ((data & mask) << shift) & ~3; 343977e1244SGerd Hoffmann } 344977e1244SGerd Hoffmann 345a9deb8c6SAvi Kivity MemoryRegionOps bmdma_addr_ioport_ops = { 3469fbef1acSAvi Kivity .read = bmdma_addr_read, 3479fbef1acSAvi Kivity .write = bmdma_addr_write, 348a9deb8c6SAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 3499fbef1acSAvi Kivity }; 350977e1244SGerd Hoffmann 3515ee84c33SJuan Quintela static bool ide_bmdma_current_needed(void *opaque) 3525ee84c33SJuan Quintela { 3535ee84c33SJuan Quintela BMDMAState *bm = opaque; 3545ee84c33SJuan Quintela 3555ee84c33SJuan Quintela return (bm->cur_prd_len != 0); 3565ee84c33SJuan Quintela } 3575ee84c33SJuan Quintela 358def93791SKevin Wolf static bool ide_bmdma_status_needed(void *opaque) 359def93791SKevin Wolf { 360def93791SKevin Wolf BMDMAState *bm = opaque; 361def93791SKevin Wolf 362def93791SKevin Wolf /* Older versions abused some bits in the status register for internal 363def93791SKevin Wolf * error state. If any of these bits are set, we must add a subsection to 364def93791SKevin Wolf * transfer the real status register */ 365def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 366def93791SKevin Wolf 367def93791SKevin Wolf return ((bm->status & abused_bits) != 0); 368def93791SKevin Wolf } 369def93791SKevin Wolf 37044b1ff31SDr. David Alan Gilbert static int ide_bmdma_pre_save(void *opaque) 371def93791SKevin Wolf { 372def93791SKevin Wolf BMDMAState *bm = opaque; 373def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 374def93791SKevin Wolf 375218fd37cSPavel Butsykin if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) { 376218fd37cSPavel Butsykin bm->bus->error_status = 377218fd37cSPavel Butsykin ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd); 378218fd37cSPavel Butsykin } 379a96cb236SPaolo Bonzini bm->migration_retry_unit = bm->bus->retry_unit; 380dc5d0af4SPaolo Bonzini bm->migration_retry_sector_num = bm->bus->retry_sector_num; 381dc5d0af4SPaolo Bonzini bm->migration_retry_nsector = bm->bus->retry_nsector; 382def93791SKevin Wolf bm->migration_compat_status = 383def93791SKevin Wolf (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits); 38444b1ff31SDr. David Alan Gilbert 38544b1ff31SDr. David Alan Gilbert return 0; 386def93791SKevin Wolf } 387def93791SKevin Wolf 388def93791SKevin Wolf /* This function accesses bm->bus->error_status which is loaded only after 389def93791SKevin Wolf * BMDMA itself. This is why the function is called from ide_pci_post_load 390def93791SKevin Wolf * instead of being registered with VMState where it would run too early. */ 391def93791SKevin Wolf static int ide_bmdma_post_load(void *opaque, int version_id) 392def93791SKevin Wolf { 393def93791SKevin Wolf BMDMAState *bm = opaque; 394def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 395def93791SKevin Wolf 396def93791SKevin Wolf if (bm->status == 0) { 397def93791SKevin Wolf bm->status = bm->migration_compat_status & ~abused_bits; 398def93791SKevin Wolf bm->bus->error_status |= bm->migration_compat_status & abused_bits; 399def93791SKevin Wolf } 400a96cb236SPaolo Bonzini if (bm->bus->error_status) { 401dc5d0af4SPaolo Bonzini bm->bus->retry_sector_num = bm->migration_retry_sector_num; 402dc5d0af4SPaolo Bonzini bm->bus->retry_nsector = bm->migration_retry_nsector; 403a96cb236SPaolo Bonzini bm->bus->retry_unit = bm->migration_retry_unit; 404a96cb236SPaolo Bonzini } 405def93791SKevin Wolf 406def93791SKevin Wolf return 0; 407def93791SKevin Wolf } 408def93791SKevin Wolf 4095ee84c33SJuan Quintela static const VMStateDescription vmstate_bmdma_current = { 4105ee84c33SJuan Quintela .name = "ide bmdma_current", 4115ee84c33SJuan Quintela .version_id = 1, 4125ee84c33SJuan Quintela .minimum_version_id = 1, 4135cd8cadaSJuan Quintela .needed = ide_bmdma_current_needed, 4145ee84c33SJuan Quintela .fields = (VMStateField[]) { 4155ee84c33SJuan Quintela VMSTATE_UINT32(cur_addr, BMDMAState), 4165ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_last, BMDMAState), 4175ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_addr, BMDMAState), 4185ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_len, BMDMAState), 4195ee84c33SJuan Quintela VMSTATE_END_OF_LIST() 4205ee84c33SJuan Quintela } 4215ee84c33SJuan Quintela }; 4225ee84c33SJuan Quintela 42306ab66cfSStefan Weil static const VMStateDescription vmstate_bmdma_status = { 424def93791SKevin Wolf .name ="ide bmdma/status", 425def93791SKevin Wolf .version_id = 1, 426def93791SKevin Wolf .minimum_version_id = 1, 4275cd8cadaSJuan Quintela .needed = ide_bmdma_status_needed, 428def93791SKevin Wolf .fields = (VMStateField[]) { 429def93791SKevin Wolf VMSTATE_UINT8(status, BMDMAState), 430def93791SKevin Wolf VMSTATE_END_OF_LIST() 431def93791SKevin Wolf } 432def93791SKevin Wolf }; 4335ee84c33SJuan Quintela 434407a4f30SJuan Quintela static const VMStateDescription vmstate_bmdma = { 435407a4f30SJuan Quintela .name = "ide bmdma", 43657338424SJuan Quintela .version_id = 3, 437407a4f30SJuan Quintela .minimum_version_id = 0, 438def93791SKevin Wolf .pre_save = ide_bmdma_pre_save, 439407a4f30SJuan Quintela .fields = (VMStateField[]) { 440407a4f30SJuan Quintela VMSTATE_UINT8(cmd, BMDMAState), 441def93791SKevin Wolf VMSTATE_UINT8(migration_compat_status, BMDMAState), 442407a4f30SJuan Quintela VMSTATE_UINT32(addr, BMDMAState), 443dc5d0af4SPaolo Bonzini VMSTATE_INT64(migration_retry_sector_num, BMDMAState), 444dc5d0af4SPaolo Bonzini VMSTATE_UINT32(migration_retry_nsector, BMDMAState), 445a96cb236SPaolo Bonzini VMSTATE_UINT8(migration_retry_unit, BMDMAState), 446407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 4475ee84c33SJuan Quintela }, 4485cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 4495cd8cadaSJuan Quintela &vmstate_bmdma_current, 4505cd8cadaSJuan Quintela &vmstate_bmdma_status, 4515cd8cadaSJuan Quintela NULL 452407a4f30SJuan Quintela } 453407a4f30SJuan Quintela }; 454407a4f30SJuan Quintela 455407a4f30SJuan Quintela static int ide_pci_post_load(void *opaque, int version_id) 456977e1244SGerd Hoffmann { 457977e1244SGerd Hoffmann PCIIDEState *d = opaque; 458977e1244SGerd Hoffmann int i; 459977e1244SGerd Hoffmann 460977e1244SGerd Hoffmann for(i = 0; i < 2; i++) { 461407a4f30SJuan Quintela /* current versions always store 0/1, but older version 462407a4f30SJuan Quintela stored bigger values. We only need last bit */ 463a96cb236SPaolo Bonzini d->bmdma[i].migration_retry_unit &= 1; 464def93791SKevin Wolf ide_bmdma_post_load(&d->bmdma[i], -1); 465977e1244SGerd Hoffmann } 466def93791SKevin Wolf 467977e1244SGerd Hoffmann return 0; 468977e1244SGerd Hoffmann } 469977e1244SGerd Hoffmann 470407a4f30SJuan Quintela const VMStateDescription vmstate_ide_pci = { 471407a4f30SJuan Quintela .name = "ide", 47257338424SJuan Quintela .version_id = 3, 473407a4f30SJuan Quintela .minimum_version_id = 0, 474407a4f30SJuan Quintela .post_load = ide_pci_post_load, 475407a4f30SJuan Quintela .fields = (VMStateField[]) { 476f6c11d56SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PCIIDEState), 477407a4f30SJuan Quintela VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, 478407a4f30SJuan Quintela vmstate_bmdma, BMDMAState), 479407a4f30SJuan Quintela VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), 480407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState), 481407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState), 482407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 483407a4f30SJuan Quintela } 484407a4f30SJuan Quintela }; 485407a4f30SJuan Quintela 486df45d38fSBALATON Zoltan /* hd_table must contain 4 block drivers */ 487be1765f3SBALATON Zoltan void pci_ide_create_devs(PCIDevice *dev) 488feef3102SGerd Hoffmann { 489f6c11d56SAndreas Färber PCIIDEState *d = PCI_IDE(dev); 490be1765f3SBALATON Zoltan DriveInfo *hd_table[2 * MAX_IDE_DEVS]; 491feef3102SGerd Hoffmann static const int bus[4] = { 0, 0, 1, 1 }; 492feef3102SGerd Hoffmann static const int unit[4] = { 0, 1, 0, 1 }; 493feef3102SGerd Hoffmann int i; 494feef3102SGerd Hoffmann 495be1765f3SBALATON Zoltan ide_drive_get(hd_table, ARRAY_SIZE(hd_table)); 496feef3102SGerd Hoffmann for (i = 0; i < 4; i++) { 497417adc2dSBALATON Zoltan if (hd_table[i]) { 498b6a5ab27SPhilippe Mathieu-Daudé ide_bus_create_drive(d->bus + bus[i], unit[i], hd_table[i]); 499feef3102SGerd Hoffmann } 500feef3102SGerd Hoffmann } 501417adc2dSBALATON Zoltan } 50240a6238aSAlexander Graf 50340a6238aSAlexander Graf static const struct IDEDMAOps bmdma_ops = { 50440a6238aSAlexander Graf .start_dma = bmdma_start_dma, 50540a6238aSAlexander Graf .prepare_buf = bmdma_prepare_buf, 50640a6238aSAlexander Graf .rw_buf = bmdma_rw_buf, 507bd8892c4SPaolo Bonzini .restart_dma = bmdma_restart_dma, 50840a6238aSAlexander Graf .set_inactive = bmdma_set_inactive, 50940a6238aSAlexander Graf .reset = bmdma_reset, 51040a6238aSAlexander Graf }; 51140a6238aSAlexander Graf 512a9deb8c6SAvi Kivity void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d) 51340a6238aSAlexander Graf { 51440a6238aSAlexander Graf if (bus->dma == &bm->dma) { 51540a6238aSAlexander Graf return; 51640a6238aSAlexander Graf } 51740a6238aSAlexander Graf 51840a6238aSAlexander Graf bm->dma.ops = &bmdma_ops; 51940a6238aSAlexander Graf bus->dma = &bm->dma; 52040a6238aSAlexander Graf bm->irq = bus->irq; 5216e38a4baSShannon Zhao bus->irq = qemu_allocate_irq(bmdma_irq, bm, 0); 522*bf0576edSBernhard Beschow bm->bus = bus; 523a9deb8c6SAvi Kivity bm->pci_dev = d; 52440a6238aSAlexander Graf } 525f6c11d56SAndreas Färber 526e2b84ee4SBernhard Beschow static void pci_ide_init(Object *obj) 527e2b84ee4SBernhard Beschow { 528e2b84ee4SBernhard Beschow PCIIDEState *d = PCI_IDE(obj); 529e2b84ee4SBernhard Beschow 530e2b84ee4SBernhard Beschow qdev_init_gpio_out_named(DEVICE(d), d->isa_irq, "isa-irq", 531e2b84ee4SBernhard Beschow ARRAY_SIZE(d->isa_irq)); 532e2b84ee4SBernhard Beschow } 533e2b84ee4SBernhard Beschow 534f6c11d56SAndreas Färber static const TypeInfo pci_ide_type_info = { 535f6c11d56SAndreas Färber .name = TYPE_PCI_IDE, 536f6c11d56SAndreas Färber .parent = TYPE_PCI_DEVICE, 537f6c11d56SAndreas Färber .instance_size = sizeof(PCIIDEState), 538e2b84ee4SBernhard Beschow .instance_init = pci_ide_init, 539f6c11d56SAndreas Färber .abstract = true, 540fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) { 541fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 542fd3b02c8SEduardo Habkost { }, 543fd3b02c8SEduardo Habkost }, 544f6c11d56SAndreas Färber }; 545f6c11d56SAndreas Färber 546f6c11d56SAndreas Färber static void pci_ide_register_types(void) 547f6c11d56SAndreas Färber { 548f6c11d56SAndreas Färber type_register_static(&pci_ide_type_info); 549f6c11d56SAndreas Färber } 550f6c11d56SAndreas Färber 551f6c11d56SAndreas Färber type_init(pci_ide_register_types) 552