[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