diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/apb_pci.c | 80 | ||||
-rw-r--r-- | hw/ide/core.c | 62 | ||||
-rw-r--r-- | hw/ide/internal.h | 5 | ||||
-rw-r--r-- | hw/mac_dbdma.c | 10 | ||||
-rw-r--r-- | hw/pc.c | 73 | ||||
-rw-r--r-- | hw/pc.h | 10 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 30 | ||||
-rw-r--r-- | hw/pci.h | 1 | ||||
-rw-r--r-- | hw/pci_host.c | 172 | ||||
-rw-r--r-- | hw/pci_host.h | 4 | ||||
-rw-r--r-- | hw/pci_host_template.h | 109 | ||||
-rw-r--r-- | hw/pci_ids.h | 1 | ||||
-rw-r--r-- | hw/pl181.c | 29 | ||||
-rw-r--r-- | hw/ppc.h | 2 | ||||
-rw-r--r-- | hw/ppc_mac.h | 1 | ||||
-rw-r--r-- | hw/ppc_newworld.c | 73 | ||||
-rw-r--r-- | hw/ppc_oldworld.c | 9 | ||||
-rw-r--r-- | hw/qdev.c | 7 | ||||
-rw-r--r-- | hw/serial.c | 28 | ||||
-rw-r--r-- | hw/unin_pci.c | 151 | ||||
-rw-r--r-- | hw/usb-hid.c | 12 | ||||
-rw-r--r-- | hw/versatile_pci.c | 10 | ||||
-rw-r--r-- | hw/virtio-pci.c | 6 | ||||
-rw-r--r-- | hw/virtio-serial-bus.c | 6 |
24 files changed, 546 insertions, 345 deletions
diff --git a/hw/apb_pci.c b/hw/apb_pci.c index ebfcd4153f..324e74eec4 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -29,6 +29,7 @@ #include "sysbus.h" #include "pci.h" #include "pci_host.h" +#include "rwhandler.h" #include "apb_pci.h" /* debug APB */ @@ -65,6 +66,7 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0) typedef struct APBState { SysBusDevice busdev; PCIHostState host_state; + ReadWriteHandler pci_config_handler; uint32_t iommu[4]; uint32_t pci_control[16]; uint32_t pci_irq_map[8]; @@ -183,82 +185,28 @@ static CPUReadMemoryFunc * const apb_config_read[] = { &apb_config_readl, }; -static void apb_pci_config_write(APBState *s, target_phys_addr_t addr, +static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr, uint32_t val, int size) { + APBState *s = container_of(h, APBState, pci_config_handler); + + val = qemu_bswap_len(val, size); APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val); - pci_data_write(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31), val, - size); + pci_data_write(s->host_state.bus, addr, val, size); } -static uint32_t apb_pci_config_read(APBState *s, target_phys_addr_t addr, +static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr, int size) { uint32_t ret; + APBState *s = container_of(h, APBState, pci_config_handler); - ret = pci_data_read(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31), - size); + ret = pci_data_read(s->host_state.bus, addr, size); + ret = qemu_bswap_len(ret, size); APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret); return ret; } -static void apb_pci_config_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - APBState *s = opaque; - - apb_pci_config_write(s, addr, bswap32(val), 4); -} - -static void apb_pci_config_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - APBState *s = opaque; - - apb_pci_config_write(s, addr, bswap16(val), 2); -} - -static void apb_pci_config_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - APBState *s = opaque; - - apb_pci_config_write(s, addr, val, 1); -} - -static uint32_t apb_pci_config_readl(void *opaque, target_phys_addr_t addr) -{ - APBState *s = opaque; - - return bswap32(apb_pci_config_read(s, addr, 4)); -} - -static uint32_t apb_pci_config_readw(void *opaque, target_phys_addr_t addr) -{ - APBState *s = opaque; - - return bswap16(apb_pci_config_read(s, addr, 2)); -} - -static uint32_t apb_pci_config_readb(void *opaque, target_phys_addr_t addr) -{ - APBState *s = opaque; - - return apb_pci_config_read(s, addr, 1); -} - -static CPUWriteMemoryFunc * const apb_pci_config_writes[] = { - &apb_pci_config_writeb, - &apb_pci_config_writew, - &apb_pci_config_writel, -}; - -static CPUReadMemoryFunc * const apb_pci_config_reads[] = { - &apb_pci_config_readb, - &apb_pci_config_readw, - &apb_pci_config_readl, -}; - static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, uint32_t val) { @@ -455,8 +403,10 @@ static int pci_pbm_init_device(SysBusDevice *dev) pci_apb_iowrite, s); sysbus_init_mmio(dev, 0x10000ULL, pci_ioport); /* pci_config */ - pci_config = cpu_register_io_memory(apb_pci_config_reads, - apb_pci_config_writes, s); + s->pci_config_handler.read = apb_pci_config_read; + s->pci_config_handler.write = apb_pci_config_write; + pci_config = cpu_register_io_memory_simple(&s->pci_config_handler); + assert(pci_config >= 0); sysbus_init_mmio(dev, 0x1000000ULL, pci_config); /* mem_data */ pci_mem_data = pci_host_data_register_mmio(&s->host_state); diff --git a/hw/ide/core.c b/hw/ide/core.c index 37a5151570..2e0971ddeb 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2650,6 +2650,7 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1, s->unit = i; s->drive_serial = drive_serial++; s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4); + s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4; s->smart_selftest_data = qemu_blockalign(s->bs, 512); s->sector_write_timer = qemu_new_timer(vm_clock, ide_sector_write_timer_cb, s); @@ -2684,6 +2685,25 @@ static bool is_identify_set(void *opaque, int version_id) return s->identify_set != 0; } +static EndTransferFunc* transfer_end_table[] = { + ide_sector_read, + ide_sector_write, + ide_transfer_stop, + ide_atapi_cmd_reply_end, + ide_atapi_cmd, +}; + +static int transfer_end_table_idx(EndTransferFunc *fn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++) + if (transfer_end_table[i] == fn) + return i; + + return -1; +} + static int ide_drive_post_load(void *opaque, int version_id) { IDEState *s = opaque; @@ -2694,14 +2714,45 @@ static int ide_drive_post_load(void *opaque, int version_id) s->cdrom_changed = 1; } } + + if (s->cur_io_buffer_len) { + s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx]; + s->data_ptr = s->io_buffer + s->cur_io_buffer_offset; + s->data_end = s->data_ptr + s->cur_io_buffer_len; + } + return 0; } +static void ide_drive_pre_save(void *opaque) +{ + IDEState *s = opaque; + int idx; + + s->cur_io_buffer_len = 0; + + if (!(s->status & DRQ_STAT)) + return; + + s->cur_io_buffer_offset = s->data_ptr - s->io_buffer; + s->cur_io_buffer_len = s->data_end - s->data_ptr; + + idx = transfer_end_table_idx(s->end_transfer_func); + if (idx == -1) { + fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n", + __func__); + s->end_transfer_fn_idx = 2; + } else { + s->end_transfer_fn_idx = idx; + } +} + const VMStateDescription vmstate_ide_drive = { .name = "ide_drive", - .version_id = 3, + .version_id = 4, .minimum_version_id = 0, .minimum_version_id_old = 0, + .pre_save = ide_drive_pre_save, .post_load = ide_drive_post_load, .fields = (VMStateField []) { VMSTATE_INT32(mult_sectors, IDEState), @@ -2724,7 +2775,14 @@ const VMStateDescription vmstate_ide_drive = { VMSTATE_UINT8(sense_key, IDEState), VMSTATE_UINT8(asc, IDEState), VMSTATE_UINT8_V(cdrom_changed, IDEState, 3), - /* XXX: if a transfer is pending, we do not save it yet */ + VMSTATE_INT32_V(req_nb_sectors, IDEState, 4), + VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4, + vmstate_info_uint8, uint8_t), + VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4), + VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4), + VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4), + VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4), + VMSTATE_INT32_V(packet_transfer_size, IDEState, 4), VMSTATE_END_OF_LIST() } }; diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 9945993655..027029ecec 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -419,6 +419,11 @@ struct IDEState { uint8_t *data_ptr; uint8_t *data_end; uint8_t *io_buffer; + /* PIO save/restore */ + int32_t io_buffer_total_len; + int cur_io_buffer_offset; + int cur_io_buffer_len; + uint8_t end_transfer_fn_idx; QEMUTimer *sector_write_timer; /* only used for win2k install hack */ uint32_t irq_count; /* counts IRQs when using win2k install hack */ /* CF-ATA extended error */ diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 8ec3d99314..8f94c35ac3 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -402,7 +402,9 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr, ch->io.dma_end = dbdma_end; ch->io.is_dma_out = 1; ch->processing = 1; - ch->rw(&ch->io); + if (ch->rw) { + ch->rw(&ch->io); + } } static void start_input(DBDMA_channel *ch, int key, uint32_t addr, @@ -425,7 +427,9 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr, ch->io.dma_end = dbdma_end; ch->io.is_dma_out = 0; ch->processing = 1; - ch->rw(&ch->io); + if (ch->rw) { + ch->rw(&ch->io); + } } static void load_word(DBDMA_channel *ch, int key, uint32_t addr, @@ -688,7 +692,7 @@ dbdma_control_write(DBDMA_channel *ch) if (status & ACTIVE) qemu_bh_schedule(dbdma_bh); - if (status & FLUSH) + if ((status & FLUSH) && ch->flush) ch->flush(&ch->io); } @@ -59,6 +59,7 @@ #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) +#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) #define MAX_IDE_BUS 2 @@ -67,6 +68,21 @@ static RTCState *rtc_state; static PITState *pit; static PCII440FXState *i440fx_state; +#define E820_NR_ENTRIES 16 + +struct e820_entry { + uint64_t address; + uint64_t length; + uint32_t type; +}; + +struct e820_table { + uint32_t count; + struct e820_entry entry[E820_NR_ENTRIES]; +}; + +static struct e820_table e820_table; + typedef struct isa_irq_state { qemu_irq *i8259; qemu_irq *ioapic; @@ -435,6 +451,23 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) } } +int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) +{ + int index = e820_table.count; + struct e820_entry *entry; + + if (index >= E820_NR_ENTRIES) + return -EBUSY; + entry = &e820_table.entry[index]; + + entry->address = address; + entry->length = length; + entry->type = type; + + e820_table.count++; + return e820_table.count; +} + static void *bochs_bios_init(void) { void *fw_cfg; @@ -466,6 +499,8 @@ static void *bochs_bios_init(void) if (smbios_table) fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, smbios_table, smbios_len); + fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table, + sizeof(struct e820_table)); /* allocate memory for the NUMA channel: one (64bit) word for the number * of nodes, one word for each VCPU->node and one word for each node to @@ -1052,7 +1087,7 @@ void cmos_set_s3_resume(void) } static QEMUMachine pc_machine = { - .name = "pc-0.12", + .name = "pc-0.13", .alias = "pc", .desc = "Standard PC", .init = pc_init_pci, @@ -1060,6 +1095,25 @@ static QEMUMachine pc_machine = { .is_default = 1, }; +static QEMUMachine pc_machine_v0_12 = { + .name = "pc-0.12", + .desc = "Standard PC", + .init = pc_init_pci, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + { + .driver = "virtio-serial-pci", + .property = "max_nr_ports", + .value = stringify(1), + },{ + .driver = "virtio-serial-pci", + .property = "vectors", + .value = stringify(0), + }, + { /* end of list */ } + } +}; + static QEMUMachine pc_machine_v0_11 = { .name = "pc-0.11", .desc = "Standard PC, qemu 0.11", @@ -1071,6 +1125,14 @@ static QEMUMachine pc_machine_v0_11 = { .property = "vectors", .value = stringify(0), },{ + .driver = "virtio-serial-pci", + .property = "max_nr_ports", + .value = stringify(1), + },{ + .driver = "virtio-serial-pci", + .property = "vectors", + .value = stringify(0), + },{ .driver = "ide-drive", .property = "ver", .value = "0.11", @@ -1102,6 +1164,14 @@ static QEMUMachine pc_machine_v0_10 = { .property = "class", .value = stringify(PCI_CLASS_DISPLAY_OTHER), },{ + .driver = "virtio-serial-pci", + .property = "max_nr_ports", + .value = stringify(1), + },{ + .driver = "virtio-serial-pci", + .property = "vectors", + .value = stringify(0), + },{ .driver = "virtio-net-pci", .property = "vectors", .value = stringify(0), @@ -1136,6 +1206,7 @@ static QEMUMachine isapc_machine = { static void pc_machine_init(void) { qemu_register_machine(&pc_machine); + qemu_register_machine(&pc_machine_v0_12); qemu_register_machine(&pc_machine_v0_11); qemu_register_machine(&pc_machine_v0_10); qemu_register_machine(&isapc_machine); @@ -150,4 +150,14 @@ void isa_cirrus_vga_init(void); void isa_ne2000_init(int base, int irq, NICInfo *nd); int cpu_is_bsp(CPUState *env); + +/* e820 types */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +int e820_add_entry(uint64_t, uint64_t, uint32_t); + #endif diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 0fb96f06fd..bd82c6aab7 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -254,7 +254,7 @@ void pci_device_hot_add_print(Monitor *mon, const QObject *data) * * { "domain": 0, "bus": 0, "slot": 5, "function": 0 } */ -void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data) +int pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data) { PCIDevice *dev = NULL; const char *pci_addr = qdict_get_str(qdict, "pci_addr"); @@ -273,43 +273,49 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data) if (!strcmp(pci_addr, "auto")) pci_addr = NULL; - if (strcmp(type, "nic") == 0) + if (strcmp(type, "nic") == 0) { dev = qemu_pci_hot_add_nic(mon, pci_addr, opts); - else if (strcmp(type, "storage") == 0) + } else if (strcmp(type, "storage") == 0) { dev = qemu_pci_hot_add_storage(mon, pci_addr, opts); - else + } else { monitor_printf(mon, "invalid type: %s\n", type); + return -1; + } if (dev) { *ret_data = qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, " "'function': %d }", pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - } else + } else { monitor_printf(mon, "failed to add %s\n", opts); + return -1; + } + + return 0; } #endif -void pci_device_hot_remove(Monitor *mon, const char *pci_addr) +int pci_device_hot_remove(Monitor *mon, const char *pci_addr) { PCIDevice *d; int dom, bus; unsigned slot; if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) { - return; + return -1; } d = pci_find_device(pci_find_root_bus(0), bus, slot, 0); if (!d) { monitor_printf(mon, "slot %d empty\n", slot); - return; + return -1; } - qdev_unplug(&d->qdev); + return qdev_unplug(&d->qdev); } -void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict, - QObject **ret_data) +int do_pci_device_hot_remove(Monitor *mon, const QDict *qdict, + QObject **ret_data) { - pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); + return pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr")); } @@ -70,7 +70,6 @@ #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 -typedef uint64_t pcibus_t; #define FMT_PCIBUS PRIx64 typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, diff --git a/hw/pci_host.c b/hw/pci_host.c index 6289ead3b3..b15d5faef7 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -79,152 +79,120 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) return val; } -static void pci_host_config_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) +static void pci_host_config_write(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_handler); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n", + __func__, addr, len, val); #ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); + val = qemu_bswap_len(val, len); #endif - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); s->config_reg = val; } -static uint32_t pci_host_config_readl(void *opaque, target_phys_addr_t addr) +static uint32_t pci_host_config_read(ReadWriteHandler *handler, + pcibus_t addr, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_handler); uint32_t val = s->config_reg; - #ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); + val = qemu_bswap_len(val, len); #endif - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n", + __func__, addr, len, val); return val; } -static CPUWriteMemoryFunc * const pci_host_config_write[] = { - &pci_host_config_writel, - &pci_host_config_writel, - &pci_host_config_writel, -}; - -static CPUReadMemoryFunc * const pci_host_config_read[] = { - &pci_host_config_readl, - &pci_host_config_readl, - &pci_host_config_readl, -}; - -int pci_host_conf_register_mmio(PCIHostState *s) -{ - return cpu_register_io_memory(pci_host_config_read, - pci_host_config_write, s); -} - -static void pci_host_config_writel_noswap(void *opaque, - target_phys_addr_t addr, - uint32_t val) +static void pci_host_config_write_noswap(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler); - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n", + __func__, addr, len, val); s->config_reg = val; } -static uint32_t pci_host_config_readl_noswap(void *opaque, - target_phys_addr_t addr) +static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler, + pcibus_t addr, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler); uint32_t val = s->config_reg; - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n", + __func__, addr, len, val); return val; } -static CPUWriteMemoryFunc * const pci_host_config_write_noswap[] = { - &pci_host_config_writel_noswap, - &pci_host_config_writel_noswap, - &pci_host_config_writel_noswap, -}; - -static CPUReadMemoryFunc * const pci_host_config_read_noswap[] = { - &pci_host_config_readl_noswap, - &pci_host_config_readl_noswap, - &pci_host_config_readl_noswap, -}; - -int pci_host_conf_register_mmio_noswap(PCIHostState *s) +static void pci_host_data_write(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) { - return cpu_register_io_memory(pci_host_config_read_noswap, - pci_host_config_write_noswap, s); + PCIHostState *s = container_of(handler, PCIHostState, data_handler); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", + addr, len, val); + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); } -static void pci_host_config_writel_ioport(void *opaque, - uint32_t addr, uint32_t val) +static uint32_t pci_host_data_read(ReadWriteHandler *handler, + pcibus_t addr, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, data_handler); + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffffffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); + PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", + addr, len, val); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + return val; +} - PCI_DPRINTF("%s addr %"PRIx32 " val %"PRIx32"\n", __func__, addr, val); - s->config_reg = val; +static void pci_host_init(PCIHostState *s) +{ + s->conf_handler.write = pci_host_config_write; + s->conf_handler.read = pci_host_config_read; + s->conf_noswap_handler.write = pci_host_config_write_noswap; + s->conf_noswap_handler.read = pci_host_config_read_noswap; + s->data_handler.write = pci_host_data_write; + s->data_handler.read = pci_host_data_read; } -static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr) +int pci_host_conf_register_mmio(PCIHostState *s) { - PCIHostState *s = opaque; - uint32_t val = s->config_reg; + pci_host_init(s); + return cpu_register_io_memory_simple(&s->conf_handler); +} - PCI_DPRINTF("%s addr %"PRIx32" val %"PRIx32"\n", __func__, addr, val); - return val; +int pci_host_conf_register_mmio_noswap(PCIHostState *s) +{ + pci_host_init(s); + return cpu_register_io_memory_simple(&s->conf_noswap_handler); } void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s) { - register_ioport_write(ioport, 4, 4, pci_host_config_writel_ioport, s); - register_ioport_read(ioport, 4, 4, pci_host_config_readl_ioport, s); + pci_host_init(s); + register_ioport_simple(&s->conf_noswap_handler, ioport, 4, 4); } -#define PCI_ADDR_T target_phys_addr_t -#define PCI_HOST_SUFFIX _mmio - -#include "pci_host_template.h" - -static CPUWriteMemoryFunc * const pci_host_data_write_mmio[] = { - pci_host_data_writeb_mmio, - pci_host_data_writew_mmio, - pci_host_data_writel_mmio, -}; - -static CPUReadMemoryFunc * const pci_host_data_read_mmio[] = { - pci_host_data_readb_mmio, - pci_host_data_readw_mmio, - pci_host_data_readl_mmio, -}; - int pci_host_data_register_mmio(PCIHostState *s) { - return cpu_register_io_memory(pci_host_data_read_mmio, - pci_host_data_write_mmio, - s); + pci_host_init(s); + return cpu_register_io_memory_simple(&s->data_handler); } -#undef PCI_ADDR_T -#undef PCI_HOST_SUFFIX - -#define PCI_ADDR_T uint32_t -#define PCI_HOST_SUFFIX _ioport - -#include "pci_host_template.h" - void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s) { - register_ioport_write(ioport, 4, 1, pci_host_data_writeb_ioport, s); - register_ioport_write(ioport, 4, 2, pci_host_data_writew_ioport, s); - register_ioport_write(ioport, 4, 4, pci_host_data_writel_ioport, s); - register_ioport_read(ioport, 4, 1, pci_host_data_readb_ioport, s); - register_ioport_read(ioport, 4, 2, pci_host_data_readw_ioport, s); - register_ioport_read(ioport, 4, 4, pci_host_data_readl_ioport, s); + pci_host_init(s); + register_ioport_simple(&s->data_handler, ioport, 4, 1); + register_ioport_simple(&s->data_handler, ioport, 4, 2); + register_ioport_simple(&s->data_handler, ioport, 4, 4); } diff --git a/hw/pci_host.h b/hw/pci_host.h index a006687f8b..5ff64430ed 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -29,9 +29,13 @@ #define PCI_HOST_H #include "sysbus.h" +#include "rwhandler.h" struct PCIHostState { SysBusDevice busdev; + ReadWriteHandler conf_noswap_handler; + ReadWriteHandler conf_handler; + ReadWriteHandler data_handler; uint32_t config_reg; PCIBus *bus; }; diff --git a/hw/pci_host_template.h b/hw/pci_host_template.h deleted file mode 100644 index 11e6c88fd7..0000000000 --- a/hw/pci_host_template.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * QEMU Common PCI Host bridge configuration data space access routines. - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* Worker routines for a PCI host controller that uses an {address,data} - register pair to access PCI configuration space. */ - -static void glue(pci_host_data_writeb, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr, uint32_t val) -{ - PCIHostState *s = opaque; - - PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1); -} - -static void glue(pci_host_data_writew, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr, uint32_t val) -{ - PCIHostState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2); -} - -static void glue(pci_host_data_writel, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr, uint32_t val) -{ - PCIHostState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg, val, 4); -} - -static uint32_t glue(pci_host_data_readb, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr) -{ - PCIHostState *s = opaque; - uint32_t val; - - if (!(s->config_reg & (1 << 31))) - return 0xff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1); - PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - return val; -} - -static uint32_t glue(pci_host_data_readw, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr) -{ - PCIHostState *s = opaque; - uint32_t val; - if (!(s->config_reg & (1 << 31))) - return 0xffff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2); - PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t glue(pci_host_data_readl, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr) -{ - PCIHostState *s = opaque; - uint32_t val; - if (!(s->config_reg & (1 << 31))) - return 0xffffffff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4); - PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 63379c234a..fe7a121562 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -63,6 +63,7 @@ #define PCI_VENDOR_ID_APPLE 0x106b #define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b #define PCI_VENDOR_ID_SUN 0x108e #define PCI_DEVICE_ID_SUN_EBUS 0x1000 diff --git a/hw/pl181.c b/hw/pl181.c index 7282053053..1924053330 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -182,39 +182,40 @@ error: static void pl181_fifo_run(pl181_state *s) { uint32_t bits; - uint32_t value; + uint32_t value = 0; int n; - int limit; int is_read; is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0; if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card)) && !s->linux_hack) { - limit = is_read ? PL181_FIFO_LEN : 0; - n = 0; - value = 0; - while (s->datacnt && s->fifo_len != limit) { - if (is_read) { + if (is_read) { + n = 0; + while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) { value |= (uint32_t)sd_read_data(s->card) << (n * 8); + s->datacnt--; n++; if (n == 4) { pl181_fifo_push(s, value); - value = 0; n = 0; + value = 0; } - } else { + } + if (n != 0) { + pl181_fifo_push(s, value); + } + } else { /* write */ + n = 0; + while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { if (n == 0) { value = pl181_fifo_pop(s); n = 4; } + n--; + s->datacnt--; sd_write_data(s->card, value & 0xff); value >>= 8; - n--; } - s->datacnt--; - } - if (n && is_read) { - pl181_fifo_push(s, value); } } s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO); @@ -40,10 +40,12 @@ enum { ARCH_PREP = 0, ARCH_MAC99, ARCH_HEATHROW, + ARCH_MAC99_U3, }; #define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) #define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) #define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) +#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03) #define PPC_SERIAL_MM_BAUDBASE 399193 diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index a04dffea84..89f96bbc34 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -58,6 +58,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic); /* UniNorth PCI */ PCIBus *pci_pmac_init(qemu_irq *pic); +PCIBus *pci_pmac_u3_init(qemu_irq *pic); /* Mac NVRAM */ typedef struct MacIONVRAMState MacIONVRAMState; diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index a4c714ae7f..bc86c851e7 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -21,6 +21,30 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. + * + * PCI bus layout on a real G5 (U3 based): + * + * 0000:f0:0b.0 Host bridge [0600]: Apple Computer Inc. U3 AGP [106b:004b] + * 0000:f0:10.0 VGA compatible controller [0300]: ATI Technologies Inc RV350 AP [Radeon 9600] [1002:4150] + * 0001:00:00.0 Host bridge [0600]: Apple Computer Inc. CPC945 HT Bridge [106b:004a] + * 0001:00:01.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12) + * 0001:00:02.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12) + * 0001:00:03.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0045] + * 0001:00:04.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0046] + * 0001:00:05.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0047] + * 0001:00:06.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0048] + * 0001:00:07.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0049] + * 0001:01:07.0 Class [ff00]: Apple Computer Inc. K2 KeyLargo Mac/IO [106b:0041] (rev 20) + * 0001:01:08.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040] + * 0001:01:09.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040] + * 0001:02:0b.0 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43) + * 0001:02:0b.1 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43) + * 0001:02:0b.2 USB Controller [0c03]: NEC Corporation USB 2.0 [1033:00e0] (rev 04) + * 0001:03:0d.0 Class [ff00]: Apple Computer Inc. K2 ATA/100 [106b:0043] + * 0001:03:0e.0 FireWire (IEEE 1394) [0c00]: Apple Computer Inc. K2 FireWire [106b:0042] + * 0001:04:0f.0 Ethernet controller [0200]: Apple Computer Inc. K2 GMAC (Sun GEM) [106b:004c] + * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240] + * */ #include "hw.h" #include "ppc.h" @@ -40,6 +64,8 @@ #include "loader.h" #include "elf.h" #include "kvm.h" +#include "kvm_ppc.h" +#include "hw/usb.h" #define MAX_IDE_BUS 2 #define VGA_BIOS_SIZE 65536 @@ -109,11 +135,13 @@ static void ppc_core99_init (ram_addr_t ram_size, int nvram_mem_index; int vga_bios_size, bios_size; int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index; + int ide_mem_index[3]; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; void *dbdma; uint8_t *vga_bios_ptr; + int machine_arch; linux_boot = (kernel_filename != NULL); @@ -317,7 +345,14 @@ static void ppc_core99_init (ram_addr_t ram_size, } } pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL); - pci_bus = pci_pmac_init(pic); + if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { + /* 970 gets a U3 bus */ + pci_bus = pci_pmac_u3_init(pic); + machine_arch = ARCH_MAC99_U3; + } else { + pci_bus = pci_pmac_init(pic); + machine_arch = ARCH_MAC99; + } /* init basic PC hardware */ pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size); @@ -331,27 +366,41 @@ static void ppc_core99_init (ram_addr_t ram_size, fprintf(stderr, "qemu: too many IDE bus\n"); exit(1); } - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } dbdma = DBDMA_init(&dbdma_mem_index); - pci_cmd646_ide_init(pci_bus, hd, 0); + + /* We only emulate 2 out of 3 IDE controllers for now */ + ide_mem_index[0] = -1; + hd[0] = drive_get(IF_IDE, 0, 0); + hd[1] = drive_get(IF_IDE, 0, 1); + ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); + hd[0] = drive_get(IF_IDE, 1, 0); + hd[1] = drive_get(IF_IDE, 1, 1); + ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]); /* cuda also initialize ADB */ + if (machine_arch == ARCH_MAC99_U3) { + usb_enabled = 1; + } cuda_init(&cuda_mem_index, pic[0x19]); adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index, - dbdma_mem_index, cuda_mem_index, NULL, 0, NULL, + dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index, escc_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, -1); } + /* U3 needs to use USB for input because Linux doesn't support via-cuda + on PPC64 */ + if (machine_arch == ARCH_MAC99_U3) { + usbdevice_create("keyboard"); + usbdevice_create("mouse"); + } + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; @@ -364,7 +413,7 @@ static void ppc_core99_init (ram_addr_t ram_size, fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_MAC99); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { @@ -381,6 +430,14 @@ static void ppc_core99_init (ram_addr_t ram_size, fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); + if (kvm_enabled()) { +#ifdef CONFIG_KVM + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); +#endif + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + } + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 7ccc6a1471..04a78358dd 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -40,6 +40,7 @@ #include "loader.h" #include "elf.h" #include "kvm.h" +#include "kvm_ppc.h" #define MAX_IDE_BUS 2 #define VGA_BIOS_SIZE 65536 @@ -401,6 +402,14 @@ static void ppc_heathrow_init (ram_addr_t ram_size, fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); + if (kvm_enabled()) { +#ifdef CONFIG_KVM + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); +#endif + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + } + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } @@ -749,8 +749,11 @@ void do_device_add(Monitor *mon, const QDict *qdict) opts = qemu_opts_parse(&qemu_device_opts, qdict_get_str(qdict, "config"), "driver"); - if (opts && !qdev_device_help(opts)) - qdev_device_add(opts); + if (opts) { + if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) { + qemu_opts_del(opts); + } + } } void do_device_del(Monitor *mon, const QDict *qdict) diff --git a/hw/serial.c b/hw/serial.c index e7538ac8ca..df67383d06 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -169,11 +169,19 @@ static int fifo_put(SerialState *s, int fifo, uint8_t chr) { SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; - f->data[f->head++] = chr; + /* Receive overruns do not overwrite FIFO contents. */ + if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) { - if (f->head == UART_FIFO_LENGTH) - f->head = 0; - f->count++; + f->data[f->head++] = chr; + + if (f->head == UART_FIFO_LENGTH) + f->head = 0; + } + + if (f->count < UART_FIFO_LENGTH) + f->count++; + else if (fifo == RECV_FIFO) + s->lsr |= UART_LSR_OE; return 1; } @@ -533,8 +541,10 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) break; case 2: ret = s->iir; + if (ret & UART_IIR_THRI) { s->thr_ipending = 0; - serial_update_irq(s); + serial_update_irq(s); + } break; case 3: ret = s->lcr; @@ -544,9 +554,9 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) break; case 5: ret = s->lsr; - /* Clear break interrupt */ - if (s->lsr & UART_LSR_BI) { - s->lsr &= ~UART_LSR_BI; + /* Clear break and overrun interrupts */ + if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) { + s->lsr &= ~(UART_LSR_BI|UART_LSR_OE); serial_update_irq(s); } break; @@ -629,6 +639,8 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) /* call the timeout receive callback in 4 char transmit time */ qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4); } else { + if (s->lsr & UART_LSR_DR) + s->lsr |= UART_LSR_OE; s->rbr = buf[0]; s->lsr |= UART_LSR_DR; } diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 19eb5e0ad7..7bdf430346 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -36,22 +36,31 @@ #define UNIN_DPRINTF(fmt, ...) #endif +static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e }; + typedef struct UNINState { SysBusDevice busdev; PCIHostState host_state; + ReadWriteHandler data_handler; } UNINState; -/* Don't know if this matches real hardware, but it agrees with OHW. */ static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num) { - return (irq_num + (pci_dev->devfn >> 3)) & 3; + int retval; + int devfn = pci_dev->devfn & 0x00FFFFFF; + + retval = (((devfn >> 11) & 0x1F) + irq_num) & 3; + + return retval; } static void pci_unin_set_irq(void *opaque, int irq_num, int level) { qemu_irq *pic = opaque; - qemu_set_irq(pic[irq_num + 8], level); + UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__, + unin_irq_line[irq_num], level); + qemu_set_irq(pic[unin_irq_line[irq_num]], level); } static void pci_unin_save(QEMUFile* f, void *opaque) @@ -75,6 +84,68 @@ static void pci_unin_reset(void *opaque) { } +static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr) +{ + uint32_t retval; + + if (reg & (1u << 31)) { + /* XXX OpenBIOS compatibility hack */ + retval = reg | (addr & 3); + } else if (reg & 1) { + /* CFA1 style */ + retval = (reg & ~7u) | (addr & 7); + } else { + uint32_t slot, func; + + /* Grab CFA0 style values */ + slot = ffs(reg & 0xfffff800) - 1; + func = (reg >> 8) & 7; + + /* ... and then convert them to x86 format */ + /* config pointer */ + retval = (reg & (0xff - 7)) | (addr & 7); + /* slot */ + retval |= slot << 11; + /* fn */ + retval |= func << 8; + } + + + UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n", + reg, addr, retval); + + return retval; +} + +static void unin_data_write(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) +{ + UNINState *s = container_of(handler, UNINState, data_handler); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val); + pci_data_write(s->host_state.bus, + unin_get_config_reg(s->host_state.config_reg, addr), + val, len); +} + +static uint32_t unin_data_read(ReadWriteHandler *handler, + pcibus_t addr, int len) +{ + UNINState *s = container_of(handler, UNINState, data_handler); + uint32_t val; + + val = pci_data_read(s->host_state.bus, + unin_get_config_reg(s->host_state.config_reg, addr), + len); + UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + return val; +} + static int pci_unin_main_init_device(SysBusDevice *dev) { UNINState *s; @@ -85,7 +156,9 @@ static int pci_unin_main_init_device(SysBusDevice *dev) s = FROM_SYSBUS(UNINState, dev); pci_mem_config = pci_host_conf_register_mmio(&s->host_state); - pci_mem_data = pci_host_data_register_mmio(&s->host_state); + s->data_handler.read = unin_data_read; + s->data_handler.write = unin_data_write; + pci_mem_data = cpu_register_io_memory_simple(&s->data_handler); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); @@ -94,6 +167,27 @@ static int pci_unin_main_init_device(SysBusDevice *dev) return 0; } +static int pci_u3_agp_init_device(SysBusDevice *dev) +{ + UNINState *s; + int pci_mem_config, pci_mem_data; + + /* Uninorth U3 AGP bus */ + s = FROM_SYSBUS(UNINState, dev); + + pci_mem_config = pci_host_conf_register_mmio(&s->host_state); + s->data_handler.read = unin_data_read; + s->data_handler.write = unin_data_write; + pci_mem_data = cpu_register_io_memory_simple(&s->data_handler); + sysbus_init_mmio(dev, 0x1000, pci_mem_config); + sysbus_init_mmio(dev, 0x1000, pci_mem_data); + + register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, &s->host_state); + qemu_register_reset(pci_unin_reset, &s->host_state); + + return 0; +} + static int pci_unin_agp_init_device(SysBusDevice *dev) { UNINState *s; @@ -175,6 +269,31 @@ PCIBus *pci_pmac_init(qemu_irq *pic) return d->host_state.bus; } +PCIBus *pci_pmac_u3_init(qemu_irq *pic) +{ + DeviceState *dev; + SysBusDevice *s; + UNINState *d; + + /* Uninorth AGP bus */ + + dev = qdev_create(NULL, "u3-agp"); + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + d = FROM_SYSBUS(UNINState, s); + + d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", + pci_unin_set_irq, pci_unin_map_irq, + pic, 11 << 3, 4); + + sysbus_mmio_map(s, 0, 0xf0800000); + sysbus_mmio_map(s, 1, 0xf0c00000); + + pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp"); + + return d->host_state.bus; +} + static int unin_main_pci_host_init(PCIDevice *d) { pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); @@ -201,6 +320,21 @@ static int unin_agp_pci_host_init(PCIDevice *d) return 0; } +static int u3_agp_pci_host_init(PCIDevice *d) +{ + pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); + pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP); + /* revision */ + d->config[0x08] = 0x00; + pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST); + /* cache line size */ + d->config[0x0C] = 0x08; + /* latency timer */ + d->config[0x0D] = 0x10; + d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; + return 0; +} + static int unin_internal_pci_host_init(PCIDevice *d) { pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); @@ -220,6 +354,12 @@ static PCIDeviceInfo unin_main_pci_host_info = { .init = unin_main_pci_host_init, }; +static PCIDeviceInfo u3_agp_pci_host_info = { + .qdev.name = "u3-agp", + .qdev.size = sizeof(PCIDevice), + .init = u3_agp_pci_host_init, +}; + static PCIDeviceInfo unin_agp_pci_host_info = { .qdev.name = "uni-north-agp", .qdev.size = sizeof(PCIDevice), @@ -237,6 +377,9 @@ static void unin_register_devices(void) sysbus_register_dev("uni-north", sizeof(UNINState), pci_unin_main_init_device); pci_qdev_register(&unin_main_pci_host_info); + sysbus_register_dev("u3-agp", sizeof(UNINState), + pci_u3_agp_init_device); + pci_qdev_register(&u3_agp_pci_host_info); sysbus_register_dev("uni-north-agp", sizeof(UNINState), pci_unin_agp_init_device); pci_qdev_register(&unin_agp_pci_host_info); diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 4f320d7763..bf456bbadf 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -66,6 +66,7 @@ typedef struct USBHIDState { int kind; int protocol; uint8_t idle; + int64_t next_idle_clock; int changed; void *datain_opaque; void (*datain)(void *); @@ -630,6 +631,11 @@ static void usb_keyboard_handle_reset(USBDevice *dev) s->protocol = 1; } +static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime) +{ + s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000; +} + static int usb_hid_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { @@ -795,6 +801,7 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, break; case SET_IDLE: s->idle = (uint8_t) (value >> 8); + usb_hid_set_next_idle(s, qemu_get_clock(vm_clock)); ret = 0; break; default: @@ -813,9 +820,10 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) switch(p->pid) { case USB_TOKEN_IN: if (p->devep == 1) { - /* TODO: Implement finite idle delays. */ - if (!(s->changed || s->idle)) + int64_t curtime = qemu_get_clock(vm_clock); + if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0)) return USB_RET_NAK; + usb_hid_set_next_idle(s, curtime); s->changed = 0; if (s->kind == USB_MOUSE) ret = usb_mouse_poll(s, p->data, p->len); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 153c6514f7..7048fb84d0 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -147,14 +147,10 @@ static int versatile_pci_host_init(PCIDevice *d) pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX); /* Both boards have the same device ID. Oh well. */ pci_config_set_device_id(d->config, PCI_DEVICE_ID_XILINX_XC2VP30); - d->config[0x04] = 0x00; - d->config[0x05] = 0x00; - d->config[0x06] = 0x20; - d->config[0x07] = 0x02; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x00; // programming i/f + pci_set_word(d->config + PCI_STATUS, + PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO); - d->config[0x0D] = 0x10; // latency_timer + pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10); return 0; } diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index f3373ae50e..bcd40f7b23 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -500,8 +500,8 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev) if (!vdev) { return -1; } - vdev->nvectors = proxy->nvectors ? proxy->nvectors - : proxy->max_virtserial_ports + 1; + vdev->nvectors = proxy->nvectors == -1 ? proxy->max_virtserial_ports + 1 + : proxy->nvectors; virtio_init_pci(proxy, vdev, PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_DEVICE_ID_VIRTIO_CONSOLE, @@ -585,7 +585,7 @@ static PCIDeviceInfo virtio_info[] = { .init = virtio_serial_init_pci, .exit = virtio_exit_pci, .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 0), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, -1), DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports, diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index ab456ea396..d0e021932c 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -335,8 +335,10 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq) static uint32_t get_features(VirtIODevice *vdev, uint32_t features) { - features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT); - + VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev); + if (vser->bus->max_nr_ports > 1) { + features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT); + } return features; } |