diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/acpi.c | 113 | ||||
-rw-r--r-- | hw/acpi.h | 18 | ||||
-rw-r--r-- | hw/acpi_ich9.c | 199 | ||||
-rw-r--r-- | hw/acpi_ich9.h | 3 | ||||
-rw-r--r-- | hw/acpi_piix4.c | 185 | ||||
-rw-r--r-- | hw/apm.c | 23 | ||||
-rw-r--r-- | hw/apm.h | 5 | ||||
-rw-r--r-- | hw/cirrus_vga.c | 48 | ||||
-rw-r--r-- | hw/dma.c | 106 | ||||
-rw-r--r-- | hw/ich9.h | 1 | ||||
-rw-r--r-- | hw/isa-bus.c | 9 | ||||
-rw-r--r-- | hw/isa.h | 1 | ||||
-rw-r--r-- | hw/lpc_ich9.c | 31 | ||||
-rw-r--r-- | hw/mips_mipssim.c | 3 | ||||
-rw-r--r-- | hw/pc.c | 49 | ||||
-rw-r--r-- | hw/pc_piix.c | 24 | ||||
-rw-r--r-- | hw/pm_smbus.c | 17 | ||||
-rw-r--r-- | hw/pm_smbus.h | 3 | ||||
-rw-r--r-- | hw/serial.c | 4 | ||||
-rw-r--r-- | hw/serial.h | 2 | ||||
-rw-r--r-- | hw/smbus_ich9.c | 64 | ||||
-rw-r--r-- | hw/usb.h | 2 | ||||
-rw-r--r-- | hw/usb/bus.c | 3 | ||||
-rw-r--r-- | hw/usb/core.c | 4 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 85 | ||||
-rw-r--r-- | hw/usb/dev-hub.c | 2 | ||||
-rw-r--r-- | hw/usb/dev-network.c | 7 | ||||
-rw-r--r-- | hw/usb/dev-wacom.c | 4 | ||||
-rw-r--r-- | hw/usb/hcd-ehci.c | 39 | ||||
-rw-r--r-- | hw/usb/hcd-ehci.h | 1 | ||||
-rw-r--r-- | hw/usb/host-bsd.c | 1 | ||||
-rw-r--r-- | hw/usb/host-linux.c | 1 | ||||
-rw-r--r-- | hw/usb/redirect.c | 4 | ||||
-rw-r--r-- | hw/vt82c686.c | 104 |
34 files changed, 663 insertions, 502 deletions
@@ -275,7 +275,7 @@ uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar) return ar->pm1.evt.sts; } -void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) +static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) { uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { @@ -285,7 +285,7 @@ void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) ar->pm1.evt.sts &= ~val; } -void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) +static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) { ar->pm1.evt.en = val; qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, @@ -310,6 +310,51 @@ void acpi_pm1_evt_reset(ACPIREGS *ar) qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0); } +static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) +{ + ACPIREGS *ar = opaque; + switch (addr) { + case 0: + return acpi_pm1_evt_get_sts(ar); + case 2: + return ar->pm1.evt.en; + default: + return 0; + } +} + +static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + ACPIREGS *ar = opaque; + switch (addr) { + case 0: + acpi_pm1_evt_write_sts(ar, val); + ar->pm1.evt.update_sci(ar); + break; + case 2: + acpi_pm1_evt_write_en(ar, val); + ar->pm1.evt.update_sci(ar); + break; + } +} + +static const MemoryRegionOps acpi_pm_evt_ops = { + .read = acpi_pm_evt_read, + .write = acpi_pm_evt_write, + .valid.min_access_size = 2, + .valid.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent) +{ + ar->pm1.evt.update_sci = update_sci; + memory_region_init_io(&ar->pm1.evt.io, &acpi_pm_evt_ops, ar, "acpi-evt", 4); + memory_region_add_subregion(parent, 0, &ar->pm1.evt.io); +} + /* ACPI PM_TMR */ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable) { @@ -331,7 +376,7 @@ void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar) ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL; } -uint32_t acpi_pm_tmr_get(ACPIREGS *ar) +static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) { uint32_t d = acpi_pm_tmr_get_clock(); return d & 0xffffff; @@ -344,10 +389,25 @@ static void acpi_pm_tmr_timer(void *opaque) ar->tmr.update_sci(ar); } -void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci) +static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) +{ + return acpi_pm_tmr_get(opaque); +} + +static const MemoryRegionOps acpi_pm_tmr_ops = { + .read = acpi_pm_tmr_read, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent) { ar->tmr.update_sci = update_sci; ar->tmr.timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, ar); + memory_region_init_io(&ar->tmr.io, &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); + memory_region_add_subregion(parent, 8, &ar->tmr.io); } void acpi_pm_tmr_reset(ACPIREGS *ar) @@ -357,13 +417,7 @@ void acpi_pm_tmr_reset(ACPIREGS *ar) } /* ACPI PM1aCNT */ -void acpi_pm1_cnt_init(ACPIREGS *ar) -{ - ar->wakeup.notify = acpi_notify_wakeup; - qemu_register_wakeup_notifier(&ar->wakeup); -} - -void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4) +static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) { ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); @@ -378,7 +432,7 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4) qemu_system_suspend_request(); break; default: - if (sus_typ == s4) { /* S4 request */ + if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */ monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL); qemu_system_shutdown_request(); } @@ -398,6 +452,34 @@ void acpi_pm1_cnt_update(ACPIREGS *ar, } } +static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) +{ + ACPIREGS *ar = opaque; + return ar->pm1.cnt.cnt; +} + +static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + acpi_pm1_cnt_write(opaque, val); +} + +static const MemoryRegionOps acpi_pm_cnt_ops = { + .read = acpi_pm_cnt_read, + .write = acpi_pm_cnt_write, + .valid.min_access_size = 2, + .valid.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent) +{ + ar->wakeup.notify = acpi_notify_wakeup; + qemu_register_wakeup_notifier(&ar->wakeup); + memory_region_init_io(&ar->pm1.cnt.io, &acpi_pm_cnt_ops, ar, "acpi-cnt", 2); + memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io); +} + void acpi_pm1_cnt_reset(ACPIREGS *ar) { ar->pm1.cnt.cnt = 0; @@ -411,11 +493,6 @@ void acpi_gpe_init(ACPIREGS *ar, uint8_t len) ar->gpe.en = g_malloc0(len / 2); } -void acpi_gpe_blk(ACPIREGS *ar, uint32_t blk) -{ - ar->gpe.blk = blk; -} - void acpi_gpe_reset(ACPIREGS *ar) { memset(ar->gpe.sts, 0, ar->gpe.len / 2); @@ -441,7 +518,6 @@ void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val) { uint8_t *cur; - addr -= ar->gpe.blk; cur = acpi_gpe_ioport_get_ptr(ar, addr); if (addr < ar->gpe.len / 2) { /* GPE_STS */ @@ -459,7 +535,6 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) uint8_t *cur; uint32_t val; - addr -= ar->gpe.blk; cur = acpi_gpe_ioport_get_ptr(ar, addr); val = 0; if (cur != NULL) { @@ -84,22 +84,26 @@ typedef void (*acpi_update_sci_fn)(ACPIREGS *ar); struct ACPIPMTimer { QEMUTimer *timer; + MemoryRegion io; int64_t overflow_time; acpi_update_sci_fn update_sci; }; struct ACPIPM1EVT { + MemoryRegion io; uint16_t sts; uint16_t en; + acpi_update_sci_fn update_sci; }; struct ACPIPM1CNT { + MemoryRegion io; uint16_t cnt; + uint8_t s4_val; }; struct ACPIGPE { - uint32_t blk; uint8_t len; uint8_t *sts; @@ -119,8 +123,8 @@ struct ACPIREGS { /* PM_TMR */ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable); void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar); -uint32_t acpi_pm_tmr_get(ACPIREGS *ar); -void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci); +void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent); void acpi_pm_tmr_reset(ACPIREGS *ar); #include "qemu-timer.h" @@ -132,21 +136,19 @@ static inline int64_t acpi_pm_tmr_get_clock(void) /* PM1a_EVT: piix and ich9 don't implement PM1b. */ uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar); -void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val); -void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val); void acpi_pm1_evt_power_down(ACPIREGS *ar); void acpi_pm1_evt_reset(ACPIREGS *ar); +void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent); /* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */ -void acpi_pm1_cnt_init(ACPIREGS *ar); -void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4); +void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent); void acpi_pm1_cnt_update(ACPIREGS *ar, bool sci_enable, bool sci_disable); void acpi_pm1_cnt_reset(ACPIREGS *ar); /* GPE0 */ void acpi_gpe_init(ACPIREGS *ar, uint8_t len); -void acpi_gpe_blk(ACPIREGS *ar, uint32_t blk); void acpi_gpe_reset(ACPIREGS *ar); void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val); diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index 61034d3bd7..c5978d33cc 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -29,6 +29,7 @@ #include "sysemu.h" #include "acpi.h" #include "kvm.h" +#include "exec-memory.h" #include "ich9.h" @@ -41,10 +42,6 @@ do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0) #define ICH9_DEBUG(fmt, ...) do { } while (0) #endif -static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len, - uint32_t val); -static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len); - static void pm_update_sci(ICH9LPCPMRegs *pm) { int sci_level, pm1a_sts; @@ -70,152 +67,60 @@ static void ich9_pm_update_sci_fn(ACPIREGS *regs) pm_update_sci(pm); } -static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width) { ICH9LPCPMRegs *pm = opaque; - - switch (addr & ICH9_PMIO_MASK) { - case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1): - acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); - break; - default: - break; - } - - ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val); + return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); } -static uint32_t pm_ioport_readb(void *opaque, uint32_t addr) +static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { ICH9LPCPMRegs *pm = opaque; - uint32_t val = 0; - - switch (addr & ICH9_PMIO_MASK) { - case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1): - val = acpi_gpe_ioport_readb(&pm->acpi_regs, addr); - break; - default: - val = 0; - break; - } - ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val); - return val; + acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); } -static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - ICH9LPCPMRegs *pm = opaque; - - switch (addr & ICH9_PMIO_MASK) { - case ICH9_PMIO_PM1_STS: - acpi_pm1_evt_write_sts(&pm->acpi_regs, val); - pm_update_sci(pm); - break; - case ICH9_PMIO_PM1_EN: - pm->acpi_regs.pm1.evt.en = val; - pm_update_sci(pm); - break; - case ICH9_PMIO_PM1_CNT: - acpi_pm1_cnt_write(&pm->acpi_regs, val, 0); - break; - default: - pm_ioport_write_fallback(opaque, addr, 2, val); - break; - } - ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val); -} +static const MemoryRegionOps ich9_gpe_ops = { + .read = ich9_gpe_readb, + .write = ich9_gpe_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; -static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) +static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width) { ICH9LPCPMRegs *pm = opaque; - uint32_t val; - - switch (addr & ICH9_PMIO_MASK) { - case ICH9_PMIO_PM1_STS: - val = acpi_pm1_evt_get_sts(&pm->acpi_regs); - break; - case ICH9_PMIO_PM1_EN: - val = pm->acpi_regs.pm1.evt.en; - break; - case ICH9_PMIO_PM1_CNT: - val = pm->acpi_regs.pm1.cnt.cnt; - break; + switch (addr) { + case 0: + return pm->smi_en; + case 4: + return pm->smi_sts; default: - val = pm_ioport_read_fallback(opaque, addr, 2); - break; + return 0; } - ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val); - return val; } -static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { ICH9LPCPMRegs *pm = opaque; - - switch (addr & ICH9_PMIO_MASK) { - case ICH9_PMIO_SMI_EN: + switch (addr) { + case 0: pm->smi_en = val; break; - default: - pm_ioport_write_fallback(opaque, addr, 4, val); - break; } - ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val); } -static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) -{ - ICH9LPCPMRegs *pm = opaque; - uint32_t val; - - switch (addr & ICH9_PMIO_MASK) { - case ICH9_PMIO_PM1_TMR: - val = acpi_pm_tmr_get(&pm->acpi_regs); - break; - case ICH9_PMIO_SMI_EN: - val = pm->smi_en; - break; - - default: - val = pm_ioport_read_fallback(opaque, addr, 4); - break; - } - ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val); - return val; -} - -static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len, - uint32_t val) - { - int subsize = (len == 4) ? 2 : 1; - IOPortWriteFunc *ioport_write = - (subsize == 2) ? pm_ioport_writew : pm_ioport_writeb; - - int i; - - for (i = 0; i < len; i += subsize) { - ioport_write(opaque, addr, val); - val >>= 8 * subsize; - } -} - -static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len) -{ - int subsize = (len == 4) ? 2 : 1; - IOPortReadFunc *ioport_read = - (subsize == 2) ? pm_ioport_readw : pm_ioport_readb; - - uint32_t val; - int i; - - val = 0; - for (i = 0; i < len; i += subsize) { - val <<= 8 * subsize; - val |= ioport_read(opaque, addr); - } - - return val; -} +static const MemoryRegionOps ich9_smi_ops = { + .read = ich9_smi_readl, + .write = ich9_smi_writel, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base) { @@ -223,24 +128,11 @@ void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base) assert((pm_io_base & ICH9_PMIO_MASK) == 0); - if (pm->pm_io_base != 0) { - isa_unassign_ioport(pm->pm_io_base, ICH9_PMIO_SIZE); - } - - /* don't map at 0 */ - if (pm_io_base == 0) { - return; - } - - register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 1, pm_ioport_writeb, pm); - register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 1, pm_ioport_readb, pm); - register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 2, pm_ioport_writew, pm); - register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 2, pm_ioport_readw, pm); - register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_writel, pm); - register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_readl, pm); - pm->pm_io_base = pm_io_base; - acpi_gpe_blk(&pm->acpi_regs, pm_io_base + ICH9_PMIO_GPE0_STS); + memory_region_transaction_begin(); + memory_region_set_enabled(&pm->io, pm->pm_io_base != 0); + memory_region_set_address(&pm->io, pm->pm_io_base); + memory_region_transaction_commit(); } static int ich9_pm_post_load(void *opaque, int version_id) @@ -311,9 +203,22 @@ static void pm_powerdown_req(Notifier *n, void *opaque) void ich9_pm_init(ICH9LPCPMRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3) { - acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn); - acpi_pm1_cnt_init(&pm->acpi_regs); + memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE); + memory_region_set_enabled(&pm->io, false); + memory_region_add_subregion(get_system_io(), 0, &pm->io); + + acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); + acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); + acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io); + acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); + memory_region_init_io(&pm->io_gpe, &ich9_gpe_ops, pm, "apci-gpe0", + ICH9_PMIO_GPE0_LEN); + memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe); + + memory_region_init_io(&pm->io_smi, &ich9_smi_ops, pm, "apci-smi", + 8); + memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); pm->irq = sci_irq; qemu_register_reset(pm_reset, pm); diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h index 180c40673b..bc221d3cbc 100644 --- a/hw/acpi_ich9.h +++ b/hw/acpi_ich9.h @@ -30,6 +30,9 @@ typedef struct ICH9LPCPMRegs { * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t. */ ACPIREGS acpi_regs; + MemoryRegion io; + MemoryRegion io_gpe; + MemoryRegion io_smi; uint32_t smi_en; uint32_t smi_sts; diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 519269a013..0b5b0d3d3e 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -28,6 +28,7 @@ #include "range.h" #include "ioport.h" #include "fw_cfg.h" +#include "exec-memory.h" //#define DEBUG @@ -37,10 +38,11 @@ # define PIIX4_DPRINTF(format, ...) do { } while (0) #endif -#define ACPI_DBG_IO_ADDR 0xb044 - #define GPE_BASE 0xafe0 #define GPE_LEN 4 + +#define PCI_HOTPLUG_ADDR 0xae00 +#define PCI_HOTPLUG_SIZE 0x000f #define PCI_UP_BASE 0xae00 #define PCI_DOWN_BASE 0xae04 #define PCI_EJ_BASE 0xae08 @@ -55,7 +57,9 @@ struct pci_status { typedef struct PIIX4PMState { PCIDevice dev; - IORange ioport; + MemoryRegion io; + MemoryRegion io_gpe; + MemoryRegion io_pci; ACPIREGS ar; APMState apm; @@ -109,67 +113,6 @@ static void pm_tmr_timer(ACPIREGS *ar) pm_update_sci(s); } -static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, - uint64_t val) -{ - PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); - - if (width != 2) { - PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n", - (unsigned)addr, width, (unsigned)val); - } - - switch(addr) { - case 0x00: - acpi_pm1_evt_write_sts(&s->ar, val); - pm_update_sci(s); - break; - case 0x02: - acpi_pm1_evt_write_en(&s->ar, val); - pm_update_sci(s); - break; - case 0x04: - acpi_pm1_cnt_write(&s->ar, val, s->s4_val); - break; - default: - break; - } - PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr, - (unsigned int)val); -} - -static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, - uint64_t *data) -{ - PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); - uint32_t val; - - switch(addr) { - case 0x00: - val = acpi_pm1_evt_get_sts(&s->ar); - break; - case 0x02: - val = s->ar.pm1.evt.en; - break; - case 0x04: - val = s->ar.pm1.cnt.cnt; - break; - case 0x08: - val = acpi_pm_tmr_get(&s->ar); - break; - default: - val = 0; - break; - } - PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val); - *data = val; -} - -static const IORangeOps pm_iorange_ops = { - .read = pm_ioport_read, - .write = pm_ioport_write, -}; - static void apm_ctrl_changed(uint32_t val, void *arg) { PIIX4PMState *s = arg; @@ -184,32 +127,42 @@ static void apm_ctrl_changed(uint32_t val, void *arg) } } -static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) -{ - PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val); -} - static void pm_io_space_update(PIIX4PMState *s) { uint32_t pm_io_base; - if (s->dev.config[0x80] & 1) { - pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); - pm_io_base &= 0xffc0; + pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); + pm_io_base &= 0xffc0; - /* XXX: need to improve memory and ioport allocation */ - PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); - iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64); - ioport_register(&s->ioport); - } + memory_region_transaction_begin(); + memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1); + memory_region_set_address(&s->io, pm_io_base); + memory_region_transaction_commit(); +} + +static void smbus_io_space_update(PIIX4PMState *s) +{ + s->smb_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x90)); + s->smb_io_base &= 0xffc0; + + memory_region_transaction_begin(); + memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & 1); + memory_region_set_address(&s->smb.io, s->smb_io_base); + memory_region_transaction_commit(); } static void pm_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config(d, address, val, len); - if (range_covers_byte(address, len, 0x80)) + if (range_covers_byte(address, len, 0x80) || + ranges_overlap(address, len, 0x40, 4)) { pm_io_space_update((PIIX4PMState *)d); + } + if (range_covers_byte(address, len, 0xd2) || + ranges_overlap(address, len, 0x90, 4)) { + smbus_io_space_update((PIIX4PMState *)d); + } } static void vmstate_pci_status_pre_save(void *opaque) @@ -438,9 +391,7 @@ static int piix4_pm_initfn(PCIDevice *dev) pci_conf[0x3d] = 0x01; // interrupt pin 1 /* APM */ - apm_init(&s->apm, apm_ctrl_changed, s); - - register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + apm_init(dev, &s->apm, apm_ctrl_changed, s); if (s->kvm_enabled) { /* Mark SMM as already inited to prevent SMM from running. KVM does not @@ -453,16 +404,22 @@ static int piix4_pm_initfn(PCIDevice *dev) pci_conf[0x90] = s->smb_io_base | 1; pci_conf[0x91] = s->smb_io_base >> 8; pci_conf[0xd2] = 0x09; - register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); - register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); + pm_smbus_init(&s->dev.qdev, &s->smb); + memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1); + memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); + + memory_region_init(&s->io, "piix4-pm", 64); + memory_region_set_enabled(&s->io, false); + memory_region_add_subregion(get_system_io(), 0, &s->io); - acpi_pm_tmr_init(&s->ar, pm_tmr_timer); + acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_cnt_init(&s->ar, &s->io); acpi_gpe_init(&s->ar, GPE_LEN); s->powerdown_notifier.notify = piix4_pm_powerdown_req; qemu_register_powerdown_notifier(&s->powerdown_notifier); - pm_smbus_init(&s->dev.qdev, &s->smb); s->machine_ready.notify = piix4_pm_machine_ready; qemu_add_machine_init_done_notifier(&s->machine_ready); qemu_register_reset(piix4_reset, s); @@ -483,7 +440,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, s = DO_UPCAST(PIIX4PMState, dev, dev); s->irq = sci_irq; - acpi_pm1_cnt_init(&s->ar); s->smi_irq = smi_irq; s->kvm_enabled = kvm_enabled; @@ -540,7 +496,7 @@ static void piix4_pm_register_types(void) type_init(piix4_pm_register_types) -static uint32_t gpe_readb(void *opaque, uint32_t addr) +static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) { PIIX4PMState *s = opaque; uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); @@ -549,7 +505,8 @@ static uint32_t gpe_readb(void *opaque, uint32_t addr) return val; } -static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) +static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { PIIX4PMState *s = opaque; @@ -559,6 +516,16 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); } +static const MemoryRegionOps piix4_gpe_ops = { + .read = gpe_readb, + .write = gpe_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static uint32_t pci_up_read(void *opaque, uint32_t addr) { PIIX4PMState *s = opaque; @@ -602,24 +569,40 @@ static uint32_t pcirmv_read(void *opaque, uint32_t addr) return s->pci0_hotplug_enable; } +static const MemoryRegionOps piix4_pci_ops = { + .old_portio = (MemoryRegionPortio[]) { + { + .offset = PCI_UP_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pci_up_read, + },{ + .offset = PCI_DOWN_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pci_down_read, + },{ + .offset = PCI_EJ_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pci_features_read, + .write = pciej_write, + },{ + .offset = PCI_RMV_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pcirmv_read, + }, + PORTIO_END_OF_LIST() + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, PCIHotplugState state); static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { - - register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); - register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); - acpi_gpe_blk(&s->ar, GPE_BASE); - - register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s); - register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s); - - register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s); - register_ioport_read(PCI_EJ_BASE, 4, 4, pci_features_read, s); - - register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s); - + memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0", + GPE_LEN); + memory_region_add_subregion(get_system_io(), GPE_BASE, &s->io_gpe); + + memory_region_init_io(&s->io_pci, &piix4_pci_ops, s, "apci-pci-hotplug", + PCI_HOTPLUG_SIZE); + memory_region_add_subregion(get_system_io(), PCI_HOTPLUG_ADDR, + &s->io_pci); pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); } @@ -22,6 +22,7 @@ #include "apm.h" #include "hw.h" +#include "pci.h" //#define DEBUG @@ -35,7 +36,8 @@ #define APM_CNT_IOPORT 0xb2 #define APM_STS_IOPORT 0xb3 -static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { APMState *apm = opaque; addr &= 1; @@ -51,7 +53,7 @@ static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t apm_ioport_readb(void *opaque, uint32_t addr) +static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size) { APMState *apm = opaque; uint32_t val; @@ -78,12 +80,23 @@ const VMStateDescription vmstate_apm = { } }; -void apm_init(APMState *apm, apm_ctrl_changed_t callback, void *arg) +static const MemoryRegionOps apm_ops = { + .read = apm_ioport_readb, + .write = apm_ioport_writeb, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +void apm_init(PCIDevice *dev, APMState *apm, apm_ctrl_changed_t callback, + void *arg) { apm->callback = callback; apm->arg = arg; /* ioport 0xb2, 0xb3 */ - register_ioport_write(APM_CNT_IOPORT, 2, 1, apm_ioport_writeb, apm); - register_ioport_read(APM_CNT_IOPORT, 2, 1, apm_ioport_readb, apm); + memory_region_init_io(&apm->io, &apm_ops, apm, "apm-io", 2); + memory_region_add_subregion(pci_address_space_io(dev), APM_CNT_IOPORT, + &apm->io); } @@ -4,6 +4,7 @@ #include <stdint.h> #include "qemu-common.h" #include "hw.h" +#include "memory.h" typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg); @@ -13,9 +14,11 @@ typedef struct APMState { apm_ctrl_changed_t callback; void *arg; + MemoryRegion io; } APMState; -void apm_init(APMState *s, apm_ctrl_changed_t callback, void *arg); +void apm_init(PCIDevice *dev, APMState *s, apm_ctrl_changed_t callback, + void *arg); extern const VMStateDescription vmstate_apm; diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 9bef96e6d7..40efa8a523 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -197,6 +197,7 @@ typedef void (*cirrus_fill_t)(struct CirrusVGAState *s, typedef struct CirrusVGAState { VGACommonState vga; + MemoryRegion cirrus_vga_io; MemoryRegion cirrus_linear_io; MemoryRegion cirrus_linear_bitblt_io; MemoryRegion cirrus_mmio_io; @@ -2432,13 +2433,15 @@ static void cirrus_update_memory_access(CirrusVGAState *s) /* I/O ports */ -static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) +static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr, + unsigned size) { CirrusVGAState *c = opaque; VGACommonState *s = &c->vga; int val, index; qemu_flush_coalesced_mmio_buffer(); + addr += 0x3b0; if (vga_ioport_invalid(s, addr)) { val = 0xff; @@ -2527,13 +2530,15 @@ static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) return val; } -static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { CirrusVGAState *c = opaque; VGACommonState *s = &c->vga; int index; qemu_flush_coalesced_mmio_buffer(); + addr += 0x3b0; /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { @@ -2646,7 +2651,7 @@ static uint64_t cirrus_mmio_read(void *opaque, hwaddr addr, if (addr >= 0x100) { return cirrus_mmio_blt_read(s, addr - 0x100); } else { - return cirrus_vga_ioport_read(s, addr + 0x3c0); + return cirrus_vga_ioport_read(s, addr + 0x10, size); } } @@ -2658,7 +2663,7 @@ static void cirrus_mmio_write(void *opaque, hwaddr addr, if (addr >= 0x100) { cirrus_mmio_blt_write(s, addr - 0x100, val); } else { - cirrus_vga_ioport_write(s, addr + 0x3c0, val); + cirrus_vga_ioport_write(s, addr + 0x10, val, size); } } @@ -2784,8 +2789,19 @@ static const MemoryRegionOps cirrus_linear_io_ops = { }, }; +static const MemoryRegionOps cirrus_vga_io_ops = { + .read = cirrus_vga_ioport_read, + .write = cirrus_vga_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, - MemoryRegion *system_memory) + MemoryRegion *system_memory, + MemoryRegion *system_io) { int i; static int inited; @@ -2817,19 +2833,10 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, s->bustype = CIRRUS_BUSTYPE_ISA; } - register_ioport_write(0x3c0, 16, 1, cirrus_vga_ioport_write, s); - - register_ioport_write(0x3b4, 2, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3d4, 2, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3ba, 1, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3da, 1, 1, cirrus_vga_ioport_write, s); - - register_ioport_read(0x3c0, 16, 1, cirrus_vga_ioport_read, s); - - register_ioport_read(0x3b4, 2, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3d4, 2, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3ba, 1, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3da, 1, 1, cirrus_vga_ioport_read, s); + /* Register ioport 0x3b0 - 0x3df */ + memory_region_init_io(&s->cirrus_vga_io, &cirrus_vga_io_ops, s, + "cirrus-io", 0x30); + memory_region_add_subregion(system_io, 0x3b0, &s->cirrus_vga_io); memory_region_init(&s->low_mem_container, "cirrus-lowmem-container", @@ -2900,7 +2907,7 @@ static int vga_initfn(ISADevice *dev) vga_common_init(s); cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, - isa_address_space(dev)); + isa_address_space(dev), isa_address_space_io(dev)); s->ds = graphic_console_init(s->update, s->invalidate, s->screen_dump, s->text_update, s); @@ -2948,7 +2955,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) /* setup VGA */ vga_common_init(&s->vga); - cirrus_init_common(s, device_id, 1, pci_address_space(dev)); + cirrus_init_common(s, device_id, 1, pci_address_space(dev), + pci_address_space_io(dev)); s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, s->vga.screen_dump, s->vga.text_update, &s->vga); @@ -58,6 +58,8 @@ static struct dma_cont { int dshift; struct dma_regs regs[4]; qemu_irq *cpu_request_exit; + MemoryRegion channel_io; + MemoryRegion cont_io; } dma_controllers[2]; enum { @@ -149,7 +151,7 @@ static inline int getff (struct dma_cont *d) return ff; } -static uint32_t read_chan (void *opaque, uint32_t nport) +static uint64_t read_chan(void *opaque, hwaddr nport, unsigned size) { struct dma_cont *d = opaque; int ichan, nreg, iport, ff, val, dir; @@ -171,7 +173,8 @@ static uint32_t read_chan (void *opaque, uint32_t nport) return (val >> (d->dshift + (ff << 3))) & 0xff; } -static void write_chan (void *opaque, uint32_t nport, uint32_t data) +static void write_chan(void *opaque, hwaddr nport, uint64_t data, + unsigned size) { struct dma_cont *d = opaque; int iport, ichan, nreg; @@ -189,22 +192,23 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data) } } -static void write_cont (void *opaque, uint32_t nport, uint32_t data) +static void write_cont(void *opaque, hwaddr nport, uint64_t data, + unsigned size) { struct dma_cont *d = opaque; int iport, ichan = 0; iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 0x08: /* command */ + case 0x01: /* command */ if ((data != 0) && (data & CMD_NOT_SUPPORTED)) { - dolog ("command %#x not supported\n", data); + dolog("command %"PRIx64" not supported\n", data); return; } d->command = data; break; - case 0x09: + case 0x02: ichan = data & 3; if (data & 4) { d->status |= 1 << (ichan + 4); @@ -216,7 +220,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) DMA_run(); break; - case 0x0a: /* single mask */ + case 0x03: /* single mask */ if (data & 4) d->mask |= 1 << (data & 3); else @@ -224,7 +228,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) DMA_run(); break; - case 0x0b: /* mode */ + case 0x04: /* mode */ { ichan = data & 3; #ifdef DEBUG_DMA @@ -243,23 +247,23 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) break; } - case 0x0c: /* clear flip flop */ + case 0x05: /* clear flip flop */ d->flip_flop = 0; break; - case 0x0d: /* reset */ + case 0x06: /* reset */ d->flip_flop = 0; d->mask = ~0; d->status = 0; d->command = 0; break; - case 0x0e: /* clear mask for all channels */ + case 0x07: /* clear mask for all channels */ d->mask = 0; DMA_run(); break; - case 0x0f: /* write mask for all channels */ + case 0x08: /* write mask for all channels */ d->mask = data; DMA_run(); break; @@ -277,7 +281,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) #endif } -static uint32_t read_cont (void *opaque, uint32_t nport) +static uint64_t read_cont(void *opaque, hwaddr nport, unsigned size) { struct dma_cont *d = opaque; int iport, val; @@ -463,7 +467,7 @@ void DMA_schedule(int nchan) static void dma_reset(void *opaque) { struct dma_cont *d = opaque; - write_cont (d, (0x0d << d->dshift), 0); + write_cont(d, (0x06 << d->dshift), 0, 1); } static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) @@ -473,38 +477,68 @@ static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) return dma_pos; } + +static const MemoryRegionOps channel_io_ops = { + .read = read_chan, + .write = write_chan, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +/* IOport from page_base */ +static const MemoryRegionPortio page_portio_list[] = { + { 0x01, 3, 1, .write = write_page, .read = read_page, }, + { 0x07, 1, 1, .write = write_page, .read = read_page, }, + PORTIO_END_OF_LIST(), +}; + +/* IOport from pageh_base */ +static const MemoryRegionPortio pageh_portio_list[] = { + { 0x01, 3, 1, .write = write_pageh, .read = read_pageh, }, + { 0x07, 3, 1, .write = write_pageh, .read = read_pageh, }, + PORTIO_END_OF_LIST(), +}; + +static const MemoryRegionOps cont_io_ops = { + .read = read_cont, + .write = write_cont, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base, int pageh_base, qemu_irq *cpu_request_exit) { - static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; int i; d->dshift = dshift; d->cpu_request_exit = cpu_request_exit; - for (i = 0; i < 8; i++) { - register_ioport_write (base + (i << dshift), 1, 1, write_chan, d); - register_ioport_read (base + (i << dshift), 1, 1, read_chan, d); - } - for (i = 0; i < ARRAY_SIZE (page_port_list); i++) { - register_ioport_write (page_base + page_port_list[i], 1, 1, - write_page, d); - register_ioport_read (page_base + page_port_list[i], 1, 1, - read_page, d); - if (pageh_base >= 0) { - register_ioport_write (pageh_base + page_port_list[i], 1, 1, - write_pageh, d); - register_ioport_read (pageh_base + page_port_list[i], 1, 1, - read_pageh, d); - } - } - for (i = 0; i < 8; i++) { - register_ioport_write (base + ((i + 8) << dshift), 1, 1, - write_cont, d); - register_ioport_read (base + ((i + 8) << dshift), 1, 1, - read_cont, d); + + memory_region_init_io(&d->channel_io, &channel_io_ops, d, + "dma-chan", 8 << d->dshift); + memory_region_add_subregion(isa_address_space_io(NULL), + base, &d->channel_io); + + isa_register_portio_list(NULL, page_base, page_portio_list, d, + "dma-page"); + if (pageh_base >= 0) { + isa_register_portio_list(NULL, pageh_base, pageh_portio_list, d, + "dma-pageh"); } + + memory_region_init_io(&d->cont_io, &cont_io_ops, d, "dma-cont", + 8 << d->dshift); + memory_region_add_subregion(isa_address_space_io(NULL), + base + (8 << d->dshift), &d->cont_io); + qemu_register_reset(dma_reset, d); dma_reset(d); for (i = 0; i < ARRAY_SIZE (d->regs); ++i) { @@ -51,6 +51,7 @@ typedef struct ICH9LPCState { /* isa bus */ ISABus *isa_bus; MemoryRegion rbca_mem; + Notifier machine_ready; qemu_irq *pic; qemu_irq *ioapic; diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 685fdc0f82..144a88e272 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -264,4 +264,13 @@ MemoryRegion *isa_address_space(ISADevice *dev) return get_system_memory(); } +MemoryRegion *isa_address_space_io(ISADevice *dev) +{ + if (dev) { + return isa_bus_from_device(dev)->address_space_io; + } + + return isabus->address_space_io; +} + type_init(isabus_register_types) @@ -43,6 +43,7 @@ void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); qemu_irq isa_get_irq(ISADevice *dev, int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); MemoryRegion *isa_address_space(ISADevice *dev); +MemoryRegion *isa_address_space_io(ISADevice *dev); ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_create_simple(ISABus *bus, const char *name); diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index 2fc83a496f..878a43e92c 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -60,6 +60,7 @@ #include "pam.h" #include "pci_internals.h" #include "exec-memory.h" +#include "sysemu.h" static int ich9_lpc_sci_irq(ICH9LPCState *lpc); @@ -456,6 +457,30 @@ static const MemoryRegionOps rbca_mmio_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static void ich9_lpc_machine_ready(Notifier *n, void *opaque) +{ + ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready); + uint8_t *pci_conf; + + pci_conf = s->d.config; + if (isa_is_ioport_assigned(0x3f8)) { + /* com1 */ + pci_conf[0x82] |= 0x01; + } + if (isa_is_ioport_assigned(0x2f8)) { + /* com2 */ + pci_conf[0x82] |= 0x02; + } + if (isa_is_ioport_assigned(0x378)) { + /* lpt */ + pci_conf[0x82] |= 0x04; + } + if (isa_is_ioport_assigned(0x3f0)) { + /* floppy */ + pci_conf[0x82] |= 0x08; + } +} + static int ich9_lpc_initfn(PCIDevice *d) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); @@ -472,7 +497,11 @@ static int ich9_lpc_initfn(PCIDevice *d) lpc->isa_bus = isa_bus; ich9_cc_init(lpc); - apm_init(&lpc->apm, ich9_apm_ctrl_changed, lpc); + apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc); + + lpc->machine_ready.notify = ich9_lpc_machine_ready; + qemu_add_machine_init_done_notifier(&lpc->machine_ready); + return 0; } diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index a95a3c1f11..20b5f1a58c 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -217,7 +217,8 @@ mips_mipssim_init(QEMUMachineInitArgs *args) /* A single 16450 sits at offset 0x3f8. It is attached to MIPS CPU INT2, which is interrupt 4. */ if (serial_hds[0]) - serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]); + serial_init(0x3f8, env->irq[4], 115200, serial_hds[0], + get_system_io()); if (nd_table[0].used) /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ @@ -98,7 +98,8 @@ void gsi_handler(void *opaque, int n, int level) qemu_set_irq(s->ioapic_irq[n], level); } -static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) +static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { } @@ -116,7 +117,8 @@ void cpu_set_ferr(CPUX86State *s) qemu_irq_raise(ferr_irq); } -static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) +static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { qemu_irq_lower(ferr_irq); } @@ -567,6 +569,14 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; } +static const MemoryRegionPortio bochs_bios_portio_list[] = { + { 0x500, 1, 1, .write = bochs_bios_write, }, /* 0x500 */ + { 0x501, 1, 1, .write = bochs_bios_write, }, /* 0x501 */ + { 0x501, 2, 2, .write = bochs_bios_write, }, /* 0x501 */ + { 0x8900, 1, 1, .write = bochs_bios_write, }, /* 0x8900 */ + PORTIO_END_OF_LIST(), +}; + static void *bochs_bios_init(void) { void *fw_cfg; @@ -574,12 +584,11 @@ static void *bochs_bios_init(void) size_t smbios_len; uint64_t *numa_fw_cfg; int i, j; + PortioList *bochs_bios_port_list = g_new(PortioList, 1); - register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL); - - register_ioport_write(0x501, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); + portio_list_init(bochs_bios_port_list, bochs_bios_portio_list, + NULL, "bochs-bios"); + portio_list_add(bochs_bios_port_list, get_system_io(), 0x0); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); @@ -967,6 +976,24 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } +static const MemoryRegionOps ioport80_io_ops = { + .write = ioport80_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static const MemoryRegionOps ioportF0_io_ops = { + .write = ioportF0_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, ISADevice **floppy, @@ -981,10 +1008,14 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_irq *a20_line; ISADevice *i8042, *port92, *vmmouse, *pit = NULL; qemu_irq *cpu_exit_irq; + MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); + MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); - register_ioport_write(0x80, 1, 1, ioport80_write, NULL); + memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); - register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); + memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io); /* * Check if an HPET shall be created. diff --git a/hw/pc_piix.c b/hw/pc_piix.c index aa3e7f40dc..19e342aeb4 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -281,8 +281,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) } #endif -static QEMUMachine pc_machine_v1_3 = { - .name = "pc-1.3", +static QEMUMachine pc_machine_v1_4 = { + .name = "pc-1.4", .alias = "pc", .desc = "Standard PC", .init = pc_init_pci_1_3, @@ -290,7 +290,26 @@ static QEMUMachine pc_machine_v1_3 = { .is_default = 1, }; +#define PC_COMPAT_1_3 \ + {\ + .driver = "usb-tablet",\ + .property = "usb_version",\ + .value = stringify(1),\ + } + +static QEMUMachine pc_machine_v1_3 = { + .name = "pc-1.3", + .desc = "Standard PC", + .init = pc_init_pci_1_3, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_3, + { /* end of list */ } + }, +}; + #define PC_COMPAT_1_2 \ + PC_COMPAT_1_3,\ {\ .driver = "nec-usb-xhci",\ .property = "msi",\ @@ -626,6 +645,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_machine_v1_4); qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); qemu_register_machine(&pc_machine_v1_1); diff --git a/hw/pm_smbus.c b/hw/pm_smbus.c index 5d6046de5a..ea1380ca68 100644 --- a/hw/pm_smbus.c +++ b/hw/pm_smbus.c @@ -94,10 +94,11 @@ static void smb_transaction(PMSMBus *s) s->smb_stat |= 0x04; } -void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { PMSMBus *s = opaque; - addr &= 0x3f; + SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val); switch(addr) { case SMBHSTSTS: @@ -131,12 +132,11 @@ void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) } } -uint32_t smb_ioport_readb(void *opaque, uint32_t addr) +static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) { PMSMBus *s = opaque; uint32_t val; - addr &= 0x3f; switch(addr) { case SMBHSTSTS: val = s->smb_stat; @@ -170,7 +170,16 @@ uint32_t smb_ioport_readb(void *opaque, uint32_t addr) return val; } +static const MemoryRegionOps pm_smbus_ops = { + .read = smb_ioport_readb, + .write = smb_ioport_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + void pm_smbus_init(DeviceState *parent, PMSMBus *smb) { smb->smbus = i2c_init_bus(parent, "i2c"); + memory_region_init_io(&smb->io, &pm_smbus_ops, smb, "pm-smbus", 64); } diff --git a/hw/pm_smbus.h b/hw/pm_smbus.h index 4750a409f9..e3069bf7d4 100644 --- a/hw/pm_smbus.h +++ b/hw/pm_smbus.h @@ -3,6 +3,7 @@ typedef struct PMSMBus { i2c_bus *smbus; + MemoryRegion io; uint8_t smb_stat; uint8_t smb_ctl; @@ -15,7 +16,5 @@ typedef struct PMSMBus { } PMSMBus; void pm_smbus_init(DeviceState *parent, PMSMBus *smb); -void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val); -uint32_t smb_ioport_readb(void *opaque, uint32_t addr); #endif /* !PM_SMBUS_H */ diff --git a/hw/serial.c b/hw/serial.c index 60283eab91..07a2a11931 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -718,7 +718,7 @@ const MemoryRegionOps serial_io_ops = { }; SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr) + CharDriverState *chr, MemoryRegion *system_io) { SerialState *s; @@ -732,7 +732,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase, vmstate_register(NULL, base, &vmstate_serial, s); memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); - memory_region_add_subregion(get_system_io(), base, &s->io); + memory_region_add_subregion(system_io, base, &s->io); return s; } diff --git a/hw/serial.h b/hw/serial.h index f1e3c4aaa7..ed1a5cd43e 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -89,7 +89,7 @@ void serial_set_frequency(SerialState *s, uint32_t frequency); /* legacy pre qom */ SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr); + CharDriverState *chr, MemoryRegion *system_io); SerialState *serial_mm_init(MemoryRegion *address_space, hwaddr base, int it_shift, qemu_irq irq, int baudbase, diff --git a/hw/smbus_ich9.c b/hw/smbus_ich9.c index 6940583bb6..4194785d71 100644 --- a/hw/smbus_ich9.c +++ b/hw/smbus_ich9.c @@ -40,7 +40,6 @@ typedef struct ICH9SMBState { PCIDevice dev; PMSMBus smb; - MemoryRegion mem_bar; } ICH9SMBState; static const VMStateDescription vmstate_ich9_smbus = { @@ -54,42 +53,23 @@ static const VMStateDescription vmstate_ich9_smbus = { } }; -static void ich9_smb_ioport_writeb(void *opaque, hwaddr addr, - uint64_t val, unsigned size) +static void ich9_smbus_write_config(PCIDevice *d, uint32_t address, + uint32_t val, int len) { - ICH9SMBState *s = opaque; - uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC]; - - if ((hostc & ICH9_SMB_HOSTC_HST_EN) && !(hostc & ICH9_SMB_HOSTC_I2C_EN)) { - uint64_t offset = addr - s->dev.io_regions[ICH9_SMB_SMB_BASE_BAR].addr; - smb_ioport_writeb(&s->smb, offset, val); - } -} - -static uint64_t ich9_smb_ioport_readb(void *opaque, hwaddr addr, - unsigned size) -{ - ICH9SMBState *s = opaque; - uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC]; + ICH9SMBState *s = ICH9_SMB_DEVICE(d); - if ((hostc & ICH9_SMB_HOSTC_HST_EN) && !(hostc & ICH9_SMB_HOSTC_I2C_EN)) { - uint64_t offset = addr - s->dev.io_regions[ICH9_SMB_SMB_BASE_BAR].addr; - return smb_ioport_readb(&s->smb, offset); + pci_default_write_config(d, address, val, len); + if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) { + uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC]; + if ((hostc & ICH9_SMB_HOSTC_HST_EN) && + !(hostc & ICH9_SMB_HOSTC_I2C_EN)) { + memory_region_set_enabled(&s->smb.io, true); + } else { + memory_region_set_enabled(&s->smb.io, false); + } } - - return 0xff; } -static const MemoryRegionOps lpc_smb_mmio_ops = { - .read = ich9_smb_ioport_readb, - .write = ich9_smb_ioport_writeb, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - static int ich9_smbus_initfn(PCIDevice *d) { ICH9SMBState *s = ICH9_SMB_DEVICE(d); @@ -98,26 +78,11 @@ static int ich9_smbus_initfn(PCIDevice *d) pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */ pci_set_byte(d->config + ICH9_SMB_HOSTC, 0); - - /* - * update parameters based on - * paralell_hds[0] - * serial_hds[0] - * serial_hds[0] - * fdc - * - * Is there any OS that depends on them? - */ - - /* TODO smb_io_base */ - pci_set_byte(d->config + ICH9_SMB_HOSTC, 0); /* TODO bar0, bar1: 64bit BAR support*/ - memory_region_init_io(&s->mem_bar, &lpc_smb_mmio_ops, s, "ich9-smbus-bar", - ICH9_SMB_SMB_BASE_SIZE); - pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO, - &s->mem_bar); pm_smbus_init(&d->qdev, &s->smb); + pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO, + &s->smb.io); return 0; } @@ -134,6 +99,7 @@ static void ich9_smb_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ich9_smbus; dc->desc = "ICH9 SMBUS Bridge"; k->init = ich9_smbus_initfn; + k->config_write = ich9_smbus_write_config; } i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base) @@ -197,6 +197,7 @@ struct USBEndpoint { enum USBDeviceFlags { USB_DEV_FLAG_FULL_PATH, + USB_DEV_FLAG_IS_HOST, }; /* definition of a USB device */ @@ -229,6 +230,7 @@ struct USBDevice { USBEndpoint ep_out[USB_MAX_ENDPOINTS]; QLIST_HEAD(, USBDescString) strings; + const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */ const USBDescDevice *device; int configuration; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 55d0edd5c3..8264c240ee 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -166,6 +166,9 @@ const char *usb_device_get_product_desc(USBDevice *dev) const USBDesc *usb_device_get_usb_desc(USBDevice *dev) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (dev->usb_desc) { + return dev->usb_desc; + } return klass->usb_desc; } diff --git a/hw/usb/core.c b/hw/usb/core.c index 52b53108cd..8e360d3ec0 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -406,7 +406,11 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p) if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) { usb_process_one(p); if (p->status == USB_RET_ASYNC) { + /* hcd drivers cannot handle async for isoc */ assert(p->ep->type != USB_ENDPOINT_XFER_ISOC); + /* using async for interrupt packets breaks migration */ + assert(p->ep->type != USB_ENDPOINT_XFER_INT || + (dev->flags & USB_DEV_FLAG_IS_HOST)); usb_packet_set_state(p, USB_PACKET_ASYNC); QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); } else if (p->status == USB_RET_ADD_TO_QUEUE) { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 55266b18ef..87491284a8 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -46,6 +46,7 @@ typedef struct USBHIDState { USBDevice dev; USBEndpoint *intr; HIDState hid; + uint32_t usb_version; } USBHIDState; enum { @@ -131,6 +132,36 @@ static const USBDescIface desc_iface_tablet = { }, }; +static const USBDescIface desc_iface_tablet2 = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceProtocol = 0x02, + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_HID, /* u8 bDescriptorType */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type: Report */ + 74, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 8, + .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */ + }, + }, +}; + static const USBDescIface desc_iface_keyboard = { .bInterfaceNumber = 0, .bNumEndpoints = 1, @@ -196,6 +227,23 @@ static const USBDescDevice desc_device_tablet = { }, }; +static const USBDescDevice desc_device_tablet2 = { + .bcdUSB = 0x0200, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_TABLET, + .bmAttributes = 0xa0, + .bMaxPower = 50, + .nif = 1, + .ifs = &desc_iface_tablet2, + }, + }, +}; + static const USBDescDevice desc_device_keyboard = { .bcdUSB = 0x0100, .bMaxPacketSize0 = 8, @@ -239,6 +287,20 @@ static const USBDesc desc_tablet = { .str = desc_strings, }; +static const USBDesc desc_tablet2 = { + .id = { + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_TABLET, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_tablet, + .high = &desc_device_tablet2, + .str = desc_strings, +}; + static const USBDesc desc_keyboard = { .id = { .idVendor = 0x0627, @@ -508,6 +570,21 @@ static int usb_hid_initfn(USBDevice *dev, int kind) static int usb_tablet_initfn(USBDevice *dev) { + USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); + + switch (us->usb_version) { + case 1: + dev->usb_desc = &desc_tablet; + break; + case 2: + dev->usb_desc = &desc_tablet2; + break; + default: + error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)", + us->usb_version); + return -1; + } + return usb_hid_initfn(dev, HID_TABLET); } @@ -562,8 +639,14 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_hid_handle_control; uc->handle_data = usb_hid_handle_data; uc->handle_destroy = usb_hid_handle_destroy; + uc->handle_attach = usb_desc_attach; } +static Property usb_tablet_properties[] = { + DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), + DEFINE_PROP_END_OF_LIST(), +}; + static void usb_tablet_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -572,8 +655,8 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) usb_hid_class_initfn(klass, data); uc->init = usb_tablet_initfn; uc->product_desc = "QEMU USB Tablet"; - uc->usb_desc = &desc_tablet; dc->vmsd = &vmstate_usb_ptr; + dc->props = usb_tablet_properties; } static TypeInfo usb_tablet_info = { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 9ee60dd412..470fbbb86c 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -184,6 +184,7 @@ static void usb_hub_detach(USBPort *port1) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } + usb_wakeup(s->intr); } static void usb_hub_child_detach(USBPort *port1, USBDevice *child) @@ -363,6 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ port->wPortStatus |= PORT_STAT_ENABLE; + usb_wakeup(s->intr); } break; case PORT_POWER: diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 14d9e5aa5b..30cb03373e 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -639,6 +639,8 @@ typedef struct USBNetState { unsigned int in_ptr, in_len; uint8_t in_buf[2048]; + USBEndpoint *intr; + char usbstring_mac[13]; NICState *nic; NICConf conf; @@ -851,6 +853,10 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length) struct rndis_response *r = g_malloc0(sizeof(struct rndis_response) + length); + if (QTAILQ_EMPTY(&s->rndis_resp)) { + usb_wakeup(s->intr); + } + QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); r->length = length; @@ -1349,6 +1355,7 @@ static int usb_net_initfn(USBDevice *dev) s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; s->filter = 0; s->vendorid = 0x1234; + s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 08b416daa6..f7342b08c3 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -43,6 +43,7 @@ typedef struct USBWacomState { USBDevice dev; + USBEndpoint *intr; QEMUPutMouseEntry *eh_entry; int dx, dy, dz, buttons_state; int x, y; @@ -137,6 +138,7 @@ static void usb_mouse_event(void *opaque, s->dz += dz1; s->buttons_state = buttons_state; s->changed = 1; + usb_wakeup(s->intr); } static void usb_wacom_event(void *opaque, @@ -150,6 +152,7 @@ static void usb_wacom_event(void *opaque, s->dz += dz; s->buttons_state = buttons_state; s->changed = 1; + usb_wakeup(s->intr); } static inline int int_clamp(int val, int vmin, int vmax) @@ -337,6 +340,7 @@ static int usb_wacom_initfn(USBDevice *dev) USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev); usb_desc_create_serial(dev); usb_desc_init(dev); + s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); s->changed = 1; return 0; } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 7df8e21ecb..7536837fb2 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -114,6 +114,7 @@ #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_QH 100 // Max allowable queue heads in a chain #define MIN_FR_PER_TICK 3 // Min frames to process when catching up +#define PERIODIC_ACTIVE 64 /* Internal periodic / asynchronous schedule state machine states */ @@ -738,6 +739,19 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], return 0; } +static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) +{ + EHCIState *s = container_of(bus, EHCIState, bus); + uint32_t portsc = s->portsc[ep->dev->port->index]; + + if (portsc & PORTSC_POWNER) { + return; + } + + s->periodic_sched_active = PERIODIC_ACTIVE; + qemu_bh_schedule(s->async_bh); +} + static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr) { USBDevice *dev; @@ -1188,9 +1202,10 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) trace_usb_ehci_packet_action(p->queue, p, "wakeup"); p->async = EHCI_ASYNC_FINISHED; - if (p->queue->async) { - qemu_bh_schedule(p->queue->ehci->async_bh); + if (!p->queue->async) { + s->periodic_sched_active = PERIODIC_ACTIVE; } + qemu_bh_schedule(s->async_bh); } static void ehci_execute_complete(EHCIQueue *q) @@ -1344,6 +1359,8 @@ static int ehci_process_itd(EHCIState *ehci, uint32_t i, len, pid, dir, devaddr, endp; uint32_t pg, off, ptr1, ptr2, max, mult; + ehci->periodic_sched_active = PERIODIC_ACTIVE; + dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION); devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR); endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP); @@ -2033,6 +2050,9 @@ static void ehci_advance_state(EHCIState *ehci, int async) case EST_WRITEBACK: assert(q != NULL); again = ehci_state_writeback(q); + if (!async) { + ehci->periodic_sched_active = PERIODIC_ACTIVE; + } break; default: @@ -2198,7 +2218,6 @@ static void ehci_frame_timer(void *opaque) if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { need_timer++; - ehci->async_stepdown = 0; if (frames > ehci->maxframes) { skipped_frames = frames - ehci->maxframes; @@ -2222,18 +2241,25 @@ static void ehci_frame_timer(void *opaque) break; } } + if (ehci->periodic_sched_active) { + ehci->periodic_sched_active--; + } ehci_update_frindex(ehci, 1); ehci_advance_periodic_state(ehci); ehci->last_run_ns += FRAME_TIMER_NS; } } else { - if (ehci->async_stepdown < ehci->maxframes / 2) { - ehci->async_stepdown++; - } + ehci->periodic_sched_active = 0; ehci_update_frindex(ehci, frames); ehci->last_run_ns += FRAME_TIMER_NS * frames; } + if (ehci->periodic_sched_active) { + ehci->async_stepdown = 0; + } else if (ehci->async_stepdown < ehci->maxframes / 2) { + ehci->async_stepdown++; + } + /* Async is not inside loop since it executes everything it can once * called */ @@ -2301,6 +2327,7 @@ static USBPortOps ehci_port_ops = { static USBBusOps ehci_bus_ops = { .register_companion = ehci_register_companion, + .wakeup_endpoint = ehci_wakeup_endpoint, }; static int usb_ehci_post_load(void *opaque, int version_id) diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index d8078f4555..772870b727 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -311,6 +311,7 @@ struct EHCIState { uint64_t last_run_ns; uint32_t async_stepdown; + uint32_t periodic_sched_active; bool int_req_by_async; }; diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index 6473e8b747..dae0009378 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -292,6 +292,7 @@ static void usb_host_handle_destroy(USBDevice *opaque) static int usb_host_initfn(USBDevice *dev) { + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); return 0; } diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index aa77b7704d..bdafb6bc87 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1476,6 +1476,7 @@ static int usb_host_initfn(USBDevice *dev) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); dev->auto_attach = 0; s->fd = -1; s->hub_fd = -1; diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 490c90fae1..9e7f6453f7 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1644,6 +1644,10 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, return; } + if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { + usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f)); + } + /* bufp_alloc also adds the packet to the ep queue */ bufp_alloc(dev, data, data_len, interrupt_packet->status, ep); } else { diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 5d7c00cf4b..57d16c0134 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -24,6 +24,7 @@ #include "pm_smbus.h" #include "sysemu.h" #include "qemu-timer.h" +#include "exec-memory.h" typedef uint32_t pci_addr_t; #include "pci_host.h" @@ -159,6 +160,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address, typedef struct VT686PMState { PCIDevice dev; + MemoryRegion io; ACPIREGS ar; APMState apm; PMSMBus smb; @@ -195,92 +197,17 @@ static void pm_tmr_timer(ACPIREGS *ar) pm_update_sci(s); } -static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - VT686PMState *s = opaque; - - addr &= 0x0f; - switch (addr) { - case 0x00: - acpi_pm1_evt_write_sts(&s->ar, val); - pm_update_sci(s); - break; - case 0x02: - acpi_pm1_evt_write_en(&s->ar, val); - pm_update_sci(s); - break; - case 0x04: - acpi_pm1_cnt_write(&s->ar, val, 0); - break; - default: - break; - } - DPRINTF("PM writew port=0x%04x val=0x%02x\n", addr, val); -} - -static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) -{ - VT686PMState *s = opaque; - uint32_t val; - - addr &= 0x0f; - switch (addr) { - case 0x00: - val = acpi_pm1_evt_get_sts(&s->ar); - break; - case 0x02: - val = s->ar.pm1.evt.en; - break; - case 0x04: - val = s->ar.pm1.cnt.cnt; - break; - default: - val = 0; - break; - } - DPRINTF("PM readw port=0x%04x val=0x%02x\n", addr, val); - return val; -} - -static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - addr &= 0x0f; - DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr, val); -} - -static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) -{ - VT686PMState *s = opaque; - uint32_t val; - - addr &= 0x0f; - switch (addr) { - case 0x08: - val = acpi_pm_tmr_get(&s->ar); - break; - default: - val = 0; - break; - } - DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val); - return val; -} - static void pm_io_space_update(VT686PMState *s) { uint32_t pm_io_base; - if (s->dev.config[0x80] & 1) { - pm_io_base = pci_get_long(s->dev.config + 0x40); - pm_io_base &= 0xffc0; + pm_io_base = pci_get_long(s->dev.config + 0x40); + pm_io_base &= 0xffc0; - /* XXX: need to improve memory and ioport allocation */ - DPRINTF("PM: mapping to 0x%x\n", pm_io_base); - register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); - register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); - register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); - register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); - } + memory_region_transaction_begin(); + memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1); + memory_region_set_address(&s->io, pm_io_base); + memory_region_transaction_commit(); } static void pm_write_config(PCIDevice *d, @@ -424,15 +351,18 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) pci_conf[0x90] = s->smb_io_base | 1; pci_conf[0x91] = s->smb_io_base >> 8; pci_conf[0xd2] = 0x90; - register_ioport_write(s->smb_io_base, 0xf, 1, smb_ioport_writeb, &s->smb); - register_ioport_read(s->smb_io_base, 0xf, 1, smb_ioport_readb, &s->smb); + pm_smbus_init(&s->dev.qdev, &s->smb); + memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); - apm_init(&s->apm, NULL, s); + apm_init(dev, &s->apm, NULL, s); - acpi_pm_tmr_init(&s->ar, pm_tmr_timer); - acpi_pm1_cnt_init(&s->ar); + memory_region_init(&s->io, "vt82c686-pm", 64); + memory_region_set_enabled(&s->io, false); + memory_region_add_subregion(get_system_io(), 0, &s->io); - pm_smbus_init(&s->dev.qdev, &s->smb); + acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_cnt_init(&s->ar, &s->io); return 0; } |