mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-02 21:32:52 +00:00
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:
commit
0888a29caa
38 changed files with 542 additions and 463 deletions
127
hw/acpi/pcihp.c
127
hw/acpi/pcihp.c
|
@ -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 = {
|
||||
|
|
326
hw/acpi/piix4.c
326
hw/acpi/piix4.c
|
@ -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)
|
||||
|
|
|
@ -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
48
hw/core/hotplug.c
Normal 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)
|
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
40
hw/pci/pci.c
40
hw/pci/pci.c
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
124
hw/pci/shpc.c
124
hw/pci/shpc.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
78
include/hw/hotplug.h
Normal 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
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
5
qtest.c
5
qtest.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
2
vl.c
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue