diff --git a/hw/acpi.c b/hw/acpi.c index f4aca493fc..ae29a59077 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -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) { diff --git a/hw/acpi.h b/hw/acpi.h index 7337f41857..afda153d09 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -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) +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 uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width) { 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; + switch (addr) { + case 0: + return pm->smi_en; + case 4: + return pm->smi_sts; default: - pm_ioport_write_fallback(opaque, addr, 2, val); - break; + return 0; } - ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val); } -static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) +static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, + 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; - default: - val = pm_ioport_read_fallback(opaque, addr, 2); - break; - } - 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) -{ - 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 dbddde13ab..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) @@ -440,8 +393,6 @@ static int piix4_pm_initfn(PCIDevice *dev) /* APM */ apm_init(dev, &s->apm, apm_ctrl_changed, s); - register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); - if (s->kvm_enabled) { /* Mark SMM as already inited to prevent SMM from running. KVM does not * support SMM mode. */ @@ -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); - acpi_pm_tmr_init(&s->ar, pm_tmr_timer); + 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, &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) { + 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); - 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_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); } diff --git a/hw/ich9.h b/hw/ich9.h index de491350c3..34e216f142 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -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/lpc_ich9.c b/hw/lpc_ich9.c index 7de5427a69..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); @@ -473,6 +498,10 @@ static int ich9_lpc_initfn(PCIDevice *d) ich9_cc_init(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/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/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]; + 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; - smb_ioport_writeb(&s->smb, offset, val); + 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); + } } } -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]; - - 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); - } - - 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); @@ -97,27 +77,12 @@ static int ich9_smbus_initfn(PCIDevice *d) /* TODO? D31IP.SMIP in chipset configuration space */ 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) diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 7f11dbe782..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(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; }