[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 23/25] q35: add acpi-based pci hotplug.
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH 23/25] q35: add acpi-based pci hotplug. |
Date: |
Fri, 14 Sep 2012 18:56:13 +0000 |
On Thu, Sep 13, 2012 at 8:12 PM, Jason Baron <address@hidden> wrote:
> Add piix style acpi hotplug to q35.
>
> Signed-off-by: Jason Baron <address@hidden>
> ---
> hw/acpi_ich9.c | 173
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> hw/acpi_ich9.h | 10 +++
> 2 files changed, 182 insertions(+), 1 deletions(-)
>
> diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
> index 570ce0c..ba463a0 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(ICH9_LPCPmRegs *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(ICH9_LPCPmRegs *opaque, unsigned slots)
> +{
> + BusChild *kid, *next;
> + ICH9_LPCPmRegs *pm = opaque;
> + ICH9_LPCState *lpc = container_of(pm, ICH9_LPCState, 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(ICH9_LPCPmRegs *pm)
> +{
> + ICH9_LPCState *lpc = container_of(pm, ICH9_LPCState, 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)
> {
> ICH9_LPCPmRegs *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(void *opaque, int irq, int power_failing)
> @@ -309,6 +380,104 @@ static void pm_powerdown(void *opaque, int irq, int
> power_failing)
> acpi_pm1_evt_power_down(&pm->acpi_regs);
> }
>
> +static uint32_t pci_up_read(void *opaque, uint32_t addr)
> +{
> + ICH9_LPCPmRegs *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)
> +{
> + ICH9_LPCPmRegs *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)
> +{
> + ICH9_LPCPmRegs *pm = opaque;
> +
> + return pm->pci0_hotplug_enable;
> +}
> +
> +static void enable_device(ICH9_LPCPmRegs *pm, int slot)
> +{
> + pm->acpi_regs.gpe.sts[0] |= ICH9_PCI_HOTPLUG_STATUS;
> + pm->pci0_slot_device_present |= (1U << slot);
> +}
> +
> +static void disable_device(ICH9_LPCPmRegs *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);
> + ICH9_LPCState *lpc = DO_UPCAST(ICH9_LPCState, d,
> + PCI_DEVICE(qdev));
> + ICH9_LPCPmRegs *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(ICH9_LPCPmRegs *s)
> +{
> + ICH9_LPCState *lpc = container_of(s, ICH9_LPCState, pm);
> + PCIDevice *pdev = PCI_DEVICE(lpc);
> +
> + register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s);
Please convert these to MemoryRegionPortio.
> + 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(ICH9_LPCPmRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3)
> {
> acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn);
> @@ -318,4 +487,6 @@ void ich9_pm_init(ICH9_LPCPmRegs *pm, qemu_irq sci_irq,
> qemu_irq cmos_s3)
> pm->irq = sci_irq;
> qemu_register_reset(pm_reset, pm);
> qemu_system_powerdown = *qemu_allocate_irqs(pm_powerdown, pm, 1);
> +
> + ich9_acpi_system_hot_add_init(pm);
> }
> diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h
> index 9ff4c42..434e221 100644
> --- a/hw/acpi_ich9.h
> +++ b/hw/acpi_ich9.h
> @@ -23,6 +23,11 @@
>
> #include "acpi.h"
>
> +struct pci_status {
PCIStatus, typedef missing
> + uint32_t up; /* deprecated, maintained for migration compatibility */
> + uint32_t down;
> +};
> +
> typedef struct ICH9_LPCPmRegs {
> /*
> * In ich9 spec says that pm1_cnt register is 32bit width and
> @@ -36,6 +41,11 @@ typedef struct ICH9_LPCPmRegs {
> qemu_irq irq; /* SCI */
>
> uint32_t pm_io_base;
> +
> + /* for pci hotplug */
> + struct pci_status pci0_status;
> + uint32_t pci0_hotplug_enable;
> + uint32_t pci0_slot_device_present;
> } ICH9_LPCPmRegs;
>
> void ich9_pm_init(ICH9_LPCPmRegs *pm,
> --
> 1.7.1
>
>
- Re: [Qemu-devel] [PATCH 24/25] Add a fallback bios file search, if -L fails., (continued)
- [Qemu-devel] [PATCH 16/25] pci: Add class 0xc05 as 'SMBus', Jason Baron, 2012/09/13
- [Qemu-devel] [PATCH 18/25] q35: Fix irr initialization for slots 25..31, Jason Baron, 2012/09/13
- [Qemu-devel] [PATCH 23/25] q35: add acpi-based pci hotplug., Jason Baron, 2012/09/13
- Re: [Qemu-devel] [PATCH 23/25] q35: add acpi-based pci hotplug.,
Blue Swirl <=
- [Qemu-devel] [PATCH 12/25] q35: Re-base q35 to 1.2, Jason Baron, 2012/09/13
- Re: [Qemu-devel] [PATCH 00/25] q35 series take #1, Alexander Graf, 2012/09/13
Re: [Qemu-devel] [PATCH 00/25] q35 series take #1, Isaku Yamahata, 2012/09/14