acpi,pc,pci fixes and enhancements

Most changes here are hotplug related:
 
 This merges hotplug infrastructure changes by Igor,
 some acpi related fixes, and PC fixes.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJS+Jg2AAoJECgfDbjSjVRp2hIH/3PezOqYAJlp1LzHPYgTII5R
 ZWdlHWJODB5QKGuDnJ0rKTZn+9n4f27Q7ynwqrodrLNtzglfmPUwtjTb52vbd1yh
 qJ7BtvGIewUEjTPVs2feipb75jFZFhvIU46F1jPJAiaNKG0nl6zwVHn5XfFqesv2
 4TlHAoqYvpUUuFcG7Qu+hREUrjb/tdxwP8EYM4qDPOSxguS2R2+3/17BVlPDQGia
 bKl6j5EmnmmbQ0h8Sepy3YKh9d1rZnKFsolMFrL8ITjzEzzyKjpE284GNe/5eY25
 HR25dY5eYTb0d3QPeH2O5sOrZgOFpTZc8WOo9Kxi0OTjWxFoZstZ1AOM3A2DAoY=
 =EtLZ
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

acpi,pc,pci fixes and enhancements

Most changes here are hotplug related:

This merges hotplug infrastructure changes by Igor,
some acpi related fixes, and PC fixes.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Mon 10 Feb 2014 09:13:26 GMT using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream:
  ACPI: Remove commented-out code from HPET._CRS
  hw/pci: switch to a generic hotplug handling for PCIDevice
  pci/pcie: convert PCIE hotplug to use hotplug-handler API
  pci/shpc: convert SHPC hotplug to use hotplug-handler API
  acpi/piix4pm: convert ACPI PCI hotplug to use hotplug-handler API
  qdev:pci: refactor PCIDevice to use generic "hotpluggable" property
  hw/acpi: move typeinfo to the file end
  qdev: add "hotpluggable" property to Device
  qdev: add to BusState "hotplug-handler" link
  define hotplug interface
  loader: document that errno is set
  pc.c: better error message on initrd sizing failure
  pc_piix: enable legacy hotplug for Xen
  qtest: don't report signals if qtest driver enabled
  hw:piix4:acpi: reuse pcihp code for legacy PCI hotplug
  pcihp: remove unused AcpiPciHpPciStatus.device_present field
  pcihp: make pci_read() mmio calback compatible with legacy ACPI hotplug
  pcihp: make PCI hotplug mmio handlers indifferent to PCI_HOTPLUG_ADDR
  pcihp: replace enable|disable_device() with oneliners
  pcihp: reduce number of device check events

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-02-13 15:02:03 +00:00
commit 0888a29caa
38 changed files with 542 additions and 463 deletions

View file

