[PATCH 06/95] drm/amdgpu: Add sysfs API for UALink station configuration

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

<device>/ualink/stations: Directory for staging UALink station/port
configuration attributes:
- station_flags (currently only sets the number of port per station)
- lane_en_bitmap (hexadecimal bitmaps of lanes enabled per station)
- write "true" to commit to apply settings

Signed-off-by: Felix Kuehling <[email protected]>
Reviewed-by: Mukul Joshi <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 144 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h |  16 +++
 2 files changed, 160 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
index 420e18a658e83..4f50040a99256 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
@@ -714,8 +714,125 @@ static const struct kobj_type ualink_vpod_config_ktype = {
 	.sysfs_ops = &kobj_sysfs_ops
 };
 
+UALINK_VALUE_SHOW(station_config, flags, flags, "0x%x");
+
+UALINK_VALUE_STORE(station_config, flags, flags, u8, 16);
+
+static size_t lane_bitmap_to_string(char *str,
+		const struct amdgpu_ualink_station_config *stations)
+{
+	size_t i;
+
+	for (i = 0; i < stations->n_stations; i++)
+		str[i] = stations->lane_en_bitmap[i] +
+			(stations->lane_en_bitmap[i] < 10 ? '0' : 'a' - 10);
+	str[i] = '\0';
+
+	return i;
+}
+static ssize_t
+ualink_station_config_lane_en_bitmap_show(struct kobject *kobj,
+					  struct kobj_attribute *attr,
+					  char *buf)
+{
+	struct amdgpu_ualink_station_config *stations = to_ualink_station_config(kobj);
+	char str[AMDGPU_UALINK_STATIONS_MAX + 1];
+
+	lane_bitmap_to_string(str, stations);
+	return sysfs_emit(buf, "%s\n", str);
+}
+static ssize_t
+ualink_station_config_lane_en_bitmap_store(struct kobject *kobj,
+					   struct kobj_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct amdgpu_ualink_station_config *stations = to_ualink_station_config(kobj);
+	u8 lane_en_bitmap[AMDGPU_UALINK_STATIONS_MAX];
+	u32 n_stations = 0;
+	bool end = false;
+	size_t i;
+
+	for (i = 0; i < count; i++) {
+		/* Accept any number of \n in the end */
+		if (buf[i] == '\n') {
+			end = true;
+			continue;
+		}
+		/* Don't accept any more data after \n */
+		if (end)
+			return -EINVAL;
+		/* Don't accept more data than the array size */
+		if (i >= sizeof(lane_en_bitmap))
+			return -ENOSPC;
+		/* Accept hex digits */
+		if (buf[i] >= '0' && buf[i] <= '9')
+			lane_en_bitmap[n_stations++] = buf[i] - '0';
+		else if (buf[i] >= 'a' && buf[i] <= 'f')
+			lane_en_bitmap[n_stations++] = buf[i] + 10 - 'a';
+		else if (buf[i] >= 'A' && buf[i] <= 'F')
+			lane_en_bitmap[n_stations++] = buf[i] + 10 - 'A';
+		else
+			return -EINVAL;
+	}
+
+	memcpy(stations->lane_en_bitmap, lane_en_bitmap, sizeof(lane_en_bitmap));
+	stations->n_stations = n_stations;
+	return i;
+}
+
+static ssize_t ualink_station_config_commit_store(struct kobject *kobj,
+						  struct kobj_attribute *attr,
+						  const char *buf, size_t count)
+{
+	struct amdgpu_ualink_station_config *stations = to_ualink_station_config(kobj);
+	struct amdgpu_ualink_info *info = to_ualink_info(kobj->parent);
+	struct device *dev = kobj_to_dev(info->kobj.parent);
+	struct drm_device *ddev = dev_get_drvdata(dev);
+	struct amdgpu_device *adev = drm_to_adev(ddev);
+
+	/* DF reconfiguration does not interact with accelerator state */
+
+	if (!sysfs_streq(buf, "true"))
+		return -EINVAL;
+
+	/* TODO: Send configuration to ASP */
+	(void)adev;
+	(void)stations;
+
+	return count;
+}
+
+#define UALINK_STATION_CONFIG_ATTR(name) __ATTR(name, 0600,		\
+		ualink_station_config_##name##_show,			\
+		ualink_station_config_##name##_store)
+static struct kobj_attribute ualink_station_config_flags  = UALINK_STATION_CONFIG_ATTR(flags);
+static struct kobj_attribute ualink_station_config_lane_en_bitmap =
+							UALINK_STATION_CONFIG_ATTR(lane_en_bitmap);
+static struct kobj_attribute ualink_station_config_commit =
+				__ATTR(commit, 0200, NULL, ualink_station_config_commit_store);
+
+static const struct attribute *ualink_station_config_attrs[] = {
+	&ualink_station_config_flags.attr,
+	&ualink_station_config_lane_en_bitmap.attr,
+	&ualink_station_config_commit.attr,
+	NULL
+};
+
+static void ualink_station_config_release(struct kobject *kobj)
+{
+	struct amdgpu_ualink_station_config *stations = to_ualink_station_config(kobj);
+
+	kfree(stations);
+}
+
+static const struct kobj_type ualink_station_config_ktype = {
+	.release = ualink_station_config_release,
+	.sysfs_ops = &kobj_sysfs_ops
+};
+
 int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev)
 {
+	struct amdgpu_ualink_station_config *stations = NULL;
 	struct amdgpu_ualink_vpod_config *vpod_config = NULL;
 	struct amdgpu_ualink_ppod_setup *ppod_setup = NULL;
 	struct amdgpu_ualink_info *info = NULL;
@@ -765,12 +882,32 @@ int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev)
 	if (r)
 		goto err_del_vpod_config;
 
