From nobody Thu Oct 30 05:02:38 2025 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; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1525362690780685.5234311384442; Thu, 3 May 2018 08:51:30 -0700 (PDT) Received: from localhost ([::1]:57358 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fEGVv-0001dv-Rs for importer@patchew.org; Thu, 03 May 2018 11:51:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50179) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fEGUS-0000h1-CB for qemu-devel@nongnu.org; Thu, 03 May 2018 11:49:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fEGUQ-0003gP-O8 for qemu-devel@nongnu.org; Thu, 03 May 2018 11:49:52 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:60478 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fEGUQ-0003gD-I2; Thu, 03 May 2018 11:49:50 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0EED94270963; Thu, 3 May 2018 15:49:50 +0000 (UTC) Received: from t460s.redhat.com (ovpn-117-201.ams2.redhat.com [10.36.117.201]) by smtp.corp.redhat.com (Postfix) with ESMTP id E0B4F215CDAA; Thu, 3 May 2018 15:49:47 +0000 (UTC) From: David Hildenbrand To: qemu-devel@nongnu.org Date: Thu, 3 May 2018 17:49:30 +0200 Message-Id: <20180503154936.18946-3-david@redhat.com> In-Reply-To: <20180503154936.18946-1-david@redhat.com> References: <20180503154936.18946-1-david@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Thu, 03 May 2018 15:49:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Thu, 03 May 2018 15:49:50 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'david@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v1 2/8] qdev: introduce ResourceHandler as a first-stage hotplug handler 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: Pankaj Gupta , Eduardo Habkost , "Michael S . Tsirkin" , David Hildenbrand , Markus Armbruster , Alexander Graf , qemu-s390x@nongnu.org, qemu-ppc@nongnu.org, Paolo Bonzini , Marcel Apfelbaum , Igor Mammedov , David Gibson , Richard Henderson 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" Hotplug handlers usually do 3 things: 1. Allocate some resources for a new device 2. Make the new device visible for the guest 3. Notify the guest about the new device While 2. and 3. are only ever performed once for a device, there might be various resources to allocate. E.g. a MemoryDevice could be exposed via Virtio. The proxy device hotplug handler (e.g. virtio-pci, virtio-ccw) takes care of exposing the device to the guest. However, we also have to allocate system resources, like a portion in guest physical address space, which is to be handled by the machine. One key difference between a hotplug handler and a resource handler is that resource handlers have no "unplug_request". There is no communication with the guest (this is done by a "hotplug" handler). So conceptually, they are different. For now we live with the assumption, that - in additon to the existing hotplug handler which can do some resource asignment - at most one resource handler is necessary. We might even later decide to have multiple resource handlers for a specific device (e.g. one for each interface they implement). For now, this design is sufficient. Resource handlers have to run before the hotplug handler runs (esp before exposing the device to the guest). Signed-off-by: David Hildenbrand --- hw/core/Makefile.objs | 1 + hw/core/qdev.c | 41 ++++++++++++++++++++++++++++++- hw/core/resource-handler.c | 57 +++++++++++++++++++++++++++++++++++++++= ++++ include/hw/boards.h | 9 +++++++ include/hw/resource-handler.h | 46 ++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 hw/core/resource-handler.c create mode 100644 include/hw/resource-handler.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index eb88ca979e..7474387fcd 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -6,6 +6,7 @@ common-obj-$(CONFIG_SOFTMMU) +=3D fw-path-provider.o # irq.o needed for qdev GPIO handling: common-obj-y +=3D irq.o common-obj-y +=3D hotplug.o +common-obj-y +=3D resource-handler.o common-obj-$(CONFIG_SOFTMMU) +=3D nmi.o =20 common-obj-$(CONFIG_EMPTY_SLOT) +=3D empty_slot.o diff --git a/hw/core/qdev.c b/hw/core/qdev.c index f6f92473b8..042e275884 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -35,6 +35,7 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include "hw/hotplug.h" +#include "hw/resource-handler.h" #include "hw/boards.h" #include "hw/sysbus.h" =20 @@ -271,6 +272,17 @@ HotplugHandler *qdev_get_hotplug_handler(DeviceState *= dev) return hotplug_ctrl; } =20 +static ResourceHandler *qdev_get_resource_handler(DeviceState *dev) +{ + MachineState *ms =3D MACHINE(qdev_get_machine()); + MachineClass *mc =3D MACHINE_GET_CLASS(ms); + + if (mc->get_resource_handler) { + return mc->get_resource_handler(ms, dev); + } + return NULL; +} + static int qdev_reset_one(DeviceState *dev, void *opaque) { device_reset(dev); @@ -814,6 +826,7 @@ static void device_set_realized(Object *obj, bool value= , Error **errp) { DeviceState *dev =3D DEVICE(obj); DeviceClass *dc =3D DEVICE_GET_CLASS(dev); + ResourceHandler *resource_ctrl; HotplugHandler *hotplug_ctrl; BusState *bus; Error *local_err =3D NULL; @@ -825,6 +838,8 @@ static void device_set_realized(Object *obj, bool value= , Error **errp) return; } =20 + resource_ctrl =3D qdev_get_resource_handler(dev); + if (value && !dev->realized) { if (!check_only_migratable(obj, &local_err)) { goto fail; @@ -840,6 +855,13 @@ static void device_set_realized(Object *obj, bool valu= e, Error **errp) g_free(name); } =20 + if (resource_ctrl) { + resource_handler_pre_assign(resource_ctrl, dev, &local_err); + if (local_err !=3D NULL) { + goto fail; + } + } + hotplug_ctrl =3D qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); @@ -858,12 +880,19 @@ static void device_set_realized(Object *obj, bool val= ue, Error **errp) =20 DEVICE_LISTENER_CALL(realize, Forward, dev); =20 + if (resource_ctrl) { + resource_handler_assign(resource_ctrl, dev, &local_err); + if (local_err !=3D NULL) { + goto post_realize_fail; + } + } + if (hotplug_ctrl) { hotplug_handler_plug(hotplug_ctrl, dev, &local_err); } =20 if (local_err !=3D NULL) { - goto post_realize_fail; + goto post_assign_fail; } =20 /* @@ -903,6 +932,11 @@ static void device_set_realized(Object *obj, bool valu= e, Error **errp) if (qdev_get_vmsd(dev)) { vmstate_unregister(dev, qdev_get_vmsd(dev), dev); } + + if (resource_ctrl) { + resource_handler_unassign(resource_ctrl, dev); + } + if (dc->unrealize) { local_errp =3D local_err ? NULL : &local_err; dc->unrealize(dev, local_errp); @@ -928,6 +962,11 @@ child_realize_fail: vmstate_unregister(dev, qdev_get_vmsd(dev), dev); } =20 +post_assign_fail: + if (resource_ctrl) { + resource_handler_unassign(resource_ctrl, dev); + } + post_realize_fail: g_free(dev->canonical_path); dev->canonical_path =3D NULL; diff --git a/hw/core/resource-handler.c b/hw/core/resource-handler.c new file mode 100644 index 0000000000..0a1ff0e66a --- /dev/null +++ b/hw/core/resource-handler.c @@ -0,0 +1,57 @@ +/* + * Resource handler interface. + * + * Copyright (c) 2018 Red Hat Inc. + * + * Authors: + * David Hildenbrand + * + * 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 "hw/resource-handler.h" +#include "qemu/module.h" + +void resource_handler_pre_assign(ResourceHandler *rh, + const DeviceState *dev, Error **errp) +{ + ResourceHandlerClass *rhc =3D RESOURCE_HANDLER_GET_CLASS(rh); + + if (rhc->pre_assign) { + rhc->pre_assign(rh, dev, errp); + } +} + +void resource_handler_assign(ResourceHandler *rh, DeviceState *dev, + Error **errp) +{ + ResourceHandlerClass *rhc =3D RESOURCE_HANDLER_GET_CLASS(rh); + + if (rhc->assign) { + rhc->assign(rh, dev, errp); + } +} + +void resource_handler_unassign(ResourceHandler *rh, DeviceState *dev) +{ + ResourceHandlerClass *rhc =3D RESOURCE_HANDLER_GET_CLASS(rh); + + if (rhc->unassign) { + rhc->unassign(rh, dev); + } +} + +static const TypeInfo resource_handler_info =3D { + .name =3D TYPE_RESOURCE_HANDLER, + .parent =3D TYPE_INTERFACE, + .class_size =3D sizeof(ResourceHandlerClass), +}; + +static void resource_handler_register_types(void) +{ + type_register_static(&resource_handler_info); +} + +type_init(resource_handler_register_types) diff --git a/include/hw/boards.h b/include/hw/boards.h index 8748964e6f..ff5142d7c2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -8,6 +8,7 @@ #include "hw/qdev.h" #include "qom/object.h" #include "qom/cpu.h" +#include "hw/resource-handler.h" =20 /** * memory_region_allocate_system_memory - Allocate a board's main memory @@ -115,6 +116,12 @@ typedef struct { * of HotplugHandler object, which handles hotplug operation * for a given @dev. It may return NULL if @dev doesn't require * any actions to be performed by hotplug handler. + * @get_resource_handler: this function is called when a new device is + * about to be hotplugged. If defined, it returns p= ointer + * to an instance of ResourceHandler object, which + * handles resource asignment for a given @dev. It + * may return NULL if @dev doesn't require any acti= ons + * to be performed by a resource handler. * @cpu_index_to_instance_props: * used to provide @cpu_index to socket/core/thread number mapping, all= owing * legacy code to perform maping from cpu_index to topology properties @@ -208,6 +215,8 @@ struct MachineClass { =20 HotplugHandler *(*get_hotplug_handler)(MachineState *machine, DeviceState *dev); + ResourceHandler *(*get_resource_handler)(MachineState *machine, + const DeviceState *dev); CpuInstanceProperties (*cpu_index_to_instance_props)(MachineState *mac= hine, unsigned cpu_inde= x); const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine); diff --git a/include/hw/resource-handler.h b/include/hw/resource-handler.h new file mode 100644 index 0000000000..3eda1bec5c --- /dev/null +++ b/include/hw/resource-handler.h @@ -0,0 +1,46 @@ +/* + * Resource handler interface. + * + * Copyright (c) 2018 Red Hat Inc. + * + * Authors: + * David Hildenbrand + * + * 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. + */ + +#ifndef RESOURCE_HANDLER_H +#define RESOURCE_HANDLER_H + +#include "qom/object.h" + +#define TYPE_RESOURCE_HANDLER "resource-handler" + +#define RESOURCE_HANDLER_CLASS(klass) \ + OBJECT_CLASS_CHECK(ResourceHandlerClass, (klass), TYPE_RESOURCE_HANDLE= R) +#define RESOURCE_HANDLER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ResourceHandlerClass, (obj), TYPE_RESOURCE_HANDLER) +#define RESOURCE_HANDLER(obj) \ + INTERFACE_CHECK(ResourceHandler, (obj), TYPE_RESOURCE_HANDLER) + +typedef struct ResourceHandler { + Object Parent; +} ResourceHandler; + +typedef struct ResourceHandlerClass { + InterfaceClass parent; + + void (*pre_assign)(ResourceHandler *rh, const DeviceState *dev, + Error **errp); + void (*assign)(ResourceHandler *rh, DeviceState *dev, Error **errp); + void (*unassign)(ResourceHandler *rh, DeviceState *dev); +} ResourceHandlerClass; + +void resource_handler_pre_assign(ResourceHandler *rh, const DeviceState *d= ev, + Error **errp); +void resource_handler_assign(ResourceHandler *rh, DeviceState *dev, + Error **errp); +void resource_handler_unassign(ResourceHandler *rh, DeviceState *dev); + +#endif /* RESOURCE_HANDLER_H */ --=20 2.14.3