[PATCH 91/95] drm/amdgpu: Expose ualink info under each xcp

Alex Deucher <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Lijo Lazar <[email protected]>

Mirror the read-only ualink info attributes on each secondary compute
partition as a per-partition ualink node, so a partition-scoped consumer
(e.g. a container that only sees its partition's device node) can read
the ualink identity and state. Partition 0 shares the primary device,
which already exposes that node, so it is skipped. An inactive partition
device won't be having any attributes listed under ualink node.

The per-partition attributes are served by thin wrappers that delegate
to the existing device-level info show functions. A reference on the
info kobject is held for the node's lifetime so it cannot be freed
while a partition still uses it.

Signed-off-by: Lijo Lazar <[email protected]>
Assisted-by: Claude (claude-opus-4.7)
Reviewed-by: Felix Kuehling <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 165 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h |   3 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c    |   6 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h    |   7 +
 4 files changed, 181 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
index 0baa8c07077d5..765105aea09e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
@@ -746,6 +746,37 @@ UALINK_ENUM_SHOW(info, addr_mode, vpod.addr_mode);
 UALINK_ENUM_SHOW(info, accel_state, accel_state);
 UALINK_IDARRAY_SHOW(info, local_accels, local_accels, n_local_accels);
 
+static struct amdgpu_device *ualink_xcp_kobj_to_adev(struct kobject *kobj)
+{
+	struct amdgpu_xcp *xcp = container_of(kobj, struct amdgpu_xcp,
+					      ualink.kobj);
+
+	return xcp->xcp_mgr->adev;
+}
+
+#define UALINK_XCP_INFO_SHOW(name)					\
+static ssize_t ualink_xcp_info_##name##_show(struct kobject *kobj,	\
+		struct kobj_attribute *attr, char *buf)			\
+{									\
+	struct amdgpu_device *adev = ualink_xcp_kobj_to_adev(kobj);	\
+									\
+	return ualink_info_##name##_show(&adev->ualink.info->kobj,	\
+					 attr, buf);			\
+}
+
+UALINK_XCP_INFO_SHOW(link_type)
+UALINK_XCP_INFO_SHOW(accel_id)
+UALINK_XCP_INFO_SHOW(bandwidth)
+UALINK_XCP_INFO_SHOW(latency)
+UALINK_XCP_INFO_SHOW(ppod_id)
+UALINK_XCP_INFO_SHOW(ppod_size)
+UALINK_XCP_INFO_SHOW(vpod_id)
+UALINK_XCP_INFO_SHOW(vpod_size)
+UALINK_XCP_INFO_SHOW(vpod_active_accels)
+UALINK_XCP_INFO_SHOW(addr_mode)
+UALINK_XCP_INFO_SHOW(accel_state)
+UALINK_XCP_INFO_SHOW(local_accels)
+
 #define UALINK_INFO_ATTR(name) __ATTR(name, 0444, ualink_info_##name##_show, NULL)
 static struct kobj_attribute ualink_info_link_type = UALINK_INFO_ATTR(link_type);
 static struct kobj_attribute ualink_info_accel_id  = UALINK_INFO_ATTR(accel_id);
@@ -776,6 +807,58 @@ static const struct attribute *ualink_info_attrs[] = {
 	NULL
 };
 
