[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug.
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug. |
Date: |
Tue, 09 Oct 2012 10:04:13 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20120911 Thunderbird/15.0.1 |
Il 09/10/2012 05:30, Jason Baron ha scritto:
> From: Jason Baron <address@hidden>
>
> Add piix style acpi hotplug to q35.
>
> Signed-off-by: Jason Baron <address@hidden>
Not a thorough review, but it looks good.
Paolo
> ---
> hw/acpi_ich9.c | 172
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> hw/acpi_ich9.h | 10 +++
> 2 files changed, 181 insertions(+), 1 deletions(-)
>
> diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
> index 1412ad3..412c9c1 100644
> --- a/hw/acpi_ich9.c
> +++ b/hw/acpi_ich9.c
> @@ -41,6 +41,13 @@ do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while
> (0)
> #define ICH9_DEBUG(fmt, ...) do { } while (0)
> #endif
>
> +#define PCI_UP_BASE 0xae00
> +#define PCI_DOWN_BASE 0xae04
> +#define PCI_EJ_BASE 0xae08
> +#define PCI_RMV_BASE 0xae0c
> +#define ICH9_PCI_HOTPLUG_STATUS 2
> +
> +
> 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);
> @@ -55,7 +62,10 @@ static void pm_update_sci(ICH9LPCPMRegs *pm)
> (ACPI_BITMASK_RT_CLOCK_ENABLE |
> ACPI_BITMASK_POWER_BUTTON_ENABLE |
> ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
> - ACPI_BITMASK_TIMER_ENABLE)) != 0);
> + ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
> + (((pm->acpi_regs.gpe.sts[0] & pm->acpi_regs.gpe.en[0])
> + & ICH9_PCI_HOTPLUG_STATUS) != 0);
> +
> qemu_set_irq(pm->irq, sci_level);
>
> /* schedule a timer interruption if needed */
> @@ -77,6 +87,7 @@ static void pm_ioport_writeb(void *opaque, uint32_t addr,
> uint32_t val)
> 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);
> + pm_update_sci(pm);
> break;
> default:
> break;
> @@ -283,6 +294,65 @@ const VMStateDescription vmstate_ich9_pm = {
> }
> };
>
> +static void acpi_ich9_eject_slot(ICH9LPCPMRegs *opaque, unsigned slots)
> +{
> + BusChild *kid, *next;
> + ICH9LPCPMRegs *pm = opaque;
> + ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm);
> + PCIDevice *s = PCI_DEVICE(lpc);
> + BusState *bus = qdev_get_parent_bus(&s->qdev);
> + int slot = ffs(slots) - 1;
> + bool slot_free = true;
> +
> + /* Mark request as complete */
> + pm->pci0_status.down &= ~(1U << slot);
> +
> + QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
> + DeviceState *qdev = kid->child;
> + PCIDevice *dev = PCI_DEVICE(qdev);
> + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
> + if (PCI_SLOT(dev->devfn) == slot) {
> + if (pc->no_hotplug) {
> + slot_free = false;
> + } else {
> + qdev_free(qdev);
> + }
> + }
> + }
> + if (slot_free) {
> + pm->pci0_slot_device_present &= ~(1U << slot);
> + }
> +}
> +
> +static void acpi_ich9_update_hotplug(ICH9LPCPMRegs *pm)
> +{
> + ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm);
> + PCIDevice *dev = PCI_DEVICE(lpc);
> + BusState *bus = qdev_get_parent_bus(&dev->qdev);
> + BusChild *kid, *next;
> +
> + /* Execute any pending removes during reset */
> + while (pm->pci0_status.down) {
> + acpi_ich9_eject_slot(pm, pm->pci0_status.down);
> + }
> +
> + pm->pci0_hotplug_enable = ~0;
> + pm->pci0_slot_device_present = 0;
> +
> + QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
> + DeviceState *qdev = kid->child;
> + PCIDevice *pdev = PCI_DEVICE(qdev);
> + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
> + int slot = PCI_SLOT(pdev->devfn);
> +
> + if (pc->no_hotplug) {
> + pm->pci0_hotplug_enable &= ~(1U << slot);
> + }
> +
> + pm->pci0_slot_device_present |= (1U << slot);
> + }
> +}
> +
> static void pm_reset(void *opaque)
> {
> ICH9LPCPMRegs *pm = opaque;
> @@ -300,6 +370,7 @@ static void pm_reset(void *opaque)
> }
>
> pm_update_sci(pm);
> + acpi_ich9_update_hotplug(pm);
> }
>
> static void pm_powerdown_req(Notifier *n, void *opaque)
> @@ -309,6 +380,104 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
> acpi_pm1_evt_power_down(&pm->acpi_regs);
> }
>
> +static uint32_t pci_up_read(void *opaque, uint32_t addr)
> +{
> + ICH9LPCPMRegs *pm = opaque;
> + uint32_t val;
> +
> + /* Manufacture an "up" value to cause a device check on any hotplug
> + * slot with a device. Extra device checks are harmless. */
> + val = pm->pci0_slot_device_present & pm->pci0_hotplug_enable;
> +
> + ICH9_DEBUG("pci_up_read %x\n", val);
> + return val;
> +}
> +
> +static uint32_t pci_down_read(void *opaque, uint32_t addr)
> +{
> + ICH9LPCPMRegs *pm = opaque;
> + uint32_t val = pm->pci0_status.down;
> +
> + ICH9_DEBUG("pci_down_read %x\n", val);
> + return val;
> +}
> +
> +static uint32_t pci_features_read(void *opaque, uint32_t addr)
> +{
> + /* No feature defined yet */
> + ICH9_DEBUG("pci_features_read %x\n", 0);
> + return 0;
> +}
> +
> +static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
> +{
> + acpi_ich9_eject_slot(opaque, val);
> +
> + ICH9_DEBUG("pciej write %x <== %d\n", addr, val);
> +}
> +
> +static uint32_t pcirmv_read(void *opaque, uint32_t addr)
> +{
> + ICH9LPCPMRegs *pm = opaque;
> +
> + return pm->pci0_hotplug_enable;
> +}
> +
> +static void enable_device(ICH9LPCPMRegs *pm, int slot)
> +{
> + pm->acpi_regs.gpe.sts[0] |= ICH9_PCI_HOTPLUG_STATUS;
> + pm->pci0_slot_device_present |= (1U << slot);
> +}
> +
> +static void disable_device(ICH9LPCPMRegs *pm, int slot)
> +{
> + pm->acpi_regs.gpe.sts[0] |= ICH9_PCI_HOTPLUG_STATUS;
> + pm->pci0_status.down |= (1U << slot);
> +}
> +
> +static int ich9_device_hotplug(DeviceState *qdev, PCIDevice *dev,
> + PCIHotplugState state)
> +{
> + int slot = PCI_SLOT(dev->devfn);
> + ICH9LPCState *lpc = DO_UPCAST(ICH9LPCState, d,
> + PCI_DEVICE(qdev));
> + ICH9LPCPMRegs *pm = &lpc->pm;
> +
> + /* Don't send event when device is enabled during qemu machine creation:
> + * it is present on boot, no hotplug event is necessary. We do send an
> + * event when the device is disabled later. */
> + if (state == PCI_COLDPLUG_ENABLED) {
> + pm->pci0_slot_device_present |= (1U << slot);
> + return 0;
> + }
> +
> + if (state == PCI_HOTPLUG_ENABLED) {
> + enable_device(pm, slot);
> + } else {
> + disable_device(pm, slot);
> + }
> +
> + pm_update_sci(pm);
> +
> + return 0;
> +}
> +
> +static void ich9_acpi_system_hot_add_init(ICH9LPCPMRegs *s)
> +{
> + ICH9LPCState *lpc = container_of(s, ICH9LPCState, pm);
> + PCIDevice *pdev = PCI_DEVICE(lpc);
> +
> + 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);
> +
> + pci_bus_hotplug(pdev->bus, ich9_device_hotplug, &pdev->qdev);
> +}
> +
> 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);
> @@ -319,4 +488,5 @@ void ich9_pm_init(ICH9LPCPMRegs *pm, qemu_irq sci_irq,
> qemu_irq cmos_s3)
> qemu_register_reset(pm_reset, pm);
> pm->powerdown_notifier.notify = pm_powerdown_req;
> qemu_register_powerdown_notifier(&pm->powerdown_notifier);
> + ich9_acpi_system_hot_add_init(pm);
> }
> diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h
> index 180c406..b4e2aff 100644
> --- a/hw/acpi_ich9.h
> +++ b/hw/acpi_ich9.h
> @@ -23,6 +23,11 @@
>
> #include "acpi.h"
>
> +struct pci_status {
> + uint32_t up; /* deprecated, maintained for migration compatibility */
> + uint32_t down;
> +};
> +
> typedef struct ICH9LPCPMRegs {
> /*
> * In ich9 spec says that pm1_cnt register is 32bit width and
> @@ -37,6 +42,11 @@ typedef struct ICH9LPCPMRegs {
>
> uint32_t pm_io_base;
> Notifier powerdown_notifier;
> +
> + /* for pci hotplug */
> + struct pci_status pci0_status;
> + uint32_t pci0_hotplug_enable;
> + uint32_t pci0_slot_device_present;
> } ICH9LPCPMRegs;
>
> void ich9_pm_init(ICH9LPCPMRegs *pm,
>
- Re: [Qemu-devel] [PATCH v2 18/21] q35: Fix irr initialization for slots 25..31, (continued)
- [Qemu-devel] [PATCH v2 12/21] q35: Introduce q35 pc based chipset emulator, Jason Baron, 2012/10/08
- [Qemu-devel] [PATCH v2 20/21] q35: automatically load the q35 dsdt table, Jason Baron, 2012/10/08
- [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Jason Baron, 2012/10/08
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug.,
Paolo Bonzini <=
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Michael S. Tsirkin, 2012/10/11
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Jason Baron, 2012/10/11
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Michael S. Tsirkin, 2012/10/11
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Jason Baron, 2012/10/12
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Michael S. Tsirkin, 2012/10/13
- Re: [Qemu-devel] [PATCH v2 21/21] q35: add acpi-based pci hotplug., Gerd Hoffmann, 2012/10/12