This adds a new command to QMP: query-device-slots. It will allow
management software to query possible slots where devices can be
plugged.
Slot sets are represented by a list of option names and sets of
possible values for each of those options. We use a compact
format for set of valid values, to keep JSON response size
reasonable. The format is documented at the SlotOption struct.
In the future, we may use QAPI alternates to define and document
the exact data format more strictly.
Actual implementations of BusClass::enumerate_slots will be added
by other patches.
Cc: Marcel Apfelbaum <marcel(a)redhat.com>
Cc: Markus Armbruster <armbru(a)redhat.com>
Cc: libvir-list(a)redhat.com,
Cc: Igor Mammedov <imammedo(a)redhat.com>
Cc: Laine Stump <laine(a)redhat.com>
Cc: "Michael S. Tsirkin" <mst(a)redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost(a)redhat.com>
---
Changes v3 -> v4:
* Use a more compact format for the "slot sets"
* Renamed DeviceSlotInfo.props to DeviceSlotInfo.opts
* Replaced DeviceSlotInfo.incomplete with
DeviceSlotInfo.opts-complete
* Now DeviceSlotInfo.available will be true even if hotplug is
unavailable, to indicate the slot would be available using
-device.
Changes v2 -> v3:
* Implemented a "slot set" structure, where multiple slots can be
reported by using integer ranges or lists for possible
values for each property. Added a ValueSet struct, that
can represent a set of values using either a simple list of
values, or integer ranges. (Its JSON representation is very
verbose, though. See comments below).
* Removed the *Properties structs, and replaced them with
a simple list of SlotOption structs.
* DeviceSlotInfo is not an union anymore, removed the 'type'
field only because there are no slot-type-specific fields in
the current implementation, but we may add it back if necessary
* The implementation is very quick and dirty, the main purpose of
this RFC is to evaluate the schema and returned data.
Changes v1 -> v2:
* Don't show sysbus unless has_dynamic_sysbus is set for the
machine type
* Removed max-devices and devices properties
* Introduced "non-slot" slot type, to explicitly indicate
we are returning info on a bus that doesn't implement slot
enumeration yet.
* Return bus name instead of full QOM path on "bus" field
* PCI: Replaced "addr" property (string parsed by property
setter) with "device-number" uint32 property
* PCI: return only one slot for PCIe ports
---
qapi-schema.json | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/hw/qdev-core.h | 2 ++
qdev-monitor.c | 38 +++++++++++++++++++++
3 files changed, 129 insertions(+)
diff --git a/qapi-schema.json b/qapi-schema.json
index 802ea53..6a9329e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4325,6 +4325,95 @@
##
{ 'command': 'closefd', 'data': {'fdname': 'str'}
}
+
+##
+# @SlotOption:
+#
+# A option to be used when plugging a device to a slot.
+#
+# @option: Option name.
+#
+# @values: Set of valid option values.
+#
+# @values follow a compact format to represent a set of values:
+# - If @values is a string, bool, or number, it representes a
+# single-element set containing that value. In other words,
+# @values is the only valid value for the option.
+# - If @values is a list, each element E on the list represents
+# one or more possible values for the option:
+# - If E is a string, bool, or number, it indicates that E
+# is a valid value for the option.
+# - If E is a one-element list [V], it means V is a valid value
+# for the option.
+# - If E is a two-element list [A, B] where A and B are
+# numbers, it means any number X, A <= X <= B is a valid
+# value for the option.
+#
+# TODO: @values could be represented by nested 'alternate' types,
+# for more consistent documentation and automatic
+# validation/parsing, but the following limitations on
+# alternates prevent that today:
+# - alternate branches can't be lists
+# - alternate string members conflict with scalar values
+# - alternate types should have 2 or more branches
+##
+{ 'struct': 'SlotOption',
+ 'data': { 'option': 'str', 'values': 'any' } }
+
+##
+# @DeviceSlotInfo:
+#
+# Information on a set of slots where devices can be plugged.
+#
+# @device-types: List of device types accepted by the slots.
+# Any device plugged to the slot should implement
+# one of the accepted device types.
+#
+# @device: QOM path of device plugged to the slot, if any.
+#
+# @available: If false, the slot is not available for plugging any device.
+# This value can change at runtime if condition changes.
+#
+# @hotpluggable: If true, the slot accepts hotplugged devices. If false,
+# device_add won't work on the slot even if @available=true.
+#
+# @count: Number of slots represented by this slot set.
+#
+# @opts-complete: If true, all options required to plug devices
+# to slots in this set are present in @opts. If
+# false, slot information is incomplete in this
+# QEMU version and additional options may be
+# required to plug devices on those slots.
+#
+# @opts: Information on the arguments that should be provided to
+# @device_add if plugging a device to this slot.
+#
+# Incomplete Slot Sets
+# --------------------
+#
+# Slot sets with @opts-complete=false represent a bus that
+# doesn't support slot enumeration yet. Slots of this type should
+# be replaced by more detailed slot sets in future QEMU versions.
+#
+# If @count is omitted, the entry may or may not represent more
+# than one slots. Future QEMU versions should include additional
+# code to set @count on those entries.
+##
+{ 'struct': 'DeviceSlotInfo',
+ 'data': { 'device-types': [ 'str' ], '*device':
'str',
+ 'available': 'bool', 'hotpluggable': 'bool',
+ '*count': 'int', 'opts-complete': 'bool',
+ 'opts': [ 'SlotOption' ] } }
+
+##
+# @query-device-slots:
+#
+# Return the list of possible slots for plugging devices using
+# @device_add.
+##
+{ 'command': 'query-device-slots',
+ 'returns': [ 'DeviceSlotInfo' ] }
+
##
# @MachineInfo:
#
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index ae31728..0111350 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -191,6 +191,8 @@ struct BusClass {
void (*reset)(BusState *bus);
BusRealize realize;
BusUnrealize unrealize;
+ /*TODO: write doc */
+ DeviceSlotInfoList *(*enumerate_slots)(BusState *bus);
/* maximum devices allowed on the bus, 0: no limit. */
int max_dev;
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 8fd6df9..785f4af 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -30,6 +30,8 @@
#include "qemu/help_option.h"
#include "sysemu/block-backend.h"
#include "migration/misc.h"
+#include "qapi/qobject-output-visitor.h"
+#include "hw/boards.h"
/*
* Aliases were a bad idea from the start. Let's keep them
@@ -638,6 +640,42 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
return dev;
}
+typedef struct SlotListState {
+ DeviceSlotInfoList *result;
+ DeviceSlotInfoList **next;
+} SlotListState;
+
+static void append_slots(SlotListState *s, DeviceSlotInfoList *l)
+{
+ *s->next = l;
+ for (; l; l = l->next) {
+ s->next = &l->next;
+ }
+}
+
+static int enumerate_bus(Object *obj, void *opaque)
+{
+ SlotListState *s = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_BUS)) {
+ BusState *bus = BUS(obj);
+ BusClass *bc = BUS_GET_CLASS(bus);
+
+ if (bc->enumerate_slots) {
+ append_slots(s, bc->enumerate_slots(bus));
+ }
+ }
+ return 0;
+}
+
+DeviceSlotInfoList *qmp_query_device_slots(Error **errp)
+{
+ SlotListState s = { .next = &s.result };
+
+ object_child_foreach_recursive(qdev_get_machine(), enumerate_bus, &s);
+ return s.result;
+}
+
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent,
"", ## __VA_ARGS__)
static void qbus_print(Monitor *mon, BusState *bus, int indent);
--
2.9.4