+#define UALINK_XCP_INFO_ATTR(name) \
+	__ATTR(name, 0444, ualink_xcp_info_##name##_show, NULL)
+static struct kobj_attribute ualink_xcp_info_link_type = UALINK_XCP_INFO_ATTR(link_type);
+static struct kobj_attribute ualink_xcp_info_accel_id  = UALINK_XCP_INFO_ATTR(accel_id);
+static struct kobj_attribute ualink_xcp_info_bandwidth = UALINK_XCP_INFO_ATTR(bandwidth);
+static struct kobj_attribute ualink_xcp_info_latency   = UALINK_XCP_INFO_ATTR(latency);
+static struct kobj_attribute ualink_xcp_info_ppod_id   = UALINK_XCP_INFO_ATTR(ppod_id);
+static struct kobj_attribute ualink_xcp_info_ppod_size = UALINK_XCP_INFO_ATTR(ppod_size);
+static struct kobj_attribute ualink_xcp_info_vpod_id   = UALINK_XCP_INFO_ATTR(vpod_id);
+static struct kobj_attribute ualink_xcp_info_vpod_size = UALINK_XCP_INFO_ATTR(vpod_size);
+static struct kobj_attribute ualink_xcp_info_vpod_active_accels = UALINK_XCP_INFO_ATTR(vpod_active_accels);
+static struct kobj_attribute ualink_xcp_info_addr_mode = UALINK_XCP_INFO_ATTR(addr_mode);
+static struct kobj_attribute ualink_xcp_info_accel_state = UALINK_XCP_INFO_ATTR(accel_state);
+static struct kobj_attribute ualink_xcp_info_local_accels = UALINK_XCP_INFO_ATTR(local_accels);
+
+static struct attribute *ualink_xcp_info_attrs[] = {
+	&ualink_xcp_info_link_type.attr,
+	&ualink_xcp_info_accel_id.attr,
+	&ualink_xcp_info_bandwidth.attr,
+	&ualink_xcp_info_latency.attr,
+	&ualink_xcp_info_ppod_id.attr,
+	&ualink_xcp_info_ppod_size.attr,
+	&ualink_xcp_info_vpod_id.attr,
+	&ualink_xcp_info_vpod_size.attr,
+	&ualink_xcp_info_vpod_active_accels.attr,
+	&ualink_xcp_info_addr_mode.attr,
+	&ualink_xcp_info_accel_state.attr,
+	&ualink_xcp_info_local_accels.attr,
+	NULL
+};
+
+static umode_t ualink_xcp_info_is_visible(struct kobject *kobj,
+					  struct attribute *attr, int n)
+{
+	struct amdgpu_xcp *xcp = container_of(kobj, struct amdgpu_xcp,
+					      ualink.kobj);
+
+	if (!xcp->valid)
+		return 0;
+
+	return attr->mode;
+}
+
+static const struct attribute_group ualink_xcp_info_group = {
+	.attrs = ualink_xcp_info_attrs,
+	.is_visible = ualink_xcp_info_is_visible,
+};
+
+static const struct kobj_type ualink_xcp_info_ktype = {
+	.sysfs_ops = &kobj_sysfs_ops
+};
+
 static void ualink_info_release(struct kobject *kobj)
 {
 	kfree(to_ualink_info(kobj));
@@ -1467,6 +1550,9 @@ static int ualink_kobj_add(struct kobject *kobj, struct kobject *parent,
 	return r;
 }
 
+static void amdgpu_ualink_xcp_sysfs_init(struct amdgpu_device *adev);
+static void amdgpu_ualink_xcp_sysfs_fini(struct amdgpu_device *adev);
+
 int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev)
 {
 	struct amdgpu_ualink_info *info = adev->ualink.info;
@@ -1496,7 +1582,9 @@ int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev)
 	if (r)
 		goto err_config;
 
+	amdgpu_ualink_xcp_sysfs_init(adev);
 	adev->ualink.sysfs_init = true;
+
 	return 0;
 
 err_config:
@@ -1515,6 +1603,7 @@ void amdgpu_ualink_sysfs_fini(struct amdgpu_device *adev)
 	if (!adev->ualink.sysfs_init)
 		return;
 
+	amdgpu_ualink_xcp_sysfs_fini(adev);
 	kobject_del(&adev->ualink.stations->kobj);
 	kobject_del(&adev->ualink.config->kobj);
 	kobject_del(&adev->ualink.setup->kobj);
@@ -1522,6 +1611,82 @@ void amdgpu_ualink_sysfs_fini(struct amdgpu_device *adev)
 	adev->ualink.sysfs_init = false;
 }
 
