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> 260d09e41aSPaolo Bonzini #include <hw/i386/pc.h> 27a2cb15b0SMichael S. Tsirkin #include <hw/pci/pci.h> 280d09e41aSPaolo Bonzini #include <hw/isa/isa.h> 29737e150eSPaolo Bonzini #include "block/block.h" 309c17d615SPaolo Bonzini #include "sysemu/dma.h" 3159f2a787SGerd Hoffmann 3265c0f135SJuan Quintela #include <hw/ide/pci.h> 33977e1244SGerd Hoffmann 3440a6238aSAlexander Graf #define BMDMA_PAGE_SIZE 4096 3540a6238aSAlexander Graf 3640a6238aSAlexander Graf static void bmdma_start_dma(IDEDMA *dma, IDEState *s, 3740a6238aSAlexander Graf BlockDriverCompletionFunc *dma_cb) 3840a6238aSAlexander Graf { 3940a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 4040a6238aSAlexander Graf 4140a6238aSAlexander Graf bm->unit = s->unit; 4240a6238aSAlexander Graf bm->dma_cb = dma_cb; 4340a6238aSAlexander Graf bm->cur_prd_last = 0; 4440a6238aSAlexander Graf bm->cur_prd_addr = 0; 4540a6238aSAlexander Graf bm->cur_prd_len = 0; 4640a6238aSAlexander Graf bm->sector_num = ide_get_sector(s); 4740a6238aSAlexander Graf bm->nsector = s->nsector; 4840a6238aSAlexander Graf 4940a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 5040a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 5140a6238aSAlexander Graf } 5240a6238aSAlexander Graf } 5340a6238aSAlexander Graf 5440a6238aSAlexander Graf /* return 0 if buffer completed */ 5540a6238aSAlexander Graf static int bmdma_prepare_buf(IDEDMA *dma, int is_write) 5640a6238aSAlexander Graf { 5740a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 5840a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 59*f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 6040a6238aSAlexander Graf struct { 6140a6238aSAlexander Graf uint32_t addr; 6240a6238aSAlexander Graf uint32_t size; 6340a6238aSAlexander Graf } prd; 6440a6238aSAlexander Graf int l, len; 6540a6238aSAlexander Graf 66*f6c11d56SAndreas Färber pci_dma_sglist_init(&s->sg, pci_dev, 67552908feSDavid Gibson s->nsector / (BMDMA_PAGE_SIZE / 512) + 1); 6840a6238aSAlexander Graf s->io_buffer_size = 0; 6940a6238aSAlexander Graf for(;;) { 7040a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 7140a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 7240a6238aSAlexander Graf if (bm->cur_prd_last || 7340a6238aSAlexander Graf (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) 7440a6238aSAlexander Graf return s->io_buffer_size != 0; 75*f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 7640a6238aSAlexander Graf bm->cur_addr += 8; 7740a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 7840a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 7940a6238aSAlexander Graf len = prd.size & 0xfffe; 8040a6238aSAlexander Graf if (len == 0) 8140a6238aSAlexander Graf len = 0x10000; 8240a6238aSAlexander Graf bm->cur_prd_len = len; 8340a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 8440a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 8540a6238aSAlexander Graf } 8640a6238aSAlexander Graf l = bm->cur_prd_len; 8740a6238aSAlexander Graf if (l > 0) { 8840a6238aSAlexander Graf qemu_sglist_add(&s->sg, bm->cur_prd_addr, l); 8940a6238aSAlexander Graf bm->cur_prd_addr += l; 9040a6238aSAlexander Graf bm->cur_prd_len -= l; 9140a6238aSAlexander Graf s->io_buffer_size += l; 9240a6238aSAlexander Graf } 9340a6238aSAlexander Graf } 9440a6238aSAlexander Graf return 1; 9540a6238aSAlexander Graf } 9640a6238aSAlexander Graf 9740a6238aSAlexander Graf /* return 0 if buffer completed */ 9840a6238aSAlexander Graf static int bmdma_rw_buf(IDEDMA *dma, int is_write) 9940a6238aSAlexander Graf { 10040a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 10140a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 102*f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 10340a6238aSAlexander Graf struct { 10440a6238aSAlexander Graf uint32_t addr; 10540a6238aSAlexander Graf uint32_t size; 10640a6238aSAlexander Graf } prd; 10740a6238aSAlexander Graf int l, len; 10840a6238aSAlexander Graf 10940a6238aSAlexander Graf for(;;) { 11040a6238aSAlexander Graf l = s->io_buffer_size - s->io_buffer_index; 11140a6238aSAlexander Graf if (l <= 0) 11240a6238aSAlexander Graf break; 11340a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 11440a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 11540a6238aSAlexander Graf if (bm->cur_prd_last || 11640a6238aSAlexander Graf (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) 11740a6238aSAlexander Graf return 0; 118*f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 11940a6238aSAlexander Graf bm->cur_addr += 8; 12040a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 12140a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 12240a6238aSAlexander Graf len = prd.size & 0xfffe; 12340a6238aSAlexander Graf if (len == 0) 12440a6238aSAlexander Graf len = 0x10000; 12540a6238aSAlexander Graf bm->cur_prd_len = len; 12640a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 12740a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 12840a6238aSAlexander Graf } 12940a6238aSAlexander Graf if (l > bm->cur_prd_len) 13040a6238aSAlexander Graf l = bm->cur_prd_len; 13140a6238aSAlexander Graf if (l > 0) { 13240a6238aSAlexander Graf if (is_write) { 133*f6c11d56SAndreas Färber pci_dma_write(pci_dev, bm->cur_prd_addr, 13440a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 13540a6238aSAlexander Graf } else { 136*f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_prd_addr, 13740a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 13840a6238aSAlexander Graf } 13940a6238aSAlexander Graf bm->cur_prd_addr += l; 14040a6238aSAlexander Graf bm->cur_prd_len -= l; 14140a6238aSAlexander Graf s->io_buffer_index += l; 14240a6238aSAlexander Graf } 14340a6238aSAlexander Graf } 14440a6238aSAlexander Graf return 1; 14540a6238aSAlexander Graf } 14640a6238aSAlexander Graf 14740a6238aSAlexander Graf static int bmdma_set_unit(IDEDMA *dma, int unit) 14840a6238aSAlexander Graf { 14940a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 15040a6238aSAlexander Graf bm->unit = unit; 15140a6238aSAlexander Graf 15240a6238aSAlexander Graf return 0; 15340a6238aSAlexander Graf } 15440a6238aSAlexander Graf 15540a6238aSAlexander Graf static int bmdma_add_status(IDEDMA *dma, int status) 15640a6238aSAlexander Graf { 15740a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 15840a6238aSAlexander Graf bm->status |= status; 15940a6238aSAlexander Graf 16040a6238aSAlexander Graf return 0; 16140a6238aSAlexander Graf } 16240a6238aSAlexander Graf 16340a6238aSAlexander Graf static int bmdma_set_inactive(IDEDMA *dma) 16440a6238aSAlexander Graf { 16540a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 16640a6238aSAlexander Graf 16740a6238aSAlexander Graf bm->status &= ~BM_STATUS_DMAING; 16840a6238aSAlexander Graf bm->dma_cb = NULL; 16940a6238aSAlexander Graf bm->unit = -1; 17040a6238aSAlexander Graf 17140a6238aSAlexander Graf return 0; 17240a6238aSAlexander Graf } 17340a6238aSAlexander Graf 1744e1e0051SChristoph Hellwig static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd) 17540a6238aSAlexander Graf { 17640a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 17740a6238aSAlexander Graf 17840a6238aSAlexander Graf ide_set_sector(s, bm->sector_num); 17940a6238aSAlexander Graf s->io_buffer_index = 0; 18040a6238aSAlexander Graf s->io_buffer_size = 0; 18140a6238aSAlexander Graf s->nsector = bm->nsector; 1824e1e0051SChristoph Hellwig s->dma_cmd = dma_cmd; 18340a6238aSAlexander Graf bm->cur_addr = bm->addr; 184cd369c46SChristoph Hellwig bm->dma_cb = ide_dma_cb; 18540a6238aSAlexander Graf bmdma_start_dma(&bm->dma, s, bm->dma_cb); 18640a6238aSAlexander Graf } 18740a6238aSAlexander Graf 188def93791SKevin Wolf /* TODO This should be common IDE code */ 18940a6238aSAlexander Graf static void bmdma_restart_bh(void *opaque) 19040a6238aSAlexander Graf { 19140a6238aSAlexander Graf BMDMAState *bm = opaque; 192def93791SKevin Wolf IDEBus *bus = bm->bus; 1931ceee0d5SPaolo Bonzini bool is_read; 194ee752da7SKevin Wolf int error_status; 19540a6238aSAlexander Graf 19640a6238aSAlexander Graf qemu_bh_delete(bm->bh); 19740a6238aSAlexander Graf bm->bh = NULL; 19840a6238aSAlexander Graf 199def93791SKevin Wolf if (bm->unit == (uint8_t) -1) { 200def93791SKevin Wolf return; 201def93791SKevin Wolf } 20240a6238aSAlexander Graf 2031ceee0d5SPaolo Bonzini is_read = (bus->error_status & BM_STATUS_RETRY_READ) != 0; 204def93791SKevin Wolf 205ee752da7SKevin Wolf /* The error status must be cleared before resubmitting the request: The 206ee752da7SKevin Wolf * request may fail again, and this case can only be distinguished if the 207ee752da7SKevin Wolf * called function can set a new error status. */ 208ee752da7SKevin Wolf error_status = bus->error_status; 209ee752da7SKevin Wolf bus->error_status = 0; 210ee752da7SKevin Wolf 211ee752da7SKevin Wolf if (error_status & BM_STATUS_DMA_RETRY) { 212ee752da7SKevin Wolf if (error_status & BM_STATUS_RETRY_TRIM) { 213d353fb72SChristoph Hellwig bmdma_restart_dma(bm, IDE_DMA_TRIM); 214d353fb72SChristoph Hellwig } else { 2154e1e0051SChristoph Hellwig bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE); 216d353fb72SChristoph Hellwig } 217ee752da7SKevin Wolf } else if (error_status & BM_STATUS_PIO_RETRY) { 21840a6238aSAlexander Graf if (is_read) { 21940a6238aSAlexander Graf ide_sector_read(bmdma_active_if(bm)); 22040a6238aSAlexander Graf } else { 22140a6238aSAlexander Graf ide_sector_write(bmdma_active_if(bm)); 22240a6238aSAlexander Graf } 223ee752da7SKevin Wolf } else if (error_status & BM_STATUS_RETRY_FLUSH) { 22440a6238aSAlexander Graf ide_flush_cache(bmdma_active_if(bm)); 22540a6238aSAlexander Graf } 22640a6238aSAlexander Graf } 22740a6238aSAlexander Graf 2281dfb4dd9SLuiz Capitulino static void bmdma_restart_cb(void *opaque, int running, RunState state) 22940a6238aSAlexander Graf { 23040a6238aSAlexander Graf IDEDMA *dma = opaque; 23140a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 23240a6238aSAlexander Graf 23340a6238aSAlexander Graf if (!running) 23440a6238aSAlexander Graf return; 23540a6238aSAlexander Graf 23640a6238aSAlexander Graf if (!bm->bh) { 23740a6238aSAlexander Graf bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma); 23840a6238aSAlexander Graf qemu_bh_schedule(bm->bh); 23940a6238aSAlexander Graf } 24040a6238aSAlexander Graf } 24140a6238aSAlexander Graf 24240a6238aSAlexander Graf static void bmdma_cancel(BMDMAState *bm) 24340a6238aSAlexander Graf { 24440a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 24540a6238aSAlexander Graf /* cancel DMA request */ 24640a6238aSAlexander Graf bmdma_set_inactive(&bm->dma); 24740a6238aSAlexander Graf } 24840a6238aSAlexander Graf } 24940a6238aSAlexander Graf 25040a6238aSAlexander Graf static int bmdma_reset(IDEDMA *dma) 25140a6238aSAlexander Graf { 25240a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 25340a6238aSAlexander Graf 25440a6238aSAlexander Graf #ifdef DEBUG_IDE 25540a6238aSAlexander Graf printf("ide: dma_reset\n"); 25640a6238aSAlexander Graf #endif 25740a6238aSAlexander Graf bmdma_cancel(bm); 25840a6238aSAlexander Graf bm->cmd = 0; 25940a6238aSAlexander Graf bm->status = 0; 26040a6238aSAlexander Graf bm->addr = 0; 26140a6238aSAlexander Graf bm->cur_addr = 0; 26240a6238aSAlexander Graf bm->cur_prd_last = 0; 26340a6238aSAlexander Graf bm->cur_prd_addr = 0; 26440a6238aSAlexander Graf bm->cur_prd_len = 0; 26540a6238aSAlexander Graf bm->sector_num = 0; 26640a6238aSAlexander Graf bm->nsector = 0; 26740a6238aSAlexander Graf 26840a6238aSAlexander Graf return 0; 26940a6238aSAlexander Graf } 27040a6238aSAlexander Graf 27140a6238aSAlexander Graf static int bmdma_start_transfer(IDEDMA *dma) 27240a6238aSAlexander Graf { 27340a6238aSAlexander Graf return 0; 27440a6238aSAlexander Graf } 27540a6238aSAlexander Graf 27640a6238aSAlexander Graf static void bmdma_irq(void *opaque, int n, int level) 27740a6238aSAlexander Graf { 27840a6238aSAlexander Graf BMDMAState *bm = opaque; 27940a6238aSAlexander Graf 28040a6238aSAlexander Graf if (!level) { 28140a6238aSAlexander Graf /* pass through lower */ 28240a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 28340a6238aSAlexander Graf return; 28440a6238aSAlexander Graf } 28540a6238aSAlexander Graf 28640a6238aSAlexander Graf bm->status |= BM_STATUS_INT; 28740a6238aSAlexander Graf 28840a6238aSAlexander Graf /* trigger the real irq */ 28940a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 29040a6238aSAlexander Graf } 29140a6238aSAlexander Graf 292a9deb8c6SAvi Kivity void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) 293977e1244SGerd Hoffmann { 294977e1244SGerd Hoffmann #ifdef DEBUG_IDE 295977e1244SGerd Hoffmann printf("%s: 0x%08x\n", __func__, val); 296977e1244SGerd Hoffmann #endif 297c29947bbSKevin Wolf 298c29947bbSKevin Wolf /* Ignore writes to SSBM if it keeps the old value */ 299c29947bbSKevin Wolf if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { 300977e1244SGerd Hoffmann if (!(val & BM_CMD_START)) { 301953844d1SAndrea Arcangeli /* 302953844d1SAndrea Arcangeli * We can't cancel Scatter Gather DMA in the middle of the 303953844d1SAndrea Arcangeli * operation or a partial (not full) DMA transfer would reach 304953844d1SAndrea Arcangeli * the storage so we wait for completion instead (we beahve 305953844d1SAndrea Arcangeli * like if the DMA was completed by the time the guest trying 306953844d1SAndrea Arcangeli * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not 307953844d1SAndrea Arcangeli * set). 308953844d1SAndrea Arcangeli * 309953844d1SAndrea Arcangeli * In the future we'll be able to safely cancel the I/O if the 310953844d1SAndrea Arcangeli * whole DMA operation will be submitted to disk with a single 311953844d1SAndrea Arcangeli * aio operation with preadv/pwritev. 312953844d1SAndrea Arcangeli */ 31340a6238aSAlexander Graf if (bm->bus->dma->aiocb) { 314922453bcSStefan Hajnoczi bdrv_drain_all(); 3152860e3ebSKevin Wolf assert(bm->bus->dma->aiocb == NULL); 316953844d1SAndrea Arcangeli } 317b39f9612SKevin Wolf bm->status &= ~BM_STATUS_DMAING; 318977e1244SGerd Hoffmann } else { 319b76876e6SKevin Wolf bm->cur_addr = bm->addr; 320977e1244SGerd Hoffmann if (!(bm->status & BM_STATUS_DMAING)) { 321977e1244SGerd Hoffmann bm->status |= BM_STATUS_DMAING; 322977e1244SGerd Hoffmann /* start dma transfer if possible */ 323977e1244SGerd Hoffmann if (bm->dma_cb) 32440a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 325977e1244SGerd Hoffmann } 326977e1244SGerd Hoffmann } 327977e1244SGerd Hoffmann } 328977e1244SGerd Hoffmann 329c29947bbSKevin Wolf bm->cmd = val & 0x09; 330c29947bbSKevin Wolf } 331c29947bbSKevin Wolf 332a8170e5eSAvi Kivity static uint64_t bmdma_addr_read(void *opaque, hwaddr addr, 333a9deb8c6SAvi Kivity unsigned width) 334977e1244SGerd Hoffmann { 335a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 3369fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 337a9deb8c6SAvi Kivity uint64_t data; 3389fbef1acSAvi Kivity 339a9deb8c6SAvi Kivity data = (bm->addr >> (addr * 8)) & mask; 340977e1244SGerd Hoffmann #ifdef DEBUG_IDE 341cb67be85SHervé Poussineau printf("%s: 0x%08x\n", __func__, (unsigned)data); 342977e1244SGerd Hoffmann #endif 343a9deb8c6SAvi Kivity return data; 344977e1244SGerd Hoffmann } 345977e1244SGerd Hoffmann 346a8170e5eSAvi Kivity static void bmdma_addr_write(void *opaque, hwaddr addr, 347a9deb8c6SAvi Kivity uint64_t data, unsigned width) 348977e1244SGerd Hoffmann { 349a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 3509fbef1acSAvi Kivity int shift = addr * 8; 3519fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 3529fbef1acSAvi Kivity 353977e1244SGerd Hoffmann #ifdef DEBUG_IDE 3549fbef1acSAvi Kivity printf("%s: 0x%08x\n", __func__, (unsigned)data); 355977e1244SGerd Hoffmann #endif 3569fbef1acSAvi Kivity bm->addr &= ~(mask << shift); 3579fbef1acSAvi Kivity bm->addr |= ((data & mask) << shift) & ~3; 358977e1244SGerd Hoffmann } 359977e1244SGerd Hoffmann 360a9deb8c6SAvi Kivity MemoryRegionOps bmdma_addr_ioport_ops = { 3619fbef1acSAvi Kivity .read = bmdma_addr_read, 3629fbef1acSAvi Kivity .write = bmdma_addr_write, 363a9deb8c6SAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 3649fbef1acSAvi Kivity }; 365977e1244SGerd Hoffmann 3665ee84c33SJuan Quintela static bool ide_bmdma_current_needed(void *opaque) 3675ee84c33SJuan Quintela { 3685ee84c33SJuan Quintela BMDMAState *bm = opaque; 3695ee84c33SJuan Quintela 3705ee84c33SJuan Quintela return (bm->cur_prd_len != 0); 3715ee84c33SJuan Quintela } 3725ee84c33SJuan Quintela 373def93791SKevin Wolf static bool ide_bmdma_status_needed(void *opaque) 374def93791SKevin Wolf { 375def93791SKevin Wolf BMDMAState *bm = opaque; 376def93791SKevin Wolf 377def93791SKevin Wolf /* Older versions abused some bits in the status register for internal 378def93791SKevin Wolf * error state. If any of these bits are set, we must add a subsection to 379def93791SKevin Wolf * transfer the real status register */ 380def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 381def93791SKevin Wolf 382def93791SKevin Wolf return ((bm->status & abused_bits) != 0); 383def93791SKevin Wolf } 384def93791SKevin Wolf 385def93791SKevin Wolf static void ide_bmdma_pre_save(void *opaque) 386def93791SKevin Wolf { 387def93791SKevin Wolf BMDMAState *bm = opaque; 388def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 389def93791SKevin Wolf 390def93791SKevin Wolf bm->migration_compat_status = 391def93791SKevin Wolf (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits); 392def93791SKevin Wolf } 393def93791SKevin Wolf 394def93791SKevin Wolf /* This function accesses bm->bus->error_status which is loaded only after 395def93791SKevin Wolf * BMDMA itself. This is why the function is called from ide_pci_post_load 396def93791SKevin Wolf * instead of being registered with VMState where it would run too early. */ 397def93791SKevin Wolf static int ide_bmdma_post_load(void *opaque, int version_id) 398def93791SKevin Wolf { 399def93791SKevin Wolf BMDMAState *bm = opaque; 400def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 401def93791SKevin Wolf 402def93791SKevin Wolf if (bm->status == 0) { 403def93791SKevin Wolf bm->status = bm->migration_compat_status & ~abused_bits; 404def93791SKevin Wolf bm->bus->error_status |= bm->migration_compat_status & abused_bits; 405def93791SKevin Wolf } 406def93791SKevin Wolf 407def93791SKevin Wolf return 0; 408def93791SKevin Wolf } 409def93791SKevin Wolf 4105ee84c33SJuan Quintela static const VMStateDescription vmstate_bmdma_current = { 4115ee84c33SJuan Quintela .name = "ide bmdma_current", 4125ee84c33SJuan Quintela .version_id = 1, 4135ee84c33SJuan Quintela .minimum_version_id = 1, 4145ee84c33SJuan Quintela .minimum_version_id_old = 1, 4155ee84c33SJuan Quintela .fields = (VMStateField []) { 4165ee84c33SJuan Quintela VMSTATE_UINT32(cur_addr, BMDMAState), 4175ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_last, BMDMAState), 4185ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_addr, BMDMAState), 4195ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_len, BMDMAState), 4205ee84c33SJuan Quintela VMSTATE_END_OF_LIST() 4215ee84c33SJuan Quintela } 4225ee84c33SJuan Quintela }; 4235ee84c33SJuan Quintela 424def93791SKevin Wolf const VMStateDescription vmstate_bmdma_status = { 425def93791SKevin Wolf .name ="ide bmdma/status", 426def93791SKevin Wolf .version_id = 1, 427def93791SKevin Wolf .minimum_version_id = 1, 428def93791SKevin Wolf .minimum_version_id_old = 1, 429def93791SKevin Wolf .fields = (VMStateField []) { 430def93791SKevin Wolf VMSTATE_UINT8(status, BMDMAState), 431def93791SKevin Wolf VMSTATE_END_OF_LIST() 432def93791SKevin Wolf } 433def93791SKevin Wolf }; 4345ee84c33SJuan Quintela 435407a4f30SJuan Quintela static const VMStateDescription vmstate_bmdma = { 436407a4f30SJuan Quintela .name = "ide bmdma", 43757338424SJuan Quintela .version_id = 3, 438407a4f30SJuan Quintela .minimum_version_id = 0, 439407a4f30SJuan Quintela .minimum_version_id_old = 0, 440def93791SKevin Wolf .pre_save = ide_bmdma_pre_save, 441407a4f30SJuan Quintela .fields = (VMStateField []) { 442407a4f30SJuan Quintela VMSTATE_UINT8(cmd, BMDMAState), 443def93791SKevin Wolf VMSTATE_UINT8(migration_compat_status, BMDMAState), 444407a4f30SJuan Quintela VMSTATE_UINT32(addr, BMDMAState), 445407a4f30SJuan Quintela VMSTATE_INT64(sector_num, BMDMAState), 446407a4f30SJuan Quintela VMSTATE_UINT32(nsector, BMDMAState), 447407a4f30SJuan Quintela VMSTATE_UINT8(unit, BMDMAState), 448407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 4495ee84c33SJuan Quintela }, 4505ee84c33SJuan Quintela .subsections = (VMStateSubsection []) { 4515ee84c33SJuan Quintela { 4525ee84c33SJuan Quintela .vmsd = &vmstate_bmdma_current, 4535ee84c33SJuan Quintela .needed = ide_bmdma_current_needed, 4545ee84c33SJuan Quintela }, { 455def93791SKevin Wolf .vmsd = &vmstate_bmdma_status, 456def93791SKevin Wolf .needed = ide_bmdma_status_needed, 457def93791SKevin Wolf }, { 4585ee84c33SJuan Quintela /* empty */ 4595ee84c33SJuan Quintela } 460407a4f30SJuan Quintela } 461407a4f30SJuan Quintela }; 462407a4f30SJuan Quintela 463407a4f30SJuan Quintela static int ide_pci_post_load(void *opaque, int version_id) 464977e1244SGerd Hoffmann { 465977e1244SGerd Hoffmann PCIIDEState *d = opaque; 466977e1244SGerd Hoffmann int i; 467977e1244SGerd Hoffmann 468977e1244SGerd Hoffmann for(i = 0; i < 2; i++) { 469407a4f30SJuan Quintela /* current versions always store 0/1, but older version 470407a4f30SJuan Quintela stored bigger values. We only need last bit */ 471407a4f30SJuan Quintela d->bmdma[i].unit &= 1; 472def93791SKevin Wolf ide_bmdma_post_load(&d->bmdma[i], -1); 473977e1244SGerd Hoffmann } 474def93791SKevin Wolf 475977e1244SGerd Hoffmann return 0; 476977e1244SGerd Hoffmann } 477977e1244SGerd Hoffmann 478407a4f30SJuan Quintela const VMStateDescription vmstate_ide_pci = { 479407a4f30SJuan Quintela .name = "ide", 48057338424SJuan Quintela .version_id = 3, 481407a4f30SJuan Quintela .minimum_version_id = 0, 482407a4f30SJuan Quintela .minimum_version_id_old = 0, 483407a4f30SJuan Quintela .post_load = ide_pci_post_load, 484407a4f30SJuan Quintela .fields = (VMStateField []) { 485*f6c11d56SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PCIIDEState), 486407a4f30SJuan Quintela VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, 487407a4f30SJuan Quintela vmstate_bmdma, BMDMAState), 488407a4f30SJuan Quintela VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), 489407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState), 490407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState), 491407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 492407a4f30SJuan Quintela } 493407a4f30SJuan Quintela }; 494407a4f30SJuan Quintela 4953e7e1558SJuan Quintela void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table) 496feef3102SGerd Hoffmann { 497*f6c11d56SAndreas Färber PCIIDEState *d = PCI_IDE(dev); 498feef3102SGerd Hoffmann static const int bus[4] = { 0, 0, 1, 1 }; 499feef3102SGerd Hoffmann static const int unit[4] = { 0, 1, 0, 1 }; 500feef3102SGerd Hoffmann int i; 501feef3102SGerd Hoffmann 502feef3102SGerd Hoffmann for (i = 0; i < 4; i++) { 503feef3102SGerd Hoffmann if (hd_table[i] == NULL) 504feef3102SGerd Hoffmann continue; 5051f850f10SGerd Hoffmann ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]); 506feef3102SGerd Hoffmann } 507feef3102SGerd Hoffmann } 50840a6238aSAlexander Graf 50940a6238aSAlexander Graf static const struct IDEDMAOps bmdma_ops = { 51040a6238aSAlexander Graf .start_dma = bmdma_start_dma, 51140a6238aSAlexander Graf .start_transfer = bmdma_start_transfer, 51240a6238aSAlexander Graf .prepare_buf = bmdma_prepare_buf, 51340a6238aSAlexander Graf .rw_buf = bmdma_rw_buf, 51440a6238aSAlexander Graf .set_unit = bmdma_set_unit, 51540a6238aSAlexander Graf .add_status = bmdma_add_status, 51640a6238aSAlexander Graf .set_inactive = bmdma_set_inactive, 51740a6238aSAlexander Graf .restart_cb = bmdma_restart_cb, 51840a6238aSAlexander Graf .reset = bmdma_reset, 51940a6238aSAlexander Graf }; 52040a6238aSAlexander Graf 521a9deb8c6SAvi Kivity void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d) 52240a6238aSAlexander Graf { 52340a6238aSAlexander Graf qemu_irq *irq; 52440a6238aSAlexander Graf 52540a6238aSAlexander Graf if (bus->dma == &bm->dma) { 52640a6238aSAlexander Graf return; 52740a6238aSAlexander Graf } 52840a6238aSAlexander Graf 52940a6238aSAlexander Graf bm->dma.ops = &bmdma_ops; 53040a6238aSAlexander Graf bus->dma = &bm->dma; 53140a6238aSAlexander Graf bm->irq = bus->irq; 53240a6238aSAlexander Graf irq = qemu_allocate_irqs(bmdma_irq, bm, 1); 53340a6238aSAlexander Graf bus->irq = *irq; 534a9deb8c6SAvi Kivity bm->pci_dev = d; 53540a6238aSAlexander Graf } 536*f6c11d56SAndreas Färber 537*f6c11d56SAndreas Färber static const TypeInfo pci_ide_type_info = { 538*f6c11d56SAndreas Färber .name = TYPE_PCI_IDE, 539*f6c11d56SAndreas Färber .parent = TYPE_PCI_DEVICE, 540*f6c11d56SAndreas Färber .instance_size = sizeof(PCIIDEState), 541*f6c11d56SAndreas Färber .abstract = true, 542*f6c11d56SAndreas Färber }; 543*f6c11d56SAndreas Färber 544*f6c11d56SAndreas Färber static void pci_ide_register_types(void) 545*f6c11d56SAndreas Färber { 546*f6c11d56SAndreas Färber type_register_static(&pci_ide_type_info); 547*f6c11d56SAndreas Färber } 548*f6c11d56SAndreas Färber 549*f6c11d56SAndreas Färber type_init(pci_ide_register_types) 550