@ -46,13 +46,15 @@
# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0)
#endif
#define PCI_HOTPLUG_ADDR 0xae00
#define PCI_HOTPLUG_SIZE 0x0014
#define PCI_UP_BASE 0xae00
#define PCI_DOWN_BASE 0xae04
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
#define PCI_SEL_BASE 0xae10
#define ACPI_PCI_HOTPLUG_STATUS 2
#define ACPI_PCIHP_ADDR 0xae00
#define ACPI_PCIHP_SIZE 0x0014
#define ACPI_PCIHP_LEGACY_SIZE 0x000f
#define PCI_UP_BASE 0x0000
#define PCI_DOWN_BASE 0x0004
#define PCI_EJ_BASE 0x0008
#define PCI_RMV_BASE 0x000c
#define PCI_SEL_BASE 0x0010
typedef struct AcpiPciHpFind {
int bsel;
@ -104,19 +106,19 @@ static PCIBus *acpi_pcihp_find_hotplug_bus(AcpiPciHpState *s, int bsel)
static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
{
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
DeviceClass *dc = DEVICE_GET_CLASS(dev);
/*
* ACPI doesn't allow hotplug of bridge devices. Don't allow
* hot-unplug of bridge devices unless they were added by hotplug
* (and so, not described by acpi).
*/
return (pc->is_bridge && !dev->qdev.hotplugged) || pc->no_hotplug;
return (pc->is_bridge && !dev->qdev.hotplugged) || !dc->hotpluggable;
}
static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
{
BusChild *kid, *next;
int slot = ffs(slots) - 1;
bool slot_free = true;
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
if (!bus) {
@ -125,21 +127,17 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
/* Mark request as complete */
s->acpi_pcihp_pci_status[bsel].down &= ~(1U << slot);
s->acpi_pcihp_pci_status[bsel].up &= ~(1U << slot);
QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
DeviceState *qdev = kid->child;
PCIDevice *dev = PCI_DEVICE(qdev);
if (PCI_SLOT(dev->devfn) == slot) {
if (acpi_pcihp_pc_no_hotplug(s, dev)) {
slot_free = false;
} else {
if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
object_unparent(OBJECT(qdev));
}
}
}
if (slot_free) {
s->acpi_pcihp_pci_status[bsel].device_present &= ~(1U << slot);
}
}
static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
@ -153,7 +151,6 @@ static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
}
s->acpi_pcihp_pci_status[bsel].hotplug_enable = ~0;
s->acpi_pcihp_pci_status[bsel].device_present = 0;
if (!bus) {
return;
@ -166,8 +163,6 @@ static void acpi_pcihp_update_hotplug_bus(AcpiPciHpState *s, int bsel)
if (acpi_pcihp_pc_no_hotplug(s, pdev)) {
s->acpi_pcihp_pci_status[bsel].hotplug_enable &= ~(1U << slot);
}
s->acpi_pcihp_pci_status[bsel].device_present |= (1U << slot);
}
}
@ -185,40 +180,47 @@ void acpi_pcihp_reset(AcpiPciHpState *s)
acpi_pcihp_update(s);
}
static void enable_device(AcpiPciHpState *s, unsigned bsel, int slot)
void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
DeviceState *dev, Error **errp)
{
s->acpi_pcihp_pci_status[bsel].device_present |= (1U << slot);
}
static void disable_device(AcpiPciHpState *s, unsigned bsel, int slot)
{
s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
}
int acpi_pcihp_device_hotplug(AcpiPciHpState *s, PCIDevice *dev,
PCIHotplugState state)
{
int slot = PCI_SLOT(dev->devfn);
int bsel = acpi_pcihp_get_bsel(dev->bus);
PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn);
int bsel = acpi_pcihp_get_bsel(pdev->bus);
if (bsel < 0) {
return -1;
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
/* 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) {
s->acpi_pcihp_pci_status[bsel].device_present |= (1U << slot);
return 0;
if (!dev->hotplugged) {
return;
}
if (state == PCI_HOTPLUG_ENABLED) {
enable_device(s, bsel, slot);
} else {
disable_device(s, bsel, slot);
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
ar->gpe.sts[0] |= ACPI_PCI_HOTPLUG_STATUS;
acpi_update_sci(ar, irq);
}
void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
DeviceState *dev, Error **errp)
{
PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn);
int bsel = acpi_pcihp_get_bsel(pdev->bus);
if (bsel < 0) {
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
return 0;
s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
ar->gpe.sts[0] |= ACPI_PCI_HOTPLUG_STATUS;
acpi_update_sci(ar, irq);
}
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
@ -232,26 +234,26 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
}
switch (addr) {
case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
/* Manufacture an "up" value to cause a device check on any hotplug
* slot with a device. Extra device checks are harmless. */
val = s->acpi_pcihp_pci_status[bsel].device_present &
s->acpi_pcihp_pci_status[bsel].hotplug_enable;
case PCI_UP_BASE:
val = s->acpi_pcihp_pci_status[bsel].up;
if (!s->legacy_piix) {
s->acpi_pcihp_pci_status[bsel].up = 0;
}
ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val);
break;
case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
case PCI_DOWN_BASE:
val = s->acpi_pcihp_pci_status[bsel].down;
ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val);
break;
case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
case PCI_EJ_BASE:
/* No feature defined yet */
ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val);
break;
case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
case PCI_RMV_BASE:
val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val);
break;
case PCI_SEL_BASE - PCI_HOTPLUG_ADDR:
case PCI_SEL_BASE:
val = s->hotplug_select;
ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val);
default:
@ -266,7 +268,7 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data,
{
AcpiPciHpState *s = opaque;
switch (addr) {
case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
case PCI_EJ_BASE:
if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
break;
}
@ -274,7 +276,7 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data,
ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
addr, data);
break;
case PCI_SEL_BASE - PCI_HOTPLUG_ADDR:
case PCI_SEL_BASE:
s->hotplug_select = data;
ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n",
addr, data);
@ -294,13 +296,26 @@ static const MemoryRegionOps acpi_pcihp_io_ops = {
};
void acpi_pcihp_init(AcpiPciHpState *s, PCIBus *root_bus,
MemoryRegion *address_space_io)
MemoryRegion *address_space_io, bool bridges_enabled)
{
uint16_t io_size = ACPI_PCIHP_SIZE;
s->root= root_bus;
s->legacy_piix = !bridges_enabled;
if (s->legacy_piix) {
unsigned *bus_bsel = g_malloc(sizeof *bus_bsel);
io_size = ACPI_PCIHP_LEGACY_SIZE;
*bus_bsel = ACPI_PCIHP_BSEL_DEFAULT;
object_property_add_uint32_ptr(OBJECT(root_bus), ACPI_PCIHP_PROP_BSEL,
bus_bsel, NULL);
}
memory_region_init_io(&s->io, NULL, &acpi_pcihp_io_ops, s,
"acpi-pci-hotplug",
PCI_HOTPLUG_SIZE);
memory_region_add_subregion(address_space_io, PCI_HOTPLUG_ADDR, &s->io);
"acpi-pci-hotplug", io_size);
memory_region_add_subregion(address_space_io, ACPI_PCIHP_ADDR, &s->io);
}
const VMStateDescription vmstate_acpi_pcihp_pci_status = {

View file

@ -32,6 +32,7 @@
#include "hw/acpi/piix4.h"
#include "hw/acpi/pcihp.h"
#include "hw/acpi/cpu_hotplug.h"
#include "hw/hotplug.h"
//#define DEBUG
@ -44,15 +45,6 @@
#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
#define PCI_RMV_BASE 0xae0c
#define PIIX4_PCI_HOTPLUG_STATUS 2
struct pci_status {
uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t down;
@ -80,13 +72,6 @@ typedef struct PIIX4PMState {
Notifier machine_ready;
Notifier powerdown_notifier;
/* for legacy pci hotplug (compatible with qemu 1.6 and older) */
MemoryRegion io_pci;
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
uint32_t pci0_slot_device_present;
/* for new pci hotplug (with PCI2PCI bridge support) */
AcpiPciHpState acpi_pci_hotplug;
bool use_acpi_pci_hotplug;
@ -170,17 +155,6 @@ static void pm_write_config(PCIDevice *d,
}
}
static void vmstate_pci_status_pre_save(void *opaque)
{
struct pci_status *pci0_status = opaque;
PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
/* We no longer track up, so build a safe value for migrating
* to a version that still does... of course these might get lost
* by an old buggy implementation, but we try. */
pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
}
static int vmstate_acpi_post_load(void *opaque, int version_id)
{
PIIX4PMState *s = opaque;
@ -216,10 +190,9 @@ static const VMStateDescription vmstate_pci_status = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = vmstate_pci_status_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT32(up, struct pci_status),
VMSTATE_UINT32(down, struct pci_status),
VMSTATE_UINT32(up, struct AcpiPciHpPciStatus),
VMSTATE_UINT32(down, struct AcpiPciHpPciStatus),
VMSTATE_END_OF_LIST()
}
};
@ -256,7 +229,8 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_be16s(f, &temp);
}
ret = vmstate_load_state(f, &vmstate_pci_status, &s->pci0_status, 1);
ret = vmstate_load_state(f, &vmstate_pci_status,
&s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1);
return ret;
}
@ -294,70 +268,18 @@ static const VMStateDescription vmstate_acpi = {
VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
VMSTATE_STRUCT_TEST(pci0_status, PIIX4PMState,
vmstate_test_no_use_acpi_pci_hotplug,
2, vmstate_pci_status,
struct pci_status),
VMSTATE_STRUCT_TEST(
acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
PIIX4PMState,
vmstate_test_no_use_acpi_pci_hotplug,
2, vmstate_pci_status,
struct AcpiPciHpPciStatus),
VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
vmstate_test_use_acpi_pci_hotplug),
VMSTATE_END_OF_LIST()
}
};
static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
{
BusChild *kid, *next;
BusState *bus = qdev_get_parent_bus(DEVICE(s));
int slot = ffs(slots) - 1;
bool slot_free = true;
/* Mark request as complete */
s->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 {
object_unparent(OBJECT(qdev));
}
}
}
if (slot_free) {
s->pci0_slot_device_present &= ~(1U << slot);
}
}
static void piix4_update_hotplug(PIIX4PMState *s)
{
BusState *bus = qdev_get_parent_bus(DEVICE(s));
BusChild *kid, *next;
/* Execute any pending removes during reset */
while (s->pci0_status.down) {
acpi_piix_eject_slot(s, s->pci0_status.down);
}
s->pci0_hotplug_enable = ~0;
s->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) {
s->pci0_hotplug_enable &= ~(1U << slot);
}
s->pci0_slot_device_present |= (1U << slot);
}
}
static void piix4_reset(void *opaque)
{
PIIX4PMState *s = opaque;
@ -377,11 +299,7 @@ static void piix4_reset(void *opaque)
pci_conf[0x5B] = 0x02;
}
pm_io_space_update(s);
if (s->use_acpi_pci_hotplug) {
acpi_pcihp_reset(&s->acpi_pci_hotplug);
} else {
piix4_update_hotplug(s);
}
acpi_pcihp_reset(&s->acpi_pci_hotplug);
}
static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
@ -392,24 +310,26 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
acpi_pm1_evt_power_down(&s->ar);
}
static int piix4_acpi_pci_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state)
static void piix4_pci_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
PIIX4PMState *s = PIIX4_PM(qdev);
int ret = acpi_pcihp_device_hotplug(&s->acpi_pci_hotplug, dev, state);
if (ret < 0) {
return ret;
}
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
acpi_update_sci(&s->ar, s->irq);
return 0;
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
acpi_pcihp_device_plug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, errp);
}
static void piix4_update_bus_hotplug(PCIBus *bus, void *opaque)
static void piix4_pci_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
errp);
}
static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
{
PIIX4PMState *s = opaque;
pci_bus_hotplug(bus, piix4_acpi_pci_hotplug, DEVICE(s));
qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
}
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
@ -428,6 +348,8 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
if (s->use_acpi_pci_hotplug) {
pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s);
} else {
piix4_update_bus_hotplug(d->bus, s);
}
}
@ -545,52 +467,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
return s->smb.smbus;
}
static Property piix4_pm_properties[] = {
DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
use_acpi_pci_hotplug, true),
DEFINE_PROP_END_OF_LIST(),
};
static void piix4_pm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = piix4_pm_initfn;
k->config_write = pm_write_config;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
k->revision = 0x03;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
dc->desc = "PM";
dc->vmsd = &vmstate_acpi;
dc->props = piix4_pm_properties;
/*
* Reason: part of PIIX4 southbridge, needs to be wired up,
* e.g. by mips_malta_init()
*/
dc->cannot_instantiate_with_device_add_yet = true;
}
static const TypeInfo piix4_pm_info = {
.name = TYPE_PIIX4_PM,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX4PMState),
.class_init = piix4_pm_class_init,
};
static void piix4_pm_register_types(void)
{
type_register_static(&piix4_pm_info);
}
type_init(piix4_pm_register_types)
static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
{
PIIX4PMState *s = opaque;
@ -621,60 +497,6 @@ static const MemoryRegionOps piix4_gpe_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
{
PIIX4PMState *s = opaque;
uint32_t val = 0;
switch (addr) {
case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
/* Manufacture an "up" value to cause a device check on any hotplug
* slot with a device. Extra device checks are harmless. */
val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
PIIX4_DPRINTF("pci_up_read %" PRIu32 "\n", val);
break;
case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
val = s->pci0_status.down;
PIIX4_DPRINTF("pci_down_read %" PRIu32 "\n", val);
break;
case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
/* No feature defined yet */
PIIX4_DPRINTF("pci_features_read %" PRIu32 "\n", val);
break;
case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
val = s->pci0_hotplug_enable;
break;
default:
break;
}
return val;
}
static void pci_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
switch (addr) {
case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
acpi_piix_eject_slot(opaque, (uint32_t)data);
PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
addr, data);
break;
default:
break;
}
}
static const MemoryRegionOps piix4_pci_ops = {
.read = pci_read,
.write = pci_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void piix4_cpu_added_req(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_added_notifier);
@ -684,9 +506,6 @@ static void piix4_cpu_added_req(Notifier *n, void *opaque)
acpi_update_sci(&s->ar, s->irq);
}
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
PCIBus *bus, PIIX4PMState *s)
{
@ -694,15 +513,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
"acpi-gpe0", GPE_LEN);
memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
if (s->use_acpi_pci_hotplug) {
acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent);
} else {
memory_region_init_io(&s->io_pci, OBJECT(s), &piix4_pci_ops, s,
"acpi-pci-hotplug", PCI_HOTPLUG_SIZE);
memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
&s->io_pci);
pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
}
acpi_pcihp_init(&s->acpi_pci_hotplug, bus, parent,
s->use_acpi_pci_hotplug);
AcpiCpuHotplug_init(parent, OBJECT(s), &s->gpe_cpu,
PIIX4_CPU_HOTPLUG_IO_BASE);
@ -710,39 +522,55 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
qemu_register_cpu_added_notifier(&s->cpu_added_notifier);
}
static void enable_device(PIIX4PMState *s, int slot)
static Property piix4_pm_properties[] = {
DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
use_acpi_pci_hotplug, true),
DEFINE_PROP_END_OF_LIST(),
};
static void piix4_pm_class_init(ObjectClass *klass, void *data)
{
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
s->pci0_slot_device_present |= (1U << slot);
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->init = piix4_pm_initfn;
k->config_write = pm_write_config;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
k->revision = 0x03;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
dc->desc = "PM";
dc->vmsd = &vmstate_acpi;
dc->props = piix4_pm_properties;
/*
* Reason: part of PIIX4 southbridge, needs to be wired up,
* e.g. by mips_malta_init()
*/
dc->cannot_instantiate_with_device_add_yet = true;
dc->hotpluggable = false;
hc->plug = piix4_pci_device_plug_cb;
hc->unplug = piix4_pci_device_unplug_cb;
}
static void disable_device(PIIX4PMState *s, int slot)
{
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
s->pci0_status.down |= (1U << slot);
}
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state)
{
int slot = PCI_SLOT(dev->devfn);
PIIX4PMState *s = PIIX4_PM(qdev);
/* 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) {
s->pci0_slot_device_present |= (1U << slot);
return 0;
static const TypeInfo piix4_pm_info = {
.name = TYPE_PIIX4_PM,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX4PMState),
.class_init = piix4_pm_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
if (state == PCI_HOTPLUG_ENABLED) {
enable_device(s, slot);
} else {
disable_device(s, slot);
}
acpi_update_sci(&s->ar, s->irq);
return 0;
static void piix4_pm_register_types(void)
{
type_register_static(&piix4_pm_info);
}
type_init(piix4_pm_register_types)

View file

@ -2,6 +2,7 @@
common-obj-y += qdev.o qdev-properties.o
# irq.o needed for qdev GPIO handling:
common-obj-y += irq.o
common-obj-y += hotplug.o
common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
common-obj-$(CONFIG_XILINX_AXI) += stream.o

48
hw/core/hotplug.c Normal file
View file

@ -0,0 +1,48 @@
/*
* Hotplug handler interface.
*
* Copyright (c) 2014 Red Hat Inc.
*
* Authors:
* Igor Mammedov <imammedo@redhat.com>,
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "hw/hotplug.h"
#include "qemu/module.h"
void hotplug_handler_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp)
{
HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
if (hdc->plug) {
hdc->plug(plug_handler, plugged_dev, errp);
}
}
void hotplug_handler_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp)
{
HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
if (hdc->unplug) {
hdc->unplug(plug_handler, plugged_dev, errp);
}
}
static const TypeInfo hotplug_handler_info = {
.name = TYPE_HOTPLUG_HANDLER,
.parent = TYPE_INTERFACE,
.class_size = sizeof(HotplugHandlerClass),
};
static void hotplug_handler_register_types(void)
{
type_register_static(&hotplug_handler_info);
}
type_init(hotplug_handler_register_types)

View file

@ -32,6 +32,7 @@
#include "qapi/visitor.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
#include "hw/hotplug.h"
int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@ -212,13 +213,22 @@ void qdev_unplug(DeviceState *dev, Error **errp)
error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
return;
}
assert(dc->unplug != NULL);
if (!dc->hotpluggable) {
error_set(errp, QERR_DEVICE_NO_HOTPLUG,
object_get_typename(OBJECT(dev)));
return;
}
qdev_hot_removed = true;
if (dc->unplug(dev) < 0) {
error_set(errp, QERR_UNDEFINED_ERROR);
return;
if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
hotplug_handler_unplug(dev->parent_bus->hotplug_handler, dev, errp);
} else {
assert(dc->unplug != NULL);
if (dc->unplug(dev) < 0) { /* legacy handler */
error_set(errp, QERR_UNDEFINED_ERROR);
}
}
}
@ -693,6 +703,11 @@ static void device_set_realized(Object *obj, bool value, Error **err)
DeviceClass *dc = DEVICE_GET_CLASS(dev);
Error *local_err = NULL;
if (dev->hotplugged && !dc->hotpluggable) {
error_set(err, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
return;
}
if (value && !dev->realized) {
if (!obj->parent && local_err == NULL) {
static int unattached_count;
@ -708,6 +723,12 @@ static void device_set_realized(Object *obj, bool value, Error **err)
dc->realize(dev, &local_err);
}
if (dev->parent_bus && dev->parent_bus->hotplug_handler &&
local_err == NULL) {
hotplug_handler_plug(dev->parent_bus->hotplug_handler,
dev, &local_err);
}
if (qdev_get_vmsd(dev) && local_err == NULL) {
vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
@ -733,6 +754,14 @@ static void device_set_realized(Object *obj, bool value, Error **err)
dev->realized = value;
}
static bool device_get_hotpluggable(Object *obj, Error **err)
{
DeviceClass *dc = DEVICE_GET_CLASS(obj);
DeviceState *dev = DEVICE(obj);
return dc->hotpluggable && dev->parent_bus->allow_hotplug;
}
static void device_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj);
@ -749,6 +778,8 @@ static void device_initfn(Object *obj)
object_property_add_bool(obj, "realized",
device_get_realized, device_set_realized, NULL);
object_property_add_bool(obj, "hotpluggable",
device_get_hotpluggable, NULL, NULL);
class = object_get_class(OBJECT(dev));
do {
@ -785,6 +816,14 @@ static void device_class_base_init(ObjectClass *class, void *data)
* so do not propagate them to the subclasses.
*/
klass->props = NULL;
/* by default all devices were considered as hotpluggable,
* so with intent to check it in generic qdev_unplug() /
* device_set_realized() functions make every device
* hotpluggable. Devices that shouldn't be hotpluggable,
* should override it in their class_init()
*/
klass->hotpluggable = true;
}
static void device_unparent(Object *obj)
@ -870,6 +909,9 @@ static void qbus_initfn(Object *obj)
BusState *bus = BUS(obj);
QTAILQ_INIT(&bus->children);
object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
TYPE_HOTPLUG_HANDLER,
(Object **)&bus->hotplug_handler, NULL);
}
static char *default_bus_get_fw_dev_path(DeviceState *dev)

