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" 30*32cad1ffSPhilippe Mathieu-Daudé #include "system/dma.h" 313251bdcfSJohn Snow #include "qemu/error-report.h" 320b8fa32fSMarkus Armbruster #include "qemu/module.h" 33a9c94277SMarkus Armbruster #include "hw/ide/pci.h" 340316482eSPhilippe Mathieu-Daudé #include "ide-internal.h" 353eee2611SJohn Snow #include "trace.h" 36977e1244SGerd Hoffmann 3740a6238aSAlexander Graf #define BMDMA_PAGE_SIZE 4096 3840a6238aSAlexander Graf 397e2648dfSPaolo Bonzini #define BM_MIGRATION_COMPAT_STATUS_BITS \ 40fd648f10SPaolo Bonzini (IDE_RETRY_DMA | IDE_RETRY_PIO | \ 41fd648f10SPaolo Bonzini IDE_RETRY_READ | IDE_RETRY_FLUSH) 427e2648dfSPaolo Bonzini 4398d98912SJohn Snow static uint64_t pci_ide_status_read(void *opaque, hwaddr addr, unsigned size) 44c9ebc75dSBALATON Zoltan { 45c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 46c9ebc75dSBALATON Zoltan 47c9ebc75dSBALATON Zoltan if (addr != 2 || size != 1) { 48c9ebc75dSBALATON Zoltan return ((uint64_t)1 << (size * 8)) - 1; 49c9ebc75dSBALATON Zoltan } 50c9ebc75dSBALATON Zoltan return ide_status_read(bus, addr + 2); 51c9ebc75dSBALATON Zoltan } 52c9ebc75dSBALATON Zoltan 5398d98912SJohn Snow static void pci_ide_ctrl_write(void *opaque, hwaddr addr, 54c9ebc75dSBALATON Zoltan uint64_t data, unsigned size) 55c9ebc75dSBALATON Zoltan { 56c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 57c9ebc75dSBALATON Zoltan 58c9ebc75dSBALATON Zoltan if (addr != 2 || size != 1) { 59c9ebc75dSBALATON Zoltan return; 60c9ebc75dSBALATON Zoltan } 6198d98912SJohn Snow ide_ctrl_write(bus, addr + 2, data); 62c9ebc75dSBALATON Zoltan } 63c9ebc75dSBALATON Zoltan 64c9ebc75dSBALATON Zoltan const MemoryRegionOps pci_ide_cmd_le_ops = { 6598d98912SJohn Snow .read = pci_ide_status_read, 6698d98912SJohn Snow .write = pci_ide_ctrl_write, 67c9ebc75dSBALATON Zoltan .endianness = DEVICE_LITTLE_ENDIAN, 68c9ebc75dSBALATON Zoltan }; 69c9ebc75dSBALATON Zoltan 70c9ebc75dSBALATON Zoltan static uint64_t pci_ide_data_read(void *opaque, hwaddr addr, unsigned size) 71c9ebc75dSBALATON Zoltan { 72c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 73c9ebc75dSBALATON Zoltan 74c9ebc75dSBALATON Zoltan if (size == 1) { 75c9ebc75dSBALATON Zoltan return ide_ioport_read(bus, addr); 76c9ebc75dSBALATON Zoltan } else if (addr == 0) { 77c9ebc75dSBALATON Zoltan if (size == 2) { 78c9ebc75dSBALATON Zoltan return ide_data_readw(bus, addr); 79c9ebc75dSBALATON Zoltan } else { 80c9ebc75dSBALATON Zoltan return ide_data_readl(bus, addr); 81c9ebc75dSBALATON Zoltan } 82c9ebc75dSBALATON Zoltan } 83c9ebc75dSBALATON Zoltan return ((uint64_t)1 << (size * 8)) - 1; 84c9ebc75dSBALATON Zoltan } 85c9ebc75dSBALATON Zoltan 86c9ebc75dSBALATON Zoltan static void pci_ide_data_write(void *opaque, hwaddr addr, 87c9ebc75dSBALATON Zoltan uint64_t data, unsigned size) 88c9ebc75dSBALATON Zoltan { 89c9ebc75dSBALATON Zoltan IDEBus *bus = opaque; 90c9ebc75dSBALATON Zoltan 91c9ebc75dSBALATON Zoltan if (size == 1) { 92c9ebc75dSBALATON Zoltan ide_ioport_write(bus, addr, data); 93c9ebc75dSBALATON Zoltan } else if (addr == 0) { 94c9ebc75dSBALATON Zoltan if (size == 2) { 95c9ebc75dSBALATON Zoltan ide_data_writew(bus, addr, data); 96c9ebc75dSBALATON Zoltan } else { 97c9ebc75dSBALATON Zoltan ide_data_writel(bus, addr, data); 98c9ebc75dSBALATON Zoltan } 99c9ebc75dSBALATON Zoltan } 100c9ebc75dSBALATON Zoltan } 101c9ebc75dSBALATON Zoltan 102c9ebc75dSBALATON Zoltan const MemoryRegionOps pci_ide_data_le_ops = { 103c9ebc75dSBALATON Zoltan .read = pci_ide_data_read, 104c9ebc75dSBALATON Zoltan .write = pci_ide_data_write, 105c9ebc75dSBALATON Zoltan .endianness = DEVICE_LITTLE_ENDIAN, 106c9ebc75dSBALATON Zoltan }; 107c9ebc75dSBALATON Zoltan 108fd6a543dSMark Cave-Ayland void pci_ide_update_mode(PCIIDEState *s) 109fd6a543dSMark Cave-Ayland { 110fd6a543dSMark Cave-Ayland PCIDevice *d = PCI_DEVICE(s); 111fd6a543dSMark Cave-Ayland uint8_t mode = d->config[PCI_CLASS_PROG]; 112fd6a543dSMark Cave-Ayland 113fd6a543dSMark Cave-Ayland /* 114fd6a543dSMark Cave-Ayland * This function only configures the BARs/ioports for now: PCI IDE 115fd6a543dSMark Cave-Ayland * controllers must manage their own IRQ routing 116fd6a543dSMark Cave-Ayland */ 117fd6a543dSMark Cave-Ayland 118fd6a543dSMark Cave-Ayland switch (mode & 0xf) { 119fd6a543dSMark Cave-Ayland case 0xa: 120fd6a543dSMark Cave-Ayland /* Both channels legacy mode */ 121fd6a543dSMark Cave-Ayland 122fd6a543dSMark Cave-Ayland /* 123fd6a543dSMark Cave-Ayland * TODO: according to the PCI IDE specification the BARs should 124fd6a543dSMark Cave-Ayland * be completely disabled, however Linux for the pegasos2 125fd6a543dSMark Cave-Ayland * machine stil accesses the BAR addresses after switching to legacy 126fd6a543dSMark Cave-Ayland * mode. Hence we leave them active for now. 127fd6a543dSMark Cave-Ayland */ 128fd6a543dSMark Cave-Ayland 129fd6a543dSMark Cave-Ayland /* Clear interrupt pin */ 130fd6a543dSMark Cave-Ayland pci_config_set_interrupt_pin(d->config, 0); 131fd6a543dSMark Cave-Ayland 132fd6a543dSMark Cave-Ayland /* Add legacy IDE ports */ 133fd6a543dSMark Cave-Ayland if (!s->bus[0].portio_list.owner) { 134fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[0].portio_list, OBJECT(d), 135fd6a543dSMark Cave-Ayland ide_portio_list, &s->bus[0], "ide"); 136fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[0].portio_list, 137fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x1f0); 138fd6a543dSMark Cave-Ayland } 139fd6a543dSMark Cave-Ayland 140fd6a543dSMark Cave-Ayland if (!s->bus[0].portio2_list.owner) { 141fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[0].portio2_list, OBJECT(d), 142fd6a543dSMark Cave-Ayland ide_portio2_list, &s->bus[0], "ide"); 143fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[0].portio2_list, 144fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x3f6); 145fd6a543dSMark Cave-Ayland } 146fd6a543dSMark Cave-Ayland 147fd6a543dSMark Cave-Ayland if (!s->bus[1].portio_list.owner) { 148fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[1].portio_list, OBJECT(d), 149fd6a543dSMark Cave-Ayland ide_portio_list, &s->bus[1], "ide"); 150fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[1].portio_list, 151fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x170); 152fd6a543dSMark Cave-Ayland } 153fd6a543dSMark Cave-Ayland 154fd6a543dSMark Cave-Ayland if (!s->bus[1].portio2_list.owner) { 155fd6a543dSMark Cave-Ayland portio_list_init(&s->bus[1].portio2_list, OBJECT(d), 156fd6a543dSMark Cave-Ayland ide_portio2_list, &s->bus[1], "ide"); 157fd6a543dSMark Cave-Ayland portio_list_add(&s->bus[1].portio2_list, 158fd6a543dSMark Cave-Ayland pci_address_space_io(d), 0x376); 159fd6a543dSMark Cave-Ayland } 160fd6a543dSMark Cave-Ayland break; 161fd6a543dSMark Cave-Ayland 162fd6a543dSMark Cave-Ayland case 0xf: 163fd6a543dSMark Cave-Ayland /* Both channels native mode */ 164fd6a543dSMark Cave-Ayland 165fd6a543dSMark Cave-Ayland /* Set interrupt pin */ 166fd6a543dSMark Cave-Ayland pci_config_set_interrupt_pin(d->config, 1); 167fd6a543dSMark Cave-Ayland 168fd6a543dSMark Cave-Ayland /* Remove legacy IDE ports */ 169fd6a543dSMark Cave-Ayland if (s->bus[0].portio_list.owner) { 170fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[0].portio_list); 171fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[0].portio_list); 172fd6a543dSMark Cave-Ayland } 173fd6a543dSMark Cave-Ayland 174fd6a543dSMark Cave-Ayland if (s->bus[0].portio2_list.owner) { 175fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[0].portio2_list); 176fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[0].portio2_list); 177fd6a543dSMark Cave-Ayland } 178fd6a543dSMark Cave-Ayland 179fd6a543dSMark Cave-Ayland if (s->bus[1].portio_list.owner) { 180fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[1].portio_list); 181fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[1].portio_list); 182fd6a543dSMark Cave-Ayland } 183fd6a543dSMark Cave-Ayland 184fd6a543dSMark Cave-Ayland if (s->bus[1].portio2_list.owner) { 185fd6a543dSMark Cave-Ayland portio_list_del(&s->bus[1].portio2_list); 186fd6a543dSMark Cave-Ayland portio_list_destroy(&s->bus[1].portio2_list); 187fd6a543dSMark Cave-Ayland } 188fd6a543dSMark Cave-Ayland break; 189fd6a543dSMark Cave-Ayland } 190fd6a543dSMark Cave-Ayland } 191fd6a543dSMark Cave-Ayland 1923e5f247eSBernhard Beschow static IDEState *bmdma_active_if(BMDMAState *bmdma) 1933e5f247eSBernhard Beschow { 1943e5f247eSBernhard Beschow assert(bmdma->bus->retry_unit != (uint8_t)-1); 1953e5f247eSBernhard Beschow return bmdma->bus->ifs + bmdma->bus->retry_unit; 1963e5f247eSBernhard Beschow } 1973e5f247eSBernhard Beschow 198ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_start_dma(const IDEDMA *dma, IDEState *s, 199097310b5SMarkus Armbruster BlockCompletionFunc *dma_cb) 20040a6238aSAlexander Graf { 20140a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 20240a6238aSAlexander Graf 20340a6238aSAlexander Graf bm->dma_cb = dma_cb; 20440a6238aSAlexander Graf bm->cur_prd_last = 0; 20540a6238aSAlexander Graf bm->cur_prd_addr = 0; 20640a6238aSAlexander Graf bm->cur_prd_len = 0; 20740a6238aSAlexander Graf 20840a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 20940a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 21040a6238aSAlexander Graf } 21140a6238aSAlexander Graf } 21240a6238aSAlexander Graf 2133251bdcfSJohn Snow /** 214a718978eSJohn Snow * Prepare an sglist based on available PRDs. 215a718978eSJohn Snow * @limit: How many bytes to prepare total. 216a718978eSJohn Snow * 217a718978eSJohn Snow * Returns the number of bytes prepared, -1 on error. 218a718978eSJohn Snow * IDEState.io_buffer_size will contain the number of bytes described 219a718978eSJohn Snow * by the PRDs, whether or not we added them to the sglist. 2203251bdcfSJohn Snow */ 221ae0cebd7SPhilippe Mathieu-Daudé static int32_t bmdma_prepare_buf(const IDEDMA *dma, int32_t limit) 22240a6238aSAlexander Graf { 22340a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 22440a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 225f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 22640a6238aSAlexander Graf struct { 22740a6238aSAlexander Graf uint32_t addr; 22840a6238aSAlexander Graf uint32_t size; 22940a6238aSAlexander Graf } prd; 23040a6238aSAlexander Graf int l, len; 23140a6238aSAlexander Graf 232f6c11d56SAndreas Färber pci_dma_sglist_init(&s->sg, pci_dev, 2334a13980bSPhilippe Mathieu-Daudé s->nsector / (BMDMA_PAGE_SIZE / BDRV_SECTOR_SIZE) + 1); 23440a6238aSAlexander Graf s->io_buffer_size = 0; 23540a6238aSAlexander Graf for(;;) { 23640a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 23740a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 23840a6238aSAlexander Graf if (bm->cur_prd_last || 2393251bdcfSJohn Snow (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) { 240c1a6ae51SPeter Maydell break; 2413251bdcfSJohn Snow } 242f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 24340a6238aSAlexander Graf bm->cur_addr += 8; 24440a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 24540a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 24640a6238aSAlexander Graf len = prd.size & 0xfffe; 24740a6238aSAlexander Graf if (len == 0) 24840a6238aSAlexander Graf len = 0x10000; 24940a6238aSAlexander Graf bm->cur_prd_len = len; 25040a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 25140a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 25240a6238aSAlexander Graf } 25340a6238aSAlexander Graf l = bm->cur_prd_len; 25440a6238aSAlexander Graf if (l > 0) { 255a718978eSJohn Snow uint64_t sg_len; 256a718978eSJohn Snow 257a718978eSJohn Snow /* Don't add extra bytes to the SGList; consume any remaining 258a718978eSJohn Snow * PRDs from the guest, but ignore them. */ 259a718978eSJohn Snow sg_len = MIN(limit - s->sg.size, bm->cur_prd_len); 260a718978eSJohn Snow if (sg_len) { 261a718978eSJohn Snow qemu_sglist_add(&s->sg, bm->cur_prd_addr, sg_len); 262a718978eSJohn Snow } 2633251bdcfSJohn Snow 26440a6238aSAlexander Graf bm->cur_prd_addr += l; 26540a6238aSAlexander Graf bm->cur_prd_len -= l; 26640a6238aSAlexander Graf s->io_buffer_size += l; 26740a6238aSAlexander Graf } 26840a6238aSAlexander Graf } 269c1a6ae51SPeter Maydell return s->sg.size; 27040a6238aSAlexander Graf } 27140a6238aSAlexander Graf 27240a6238aSAlexander Graf /* return 0 if buffer completed */ 273ae0cebd7SPhilippe Mathieu-Daudé static int bmdma_rw_buf(const IDEDMA *dma, bool is_write) 27440a6238aSAlexander Graf { 27540a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 27640a6238aSAlexander Graf IDEState *s = bmdma_active_if(bm); 277f6c11d56SAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev); 27840a6238aSAlexander Graf struct { 27940a6238aSAlexander Graf uint32_t addr; 28040a6238aSAlexander Graf uint32_t size; 28140a6238aSAlexander Graf } prd; 28240a6238aSAlexander Graf int l, len; 28340a6238aSAlexander Graf 28440a6238aSAlexander Graf for(;;) { 28540a6238aSAlexander Graf l = s->io_buffer_size - s->io_buffer_index; 28640a6238aSAlexander Graf if (l <= 0) 28740a6238aSAlexander Graf break; 28840a6238aSAlexander Graf if (bm->cur_prd_len == 0) { 28940a6238aSAlexander Graf /* end of table (with a fail safe of one page) */ 29040a6238aSAlexander Graf if (bm->cur_prd_last || 29140a6238aSAlexander Graf (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) 29240a6238aSAlexander Graf return 0; 293f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); 29440a6238aSAlexander Graf bm->cur_addr += 8; 29540a6238aSAlexander Graf prd.addr = le32_to_cpu(prd.addr); 29640a6238aSAlexander Graf prd.size = le32_to_cpu(prd.size); 29740a6238aSAlexander Graf len = prd.size & 0xfffe; 29840a6238aSAlexander Graf if (len == 0) 29940a6238aSAlexander Graf len = 0x10000; 30040a6238aSAlexander Graf bm->cur_prd_len = len; 30140a6238aSAlexander Graf bm->cur_prd_addr = prd.addr; 30240a6238aSAlexander Graf bm->cur_prd_last = (prd.size & 0x80000000); 30340a6238aSAlexander Graf } 30440a6238aSAlexander Graf if (l > bm->cur_prd_len) 30540a6238aSAlexander Graf l = bm->cur_prd_len; 30640a6238aSAlexander Graf if (l > 0) { 30740a6238aSAlexander Graf if (is_write) { 308f6c11d56SAndreas Färber pci_dma_write(pci_dev, bm->cur_prd_addr, 30940a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 31040a6238aSAlexander Graf } else { 311f6c11d56SAndreas Färber pci_dma_read(pci_dev, bm->cur_prd_addr, 31240a6238aSAlexander Graf s->io_buffer + s->io_buffer_index, l); 31340a6238aSAlexander Graf } 31440a6238aSAlexander Graf bm->cur_prd_addr += l; 31540a6238aSAlexander Graf bm->cur_prd_len -= l; 31640a6238aSAlexander Graf s->io_buffer_index += l; 31740a6238aSAlexander Graf } 31840a6238aSAlexander Graf } 31940a6238aSAlexander Graf return 1; 32040a6238aSAlexander Graf } 32140a6238aSAlexander Graf 322ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_set_inactive(const IDEDMA *dma, bool more) 32340a6238aSAlexander Graf { 32440a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 32540a6238aSAlexander Graf 32640a6238aSAlexander Graf bm->dma_cb = NULL; 3270e7ce54cSPaolo Bonzini if (more) { 3280e7ce54cSPaolo Bonzini bm->status |= BM_STATUS_DMAING; 3290e7ce54cSPaolo Bonzini } else { 3300e7ce54cSPaolo Bonzini bm->status &= ~BM_STATUS_DMAING; 3310e7ce54cSPaolo Bonzini } 33240a6238aSAlexander Graf } 33340a6238aSAlexander Graf 334ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_restart_dma(const IDEDMA *dma) 33540a6238aSAlexander Graf { 33640a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 33740a6238aSAlexander Graf 33806b95b1eSPaolo Bonzini bm->cur_addr = bm->addr; 33940a6238aSAlexander Graf } 34040a6238aSAlexander Graf 34140a6238aSAlexander Graf static void bmdma_cancel(BMDMAState *bm) 34240a6238aSAlexander Graf { 34340a6238aSAlexander Graf if (bm->status & BM_STATUS_DMAING) { 34440a6238aSAlexander Graf /* cancel DMA request */ 3450e7ce54cSPaolo Bonzini bmdma_set_inactive(&bm->dma, false); 34640a6238aSAlexander Graf } 34740a6238aSAlexander Graf } 34840a6238aSAlexander Graf 349ae0cebd7SPhilippe Mathieu-Daudé static void bmdma_reset(const IDEDMA *dma) 35040a6238aSAlexander Graf { 35140a6238aSAlexander Graf BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); 35240a6238aSAlexander Graf 3533eee2611SJohn Snow trace_bmdma_reset(); 35440a6238aSAlexander Graf bmdma_cancel(bm); 35540a6238aSAlexander Graf bm->cmd = 0; 35640a6238aSAlexander Graf bm->status = 0; 35740a6238aSAlexander Graf bm->addr = 0; 35840a6238aSAlexander Graf bm->cur_addr = 0; 35940a6238aSAlexander Graf bm->cur_prd_last = 0; 36040a6238aSAlexander Graf bm->cur_prd_addr = 0; 36140a6238aSAlexander Graf bm->cur_prd_len = 0; 36240a6238aSAlexander Graf } 36340a6238aSAlexander Graf 36440a6238aSAlexander Graf static void bmdma_irq(void *opaque, int n, int level) 36540a6238aSAlexander Graf { 36640a6238aSAlexander Graf BMDMAState *bm = opaque; 36740a6238aSAlexander Graf 36840a6238aSAlexander Graf if (!level) { 36940a6238aSAlexander Graf /* pass through lower */ 37040a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 37140a6238aSAlexander Graf return; 37240a6238aSAlexander Graf } 37340a6238aSAlexander Graf 37440a6238aSAlexander Graf bm->status |= BM_STATUS_INT; 37540a6238aSAlexander Graf 37640a6238aSAlexander Graf /* trigger the real irq */ 37740a6238aSAlexander Graf qemu_set_irq(bm->irq, level); 37840a6238aSAlexander Graf } 37940a6238aSAlexander Graf 380a9deb8c6SAvi Kivity void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) 381977e1244SGerd Hoffmann { 3823eee2611SJohn Snow trace_bmdma_cmd_writeb(val); 383c29947bbSKevin Wolf 384c29947bbSKevin Wolf /* Ignore writes to SSBM if it keeps the old value */ 385c29947bbSKevin Wolf if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { 386977e1244SGerd Hoffmann if (!(val & BM_CMD_START)) { 3872c50207fSPhilippe Mathieu-Daudé ide_cancel_dma_sync(ide_bus_active_if(bm->bus)); 388b39f9612SKevin Wolf bm->status &= ~BM_STATUS_DMAING; 389977e1244SGerd Hoffmann } else { 390b76876e6SKevin Wolf bm->cur_addr = bm->addr; 391977e1244SGerd Hoffmann if (!(bm->status & BM_STATUS_DMAING)) { 392977e1244SGerd Hoffmann bm->status |= BM_STATUS_DMAING; 393977e1244SGerd Hoffmann /* start dma transfer if possible */ 394977e1244SGerd Hoffmann if (bm->dma_cb) 39540a6238aSAlexander Graf bm->dma_cb(bmdma_active_if(bm), 0); 396977e1244SGerd Hoffmann } 397977e1244SGerd Hoffmann } 398977e1244SGerd Hoffmann } 399977e1244SGerd Hoffmann 400c29947bbSKevin Wolf bm->cmd = val & 0x09; 401c29947bbSKevin Wolf } 402c29947bbSKevin Wolf 4035fe24213SBernhard Beschow void bmdma_status_writeb(BMDMAState *bm, uint32_t val) 4045fe24213SBernhard Beschow { 40517d6a4a3SBernhard Beschow bm->status = (val & 0x60) | (bm->status & BM_STATUS_DMAING) 40617d6a4a3SBernhard Beschow | (bm->status & ~val & (BM_STATUS_ERROR | BM_STATUS_INT)); 4075fe24213SBernhard Beschow } 4085fe24213SBernhard Beschow 409a8170e5eSAvi Kivity static uint64_t bmdma_addr_read(void *opaque, hwaddr addr, 410a9deb8c6SAvi Kivity unsigned width) 411977e1244SGerd Hoffmann { 412a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 4139fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 414a9deb8c6SAvi Kivity uint64_t data; 4159fbef1acSAvi Kivity 416a9deb8c6SAvi Kivity data = (bm->addr >> (addr * 8)) & mask; 4173eee2611SJohn Snow trace_bmdma_addr_read(data); 418a9deb8c6SAvi Kivity return data; 419977e1244SGerd Hoffmann } 420977e1244SGerd Hoffmann 421a8170e5eSAvi Kivity static void bmdma_addr_write(void *opaque, hwaddr addr, 422a9deb8c6SAvi Kivity uint64_t data, unsigned width) 423977e1244SGerd Hoffmann { 424a9deb8c6SAvi Kivity BMDMAState *bm = opaque; 4259fbef1acSAvi Kivity int shift = addr * 8; 4269fbef1acSAvi Kivity uint32_t mask = (1ULL << (width * 8)) - 1; 4279fbef1acSAvi Kivity 4283eee2611SJohn Snow trace_bmdma_addr_write(data); 4299fbef1acSAvi Kivity bm->addr &= ~(mask << shift); 4309fbef1acSAvi Kivity bm->addr |= ((data & mask) << shift) & ~3; 431977e1244SGerd Hoffmann } 432977e1244SGerd Hoffmann 433a9deb8c6SAvi Kivity MemoryRegionOps bmdma_addr_ioport_ops = { 4349fbef1acSAvi Kivity .read = bmdma_addr_read, 4359fbef1acSAvi Kivity .write = bmdma_addr_write, 436a9deb8c6SAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 4379fbef1acSAvi Kivity }; 438977e1244SGerd Hoffmann 4395ee84c33SJuan Quintela static bool ide_bmdma_current_needed(void *opaque) 4405ee84c33SJuan Quintela { 4415ee84c33SJuan Quintela BMDMAState *bm = opaque; 4425ee84c33SJuan Quintela 4435ee84c33SJuan Quintela return (bm->cur_prd_len != 0); 4445ee84c33SJuan Quintela } 4455ee84c33SJuan Quintela 446def93791SKevin Wolf static bool ide_bmdma_status_needed(void *opaque) 447def93791SKevin Wolf { 448def93791SKevin Wolf BMDMAState *bm = opaque; 449def93791SKevin Wolf 450def93791SKevin Wolf /* Older versions abused some bits in the status register for internal 451def93791SKevin Wolf * error state. If any of these bits are set, we must add a subsection to 452def93791SKevin Wolf * transfer the real status register */ 453def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 454def93791SKevin Wolf 455def93791SKevin Wolf return ((bm->status & abused_bits) != 0); 456def93791SKevin Wolf } 457def93791SKevin Wolf 45844b1ff31SDr. David Alan Gilbert static int ide_bmdma_pre_save(void *opaque) 459def93791SKevin Wolf { 460def93791SKevin Wolf BMDMAState *bm = opaque; 461def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 462def93791SKevin Wolf 463218fd37cSPavel Butsykin if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) { 464218fd37cSPavel Butsykin bm->bus->error_status = 465218fd37cSPavel Butsykin ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd); 466218fd37cSPavel Butsykin } 467a96cb236SPaolo Bonzini bm->migration_retry_unit = bm->bus->retry_unit; 468dc5d0af4SPaolo Bonzini bm->migration_retry_sector_num = bm->bus->retry_sector_num; 469dc5d0af4SPaolo Bonzini bm->migration_retry_nsector = bm->bus->retry_nsector; 470def93791SKevin Wolf bm->migration_compat_status = 471def93791SKevin Wolf (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits); 47244b1ff31SDr. David Alan Gilbert 47344b1ff31SDr. David Alan Gilbert return 0; 474def93791SKevin Wolf } 475def93791SKevin Wolf 476def93791SKevin Wolf /* This function accesses bm->bus->error_status which is loaded only after 477def93791SKevin Wolf * BMDMA itself. This is why the function is called from ide_pci_post_load 478def93791SKevin Wolf * instead of being registered with VMState where it would run too early. */ 479def93791SKevin Wolf static int ide_bmdma_post_load(void *opaque, int version_id) 480def93791SKevin Wolf { 481def93791SKevin Wolf BMDMAState *bm = opaque; 482def93791SKevin Wolf uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; 483def93791SKevin Wolf 484def93791SKevin Wolf if (bm->status == 0) { 485def93791SKevin Wolf bm->status = bm->migration_compat_status & ~abused_bits; 486def93791SKevin Wolf bm->bus->error_status |= bm->migration_compat_status & abused_bits; 487def93791SKevin Wolf } 488a96cb236SPaolo Bonzini if (bm->bus->error_status) { 489dc5d0af4SPaolo Bonzini bm->bus->retry_sector_num = bm->migration_retry_sector_num; 490dc5d0af4SPaolo Bonzini bm->bus->retry_nsector = bm->migration_retry_nsector; 491a96cb236SPaolo Bonzini bm->bus->retry_unit = bm->migration_retry_unit; 492a96cb236SPaolo Bonzini } 493def93791SKevin Wolf 494def93791SKevin Wolf return 0; 495def93791SKevin Wolf } 496def93791SKevin Wolf 4975ee84c33SJuan Quintela static const VMStateDescription vmstate_bmdma_current = { 4985ee84c33SJuan Quintela .name = "ide bmdma_current", 4995ee84c33SJuan Quintela .version_id = 1, 5005ee84c33SJuan Quintela .minimum_version_id = 1, 5015cd8cadaSJuan Quintela .needed = ide_bmdma_current_needed, 5028595c054SRichard Henderson .fields = (const VMStateField[]) { 5035ee84c33SJuan Quintela VMSTATE_UINT32(cur_addr, BMDMAState), 5045ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_last, BMDMAState), 5055ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_addr, BMDMAState), 5065ee84c33SJuan Quintela VMSTATE_UINT32(cur_prd_len, BMDMAState), 5075ee84c33SJuan Quintela VMSTATE_END_OF_LIST() 5085ee84c33SJuan Quintela } 5095ee84c33SJuan Quintela }; 5105ee84c33SJuan Quintela 51106ab66cfSStefan Weil static const VMStateDescription vmstate_bmdma_status = { 512def93791SKevin Wolf .name ="ide bmdma/status", 513def93791SKevin Wolf .version_id = 1, 514def93791SKevin Wolf .minimum_version_id = 1, 5155cd8cadaSJuan Quintela .needed = ide_bmdma_status_needed, 5168595c054SRichard Henderson .fields = (const VMStateField[]) { 517def93791SKevin Wolf VMSTATE_UINT8(status, BMDMAState), 518def93791SKevin Wolf VMSTATE_END_OF_LIST() 519def93791SKevin Wolf } 520def93791SKevin Wolf }; 5215ee84c33SJuan Quintela 522407a4f30SJuan Quintela static const VMStateDescription vmstate_bmdma = { 523407a4f30SJuan Quintela .name = "ide bmdma", 52457338424SJuan Quintela .version_id = 3, 525407a4f30SJuan Quintela .minimum_version_id = 0, 526def93791SKevin Wolf .pre_save = ide_bmdma_pre_save, 5278595c054SRichard Henderson .fields = (const VMStateField[]) { 528407a4f30SJuan Quintela VMSTATE_UINT8(cmd, BMDMAState), 529def93791SKevin Wolf VMSTATE_UINT8(migration_compat_status, BMDMAState), 530407a4f30SJuan Quintela VMSTATE_UINT32(addr, BMDMAState), 531dc5d0af4SPaolo Bonzini VMSTATE_INT64(migration_retry_sector_num, BMDMAState), 532dc5d0af4SPaolo Bonzini VMSTATE_UINT32(migration_retry_nsector, BMDMAState), 533a96cb236SPaolo Bonzini VMSTATE_UINT8(migration_retry_unit, BMDMAState), 534407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 5355ee84c33SJuan Quintela }, 5368595c054SRichard Henderson .subsections = (const VMStateDescription * const []) { 5375cd8cadaSJuan Quintela &vmstate_bmdma_current, 5385cd8cadaSJuan Quintela &vmstate_bmdma_status, 5395cd8cadaSJuan Quintela NULL 540407a4f30SJuan Quintela } 541407a4f30SJuan Quintela }; 542407a4f30SJuan Quintela 543407a4f30SJuan Quintela static int ide_pci_post_load(void *opaque, int version_id) 544977e1244SGerd Hoffmann { 545977e1244SGerd Hoffmann PCIIDEState *d = opaque; 546977e1244SGerd Hoffmann int i; 547977e1244SGerd Hoffmann 548977e1244SGerd Hoffmann for(i = 0; i < 2; i++) { 549407a4f30SJuan Quintela /* current versions always store 0/1, but older version 550407a4f30SJuan Quintela stored bigger values. We only need last bit */ 551a96cb236SPaolo Bonzini d->bmdma[i].migration_retry_unit &= 1; 552def93791SKevin Wolf ide_bmdma_post_load(&d->bmdma[i], -1); 553977e1244SGerd Hoffmann } 554def93791SKevin Wolf 555977e1244SGerd Hoffmann return 0; 556977e1244SGerd Hoffmann } 557977e1244SGerd Hoffmann 558407a4f30SJuan Quintela const VMStateDescription vmstate_ide_pci = { 559407a4f30SJuan Quintela .name = "ide", 56057338424SJuan Quintela .version_id = 3, 561407a4f30SJuan Quintela .minimum_version_id = 0, 562407a4f30SJuan Quintela .post_load = ide_pci_post_load, 5638595c054SRichard Henderson .fields = (const VMStateField[]) { 564f6c11d56SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PCIIDEState), 565407a4f30SJuan Quintela VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, 566407a4f30SJuan Quintela vmstate_bmdma, BMDMAState), 567407a4f30SJuan Quintela VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2), 568407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState), 569407a4f30SJuan Quintela VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState), 570407a4f30SJuan Quintela VMSTATE_END_OF_LIST() 571407a4f30SJuan Quintela } 572407a4f30SJuan Quintela }; 573407a4f30SJuan Quintela 574df45d38fSBALATON Zoltan /* hd_table must contain 4 block drivers */ 575be1765f3SBALATON Zoltan void pci_ide_create_devs(PCIDevice *dev) 576feef3102SGerd Hoffmann { 577f6c11d56SAndreas Färber PCIIDEState *d = PCI_IDE(dev); 578be1765f3SBALATON Zoltan DriveInfo *hd_table[2 * MAX_IDE_DEVS]; 579feef3102SGerd Hoffmann static const int bus[4] = { 0, 0, 1, 1 }; 580feef3102SGerd Hoffmann static const int unit[4] = { 0, 1, 0, 1 }; 581feef3102SGerd Hoffmann int i; 582feef3102SGerd Hoffmann 583be1765f3SBALATON Zoltan ide_drive_get(hd_table, ARRAY_SIZE(hd_table)); 584feef3102SGerd Hoffmann for (i = 0; i < 4; i++) { 585417adc2dSBALATON Zoltan if (hd_table[i]) { 586b6a5ab27SPhilippe Mathieu-Daudé ide_bus_create_drive(d->bus + bus[i], unit[i], hd_table[i]); 587feef3102SGerd Hoffmann } 588feef3102SGerd Hoffmann } 589417adc2dSBALATON Zoltan } 59040a6238aSAlexander Graf 59140a6238aSAlexander Graf static const struct IDEDMAOps bmdma_ops = { 59240a6238aSAlexander Graf .start_dma = bmdma_start_dma, 59340a6238aSAlexander Graf .prepare_buf = bmdma_prepare_buf, 59440a6238aSAlexander Graf .rw_buf = bmdma_rw_buf, 595bd8892c4SPaolo Bonzini .restart_dma = bmdma_restart_dma, 59640a6238aSAlexander Graf .set_inactive = bmdma_set_inactive, 59740a6238aSAlexander Graf .reset = bmdma_reset, 59840a6238aSAlexander Graf }; 59940a6238aSAlexander Graf 600a9deb8c6SAvi Kivity void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d) 60140a6238aSAlexander Graf { 60240a6238aSAlexander Graf if (bus->dma == &bm->dma) { 60340a6238aSAlexander Graf return; 60440a6238aSAlexander Graf } 60540a6238aSAlexander Graf 60640a6238aSAlexander Graf bm->dma.ops = &bmdma_ops; 60740a6238aSAlexander Graf bus->dma = &bm->dma; 60840a6238aSAlexander Graf bm->irq = bus->irq; 6096e38a4baSShannon Zhao bus->irq = qemu_allocate_irq(bmdma_irq, bm, 0); 610bf0576edSBernhard Beschow bm->bus = bus; 611a9deb8c6SAvi Kivity bm->pci_dev = d; 61240a6238aSAlexander Graf } 613f6c11d56SAndreas Färber 614e2b84ee4SBernhard Beschow static void pci_ide_init(Object *obj) 615e2b84ee4SBernhard Beschow { 616e2b84ee4SBernhard Beschow PCIIDEState *d = PCI_IDE(obj); 617e2b84ee4SBernhard Beschow 618e2b84ee4SBernhard Beschow qdev_init_gpio_out_named(DEVICE(d), d->isa_irq, "isa-irq", 619e2b84ee4SBernhard Beschow ARRAY_SIZE(d->isa_irq)); 620e2b84ee4SBernhard Beschow } 621e2b84ee4SBernhard Beschow 622f6c11d56SAndreas Färber static const TypeInfo pci_ide_type_info = { 623f6c11d56SAndreas Färber .name = TYPE_PCI_IDE, 624f6c11d56SAndreas Färber .parent = TYPE_PCI_DEVICE, 625f6c11d56SAndreas Färber .instance_size = sizeof(PCIIDEState), 626e2b84ee4SBernhard Beschow .instance_init = pci_ide_init, 627f6c11d56SAndreas Färber .abstract = true, 628fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) { 629fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 630fd3b02c8SEduardo Habkost { }, 631fd3b02c8SEduardo Habkost }, 632f6c11d56SAndreas Färber }; 633f6c11d56SAndreas Färber 634f6c11d56SAndreas Färber static void pci_ide_register_types(void) 635f6c11d56SAndreas Färber { 636f6c11d56SAndreas Färber type_register_static(&pci_ide_type_info); 637f6c11d56SAndreas Färber } 638f6c11d56SAndreas Färber 639f6c11d56SAndreas Färber type_init(pci_ide_register_types) 640