@@ -173,3 +173,178 @@
#
##
{ 'event': 'DEVICE_UNPLUG_GUEST_ERROR', 'data': 'DeviceAndPath' }
+
+##
+# @LedActivity:
+#
+# Three-state led indicator state.
+#
+# @on: Indicator is on.
+#
+# @blink: Indicator is blinking.
+#
+# @off: Indicator is off.
+#
+# Since: 8.0
+##
+{ 'enum': 'LedActivity',
+ 'data': [ 'on', 'blink', 'off' ] }
+
+##
+# @HotplugSHPCSlotState:
+#
+# Standard Hot-Plug Controller slot state.
+#
+# @power-only: Slot is powered on but neither clock nor bus are connected.
+#
+# @enabled: Slot is powered on, clock and bus are connected, the card is
+# fully functional from a hardware standpoint.
+#
+# @disabled: Slot is disabled, card is safe to be removed.
+#
+# Since: 8.0
+##
+{ 'enum': 'HotplugSHPCSlotState',
+ 'data': [ 'power-only', 'enabled', 'disabled' ] }
+
+##
+# @HotplugBaseState:
+#
+# Base structure for SHPC and PCIe-native hotplug.
+#
+# @power-led: Power indicator. When power indicator is on the device is
+# ready and accepted by guest. Off status means that device
+# is safe to remove and blinking is an intermediate state of
+# hot-plug or hot-unplug.
+#
+# @attention-led: Attention indicator. Off status means normal operation,
+# On signals about operational problem, Blinking is for
+# locating the slot.
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugBaseState',
+ 'data': { '*power-led': 'LedActivity',
+ '*attention-led': 'LedActivity' } }
+
+##
+# @HotplugSHPCState:
+#
+# Standard Hot Plug Controller state.
+#
+# @slot-state: The slot state field of Slot Status.
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugSHPCState',
+ 'base': 'HotplugBaseState',
+ 'data': { '*slot-state': 'HotplugSHPCSlotState' } }
+
+##
+# @HotplugPCIeNativeState:
+#
+# PCIe Native hotplug slot state.
+#
+# @power-on: PCIe Power Controller Control of Slot Control Register.
+# True means Power On (Power Controller Control bit is 0),
+# False means Power Off (Power Controller Control bit is 1).
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugPCIeNativeState',
+ 'base': 'HotplugBaseState',
+ 'data': { '*power-on': 'bool' } }
+
+##
+# @HotplugType:
+#
+# Type of hotplug controller / provider.
+#
+# @shpc: Standard Hot Plug Controller
+#
+# @pcie-native: PCIe Native hotplug
+#
+# Since: 8.0
+##
+{ 'enum': 'HotplugType',
+ 'data': ['shpc', 'pcie-native'] }
+
+##
+# @HotplugState:
+#
+# Generic hotplug slot state.
+#
+# @type: type of the hotplug (shpc or pcie-native)
+#
+# Single: 8.0
+##
+{ 'union': 'HotplugState',
+ 'base': { 'type': 'HotplugType' },
+ 'discriminator': 'type',
+ 'data': { 'shpc': 'HotplugSHPCState',
+ 'pcie-native': 'HotplugPCIeNativeState' } }
+
+##
+# @HotplugBase:
+#
+# @bus: The QOM path of the parent bus where device is hotplugged.
+#
+# @addr: The bus address for hotplugged device if applicable.
+#
+# @child: the hotplugged device's QOM path. The field absent if
+# there is no device at the moment.
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugBase',
+ 'data': { 'bus': 'DeviceAndPath',
+ '*addr': 'str',
+ 'child': 'DeviceAndPath' } }
+
+##
+# @HotplugEvent:
+#
+# @changed: The hotplug controller states being changed. The state
+# fields that are not changed are not included into @changed.
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugEvent',
+ 'base': 'HotplugBase',
+ 'data': { 'changed': 'HotplugState' } }
+
+##
+# @HotplugInfo:
+#
+# @state: Current hotplug controller state. All applicable fields are
+# included into @state.
+#
+# Since: 8.0
+##
+{ 'struct': 'HotplugInfo',
+ 'base': 'HotplugBase',
+ 'data': { 'state': 'HotplugState' } }
+
+##
+# @HOTPLUG_STATE:
+#
+# Emitted whenever the state of hotplug controller changes.
+# Only changed values are included into event. Any change of any field
+# of the state trigger the event. Several fields are included into one
+# event if they are changed simultaneously.
+#
+# Since: 8.0
+##
+{ 'event': 'HOTPLUG_STATE',
+ 'data': 'HotplugEvent' }
+
+##
+# @query-hotplug:
+#
+# Query the state of hotplug controller.
+#
+# Since: 8.0
+##
+{ 'command': 'query-hotplug',
+ 'data': { 'id': 'str' },
+ 'returns': 'HotplugInfo' }
@@ -13,6 +13,7 @@
#define HOTPLUG_H
#include "qom/object.h"
+#include "qapi/qapi-types-qdev.h"
#define TYPE_HOTPLUG_HANDLER "hotplug-handler"
@@ -58,6 +59,8 @@ struct HotplugHandlerClass {
hotplug_fn plug;
hotplug_fn unplug_request;
hotplug_fn unplug;
+ HotplugInfo *(*get_hotplug_state)(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp);
};
/**
@@ -94,4 +97,13 @@ void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
void hotplug_handler_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp);
+
+/**
+ * hotplug_handler_get_hotplug_state:
+ *
+ * Calls #HotplugHandlerClass.get_hotplug_state callback of @plug_handler.
+ */
+HotplugInfo *hotplug_handler_get_hotplug_state(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev,
+ Error **errp);
#endif
@@ -1,6 +1,8 @@
#ifndef MONITOR_QDEV_H
#define MONITOR_QDEV_H
+#include "qapi/qapi-types-qdev.h"
+
/*** monitor commands ***/
void hmp_info_qtree(Monitor *mon, const QDict *qdict);
@@ -36,4 +38,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts,
*/
const char *qdev_set_id(DeviceState *dev, char *id, Error **errp);
+void qdev_hotplug_state_event(DeviceState *bus, const char *addr,
+ DeviceState *child, HotplugState *changed_state);
+
#endif
@@ -57,6 +57,19 @@ void hotplug_handler_unplug(HotplugHandler *plug_handler,
}
}
+HotplugInfo *hotplug_handler_get_hotplug_state(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev,
+ Error **errp)
+{
+ HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+
+ if (hdc->get_hotplug_state) {
+ return hdc->get_hotplug_state(plug_handler, plugged_dev, errp);
+ }
+
+ return NULL;
+}
+
static const TypeInfo hotplug_handler_info = {
.name = TYPE_HOTPLUG_HANDLER,
.parent = TYPE_INTERFACE,
@@ -25,6 +25,7 @@
#include "sysemu/arch_init.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-qdev.h"
+#include "qapi/qapi-events-qdev.h"
#include "qapi/qmp/dispatch.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
@@ -956,6 +957,36 @@ void qmp_device_del(const char *id, Error **errp)
}
}
+HotplugInfo *qmp_query_hotplug(const char *id, Error **errp)
+{
+ DeviceState *dev = find_device_state(id, errp);
+ HotplugHandler *hotplug_ctrl;
+
+ if (!dev) {
+ return NULL;
+ }
+
+ if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
+ error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
+ return NULL;
+ }
+
+ if (!DEVICE_GET_CLASS(dev)->hotpluggable) {
+ error_setg(errp, QERR_DEVICE_NO_HOTPLUG,
+ object_get_typename(OBJECT(dev)));
+ return NULL;
+ }
+
+ hotplug_ctrl = qdev_get_hotplug_handler(dev);
+ /*
+ * hotpluggable device MUST have HotplugHandler, if it doesn't
+ * then something is very wrong with it.
+ */
+ g_assert(hotplug_ctrl);
+
+ return hotplug_handler_get_hotplug_state(hotplug_ctrl, dev, errp);
+}
+
void hmp_device_add(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
@@ -1146,3 +1177,22 @@ bool qmp_command_available(const QmpCommand *cmd, Error **errp)
}
return true;
}
+
+void qdev_hotplug_state_event(DeviceState *bus, const char *addr,
+ DeviceState *child, HotplugState *changed_state)
+{
+ DeviceAndPath child_desc, bus_desc = {
+ .device = bus->id,
+ .path = bus->canonical_path,
+ };
+
+ if (child) {
+ child_desc = (DeviceAndPath) {
+ .device = child->id,
+ .path = child->canonical_path,
+ };
+ }
+
+ qapi_event_send_hotplug_state(&bus_desc, addr, child ? &child_desc : NULL,
+ changed_state);
+}
For PCIe and SHPC hotplug it's important to track led indicators, especially the power led. Add an event that helps. This commits adds infrastructure for HOTPLUG_STATE event and corresponding query command. The implementation for PCIe and SHPC will follow in further commits. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> --- qapi/qdev.json | 175 +++++++++++++++++++++++++++++++++++++++++ include/hw/hotplug.h | 12 +++ include/monitor/qdev.h | 5 ++ hw/core/hotplug.c | 13 +++ softmmu/qdev-monitor.c | 50 ++++++++++++ 5 files changed, 255 insertions(+)