View file

@ -2996,7 +2996,6 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = pci_cirrus_vga_initfn;
k->romfile = VGABIOS_CIRRUS_FILENAME;
k->vendor_id = PCI_VENDOR_ID_CIRRUS;
@ -3006,6 +3005,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data)
dc->desc = "Cirrus CLGD 54xx VGA";
dc->vmsd = &vmstate_pci_cirrus_vga;
dc->props = pci_vga_cirrus_properties;
dc->hotpluggable = false;
}
static const TypeInfo cirrus_vga_info = {

View file

@ -2303,7 +2303,6 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = qxl_init_primary;
k->romfile = "vgabios-qxl.bin";
k->vendor_id = REDHAT_PCI_VENDOR_ID;
@ -2314,6 +2313,7 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data)
dc->reset = qxl_reset_handler;
dc->vmsd = &qxl_vmstate;
dc->props = qxl_properties;
dc->hotpluggable = false;
}
static const TypeInfo qxl_primary_info = {

View file

@ -190,7 +190,6 @@ static void vga_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = pci_std_vga_initfn;
k->romfile = "vgabios-stdvga.bin";
k->vendor_id = PCI_VENDOR_ID_QEMU;
@ -198,6 +197,7 @@ static void vga_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_DISPLAY_VGA;
dc->vmsd = &vmstate_vga_pci;
dc->props = vga_pci_properties;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
}

