From 4d3c94f1e3107279e20265a8b64147330b3bb85f Mon Sep 17 00:00:00 2001 From: Dan Sneddon Date: Thu, 2 Oct 2014 13:11:09 -0600 Subject: devfreq: devfreq spdm: Add debugfs support Add debugfs support for the devfreq spdm driver. The parameters used for determing the SPDM port threshold value can be updated via debugfs and sent to the hypervisor to support fine tuning SPDM performance. Change-Id: I6f85deacd7d463d90f512f5de18b7e2140c9f492 Signed-off-by: Dan Sneddon [junjiew@codeaurora.org: resolved trivial conflicts] Signed-off-by: Junjie Wu --- drivers/devfreq/Makefile | 2 +- drivers/devfreq/devfreq_spdm.c | 6 +- drivers/devfreq/devfreq_spdm.h | 3 + drivers/devfreq/devfreq_spdm_debugfs.c | 456 +++++++++++++++++++++++++++++++++ 4 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 drivers/devfreq/devfreq_spdm_debugfs.c (limited to 'drivers') diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 08f561d860b0..6f037f0f7ffb 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o obj-$(CONFIG_MSM_DEVFREQ_DEVBW) += devfreq_devbw.o obj-$(CONFIG_DEVFREQ_SIMPLE_DEV) += devfreq_simple_dev.o -obj-$(CONFIG_DEVFREQ_SPDM) += devfreq_spdm.o +obj-$(CONFIG_DEVFREQ_SPDM) += devfreq_spdm.o devfreq_spdm_debugfs.o # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/devfreq_spdm.c b/drivers/devfreq/devfreq_spdm.c index 749cfe1aaefa..1217ddea2929 100644 --- a/drivers/devfreq/devfreq_spdm.c +++ b/drivers/devfreq/devfreq_spdm.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include "governor.h" @@ -281,6 +279,8 @@ static int probe(struct platform_device *pdev) goto no_profile; } + spdm_init_debugfs(&pdev->dev); + return 0; no_profile: @@ -299,6 +299,8 @@ static int remove(struct platform_device *pdev) data = platform_get_drvdata(pdev); + spdm_remove_debugfs(data); + if (data->devfreq) devfreq_remove_device(data->devfreq); diff --git a/drivers/devfreq/devfreq_spdm.h b/drivers/devfreq/devfreq_spdm.h index 24c2b2be7f06..cdb45c88bc57 100644 --- a/drivers/devfreq/devfreq_spdm.h +++ b/drivers/devfreq/devfreq_spdm.h @@ -79,6 +79,9 @@ struct spdm_data { struct dentry *debugfs_dir; }; +extern void spdm_init_debugfs(struct device *dev); +extern void spdm_remove_debugfs(struct spdm_data *data); + #define SPDM_HYP_FNID 5 /* CMD ID's for hypervisor */ #define SPDM_CMD_GET_BW_ALL 1 diff --git a/drivers/devfreq/devfreq_spdm_debugfs.c b/drivers/devfreq/devfreq_spdm_debugfs.c new file mode 100644 index 000000000000..ef7ac3323ce2 --- /dev/null +++ b/drivers/devfreq/devfreq_spdm_debugfs.c @@ -0,0 +1,456 @@ +/* +*Copyright (c) 2014, The Linux Foundation. All rights reserved. +* +*This program is free software; you can redistribute it and/or modify +*it under the terms of the GNU General Public License version 2 and +*only version 2 as published by the Free Software Foundation. +* +*This program is distributed in the hope that it will be useful, +*but WITHOUT ANY WARRANTY; without even the implied warranty of +*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +*GNU General Public License for more details. +*/ +#include +#include +#include +#include +#include +#include +#include "devfreq_spdm.h" + +static int spdm_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t pl_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + int i; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + + sscanf(buf, "%u %u\n", &spdm_data->config_data.pl_freqs[0], + &spdm_data->config_data.pl_freqs[1]); + + + desc.arg[0] = SPDM_CMD_CFG_PL; + desc.arg[1] = spdm_data->spdm_client; + for (i = 0; i < SPDM_PL_COUNT - 1; i++) + desc.arg[i+2] = spdm_data->config_data.pl_freqs[i]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations pl_fops = { + .open = spdm_open, + .write = pl_write, +}; + +static ssize_t rejrate_low_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + + sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[0], + &spdm_data->config_data.reject_rate[1]); + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[0]; + desc.arg[3] = spdm_data->config_data.reject_rate[1]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations rrl_fops = { + .open = spdm_open, + .write = rejrate_low_write, +}; + +static ssize_t rejrate_med_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[2], + &spdm_data->config_data.reject_rate[3]); + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[2]; + desc.arg[3] = spdm_data->config_data.reject_rate[3]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations rrm_fops = { + .open = spdm_open, + .write = rejrate_med_write, +}; + +static ssize_t rejrate_high_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[4], + &spdm_data->config_data.reject_rate[5]); + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[4]; + desc.arg[3] = spdm_data->config_data.reject_rate[5]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations rrh_fops = { + .open = spdm_open, + .write = rejrate_high_write, +}; + +static ssize_t resptime_low_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[0], + &spdm_data->config_data.response_time_us[1]); + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[0]; + desc.arg[3] = spdm_data->config_data.response_time_us[1]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations rtl_fops = { + .open = spdm_open, + .write = resptime_low_write, +}; + +static ssize_t resptime_med_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[2], + &spdm_data->config_data.response_time_us[3]); + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[2]; + desc.arg[3] = spdm_data->config_data.response_time_us[3]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations rtm_fops = { + .open = spdm_open, + .write = resptime_med_write, +}; + +static ssize_t resptime_high_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[4], + &spdm_data->config_data.response_time_us[5]); + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[4]; + desc.arg[3] = spdm_data->config_data.response_time_us[5]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations rth_fops = { + .open = spdm_open, + .write = resptime_high_write, +}; + +static ssize_t cciresptime_low_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[0], + &spdm_data->config_data.cci_response_time_us[1]); + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[0]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[1]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations ccil_fops = { + .open = spdm_open, + .write = cciresptime_low_write, +}; + +static ssize_t cciresptime_med_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[2], + &spdm_data->config_data.cci_response_time_us[3]); + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[2]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[3]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations ccim_fops = { + .open = spdm_open, + .write = cciresptime_med_write, +}; + +static ssize_t cciresptime_high_write(struct file *file, + const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u\n", &spdm_data->config_data.cci_response_time_us[4], + &spdm_data->config_data.cci_response_time_us[5]); + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[4]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[5]; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations ccih_fops = { + .open = spdm_open, + .write = cciresptime_high_write, +}; + +static ssize_t cci_max_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u\n", &spdm_data->config_data.max_cci_freq); + + desc.arg[0] = SPDM_CMD_CFG_MAXCCI; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.max_cci_freq; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations ccimax_fops = { + .open = spdm_open, + .write = cci_max_write, +}; + +static ssize_t vote_cfg_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + char *buf; + struct hvc_desc desc; + + buf = kzalloc(size, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, data, size)) + return -EINVAL; + sscanf(buf, "%u %u %u %u\n", &spdm_data->config_data.upstep, + &spdm_data->config_data.downstep, + &spdm_data->config_data.max_vote, + &spdm_data->config_data.up_step_multp); + + desc.arg[0] = SPDM_CMD_CFG_VOTES; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.upstep; + desc.arg[3] = spdm_data->config_data.downstep; + desc.arg[4] = spdm_data->config_data.max_vote; + desc.arg[5] = spdm_data->config_data.up_step_multp; + if (hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc)) + pr_debug("check hvc logs"); + *offset += size; + kfree(buf); + return size; +} + +static const struct file_operations vote_fops = { + .open = spdm_open, + .write = vote_cfg_write, +}; + +void spdm_init_debugfs(struct device *dev) +{ + struct spdm_data *data = 0; + + data = dev_get_drvdata(dev); + data->debugfs_dir = debugfs_create_dir(dev_name(dev), NULL); + + debugfs_create_file("pl_freqs", 0x700, data->debugfs_dir, data, + &pl_fops); + debugfs_create_file("rej_rate_low", 0x700, data->debugfs_dir, data, + &rrl_fops); + debugfs_create_file("rej_rate_med", 0x700, data->debugfs_dir, data, + &rrm_fops); + debugfs_create_file("rej_rate_high", 0x700, data->debugfs_dir, data, + &rrh_fops); + debugfs_create_file("resp_time_low", 0x700, data->debugfs_dir, data, + &rtl_fops); + debugfs_create_file("resp_time_med", 0x700, data->debugfs_dir, data, + &rtm_fops); + debugfs_create_file("resp_time_high", 0x700, data->debugfs_dir, data, + &rth_fops); + debugfs_create_file("cci_resp_time_low", 0x700, data->debugfs_dir, data, + &ccil_fops); + debugfs_create_file("cci_resp_time_med", 0x700, data->debugfs_dir, data, + &ccim_fops); + debugfs_create_file("cci_resp_time_high", 0x700, data->debugfs_dir, + data, &ccih_fops); + debugfs_create_file("cci_max", 0x700, data->debugfs_dir, data, + &ccimax_fops); + debugfs_create_file("vote_cfg", 0x700, data->debugfs_dir, data, + &vote_fops); +} + +void spdm_remove_debugfs(struct spdm_data *data) +{ + debugfs_remove_recursive(data->debugfs_dir); +} + +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3