--- qemu/hw/ide/cmd646.c 2018/04/24 18:13:30 1.1.1.2 +++ qemu/hw/ide/cmd646.c 2018/04/24 19:50:58 1.1.1.7 @@ -27,7 +27,6 @@ #include #include #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" @@ -44,41 +43,95 @@ static void cmd646_update_irq(PCIIDEState *d); -static void ide_map(PCIDevice *pci_dev, int region_num, - pcibus_t addr, pcibus_t size, int type) +static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr, + unsigned size) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev); - IDEBus *bus; + CMD646BAR *cmd646bar = opaque; - if (region_num <= 3) { - bus = &d->bus[(region_num >> 1)]; - if (region_num & 1) { - register_ioport_read(addr + 2, 1, 1, ide_status_read, bus); - register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus); + if (addr != 2 || size != 1) { + return ((uint64_t)1 << (size * 8)) - 1; + } + return ide_status_read(cmd646bar->bus, addr + 2); +} + +static void cmd646_cmd_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + CMD646BAR *cmd646bar = opaque; + + if (addr != 2 || size != 1) { + return; + } + ide_cmd_write(cmd646bar->bus, addr + 2, data); +} + +static const MemoryRegionOps cmd646_cmd_ops = { + .read = cmd646_cmd_read, + .write = cmd646_cmd_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + CMD646BAR *cmd646bar = opaque; + + if (size == 1) { + return ide_ioport_read(cmd646bar->bus, addr); + } else if (addr == 0) { + if (size == 2) { + return ide_data_readw(cmd646bar->bus, addr); } else { - register_ioport_write(addr, 8, 1, ide_ioport_write, bus); - register_ioport_read(addr, 8, 1, ide_ioport_read, bus); + return ide_data_readl(cmd646bar->bus, addr); + } + } + return ((uint64_t)1 << (size * 8)) - 1; +} + +static void cmd646_data_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + CMD646BAR *cmd646bar = opaque; - /* data ports */ - register_ioport_write(addr, 2, 2, ide_data_writew, bus); - register_ioport_read(addr, 2, 2, ide_data_readw, bus); - register_ioport_write(addr, 4, 4, ide_data_writel, bus); - register_ioport_read(addr, 4, 4, ide_data_readl, bus); + if (size == 1) { + return ide_ioport_write(cmd646bar->bus, addr, data); + } else if (addr == 0) { + if (size == 2) { + return ide_data_writew(cmd646bar->bus, addr, data); + } else { + return ide_data_writel(cmd646bar->bus, addr, data); } } } -static PCIIDEState *pci_from_bm(BMDMAState *bm) +static const MemoryRegionOps cmd646_data_ops = { + .read = cmd646_data_read, + .write = cmd646_data_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void setup_cmd646_bar(PCIIDEState *d, int bus_num) { - return bm->pci_dev; + IDEBus *bus = &d->bus[bus_num]; + CMD646BAR *bar = &d->cmd646_bar[bus_num]; + + bar->bus = bus; + bar->pci_dev = d; + memory_region_init_io(&bar->cmd, &cmd646_cmd_ops, bar, "cmd646-cmd", 4); + memory_region_init_io(&bar->data, &cmd646_data_ops, bar, "cmd646-data", 8); } -static uint32_t bmdma_readb(void *opaque, uint32_t addr) +static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, + unsigned size) { BMDMAState *bm = opaque; - PCIIDEState *pci_dev = pci_from_bm(bm); + PCIIDEState *pci_dev = bm->pci_dev; uint32_t val; + if (size != 1) { + return ((uint64_t)1 << (size * 8)) - 1; + } + switch(addr & 3) { case 0: val = bm->cmd; @@ -90,7 +143,7 @@ static uint32_t bmdma_readb(void *opaque val = bm->status; break; case 3: - if (bm->unit == 0) { + if (bm == &pci_dev->bmdma[0]) { val = pci_dev->dev.config[UDIDETCR0]; } else { val = pci_dev->dev.config[UDIDETCR1]; @@ -106,14 +159,23 @@ static uint32_t bmdma_readb(void *opaque return val; } -static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) +static void bmdma_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned size) { BMDMAState *bm = opaque; - PCIIDEState *pci_dev = pci_from_bm(bm); + PCIIDEState *pci_dev = bm->pci_dev; + + if (size != 1) { + return; + } + #ifdef DEBUG_IDE printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); #endif switch(addr & 3) { + case 0: + bmdma_cmd_writeb(bm, val); + break; case 1: pci_dev->dev.config[MRDMODE] = (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); @@ -123,7 +185,7 @@ static void bmdma_writeb(void *opaque, u bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); break; case 3: - if (bm->unit == 0) + if (bm == &pci_dev->bmdma[0]) pci_dev->dev.config[UDIDETCR0] = val; else pci_dev->dev.config[UDIDETCR1] = val; @@ -131,31 +193,25 @@ static void bmdma_writeb(void *opaque, u } } -static void bmdma_map(PCIDevice *pci_dev, int region_num, - pcibus_t addr, pcibus_t size, int type) +static const MemoryRegionOps cmd646_bmdma_ops = { + .read = bmdma_read, + .write = bmdma_write, +}; + +static void bmdma_setup_bar(PCIIDEState *d) { - PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev); + BMDMAState *bm; int i; + memory_region_init(&d->bmdma_bar, "cmd646-bmdma", 16); for(i = 0;i < 2; i++) { - BMDMAState *bm = &d->bmdma[i]; - d->bus[i].bmdma = bm; - bm->bus = d->bus+i; - bm->pci_dev = d; - qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); - - register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); - - register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); - register_ioport_read(addr, 4, 1, bmdma_readb, bm); - - register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); - register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); - register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); - register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); - register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); - register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); - addr += 8; + bm = &d->bmdma[i]; + memory_region_init_io(&bm->extra_io, &cmd646_bmdma_ops, bm, + "cmd646-bmdma-bus", 4); + memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io); + memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm, + "cmd646-bmdma-ioport", 4); + memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport); } } @@ -192,7 +248,6 @@ static void cmd646_reset(void *opaque) for (i = 0; i < 2; i++) { ide_bus_reset(&d->bus[i]); - ide_dma_reset(&d->bmdma[i]); } } @@ -202,15 +257,9 @@ static int pci_cmd646_ide_initfn(PCIDevi PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); uint8_t *pci_conf = d->dev.config; qemu_irq *irq; + int i; - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646); - - pci_conf[0x08] = 0x07; // IDE controller revision - pci_conf[0x09] = 0x8f; - - pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE); - pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type + pci_conf[PCI_CLASS_PROG] = 0x8f; pci_conf[0x51] = 0x04; // enable IDE0 if (d->secondary) { @@ -218,25 +267,52 @@ static int pci_cmd646_ide_initfn(PCIDevi pci_conf[0x51] |= 0x08; /* enable IDE1 */ } - pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map); - pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map); - pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map); - pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map); - pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map); + setup_cmd646_bar(d, 0); + setup_cmd646_bar(d, 1); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data); + pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].cmd); + pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].data); + pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].cmd); + bmdma_setup_bar(d); + pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar); - pci_conf[0x3d] = 0x01; // interrupt on pin 1 + /* TODO: RST# value should be 0 */ + pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1 irq = qemu_allocate_irqs(cmd646_set_irq, d, 2); - ide_bus_new(&d->bus[0], &d->dev.qdev); - ide_bus_new(&d->bus[1], &d->dev.qdev); - ide_init2(&d->bus[0], NULL, NULL, irq[0]); - ide_init2(&d->bus[1], NULL, NULL, irq[1]); + for (i = 0; i < 2; i++) { + ide_bus_new(&d->bus[i], &d->dev.qdev, i); + ide_init2(&d->bus[i], irq[i]); + + bmdma_init(&d->bus[i], &d->bmdma[i], d); + d->bmdma[i].bus = &d->bus[i]; + qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb, + &d->bmdma[i].dma); + } - vmstate_register(0, &vmstate_ide_pci, d); + vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d); qemu_register_reset(cmd646_reset, d); return 0; } +static int pci_cmd646_ide_exitfn(PCIDevice *dev) +{ + PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); + unsigned i; + + for (i = 0; i < 2; ++i) { + memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io); + memory_region_destroy(&d->bmdma[i].extra_io); + memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport); + memory_region_destroy(&d->bmdma[i].addr_ioport); + memory_region_destroy(&d->cmd646_bar[i].cmd); + memory_region_destroy(&d->cmd646_bar[i].data); + } + memory_region_destroy(&d->bmdma_bar); + + return 0; +} + void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table, int secondary_ide_enabled) { @@ -249,22 +325,35 @@ void pci_cmd646_ide_init(PCIBus *bus, Dr pci_ide_create_devs(dev, hd_table); } -static PCIDeviceInfo cmd646_ide_info[] = { - { - .qdev.name = "cmd646-ide", - .qdev.size = sizeof(PCIIDEState), - .init = pci_cmd646_ide_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0), - DEFINE_PROP_END_OF_LIST(), - }, - },{ - /* end of list */ - } +static Property cmd646_ide_properties[] = { + DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void cmd646_ide_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_cmd646_ide_initfn; + k->exit = pci_cmd646_ide_exitfn; + k->vendor_id = PCI_VENDOR_ID_CMD; + k->device_id = PCI_DEVICE_ID_CMD_646; + k->revision = 0x07; + k->class_id = PCI_CLASS_STORAGE_IDE; + dc->props = cmd646_ide_properties; +} + +static TypeInfo cmd646_ide_info = { + .name = "cmd646-ide", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .class_init = cmd646_ide_class_init, }; -static void cmd646_ide_register(void) +static void cmd646_ide_register_types(void) { - pci_qdev_register_many(cmd646_ide_info); + type_register_static(&cmd646_ide_info); } -device_init(cmd646_ide_register); + +type_init(cmd646_ide_register_types)