<ank...@nvidia.com> writes: > From: Ankit Agrawal <ank...@nvidia.com> > > NVIDIA GPU's support MIG (Mult-Instance GPUs) feature [1], which allows > partitioning of the GPU device resources (including device memory) into > several (upto 8) isolated instances. Each of the partitioned memory needs > a dedicated NUMA node to operate. The partitions are not fixed and they > can be created/deleted at runtime. > > Unfortunately Linux OS does not provide a means to dynamically create/destroy > NUMA nodes and such feature implementation is not expected to be trivial. The > nodes that OS discovers at the boot time while parsing SRAT remains fixed. So > we utilize the Generic Initiator Affinity structures that allows association > between nodes and devices. Multiple GI structures per BDF is possible, > allowing creation of multiple nodes by exposing unique PXM in each of these > structures. > > Introduce a new acpi-generic-initiator object to allow host admin provide the > device and the corresponding NUMA nodes. Qemu maintain this association and > use this object to build the requisite GI Affinity Structure. > > An admin can provide the range of nodes using a ':' delimited numalist and
Please don't create special-purpose syntax, use existing general-purpose syntax. See also review of qom.json below. > link it to a device by providing its id. The node ids are extracted from > numalist and stores as a uint16List. The following sample creates 8 nodes > and link them to the device dev0: > > -numa node,nodeid=2 \ > -numa node,nodeid=3 \ > -numa node,nodeid=4 \ > -numa node,nodeid=5 \ > -numa node,nodeid=6 \ > -numa node,nodeid=7 \ > -numa node,nodeid=8 \ > -numa node,nodeid=9 \ > -device > vfio-pci-nohotplug,host=0009:01:00.0,bus=pcie.0,addr=04.0,rombar=0,id=dev0 \ > -object acpi-generic-initiator,id=gi0,device=dev0,numalist=2:3:4:5:6:7:8:9 \ > > [1] https://www.nvidia.com/en-in/technologies/multi-instance-gpu > > Signed-off-by: Ankit Agrawal <ank...@nvidia.com> > --- > hw/acpi/acpi-generic-initiator.c | 80 ++++++++++++++++++++++++ > hw/acpi/meson.build | 1 + > include/hw/acpi/acpi-generic-initiator.h | 29 +++++++++ > qapi/qom.json | 16 +++++ > 4 files changed, 126 insertions(+) > create mode 100644 hw/acpi/acpi-generic-initiator.c > create mode 100644 include/hw/acpi/acpi-generic-initiator.h > > diff --git a/hw/acpi/acpi-generic-initiator.c > b/hw/acpi/acpi-generic-initiator.c > new file mode 100644 > index 0000000000..0699c878e2 > --- /dev/null > +++ b/hw/acpi/acpi-generic-initiator.c > @@ -0,0 +1,80 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved > + */ > + > +#include "qemu/osdep.h" > +#include "hw/qdev-properties.h" > +#include "qapi/error.h" > +#include "qapi/visitor.h" > +#include "qom/object_interfaces.h" > +#include "qom/object.h" > +#include "hw/qdev-core.h" > +#include "hw/vfio/vfio-common.h" > +#include "hw/vfio/pci.h" > +#include "hw/pci/pci_device.h" > +#include "sysemu/numa.h" > +#include "hw/acpi/acpi-generic-initiator.h" > + > +OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, > acpi_generic_initiator, > + ACPI_GENERIC_INITIATOR, OBJECT, > + { TYPE_USER_CREATABLE }, > + { NULL }) > + > +OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR) > + > +static void acpi_generic_initiator_init(Object *obj) > +{ > + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); > + gi->device = NULL; > + gi->nodelist = NULL; > +} > + > +static void acpi_generic_initiator_finalize(Object *obj) > +{ > + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); > + > + g_free(gi->device); > + qapi_free_uint16List(gi->nodelist); > +} > + > +static void acpi_generic_initiator_set_device(Object *obj, const char *val, > + Error **errp) > +{ > + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); > + > + gi->device = g_strdup(val); > +} > + > +static void acpi_generic_initiator_set_nodelist(Object *obj, const char *val, > + Error **errp) > +{ > + AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj); > + char *value = g_strdup(val); > + uint16_t node; > + uint16List **tail = &(gi->nodelist); > + char *nodestr = value ? strtok(value, ":") : NULL; > + > + while (nodestr) { > + if (sscanf(nodestr, "%hu", &node) != 1) { > + error_setg(errp, "failed to read node-id"); > + return; > + } > + > + if (node >= MAX_NODES) { > + error_setg(errp, "invalid node-id"); > + return; > + } > + > + QAPI_LIST_APPEND(tail, node); > + nodestr = strtok(NULL, ":"); > + } > +} > + > +static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data) > +{ > + object_class_property_add_str(oc, ACPI_GENERIC_INITIATOR_DEVICE_PROP, > NULL, > + acpi_generic_initiator_set_device); > + object_class_property_add_str(oc, ACPI_GENERIC_INITIATOR_NODELIST_PROP, > + NULL, acpi_generic_initiator_set_nodelist); > +} > diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build > index fc1b952379..2268589519 100644 > --- a/hw/acpi/meson.build > +++ b/hw/acpi/meson.build > @@ -1,5 +1,6 @@ > acpi_ss = ss.source_set() > acpi_ss.add(files( > + 'acpi-generic-initiator.c', > 'acpi_interface.c', > 'aml-build.c', > 'bios-linker-loader.c', > diff --git a/include/hw/acpi/acpi-generic-initiator.h > b/include/hw/acpi/acpi-generic-initiator.h > new file mode 100644 > index 0000000000..bb127b2541 > --- /dev/null > +++ b/include/hw/acpi/acpi-generic-initiator.h > @@ -0,0 +1,29 @@ > +#ifndef ACPI_GENERIC_INITIATOR_H > +#define ACPI_GENERIC_INITIATOR_H > + > +#include "hw/mem/pc-dimm.h" > +#include "hw/acpi/bios-linker-loader.h" > +#include "qemu/uuid.h" > +#include "hw/acpi/aml-build.h" > +#include "qom/object.h" > +#include "qom/object_interfaces.h" > + > +#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator" > + > +#define ACPI_GENERIC_INITIATOR_DEVICE_PROP "device" > +#define ACPI_GENERIC_INITIATOR_NODELIST_PROP "nodelist" > + > +typedef struct AcpiGenericInitiator { > + /* private */ > + Object parent; > + > + /* public */ > + char *device; > + uint16List *nodelist; > +} AcpiGenericInitiator; > + > +typedef struct AcpiGenericInitiatorClass { > + ObjectClass parent_class; > +} AcpiGenericInitiatorClass; > + > +#endif > diff --git a/qapi/qom.json b/qapi/qom.json > index fa3e88c8e6..66d2bffdcc 100644 > --- a/qapi/qom.json > +++ b/qapi/qom.json > @@ -779,6 +779,20 @@ > { 'struct': 'VfioUserServerProperties', > 'data': { 'socket': 'SocketAddress', 'device': 'str' } } > > +## > +# @AcpiGenericInitiatorProperties: > +# > +# Properties for acpi-generic-initiator objects. > +# > +# @device: the ID of the device to be associated with the node > +# > +# @nodelist: delimited numa node list > +# > +# Since: 8.2 > +## > +{ 'struct': 'AcpiGenericInitiatorProperties', > + 'data': { 'device': 'str', 'nodelist': 'str' } } Do not encode structured data in strings. Instead: 'nodes': ['uint16'] This matches MemoryBackendProperties member @host-nodes. Check out host_memory_backend_get_host_nodes() and host_memory_backend_set_host_nodes() to see how to work with such a member. > + > ## > # @RngProperties: > # > @@ -896,6 +910,7 @@ > ## > { 'enum': 'ObjectType', > 'data': [ > + 'acpi-generic-initiator', > 'authz-list', > 'authz-listfile', > 'authz-pam', > @@ -966,6 +981,7 @@ > 'id': 'str' }, > 'discriminator': 'qom-type', > 'data': { > + 'acpi-generic-initiator': 'AcpiGenericInitiatorProperties', > 'authz-list': 'AuthZListProperties', > 'authz-listfile': 'AuthZListFileProperties', > 'authz-pam': 'AuthZPAMProperties',