cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

virtual.c (9611B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * reg-virtual-consumer.c
      4 *
      5 * Copyright 2008 Wolfson Microelectronics PLC.
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/err.h>
     11#include <linux/mutex.h>
     12#include <linux/platform_device.h>
     13#include <linux/regulator/consumer.h>
     14#include <linux/slab.h>
     15#include <linux/module.h>
     16#include <linux/of.h>
     17
     18struct virtual_consumer_data {
     19	struct mutex lock;
     20	struct regulator *regulator;
     21	bool enabled;
     22	int min_uV;
     23	int max_uV;
     24	int min_uA;
     25	int max_uA;
     26	unsigned int mode;
     27};
     28
     29static void update_voltage_constraints(struct device *dev,
     30				       struct virtual_consumer_data *data)
     31{
     32	int ret;
     33
     34	if (data->min_uV && data->max_uV
     35	    && data->min_uV <= data->max_uV) {
     36		dev_dbg(dev, "Requesting %d-%duV\n",
     37			data->min_uV, data->max_uV);
     38		ret = regulator_set_voltage(data->regulator,
     39					data->min_uV, data->max_uV);
     40		if (ret != 0) {
     41			dev_err(dev,
     42				"regulator_set_voltage() failed: %d\n", ret);
     43			return;
     44		}
     45	}
     46
     47	if (data->min_uV && data->max_uV && !data->enabled) {
     48		dev_dbg(dev, "Enabling regulator\n");
     49		ret = regulator_enable(data->regulator);
     50		if (ret == 0)
     51			data->enabled = true;
     52		else
     53			dev_err(dev, "regulator_enable() failed: %d\n",
     54				ret);
     55	}
     56
     57	if (!(data->min_uV && data->max_uV) && data->enabled) {
     58		dev_dbg(dev, "Disabling regulator\n");
     59		ret = regulator_disable(data->regulator);
     60		if (ret == 0)
     61			data->enabled = false;
     62		else
     63			dev_err(dev, "regulator_disable() failed: %d\n",
     64				ret);
     65	}
     66}
     67
     68static void update_current_limit_constraints(struct device *dev,
     69					  struct virtual_consumer_data *data)
     70{
     71	int ret;
     72
     73	if (data->max_uA
     74	    && data->min_uA <= data->max_uA) {
     75		dev_dbg(dev, "Requesting %d-%duA\n",
     76			data->min_uA, data->max_uA);
     77		ret = regulator_set_current_limit(data->regulator,
     78					data->min_uA, data->max_uA);
     79		if (ret != 0) {
     80			dev_err(dev,
     81				"regulator_set_current_limit() failed: %d\n",
     82				ret);
     83			return;
     84		}
     85	}
     86
     87	if (data->max_uA && !data->enabled) {
     88		dev_dbg(dev, "Enabling regulator\n");
     89		ret = regulator_enable(data->regulator);
     90		if (ret == 0)
     91			data->enabled = true;
     92		else
     93			dev_err(dev, "regulator_enable() failed: %d\n",
     94				ret);
     95	}
     96
     97	if (!(data->min_uA && data->max_uA) && data->enabled) {
     98		dev_dbg(dev, "Disabling regulator\n");
     99		ret = regulator_disable(data->regulator);
    100		if (ret == 0)
    101			data->enabled = false;
    102		else
    103			dev_err(dev, "regulator_disable() failed: %d\n",
    104				ret);
    105	}
    106}
    107
    108static ssize_t show_min_uV(struct device *dev,
    109			   struct device_attribute *attr, char *buf)
    110{
    111	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    112	return sprintf(buf, "%d\n", data->min_uV);
    113}
    114
    115static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
    116			  const char *buf, size_t count)
    117{
    118	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    119	long val;
    120
    121	if (kstrtol(buf, 10, &val) != 0)
    122		return count;
    123
    124	mutex_lock(&data->lock);
    125
    126	data->min_uV = val;
    127	update_voltage_constraints(dev, data);
    128
    129	mutex_unlock(&data->lock);
    130
    131	return count;
    132}
    133
    134static ssize_t show_max_uV(struct device *dev,
    135			   struct device_attribute *attr, char *buf)
    136{
    137	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    138	return sprintf(buf, "%d\n", data->max_uV);
    139}
    140
    141static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
    142			  const char *buf, size_t count)
    143{
    144	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    145	long val;
    146
    147	if (kstrtol(buf, 10, &val) != 0)
    148		return count;
    149
    150	mutex_lock(&data->lock);
    151
    152	data->max_uV = val;
    153	update_voltage_constraints(dev, data);
    154
    155	mutex_unlock(&data->lock);
    156
    157	return count;
    158}
    159
    160static ssize_t show_min_uA(struct device *dev,
    161			   struct device_attribute *attr, char *buf)
    162{
    163	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    164	return sprintf(buf, "%d\n", data->min_uA);
    165}
    166
    167static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
    168			  const char *buf, size_t count)
    169{
    170	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    171	long val;
    172
    173	if (kstrtol(buf, 10, &val) != 0)
    174		return count;
    175
    176	mutex_lock(&data->lock);
    177
    178	data->min_uA = val;
    179	update_current_limit_constraints(dev, data);
    180
    181	mutex_unlock(&data->lock);
    182
    183	return count;
    184}
    185
    186static ssize_t show_max_uA(struct device *dev,
    187			   struct device_attribute *attr, char *buf)
    188{
    189	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    190	return sprintf(buf, "%d\n", data->max_uA);
    191}
    192
    193static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
    194			  const char *buf, size_t count)
    195{
    196	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    197	long val;
    198
    199	if (kstrtol(buf, 10, &val) != 0)
    200		return count;
    201
    202	mutex_lock(&data->lock);
    203
    204	data->max_uA = val;
    205	update_current_limit_constraints(dev, data);
    206
    207	mutex_unlock(&data->lock);
    208
    209	return count;
    210}
    211
    212static ssize_t show_mode(struct device *dev,
    213			 struct device_attribute *attr, char *buf)
    214{
    215	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    216
    217	switch (data->mode) {
    218	case REGULATOR_MODE_FAST:
    219		return sprintf(buf, "fast\n");
    220	case REGULATOR_MODE_NORMAL:
    221		return sprintf(buf, "normal\n");
    222	case REGULATOR_MODE_IDLE:
    223		return sprintf(buf, "idle\n");
    224	case REGULATOR_MODE_STANDBY:
    225		return sprintf(buf, "standby\n");
    226	default:
    227		return sprintf(buf, "unknown\n");
    228	}
    229}
    230
    231static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
    232			const char *buf, size_t count)
    233{
    234	struct virtual_consumer_data *data = dev_get_drvdata(dev);
    235	unsigned int mode;
    236	int ret;
    237
    238	/*
    239	 * sysfs_streq() doesn't need the \n's, but we add them so the strings
    240	 * will be shared with show_mode(), above.
    241	 */
    242	if (sysfs_streq(buf, "fast\n"))
    243		mode = REGULATOR_MODE_FAST;
    244	else if (sysfs_streq(buf, "normal\n"))
    245		mode = REGULATOR_MODE_NORMAL;
    246	else if (sysfs_streq(buf, "idle\n"))
    247		mode = REGULATOR_MODE_IDLE;
    248	else if (sysfs_streq(buf, "standby\n"))
    249		mode = REGULATOR_MODE_STANDBY;
    250	else {
    251		dev_err(dev, "Configuring invalid mode\n");
    252		return count;
    253	}
    254
    255	mutex_lock(&data->lock);
    256	ret = regulator_set_mode(data->regulator, mode);
    257	if (ret == 0)
    258		data->mode = mode;
    259	else
    260		dev_err(dev, "Failed to configure mode: %d\n", ret);
    261	mutex_unlock(&data->lock);
    262
    263	return count;
    264}
    265
    266static DEVICE_ATTR(min_microvolts, 0664, show_min_uV, set_min_uV);
    267static DEVICE_ATTR(max_microvolts, 0664, show_max_uV, set_max_uV);
    268static DEVICE_ATTR(min_microamps, 0664, show_min_uA, set_min_uA);
    269static DEVICE_ATTR(max_microamps, 0664, show_max_uA, set_max_uA);
    270static DEVICE_ATTR(mode, 0664, show_mode, set_mode);
    271
    272static struct attribute *regulator_virtual_attributes[] = {
    273	&dev_attr_min_microvolts.attr,
    274	&dev_attr_max_microvolts.attr,
    275	&dev_attr_min_microamps.attr,
    276	&dev_attr_max_microamps.attr,
    277	&dev_attr_mode.attr,
    278	NULL
    279};
    280
    281static const struct attribute_group regulator_virtual_attr_group = {
    282	.attrs	= regulator_virtual_attributes,
    283};
    284
    285#ifdef CONFIG_OF
    286static const struct of_device_id regulator_virtual_consumer_of_match[] = {
    287	{ .compatible = "regulator-virtual-consumer" },
    288	{},
    289};
    290MODULE_DEVICE_TABLE(of, regulator_virtual_consumer_of_match);
    291#endif
    292
    293static int regulator_virtual_probe(struct platform_device *pdev)
    294{
    295	char *reg_id = dev_get_platdata(&pdev->dev);
    296	struct virtual_consumer_data *drvdata;
    297	static bool warned;
    298	int ret;
    299
    300	if (!warned) {
    301		warned = true;
    302		pr_warn("**********************************************************\n");
    303		pr_warn("**   NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE   **\n");
    304		pr_warn("**                                                      **\n");
    305		pr_warn("** regulator-virtual-consumer is only for testing and   **\n");
    306		pr_warn("** debugging.  Do not use it in a production kernel.    **\n");
    307		pr_warn("**                                                      **\n");
    308		pr_warn("**   NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE   **\n");
    309		pr_warn("**********************************************************\n");
    310	}
    311
    312	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct virtual_consumer_data),
    313			       GFP_KERNEL);
    314	if (drvdata == NULL)
    315		return -ENOMEM;
    316
    317	/*
    318	 * This virtual consumer does not have any hardware-defined supply
    319	 * name, so just allow the regulator to be specified in a property
    320	 * named "default-supply" when we're being probed from devicetree.
    321	 */
    322	if (!reg_id && pdev->dev.of_node)
    323		reg_id = "default";
    324
    325	mutex_init(&drvdata->lock);
    326
    327	drvdata->regulator = devm_regulator_get(&pdev->dev, reg_id);
    328	if (IS_ERR(drvdata->regulator))
    329		return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->regulator),
    330				     "Failed to obtain supply '%s'\n",
    331				     reg_id);
    332
    333	ret = sysfs_create_group(&pdev->dev.kobj,
    334				 &regulator_virtual_attr_group);
    335	if (ret != 0) {
    336		dev_err(&pdev->dev,
    337			"Failed to create attribute group: %d\n", ret);
    338		return ret;
    339	}
    340
    341	drvdata->mode = regulator_get_mode(drvdata->regulator);
    342
    343	platform_set_drvdata(pdev, drvdata);
    344
    345	return 0;
    346}
    347
    348static int regulator_virtual_remove(struct platform_device *pdev)
    349{
    350	struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
    351
    352	sysfs_remove_group(&pdev->dev.kobj, &regulator_virtual_attr_group);
    353
    354	if (drvdata->enabled)
    355		regulator_disable(drvdata->regulator);
    356
    357	return 0;
    358}
    359
    360static struct platform_driver regulator_virtual_consumer_driver = {
    361	.probe		= regulator_virtual_probe,
    362	.remove		= regulator_virtual_remove,
    363	.driver		= {
    364		.name		= "reg-virt-consumer",
    365		.of_match_table = of_match_ptr(regulator_virtual_consumer_of_match),
    366	},
    367};
    368
    369module_platform_driver(regulator_virtual_consumer_driver);
    370
    371MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
    372MODULE_DESCRIPTION("Virtual regulator consumer");
    373MODULE_LICENSE("GPL");
    374MODULE_ALIAS("platform:reg-virt-consumer");