+static int amdgpu_ualink_xcp_sysfs_add(struct amdgpu_xcp *xcp)
+{
+	struct amdgpu_device *adev = xcp->xcp_mgr->adev;
+	int r;
+
+	r = kobject_init_and_add(&xcp->ualink.kobj, &ualink_xcp_info_ktype,
+				 &xcp->ddev->dev->kobj, "ualink");
+	if (r)
+		goto err;
+
+	r = sysfs_create_group(&xcp->ualink.kobj, &ualink_xcp_info_group);
+	if (r)
+		goto err;
+
+	/* pin info so it outlives this node regardless of teardown order */
+	kobject_get(&adev->ualink.info->kobj);
+	xcp->ualink.sysfs = true;
+	return 0;
+err:
+	kobject_put(&xcp->ualink.kobj);
+	return r;
+}
+
+void amdgpu_ualink_xcp_sysfs_update(struct amdgpu_xcp *xcp)
+{
+	if (!xcp->ualink.sysfs)
+		return;
+
+	sysfs_update_group(&xcp->ualink.kobj, &ualink_xcp_info_group);
+}
+
+static void amdgpu_ualink_xcp_sysfs_remove(struct amdgpu_xcp *xcp)
+{
+	struct amdgpu_device *adev = xcp->xcp_mgr->adev;
+
+	if (!xcp->ualink.sysfs)
+		return;
+
+	/* group is only populated for valid partitions */
+	if (xcp->valid)
+		sysfs_remove_group(&xcp->ualink.kobj, &ualink_xcp_info_group);
+	kobject_put(&adev->ualink.info->kobj);
+	kobject_put(&xcp->ualink.kobj);
+	xcp->ualink.sysfs = false;
+}
+
+static void amdgpu_ualink_xcp_sysfs_init(struct amdgpu_device *adev)
+{
+	struct amdgpu_xcp *xcp;
+	int i;
+
+	if (!adev->xcp_mgr)
+		return;
+
+	for (i = 0; i < MAX_XCP; i++) {
+		xcp = &adev->xcp_mgr->xcp[i];
+		if (!xcp->ddev || amdgpu_xcp_is_primary(xcp))
+			continue;
+		amdgpu_ualink_xcp_sysfs_add(xcp);
+	}
+}
+
+static void amdgpu_ualink_xcp_sysfs_fini(struct amdgpu_device *adev)
+{
+	struct amdgpu_xcp *xcp;
+	int i;
+
+	if (!adev->xcp_mgr)
+		return;
+
+	for (i = 0; i < MAX_XCP; i++) {
+		xcp = &adev->xcp_mgr->xcp[i];
+		amdgpu_ualink_xcp_sysfs_remove(xcp);
+	}
+}
+
 static int amdgpu_ualink_npa_alloc_va(struct amdgpu_device *adev,
 			       struct drm_mm_node *mm_node,
 			       u64 va, u64 range_start,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
index 2e579d0bbe9e6..63710b484c6a5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
@@ -27,6 +27,8 @@
 
 #include <linux/uuid.h>
 
+struct amdgpu_xcp;
+
 #define AMDGPU_UALINK_ACCEL_MAX 256
 #define AMDGPU_UALINK_LOCAL_ACCELS_MAX 8
 #define AMDGPU_UALINK_STATIONS_MAX 64
@@ -398,6 +400,7 @@ int amdgpu_ualink_resume_handler(struct amdgpu_device *adev);
 
 int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev);
 void amdgpu_ualink_sysfs_fini(struct amdgpu_device *adev);
+void amdgpu_ualink_xcp_sysfs_update(struct amdgpu_xcp *xcp);
 int amdgpu_ualink_manager_start(struct amdgpu_device *adev);
 void amdgpu_ualink_manager_stop(struct amdgpu_device *adev);
 int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
index 18f4455ef0a8f..a8c79a66df1d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
@@ -1061,6 +1061,11 @@ static const struct kobj_type xcp_sysfs_ktype = {
 	.sysfs_ops = &kobj_sysfs_ops,
 };
 
+bool amdgpu_xcp_is_primary(struct amdgpu_xcp *xcp)
+{
+	return xcp->ddev == adev_to_drm(xcp->xcp_mgr->adev);
+}
+
 static void amdgpu_xcp_sysfs_entries_fini(struct amdgpu_xcp_mgr *xcp_mgr, int n)
 {
 	struct amdgpu_xcp *xcp;
@@ -1110,6 +1115,7 @@ static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr)
 		if (!xcp->ddev)
 			continue;
 		sysfs_update_group(&xcp->kobj, &amdgpu_xcp_attrs_group);
+		amdgpu_ualink_xcp_sysfs_update(xcp);
 	}
 
 	return;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h
index 878c1c422893c..33157409eda0c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h
@@ -100,6 +100,11 @@ struct amdgpu_xcp_ip {
 	bool valid;
 };
 
+struct amdgpu_xcp_ualink {
+	struct kobject kobj;
+	bool sysfs;
+};
+
 struct amdgpu_xcp {
 	struct amdgpu_xcp_ip ip[AMDGPU_XCP_MAX_BLOCKS];
 
@@ -115,6 +120,7 @@ struct amdgpu_xcp {
 	struct amdgpu_sched	gpu_sched[AMDGPU_HW_IP_NUM][AMDGPU_RING_PRIO_MAX];
 	struct amdgpu_xcp_mgr *xcp_mgr;
 	struct kobject kobj;
+	struct amdgpu_xcp_ualink ualink;
 	uint64_t unique_id;
 };
 
@@ -191,6 +197,7 @@ int amdgpu_xcp_pre_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags);
 int amdgpu_xcp_post_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, u32 flags);
 void amdgpu_xcp_sysfs_init(struct amdgpu_device *adev);
 void amdgpu_xcp_sysfs_fini(struct amdgpu_device *adev);
+bool amdgpu_xcp_is_primary(struct amdgpu_xcp *xcp);
 
 static inline int amdgpu_xcp_get_num_xcp(struct amdgpu_xcp_mgr *xcp_mgr)
 {
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.