View file

@ -1296,7 +1296,6 @@ static void vmsvga_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = pci_vmsvga_initfn;
k->romfile = "vgabios-vmware.bin";
k->vendor_id = PCI_VENDOR_ID_VMWARE;
@ -1307,6 +1306,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data)
dc->reset = vmsvga_reset;
dc->vmsd = &vmstate_vmware_vga;
dc->props = vga_vmware_properties;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
}

View file

@ -768,6 +768,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable);
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
DeviceClass *dc;
PCIDeviceClass *pc;
PCIDevice *pdev = bus->devices[i];
@ -776,8 +777,9 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
}
pc = PCI_DEVICE_GET_CLASS(pdev);
dc = DEVICE_GET_CLASS(pdev);
if (pc->no_hotplug || pc->is_bridge) {
if (!dc->hotpluggable || pc->is_bridge) {
int slot = PCI_SLOT(i);
clear_bit(slot, slot_hotplug_enable);

View file

@ -39,9 +39,6 @@ Scope(\_SB) {
Return (0x0F)
}
Name(_CRS, ResourceTemplate() {
#if 0 /* This makes WinXP BSOD for not yet figured reasons. */
IRQNoFlags() {2, 8}
#endif
Memory32Fixed(ReadOnly,
0xFED00000, // Address Base
0x00000400, // Address Length

View file

@ -835,8 +835,8 @@ static void load_linux(FWCfgState *fw_cfg,
initrd_size = get_image_size(initrd_filename);
if (initrd_size < 0) {
fprintf(stderr, "qemu: error reading initrd %s\n",
initrd_filename);
fprintf(stderr, "qemu: error reading initrd %s: %s\n",
initrd_filename, strerror(errno));
exit(1);
}

View file

@ -793,6 +793,17 @@ static QEMUMachine xenfv_machine = {
.max_cpus = HVM_MAX_VCPUS,
.default_machine_opts = "accel=xen",
.hot_add_cpu = pc_hot_add_cpu,
.compat_props = (GlobalProperty[]) {
/* xenfv has no fwcfg and so does not load acpi from QEMU.
* as such new acpi features don't work.
*/
{
.driver = "PIIX4_PM",
.property = "acpi-pci-hotplug-with-bridge-support",
.value = "off",
},
{ /* end of list */ }
},
};
#endif

View file

@ -241,13 +241,13 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = pci_piix_ide_initfn;
k->exit = pci_piix_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
k->class_id = PCI_CLASS_STORAGE_IDE;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->hotpluggable = false;
}
static const TypeInfo piix3_ide_info = {
@ -280,13 +280,13 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = pci_piix_ide_initfn;
k->exit = pci_piix_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82371AB;
k->class_id = PCI_CLASS_STORAGE_IDE;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->hotpluggable = false;
}
static const TypeInfo piix4_ide_info = {

View file

@ -107,7 +107,6 @@ static void piix4_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = piix4_initfn;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
@ -119,6 +118,7 @@ static void piix4_class_init(ObjectClass *klass, void *data)
* e.g. by mips_malta_init()
*/
dc->cannot_instantiate_with_device_add_yet = true;
dc->hotpluggable = false;
}
static const TypeInfo piix4_info = {

View file

@ -26,6 +26,7 @@
#include "hw/pci/slotid_cap.h"
#include "exec/memory.h"
#include "hw/pci/pci_bus.h"
#include "hw/hotplug.h"
#define TYPE_PCI_BRIDGE_DEV "pci-bridge"
#define PCI_BRIDGE_DEV(obj) \
@ -136,6 +137,8 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->init = pci_bridge_dev_initfn;
k->exit = pci_bridge_dev_exitfn;
k->config_write = pci_bridge_dev_write_config;
@ -148,6 +151,8 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
dc->props = pci_bridge_dev_properties;
dc->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = shpc_device_hotplug_cb;
hc->unplug = shpc_device_hot_unplug_cb;
}
static const TypeInfo pci_bridge_dev_info = {
@ -155,6 +160,10 @@ static const TypeInfo pci_bridge_dev_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(PCIBridgeDev),
.class_init = pci_bridge_dev_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
static void pci_bridge_dev_register(void)

View file

@ -628,7 +628,7 @@ static void piix3_class_init(ObjectClass *klass, void *data)
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_piix3;
k->no_hotplug = 1;
dc->hotpluggable = false;
k->init = piix3_initfn;
k->config_write = piix3_write_config;
k->vendor_id = PCI_VENDOR_ID_INTEL;
@ -656,7 +656,7 @@ static void piix3_xen_class_init(ObjectClass *klass, void *data)
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_piix3;
k->no_hotplug = 1;
dc->hotpluggable = false;
k->init = piix3_initfn;
k->config_write = piix3_write_config_xen;
k->vendor_id = PCI_VENDOR_ID_INTEL;
@ -682,7 +682,6 @@ static void i440fx_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = i440fx_initfn;
k->config_write = i440fx_write_config;
k->vendor_id = PCI_VENDOR_ID_INTEL;
@ -696,6 +695,7 @@ static void i440fx_class_init(ObjectClass *klass, void *data)
* host-facing part, which can't be device_add'ed, yet.
*/
dc->cannot_instantiate_with_device_add_yet = true;
dc->hotpluggable = false;
}
static const TypeInfo i440fx_info = {

View file

@ -35,6 +35,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "exec/address-spaces.h"
#include "hw/hotplug.h"
//#define DEBUG_PCI
#ifdef DEBUG_PCI
@ -346,13 +347,6 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
}
void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
{
bus->qbus.allow_hotplug = 1;
bus->hotplug = hotplug;
bus->hotplug_qdev = qdev;
}
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque,
@ -1761,11 +1755,7 @@ static int pci_qdev_init(DeviceState *qdev)
pci_dev->devfn);
if (pci_dev == NULL)
return -1;
if (qdev->hotplugged && pc->no_hotplug) {
qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev)));
do_pci_unregister_device(pci_dev);
return -1;
}
if (pc->init) {
rc = pc->init(pci_dev);
if (rc != 0) {
@ -1782,34 +1772,9 @@ static int pci_qdev_init(DeviceState *qdev)
}
pci_add_option_rom(pci_dev, is_default_rom);
if (bus->hotplug) {
/* Let buses differentiate between hotplug and when device is
* enabled during qemu machine creation. */
rc = bus->hotplug(bus->hotplug_qdev, pci_dev,
qdev->hotplugged ? PCI_HOTPLUG_ENABLED:
PCI_COLDPLUG_ENABLED);
if (rc != 0) {
int r = pci_unregister_device(&pci_dev->qdev);
assert(!r);
return rc;
}
}
return 0;
}
static int pci_unplug_device(DeviceState *qdev)
{
PCIDevice *dev = PCI_DEVICE(qdev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
if (pc->no_hotplug) {
qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
return -1;
}
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
PCI_HOTPLUG_DISABLED);
}
PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name)
{
@ -2280,7 +2245,6 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->init = pci_qdev_init;
k->unplug = pci_unplug_device;
k->exit = pci_unregister_device;
k->bus_type = TYPE_PCI_BUS;
k->props = pci_props;

View file

@ -26,6 +26,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/pci/pcie_regs.h"
#include "qemu/range.h"
#include "qapi/qmp/qerror.h"
//#define DEBUG_PCIE
#ifdef DEBUG_PCIE
@ -216,28 +217,20 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
hotplug_event_notify(dev);
}
static int pcie_cap_slot_hotplug(DeviceState *qdev,
PCIDevice *pci_dev, PCIHotplugState state)
static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
DeviceState *dev,
uint8_t **exp_cap, Error **errp)
{
PCIDevice *d = PCI_DEVICE(qdev);
uint8_t *exp_cap = d->config + d->exp.exp_cap;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
/* 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) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
return 0;
}
PCIDevice *pci_dev = PCI_DEVICE(dev);
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
if (sltsta & PCI_EXP_SLTSTA_EIS) {
/* the slot is electromechanically locked.
* This error is propagated up to qdev and then to HMP/QMP.
*/
return -EBUSY;
error_setg_errno(errp, -EBUSY, "slot is electromechanically locked");
}
/* TODO: multifunction hot-plug.
@ -245,18 +238,40 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev,
* hot plugged/unplugged.
*/
assert(PCI_FUNC(pci_dev->devfn) == 0);
}
if (state == PCI_HOTPLUG_ENABLED) {
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
uint8_t *exp_cap;
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
/* 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 (!dev->hotplugged) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
} else {
object_unparent(OBJECT(pci_dev));
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
return;
}
return 0;
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
}
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
uint8_t *exp_cap;
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
object_unparent(OBJECT(dev));
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
}
/* pci express slot for pci express root/downstream port
@ -305,8 +320,8 @@ void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
dev->exp.hpev_notified = false;
pci_bus_hotplug(pci_bridge_get_sec_bus(PCI_BRIDGE(dev)),
pcie_cap_slot_hotplug, &dev->qdev);
qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))),
DEVICE(dev), NULL);
}
void pcie_cap_slot_reset(PCIDevice *dev)

View file

@ -19,6 +19,7 @@
*/
#include "hw/pci/pcie_port.h"
#include "hw/hotplug.h"
void pcie_port_init_reg(PCIDevice *d)
{
@ -149,8 +150,11 @@ static Property pcie_slot_props[] = {
static void pcie_slot_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
dc->props = pcie_slot_props;
hc->plug = pcie_cap_slot_hotplug_cb;
hc->unplug = pcie_cap_slot_hot_unplug_cb;
}
static const TypeInfo pcie_slot_type_info = {
@ -159,6 +163,10 @@ static const TypeInfo pcie_slot_type_info = {
.instance_size = sizeof(PCIESlot),
.abstract = true,
.class_init = pcie_slot_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
static void pcie_port_register_types(void)

View file

@ -7,6 +7,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/msi.h"
#include "qapi/qmp/qerror.h"
/* TODO: model power only and disabled slot states. */
/* TODO: handle SERR and wakeups */
@ -490,65 +491,93 @@ static const MemoryRegionOps shpc_mmio_ops = {
.max_access_size = 4,
},
};
static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev,
PCIHotplugState hotplug_state)
static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
SHPCDevice *shpc, Error **errp)
{
int pci_slot = PCI_SLOT(affected_dev->devfn);
uint8_t state;
uint8_t led;
PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
SHPCDevice *shpc = d->shpc;
int slot = SHPC_PCI_TO_IDX(pci_slot);
if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) {
error_report("Unsupported PCI slot %d for standard hotplug "
"controller. Valid slots are between %d and %d.",
pci_slot, SHPC_IDX_TO_PCI(0),
SHPC_IDX_TO_PCI(shpc->nslots) - 1);
return -1;
*slot = SHPC_PCI_TO_IDX(pci_slot);
if (pci_slot < SHPC_IDX_TO_PCI(0) || *slot >= shpc->nslots) {
error_setg(errp, "Unsupported PCI slot %d for standard hotplug "
"controller. Valid slots are between %d and %d.",
pci_slot, SHPC_IDX_TO_PCI(0),
SHPC_IDX_TO_PCI(shpc->nslots) - 1);
return;
}
}
void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
Error *local_err = NULL;
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
SHPCDevice *shpc = pci_hotplug_dev->shpc;
int slot;
shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
/* 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 (hotplug_state == PCI_COLDPLUG_ENABLED) {
if (!dev->hotplugged) {
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
SHPC_SLOT_STATUS_PRSNT_MASK);
return 0;
return;
}
if (hotplug_state == PCI_HOTPLUG_DISABLED) {
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
shpc_free_devices_in_slot(shpc, slot);
shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
SHPC_SLOT_STATUS_PRSNT_MASK);
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
SHPC_SLOT_EVENT_MRL |
SHPC_SLOT_EVENT_PRESENCE;
}
/* This could be a cancellation of the previous removal.
* We check MRL state to figure out. */
if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
SHPC_SLOT_STATUS_PRSNT_MASK);
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
SHPC_SLOT_EVENT_BUTTON |
SHPC_SLOT_EVENT_MRL |
SHPC_SLOT_EVENT_PRESENCE;
} else {
/* This could be a cancellation of the previous removal.
* We check MRL state to figure out. */
if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
SHPC_SLOT_STATUS_PRSNT_MASK);
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
SHPC_SLOT_EVENT_BUTTON |
SHPC_SLOT_EVENT_MRL |
SHPC_SLOT_EVENT_PRESENCE;
} else {
/* Press attention button to cancel removal */
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
SHPC_SLOT_EVENT_BUTTON;
}
/* Press attention button to cancel removal */
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
SHPC_SLOT_EVENT_BUTTON;
}
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
shpc_interrupt_update(d);
return 0;
shpc_interrupt_update(pci_hotplug_dev);
}
void shpc_device_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
Error *local_err = NULL;
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
SHPCDevice *shpc = pci_hotplug_dev->shpc;
uint8_t state;
uint8_t led;
int slot;
shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, errp);
if (local_err) {
return;
}
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
shpc_free_devices_in_slot(shpc, slot);
shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
SHPC_SLOT_STATUS_PRSNT_MASK);
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
SHPC_SLOT_EVENT_MRL |
SHPC_SLOT_EVENT_PRESENCE;
}
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
shpc_interrupt_update(pci_hotplug_dev);
}
/* Initialize the SHPC structure in bridge's BAR. */
@ -616,7 +645,8 @@ int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset)
d, "shpc-mmio", SHPC_SIZEOF(d));
shpc_cap_update_dword(d);
memory_region_add_subregion(bar, offset, &shpc->mmio);
pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev);
qbus_set_hotplug_handler(BUS(sec_bus), DEVICE(d), NULL);
d->cap_present |= QEMU_PCI_CAP_SHPC;
return 0;

