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

linear_ranges.c (8311B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * helpers to map values in a linear range to range index
      4 *
      5 * Original idea borrowed from regulator framework
      6 *
      7 * It might be useful if we could support also inversely proportional ranges?
      8 * Copyright 2020 ROHM Semiconductors
      9 */
     10
     11#include <linux/errno.h>
     12#include <linux/export.h>
     13#include <linux/kernel.h>
     14#include <linux/linear_range.h>
     15#include <linux/module.h>
     16
     17/**
     18 * linear_range_values_in_range - return the amount of values in a range
     19 * @r:		pointer to linear range where values are counted
     20 *
     21 * Compute the amount of values in range pointed by @r. Note, values can
     22 * be all equal - range with selectors 0,...,2 with step 0 still contains
     23 * 3 values even though they are all equal.
     24 *
     25 * Return: the amount of values in range pointed by @r
     26 */
     27unsigned int linear_range_values_in_range(const struct linear_range *r)
     28{
     29	if (!r)
     30		return 0;
     31	return r->max_sel - r->min_sel + 1;
     32}
     33EXPORT_SYMBOL_GPL(linear_range_values_in_range);
     34
     35/**
     36 * linear_range_values_in_range_array - return the amount of values in ranges
     37 * @r:		pointer to array of linear ranges where values are counted
     38 * @ranges:	amount of ranges we include in computation.
     39 *
     40 * Compute the amount of values in ranges pointed by @r. Note, values can
     41 * be all equal - range with selectors 0,...,2 with step 0 still contains
     42 * 3 values even though they are all equal.
     43 *
     44 * Return: the amount of values in first @ranges ranges pointed by @r
     45 */
     46unsigned int linear_range_values_in_range_array(const struct linear_range *r,
     47						int ranges)
     48{
     49	int i, values_in_range = 0;
     50
     51	for (i = 0; i < ranges; i++) {
     52		int values;
     53
     54		values = linear_range_values_in_range(&r[i]);
     55		if (!values)
     56			return values;
     57
     58		values_in_range += values;
     59	}
     60	return values_in_range;
     61}
     62EXPORT_SYMBOL_GPL(linear_range_values_in_range_array);
     63
     64/**
     65 * linear_range_get_max_value - return the largest value in a range
     66 * @r:		pointer to linear range where value is looked from
     67 *
     68 * Return: the largest value in the given range
     69 */
     70unsigned int linear_range_get_max_value(const struct linear_range *r)
     71{
     72	return r->min + (r->max_sel - r->min_sel) * r->step;
     73}
     74EXPORT_SYMBOL_GPL(linear_range_get_max_value);
     75
     76/**
     77 * linear_range_get_value - fetch a value from given range
     78 * @r:		pointer to linear range where value is looked from
     79 * @selector:	selector for which the value is searched
     80 * @val:	address where found value is updated
     81 *
     82 * Search given ranges for value which matches given selector.
     83 *
     84 * Return: 0 on success, -EINVAL given selector is not found from any of the
     85 * ranges.
     86 */
     87int linear_range_get_value(const struct linear_range *r, unsigned int selector,
     88			   unsigned int *val)
     89{
     90	if (r->min_sel > selector || r->max_sel < selector)
     91		return -EINVAL;
     92
     93	*val = r->min + (selector - r->min_sel) * r->step;
     94
     95	return 0;
     96}
     97EXPORT_SYMBOL_GPL(linear_range_get_value);
     98
     99/**
    100 * linear_range_get_value_array - fetch a value from array of ranges
    101 * @r:		pointer to array of linear ranges where value is looked from
    102 * @ranges:	amount of ranges in an array
    103 * @selector:	selector for which the value is searched
    104 * @val:	address where found value is updated
    105 *
    106 * Search through an array of ranges for value which matches given selector.
    107 *
    108 * Return: 0 on success, -EINVAL given selector is not found from any of the
    109 * ranges.
    110 */
    111int linear_range_get_value_array(const struct linear_range *r, int ranges,
    112				 unsigned int selector, unsigned int *val)
    113{
    114	int i;
    115
    116	for (i = 0; i < ranges; i++)
    117		if (r[i].min_sel <= selector && r[i].max_sel >= selector)
    118			return linear_range_get_value(&r[i], selector, val);
    119
    120	return -EINVAL;
    121}
    122EXPORT_SYMBOL_GPL(linear_range_get_value_array);
    123
    124/**
    125 * linear_range_get_selector_low - return linear range selector for value
    126 * @r:		pointer to linear range where selector is looked from
    127 * @val:	value for which the selector is searched
    128 * @selector:	address where found selector value is updated
    129 * @found:	flag to indicate that given value was in the range
    130 *
    131 * Return selector for which range value is closest match for given
    132 * input value. Value is matching if it is equal or smaller than given
    133 * value. If given value is in the range, then @found is set true.
    134 *
    135 * Return: 0 on success, -EINVAL if range is invalid or does not contain
    136 * value smaller or equal to given value
    137 */
    138int linear_range_get_selector_low(const struct linear_range *r,
    139				  unsigned int val, unsigned int *selector,
    140				  bool *found)
    141{
    142	*found = false;
    143
    144	if (r->min > val)
    145		return -EINVAL;
    146
    147	if (linear_range_get_max_value(r) < val) {
    148		*selector = r->max_sel;
    149		return 0;
    150	}
    151
    152	*found = true;
    153
    154	if (r->step == 0)
    155		*selector = r->min_sel;
    156	else
    157		*selector = (val - r->min) / r->step + r->min_sel;
    158
    159	return 0;
    160}
    161EXPORT_SYMBOL_GPL(linear_range_get_selector_low);
    162
    163/**
    164 * linear_range_get_selector_low_array - return linear range selector for value
    165 * @r:		pointer to array of linear ranges where selector is looked from
    166 * @ranges:	amount of ranges to scan from array
    167 * @val:	value for which the selector is searched
    168 * @selector:	address where found selector value is updated
    169 * @found:	flag to indicate that given value was in the range
    170 *
    171 * Scan array of ranges for selector for which range value matches given
    172 * input value. Value is matching if it is equal or smaller than given
    173 * value. If given value is found to be in a range scanning is stopped and
    174 * @found is set true. If a range with values smaller than given value is found
    175 * but the range max is being smaller than given value, then the range's
    176 * biggest selector is updated to @selector but scanning ranges is continued
    177 * and @found is set to false.
    178 *
    179 * Return: 0 on success, -EINVAL if range array is invalid or does not contain
    180 * range with a value smaller or equal to given value
    181 */
    182int linear_range_get_selector_low_array(const struct linear_range *r,
    183					int ranges, unsigned int val,
    184					unsigned int *selector, bool *found)
    185{
    186	int i;
    187	int ret = -EINVAL;
    188
    189	for (i = 0; i < ranges; i++) {
    190		int tmpret;
    191
    192		tmpret = linear_range_get_selector_low(&r[i], val, selector,
    193						       found);
    194		if (!tmpret)
    195			ret = 0;
    196
    197		if (*found)
    198			break;
    199	}
    200
    201	return ret;
    202}
    203EXPORT_SYMBOL_GPL(linear_range_get_selector_low_array);
    204
    205/**
    206 * linear_range_get_selector_high - return linear range selector for value
    207 * @r:		pointer to linear range where selector is looked from
    208 * @val:	value for which the selector is searched
    209 * @selector:	address where found selector value is updated
    210 * @found:	flag to indicate that given value was in the range
    211 *
    212 * Return selector for which range value is closest match for given
    213 * input value. Value is matching if it is equal or higher than given
    214 * value. If given value is in the range, then @found is set true.
    215 *
    216 * Return: 0 on success, -EINVAL if range is invalid or does not contain
    217 * value greater or equal to given value
    218 */
    219int linear_range_get_selector_high(const struct linear_range *r,
    220				   unsigned int val, unsigned int *selector,
    221				   bool *found)
    222{
    223	*found = false;
    224
    225	if (linear_range_get_max_value(r) < val)
    226		return -EINVAL;
    227
    228	if (r->min > val) {
    229		*selector = r->min_sel;
    230		return 0;
    231	}
    232
    233	*found = true;
    234
    235	if (r->step == 0)
    236		*selector = r->max_sel;
    237	else
    238		*selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel;
    239
    240	return 0;
    241}
    242EXPORT_SYMBOL_GPL(linear_range_get_selector_high);
    243
    244/**
    245 * linear_range_get_selector_within - return linear range selector for value
    246 * @r:		pointer to linear range where selector is looked from
    247 * @val:	value for which the selector is searched
    248 * @selector:	address where found selector value is updated
    249 *
    250 * Return selector for which range value is closest match for given
    251 * input value. Value is matching if it is equal or lower than given
    252 * value. But return maximum selector if given value is higher than
    253 * maximum value.
    254 */
    255void linear_range_get_selector_within(const struct linear_range *r,
    256				      unsigned int val, unsigned int *selector)
    257{
    258	if (r->min > val) {
    259		*selector = r->min_sel;
    260		return;
    261	}
    262
    263	if (linear_range_get_max_value(r) < val) {
    264		*selector = r->max_sel;
    265		return;
    266	}
    267
    268	if (r->step == 0)
    269		*selector = r->min_sel;
    270	else
    271		*selector = (val - r->min) / r->step + r->min_sel;
    272}
    273EXPORT_SYMBOL_GPL(linear_range_get_selector_within);
    274
    275MODULE_DESCRIPTION("linear-ranges helper");
    276MODULE_LICENSE("GPL");