+	stations = kzalloc(sizeof(*stations), GFP_KERNEL);
+	if (!stations) {
+		r = -ENOMEM;
+		goto err_remove_vpod_config_files;
+	}
+	r = kobject_init_and_add(&stations->kobj, &ualink_station_config_ktype,
+				 &info->kobj, "stations");
+	if (r)
+		goto err_put_stations;
+	r = sysfs_create_files(&stations->kobj, ualink_station_config_attrs);
+	if (r)
+		goto err_del_stations;
+
+	adev->ualink.stations = stations;
 	adev->ualink.config = vpod_config;
 	adev->ualink.setup = ppod_setup;
 	adev->ualink.info = info;
 
 	return r;
 
+err_del_stations:
+	kobject_del(&stations->kobj);
+err_put_stations:
+	kobject_put(&stations->kobj);
+err_remove_vpod_config_files:
+	sysfs_remove_files(&vpod_config->kobj, ualink_vpod_config_attrs);
 err_del_vpod_config:
 	kobject_del(&vpod_config->kobj);
 err_put_vpod_config:
@@ -792,6 +929,13 @@ int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev)
 
 void amdgpu_ualink_sysfs_fini(struct amdgpu_device *adev)
 {
+	if (adev->ualink.stations) {
+		sysfs_remove_files(&adev->ualink.stations->kobj,
+				   ualink_station_config_attrs);
+		kobject_del(&adev->ualink.stations->kobj);
+		kobject_put(&adev->ualink.stations->kobj);
+		adev->ualink.stations = NULL;
+	}
 	if (adev->ualink.config) {
 		sysfs_remove_files(&adev->ualink.config->kobj,
 				   ualink_vpod_config_attrs);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
index 67fe40cd08e71..384959fbb36fb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h
@@ -29,6 +29,7 @@
 
 #define AMDGPU_UALINK_ACCEL_MAX 256
 #define AMDGPU_UALINK_LOCAL_ACCELS_MAX 8
+#define AMDGPU_UALINK_STATIONS_MAX 64
 
 enum amdgpu_ualink_type {
 	AMDGPU_UALINK_TYPE_UALOE = 0,
@@ -100,10 +101,25 @@ struct amdgpu_ualink_vpod_config {
 };
 #define to_ualink_vpod_config(ko) container_of(ko, struct amdgpu_ualink_vpod_config, kobj)
 
+/* UALink station configuration */
+struct amdgpu_ualink_station_config {
+	struct kobject kobj;
+	/* Station configuration flags
+	 * bits [3:0]: PortPerStation (PPS) - 1, 2, or 4
+	 * bits [7:4]: Reserved
+	 */
+	u8 flags;
+	u8 n_stations;
+	/* bitmap or enabled lanes for each station in logical station order */
+	u8 lane_en_bitmap[AMDGPU_UALINK_STATIONS_MAX];
+};
+#define to_ualink_station_config(ko) container_of(ko, struct amdgpu_ualink_station_config, kobj)
+
 struct amdgpu_ualink_mgr {
 	struct amdgpu_ualink_info *info;
 	struct amdgpu_ualink_ppod_setup *setup;
 	struct amdgpu_ualink_vpod_config *config;
+	struct amdgpu_ualink_station_config *stations;
 };
 
 int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev);
-- 
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.