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 107*fd6a543dSMark Cave-Ayland void pci_ide_update_mode(PCIIDEState *s) 108*fd6a543dSMark Cave-Ayland { 109*fd6a543dSMark Cave-Ayland PCIDevice *d = PCI_DEVICE(s); 110*fd6a543dSMark Cave-Ayland uint8_t mode = d->config[PCI_CLASS_PROG]; 111*fd6a543dSMark Cave-Ayland 112*fd6a543dSMark Cave-Ayland /* 113*fd6a543dSMark Cave-Ayland * This function only configures the BARs/ioports for now: PCI IDE 114*fd6a543dSMark Cave-Ayland * controllers must manage their own IRQ routing 115*fd6a543dSMark Cave-Ayland */ 116*fd6a543dSMark Cave-Ayland 117*fd6a543dSMark Cave-Ayland switch (mode & 0xf) { 118*fd6a543dSMark Cave-Ayland case 0xa: 119*fd6a543dSMark Cave-Ayland /* Both channels legacy mode */ 120*fd6a543dSMark Cave-Ayland 121*fd6a543dSMark Cave-Ayland /* 122*fd6a543dSMark Cave-Ayland * TODO: according to the PCI IDE specification the BARs should 123*fd6a543dSMark Cave-Ayland * be completely disabled, however Linux for the pegasos2 124*fd6a543dSMark Cave-Ayland * machine stil accesses the BAR addresses after switching to legacy 125*fd6a543dSMark Cave-Ayland * mode. Hence we leave them active for now. 126*fd6a543dSMark Cave-Ayland */ 127*fd6a543dSMark Cave-Ayland 128*fd6a543dSMark Cave-Ayland /* Clear interrupt pin */ 129*fd6a543dSMark Cave-Ayland pci_config_set_interrupt_pin(d->config, 0); 130*fd6a543dSMark Cave-Ayland 131*fd6a543dSMark Cave-Ayland /* Add legacy IDE ports */ 132*fd6a543dSMark Cave-Ayland if (!s->bus[0].portio_list.owner) { 133*fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[0].portio_list, OBJECT(d), 134*fd6a543dSMark Cave-Ayland ide_portio_list, &s->bus[0], "ide"); 135*fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[0].portio_list, 136*fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x1f0); 137*fd6a543dSMark Cave-Ayland } 138*fd6a543dSMark Cave-Ayland 139*fd6a543dSMark Cave-Ayland if (!s->bus[0].portio2_list.owner) { 140*fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[0].portio2_list, OBJECT(d), 141*fd6a543dSMark Cave-Ayland ide_portio2_list, &s->bus[0], "ide"); 142*fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[0].portio2_list, 143*fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x3f6); 144*fd6a543dSMark Cave-Ayland } 145*fd6a543dSMark Cave-Ayland 146*fd6a543dSMark Cave-Ayland if (!s->bus[1].portio_list.owner) { 147*fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[1].portio_list, OBJECT(d), 148*fd6a543dSMark Cave-Ayland ide_portio_list, &s->bus[1], "ide"); 149*fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[1].portio_list, 150*fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x170); 151*fd6a543dSMark Cave-Ayland } 152*fd6a543dSMark Cave-Ayland 153*fd6a543dSMark Cave-Ayland if (!s->bus[1].portio2_list.owner) { 154*fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[1].portio2_list, OBJECT(d), 155*fd6a543dSMark Cave-Ayland ide_portio2_list, &s->bus[1], "ide"); 156*fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[1].portio2_list, 157*fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x376); 158*fd6a543dSMark Cave-Ayland } 159*fd6a543dSMark Cave-Ayland break; 160*fd6a543dSMark Cave-Ayland 161*fd6a543dSMark Cave-Ayland case 0xf: 162*fd6a543dSMark Cave-Ayland /* Both channels native mode */ 163*fd6a543dSMark Cave-Ayland 164*fd6a543dSMark Cave-Ayland /* Set interrupt pin */ 165*fd6a543dSMark Cave-Ayland pci_config_set_interrupt_pin(d->config, 1); 166*fd6a543dSMark Cave-Ayland 167*fd6a543dSMark Cave-Ayland /* Remove legacy IDE ports */ 168*fd6a543dSMark Cave-Ayland if (s->bus[0].portio_list.owner) { 169*fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[0].portio_list); 170*fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[0].portio_list); 171*fd6a543dSMark Cave-Ayland } 172*fd6a543dSMark Cave-Ayland 173*fd6a543dSMark Cave-Ayland if (s->bus[0].portio2_list.owner) { 174*fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[0].portio2_list); 175*fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[0].portio2_list); 176*fd6a543dSMark Cave-Ayland } 177*fd6a543dSMark Cave-Ayland 178*fd6a543dSMark Cave-Ayland if (s->bus[1].portio_list.owner) { 179*fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[1].portio_list); 180*fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[1].portio_list); 181*fd6a543dSMark Cave-Ayland } 182*fd6a543dSMark Cave-Ayland 183*fd6a543dSMark Cave-Ayland if (s->bus[1].portio2_list.owner) { 184*fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[1].portio2_list); 185*fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[1].portio2_list); 186*fd6a543dSMark Cave-Ayland } 187*fd6a543dSMark Cave-Ayland break; 188*fd6a543dSMark Cave-Ayland } 189*fd6a543dSMark Cave-Ayland } 190*fd6a543dSMark Cave-Ayland 1913e5f247eSBernhard Beschow static IDEState *bmdma_active_if(BMDMAState *bmdma) 1923e5f247eSBernhard Beschow { 1933e5f247eSBernhard Beschow assert(bmdma->bus->retry_unit != (uint8_t)-1); 1943e5f247eSBernhard Beschow return bmdma->bus->ifs + bmdma->bus->retry_unit; 1953e5f247eSBernhard Beschow } 1963e5f247eSBernhard Beschow 197ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_start_dma(const IDEDMA *dma, IDEState *s, 198097310b5SMarkus Armbruster BlockCompletionFunc *dma_cb) 19940a6238aSAlexander Graf { 20040a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 20140a6238aSAlexander Graf 20240a6238aSAlexander Graf bm->dma_cb = dma_cb; 20340a6238aSAlexander Graf bm->cur_prd_last = 0; 20440a6238aSAlexander Graf bm->cur_prd_addr = 0; 20540a6238aSAlexander Graf bm->cur_prd_len = 0; 20640a6238aSAlexander Graf 20740a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 20840a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 20940a6238aSAlexander Graf } 21040a6238aSAlexander Graf } 21140a6238aSAlexander Graf 2123251bdcfSJohn Snow /** 213a718978eSJohn Snow * Prepare an sglist based on available PRDs. 214a718978eSJohn Snow * @limit: How many bytes to prepare total. 215a718978eSJohn Snow * 216a718978eSJohn Snow * Returns the number of bytes prepared, -1 on error. 217a718978eSJohn Snow * IDEState.io_buffer_size will contain the number of bytes described 218a718978eSJohn Snow * by the PRDs, whether or not we added them to the sglist. 2193251bdcfSJohn Snow */ 220ae0cebd7SPhilippe Mathieu-Daudé static int32_t bmdma_prepare_buf(const IDEDMA *dma, int32_t limit) 22140a6238aSAlexander Graf { 22240a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 22340a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 224f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 22540a6238aSAlexander Graf struct { 22640a6238aSAlexander Graf uint32_t addr; 22740a6238aSAlexander Graf uint32_t size; 22840a6238aSAlexander Graf } prd; 22940a6238aSAlexander Graf int l, len; 23040a6238aSAlexander Graf 231f6c11d56SAndreas Färber pci_dma_sglist_init(&s->sg, pci_dev, 2324a13980bSPhilippe Mathieu-Daudé s->nsector / (BMDMA_PAGE_SIZE / BDRV_SECTOR_SIZE) + 1); 23340a6238aSAlexander Graf s->io_buffer_size = 0; 23440a6238aSAlexander Graf for(;;) { 23540a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 23640a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 23740a6238aSAlexander Graf if (bm->cur_prd_last || 2383251bdcfSJohn Snow (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) { 239a718978eSJohn Snow return s->sg.size; 2403251bdcfSJohn Snow } 241f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 24240a6238aSAlexander Graf bm->cur_addr += 8; 24340a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 24440a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 24540a6238aSAlexander Graf len = prd.size & 0xfffe; 24640a6238aSAlexander Graf if (len == 0) 24740a6238aSAlexander Graf len = 0x10000; 24840a6238aSAlexander Graf bm->cur_prd_len = len; 24940a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 25040a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 25140a6238aSAlexander Graf } 25240a6238aSAlexander Graf l = bm->cur_prd_len; 25340a6238aSAlexander Graf if (l > 0) { 254a718978eSJohn Snow uint64_t sg_len; 255a718978eSJohn Snow 256a718978eSJohn Snow /* Don't add extra bytes to the SGList; consume any remaining 257a718978eSJohn Snow * PRDs from the guest, but ignore them. */ 258a718978eSJohn Snow sg_len = MIN(limit - s->sg.size, bm->cur_prd_len); 259a718978eSJohn Snow if (sg_len) { 260a718978eSJohn Snow qemu_sglist_add(&s->sg, bm->cur_prd_addr, sg_len); 261a718978eSJohn Snow } 2623251bdcfSJohn Snow 26340a6238aSAlexander Graf bm->cur_prd_addr += l; 26440a6238aSAlexander Graf bm->cur_prd_len -= l; 26540a6238aSAlexander Graf s->io_buffer_size += l; 26640a6238aSAlexander Graf } 26740a6238aSAlexander Graf } 2683251bdcfSJohn Snow 2693251bdcfSJohn Snow qemu_sglist_destroy(&s->sg); 2703251bdcfSJohn Snow s->io_buffer_size = 0; 2713251bdcfSJohn Snow return -1; 27240a6238aSAlexander Graf } 27340a6238aSAlexander Graf 27440a6238aSAlexander Graf /* return 0 if buffer completed */ 275ae0cebd7SPhilippe Mathieu-Daudé static int bmdma_rw_buf(const IDEDMA *dma, bool is_write) 27640a6238aSAlexander Graf { 27740a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 27840a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 279f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 28040a6238aSAlexander Graf struct { 28140a6238aSAlexander Graf uint32_t addr; 28240a6238aSAlexander Graf uint32_t size; 28340a6238aSAlexander Graf } prd; 28440a6238aSAlexander Graf int l, len; 28540a6238aSAlexander Graf 28640a6238aSAlexander Graf for(;;) { 28740a6238aSAlexander Graf l = s->io_buffer_size - s->io_buffer_index; 28840a6238aSAlexander Graf if (l <= 0) 28940a6238aSAlexander Graf break; 29040a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 29140a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 29240a6238aSAlexander Graf if (bm->cur_prd_last || 29340a6238aSAlexander Graf (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) 29440a6238aSAlexander Graf return 0; 295f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 29640a6238aSAlexander Graf bm->cur_addr += 8; 29740a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 29840a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 29940a6238aSAlexander Graf len = prd.size & 0xfffe; 30040a6238aSAlexander Graf if (len == 0) 30140a6238aSAlexander Graf len = 0x10000; 30240a6238aSAlexander Graf bm->cur_prd_len = len; 30340a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 30440a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 30540a6238aSAlexander Graf } 30640a6238aSAlexander Graf if (l > bm->cur_prd_len) 30740a6238aSAlexander Graf l = bm->cur_prd_len; 30840a6238aSAlexander Graf if (l > 0) { 30940a6238aSAlexander Graf if (is_write) { 310f6c11d56SAndreas Färber pci_dma_write(pci_dev, bm->cur_prd_addr, 31140a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 31240a6238aSAlexander Graf } else { 313f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_prd_addr, 31440a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 31540a6238aSAlexander Graf } 31640a6238aSAlexander Graf bm->cur_prd_addr += l; 31740a6238aSAlexander Graf bm->cur_prd_len -= l; 31840a6238aSAlexander Graf s->io_buffer_index += l; 31940a6238aSAlexander Graf } 32040a6238aSAlexander Graf } 32140a6238aSAlexander Graf return 1; 32240a6238aSAlexander Graf } 32340a6238aSAlexander Graf 324ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_set_inactive(const IDEDMA *dma, bool more) 32540a6238aSAlexander Graf { 32640a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 32740a6238aSAlexander Graf 32840a6238aSAlexander Graf bm->dma_cb = NULL; 3290e7ce54cSPaolo Bonzini if (more) { 3300e7ce54cSPaolo Bonzini bm->status |= BM_STATUS_DMAING; 3310e7ce54cSPaolo Bonzini } else { 3320e7ce54cSPaolo Bonzini bm->status &= ~BM_STATUS_DMAING; 3330e7ce54cSPaolo Bonzini } 33440a6238aSAlexander Graf } 33540a6238aSAlexander Graf 336ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_restart_dma(const IDEDMA *dma) 33740a6238aSAlexander Graf { 33840a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 33940a6238aSAlexander Graf 34006b95b1eSPaolo Bonzini bm->cur_addr = bm->addr; 34140a6238aSAlexander Graf } 34240a6238aSAlexander Graf 34340a6238aSAlexander Graf static void bmdma_cancel(BMDMAState *bm) 34440a6238aSAlexander Graf { 34540a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 34640a6238aSAlexander Graf /* cancel DMA request */ 3470e7ce54cSPaolo Bonzini bmdma_set_inactive(&bm->dma, false); 34840a6238aSAlexander Graf } 34940a6238aSAlexander Graf } 35040a6238aSAlexander Graf 351ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_reset(const IDEDMA *dma) 35240a6238aSAlexander Graf { 35340a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 35440a6238aSAlexander Graf 3553eee2611SJohn Snow trace_bmdma_reset(); 35640a6238aSAlexander Graf bmdma_cancel(bm); 35740a6238aSAlexander Graf bm->cmd = 0; 35840a6238aSAlexander Graf bm->status = 0; 35940a6238aSAlexander Graf bm->addr = 0; 36040a6238aSAlexander Graf bm->cur_addr = 0; 36140a6238aSAlexander Graf bm->cur_prd_last = 0; 36240a6238aSAlexander Graf bm->cur_prd_addr = 0; 36340a6238aSAlexander Graf bm->cur_prd_len = 0; 36440a6238aSAlexander Graf } 36540a6238aSAlexander Graf 36640a6238aSAlexander Graf static void bmdma_irq(void *opaque, int n, int level) 36740a6238aSAlexander Graf { 36840a6238aSAlexander Graf BMDMAState *bm = opaque; 36940a6238aSAlexander Graf 37040a6238aSAlexander Graf if (!level) { 37140a6238aSAlexander Graf /* pass through lower */ 37240a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 37340a6238aSAlexander Graf return; 37440a6238aSAlexander Graf } 37540a6238aSAlexander Graf 37640a6238aSAlexander Graf bm->status |= BM_STATUS_INT; 37740a6238aSAlexander Graf 37840a6238aSAlexander Graf /* trigger the real irq */ 37940a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 38040a6238aSAlexander Graf } 38140a6238aSAlexander Graf 382a9deb8c6SAvi Kivity void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) 383977e1244SGerd Hoffmann { 3843eee2611SJohn Snow trace_bmdma_cmd_writeb(val); 385c29947bbSKevin Wolf 386c29947bbSKevin Wolf /* Ignore writes to SSBM if it keeps the old value */ 387c29947bbSKevin Wolf if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { 388977e1244SGerd Hoffmann if (!(val & BM_CMD_START)) { 3892c50207fSPhilippe Mathieu-Daudé ide_cancel_dma_sync(ide_bus_active_if(bm->bus)); 390b39f9612SKevin Wolf bm->status &= ~BM_STATUS_DMAING; 391977e1244SGerd Hoffmann } else { 392b76876e6SKevin Wolf bm->cur_addr = bm->addr; 393977e1244SGerd Hoffmann if (!(bm->status & BM_STATUS_DMAING)) { 394977e1244SGerd Hoffmann bm->status |= BM_STATUS_DMAING; 395977e1244SGerd Hoffmann /* start dma transfer if possible */ 396977e1244SGerd Hoffmann if (bm->dma_cb) 39740a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 398977e1244SGerd Hoffmann } 399977e1244SGerd Hoffmann } 400977e1244SGerd Hoffmann } 401977e1244SGerd Hoffmann 402c29947bbSKevin Wolf bm->cmd = val & 0x09; 403c29947bbSKevin Wolf } 404c29947bbSKevin Wolf 4055fe24213SBernhard Beschow void bmdma_status_writeb(BMDMAState *bm, uint32_t val) 4065fe24213SBernhard Beschow { 40717d6a4a3SBernhard Beschow bm->status = (val & 0x60) | (bm->status & BM_STATUS_DMAING) 40817d6a4a3SBernhard Beschow | (bm->status & ~val & (BM_STATUS_ERROR | BM_STATUS_INT)); 4095fe24213SBernhard Beschow } 4105fe24213SBernhard Beschow 411a8170e5eSAvi Kivity static uint64_t bmdma_addr_read(void *opaque, hwaddr addr, 412a9deb8c6SAvi Kivity unsigned width) 413977e1244SGerd Hoffmann { 414a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 4159fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 416a9deb8c6SAvi Kivity uint64_t data; 4179fbef1acSAvi Kivity 418a9deb8c6SAvi Kivity data = (bm->addr >> (addr * 8)) & mask; 4193eee2611SJohn Snow trace_bmdma_addr_read(data); 420a9deb8c6SAvi Kivity return data; 421977e1244SGerd Hoffmann } 422977e1244SGerd Hoffmann 423a8170e5eSAvi Kivity static void bmdma_addr_write(void *opaque, hwaddr addr, 424a9deb8c6SAvi Kivity uint64_t data, unsigned width) 425977e1244SGerd Hoffmann { 426a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 4279fbef1acSAvi Kivity int shift = addr * 8; 4289fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 4299fbef1acSAvi Kivity 4303eee2611SJohn Snow trace_bmdma_addr_write(data); 4319fbef1acSAvi Kivity bm->addr &= ~(mask << shift); 4329fbef1acSAvi Kivity bm->addr |= ((data & mask) << shift) & ~3; 433977e1244SGerd Hoffmann } 434977e1244SGerd Hoffmann 435a9deb8c6SAvi Kivity MemoryRegionOps bmdma_addr_ioport_ops = { 4369fbef1acSAvi Kivity .read = bmdma_addr_read, 4379fbef1acSAvi Kivity .write = bmdma_addr_write, 438a9deb8c6SAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 4399fbef1acSAvi Kivity }; 440977e1244SGerd Hoffmann 4415ee84c33SJuan Quintela static bool ide_bmdma_current_needed(void *opaque) 4425ee84c33SJuan Quintela { 4435ee84c33SJuan Quintela BMDMAState *bm = opaque; 4445ee84c33SJuan Quintela 4455ee84c33SJuan Quintela return (bm->cur_prd_len != 0); 4465ee84c33SJuan Quintela } 4475ee84c33SJuan Quintela 448def93791SKevin Wolf static bool ide_bmdma_status_needed(void *opaque) 449def93791SKevin Wolf { 450def93791SKevin Wolf BMDMAState *bm = opaque; 451def93791SKevin Wolf 452def93791SKevin Wolf /* Older versions abused some bits in the status register for internal 453def93791SKevin Wolf * error state. If any of these bits are set, we must add a subsection to 454def93791SKevin Wolf * transfer the real status register */ 455def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 456def93791SKevin Wolf 457def93791SKevin Wolf return ((bm->status & abused_bits) != 0); 458def93791SKevin Wolf } 459def93791SKevin Wolf 46044b1ff31SDr. David Alan Gilbert static int ide_bmdma_pre_save(void *opaque) 461def93791SKevin Wolf { 462def93791SKevin Wolf BMDMAState *bm = opaque; 463def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 464def93791SKevin Wolf 465218fd37cSPavel Butsykin if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) { 466218fd37cSPavel Butsykin bm->bus->error_status = 467218fd37cSPavel Butsykin ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd); 468218fd37cSPavel Butsykin } 469a96cb236SPaolo Bonzini bm->migration_retry_unit = bm->bus->retry_unit; 470dc5d0af4SPaolo Bonzini bm->migration_retry_sector_num = bm->bus->retry_sector_num; 471dc5d0af4SPaolo Bonzini bm->migration_retry_nsector = bm->bus->retry_nsector; 472def93791SKevin Wolf bm->migration_compat_status = 473def93791SKevin Wolf (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits); 47444b1ff31SDr. David Alan Gilbert 47544b1ff31SDr. David Alan Gilbert return 0; 476def93791SKevin Wolf } 477def93791SKevin Wolf 478def93791SKevin Wolf /* This function accesses bm->bus->error_status which is loaded only after 479def93791SKevin Wolf * BMDMA itself. This is why the function is called from ide_pci_post_load 480def93791SKevin Wolf * instead of being registered with VMState where it would run too early. */ 481def93791SKevin Wolf static int ide_bmdma_post_load(void *opaque, int version_id) 482def93791SKevin Wolf { 483def93791SKevin Wolf BMDMAState *bm = opaque; 484def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 485def93791SKevin Wolf 486def93791SKevin Wolf if (bm->status == 0) { 487def93791SKevin Wolf bm->status = bm->migration_compat_status & ~abused_bits; 488def93791SKevin Wolf bm->bus->error_status |= bm->migration_compat_status & abused_bits; 489def93791SKevin Wolf } 490a96cb236SPaolo Bonzini if (bm->bus->error_status) { 491dc5d0af4SPaolo Bonzini bm->bus->retry_sector_num = bm->migration_retry_sector_num; 492dc5d0af4SPaolo Bonzini bm->bus->retry_nsector = bm->migration_retry_nsector; 493a96cb236SPaolo Bonzini bm->bus->retry_unit = bm->migration_retry_unit; 494a96cb236SPaolo Bonzini } 495def93791SKevin Wolf 496def93791SKevin Wolf return 0; 497def93791SKevin Wolf } 498def93791SKevin Wolf 4995ee84c33SJuan Quintela static const VMStateDescription vmstate_bmdma_current = { 5005ee84c33SJuan Quintela .name = "ide bmdma_current", 5015ee84c33SJuan Quintela .version_id = 1, 5025ee84c33SJuan Quintela .minimum_version_id = 1, 5035cd8cadaSJuan Quintela .needed = ide_bmdma_current_needed, 5045ee84c33SJuan Quintela .fields = (VMStateField[]) { 5055ee84c33SJuan Quintela VMSTATE_UINT32(cur_addr, BMDMAState), 5065ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_last, BMDMAState), 5075ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_addr, BMDMAState), 5085ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_len, BMDMAState), 5095ee84c33SJuan Quintela VMSTATE_END_OF_LIST() 5105ee84c33SJuan Quintela } 5115ee84c33SJuan Quintela }; 5125ee84c33SJuan Quintela 51306ab66cfSStefan Weil static const VMStateDescription vmstate_bmdma_status = { 514def93791SKevin Wolf .name ="ide bmdma/status", 515def93791SKevin Wolf .version_id = 1, 516def93791SKevin Wolf .minimum_version_id = 1, 5175cd8cadaSJuan Quintela .needed = ide_bmdma_status_needed, 518def93791SKevin Wolf .fields = (VMStateField[]) { 519def93791SKevin Wolf VMSTATE_UINT8(status, BMDMAState), 520def93791SKevin Wolf VMSTATE_END_OF_LIST() 521def93791SKevin Wolf } 522def93791SKevin Wolf }; 5235ee84c33SJuan Quintela 524407a4f30SJuan Quintela static const VMStateDescription vmstate_bmdma = { 525407a4f30SJuan Quintela .name = "ide bmdma", 52657338424SJuan Quintela .version_id = 3, 527407a4f30SJuan Quintela .minimum_version_id = 0, 528def93791SKevin Wolf .pre_save = ide_bmdma_pre_save, 529407a4f30SJuan Quintela .fields = (VMStateField[]) { 530407a4f30SJuan Quintela VMSTATE_UINT8(cmd, BMDMAState), 531def93791SKevin Wolf VMSTATE_UINT8(migration_compat_status, BMDMAState), 532407a4f30SJuan Quintela VMSTATE_UINT32(addr, BMDMAState), 533dc5d0af4SPaolo Bonzini VMSTATE_INT64(migration_retry_sector_num, BMDMAState), 534dc5d0af4SPaolo Bonzini VMSTATE_UINT32(migration_retry_nsector, BMDMAState), 535a96cb236SPaolo Bonzini VMSTATE_UINT8(migration_retry_unit, BMDMAState), 536407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 5375ee84c33SJuan Quintela }, 5385cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 5395cd8cadaSJuan Quintela &vmstate_bmdma_current, 5405cd8cadaSJuan Quintela &vmstate_bmdma_status, 5415cd8cadaSJuan Quintela NULL 542407a4f30SJuan Quintela } 543407a4f30SJuan Quintela }; 544407a4f30SJuan Quintela 545407a4f30SJuan Quintela static int ide_pci_post_load(void *opaque, int version_id) 546977e1244SGerd Hoffmann { 547977e1244SGerd Hoffmann PCIIDEState *d = opaque; 548977e1244SGerd Hoffmann int i; 549977e1244SGerd Hoffmann 550977e1244SGerd Hoffmann for(i = 0; i < 2; i++) { 551407a4f30SJuan Quintela /* current versions always store 0/1, but older version 552407a4f30SJuan Quintela stored bigger values. We only need last bit */ 553a96cb236SPaolo Bonzini d->bmdma[i].migration_retry_unit &= 1; 554def93791SKevin Wolf ide_bmdma_post_load(&d->bmdma[i], -1); 555977e1244SGerd Hoffmann } 556def93791SKevin Wolf 557977e1244SGerd Hoffmann return 0; 558977e1244SGerd Hoffmann } 559977e1244SGerd Hoffmann 560407a4f30SJuan Quintela const VMStateDescription vmstate_ide_pci = { 561407a4f30SJuan Quintela .name = "ide", 56257338424SJuan Quintela .version_id = 3, 563407a4f30SJuan Quintela .minimum_version_id = 0, 564407a4f30SJuan Quintela .post_load = ide_pci_post_load, 565407a4f30SJuan Quintela .fields = (VMStateField[]) { 566f6c11d56SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PCIIDEState), 567407a4f30SJuan Quintela VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, 568407a4f30SJuan Quintela vmstate_bmdma, BMDMAState), 569407a4f30SJuan Quintela VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), 570407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState), 571407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState), 572407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 573407a4f30SJuan Quintela } 574407a4f30SJuan Quintela }; 575407a4f30SJuan Quintela 576df45d38fSBALATON Zoltan /* hd_table must contain 4 block drivers */ 577be1765f3SBALATON Zoltan void pci_ide_create_devs(PCIDevice *dev) 578feef3102SGerd Hoffmann { 579f6c11d56SAndreas Färber PCIIDEState *d = PCI_IDE(dev); 580be1765f3SBALATON Zoltan DriveInfo *hd_table[2 * MAX_IDE_DEVS]; 581feef3102SGerd Hoffmann static const int bus[4] = { 0, 0, 1, 1 }; 582feef3102SGerd Hoffmann static const int unit[4] = { 0, 1, 0, 1 }; 583feef3102SGerd Hoffmann int i; 584feef3102SGerd Hoffmann 585be1765f3SBALATON Zoltan ide_drive_get(hd_table, ARRAY_SIZE(hd_table)); 586feef3102SGerd Hoffmann for (i = 0; i < 4; i++) { 587417adc2dSBALATON Zoltan if (hd_table[i]) { 588b6a5ab27SPhilippe Mathieu-Daudé ide_bus_create_drive(d->bus + bus[i], unit[i], hd_table[i]); 589feef3102SGerd Hoffmann } 590feef3102SGerd Hoffmann } 591417adc2dSBALATON Zoltan } 59240a6238aSAlexander Graf 59340a6238aSAlexander Graf static const struct IDEDMAOps bmdma_ops = { 59440a6238aSAlexander Graf .start_dma = bmdma_start_dma, 59540a6238aSAlexander Graf .prepare_buf = bmdma_prepare_buf, 59640a6238aSAlexander Graf .rw_buf = bmdma_rw_buf, 597bd8892c4SPaolo Bonzini .restart_dma = bmdma_restart_dma, 59840a6238aSAlexander Graf .set_inactive = bmdma_set_inactive, 59940a6238aSAlexander Graf .reset = bmdma_reset, 60040a6238aSAlexander Graf }; 60140a6238aSAlexander Graf 602a9deb8c6SAvi Kivity void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d) 60340a6238aSAlexander Graf { 60440a6238aSAlexander Graf if (bus->dma == &bm->dma) { 60540a6238aSAlexander Graf return; 60640a6238aSAlexander Graf } 60740a6238aSAlexander Graf 60840a6238aSAlexander Graf bm->dma.ops = &bmdma_ops; 60940a6238aSAlexander Graf bus->dma = &bm->dma; 61040a6238aSAlexander Graf bm->irq = bus->irq; 6116e38a4baSShannon Zhao bus->irq = qemu_allocate_irq(bmdma_irq, bm, 0); 612bf0576edSBernhard Beschow bm->bus = bus; 613a9deb8c6SAvi Kivity bm->pci_dev = d; 61440a6238aSAlexander Graf } 615f6c11d56SAndreas Färber 616e2b84ee4SBernhard Beschow static void pci_ide_init(Object *obj) 617e2b84ee4SBernhard Beschow { 618e2b84ee4SBernhard Beschow PCIIDEState *d = PCI_IDE(obj); 619e2b84ee4SBernhard Beschow 620e2b84ee4SBernhard Beschow qdev_init_gpio_out_named(DEVICE(d), d->isa_irq, "isa-irq", 621e2b84ee4SBernhard Beschow ARRAY_SIZE(d->isa_irq)); 622e2b84ee4SBernhard Beschow } 623e2b84ee4SBernhard Beschow 624f6c11d56SAndreas Färber static const TypeInfo pci_ide_type_info = { 625f6c11d56SAndreas Färber .name = TYPE_PCI_IDE, 626f6c11d56SAndreas Färber .parent = TYPE_PCI_DEVICE, 627f6c11d56SAndreas Färber .instance_size = sizeof(PCIIDEState), 628e2b84ee4SBernhard Beschow .instance_init = pci_ide_init, 629f6c11d56SAndreas Färber .abstract = true, 630fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) { 631fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 632fd3b02c8SEduardo Habkost { }, 633fd3b02c8SEduardo Habkost }, 634f6c11d56SAndreas Färber }; 635f6c11d56SAndreas Färber 636f6c11d56SAndreas Färber static void pci_ide_register_types(void) 637f6c11d56SAndreas Färber { 638f6c11d56SAndreas Färber type_register_static(&pci_ide_type_info); 639f6c11d56SAndreas Färber } 640f6c11d56SAndreas Färber 641f6c11d56SAndreas Färber type_init(pci_ide_register_types) 642