View file

@ -123,7 +123,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
k->init = usb_ehci_pci_initfn;
k->class_id = PCI_CLASS_SERIAL_USB;
k->config_write = usb_ehci_pci_write_config;
k->no_hotplug = 1;
dc->hotpluggable = false;
dc->vmsd = &vmstate_ehci_pci;
dc->props = ehci_pci_properties;
}

View file

@ -1993,10 +1993,10 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
k->vendor_id = PCI_VENDOR_ID_APPLE;
k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
k->class_id = PCI_CLASS_SERIAL_USB;
k->no_hotplug = 1;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
dc->desc = "Apple USB Controller";
dc->props = ohci_pci_properties;
dc->hotpluggable = false;
}
static const TypeInfo ohci_pci_info = {

View file

@ -1318,7 +1318,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
k->device_id = info->device_id;
k->revision = info->revision;
k->class_id = PCI_CLASS_SERIAL_USB;
k->no_hotplug = 1;
dc->hotpluggable = false;
dc->vmsd = &vmstate_uhci;
dc->props = uhci_properties;
set_bit(DEVICE_CATEGORY_USB, dc->categories);

View file

@ -3798,6 +3798,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_xhci;
dc->props = xhci_properties;
dc->reset = xhci_reset;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
k->init = usb_xhci_initfn;
k->vendor_id = PCI_VENDOR_ID_NEC;
@ -3805,7 +3806,6 @@ static void xhci_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_SERIAL_USB;
k->revision = 0x03;
k->is_express = 1;
k->no_hotplug = 1;
}
static const TypeInfo xhci_info = {

View file

@ -24,6 +24,7 @@
#include "qemu/notify.h"
#include "qemu/option.h"
#include "exec/memory.h"
#include "hw/irq.h"
/* from linux include/acpi/actype.h */
/* Default ACPI register widths */

View file

@ -29,31 +29,34 @@
#include <inttypes.h>
#include <qemu/typedefs.h>
#include "hw/pci/pci.h" /* for PCIHotplugState */
#include "hw/acpi/acpi.h"
#include "migration/vmstate.h"
typedef struct AcpiPciHpPciStatus {
uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t up;
uint32_t down;
uint32_t hotplug_enable;
uint32_t device_present;
} AcpiPciHpPciStatus;
#define ACPI_PCIHP_PROP_BSEL "acpi-pcihp-bsel"
#define ACPI_PCIHP_MAX_HOTPLUG_BUS 256
#define ACPI_PCIHP_BSEL_DEFAULT 0x0
typedef struct AcpiPciHpState {
AcpiPciHpPciStatus acpi_pcihp_pci_status[ACPI_PCIHP_MAX_HOTPLUG_BUS];
uint32_t hotplug_select;
PCIBus *root;
MemoryRegion io;
bool legacy_piix;
} AcpiPciHpState;
void acpi_pcihp_init(AcpiPciHpState *, PCIBus *root,
MemoryRegion *address_space_io);
MemoryRegion *address_space_io, bool bridges_enabled);
/* Invoke on device hotplug */
int acpi_pcihp_device_hotplug(AcpiPciHpState *, PCIDevice *,
PCIHotplugState state);
void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
DeviceState *dev, Error **errp);
void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
DeviceState *dev, Error **errp);
/* Called on reset */
void acpi_pcihp_reset(AcpiPciHpState *s);

