From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1502747906549767.1597670534543; Mon, 14 Aug 2017 14:58:26 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 798F481229; Mon, 14 Aug 2017 21:58:24 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 50213600CC; Mon, 14 Aug 2017 21:58:24 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 0786D4A469; Mon, 14 Aug 2017 21:58:24 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v7ELwBSw014818 for ; Mon, 14 Aug 2017 17:58:11 -0400 Received: by smtp.corp.redhat.com (Postfix) id 6FCEB177F8; Mon, 14 Aug 2017 21:58:11 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5020C68D34; Mon, 14 Aug 2017 21:58:03 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 798F481229 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=libvir-list-bounces@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:36 -0300 Message-Id: <20170814215748.5158-2-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-loop: libvir-list@redhat.com Cc: libvir-list@redhat.com, Igor Mammedov Subject: [libvirt] [RFC v4 01/13] qmp: Define query-device-slots command X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Mon, 14 Aug 2017 21:58:25 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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 Cc: Markus Armbruster Cc: libvir-list@redhat.com, Cc: Igor Mammedov Cc: Laine Stump Cc: "Michael S. Tsirkin" Signed-off-by: Eduardo Habkost --- 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'} } =20 + +## +# @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 <=3D X <=3D 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=3Dtr= ue. +# +# @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=3Dfalse 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); =20 /* 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" =20 /* * Aliases were a bad idea from the start. Let's keep them @@ -638,6 +640,42 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **e= rrp) return dev; } =20 +typedef struct SlotListState { + DeviceSlotInfoList *result; + DeviceSlotInfoList **next; +} SlotListState; + +static void append_slots(SlotListState *s, DeviceSlotInfoList *l) +{ + *s->next =3D l; + for (; l; l =3D l->next) { + s->next =3D &l->next; + } +} + +static int enumerate_bus(Object *obj, void *opaque) +{ + SlotListState *s =3D opaque; + + if (object_dynamic_cast(obj, TYPE_BUS)) { + BusState *bus =3D BUS(obj); + BusClass *bc =3D 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 =3D { .next =3D &s.result }; + + object_child_foreach_recursive(qdev_get_machine(), enumerate_bus, &s); + return s.result; +} + =20 #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", #= # __VA_ARGS__) static void qbus_print(Monitor *mon, BusState *bus, int indent); --=20 2.9.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748023106671.7871471260787; Mon, 14 Aug 2017 15:00:23 -0700 (PDT) Received: from localhost ([::1]:58700 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNPJ-0002r8-Cd for importer@patchew.org; Mon, 14 Aug 2017 18:00:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42791) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNNO-0001Zp-Dj for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNNN-0002Kn-8t for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:22 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44012) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNNM-0002K7-VX for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:21 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D5F52C0587E3 for ; Mon, 14 Aug 2017 21:58:19 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 58F695D9CA; Mon, 14 Aug 2017 21:58:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D5F52C0587E3 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:37 -0300 Message-Id: <20170814215748.5158-3-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 14 Aug 2017 21:58:20 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 02/13] qapi: qobject_compare() helper X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The helper function will be useful when writing support code to deal with device slot information. TODO: documentation is incomplete and unclear, needs to be improved. Signed-off-by: Eduardo Habkost --- include/qapi/util.h | 39 +++++++++++++++++++++++++++++ qapi/qapi-util.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++= ++++ tests/test-qapi-util.c | 53 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) diff --git a/include/qapi/util.h b/include/qapi/util.h index 7436ed8..d4562c4 100644 --- a/include/qapi/util.h +++ b/include/qapi/util.h @@ -11,9 +11,48 @@ #ifndef QAPI_UTIL_H #define QAPI_UTIL_H =20 +#include "qapi/qmp/qobject.h" +#include "qapi-types.h" + int qapi_enum_parse(const char * const lookup[], const char *buf, int max, int def, Error **errp); =20 int parse_qapi_name(const char *name, bool complete); =20 +/** + * qobject_compare: + * + * Compare the value of @a and @b. + * + * If @a and @b have the same type and the same value (see list + * of supported types below), return 0. + * + * If @a and @b are both strings, return strcmp(a, b). + * + * If @a and @b are numbers, return a negative value if a < b, + * and a positive value if a > b. + * + * Otherwise (if @a and @b are not the same, have different types, + * are of an unsupported type, or are different), return a non-zero value. + * + * Note that this function doesn't support some types, and may + * return false if the types are unsupported, or if the types don't + * match exactly. + * + * Supported types: + * - QTYPE_QNULL + * - QTYPE_QSTRING + * - QTYPE_QBOOL + * - QTYPE_QNUM (integers only) + * - QTYPE_QLIST + * + * Unsupported (always return false): + * - QTYPE_QNUM (non-integer values) + * - QTYPE_QDICT + * + * TODO: rewrite documentation to be clearer. + * TODO: support non-integer QTYPE_NUM values and QTYPE_QDICT. + */ +int qobject_compare(QObject *a, QObject *b); + #endif diff --git a/qapi/qapi-util.c b/qapi/qapi-util.c index 46eda7d..67c5e82 100644 --- a/qapi/qapi-util.c +++ b/qapi/qapi-util.c @@ -13,6 +13,9 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qbool.h" #include "qapi/util.h" =20 int qapi_enum_parse(const char * const lookup[], const char *buf, @@ -80,3 +83,66 @@ int parse_qapi_name(const char *str, bool complete) } return p - str; } + +static int qnum_compare(QNum *a, QNum *b) +{ + int64_t ia, ib; + bool va =3D qnum_get_try_int(a, &ia); + bool vb =3D qnum_get_try_int(b, &ib); + + if (va && vb) { + return (ia < ib) ? -1 : (ia > ib) ? 1 : 0; + } + + /*TODO: uint, double */ + return -1; +} + +static int qlist_compare(QList *a, QList *b) +{ + const QListEntry *ea, *eb; + + for (ea =3D qlist_first(a), eb =3D qlist_first(b); + ea && eb; + ea =3D qlist_next(ea), eb =3D qlist_next(eb)) { + QObject *va =3D qlist_entry_obj(ea); + QObject *vb =3D qlist_entry_obj(eb); + int c =3D qobject_compare(va, vb); + if (c) { + return c; + } + } + + if (eb) { + return -1; + } else if (ea) { + return 1; + } else { + return 0; + } +} + +int qobject_compare(QObject *a, QObject *b) +{ + QType ta =3D qobject_type(a); + QType tb =3D qobject_type(b); + + if (ta !=3D tb) { + return -1; + } + + switch (ta) { + case QTYPE_QNULL: + return true; + case QTYPE_QNUM: + return qnum_compare(qobject_to_qnum(a), qobject_to_qnum(b)); + case QTYPE_QSTRING: + return strcmp(qstring_get_str(qobject_to_qstring(a)), qstring_get_= str(qobject_to_qstring(b))); + case QTYPE_QBOOL: + return (int)qbool_get_bool(qobject_to_qbool(a)) - (int)qbool_get_b= ool(qobject_to_qbool(b)); + case QTYPE_QLIST: + return qlist_compare(qobject_to_qlist(a), qobject_to_qlist(b)); + default: + return -1; + } +} diff --git a/tests/test-qapi-util.c b/tests/test-qapi-util.c index e869757..c0cf46c 100644 --- a/tests/test-qapi-util.c +++ b/tests/test-qapi-util.c @@ -13,6 +13,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/util.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qjson.h" #include "test-qapi-types.h" =20 static void test_qapi_enum_parse(void) @@ -75,11 +79,60 @@ static void test_parse_qapi_name(void) g_assert(ret =3D=3D -1); } =20 +static void test_qobject_compare(void) +{ + QString *a1 =3D qstring_from_str("abc"); + QString *a2 =3D qstring_from_str("abc"); + QString *b =3D qstring_from_str("bcd"); + QNum *i1 =3D qnum_from_int(100); + QNum *i2 =3D qnum_from_int(100); + QNum *j =3D qnum_from_int(200); + QList *l1 =3D qlist_new(); + QList *l2 =3D qlist_new(); + QList *m =3D qlist_new(); + + qlist_append_int(l1, 100); + qlist_append_int(l1, 200); + qlist_append_int(l2, 100); + qlist_append_int(l2, 200); + + qlist_append_int(m, 100); + qlist_append_int(m, 300); + + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(a2)), =3D=3D, 0); + g_assert_cmpint(qobject_compare(QOBJECT(i1), QOBJECT(i2)), =3D=3D, 0); + g_assert_cmpint(qobject_compare(QOBJECT(l1), QOBJECT(l2)), =3D=3D, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(b)), <, 0); + g_assert_cmpint(qobject_compare(QOBJECT(b), QOBJECT(a1)), >, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(i1), QOBJECT(j)), <, 0); + g_assert_cmpint(qobject_compare(QOBJECT(j), QOBJECT(i1)), >, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(l1), QOBJECT(m)), <, 0); + g_assert_cmpint(qobject_compare(QOBJECT(m), QOBJECT(l1)), >, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(i1)), !=3D, 0); + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(l1)), !=3D, 0); + g_assert_cmpint(qobject_compare(QOBJECT(l1), QOBJECT(i1)), !=3D, 0); + + QDECREF(a1); + QDECREF(a2); + QDECREF(b); + QDECREF(i1); + QDECREF(i2); + QDECREF(j); + QDECREF(l1); + QDECREF(l2); + QDECREF(m); +} + int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/qapi/util/qapi_enum_parse", test_qapi_enum_parse); g_test_add_func("/qapi/util/parse_qapi_name", test_parse_qapi_name); + g_test_add_func("/qapi/util/qobject_compare", test_qobject_compare); g_test_run(); return 0; } --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748212592149.340047838308; Mon, 14 Aug 2017 15:03:32 -0700 (PDT) Received: from localhost ([::1]:58730 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNSM-0005UY-Ur for importer@patchew.org; Mon, 14 Aug 2017 18:03:31 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42820) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNNS-0001ei-Fl for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNNP-0002M4-BC for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:26 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37624) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNNP-0002LT-1q for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:23 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E16C7F3FBD for ; Mon, 14 Aug 2017 21:58:21 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3F3DE5D9CA; Mon, 14 Aug 2017 21:58:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com E16C7F3FBD Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:38 -0300 Message-Id: <20170814215748.5158-4-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Mon, 14 Aug 2017 21:58:22 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 03/13] qdev: Add BusClass::device_type field X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The field will be useful when building device slot information for buses. TODO: Confirm if all bus types were handled by the patch. Signed-off-by: Eduardo Habkost --- include/hw/qdev-core.h | 3 +++ hw/audio/intel-hda.c | 7 +++++++ hw/block/fdc.c | 15 +++++++++++---- hw/char/virtio-serial-bus.c | 1 + hw/core/sysbus.c | 1 + hw/i2c/core.c | 7 +++++++ hw/ide/qdev.c | 1 + hw/input/adb.c | 7 +++++++ hw/ipack/ipack.c | 7 +++++++ hw/isa/isa-bus.c | 1 + hw/misc/auxbus.c | 1 + hw/pci/pci.c | 1 + hw/ppc/spapr_vio.c | 1 + hw/s390x/css-bridge.c | 2 ++ hw/s390x/event-facility.c | 1 + hw/s390x/s390-pci-bus.c | 7 +++++++ hw/scsi/scsi-bus.c | 1 + hw/sd/core.c | 7 +++++++ hw/ssi/ssi.c | 7 +++++++ hw/usb/bus.c | 1 + hw/usb/dev-smartcard-reader.c | 7 +++++++ hw/virtio/virtio-bus.c | 1 + 22 files changed, 83 insertions(+), 4 deletions(-) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 0111350..8aa1455 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -198,6 +198,9 @@ struct BusClass { int max_dev; /* number of automatically allocated bus ids (e.g. ide.0) */ int automatic_ids; + + /* Device type accepted by bus */ + const char *device_type; }; =20 typedef struct BusChild { diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 06acc98..13b6904 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -36,9 +36,16 @@ static Property hda_props[] =3D { DEFINE_PROP_END_OF_LIST() }; =20 +static void hda_codec_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_HDA_CODEC_DEVICE; +} + static const TypeInfo hda_codec_bus_info =3D { .name =3D TYPE_HDA_BUS, .parent =3D TYPE_BUS, + .class_init =3D hda_codec_bus_class_init, .instance_size =3D sizeof(HDACodecBus), }; =20 diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 4011290..976500f 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -60,6 +60,10 @@ #define TYPE_FLOPPY_BUS "floppy-bus" #define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS) =20 +#define TYPE_FLOPPY_DRIVE "floppy" +#define FLOPPY_DRIVE(obj) \ + OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE) + typedef struct FDCtrl FDCtrl; typedef struct FDrive FDrive; static FDrive *get_drv(FDCtrl *fdctrl, int unit); @@ -69,9 +73,16 @@ typedef struct FloppyBus { FDCtrl *fdc; } FloppyBus; =20 +static void floppy_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_FLOPPY_DRIVE; +} + static const TypeInfo floppy_bus_info =3D { .name =3D TYPE_FLOPPY_BUS, .parent =3D TYPE_BUS, + .class_init =3D floppy_bus_class_init, .instance_size =3D sizeof(FloppyBus), }; =20 @@ -497,10 +508,6 @@ static const BlockDevOps fd_block_ops =3D { }; =20 =20 -#define TYPE_FLOPPY_DRIVE "floppy" -#define FLOPPY_DRIVE(obj) \ - OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE) - typedef struct FloppyDrive { DeviceState qdev; uint32_t unit; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index f5bc173..28342af 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -837,6 +837,7 @@ static void virtser_bus_class_init(ObjectClass *klass, = void *data) { BusClass *k =3D BUS_CLASS(klass); k->print_dev =3D virtser_bus_dev_print; + k->device_type =3D TYPE_VIRTIO_SERIAL_PORT; } =20 static const TypeInfo virtser_bus_info =3D { diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 5d0887f..9259931 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -76,6 +76,7 @@ static void system_bus_class_init(ObjectClass *klass, voi= d *data) =20 k->print_dev =3D sysbus_dev_print; k->get_fw_dev_path =3D sysbus_get_fw_dev_path; + k->device_type =3D TYPE_SYS_BUS_DEVICE; } =20 static const TypeInfo system_bus_info =3D { diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 2c1234c..fb5aaad 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -35,9 +35,16 @@ static Property i2c_props[] =3D { #define TYPE_I2C_BUS "i2c-bus" #define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS) =20 +static void i2c_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_I2C_SLAVE; +} + static const TypeInfo i2c_bus_info =3D { .name =3D TYPE_I2C_BUS, .parent =3D TYPE_BUS, + .class_init =3D i2c_bus_class_init, .instance_size =3D sizeof(I2CBus), }; =20 diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index cc2f5bd..f17da1f 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -44,6 +44,7 @@ static void ide_bus_class_init(ObjectClass *klass, void *= data) =20 k->get_fw_dev_path =3D idebus_get_fw_dev_path; k->unrealize =3D idebus_unrealize; + k->device_type =3D TYPE_IDE_DEVICE; } =20 static void idebus_unrealize(BusState *bus, Error **errp) diff --git a/hw/input/adb.c b/hw/input/adb.c index fcca3a8..2fc292c 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -121,9 +121,16 @@ int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t p= oll_mask) return olen; } =20 +static void adb_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_ADB_DEVICE; +} + static const TypeInfo adb_bus_type_info =3D { .name =3D TYPE_ADB_BUS, .parent =3D TYPE_BUS, + .class_init =3D adb_bus_class_init, .instance_size =3D sizeof(ADBBusState), }; =20 diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c index 6021e6d..f22c504 100644 --- a/hw/ipack/ipack.c +++ b/hw/ipack/ipack.c @@ -106,9 +106,16 @@ static const TypeInfo ipack_device_info =3D { .abstract =3D true, }; =20 +static void ipack_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_IPACK_DEVICE; +} + static const TypeInfo ipack_bus_info =3D { .name =3D TYPE_IPACK_BUS, .parent =3D TYPE_BUS, + .class_init =3D ipack_bus_class_init, .instance_size =3D sizeof(IPackBus), }; =20 diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 348e0ea..45349c6 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -36,6 +36,7 @@ static void isa_bus_class_init(ObjectClass *klass, void *= data) =20 k->print_dev =3D isabus_dev_print; k->get_fw_dev_path =3D isabus_get_fw_dev_path; + k->device_type =3D TYPE_ISA_DEVICE; } =20 static const TypeInfo isa_dma_info =3D { diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 8a90ddd..7f4c87f 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -57,6 +57,7 @@ static void aux_bus_class_init(ObjectClass *klass, void *= data) * in monitor. */ k->print_dev =3D aux_slave_dev_print; + k->device_type =3D TYPE_AUX_SLAVE; } =20 AUXBus *aux_init_bus(DeviceState *parent, const char *name) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 258fbe5..31b4d69 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -154,6 +154,7 @@ static void pci_bus_class_init(ObjectClass *klass, void= *data) k->realize =3D pci_bus_realize; k->unrealize =3D pci_bus_unrealize; k->reset =3D pcibus_reset; + k->device_type =3D TYPE_PCI_DEVICE; =20 pbc->is_root =3D pcibus_is_root; pbc->bus_num =3D pcibus_num; diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index ea3bc8b..d07dcaa 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -61,6 +61,7 @@ static void spapr_vio_bus_class_init(ObjectClass *klass, = void *data) =20 k->get_dev_path =3D spapr_vio_get_dev_name; k->get_fw_dev_path =3D spapr_vio_get_dev_name; + k->device_type =3D TYPE_VIO_SPAPR_DEVICE; } =20 static const TypeInfo spapr_vio_bus_info =3D { diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index c4a9735..c442c23 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -17,6 +17,7 @@ #include "hw/s390x/css.h" #include "ccw-device.h" #include "hw/s390x/css-bridge.h" +#include "hw/s390x/virtio-ccw.h" #include "cpu.h" =20 /* @@ -82,6 +83,7 @@ static void virtual_css_bus_class_init(ObjectClass *klass= , void *data) =20 k->reset =3D virtual_css_bus_reset; k->get_dev_path =3D virtual_css_bus_get_dev_path; + k->device_type =3D TYPE_VIRTIO_CCW_DEVICE; } =20 static const TypeInfo virtual_css_bus_info =3D { diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 34b2faf..f2562ce 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -307,6 +307,7 @@ static void sclp_events_bus_class_init(ObjectClass *kla= ss, void *data) BusClass *bc =3D BUS_CLASS(klass); =20 bc->realize =3D sclp_events_bus_realize; + bc->device_type =3D TYPE_SCLP_EVENT; } =20 static const TypeInfo sclp_events_bus_info =3D { diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 61cfd21..0d71d7e 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -888,10 +888,17 @@ static const TypeInfo s390_pcihost_info =3D { } }; =20 +static void s390_pcibus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_S390_PCI_DEVICE; +} + static const TypeInfo s390_pcibus_info =3D { .name =3D TYPE_S390_PCI_BUS, .parent =3D TYPE_BUS, .instance_size =3D sizeof(S390PCIBus), + .class_init =3D s390_pcibus_class_init, }; =20 static uint16_t s390_pci_generate_uid(S390pciState *s) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index e364410..181428f7 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -31,6 +31,7 @@ static void scsi_bus_class_init(ObjectClass *klass, void = *data) =20 k->get_dev_path =3D scsibus_get_dev_path; k->get_fw_dev_path =3D scsibus_get_fw_dev_path; + k->device_type =3D TYPE_SCSI_DEVICE; hc->unplug =3D qdev_simple_device_unplug_cb; } =20 diff --git a/hw/sd/core.c b/hw/sd/core.c index 295dc44..5bfe404 100644 --- a/hw/sd/core.c +++ b/hw/sd/core.c @@ -158,11 +158,18 @@ void sdbus_reparent_card(SDBus *from, SDBus *to) sdbus_set_readonly(to, readonly); } =20 +static void sd_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_SD_CARD; +} + static const TypeInfo sd_bus_info =3D { .name =3D TYPE_SD_BUS, .parent =3D TYPE_BUS, .instance_size =3D sizeof(SDBus), .class_size =3D sizeof(SDBusClass), + .class_init =3D sd_bus_class_init, }; =20 static void sd_bus_register_types(void) diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 7eaaf56..c48920d 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -22,10 +22,17 @@ struct SSIBus { #define TYPE_SSI_BUS "SSI" #define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS) =20 +static void ssi_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_SSI_SLAVE; +} + static const TypeInfo ssi_bus_info =3D { .name =3D TYPE_SSI_BUS, .parent =3D TYPE_BUS, .instance_size =3D sizeof(SSIBus), + .class_init =3D ssi_bus_class_init, }; =20 static void ssi_cs_default(void *opaque, int n, int level) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index d910f84..42f85a7 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -33,6 +33,7 @@ static void usb_bus_class_init(ObjectClass *klass, void *= data) k->print_dev =3D usb_bus_dev_print; k->get_dev_path =3D usb_get_dev_path; k->get_fw_dev_path =3D usb_get_fw_dev_path; + k->device_type =3D TYPE_USB_DEVICE; hc->unplug =3D qdev_simple_device_unplug_cb; } =20 diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index bef1f03..01aa804 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1195,10 +1195,17 @@ static Property ccid_props[] =3D { #define TYPE_CCID_BUS "ccid-bus" #define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS) =20 +static void ccid_bus_class_init(ObjectClass *oc, void *opaque) +{ + BusClass *bc =3D BUS_CLASS(oc); + bc->device_type =3D TYPE_CCID_CARD; +} + static const TypeInfo ccid_bus_info =3D { .name =3D TYPE_CCID_BUS, .parent =3D TYPE_BUS, .instance_size =3D sizeof(CCIDBus), + .class_init =3D ccid_bus_class_init, }; =20 void ccid_card_send_apdu_to_guest(CCIDCardState *card, diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 3042232..76ce427 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -316,6 +316,7 @@ static void virtio_bus_class_init(ObjectClass *klass, v= oid *data) BusClass *bus_class =3D BUS_CLASS(klass); bus_class->get_dev_path =3D virtio_bus_get_dev_path; bus_class->get_fw_dev_path =3D virtio_bus_get_fw_dev_path; + bus_class->device_type =3D TYPE_VIRTIO_DEVICE; } =20 static const TypeInfo virtio_bus_info =3D { --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748543794743.9775135323214; Mon, 14 Aug 2017 15:09:03 -0700 (PDT) Received: from localhost ([::1]:59159 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNXi-0002hA-6M for importer@patchew.org; Mon, 14 Aug 2017 18:09:02 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42864) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNNb-0001nW-Dd for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNNX-0002Ql-Bs for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:53718) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNNW-0002Q3-VX for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:31 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DF1E77003E for ; Mon, 14 Aug 2017 21:58:29 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 39AE960BED; Mon, 14 Aug 2017 21:58:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com DF1E77003E Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:39 -0300 Message-Id: <20170814215748.5158-5-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Mon, 14 Aug 2017 21:58:30 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 04/13] qdev: Slot info helpers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Helper functions to deal with slot info data structures, and automatically merge similar device slots There's room for improvement on the slot merging algorithm, but this version should be enough to demonstrate how bus implementations can benefit from it. TODO: write API documentation, make object ownership/reference rules clear, clean up code. Signed-off-by: Eduardo Habkost --- include/hw/qdev-slotinfo.h | 85 +++++++ hw/core/slotinfo.c | 610 +++++++++++++++++++++++++++++++++++++++++= ++++ tests/test-slotinfo.c | 398 +++++++++++++++++++++++++++++ hw/core/Makefile.objs | 2 + tests/Makefile.include | 14 +- 5 files changed, 1103 insertions(+), 6 deletions(-) create mode 100644 include/hw/qdev-slotinfo.h create mode 100644 hw/core/slotinfo.c create mode 100644 tests/test-slotinfo.c diff --git a/include/hw/qdev-slotinfo.h b/include/hw/qdev-slotinfo.h new file mode 100644 index 0000000..6d8fb54 --- /dev/null +++ b/include/hw/qdev-slotinfo.h @@ -0,0 +1,85 @@ +#ifndef QDEV_SLOTINFO_H +#define QDEV_SLOTINFO_H + +#include "qapi/qmp/qobject.h" +#include "qapi/qmp/qstring.h" + +/** + * valuelist_contains: + * + * Returns true if the value list represented by @values + * contains @v. + * + * @values follows the format documented at SlotOption.values + * in the QAPI schema. + */ +bool valuelist_contains(QObject *values, QObject *v); + +/** + * valuelist_extend: + * + * Extend a value list with elements from another value list. + * + * Ownership of 'new' is transfered to the function. + */ +void valuelist_extend(QObject **valuelist, QObject *new); + +/* + * TODO: Use more efficient data structurs (instead of + * DeviceSlotInfoList and SlotOptionList) when building the list + * and combining items. + */ + +/** + * slot_options_can_be_combined: + * + * Check if two SlotOptionLists can be combined in one. + * + * Two slot option lists can be combined if all options have exactly + * the same value except (at most) one. + * + * Returns true if the option lists can be combined. + * + * If return value is true, *@opt_name is set to the only + * mismatching option name. If all options match, *@opt_name is + * set to NULL. + */ +bool slot_options_can_be_combined(SlotOptionList *a, SlotOptionList *b, + const char **opt_name); + +/*TODO: doc */ +bool slots_can_be_combined(DeviceSlotInfo *a, DeviceSlotInfo *b, + const char **opt_name); + +/*TODO: doc */ +void slots_combine(DeviceSlotInfo *a, DeviceSlotInfo *b, const char *opt_n= ame); + +/*TODO: doc */ +bool slots_try_combine(DeviceSlotInfo *a, DeviceSlotInfo *b); + +/*TODO: doc */ +void slot_list_add_slot(DeviceSlotInfoList **l, DeviceSlotInfo *slot); + +/*TODO: doc */ +DeviceSlotInfoList *slot_list_collapse(DeviceSlotInfoList *l); + +/*TODO: doc */ +void slot_add_opt(DeviceSlotInfo *slot, const char *option, QObject *value= s); + +#define slot_add_opt_str(slot, option, s) \ + slot_add_opt(slot, option, QOBJECT(qstring_from_str(s))); + +#define slot_add_opt_int(slot, option, i) \ + slot_add_opt(slot, option, QOBJECT(qnum_from_int(i))); + +SlotOption *slot_options_find_opt(SlotOptionList *opts, const char *option= ); + +static inline SlotOption *slot_find_opt(DeviceSlotInfo *slot, const char *= option) +{ + return slot_options_find_opt(slot->opts, option); +} + +/*TODO: doc */ +DeviceSlotInfo *make_slot(BusState *bus); + +#endif /* QDEV_SLOTINFO_H */ diff --git a/hw/core/slotinfo.c b/hw/core/slotinfo.c new file mode 100644 index 0000000..c03bda2 --- /dev/null +++ b/hw/core/slotinfo.c @@ -0,0 +1,610 @@ +#include "qemu/osdep.h" +#include "hw/qdev-core.h" +#include "hw/qdev-slotinfo.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qbool.h" +#include "qapi/qmp/qjson.h" +#include "qapi/util.h" +#include "qapi/qobject-output-visitor.h" +#include "qapi-visit.h" + +//#define DEBUG_QOBJECTS + +#ifdef DEBUG_QOBJECTS +#define _DBG(args...) fprintf(stderr, args); + +#define DBG(args...) do { _DBG("%s: ", __FUNCTION__); \ + _DBG(args); \ + } while (0) +#define QDBG(fmt, obj, args...) do { \ + QString *js =3D qobject_to_json(obj); \ + DBG(fmt ## args); \ + _DBG(": %s\n", qstring_get_str(js)); \ + QDECREF(js); \ + } while (0) +#else +#define DBG(...) do { } while (0) +#define QDBG(...) do { } while (0) +#endif + +/* Ensure a value list is normalized to a list of values + * + * This does NOT normalize individual elements of the list to be + * in the [A] or [A, B] format. + * + * Returns a new reference to the normalized value. + */ +static QList *valuelist_normalize(QObject *values) +{ + if (qobject_type(values) =3D=3D QTYPE_QLIST) { + qobject_incref(values); + return qobject_to_qlist(values); + } else { + QList *l =3D qlist_new(); + + qobject_incref(values); + qlist_append_obj(l, values); + return l; + } +} + +/* Simplify value list, if possible + * + * Onwership of @values is transfered to the function, and a + * new object is returned. + */ +static QObject *valuelist_simplify(QList *values) +{ + if (qlist_size(values) =3D=3D 1) { + QObject *o =3D qlist_entry_obj(qlist_first(values)); + QType t =3D qobject_type(o); + if (t =3D=3D QTYPE_QNULL || + t =3D=3D QTYPE_QNUM || + t =3D=3D QTYPE_QSTRING || + t =3D=3D QTYPE_QBOOL) { + qobject_incref(o); + QDECREF(values); + return o; + } + } + + return QOBJECT(values); +} + +/* Check if a given single-element value can be represented as a [A, B] ra= nge */ +static bool value_can_be_range(QObject *v) +{ + QType t =3D qobject_type(v); + return (t =3D=3D QTYPE_QNUM || t =3D=3D QTYPE_QSTRING); +} + +/* + * Represent a single value (if max is NULL), or a [min, max] range + * if @max is not NULL + */ +typedef struct ValueRange { + QObject *min, *max; +} ValueRange; + +/* + * Validate a value list element and put result on ValueRange + * + * NOTE: this won't increase ref count of @vr->min and @vr->max + */ +static bool valuelist_element_get_range(QObject *elm, ValueRange *vr) +{ + QObject *min =3D NULL, *max =3D NULL; + + if (qobject_type(elm) =3D=3D QTYPE_QLIST) { + QList *l =3D qobject_to_qlist(elm); + if (qlist_size(l) < 1 || qlist_size(l) > 2) { + return false; + } + min =3D qlist_entry_obj(qlist_first(l)); + if (qlist_size(l) =3D=3D 2) { + max =3D qlist_entry_obj(qlist_next(qlist_first(l))); + } + } else { + min =3D elm; + } + + assert(min); + /* Invalid range: */ + if (max && (!value_can_be_range(min) || !value_can_be_range(max) || + qobject_type(min) !=3D qobject_type(max))) { + return false; + } + + /* If the value can be a range, make it a range */ + if (!max && value_can_be_range(min)) { + max =3D min; + } + + vr->min =3D min; + vr->max =3D max; + return true; +} + +/* Check if @v is inside the @vr range */ +static bool range_contains(ValueRange *vr, QObject *v) +{ + assert(vr->min); + if (vr->max) { /* range */ + return qobject_type(vr->min) =3D=3D qobject_type(v) && + qobject_compare(vr->max, v) >=3D 0 && + qobject_compare(v, vr->min) >=3D 0; + } else { /* single element */ + return qobject_compare(vr->min, v) =3D=3D 0; + } +} + +/* Check if @a contains @b */ +static bool range_contains_range(ValueRange *a, ValueRange *b) +{ + bool r =3D range_contains(a, b->min); + if (b->max) { + r &=3D range_contains(a, b->max); + } + return r; +} + +/* Check if the intersection of @a and @b is not empty */ +static bool range_overlaps_range(ValueRange *a, ValueRange *b) +{ + return range_contains(a, b->min) || + (b->max && range_contains(a, b->max)) || + range_contains_range(b, a); +} + +/* + * Check if a given entry of a value list contains the range @minv-@maxv + * If @maxv is NULL, only check if the entry contains @minv + */ +static bool valuelist_entry_contains(QObject *ev, ValueRange *vr) +{ + ValueRange er; + + if (!valuelist_element_get_range(ev, &er)) { + return false; + } + return range_contains_range(&er, vr); +} + +/* + * Check if a given entry of a value list contains the range @minv-@maxv + * If @maxv is NULL, only check if the entry contains @minv + */ +static bool valuelist_entry_overlaps(QObject *ev, ValueRange *vr) +{ + ValueRange er; + + if (!valuelist_element_get_range(ev, &er)) { + return false; + } + + return range_overlaps_range(&er, vr); +} + +/* + * Find the entry in the value list that contains the range @minv-@maxv + * If @maxv is NULL, check if the value list contains @minv + * + * Returns the list entry that contains the range, or NULL if + * not found. + */ +static QListEntry *nvaluelist_find_range_match(QList *l, ValueRange *vr) +{ + QListEntry *e; + + QLIST_FOREACH_ENTRY(l, e) { + QObject *ev =3D qlist_entry_obj(e); + if (valuelist_entry_contains(ev, vr)) { + return e; + } + } + + return NULL; +} + +/* + * Find the entry in the value list that contains @v + * + * Returns the list entry that contains the range, or NULL if + * not found. + */ +static QListEntry *nvaluelist_find_value_match(QList *l, QObject *v) +{ + ValueRange vr =3D { .min =3D v }; + return nvaluelist_find_range_match(l, &vr); +} + +/* + * Try to sum i to number, if it's an integer. + * Otherwise, just return a new reference to @v + */ +static QObject *qnum_try_int_add(QObject *v, int i) +{ + QNum *qn; + uint64_t u64; + int64_t i64; + + if (qobject_type(v) !=3D QTYPE_QNUM) { + qobject_incref(v); + return v; + } + + /*TODO: we should be able to convert uint to int and vice-versa. e.g.: + * - qnum_try_int_add(qnum_from_int(INT64_MAX), 1) + * - qnum_try_int_add(qnum_from_uint(UINT64_MIN), -1) + */ + qn =3D qobject_to_qnum(v); + if (qnum_get_try_int(qn, &i64)) { + if ((i < 0) && INT64_MIN - i >=3D i64) { + i64 =3D INT64_MIN; + } else if ((i > 0) && INT64_MAX - i <=3D i64) { + i64 =3D INT64_MAX; + } else { + i64 =3D i64 + i; + } + return QOBJECT(qnum_from_int(i64)); + } else if (qnum_get_try_uint(qn, &u64)) { + if ((i < 0) && -i >=3D u64) { + u64 =3D 0; + } else if ((i > 0) && UINT64_MAX - i <=3D u64) { + u64 =3D UINT64_MAX; + } else { + u64 =3D u64 + i; + } + return QOBJECT(qnum_from_uint(u64)); + } else { + qobject_incref(v); + return v; + } +} + +/* + * Look for any entry that overlaps or touches @vr + * If @skip is not NULL, @skip is not considered as a match. + */ +static QListEntry *nvaluelist_find_overlap(QList *l, ValueRange *vr, + QListEntry *skip) +{ + QListEntry *r =3D NULL; + QListEntry *e; + ValueRange key; + + key.min =3D qnum_try_int_add(vr->min, -1); + key.max =3D qnum_try_int_add(vr->max, 1); + + QLIST_FOREACH_ENTRY(l, e) { + QObject *ev =3D qlist_entry_obj(e); + if (e =3D=3D skip) { + continue; + } + if (valuelist_entry_overlaps(ev, &key)) { + r =3D e; + break; + } + } + + qobject_decref(key.min); + qobject_decref(key.max); + return r; +} + +bool valuelist_contains(QObject *values, QObject *v) +{ + QList *l =3D valuelist_normalize(values); + bool r =3D !!nvaluelist_find_value_match(l, v); + + QDECREF(l); + return r; +} + +static QListEntry *valuelist_try_overlap(QList *l, ValueRange *vr, + QListEntry *skip) +{ + ValueRange ovr; + QList *newrange; + QListEntry *ov =3D nvaluelist_find_overlap(l, vr, skip); + + if (!ov) { + return NULL; + } + + valuelist_element_get_range(ov->value, &ovr); + if (qobject_compare(ovr.min, vr->min) > 0) { + ovr.min =3D vr->min; + } + if (qobject_compare(vr->max, ovr.max) > 0) { + ovr.max =3D vr->max; + } + + newrange =3D qlist_new(); + qobject_incref(ovr.min); + qlist_append_obj(newrange, ovr.min); + qobject_incref(ovr.max); + qlist_append_obj(newrange, ovr.max); + + /*FIXME: this is a hack */ + qobject_decref(ov->value); + ov->value =3D QOBJECT(newrange); + return ov; +} + +/* Ownership of @e is passed to the function */ +static QListEntry *valuelist_try_merge(QList *l, QListEntry *e) +{ + ValueRange vr; + QListEntry *ov; + + if (!valuelist_element_get_range(e->value, &vr)) { + return NULL; + } + + ov =3D valuelist_try_overlap(l, &vr, e); + assert(ov !=3D e); + if (ov) { + /*TODO: this is a hack */ + QTAILQ_REMOVE(&l->head, e, next); + qobject_decref(e->value); + g_free(e); + } + return ov; +} + +/* Ownership of @elm is NOT given to the function: only the reference + * count is increased if necessary. + */ +static void valuelist_append_element(QList *l, QObject *elm) +{ + ValueRange vr; + + if (valuelist_element_get_range(elm, &vr)) { + QListEntry *ov; + + if (nvaluelist_find_range_match(l, &vr)) { + return; + } + + ov =3D valuelist_try_overlap(l, &vr, NULL); + /* If we find an overlapping entry, keep trying to merge it with + * other elements. + */ + if (ov) { + while (ov) { + ov =3D valuelist_try_merge(l, ov); + } + return; + } + } + + /* No overlap found, just append element to the list */ + qobject_incref(elm); + qlist_append_obj(l, elm); +} + +void valuelist_extend(QObject **valuelist, QObject *new) +{ + QObject *old =3D *valuelist; + QList *l =3D valuelist_normalize(old); + QList *newl =3D valuelist_normalize(new); + QListEntry *e; + + QLIST_FOREACH_ENTRY(newl, e) { + QObject *elm =3D qlist_entry_obj(e); + valuelist_append_element(l, elm); + } + QDECREF(newl); + + *valuelist =3D valuelist_simplify(l); + qobject_decref(old); +} + +SlotOption *slot_options_find_opt(SlotOptionList *opts, const char *option) +{ + for (; opts; opts =3D opts->next) { + if (!strcmp(opts->value->option, option)) { + return opts->value; + } + } + return NULL; +} + +bool slot_options_can_be_combined(SlotOptionList *a, SlotOptionList *b, + const char **opt_name) +{ + SlotOptionList *ol; + const char *mismatch =3D NULL; + + /* Check if all options in @b will be handled when we loop through @a = */ + for (ol =3D b; ol; ol =3D ol->next) { + if (!slot_options_find_opt(a, ol->value->option)) { + return false; + } + } + + for (ol =3D a; ol; ol =3D ol->next) { + SlotOption *ao =3D ol->value; + SlotOption *bo =3D slot_options_find_opt(b, ao->option); + + if (!bo) { + return false; + } + + if (qobject_compare(bo->values, ao->values)) { + if (mismatch && strcmp(mismatch, ao->option)) { + return false; + } + + mismatch =3D ao->option; + } + } + + if (opt_name) { + *opt_name =3D mismatch; + } + return true; +} + +static int compare_strList(strList *a, strList *b) +{ + for (; a && b; a =3D a->next, b =3D b->next) { + int c =3D strcmp(a->value, b->value); + if (c) { + return c; + } + } + + if (b) { + return -1; + } else if (a) { + return 1; + } else { + return 0; + } + +} + +bool slots_can_be_combined(DeviceSlotInfo *a, DeviceSlotInfo *b, + const char **opt_name) +{ + if (a->available !=3D b->available || + a->hotpluggable !=3D b->hotpluggable || + a->has_count !=3D b->has_count || + a->opts_complete !=3D b->opts_complete || + a->has_device || b->has_device || + compare_strList(a->device_types, b->device_types)) { + return false; + } + + return slot_options_can_be_combined(a->opts, b->opts, opt_name); +} + +void slots_combine(DeviceSlotInfo *a, DeviceSlotInfo *b, const char *opt_n= ame) +{ + assert(slots_can_be_combined(a, b, NULL)); + if (a->has_count) { + a->count +=3D b->count; + } + if (opt_name) { + SlotOption *aopt =3D slot_options_find_opt(a->opts, opt_name); + SlotOption *bopt =3D slot_options_find_opt(b->opts, opt_name); + + valuelist_extend(&aopt->values, bopt->values); + } +} + +bool slots_try_combine(DeviceSlotInfo *a, DeviceSlotInfo *b) +{ + const char *opt =3D NULL; + assert(a !=3D b); + + if (slots_can_be_combined(a, b, &opt)) { + slots_combine(a, b, opt); + return true; + } + + return false; +} + +/* Try to combine @slot with an entry in @l + * + * Will return a pointer to the 'next' pointer in the previous entry, + * to allow callers to remove the entry from the list if necessary. + */ +static DeviceSlotInfoList **slot_list_try_combine_slot(DeviceSlotInfoList = **l, DeviceSlotInfo *slot) +{ + DeviceSlotInfoList **pprev; + + for (pprev =3D l; *pprev; pprev =3D &(*pprev)->next) { + DeviceSlotInfo *i =3D (*pprev)->value; + if (slots_try_combine(i, slot)) { + return pprev; + } + } + + return NULL; +} + +DeviceSlotInfoList *slot_list_collapse(DeviceSlotInfoList *l) +{ + DeviceSlotInfoList *newlist =3D NULL; + DeviceSlotInfoList *queue =3D l; + + while (queue) { + DeviceSlotInfoList **pprev; + DeviceSlotInfoList *next =3D queue->next; + + pprev =3D slot_list_try_combine_slot(&newlist, queue->value); + if (pprev) { + DeviceSlotInfoList *removed =3D *pprev; + /* Remove modified item from @newlist@ */ + *pprev =3D (*pprev)->next; + /* Dequeue item from @queue */ + queue->next =3D NULL; + qapi_free_DeviceSlotInfoList(queue); + /* Queue modified item on @queue */ + removed->next =3D next; + queue =3D removed; + } else { + /* Not combined, just insert into newlist */ + queue->next =3D newlist; + newlist =3D queue; + queue =3D next; + } + } + + return newlist; +} + +/* Ownership of @slot is given to the function */ +void slot_list_add_slot(DeviceSlotInfoList **l, DeviceSlotInfo *slot) +{ + DeviceSlotInfoList *li; + + /* Avoid adding new entry if it can be combined */ + if (slot_list_try_combine_slot(l, slot)) { + qapi_free_DeviceSlotInfo(slot); + return; + } + + li =3D g_new0(DeviceSlotInfoList, 1); + li->value =3D slot; + li->next =3D *l; + *l =3D li; +} + +void slot_add_opt(DeviceSlotInfo *slot, const char *option, QObject *value= s) +{ + SlotOptionList *l =3D g_new0(SlotOptionList, 1); + + l->value =3D g_new0(SlotOption, 1); + l->value->option =3D g_strdup(option); + l->value->values =3D values; + l->next =3D slot->opts; + slot->opts =3D l; +} + +/*TODO: move it to common code */ +static inline bool qbus_is_full(BusState *bus) +{ + BusClass *bus_class =3D BUS_GET_CLASS(bus); + return bus_class->max_dev && bus->max_index >=3D bus_class->max_dev; +} + +DeviceSlotInfo *make_slot(BusState *bus) +{ + DeviceSlotInfo *s =3D g_new0(DeviceSlotInfo, 1); + + s->device_types =3D g_new0(strList, 1); + s->device_types->value =3D g_strdup(BUS_GET_CLASS(bus)->device_type); + s->hotpluggable =3D qbus_is_hotpluggable(bus); + s->available =3D !qbus_is_full(bus); + + slot_add_opt_str(s, "bus", bus->name); + + return s; +} diff --git a/tests/test-slotinfo.c b/tests/test-slotinfo.c new file mode 100644 index 0000000..b169712 --- /dev/null +++ b/tests/test-slotinfo.c @@ -0,0 +1,398 @@ +/* + * Unit tests for QAPI utility functions + * + * Copyright (C) 2017 Red Hat Inc. + * + * Authors: + * Eduardo Habkost + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/util.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qjson.h" +#include "hw/qdev-slotinfo.h" + +#define JS(json) qobject_from_json((json), &error_abort) + +static bool json_valuelist_contains(const char *jvalues, const char *jvalu= e) +{ + QObject *values =3D JS(jvalues); + QObject *value =3D JS(jvalue); + bool r =3D valuelist_contains(values, value); + + qobject_decref(values); + qobject_decref(value); + return r; +} + +static void test_valuelist_contains(void) +{ + g_assert_true(json_valuelist_contains("100", "100")); + g_assert_false(json_valuelist_contains("100", "200")); + + g_assert_false(json_valuelist_contains("[]", "100")); + g_assert_true(json_valuelist_contains("[100, 200, 300]", "200")); + g_assert_false(json_valuelist_contains("[100, 200, 300]", "150")); + + g_assert_true(json_valuelist_contains("\"abc\"", "\"abc\"")); + g_assert_false(json_valuelist_contains("\"abc\"", "\"xyz\"")); + g_assert_true(json_valuelist_contains("[\"abc\"]", "\"abc\"")); + g_assert_false(json_valuelist_contains("[\"abc\", \"cde\"]", "\"xyz\""= )); + +#define TEST_RANGE "[[1,10], [18,20], [\"aaaa2\", \"jyz3\"], [-100, 5]," \ + "\"kkk\", 14, -50, [51], [[30, 31]] ]" + + /* [-100, 5] */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "-101")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "-100")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "-99")); + + /* -50 */ + g_assert_true( json_valuelist_contains(TEST_RANGE, "-51")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "-50")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "-49")); + + /* [-100, 5], [1, 10] */ + g_assert_true( json_valuelist_contains(TEST_RANGE, "-1")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "0")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "1")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "2")); + + /* [-100, 5] */ + g_assert_true( json_valuelist_contains(TEST_RANGE, "4")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "5")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "6")); + + /* [1, 10] */ + g_assert_true( json_valuelist_contains(TEST_RANGE, "9")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "10")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "11")); + + /* 14 */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "13")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "14")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "15")); + + /* [18, 20] */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "17")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "18")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "19")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "20")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "21")); + + /* [51] */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "50")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "51")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "52")); + + /* [ "aaa2" , "jyz3" ] */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "\"aaaa\"")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "\"aaaa1\"")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "\"aaaa2\"")); + g_assert_true(json_valuelist_contains(TEST_RANGE, "\"aaaa3\"")); + + /* [ "aaa2" , "jyz3" ] */ + g_assert_true(json_valuelist_contains(TEST_RANGE, "\"bcde\"")); + + /* [ "aaa2" , "jyz3" ] */ + g_assert_true( json_valuelist_contains(TEST_RANGE, "\"jyz\"")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "\"jyz2\"")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "\"jyz3\"")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "\"jyz4\"")); + + /* "kkk" */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "\"kk\"")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "\"kkk\"")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "\"kkkk\"")); + + /* [[30, 31]] */ + g_assert_false(json_valuelist_contains(TEST_RANGE, "30")); + g_assert_false(json_valuelist_contains(TEST_RANGE, "[30]")); + g_assert_true( json_valuelist_contains(TEST_RANGE, "[30, 31]")); + + /* empty set doesn't contain an empty list: */ + g_assert_false(json_valuelist_contains("[]", "[]")); + + /* [] is an invalid element on a value list: */ + g_assert_false(json_valuelist_contains("[[]]", "[]")); + + /* [[]] indicates [] is a valid value */ + g_assert_true(json_valuelist_contains("[[[]]]", "[]")); +} + +#define assert_valuelist_extend(before, extend, after) \ + do { \ + QObject *set =3D JS(before); \ + QObject *expected =3D JS(after); \ + \ + valuelist_extend(&set, JS(extend));; \ + g_assert_cmpint(qobject_compare(set, expected), =3D=3D, 0); \ + \ + qobject_decref(set); \ + qobject_decref(expected); \ + } while (0) + +static void test_valuelist_extend(void) +{ + assert_valuelist_extend("[]", + "1", + "1"); + + assert_valuelist_extend("1", + "1", + "1"); + + assert_valuelist_extend("1", + "3", + "[1, 3]"); + + assert_valuelist_extend("[1, 3]", + "6", + "[1, 3, 6]"); + + /*TODO: implement and test range merging */ + + /* single-element becomes range: */ + assert_valuelist_extend("[1, 3, 6]", + "4", + "[1, [3, 4], 6]"); + assert_valuelist_extend("[1, 4, 6]", + "3", + "[1, [3, 4], 6]"); + + + /* single-element merges two elements: */ + assert_valuelist_extend("[1, 3, 6]", + "2", + "[[1, 3], 6]"); + + /* [] -> empty set */ + assert_valuelist_extend("[1, 3, 6]", + "[]", + "[1, 3, 6]"); + + /* [3, 100] -> two elements: 3 and 100 (not a range) */ + assert_valuelist_extend("[[1, 4], 6]", + "[3, 100]", + "[[1, 4], 6, 100]"); + + /* tests for appending new ranges: */ + + /* add two ranges: 7-30, 40-50 */ + assert_valuelist_extend("[[1, 4], 6, 100]", + "[[7, 30], [40, 50]]", + "[[1, 4], [6, 30], 100, [40, 50]]"); + + /* multiple ways of appending to a range: */ + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "30", + "[[1, 4], [6, 30], [40, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "31", + "[[1, 4], [6, 31], [40, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[25, 35]]", + "[[1, 4], [6, 35], [40, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[30, 35]]", + "[[1, 4], [6, 35], [40, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[31, 35]]", + "[[1, 4], [6, 35], [40, 50], [53, 60]]"); + //TODO: make this work: + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[38, 51]]", + "[[1, 4], [6, 30], [38, 51], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[38, 52]]", + "[[1, 4], [6, 30], [38, 60]]"); + /* off-by-one check: */ + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "51", + "[[1, 4], [6, 30], [40, 51], [53, 60]]"); + /* _not_ appending to a range: */ + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "32", + "[[1, 4], [6, 30], [40, 50], [53, 60], 32]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[32, 35]]", + "[[1, 4], [6, 30], [40, 50], [53, 60], [32, 35= ]]"); + + /* multiple ways of prepending to a range: */ + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "40", + "[[1, 4], [6, 30], [40, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "39", + "[[1, 4], [6, 30], [39, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[35, 45]]", + "[[1, 4], [6, 30], [35, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[35, 40]]", + "[[1, 4], [6, 30], [35, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[35, 39]]", + "[[1, 4], [6, 30], [35, 50], [53, 60]]"); + /* off-by-one check: */ + assert_valuelist_extend("[[1, 4], [6, 30], [33, 50], [53, 60]]", + "32", + "[[1, 4], [6, 30], [32, 50], [53, 60]]"); + /* _not_ prepending to a range: */ + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "38", + "[[1, 4], [6, 30], [40, 50], [53, 60], 38]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[35, 38]]", + "[[1, 4], [6, 30], [40, 50], [53, 60], [35, 38= ]]"); + + /* multiple ways of combining two ranges: */ + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "5", + "[[1, 30], [40, 50], [53, 60]]"); + assert_valuelist_extend("[[1, 4], [6, 30], [40, 50], [53, 60]]", + "[[25, 45]]", + "[[1, 4], [6, 50], [53, 60]]"); +} + +static void test_slots_can_combine(void) +{ + DeviceSlotInfo *a =3D g_new0(DeviceSlotInfo, 1); + DeviceSlotInfo *b =3D g_new0(DeviceSlotInfo, 1); + const char *opt_name =3D NULL; + + g_assert_true(slots_can_be_combined(a, b, &opt_name)); + g_assert_null(opt_name); + + slot_add_opt(a, "bus", JS("\"mybus.0\"")); + g_assert_false(slots_can_be_combined(a, b, &opt_name)); + slot_add_opt(b, "bus", JS("\"mybus.0\"")); + + g_assert_true(slots_can_be_combined(a, b, &opt_name)); + g_assert_null(opt_name); + + slot_add_opt(a, "addr", JS("[ 1, 3 ]")); + g_assert_false(slots_can_be_combined(a, b, &opt_name)); + slot_add_opt(b, "addr", JS("5")); + + g_assert_true(slots_can_be_combined(a, b, &opt_name)); + g_assert_cmpstr(opt_name, =3D=3D, "addr"); + + slot_add_opt(a, "unit", JS("1")); + g_assert_false(slots_can_be_combined(a, b, &opt_name)); + slot_add_opt(b, "unit", JS("1")); + + g_assert_true(slots_can_be_combined(a, b, &opt_name)); + g_assert_cmpstr(opt_name, =3D=3D, "addr"); + + a->hotpluggable =3D true; + g_assert_false(slots_can_be_combined(a, b, &opt_name)); + a->hotpluggable =3D false; + + a->has_device =3D true; + a->device =3D g_strdup("/machine/somedevice"); + g_assert_false(slots_can_be_combined(a, b, &opt_name)); + g_free(a->device); + a->has_device =3D false; + a->device =3D NULL; + + slot_add_opt(a, "port", JS("10")); + g_assert_false(slots_can_be_combined(a, b, &opt_name)); + slot_add_opt(b, "port", JS("20")); + + g_assert_false(slots_can_be_combined(a, b, &opt_name)); +} + +static void test_slots_combine(void) +{ + DeviceSlotInfo *a =3D g_new0(DeviceSlotInfo, 1); + DeviceSlotInfo *b =3D g_new0(DeviceSlotInfo, 1); + SlotOption *o; + + slot_add_opt(a, "bus", JS("\"mybus.0\"")); + slot_add_opt(b, "bus", JS("\"mybus.0\"")); + + slot_add_opt(a, "addr", JS("[ 1, 3 ]")); + slot_add_opt(b, "addr", JS("5")); + + slot_add_opt(a, "unit", JS("1")); + slot_add_opt(b, "unit", JS("1")); + + g_assert_true(slots_try_combine(a, b)); + + o =3D a->opts->value; + g_assert_cmpstr(o->option, =3D=3D, "unit"); + g_assert_cmpint(qobject_compare(o->values, JS("1")), =3D=3D, 0); + + o =3D a->opts->next->value; + g_assert_cmpstr(o->option, =3D=3D, "addr"); + g_assert_cmpint(qobject_compare(o->values, JS("[1, 3, 5]")), =3D=3D, 0= ); + + o =3D a->opts->next->next->value; + g_assert_cmpstr(o->option, =3D=3D, "bus"); + g_assert_cmpint(qobject_compare(o->values, JS("\"mybus.0\"")), =3D=3D,= 0); +} + +static void test_slot_list_collapse(void) +{ + DeviceSlotInfoList *l =3D NULL; + SlotOption *o; + int node, socket, core, thread; + + for (node =3D 0; node < 4; node++) { + for (socket =3D 0; socket < 8; socket++) { + for (core =3D 0; core < 4; core++) { + for (thread =3D 0; thread < 2; thread++) { + DeviceSlotInfo *s =3D g_new0(DeviceSlotInfo, 1); + slot_add_opt_int(s, "node", node); + slot_add_opt_int(s, "socket", socket); + slot_add_opt_int(s, "core", core); + slot_add_opt_int(s, "thread", thread); + slot_list_add_slot(&l, s); + } + } + } + } + + /* + * All the entries above should be merged in a single entry: + * node =3D [0, 3] + * socket =3D [0, 7] + * core =3D [0, 3] + * thread =3D [0, 1] + */ + l =3D slot_list_collapse(l); + g_assert_nonnull(l); + g_assert_null(l->next); + + o =3D slot_find_opt(l->value, "node"); + g_assert_cmpint(qobject_compare(o->values, JS("[ [0, 3] ]")), =3D=3D, = 0); + + o =3D slot_find_opt(l->value, "socket"); + g_assert_cmpint(qobject_compare(o->values, JS("[ [0, 7] ]")), =3D=3D, = 0); + + o =3D slot_find_opt(l->value, "core"); + g_assert_cmpint(qobject_compare(o->values, JS("[ [0, 3] ]")), =3D=3D, = 0); + + o =3D slot_find_opt(l->value, "thread"); + g_assert_cmpint(qobject_compare(o->values, JS("[ [0, 1] ]")), =3D=3D, = 0); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/qapi/util/valuelist_contains", test_valuelist_contai= ns); + g_test_add_func("/qapi/util/valuelist_extend", test_valuelist_extend); + g_test_add_func("/qapi/util/slots_can_combine", test_slots_can_combine= ); + g_test_add_func("/qapi/util/slots_combine", test_slots_combine); + g_test_add_func("/qapi/util/slot_list_collapse", test_slot_list_collap= se); + g_test_run(); + return 0; +} diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index f8d7a4a..0f3a0a6 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -6,6 +6,7 @@ common-obj-y +=3D fw-path-provider.o common-obj-y +=3D irq.o common-obj-y +=3D hotplug.o common-obj-y +=3D nmi.o +common-obj-y +=3D slotinfo.o =20 common-obj-$(CONFIG_EMPTY_SLOT) +=3D empty_slot.o common-obj-$(CONFIG_XILINX_AXI) +=3D stream.o @@ -21,3 +22,4 @@ common-obj-$(CONFIG_PLATFORM_BUS) +=3D platform-bus.o =20 obj-$(CONFIG_SOFTMMU) +=3D generic-loader.o obj-$(CONFIG_SOFTMMU) +=3D null-machine.o + diff --git a/tests/Makefile.include b/tests/Makefile.include index eb4895f..493f9ce 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -131,6 +131,8 @@ check-unit-y +=3D tests/ptimer-test$(EXESUF) gcov-files-ptimer-test-y =3D hw/core/ptimer.c check-unit-y +=3D tests/test-qapi-util$(EXESUF) gcov-files-test-qapi-util-y =3D qapi/qapi-util.c +check-unit-y +=3D tests/test-slotinfo$(EXESUF) +gcov-files-test-slotinfo-y =3D hw/core/slotinfo.c =20 check-block-$(CONFIG_POSIX) +=3D tests/qemu-iotests-quick.sh =20 @@ -535,6 +537,10 @@ test-qom-obj-y =3D $(qom-obj-y) $(test-util-obj-y) test-qapi-obj-y =3D tests/test-qapi-visit.o tests/test-qapi-types.o \ tests/test-qapi-event.o tests/test-qmp-introspect.o \ $(test-qom-obj-y) +test-qdev-obj-y =3D hw/core/qdev.o hw/core/qdev-properties.o \ + hw/core/hotplug.o hw/core/bus.o hw/core/irq.o \ + hw/core/fw-path-provider.o hw/core/reset.o \ + hw/core/slotinfo.o benchmark-crypto-obj-y =3D $(crypto-obj-y) $(test-qom-obj-y) test-crypto-obj-y =3D $(crypto-obj-y) $(test-qom-obj-y) test-io-obj-y =3D $(io-obj-y) $(test-crypto-obj-y) @@ -573,12 +579,7 @@ tests/test-bufferiszero$(EXESUF): tests/test-bufferisz= ero.o $(test-util-obj-y) tests/atomic_add-bench$(EXESUF): tests/atomic_add-bench.o $(test-util-obj-= y) =20 tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ - hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\ - hw/core/bus.o \ - hw/core/irq.o \ - hw/core/fw-path-provider.o \ - hw/core/reset.o \ - $(test-qapi-obj-y) + $(test-qdev-obj-y) $(test-qapi-obj-y) tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/vmstate.o migration/vmstate-types.o migration/qemu-file.o \ migration/qemu-file-channel.o migration/qjson.o \ @@ -767,6 +768,7 @@ tests/vhost-user-bridge$(EXESUF): tests/vhost-user-brid= ge.o contrib/libvhost-use tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y) +tests/test-slotinfo$(EXESUF): tests/test-slotinfo.o hw/core/slotinfo.o $(t= est-qdev-obj-y) $(test-qom-obj-y) tests/numa-test$(EXESUF): tests/numa-test.o tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o test= s/acpi-utils.o =20 --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15027486454931.745942273669698; Mon, 14 Aug 2017 15:10:45 -0700 (PDT) Received: from localhost ([::1]:59472 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNZM-0004io-8R for importer@patchew.org; Mon, 14 Aug 2017 18:10:44 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42926) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNNj-0001ur-Pu for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNNj-0002Xt-42 for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39030) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNNi-0002Xa-Ty for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:43 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C8781883D4 for ; Mon, 14 Aug 2017 21:58:41 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5A2F45D9CA; Mon, 14 Aug 2017 21:58:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com C8781883D4 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:40 -0300 Message-Id: <20170814215748.5158-6-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Mon, 14 Aug 2017 21:58:41 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 05/13] query-device-slots: Collapse similar entries X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Use slot_list_collapse() on the final list returned by query-device-slots. This way we combine similar entries from different buses. For example, a machine with multiple IDE buses with no devices would return a single entry like this: { "available":true, "count":10, "device-types":["ide-device"], "hotpluggable":false, "opts":[ {"option":"unit","values":[[0,1]]}, {"option":"bus","values":["ide.4","ide.3","ide.5","ide.0","ide.1"]} ], "opts-complete":true } Signed-off-by: Eduardo Habkost --- qdev-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qdev-monitor.c b/qdev-monitor.c index 785f4af..edc6e34 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -673,7 +673,8 @@ DeviceSlotInfoList *qmp_query_device_slots(Error **errp) SlotListState s =3D { .next =3D &s.result }; =20 object_child_foreach_recursive(qdev_get_machine(), enumerate_bus, &s); - return s.result; + + return slot_list_collapse(s.result); } =20 =20 --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 150274872549567.27530933007984; Mon, 14 Aug 2017 15:12:05 -0700 (PDT) Received: from localhost ([::1]:59554 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNae-0006Iz-BB for importer@patchew.org; Mon, 14 Aug 2017 18:12:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43011) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNO0-00026q-6c for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:03 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNNw-0002f4-7F for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:00 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56367) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNNv-0002eK-U8 for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:58:56 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D171625A7A1 for ; Mon, 14 Aug 2017 21:58:54 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 41D7D600CC; Mon, 14 Aug 2017 21:58:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D171625A7A1 Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:41 -0300 Message-Id: <20170814215748.5158-7-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Mon, 14 Aug 2017 21:58:54 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 06/13] qdev core: generic enumerate_slots implementation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Implement a generic enumerate_slots method on TYPE_BUS The generic implementation will just report a opts-complete=3Dfalse entry, listing the "bus" option. This will let clients know that the bus is available, but that detailed slot information is not available by the running QEMU version. We disable the implementation on TYPE_SYS_BUS as sysbus is an exceptional case where only a handful of device types are actually user-creatable. This will be handled later by sysbus-specific slot enumeration code. TODO: write sysbus-specific slot enumeration code, based on sysbus device whitelist. Signed-off-by: Eduardo Habkost --- hw/core/bus.c | 42 ++++++++++++++++++++++++++++++++++++++++++ hw/core/sysbus.c | 7 +++++++ 2 files changed, 49 insertions(+) diff --git a/hw/core/bus.c b/hw/core/bus.c index 4651f24..227c092 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "hw/qdev.h" +#include "hw/qdev-slotinfo.h" #include "qapi/error.h" =20 static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handl= er, @@ -208,12 +209,53 @@ static char *default_bus_get_fw_dev_path(DeviceState = *dev) return g_strdup(object_get_typename(OBJECT(dev))); } =20 +static void class_check_user_creatable(ObjectClass *oc, void *opaque) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + bool *r =3D opaque; + + if (dc->user_creatable) { + *r =3D true; + } +} + +static bool bus_class_is_user_pluggable(BusClass *bc) +{ + bool r =3D false; + + object_class_foreach(class_check_user_creatable, + bc->device_type, false, &r); + return r; +} + +static DeviceSlotInfoList *bus_generic_enumerate_slots(BusState *bus) +{ + DeviceSlotInfoList *r =3D NULL; + BusChild *kid =3D NULL; + + if (!bus_class_is_user_pluggable(BUS_GET_CLASS(bus))) { + return NULL; + } + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceSlotInfo *slot =3D make_slot(bus); + slot->available =3D false; + slot->has_device =3D true; + slot->device =3D object_get_canonical_path(OBJECT(kid->child)); + slot_list_add_slot(&r, slot); + } + + slot_list_add_slot(&r, make_slot(bus)); + return r; +} + static void bus_class_init(ObjectClass *class, void *data) { BusClass *bc =3D BUS_CLASS(class); =20 class->unparent =3D bus_unparent; bc->get_fw_dev_path =3D default_bus_get_fw_dev_path; + bc->enumerate_slots =3D bus_generic_enumerate_slots; } =20 static void qbus_finalize(Object *obj) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 9259931..06cb4d8 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -77,6 +77,13 @@ static void system_bus_class_init(ObjectClass *klass, vo= id *data) k->print_dev =3D sysbus_dev_print; k->get_fw_dev_path =3D sysbus_get_fw_dev_path; k->device_type =3D TYPE_SYS_BUS_DEVICE; + /* + * We won't return sysbus devices on query-device-slots by now. + * + * TODO: return user-creatable whitelisted sybus devices + * if the machine supports dynamic sysbus devices. + */ + k->enumerate_slots =3D NULL; } =20 static const TypeInfo system_bus_info =3D { --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748075831867.172105277845; Mon, 14 Aug 2017 15:01:15 -0700 (PDT) Received: from localhost ([::1]:58708 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNQA-0003gl-JY for importer@patchew.org; Mon, 14 Aug 2017 18:01:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43077) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOA-0002EN-Oz for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNO6-0002lP-TS for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:10 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50548) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNO6-0002kx-KU for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:06 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6468D13A9D; Mon, 14 Aug 2017 21:59:05 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 49DF461F24; Mon, 14 Aug 2017 21:58:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6468D13A9D Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:42 -0300 Message-Id: <20170814215748.5158-8-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Mon, 14 Aug 2017 21:59:05 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 07/13] qdev: Enumerate CPU slots on query-device-slots X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Igor Mammedov , Bharata B Rao , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Use machine_query_hotpluggable_cpus() to build the slot list for CPU devices. Example output: the following command line: $ qemu-system-x86_64 -machine q35,accel=3Dkvm \ -cpu Haswell -smp 2,maxcpus=3D4 will generate the following entries: { "available": false, "count": 1, "device": "/machine/unattached/device[0]", "device-types": [ "Haswell-x86_64-cpu" ], "hotpluggable": true, "opts": [ { "option": "socket-id", "values": 0 }, { "option": "thread-id", "values": 0 }, { "option": "core-id", "values": 0 } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[2]", "device-types": [ "Haswell-x86_64-cpu" ], "hotpluggable": true, "opts": [ { "option": "socket-id", "values": 1 }, { "option": "thread-id", "values": 0 }, { "option": "core-id", "values": 0 } ], "opts-complete": true } { "available": true, "count": 2, "device-types": [ "Haswell-x86_64-cpu" ], "hotpluggable": true, "opts": [ { "option": "socket-id", "values": [ [ 2, 3 ] ] }, { "option": "thread-id", "values": 0 }, { "option": "core-id", "values": 0 } ], "opts-complete": true } Cc: Igor Mammedov Cc: David Gibson Cc: Bharata B Rao Signed-off-by: Eduardo Habkost --- qdev-monitor.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 70 insertions(+) diff --git a/qdev-monitor.c b/qdev-monitor.c index edc6e34..7ed41df 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -32,6 +32,8 @@ #include "migration/misc.h" #include "qapi/qobject-output-visitor.h" #include "hw/boards.h" +#include "hw/qdev-slotinfo.h" +#include "qapi-visit.h" =20 /* * Aliases were a bad idea from the start. Let's keep them @@ -668,11 +670,79 @@ static int enumerate_bus(Object *obj, void *opaque) return 0; } =20 +static void add_option(const char *key, QObject *obj, void *opaque) +{ + DeviceSlotInfo *slot =3D opaque; + + qobject_incref(obj); + slot_add_opt(slot, key, obj); +} + +/* Add all key/values in @d to as options to @slot */ +static void qdict_to_slot_props(QDict *d, DeviceSlotInfo *slot) +{ + qdict_iter(d, add_option, slot); +} + +static QDict *cpu_instance_props_to_qdict(CpuInstanceProperties *src) +{ + QObject *qobj =3D NULL; + Visitor *v =3D qobject_output_visitor_new(&qobj); + + visit_type_CpuInstanceProperties(v, "unused", &src, &error_abort); + visit_complete(v, &qobj); + visit_free(v); + return qobject_to_qdict(qobj); +} + +static void enumerate_cpu_slots(SlotListState *s) +{ + DeviceSlotInfoList *r =3D NULL; + MachineState *ms =3D MACHINE(qdev_get_machine()); + MachineClass *mc =3D MACHINE_GET_CLASS(ms); + HotpluggableCPUList *hcl; + HotpluggableCPUList *i; + + if (!mc->has_hotpluggable_cpus) { + return; + } + + hcl =3D machine_query_hotpluggable_cpus(ms); + for (i =3D hcl; i; i =3D i->next) { + DeviceSlotInfo *slot =3D g_new0(DeviceSlotInfo, 1); + HotpluggableCPU *hc =3D i->value; + QDict *props; + + slot->device_types =3D g_new0(strList, 1); + slot->device_types->value =3D g_strdup(hc->type); + slot->available =3D !hc->has_qom_path; + if (hc->has_qom_path) { + slot->has_device =3D true; + slot->device =3D g_strdup(hc->qom_path); + } + slot->has_count =3D true; + slot->count =3D 1; + slot->opts_complete =3D true; + /*TODO: should 'hotpluggable' be always true? */ + slot->hotpluggable =3D true; + + props =3D cpu_instance_props_to_qdict(hc->props); + qdict_to_slot_props(props, slot); + QDECREF(props); + + slot_list_add_slot(&r, slot); + } + qapi_free_HotpluggableCPUList(hcl); + + append_slots(s, r); +} + DeviceSlotInfoList *qmp_query_device_slots(Error **errp) { SlotListState s =3D { .next =3D &s.result }; =20 object_child_foreach_recursive(qdev_get_machine(), enumerate_bus, &s); + enumerate_cpu_slots(&s); =20 return slot_list_collapse(s.result); } --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748805456196.38574621822977; Mon, 14 Aug 2017 15:13:25 -0700 (PDT) Received: from localhost ([::1]:59651 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNbw-0007R2-15 for importer@patchew.org; Mon, 14 Aug 2017 18:13:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43153) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOL-0002P6-S4 for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNOL-0002tJ-10 for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:40514) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNOF-0002pz-L3; Mon, 14 Aug 2017 17:59:15 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 861A879732; Mon, 14 Aug 2017 21:59:14 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id AA46B600CE; Mon, 14 Aug 2017 21:59:06 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 861A879732 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:43 -0300 Message-Id: <20170814215748.5158-9-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Mon, 14 Aug 2017 21:59:14 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 08/13] ide: enumerate_slots implementation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , qemu-block@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Example output when using "-machine q35": { "available": true, "count": 1, "device-types": [ "ide-device" ], "hotpluggable": false, "opts": [ { "option": "unit", "values": 0 }, { "option": "bus", "values": "ide.2" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[19]", "device-types": [ "ide-device" ], "hotpluggable": false, "opts": [ { "option": "unit", "values": 1 }, { "option": "bus", "values": "ide.2" } ], "opts-complete": true } { "available": true, "count": 10, "device-types": [ "ide-device" ], "hotpluggable": false, "opts": [ { "option": "unit", "values": [ [ 0, 1 ] ] }, { "option": "bus", "values": [ "ide.4", "ide.3", "ide.5", "ide.0", "i= de.1" ] } ], "opts-complete": true } Cc: John Snow Cc: qemu-block@nongnu.org Signed-off-by: Eduardo Habkost --- hw/ide/qdev.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index f17da1f..cc96f6f 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -25,6 +25,7 @@ #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/block/block.h" +#include "hw/qdev-slotinfo.h" #include "sysemu/sysemu.h" #include "qapi/visitor.h" =20 @@ -38,6 +39,30 @@ static Property ide_props[] =3D { DEFINE_PROP_END_OF_LIST(), }; =20 +static DeviceSlotInfoList *ide_bus_enumerate_slots(BusState *bus) +{ + int unit; + DeviceSlotInfoList *r =3D NULL; + IDEBus *ib =3D IDE_BUS(bus); + + for (unit =3D 0; unit < 2; unit++) { + DeviceSlotInfo *s =3D make_slot(bus); + IDEDevice *dev =3D (unit ? ib->master : ib->slave); + slot_add_opt_int(s, "unit", unit); + s->opts_complete =3D true; + s->has_count =3D true; + s->count =3D 1; + if (dev) { + s->available =3D false; + s->has_device =3D true; + s->device =3D object_get_canonical_path(OBJECT(dev)); + } + slot_list_add_slot(&r, s); + } + + return r; +} + static void ide_bus_class_init(ObjectClass *klass, void *data) { BusClass *k =3D BUS_CLASS(klass); @@ -45,6 +70,7 @@ static void ide_bus_class_init(ObjectClass *klass, void *= data) k->get_fw_dev_path =3D idebus_get_fw_dev_path; k->unrealize =3D idebus_unrealize; k->device_type =3D TYPE_IDE_DEVICE; + k->enumerate_slots =3D ide_bus_enumerate_slots; } =20 static void idebus_unrealize(BusState *bus, Error **errp) --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748413876230.44384631893752; Mon, 14 Aug 2017 15:06:53 -0700 (PDT) Received: from localhost ([::1]:58851 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNVc-00004v-IC for importer@patchew.org; Mon, 14 Aug 2017 18:06:52 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43130) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOJ-0002Mi-QJ for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNOH-0002rc-Mk for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:19 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34918) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNOH-0002r6-G8 for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:17 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 62B1025C2A for ; Mon, 14 Aug 2017 21:59:16 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id E3F9C600CC; Mon, 14 Aug 2017 21:59:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 62B1025C2A Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:44 -0300 Message-Id: <20170814215748.5158-10-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Mon, 14 Aug 2017 21:59:16 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 09/13] pci: pci_bus_has_pcie_upstream_port() function X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The new helper will be useful when enumerating free slots on PCI buses. Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Signed-off-by: Eduardo Habkost --- hw/pci/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 31b4d69..ead9cbf 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2591,9 +2591,9 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range) pci_for_each_device_under_bus(bus, pci_dev_get_w64, range); } =20 -static bool pcie_has_upstream_port(PCIDevice *dev) +static bool pci_bus_has_pcie_upstream_port(PCIBus *bus) { - PCIDevice *parent_dev =3D pci_bridge_get_device(dev->bus); + PCIDevice *parent_dev =3D pci_bridge_get_device(bus); =20 /* Device associated with an upstream port. * As there are several types of these, it's easier to check the @@ -2609,7 +2609,7 @@ static bool pcie_has_upstream_port(PCIDevice *dev) =20 PCIDevice *pci_get_function_0(PCIDevice *pci_dev) { - if(pcie_has_upstream_port(pci_dev)) { + if(pci_bus_has_pcie_upstream_port(pci_dev->bus)) { /* With an upstream PCIe port, we only support 1 device at slot 0 = */ return pci_dev->bus->devices[0]; } else { --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748101407809.6672295883413; Mon, 14 Aug 2017 15:01:41 -0700 (PDT) Received: from localhost ([::1]:58714 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNQa-000432-6w for importer@patchew.org; Mon, 14 Aug 2017 18:01:40 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43175) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOV-0002Xu-IR for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNOQ-0002vx-Re for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:30 -0400 Received: from mx1.redhat.com ([209.132.183.28]:9513) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNOQ-0002vX-Iq for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:26 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7B545C04D938 for ; Mon, 14 Aug 2017 21:59:25 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id BD38460BEC; Mon, 14 Aug 2017 21:59:17 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 7B545C04D938 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:45 -0300 Message-Id: <20170814215748.5158-11-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 14 Aug 2017 21:59:25 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 10/13] pci: device-number & function properties X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The "addr" property on PCI devices has some magic for parsing it as a single PCI device number (called "slot" internally), or a "." string. Add simple integer properties that can represent the device address with no special parsing. Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Signed-off-by: Eduardo Habkost --- hw/pci/pci.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 63 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index ead9cbf..5753af3 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -41,6 +41,7 @@ #include "hw/hotplug.h" #include "hw/boards.h" #include "qemu/cutils.h" +#include "qapi-visit.h" =20 //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -2504,6 +2505,55 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev) return dev->bus->address_space_io; } =20 +static void pci_device_get_devnr(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + PCIDevice *dev =3D PCI_DEVICE(obj); + uint32_t devnr =3D PCI_SLOT(dev->devfn); + + visit_type_uint32(v, "device-number", &devnr, errp); +} + +static void pci_device_set_devnr(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + PCIDevice *dev =3D PCI_DEVICE(obj); + uint32_t devnr; + Error *local_err =3D NULL; + + visit_type_uint32(v, "device-number", &devnr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + dev->devfn =3D PCI_DEVFN(devnr, PCI_FUNC(dev->devfn)); +} + +static void pci_device_get_function(Object *obj, Visitor *v, const char *n= ame, + void *opaque, Error **errp) +{ + PCIDevice *dev =3D PCI_DEVICE(obj); + uint32_t function =3D PCI_FUNC(dev->devfn); + + visit_type_uint32(v, "function", &function, errp); +} + +static void pci_device_set_function(Object *obj, Visitor *v, const char *n= ame, + void *opaque, Error **errp) +{ + PCIDevice *dev =3D PCI_DEVICE(obj); + uint32_t function; + Error *local_err =3D NULL; + + visit_type_uint32(v, "function", &function, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + dev->devfn =3D PCI_DEVFN(PCI_SLOT(dev->devfn), function); +} + static void pci_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k =3D DEVICE_CLASS(klass); @@ -2514,6 +2564,19 @@ static void pci_device_class_init(ObjectClass *klass= , void *data) k->bus_type =3D TYPE_PCI_BUS; k->props =3D pci_props; pc->realize =3D pci_default_realize; + + /* Internally, bits 3:8 of devfn are called "slots", but: + * - they can be confused with physical slot numbers; + * - TYPE_PCIE_SLOT objects already have a "slot" property. + * So we use the terminology used in the PCI specifiction: + * "device number". + */ + object_class_property_add(klass, "device-number", "uint32", + pci_device_get_devnr, pci_device_set_devnr, + NULL, NULL, &error_abort); + object_class_property_add(klass, "function", "uint32", + pci_device_get_function, pci_device_set_func= tion, + NULL, NULL, &error_abort); } =20 AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748277295675.0316134368543; Mon, 14 Aug 2017 15:04:37 -0700 (PDT) Received: from localhost ([::1]:58731 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNTP-0006FT-U7 for importer@patchew.org; Mon, 14 Aug 2017 18:04:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43176) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOV-0002Xv-IM for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNOS-0002wt-QD for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:30 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57598) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNOS-0002wW-HO for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:28 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6A8BB81DF6 for ; Mon, 14 Aug 2017 21:59:27 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id E9BA460BEC; Mon, 14 Aug 2017 21:59:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6A8BB81DF6 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:46 -0300 Message-Id: <20170814215748.5158-12-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Mon, 14 Aug 2017 21:59:27 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 11/13] pci: enumerate_slots implementation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Enumerate each PCI function as a separate slots, because that's how QEMU treats multi-function PCI devices. Example output using "-machine q35" is below. { "available": true, "count": 224, "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": [ [ 0, 7 ] ] }, { "option": "device-number", "values": [ [ 3, 30 ] ] }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[30]", "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": 0 }, { "option": "device-number", "values": 2 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/q35/mch", "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": 0 }, { "option": "device-number", "values": 0 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[29]", "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": 0 }, { "option": "device-number", "values": 1 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[3]", "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": 0 }, { "option": "device-number", "values": 31 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[18]", "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": 2 }, { "option": "device-number", "values": 31 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 1, "device": "/machine/unattached/device[20]", "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": 3 }, { "option": "device-number", "values": 31 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 21, "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": [ [ 1, 7 ] ] }, { "option": "device-number", "values": [ [ 0, 2 ] ] }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } { "available": false, "count": 5, "device-types": [ "pci-device" ], "hotpluggable": false, "opts": [ { "option": "function", "values": [ 1, [ 4, 7 ] ] }, { "option": "device-number", "values": 31 }, { "option": "bus", "values": "pcie.0" } ], "opts-complete": true } Cc: "Michael S. Tsirkin" Cc: Marcel Apfelbaum Signed-off-by: Eduardo Habkost --- hw/pci/pci.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 5753af3..ae268a9 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -27,6 +27,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" +#include "hw/qdev-slotinfo.h" #include "monitor/monitor.h" #include "net/net.h" #include "sysemu/sysemu.h" @@ -144,6 +145,54 @@ static uint16_t pcibus_numa_node(PCIBus *bus) return NUMA_NODE_UNASSIGNED; } =20 + +static bool pci_bus_has_pcie_upstream_port(PCIBus *bus); + +static DeviceSlotInfoList *pci_bus_enumerate_slots(BusState *bus) +{ + PCIBus *pb =3D PCI_BUS(bus); + int devnr, devnrs; + DeviceSlotInfoList *r =3D NULL; + + if (pci_bus_has_pcie_upstream_port(pb)) { + devnrs =3D 1; + } else { + devnrs =3D PCI_SLOT_MAX; + } + + /* Each PCI devfn (device number + function) is a separate slot, + * because we implement multi-function PCI devices as separate + * device objects. + */ + for(devnr =3D PCI_SLOT(pb->devfn_min); devnr < devnrs; devnr++) { + PCIDevice *dev0 =3D pb->devices[PCI_DEVFN(devnr, 0)]; + int func; + + for (func =3D 0; func < PCI_FUNC_MAX; func++) { + /*TODO: add info about accepting only bridges on extra PCI roo= t buses */ + PCIDevice *dev =3D pb->devices[PCI_DEVFN(devnr, func)]; + DeviceSlotInfo *s =3D make_slot(bus); + slot_add_opt_int(s, "device-number", devnr); + slot_add_opt_int(s, "function", func); + s->opts_complete =3D true; + s->has_count =3D true; + s->count =3D 1; + /* Conditions that make a devnr unavailable: + * - function already occupied + * - function 0 already occupied by a device + */ + s->available &=3D !dev0 && !dev; + if (dev) { + s->has_device =3D true; + s->device =3D object_get_canonical_path(OBJECT(dev)); + } + slot_list_add_slot(&r, s); + } + } + + return r; +} + static void pci_bus_class_init(ObjectClass *klass, void *data) { BusClass *k =3D BUS_CLASS(klass); @@ -156,6 +205,7 @@ static void pci_bus_class_init(ObjectClass *klass, void= *data) k->unrealize =3D pci_bus_unrealize; k->reset =3D pcibus_reset; k->device_type =3D TYPE_PCI_DEVICE; + k->enumerate_slots =3D pci_bus_enumerate_slots; =20 pbc->is_root =3D pcibus_is_root; pbc->bus_num =3D pcibus_num; --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748459408922.2965748876187; Mon, 14 Aug 2017 15:07:39 -0700 (PDT) Received: from localhost ([::1]:58920 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNWM-00012J-50 for importer@patchew.org; Mon, 14 Aug 2017 18:07:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43220) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOf-0002eD-SP for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNOc-00030H-0l for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:41 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36482) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNOb-0002zy-Of for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:37 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A8DE025A7A4 for ; Mon, 14 Aug 2017 21:59:36 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id C1E48177F8; Mon, 14 Aug 2017 21:59:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com A8DE025A7A4 Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:47 -0300 Message-Id: <20170814215748.5158-13-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Mon, 14 Aug 2017 21:59:36 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 12/13] usb: enumerate_slots implementation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Gerd Hoffmann Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Example output for QEMU command-line: $ qemu-system-x86_64 -machine q35,usb=3Don -S \ -device usb-hub,port=3D2 -device usb-tablet,port=3D2.4 Output: {"available":true,"count":12, "device-types":["usb-device"],"hotpluggable":true, "opts":[ {"option":"port","values":["1","3","4","5","6","2.1","2.2","2.3","2.5"= ,"2.6","2.7","2.8"]}, {"option":"bus","values":"usb-bus.0"}], "opts-complete":true} {"available":false,"count":1,"device":"/machine/peripheral-anon/device[1]= ", "device-types":["usb-device"],"hotpluggable":true, "opts":[{"option":"port","values":"2"},{"option":"bus","values":"usb-bus= .0"}], "opts-complete":true} {"available":false,"count":1,"device":"/machine/peripheral-anon/device[2]= ", "device-types":["usb-device"],"hotpluggable":true, "opts":[{"option":"port","values":"2.4"},{"option":"bus","values":"usb-b= us.0"}], "opts-complete":true} TODO: Introduce USBPortList typedef in a separate patch TODO: decide if "bus" should be included in the output, or we should make "port" the only parameter required to identify where the device will be plugged. Cc: Gerd Hoffmann Signed-off-by: Eduardo Habkost --- include/hw/usb.h | 6 ++++-- hw/usb/bus.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/hw/usb.h b/include/hw/usb.h index eb28655..f8119c9 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -509,14 +509,16 @@ void musb_set_size(MUSBState *s, int epnum, int size,= int is_tx); #define TYPE_USB_BUS "usb-bus" #define USB_BUS(obj) OBJECT_CHECK(USBBus, (obj), TYPE_USB_BUS) =20 +typedef QTAILQ_HEAD(, USBPort) USBPortList; + struct USBBus { BusState qbus; USBBusOps *ops; int busnr; int nfree; int nused; - QTAILQ_HEAD(, USBPort) free; - QTAILQ_HEAD(, USBPort) used; + USBPortList free; + USBPortList used; QTAILQ_ENTRY(USBBus) next; }; =20 diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 42f85a7..fd00269 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -2,6 +2,7 @@ #include "hw/hw.h" #include "hw/usb.h" #include "hw/qdev.h" +#include "hw/qdev-slotinfo.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" @@ -25,6 +26,40 @@ static Property usb_props[] =3D { DEFINE_PROP_END_OF_LIST() }; =20 +static void usb_bus_enumerate_slot_list(DeviceSlotInfoList **r, USBBus *bu= s, USBPortList *l) +{ + USBPort *port; + + QTAILQ_FOREACH(port, l, next) { + DeviceSlotInfo *slot =3D make_slot(BUS(bus)); + /* + * TODO: should the "bus" option be included, or is + * "port" enough to identify the USB bus + port? + */ + slot_add_opt_str(slot, "port", port->path); + slot->opts_complete =3D slot; + if (port->dev) { + slot->has_device =3D true; + slot->device =3D object_get_canonical_path(OBJECT(port->dev)); + slot->available =3D false; + } + slot->has_count =3D 1; + slot->count =3D 1; + + slot_list_add_slot(r, slot); + } +} + +static DeviceSlotInfoList *usb_bus_enumerate_slots(BusState *bus) +{ + USBBus *ub =3D USB_BUS(bus); + DeviceSlotInfoList *r =3D NULL; + + usb_bus_enumerate_slot_list(&r, ub, &ub->free); + usb_bus_enumerate_slot_list(&r, ub, &ub->used); + return r; +} + static void usb_bus_class_init(ObjectClass *klass, void *data) { BusClass *k =3D BUS_CLASS(klass); @@ -34,6 +69,7 @@ static void usb_bus_class_init(ObjectClass *klass, void *= data) k->get_dev_path =3D usb_get_dev_path; k->get_fw_dev_path =3D usb_get_fw_dev_path; k->device_type =3D TYPE_USB_DEVICE; + k->enumerate_slots =3D usb_bus_enumerate_slots; hc->unplug =3D qdev_simple_device_unplug_cb; } =20 --=20 2.9.4 From nobody Mon Apr 29 19:30:00 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1502748300224262.8880081571018; Mon, 14 Aug 2017 15:05:00 -0700 (PDT) Received: from localhost ([::1]:58740 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNTm-0006au-Uu for importer@patchew.org; Mon, 14 Aug 2017 18:04:59 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43222) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dhNOf-0002eF-T2 for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dhNOe-000316-3l for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:42 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35596) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dhNOd-00030l-RD for qemu-devel@nongnu.org; Mon, 14 Aug 2017 17:59:40 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BD6781F56C for ; Mon, 14 Aug 2017 21:59:38 +0000 (UTC) Received: from localhost (ovpn-116-38.gru2.redhat.com [10.97.116.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 16D6477E3C; Mon, 14 Aug 2017 21:59:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com BD6781F56C Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=ehabkost@redhat.com From: Eduardo Habkost To: Eric Blake , qemu-devel@nongnu.org, Markus Armbruster , "Michael S. Tsirkin" , Marcel Apfelbaum , Laine Stump Date: Mon, 14 Aug 2017 18:57:48 -0300 Message-Id: <20170814215748.5158-14-ehabkost@redhat.com> In-Reply-To: <20170814215748.5158-1-ehabkost@redhat.com> References: <20170814215748.5158-1-ehabkost@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Mon, 14 Aug 2017 21:59:38 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v4 13/13] tests: Experimental query-device-slots test code X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The test script is crude and full of hacks. Included in the RFC just in case somebody wants to try it. The script uses environment variables as arguments to make it easier to be invoked from the tests/ Makefile later. Signed-off-by: Eduardo Habkost --- tests/qmp-machine-info.py | 300 ++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 300 insertions(+) create mode 100755 tests/qmp-machine-info.py diff --git a/tests/qmp-machine-info.py b/tests/qmp-machine-info.py new file mode 100755 index 0000000..ad4a0ac --- /dev/null +++ b/tests/qmp-machine-info.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python +import sys, os +MY_DIR =3D os.path.dirname(__file__) +sys.path.append(os.path.join(MY_DIR, '..', 'scripts')) +import qtest +import unittest +import logging +import argparse +import itertools +import operator +import re + +logger =3D logging.getLogger('qemu.tests.machineinfo') + +# machines that we can't easily test because they can't run on all hosts: +BLACKLIST =3D set(['xenpv', 'xenfv']) + +# machines known to be broken when using -nodefaults: +NODEFAULTS_BLACKLIST =3D set([ + 'cubieboard', # segfaults + 'petalogix-ml605', # segfaults + 'or32-sim', # segfaults + 'virtex-ml507', # segfaults + 'Niagara', # segfaults + 'akita', # "qemu: missing SecureDigital device" + 'borzoi', # "qemu: missing SecureDigital device" + 'cheetah', # "qemu: missing SecureDigital device" + 'connex', # "qemu: missing SecureDigital device" + 'mainstone', # "qemu: missing SecureDigital device" + 'n800', # "qemu: missing SecureDigital device" + 'n810', # "qemu: missing SecureDigital device" + 'spitz', # "qemu: missing SecureDigital device" + 'sx1', # "qemu: missing SecureDigital device" + 'sx1-v1', # "qemu: missing SecureDigital device" + 'terrier', # "qemu: missing SecureDigital device" + 'tosa', # "qemu: missing SecureDigital device" + 'verdex', # "qemu: missing SecureDigital device" + 'z2', # "qemu: missing SecureDigital device" +]) + +# iterators for QAPI ValueSets: +# all of the iterators below should support iter() and len() + +class InvalidValueSet(Exception): + pass + +class ElementIterator: + def __init__(self, e): + self._e =3D e + + def _data(self): + e =3D self._e + if type(e) is not list: + e =3D [e] + if len(e) =3D=3D 1: + return e + elif len(e) =3D=3D 2: + return xrange(e[0], e[1] + 1) + else: + raise InvalidValueSet + + def __iter__(self): + return iter(self._data()) + + def __len__(self): + return len(self._data()) + +class ValuesIterator: + def __init__(self, values): + if type(values) is not list: + values =3D [values] + self._values =3D values + + def _iterators(self): + return map(ElementIterator, self._values) + + def __iter__(self): + return itertools.chain(self._iterators()) + + def __len__(self): + return sum(map(len, self._iterators())) + + +#TODO: move to common code +def infoQDM(vm): + """Parse 'info qdm' output""" + args =3D {'command-line': 'info qdm'} + devhelp =3D vm.command('human-monitor-command', **args) + for l in devhelp.split('\n'): + l =3D l.strip() + if l =3D=3D '' or l.endswith(':'): + continue + d =3D {'name': re.search(r'name "([^"]+)"', l).group(1), + 'no-user': (re.search(', no-user', l) is not None)} + yield d + + + +class QueryMachinesTest(unittest.TestCase): + def setUp(self): + self.vm =3D None + + def tearDown(self): + if self.vm is not None: + self.vm.shutdown() + + def walkQOMTree(self, vm, path): + """Walk QOM tree recusrively, starting at path""" + children =3D vm.qmp('qom-list', path=3Dpath)['return'] + for c in children: + logging.debug('walking %s. child: %s', path, c) + if not c['type'].startswith('child<'): + continue + + cp =3D '%s/%s' % (path, c['name']) + yield cp + + for gc in self.walkQOMTree(vm, cp): + yield gc + + def findAllBuses(self, vm): + """Find all bus objects in the QOM tree""" + r =3D vm.qmp('qom-list-types', implements=3D'bus') + bus_types =3D set([b['name'] for b in r['return']]) + for cp in self.walkQOMTree(vm, '/machine'): + t =3D vm.qmp('qom-get', path=3Dcp, property=3D'type')['return'] + if t in bus_types: + yield dict(path=3Dcp, type=3Dt) + + def getSubtypes(self, implements, **kwargs): + """Get full list of typenames of subtypes of @implements""" + types =3D self.vm.command('qom-list-types', implements=3Dimplement= s, **kwargs) + return [st['name'] for st in types] + + + def getUserCreatableSubtypes(self, devtype): + alldevs =3D set(self.getSubtypes(devtype, abstract=3DFalse)) + # there's no way to query DeviceClass::user_creatable using QMP, + # so use 'info qdm': + no_user_devs =3D set([d['name'] for d in infoQDM(self.vm, ) if d['= no-user']]) + user_devs =3D alldevs.difference(no_user_devs) + return user_devs + + def typeImplements(self, t, i): + """Returns True if type @t implements type @i""" + stypes =3D self.getSubtypes(i) + return t in stypes + + def validateBus(self, bus, slots): + """Check if the bus identified by the slot matches the information= returned + for the slot. + + TODO: check if it is really a bus + TODO: check if device-types matches device-types + property in the bus + """ + + ##we could do this: + #bustype =3D self.vm.command('qom-get', path=3Dbus, property=3D'ty= pe') + #self.assertTrue(self.typeImplements(bustype, 'bus')) + ## but the bus _name_ (accepted by qbus_find()) does not necessari= ly matches the bus _path_ + + pass + + def checkSlotProps(self, slots): + """check if all properties on "props" are valid properties + that appear on device-list-properties for all accepted device types + """ + types_to_check =3D {} + buses_to_check =3D {} + for slot in slots: + for prop in slot['opts']: + if prop['option'] =3D=3D 'bus': + values =3D ValuesIterator(bus['values']) + self.assertEquals(len(values), 1) + bus =3D values[0] + buses_to_check.setdefault(v, []).append(slot) + + for t in slot['device-types']: + types_to_check.setdefault(t, set()).update(slot['opts'].ke= ys()) + + for bus,slots in buses_to_check.items(): + self.validateBus(bus, slots) + + for t, props in types_to_check.items(): + props.discard('bus') # 'bus' is handled by device_add directly + for st in self.vm.command('qom-list-types', implements=3Dt, ab= stract=3DFalse): + dprops =3D self.vm.command('device-list-properties', typen= ame=3Dst['name']) + dpropnames =3D set([p['name'] for p in dprops]) + for p in props: + self.assertIn(p, dpropnames) + + def checkAvailableField(self, slots): + for slot in slots: + if slot.has_key('max-devices') and len(slot['devices']) >=3D s= lot['max-devices']: + self.assertFalse(slot['available']) + + def checkSlotInfo(self, args): + #TODO: check if: + # * -device works with at least one device type + # * query-hotpluggable-cpus matches what's in query-device-slots + # * device-types match the property on the bus + # * available=3Dfalse if hotpluggable=3Dfalse + # * 'count' is always set if not incomplete + # * slot count is <=3D set of possible values for @props + self.vm =3D qtest.QEMUQtestMachine(self.binary, args=3Dargs) + self.vm.launch() + + slots =3D self.vm.command('query-device-slots') + #self.checkSlotProps(slots) + #self.checkSlotDevices(slots) + #self.checkAvailableField(slots) + + for slot in slots: + logging.debug('slot: %r', slot) + if 'device' in slot: + dev =3D slot['device'] + self.assertFalse(slot['available']) + dtype =3D self.vm.command('qom-get', path=3Ddev, property= =3D'type') + self.assertTrue(any(self.typeImplements(dtype, t) for t in= slot['device-types'])) + + for dt in slot['device-types']: + self.assertTrue(len(self.getUserCreatableSubtypes(dt)) > 0= , "There's no user-creatable subtype of %s" % (dt)) + + if slot['opts-complete']: + self.assertTrue('count' in slot) + + all_counts =3D [len(ValuesIterator(p['values'])) for p in = slot['opts']] + total_count =3D reduce(operator.mul, all_counts, 1) + logging.debug('%d possible values', total_count) + self.assertEquals(total_count, slot['count']) + + self.vm.shutdown() + + def machineTestSlotInfo(self): + if self.machine['name'] in BLACKLIST: + self.skipTest("machine %s on BLACKLIST" % (self.machine['name'= ])) + + args =3D ['-S', '-machine', self.machine['name']] + self.checkSlotInfo(args) + + #TODO: also test using full config from docs/config/q35-*.cfg + + @classmethod + def addMachineTest(klass, method_name, binary, machine): + """Dynamically add a testMachine___ method to= the class""" + method =3D getattr(klass, method_name) + def testMachine(self): + self.binary =3D binary + self.machine =3D machine + return method(self) + machine_name =3D machine['name'].replace('-', '_').replace('.', '_= ') + method_name =3D 'test_%s_%s_%s' % (method_name, machine['arch'], m= achine_name) + setattr(klass, method_name, testMachine) + return method_name + + + @classmethod + def discoverMachines(klass, binary): + """Run query-machines + + This method is run before test cases are started, so we + can dynamically add test cases for each machine supported + by the binary. + """ + vm =3D qtest.QEMUQtestMachine(binary=3Dbinary, args=3D['-S', '-mac= hine', 'none']) + vm.launch() + try: + arch =3D vm.qmp('query-target')['return']['arch'] + machines =3D vm.qmp('query-machines')['return'] + for m in machines: + m['arch'] =3D arch + finally: + vm.shutdown() + return machines + + @classmethod + def addMachineTests(klass, binary): + """Dynamically add test methods for each machine found on QEMU bin= ary + + Look for all methods with "machineTest" prefix, and add + custom test methods that will test them, for each machine-type + found on QEMU binary 'binary'. + """ + method_names =3D unittest.loader.getTestCaseNames(klass, prefix=3D= 'machineTest') + machines =3D klass.discoverMachines(binary) + for machine in machines: + for mname in method_names: + klass.addMachineTest(mname, binary, machine) + + +if os.getenv('QTEST_QEMU_BINARY'): + QueryMachinesTest.addMachineTests(os.getenv('QTEST_QEMU_BINARY')) + +if __name__ =3D=3D '__main__': + if os.getenv('QTEST_LOG_LEVEL'): + logging.basicConfig(level=3Dint(os.getenv('QTEST_LOG_LEVEL'))) + else: + logging.basicConfig(level=3Dlogging.WARN) + unittest.main() --=20 2.9.4