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 3640a6238aSAlexander Graf #define BMDMA_PAGE_SIZE 4096 3740a6238aSAlexander Graf 3840a6238aSAlexander Graf static void bmdma_start_dma(IDEDMA *dma, IDEState *s, 3940a6238aSAlexander Graf BlockDriverCompletionFunc *dma_cb) 4040a6238aSAlexander Graf { 4140a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 4240a6238aSAlexander Graf 4340a6238aSAlexander Graf bm->unit = s->unit; 4440a6238aSAlexander Graf bm->dma_cb = dma_cb; 4540a6238aSAlexander Graf bm->cur_prd_last = 0; 4640a6238aSAlexander Graf bm->cur_prd_addr = 0; 4740a6238aSAlexander Graf bm->cur_prd_len = 0; 4840a6238aSAlexander Graf bm->sector_num = ide_get_sector(s); 4940a6238aSAlexander Graf bm->nsector = s->nsector; 5040a6238aSAlexander Graf 5140a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 5240a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 5340a6238aSAlexander Graf } 5440a6238aSAlexander Graf } 5540a6238aSAlexander Graf 5640a6238aSAlexander Graf /* return 0 if buffer completed */ 5740a6238aSAlexander Graf static int bmdma_prepare_buf(IDEDMA *dma, int is_write) 5840a6238aSAlexander Graf { 5940a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 6040a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 6140a6238aSAlexander Graf struct { 6240a6238aSAlexander Graf uint32_t addr; 6340a6238aSAlexander Graf uint32_t size; 6440a6238aSAlexander Graf } prd; 6540a6238aSAlexander Graf int l, len; 6640a6238aSAlexander Graf 6740a6238aSAlexander Graf qemu_sglist_init(&s->sg, 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; 7540a6238aSAlexander Graf cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&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); 10240a6238aSAlexander Graf struct { 10340a6238aSAlexander Graf uint32_t addr; 10440a6238aSAlexander Graf uint32_t size; 10540a6238aSAlexander Graf } prd; 10640a6238aSAlexander Graf int l, len; 10740a6238aSAlexander Graf 10840a6238aSAlexander Graf for(;;) { 10940a6238aSAlexander Graf l = s->io_buffer_size - s->io_buffer_index; 11040a6238aSAlexander Graf if (l <= 0) 11140a6238aSAlexander Graf break; 11240a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 11340a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 11440a6238aSAlexander Graf if (bm->cur_prd_last || 11540a6238aSAlexander Graf (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) 11640a6238aSAlexander Graf return 0; 11740a6238aSAlexander Graf cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); 11840a6238aSAlexander Graf bm->cur_addr += 8; 11940a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 12040a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 12140a6238aSAlexander Graf len = prd.size & 0xfffe; 12240a6238aSAlexander Graf if (len == 0) 12340a6238aSAlexander Graf len = 0x10000; 12440a6238aSAlexander Graf bm->cur_prd_len = len; 12540a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 12640a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 12740a6238aSAlexander Graf } 12840a6238aSAlexander Graf if (l > bm->cur_prd_len) 12940a6238aSAlexander Graf l = bm->cur_prd_len; 13040a6238aSAlexander Graf if (l > 0) { 13140a6238aSAlexander Graf if (is_write) { 13240a6238aSAlexander Graf cpu_physical_memory_write(bm->cur_prd_addr, 13340a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 13440a6238aSAlexander Graf } else { 13540a6238aSAlexander Graf cpu_physical_memory_read(bm->cur_prd_addr, 13640a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 13740a6238aSAlexander Graf } 13840a6238aSAlexander Graf bm->cur_prd_addr += l; 13940a6238aSAlexander Graf bm->cur_prd_len -= l; 14040a6238aSAlexander Graf s->io_buffer_index += l; 14140a6238aSAlexander Graf } 14240a6238aSAlexander Graf } 14340a6238aSAlexander Graf return 1; 14440a6238aSAlexander Graf } 14540a6238aSAlexander Graf 14640a6238aSAlexander Graf static int bmdma_set_unit(IDEDMA *dma, int unit) 14740a6238aSAlexander Graf { 14840a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 14940a6238aSAlexander Graf bm->unit = unit; 15040a6238aSAlexander Graf 15140a6238aSAlexander Graf return 0; 15240a6238aSAlexander Graf } 15340a6238aSAlexander Graf 15440a6238aSAlexander Graf static int bmdma_add_status(IDEDMA *dma, int status) 15540a6238aSAlexander Graf { 15640a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 15740a6238aSAlexander Graf bm->status |= status; 15840a6238aSAlexander Graf 15940a6238aSAlexander Graf return 0; 16040a6238aSAlexander Graf } 16140a6238aSAlexander Graf 16240a6238aSAlexander Graf static int bmdma_set_inactive(IDEDMA *dma) 16340a6238aSAlexander Graf { 16440a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 16540a6238aSAlexander Graf 16640a6238aSAlexander Graf bm->status &= ~BM_STATUS_DMAING; 16740a6238aSAlexander Graf bm->dma_cb = NULL; 16840a6238aSAlexander Graf bm->unit = -1; 16940a6238aSAlexander Graf 17040a6238aSAlexander Graf return 0; 17140a6238aSAlexander Graf } 17240a6238aSAlexander Graf 17340a6238aSAlexander Graf static void bmdma_restart_dma(BMDMAState *bm, int is_read) 17440a6238aSAlexander Graf { 17540a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 17640a6238aSAlexander Graf 17740a6238aSAlexander Graf ide_set_sector(s, bm->sector_num); 17840a6238aSAlexander Graf s->io_buffer_index = 0; 17940a6238aSAlexander Graf s->io_buffer_size = 0; 18040a6238aSAlexander Graf s->nsector = bm->nsector; 181*cd369c46SChristoph Hellwig s->is_read = is_read; 18240a6238aSAlexander Graf bm->cur_addr = bm->addr; 183*cd369c46SChristoph Hellwig bm->dma_cb = ide_dma_cb; 18440a6238aSAlexander Graf bmdma_start_dma(&bm->dma, s, bm->dma_cb); 18540a6238aSAlexander Graf } 18640a6238aSAlexander Graf 18740a6238aSAlexander Graf static void bmdma_restart_bh(void *opaque) 18840a6238aSAlexander Graf { 18940a6238aSAlexander Graf BMDMAState *bm = opaque; 19040a6238aSAlexander Graf int is_read; 19140a6238aSAlexander Graf 19240a6238aSAlexander Graf qemu_bh_delete(bm->bh); 19340a6238aSAlexander Graf bm->bh = NULL; 19440a6238aSAlexander Graf 19540a6238aSAlexander Graf is_read = !!(bm->status & BM_STATUS_RETRY_READ); 19640a6238aSAlexander Graf 19740a6238aSAlexander Graf if (bm->status & BM_STATUS_DMA_RETRY) { 19840a6238aSAlexander Graf bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ); 19940a6238aSAlexander Graf bmdma_restart_dma(bm, is_read); 20040a6238aSAlexander Graf } else if (bm->status & BM_STATUS_PIO_RETRY) { 20140a6238aSAlexander Graf bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ); 20240a6238aSAlexander Graf if (is_read) { 20340a6238aSAlexander Graf ide_sector_read(bmdma_active_if(bm)); 20440a6238aSAlexander Graf } else { 20540a6238aSAlexander Graf ide_sector_write(bmdma_active_if(bm)); 20640a6238aSAlexander Graf } 20740a6238aSAlexander Graf } else if (bm->status & BM_STATUS_RETRY_FLUSH) { 20840a6238aSAlexander Graf ide_flush_cache(bmdma_active_if(bm)); 20940a6238aSAlexander Graf } 21040a6238aSAlexander Graf } 21140a6238aSAlexander Graf 21240a6238aSAlexander Graf static void bmdma_restart_cb(void *opaque, int running, int reason) 21340a6238aSAlexander Graf { 21440a6238aSAlexander Graf IDEDMA *dma = opaque; 21540a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 21640a6238aSAlexander Graf 21740a6238aSAlexander Graf if (!running) 21840a6238aSAlexander Graf return; 21940a6238aSAlexander Graf 22040a6238aSAlexander Graf if (!bm->bh) { 22140a6238aSAlexander Graf bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma); 22240a6238aSAlexander Graf qemu_bh_schedule(bm->bh); 22340a6238aSAlexander Graf } 22440a6238aSAlexander Graf } 22540a6238aSAlexander Graf 22640a6238aSAlexander Graf static void bmdma_cancel(BMDMAState *bm) 22740a6238aSAlexander Graf { 22840a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 22940a6238aSAlexander Graf /* cancel DMA request */ 23040a6238aSAlexander Graf bmdma_set_inactive(&bm->dma); 23140a6238aSAlexander Graf } 23240a6238aSAlexander Graf } 23340a6238aSAlexander Graf 23440a6238aSAlexander Graf static int bmdma_reset(IDEDMA *dma) 23540a6238aSAlexander Graf { 23640a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 23740a6238aSAlexander Graf 23840a6238aSAlexander Graf #ifdef DEBUG_IDE 23940a6238aSAlexander Graf printf("ide: dma_reset\n"); 24040a6238aSAlexander Graf #endif 24140a6238aSAlexander Graf bmdma_cancel(bm); 24240a6238aSAlexander Graf bm->cmd = 0; 24340a6238aSAlexander Graf bm->status = 0; 24440a6238aSAlexander Graf bm->addr = 0; 24540a6238aSAlexander Graf bm->cur_addr = 0; 24640a6238aSAlexander Graf bm->cur_prd_last = 0; 24740a6238aSAlexander Graf bm->cur_prd_addr = 0; 24840a6238aSAlexander Graf bm->cur_prd_len = 0; 24940a6238aSAlexander Graf bm->sector_num = 0; 25040a6238aSAlexander Graf bm->nsector = 0; 25140a6238aSAlexander Graf 25240a6238aSAlexander Graf return 0; 25340a6238aSAlexander Graf } 25440a6238aSAlexander Graf 25540a6238aSAlexander Graf static int bmdma_start_transfer(IDEDMA *dma) 25640a6238aSAlexander Graf { 25740a6238aSAlexander Graf return 0; 25840a6238aSAlexander Graf } 25940a6238aSAlexander Graf 26040a6238aSAlexander Graf static void bmdma_irq(void *opaque, int n, int level) 26140a6238aSAlexander Graf { 26240a6238aSAlexander Graf BMDMAState *bm = opaque; 26340a6238aSAlexander Graf 26440a6238aSAlexander Graf if (!level) { 26540a6238aSAlexander Graf /* pass through lower */ 26640a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 26740a6238aSAlexander Graf return; 26840a6238aSAlexander Graf } 26940a6238aSAlexander Graf 27040a6238aSAlexander Graf if (bm) { 27140a6238aSAlexander Graf bm->status |= BM_STATUS_INT; 27240a6238aSAlexander Graf } 27340a6238aSAlexander Graf 27440a6238aSAlexander Graf /* trigger the real irq */ 27540a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 27640a6238aSAlexander Graf } 27740a6238aSAlexander Graf 2783e7e1558SJuan Quintela void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) 279977e1244SGerd Hoffmann { 280977e1244SGerd Hoffmann BMDMAState *bm = opaque; 281977e1244SGerd Hoffmann #ifdef DEBUG_IDE 282977e1244SGerd Hoffmann printf("%s: 0x%08x\n", __func__, val); 283977e1244SGerd Hoffmann #endif 284c29947bbSKevin Wolf 285c29947bbSKevin Wolf /* Ignore writes to SSBM if it keeps the old value */ 286c29947bbSKevin Wolf if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { 287977e1244SGerd Hoffmann if (!(val & BM_CMD_START)) { 288953844d1SAndrea Arcangeli /* 289953844d1SAndrea Arcangeli * We can't cancel Scatter Gather DMA in the middle of the 290953844d1SAndrea Arcangeli * operation or a partial (not full) DMA transfer would reach 291953844d1SAndrea Arcangeli * the storage so we wait for completion instead (we beahve 292953844d1SAndrea Arcangeli * like if the DMA was completed by the time the guest trying 293953844d1SAndrea Arcangeli * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not 294953844d1SAndrea Arcangeli * set). 295953844d1SAndrea Arcangeli * 296953844d1SAndrea Arcangeli * In the future we'll be able to safely cancel the I/O if the 297953844d1SAndrea Arcangeli * whole DMA operation will be submitted to disk with a single 298953844d1SAndrea Arcangeli * aio operation with preadv/pwritev. 299953844d1SAndrea Arcangeli */ 30040a6238aSAlexander Graf if (bm->bus->dma->aiocb) { 301953844d1SAndrea Arcangeli qemu_aio_flush(); 302953844d1SAndrea Arcangeli #ifdef DEBUG_IDE 30340a6238aSAlexander Graf if (bm->bus->dma->aiocb) 304953844d1SAndrea Arcangeli printf("ide_dma_cancel: aiocb still pending"); 305953844d1SAndrea Arcangeli if (bm->status & BM_STATUS_DMAING) 306953844d1SAndrea Arcangeli printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); 307953844d1SAndrea Arcangeli #endif 308953844d1SAndrea Arcangeli } 309977e1244SGerd Hoffmann } else { 310b76876e6SKevin Wolf bm->cur_addr = bm->addr; 311977e1244SGerd Hoffmann if (!(bm->status & BM_STATUS_DMAING)) { 312977e1244SGerd Hoffmann bm->status |= BM_STATUS_DMAING; 313977e1244SGerd Hoffmann /* start dma transfer if possible */ 314977e1244SGerd Hoffmann if (bm->dma_cb) 31540a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 316977e1244SGerd Hoffmann } 317977e1244SGerd Hoffmann } 318977e1244SGerd Hoffmann } 319977e1244SGerd Hoffmann 320c29947bbSKevin Wolf bm->cmd = val & 0x09; 321c29947bbSKevin Wolf } 322c29947bbSKevin Wolf 3239fbef1acSAvi Kivity static void bmdma_addr_read(IORange *ioport, uint64_t addr, 3249fbef1acSAvi Kivity unsigned width, uint64_t *data) 325977e1244SGerd Hoffmann { 3269fbef1acSAvi Kivity BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); 3279fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 3289fbef1acSAvi Kivity 3299fbef1acSAvi Kivity *data = (bm->addr >> (addr * 8)) & mask; 330977e1244SGerd Hoffmann #ifdef DEBUG_IDE 3319fbef1acSAvi Kivity printf("%s: 0x%08x\n", __func__, (unsigned)*data); 332977e1244SGerd Hoffmann #endif 333977e1244SGerd Hoffmann } 334977e1244SGerd Hoffmann 3359fbef1acSAvi Kivity static void bmdma_addr_write(IORange *ioport, uint64_t addr, 3369fbef1acSAvi Kivity unsigned width, uint64_t data) 337977e1244SGerd Hoffmann { 3389fbef1acSAvi Kivity BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); 3399fbef1acSAvi Kivity int shift = addr * 8; 3409fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 3419fbef1acSAvi Kivity 342977e1244SGerd Hoffmann #ifdef DEBUG_IDE 3439fbef1acSAvi Kivity printf("%s: 0x%08x\n", __func__, (unsigned)data); 344977e1244SGerd Hoffmann #endif 3459fbef1acSAvi Kivity bm->addr &= ~(mask << shift); 3469fbef1acSAvi Kivity bm->addr |= ((data & mask) << shift) & ~3; 347977e1244SGerd Hoffmann } 348977e1244SGerd Hoffmann 3499fbef1acSAvi Kivity const IORangeOps bmdma_addr_ioport_ops = { 3509fbef1acSAvi Kivity .read = bmdma_addr_read, 3519fbef1acSAvi Kivity .write = bmdma_addr_write, 3529fbef1acSAvi Kivity }; 353977e1244SGerd Hoffmann 3545ee84c33SJuan Quintela static bool ide_bmdma_current_needed(void *opaque) 3555ee84c33SJuan Quintela { 3565ee84c33SJuan Quintela BMDMAState *bm = opaque; 3575ee84c33SJuan Quintela 3585ee84c33SJuan Quintela return (bm->cur_prd_len != 0); 3595ee84c33SJuan Quintela } 3605ee84c33SJuan Quintela 3615ee84c33SJuan Quintela static const VMStateDescription vmstate_bmdma_current = { 3625ee84c33SJuan Quintela .name = "ide bmdma_current", 3635ee84c33SJuan Quintela .version_id = 1, 3645ee84c33SJuan Quintela .minimum_version_id = 1, 3655ee84c33SJuan Quintela .minimum_version_id_old = 1, 3665ee84c33SJuan Quintela .fields = (VMStateField []) { 3675ee84c33SJuan Quintela VMSTATE_UINT32(cur_addr, BMDMAState), 3685ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_last, BMDMAState), 3695ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_addr, BMDMAState), 3705ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_len, BMDMAState), 3715ee84c33SJuan Quintela VMSTATE_END_OF_LIST() 3725ee84c33SJuan Quintela } 3735ee84c33SJuan Quintela }; 3745ee84c33SJuan Quintela 3755ee84c33SJuan Quintela 376407a4f30SJuan Quintela static const VMStateDescription vmstate_bmdma = { 377407a4f30SJuan Quintela .name = "ide bmdma", 37857338424SJuan Quintela .version_id = 3, 379407a4f30SJuan Quintela .minimum_version_id = 0, 380407a4f30SJuan Quintela .minimum_version_id_old = 0, 381407a4f30SJuan Quintela .fields = (VMStateField []) { 382407a4f30SJuan Quintela VMSTATE_UINT8(cmd, BMDMAState), 383407a4f30SJuan Quintela VMSTATE_UINT8(status, BMDMAState), 384407a4f30SJuan Quintela VMSTATE_UINT32(addr, BMDMAState), 385407a4f30SJuan Quintela VMSTATE_INT64(sector_num, BMDMAState), 386407a4f30SJuan Quintela VMSTATE_UINT32(nsector, BMDMAState), 387407a4f30SJuan Quintela VMSTATE_UINT8(unit, BMDMAState), 388407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 3895ee84c33SJuan Quintela }, 3905ee84c33SJuan Quintela .subsections = (VMStateSubsection []) { 3915ee84c33SJuan Quintela { 3925ee84c33SJuan Quintela .vmsd = &vmstate_bmdma_current, 3935ee84c33SJuan Quintela .needed = ide_bmdma_current_needed, 3945ee84c33SJuan Quintela }, { 3955ee84c33SJuan Quintela /* empty */ 3965ee84c33SJuan Quintela } 397407a4f30SJuan Quintela } 398407a4f30SJuan Quintela }; 399407a4f30SJuan Quintela 400407a4f30SJuan Quintela static int ide_pci_post_load(void *opaque, int version_id) 401977e1244SGerd Hoffmann { 402977e1244SGerd Hoffmann PCIIDEState *d = opaque; 403977e1244SGerd Hoffmann int i; 404977e1244SGerd Hoffmann 405977e1244SGerd Hoffmann for(i = 0; i < 2; i++) { 406407a4f30SJuan Quintela /* current versions always store 0/1, but older version 407407a4f30SJuan Quintela stored bigger values. We only need last bit */ 408407a4f30SJuan Quintela d->bmdma[i].unit &= 1; 409977e1244SGerd Hoffmann } 410977e1244SGerd Hoffmann return 0; 411977e1244SGerd Hoffmann } 412977e1244SGerd Hoffmann 413407a4f30SJuan Quintela const VMStateDescription vmstate_ide_pci = { 414407a4f30SJuan Quintela .name = "ide", 41557338424SJuan Quintela .version_id = 3, 416407a4f30SJuan Quintela .minimum_version_id = 0, 417407a4f30SJuan Quintela .minimum_version_id_old = 0, 418407a4f30SJuan Quintela .post_load = ide_pci_post_load, 419407a4f30SJuan Quintela .fields = (VMStateField []) { 420407a4f30SJuan Quintela VMSTATE_PCI_DEVICE(dev, PCIIDEState), 421407a4f30SJuan Quintela VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, 422407a4f30SJuan Quintela vmstate_bmdma, BMDMAState), 423407a4f30SJuan Quintela VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), 424407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState), 425407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState), 426407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 427407a4f30SJuan Quintela } 428407a4f30SJuan Quintela }; 429407a4f30SJuan Quintela 4303e7e1558SJuan Quintela void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table) 431feef3102SGerd Hoffmann { 432feef3102SGerd Hoffmann PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); 433feef3102SGerd Hoffmann static const int bus[4] = { 0, 0, 1, 1 }; 434feef3102SGerd Hoffmann static const int unit[4] = { 0, 1, 0, 1 }; 435feef3102SGerd Hoffmann int i; 436feef3102SGerd Hoffmann 437feef3102SGerd Hoffmann for (i = 0; i < 4; i++) { 438feef3102SGerd Hoffmann if (hd_table[i] == NULL) 439feef3102SGerd Hoffmann continue; 4401f850f10SGerd Hoffmann ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]); 441feef3102SGerd Hoffmann } 442feef3102SGerd Hoffmann } 44340a6238aSAlexander Graf 44440a6238aSAlexander Graf static const struct IDEDMAOps bmdma_ops = { 44540a6238aSAlexander Graf .start_dma = bmdma_start_dma, 44640a6238aSAlexander Graf .start_transfer = bmdma_start_transfer, 44740a6238aSAlexander Graf .prepare_buf = bmdma_prepare_buf, 44840a6238aSAlexander Graf .rw_buf = bmdma_rw_buf, 44940a6238aSAlexander Graf .set_unit = bmdma_set_unit, 45040a6238aSAlexander Graf .add_status = bmdma_add_status, 45140a6238aSAlexander Graf .set_inactive = bmdma_set_inactive, 45240a6238aSAlexander Graf .restart_cb = bmdma_restart_cb, 45340a6238aSAlexander Graf .reset = bmdma_reset, 45440a6238aSAlexander Graf }; 45540a6238aSAlexander Graf 45640a6238aSAlexander Graf void bmdma_init(IDEBus *bus, BMDMAState *bm) 45740a6238aSAlexander Graf { 45840a6238aSAlexander Graf qemu_irq *irq; 45940a6238aSAlexander Graf 46040a6238aSAlexander Graf if (bus->dma == &bm->dma) { 46140a6238aSAlexander Graf return; 46240a6238aSAlexander Graf } 46340a6238aSAlexander Graf 46440a6238aSAlexander Graf bm->dma.ops = &bmdma_ops; 46540a6238aSAlexander Graf bus->dma = &bm->dma; 46640a6238aSAlexander Graf bm->irq = bus->irq; 46740a6238aSAlexander Graf irq = qemu_allocate_irqs(bmdma_irq, bm, 1); 46840a6238aSAlexander Graf bus->irq = *irq; 46940a6238aSAlexander Graf } 470