From 88ff0b5ea066a2354a93039c049167f4e20b70e3 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 30 Apr 2020 11:41:06 -0600 Subject: [PATCH] msm: kgsl: Add kobject sysfs ops for the /sys/kernel/gpu directory Commit 2726e792a201 ("msm: kgsl: Fix linked sysfs files") thought it was clever by reusing the callbacks for the sysfs nodes that were linked to /sys/kernel/gpu. Unfortunately, since the /sys/kernel/gpu kobject didn't have a device attached the callback function ended up dereferencing nothing. Instead, create a full kobject infrastructure with sysfs_ops and a built in kobj to access the KGSL device. We can still use the callbacks albeit with a wrapper to make them work from both locations. While we are in the midst of this, make a header for the new attributes and macros so that we can later move some of the nodes out of kgsl_pwrctrl.c with less disruption. Change-Id: Ic0dedbad5b9d7323d4f43328540dce91cc58015e Signed-off-by: Jordan Crouse --- drivers/gpu/msm/kgsl.c | 52 +++++++++++- drivers/gpu/msm/kgsl_device.h | 2 +- drivers/gpu/msm/kgsl_pwrctrl.c | 145 ++++++++++++++++++++++---------- drivers/gpu/msm/kgsl_pwrscale.c | 4 +- drivers/gpu/msm/kgsl_sysfs.h | 31 +++++++ 5 files changed, 187 insertions(+), 47 deletions(-) create mode 100644 drivers/gpu/msm/kgsl_sysfs.h diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 7263f60be36b..0eabf8914814 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -24,6 +24,7 @@ #include "kgsl_mmu.h" #include "kgsl_pool.h" #include "kgsl_sync.h" +#include "kgsl_sysfs.h" #include "kgsl_trace.h" #ifndef arch_mmap_check @@ -4733,6 +4734,50 @@ static void _unregister_device(struct kgsl_device *device) mutex_unlock(&kgsl_driver.devlock); } +/* sysfs_ops for the /sys/kernel/gpu kobject */ +static ssize_t kgsl_gpu_sysfs_attr_show(struct kobject *kobj, + struct attribute *__attr, char *buf) +{ + struct kgsl_gpu_sysfs_attr *attr = container_of(__attr, + struct kgsl_gpu_sysfs_attr, attr); + struct kgsl_device *device = container_of(kobj, + struct kgsl_device, gpu_sysfs_kobj); + + if (attr->show) + return attr->show(device, buf); + + return -EIO; +} + +static ssize_t kgsl_gpu_sysfs_attr_store(struct kobject *kobj, + struct attribute *__attr, const char *buf, size_t count) +{ + struct kgsl_gpu_sysfs_attr *attr = container_of(__attr, + struct kgsl_gpu_sysfs_attr, attr); + struct kgsl_device *device = container_of(kobj, + struct kgsl_device, gpu_sysfs_kobj); + + if (attr->store) + return attr->store(device, buf, count); + + return -EIO; +} + +/* Dummy release function - we have nothing to do here */ +static void kgsl_gpu_sysfs_release(struct kobject *kobj) +{ +} + +static const struct sysfs_ops kgsl_gpu_sysfs_ops = { + .show = kgsl_gpu_sysfs_attr_show, + .store = kgsl_gpu_sysfs_attr_store, +}; + +static struct kobj_type kgsl_gpu_sysfs_ktype = { + .sysfs_ops = &kgsl_gpu_sysfs_ops, + .release = kgsl_gpu_sysfs_release, +}; + static int _register_device(struct kgsl_device *device) { static u64 dma_mask = DMA_BIT_MASK(64); @@ -4773,6 +4818,10 @@ static int _register_device(struct kgsl_device *device) device->dev->dma_mask = &dma_mask; set_dma_ops(device->dev, NULL); + + kobject_init_and_add(&device->gpu_sysfs_kobj, &kgsl_gpu_sysfs_ktype, + kernel_kobj, "gpu"); + return 0; } @@ -4897,7 +4946,8 @@ void kgsl_device_platform_remove(struct kgsl_device *device) kgsl_device_snapshot_close(device); - kobject_put(device->gpu_sysfs_kobj); + if (device->gpu_sysfs_kobj.state_initialized) + kobject_del(&device->gpu_sysfs_kobj); idr_destroy(&device->context_idr); diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 2d82dc7384ce..861c7ca59989 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -296,7 +296,7 @@ struct kgsl_device { /* Number of active contexts seen globally for this device */ int active_context_count; - struct kobject *gpu_sysfs_kobj; + struct kobject gpu_sysfs_kobj; struct clk *l3_clk; unsigned int l3_freq[MAX_L3_LEVELS]; unsigned int num_l3_pwrlevels; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index abec2325e113..cb2335a93276 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. */ #include @@ -12,6 +12,7 @@ #include "kgsl_device.h" #include "kgsl_bus.h" #include "kgsl_pwrscale.h" +#include "kgsl_sysfs.h" #include "kgsl_trace.h" #define UPDATE_BUSY_VAL 1000000 @@ -824,10 +825,8 @@ static ssize_t popp_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0\n"); } -static ssize_t gpu_model_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t _gpu_model_show(struct kgsl_device *device, char *buf) { - struct kgsl_device *device = dev_get_drvdata(dev); char model_str[32] = {0}; device->ftbl->gpu_model(device, model_str, sizeof(model_str)); @@ -835,12 +834,18 @@ static ssize_t gpu_model_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%s\n", model_str); } -static ssize_t gpu_busy_percentage_show(struct device *dev, - struct device_attribute *attr, +static ssize_t gpu_model_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kgsl_device *device = dev_get_drvdata(dev); + + return _gpu_model_show(device, buf); +} + +static ssize_t _gpu_busy_show(struct kgsl_device *device, char *buf) { int ret; - struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_clk_stats *stats = &device->pwrctrl.clk_stats; unsigned int busy_percent = 0; @@ -857,22 +862,37 @@ static ssize_t gpu_busy_percentage_show(struct device *dev, return ret; } -static ssize_t min_clock_mhz_show(struct device *dev, +static ssize_t gpu_busy_percentage_show(struct device *dev, struct device_attribute *attr, char *buf) { struct kgsl_device *device = dev_get_drvdata(dev); + + return _gpu_busy_show(device, buf); +} + +static ssize_t _min_clock_mhz_show(struct kgsl_device *device, + char *buf) +{ struct kgsl_pwrctrl *pwr = &device->pwrctrl; return scnprintf(buf, PAGE_SIZE, "%d\n", pwr->pwrlevels[pwr->min_pwrlevel].gpu_freq / 1000000); } -static ssize_t min_clock_mhz_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t min_clock_mhz_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct kgsl_device *device = dev_get_drvdata(dev); + + return _min_clock_mhz_show(device, buf); +} + +static ssize_t _min_clock_mhz_store(struct kgsl_device *device, + const char *buf, size_t count) +{ int level, ret; unsigned int freq; struct kgsl_pwrctrl *pwr = &device->pwrctrl; @@ -890,21 +910,34 @@ static ssize_t min_clock_mhz_store(struct device *dev, return count; } -static ssize_t max_clock_mhz_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t min_clock_mhz_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct kgsl_device *device = dev_get_drvdata(dev); + + return _min_clock_mhz_store(device, buf, count); +} + +static ssize_t _max_clock_mhz_show(struct kgsl_device *device, char *buf) +{ struct kgsl_pwrctrl *pwr = &device->pwrctrl; return scnprintf(buf, PAGE_SIZE, "%d\n", pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq / 1000000); } -static ssize_t max_clock_mhz_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t max_clock_mhz_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct kgsl_device *device = dev_get_drvdata(dev); + + return _max_clock_mhz_show(device, buf); +} + +static ssize_t _max_clock_mhz_store(struct kgsl_device *device, + const char *buf, size_t count) +{ u32 freq; int ret, level; @@ -924,20 +957,32 @@ static ssize_t max_clock_mhz_store(struct device *dev, return count; } +static ssize_t max_clock_mhz_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct kgsl_device *device = dev_get_drvdata(dev); + + return _max_clock_mhz_store(device, buf, count); +} + +static ssize_t _clock_mhz_show(struct kgsl_device *device, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%ld\n", + kgsl_pwrctrl_active_freq(&device->pwrctrl) / 1000000); +} + static ssize_t clock_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) { struct kgsl_device *device = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%ld\n", - kgsl_pwrctrl_active_freq(&device->pwrctrl) / 1000000); + return _clock_mhz_show(device, buf); } -static ssize_t freq_table_mhz_show(struct device *dev, - struct device_attribute *attr, +static ssize_t _freq_table_mhz_show(struct kgsl_device *device, char *buf) { - struct kgsl_device *device = dev_get_drvdata(dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; int index, num_chars = 0; @@ -955,11 +1000,18 @@ static ssize_t freq_table_mhz_show(struct device *dev, return num_chars; } -static ssize_t temp_show(struct device *dev, +static ssize_t freq_table_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) { struct kgsl_device *device = dev_get_drvdata(dev); + + return _freq_table_mhz_show(device, buf); +} + +static ssize_t _gpu_tmu_show(struct kgsl_device *device, + char *buf) +{ struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct thermal_zone_device *thermal_dev; int ret, temperature = 0; @@ -979,6 +1031,15 @@ static ssize_t temp_show(struct device *dev, temperature); } +static ssize_t temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = dev_get_drvdata(dev); + + return _gpu_tmu_show(device, buf); +} + static ssize_t pwrscale_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1069,23 +1130,24 @@ static const struct attribute *pwrctrl_attr_list[] = { NULL, }; -static DEVICE_ATTR(gpu_busy, 0200, gpu_busy_percentage_show, NULL); -static DEVICE_ATTR(gpu_min_clock, 0644, min_clock_mhz_show, - min_clock_mhz_store); -static DEVICE_ATTR(gpu_max_clock, 0644, max_clock_mhz_show, - max_clock_mhz_store); -static DEVICE_ATTR(gpu_clock, 0200, clock_mhz_show, NULL); -static DEVICE_ATTR(gpu_freq_table, 0200, freq_table_mhz_show, NULL); -static DEVICE_ATTR(gpu_tmu, 0200, temp_show, NULL); +static GPU_SYSFS_ATTR(gpu_model, 0200, _gpu_model_show, NULL); +static GPU_SYSFS_ATTR(gpu_busy, 0200, _gpu_busy_show, NULL); +static GPU_SYSFS_ATTR(gpu_min_clock, 0644, _min_clock_mhz_show, + _min_clock_mhz_store); +static GPU_SYSFS_ATTR(gpu_max_clock, 0644, _max_clock_mhz_show, + _max_clock_mhz_store); +static GPU_SYSFS_ATTR(gpu_clock, 0200, _clock_mhz_show, NULL); +static GPU_SYSFS_ATTR(gpu_freq_table, 0200, _freq_table_mhz_show, NULL); +static GPU_SYSFS_ATTR(gpu_tmu, 0200, _gpu_tmu_show, NULL); -static const struct attribute *pwrctrl_gpu_attr_list[] = { - &dev_attr_gpu_model.attr, - &dev_attr_gpu_busy.attr, - &dev_attr_gpu_min_clock.attr, - &dev_attr_gpu_max_clock.attr, - &dev_attr_gpu_clock.attr, - &dev_attr_gpu_freq_table.attr, - &dev_attr_gpu_tmu.attr, +static const struct attribute *gpu_sysfs_attr_list[] = { + &gpu_sysfs_attr_gpu_model.attr, + &gpu_sysfs_attr_gpu_busy.attr, + &gpu_sysfs_attr_gpu_min_clock.attr, + &gpu_sysfs_attr_gpu_max_clock.attr, + &gpu_sysfs_attr_gpu_clock.attr, + &gpu_sysfs_attr_gpu_freq_table.attr, + &gpu_sysfs_attr_gpu_tmu.attr, NULL, }; @@ -1097,13 +1159,10 @@ int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device) if (ret) return ret; - device->gpu_sysfs_kobj = kobject_create_and_add("gpu", kernel_kobj); - - if (!device->gpu_sysfs_kobj) + if (!device->gpu_sysfs_kobj.state_in_sysfs) return 0; - return sysfs_create_files(device->gpu_sysfs_kobj, - pwrctrl_gpu_attr_list); + return sysfs_create_files(&device->gpu_sysfs_kobj, gpu_sysfs_attr_list); } /* diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index c07cc7583084..0549ead0658c 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -886,10 +886,10 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev, KGSL_GOVERNOR_CALL_INTERVAL); /* Add links to the devfreq sysfs nodes */ - kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj, + kgsl_gpu_sysfs_add_link(&device->gpu_sysfs_kobj, &pwrscale->devfreqptr->dev.kobj, "governor", "gpu_governor"); - kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj, + kgsl_gpu_sysfs_add_link(&device->gpu_sysfs_kobj, &pwrscale->devfreqptr->dev.kobj, "available_governors", "gpu_available_governor"); diff --git a/drivers/gpu/msm/kgsl_sysfs.h b/drivers/gpu/msm/kgsl_sysfs.h new file mode 100644 index 000000000000..47d5c3f2a29e --- /dev/null +++ b/drivers/gpu/msm/kgsl_sysfs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#ifndef _KGSL_SYSFS_H_ +#define _KGSL_SYSFS_H_ + +struct kgsl_device; + +/** + * struct kgsl_gpu_sysfs_attr - Attribute definition for sysfs objects in the + * /sys/kernel/gpu kobject + */ +struct kgsl_gpu_sysfs_attr { + /** @attr: Attribute for the sysfs node */ + struct attribute attr; + /** @show: Show function for the node */ + ssize_t (*show)(struct kgsl_device *device, char *buf); + /** @store: Store function for the node */ + ssize_t (*store)(struct kgsl_device *device, const char *buf, + size_t count); +}; + +#define GPU_SYSFS_ATTR(_name, _mode, _show, _store) \ +struct kgsl_gpu_sysfs_attr gpu_sysfs_attr_##_name = { \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +} + +#endif