78
include/hw/hotplug.h Normal file
View file

@ -0,0 +1,78 @@
/*
* Hotplug handler interface.
*
* Copyright (c) 2014 Red Hat Inc.
*
* Authors:
* Igor Mammedov <imammedo@redhat.com>,
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HOTPLUG_H
#define HOTPLUG_H
#include "qom/object.h"
#include "qemu/typedefs.h"
#define TYPE_HOTPLUG_HANDLER "hotplug-handler"
#define HOTPLUG_HANDLER_CLASS(klass) \
OBJECT_CLASS_CHECK(HotplugHandlerClass, (klass), TYPE_HOTPLUG_HANDLER)
#define HOTPLUG_HANDLER_GET_CLASS(obj) \
OBJECT_GET_CLASS(HotplugHandlerClass, (obj), TYPE_HOTPLUG_HANDLER)
#define HOTPLUG_HANDLER(obj) \
INTERFACE_CHECK(HotplugHandler, (obj), TYPE_HOTPLUG_HANDLER)
typedef struct HotplugHandler {
/* <private> */
Object Parent;
} HotplugHandler;
/**
* hotplug_fn:
* @plug_handler: a device performing plug/uplug action
* @plugged_dev: a device that has been (un)plugged
* @errp: returns an error if this function fails
*/
typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp);
/**
* HotplugDeviceClass:
*
* Interface to be implemented by a device performing
* hardware (un)plug functions.
*
* @parent: Opaque parent interface.
* @plug: plug callback.
* @unplug: unplug callback.
*/
typedef struct HotplugHandlerClass {
/* <private> */
InterfaceClass parent;
/* <public> */
hotplug_fn plug;
hotplug_fn unplug;
} HotplugHandlerClass;
/**
* hotplug_handler_plug:
*
* Call #HotplugHandlerClass.plug callback of @plug_handler.
*/
void hotplug_handler_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp);
/**
* hotplug_handler_unplug:
*
* Call #HotplugHandlerClass.unplug callback of @plug_handler.
*/
void hotplug_handler_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp);
#endif

