[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 5/7] pci/shpc: convert SHPC hotplug to use hotplug-d
From: |
Igor Mammedov |
Subject: |
[Qemu-devel] [PATCH 5/7] pci/shpc: convert SHPC hotplug to use hotplug-device interface |
Date: |
Fri, 6 Dec 2013 18:03:13 +0100 |
Split shpc_device_hotplug() into hotplug/unplug callbacks
and register them as "hotplug-device" interface implementation of
PCI_BRIDGE_DEV device.
Replace pci_bus_hotplug() wiring with setting link on PCI BUS
"hotplug-device" property to PCI_BRIDGE_DEV device.
Signed-off-by: Igor Mammedov <address@hidden>
---
hw/pci-bridge/pci_bridge_dev.c | 9 +++
hw/pci/shpc.c | 132 ++++++++++++++++++++++++++--------------
include/hw/pci/shpc.h | 7 ++
3 files changed, 101 insertions(+), 47 deletions(-)
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 440e187..8a1813e 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -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);
+ HotplugDeviceClass *hc = HOTPLUG_DEVICE_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->hotplug = shpc_device_hotplug_cb;
+ hc->hot_unplug = shpc_device_hotplug_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_DEVICE },
+ { }
+ }
};
static void pci_bridge_dev_register(void)
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index 576244b..e1ef84d 100644
--- a/hw/pci/shpc.c
+++ b/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,73 +491,102 @@ 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(DeviceState *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, errp);
+ if (error_is_set(&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(DeviceState *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 (error_is_set(&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. */
int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned
offset)
{
int i, ret;
+ Error *local_error = NULL;
int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
+ BusState *bus = BUS(sec_bus);
shpc->sec_bus = sec_bus;
ret = shpc_cap_add_config(d);
if (ret) {
@@ -616,7 +646,15 @@ 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);
+
+ object_property_set_link(OBJECT(sec_bus), OBJECT(d),
+ QDEV_HOTPLUG_DEVICE_PROPERTY, &local_error);
+ if (error_is_set(&local_error)) {
+ qerror_report_err(local_error);
+ error_free(local_error);
+ return -1;
+ }
+ bus->allow_hotplug = 1;
d->cap_present |= QEMU_PCI_CAP_SHPC;
return 0;
diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h
index 467911a..ea1efde 100644
--- a/include/hw/pci/shpc.h
+++ b/include/hw/pci/shpc.h
@@ -4,6 +4,7 @@
#include "qemu-common.h"
#include "exec/memory.h"
#include "migration/vmstate.h"
+#include "qapi/error.h"
struct SHPCDevice {
/* Capability offset in device's config space */
@@ -41,6 +42,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(DeviceState *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void shpc_device_hot_unplug_cb(DeviceState *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)
--
1.7.1
- [Qemu-devel] [PATCH 0/7] Refactor PCI/SHPC/PCIE hotplug to use a more generic hotplug API, Igor Mammedov, 2013/12/06
- [Qemu-devel] [PATCH 3/7] hw/acpi: move typeinfo to the file end, Igor Mammedov, 2013/12/06
- [Qemu-devel] [PATCH 4/7] acpi/piix4pm: convert ACPI PCI hotplug to use hotplug-device interface, Igor Mammedov, 2013/12/06
- [Qemu-devel] [PATCH 5/7] pci/shpc: convert SHPC hotplug to use hotplug-device interface,
Igor Mammedov <=
- [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Igor Mammedov, 2013/12/06
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Paolo Bonzini, 2013/12/06
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Igor Mammedov, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Paolo Bonzini, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Igor Mammedov, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Paolo Bonzini, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Igor Mammedov, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Paolo Bonzini, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Igor Mammedov, 2013/12/09
- Re: [Qemu-devel] [PATCH 7/7] hw/pci: convert PCI bus to use "hotplug-device" interface., Paolo Bonzini, 2013/12/09