aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/apb_pci.c80
-rw-r--r--hw/ide/core.c62
-rw-r--r--hw/ide/internal.h5
-rw-r--r--hw/mac_dbdma.c10
-rw-r--r--hw/pc.c73
-rw-r--r--hw/pc.h10
-rw-r--r--hw/pci-hotplug.c30
-rw-r--r--hw/pci.h1
-rw-r--r--hw/pci_host.c172
-rw-r--r--hw/pci_host.h4
-rw-r--r--hw/pci_host_template.h109
-rw-r--r--hw/pci_ids.h1
-rw-r--r--hw/pl181.c29
-rw-r--r--hw/ppc.h2
-rw-r--r--hw/ppc_mac.h1
-rw-r--r--hw/ppc_newworld.c73
-rw-r--r--hw/ppc_oldworld.c9
-rw-r--r--hw/qdev.c7
-rw-r--r--hw/serial.c28
-rw-r--r--hw/unin_pci.c151
-rw-r--r--hw/usb-hid.c12
-rw-r--r--hw/versatile_pci.c10
-rw-r--r--hw/virtio-pci.c6
-rw-r--r--hw/virtio-serial-bus.c6
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);
}
diff --git a/hw/pc.c b/hw/pc.c
index 6fbe98bb64..4f6a5228fd 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -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);
diff --git a/hw/pc.h b/hw/pc.h
index 03ffc91536..92f8563609 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -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"));
}
diff --git a/hw/pci.h b/hw/pci.h
index 8b511d243c..37ebdc423c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -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);
diff --git a/hw/ppc.h b/hw/ppc.h
index bbf3a986b6..de13092ae4 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -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);
}
diff --git a/hw/qdev.c b/hw/qdev.c
index 539b5a2009..d0052d436c 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -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;
}