View file

@ -4,6 +4,13 @@
#include "hw/nvram/fw_cfg.h"
/* loader.c */
/**
* get_image_size: retrieve size of an image file
* @filename: Path to the image file
*
* Returns the size of the image file on success, -1 otherwise.
* On error, errno is also set as appropriate.
*/
int get_image_size(const char *filename);
int load_image(const char *filename, uint8_t *addr); /* deprecated */
int load_image_targphys(const char *filename, hwaddr,

View file

@ -201,9 +201,6 @@ typedef struct PCIDeviceClass {
/* pcie stuff */
int is_express; /* is this device pci express? */
/* device isn't hot-pluggable */
int no_hotplug;
/* rom bar */
const char *romfile;
} PCIDeviceClass;
@ -330,15 +327,6 @@ typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
typedef enum {
PCI_HOTPLUG_DISABLED,
PCI_HOTPLUG_ENABLED,
PCI_COLDPLUG_ENABLED,
} PCIHotplugState;
typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
PCIHotplugState state);
#define TYPE_PCI_BUS "PCI"
#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
#define TYPE_PCIE_BUS "PCIE"
@ -357,7 +345,6 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
PCIBus *pci_register_bus(DeviceState *parent, const char *name,

View file

@ -16,8 +16,6 @@ struct PCIBus {
pci_set_irq_fn set_irq;
pci_map_irq_fn map_irq;
pci_route_irq_fn route_intx_to_irq;
pci_hotplug_fn hotplug;
DeviceState *hotplug_qdev;
void *irq_opaque;
PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
PCIDevice *parent_dev;

View file

@ -25,6 +25,7 @@
#include "hw/pci/pci_regs.h"
#include "hw/pci/pcie_regs.h"
#include "hw/pci/pcie_aer.h"
#include "hw/hotplug.h"
typedef enum {
/* for attention and power indicator */
@ -122,4 +123,8 @@ extern const VMStateDescription vmstate_pcie_device;
.offset = vmstate_offset_value(_state, _field, PCIDevice), \
}
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
#endif /* QEMU_PCIE_H */

View file

@ -4,6 +4,8 @@
#include "qemu-common.h"
#include "exec/memory.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "hw/hotplug.h"
struct SHPCDevice {
/* Capability offset in device's config space */
@ -41,6 +43,12 @@ int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off);
void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void shpc_device_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
extern VMStateInfo shpc_vmstate_info;
#define SHPC_VMSTATE(_field, _type) \
VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)

View file

@ -8,6 +8,7 @@
#include "qom/object.h"
#include "hw/irq.h"
#include "qapi/error.h"
#include "hw/hotplug.h"
enum {
DEV_NVECTORS_UNSPECIFIED = -1,
@ -49,6 +50,8 @@ struct VMStateDescription;
* is changed to %true. Deprecated, new types inheriting directly from
* TYPE_DEVICE should use @realize instead, new leaf types should consult
* their respective parent type.
* @hotpluggable: indicates if #DeviceClass is hotpluggable, available
* as readonly "hotpluggable" property of #DeviceState instance
*
* # Realization #
* Devices are constructed in two stages,
@ -109,6 +112,7 @@ typedef struct DeviceClass {
* TODO remove once we're there
*/
bool cannot_instantiate_with_device_add_yet;
bool hotpluggable;
/* callbacks */
void (*reset)(DeviceState *dev);
@ -180,14 +184,18 @@ typedef struct BusChild {
QTAILQ_ENTRY(BusChild) sibling;
} BusChild;
#define QDEV_HOTPLUG_HANDLER_PROPERTY "hotplug-handler"
/**
* BusState:
* @hotplug_device: link to a hotplug device associated with bus.
*/
struct BusState {
Object obj;
DeviceState *parent;
const char *name;
int allow_hotplug;
HotplugHandler *hotplug_handler;
int max_index;
QTAILQ_HEAD(ChildrenHead, BusChild) children;
QLIST_ENTRY(BusState) sibling;
@ -321,4 +329,11 @@ extern int qdev_hotplug;
char *qdev_get_dev_path(DeviceState *dev);
static inline void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
Error **errp)
{
object_property_set_link(OBJECT(bus), OBJECT(handler),
QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
bus->allow_hotplug = 1;
}
#endif

View file

@ -23,6 +23,8 @@ static inline bool qtest_enabled(void)
return qtest_allowed;
}
bool qtest_driver(void);
int qtest_init_accel(void);
void qtest_init(const char *qtest_chrdev, const char *qtest_log);

View file

@ -528,3 +528,8 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log)
qtest_chr = chr;
}
bool qtest_driver(void)
{
return qtest_chr;
}

View file

@ -163,7 +163,7 @@ tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuuti
tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
tests/test-int128$(EXESUF): tests/test-int128.o
tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
hw/core/qdev.o hw/core/qdev-properties.o \
hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
hw/core/irq.o \
$(qom-core-obj) \
$(test-qapi-obj-y) \

2
vl.c
View file

@ -1750,7 +1750,7 @@ static int qemu_shutdown_requested(void)
static void qemu_kill_report(void)
{
if (!qtest_enabled() && shutdown_signal != -1) {
if (!qtest_driver() && shutdown_signal != -1) {
fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal);
if (shutdown_pid == 0) {
/* This happens for eg ^C at the terminal, so it's worth