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

clkdev.c (10171B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * drivers/clk/clkdev.c
      4 *
      5 *  Copyright (C) 2008 Russell King.
      6 *
      7 * Helper for the clk API to assist looking up a struct clk.
      8 */
      9#include <linux/module.h>
     10#include <linux/kernel.h>
     11#include <linux/device.h>
     12#include <linux/list.h>
     13#include <linux/errno.h>
     14#include <linux/err.h>
     15#include <linux/string.h>
     16#include <linux/mutex.h>
     17#include <linux/clk.h>
     18#include <linux/clkdev.h>
     19#include <linux/clk-provider.h>
     20#include <linux/of.h>
     21
     22#include "clk.h"
     23
     24static LIST_HEAD(clocks);
     25static DEFINE_MUTEX(clocks_mutex);
     26
     27/*
     28 * Find the correct struct clk for the device and connection ID.
     29 * We do slightly fuzzy matching here:
     30 *  An entry with a NULL ID is assumed to be a wildcard.
     31 *  If an entry has a device ID, it must match
     32 *  If an entry has a connection ID, it must match
     33 * Then we take the most specific entry - with the following
     34 * order of precedence: dev+con > dev only > con only.
     35 */
     36static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
     37{
     38	struct clk_lookup *p, *cl = NULL;
     39	int match, best_found = 0, best_possible = 0;
     40
     41	if (dev_id)
     42		best_possible += 2;
     43	if (con_id)
     44		best_possible += 1;
     45
     46	lockdep_assert_held(&clocks_mutex);
     47
     48	list_for_each_entry(p, &clocks, node) {
     49		match = 0;
     50		if (p->dev_id) {
     51			if (!dev_id || strcmp(p->dev_id, dev_id))
     52				continue;
     53			match += 2;
     54		}
     55		if (p->con_id) {
     56			if (!con_id || strcmp(p->con_id, con_id))
     57				continue;
     58			match += 1;
     59		}
     60
     61		if (match > best_found) {
     62			cl = p;
     63			if (match != best_possible)
     64				best_found = match;
     65			else
     66				break;
     67		}
     68	}
     69	return cl;
     70}
     71
     72struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id)
     73{
     74	struct clk_lookup *cl;
     75	struct clk_hw *hw = ERR_PTR(-ENOENT);
     76
     77	mutex_lock(&clocks_mutex);
     78	cl = clk_find(dev_id, con_id);
     79	if (cl)
     80		hw = cl->clk_hw;
     81	mutex_unlock(&clocks_mutex);
     82
     83	return hw;
     84}
     85
     86static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
     87				 const char *con_id)
     88{
     89	struct clk_hw *hw = clk_find_hw(dev_id, con_id);
     90
     91	return clk_hw_create_clk(dev, hw, dev_id, con_id);
     92}
     93
     94struct clk *clk_get_sys(const char *dev_id, const char *con_id)
     95{
     96	return __clk_get_sys(NULL, dev_id, con_id);
     97}
     98EXPORT_SYMBOL(clk_get_sys);
     99
    100struct clk *clk_get(struct device *dev, const char *con_id)
    101{
    102	const char *dev_id = dev ? dev_name(dev) : NULL;
    103	struct clk_hw *hw;
    104
    105	if (dev && dev->of_node) {
    106		hw = of_clk_get_hw(dev->of_node, 0, con_id);
    107		if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER)
    108			return clk_hw_create_clk(dev, hw, dev_id, con_id);
    109	}
    110
    111	return __clk_get_sys(dev, dev_id, con_id);
    112}
    113EXPORT_SYMBOL(clk_get);
    114
    115void clk_put(struct clk *clk)
    116{
    117	__clk_put(clk);
    118}
    119EXPORT_SYMBOL(clk_put);
    120
    121static void __clkdev_add(struct clk_lookup *cl)
    122{
    123	mutex_lock(&clocks_mutex);
    124	list_add_tail(&cl->node, &clocks);
    125	mutex_unlock(&clocks_mutex);
    126}
    127
    128void clkdev_add(struct clk_lookup *cl)
    129{
    130	if (!cl->clk_hw)
    131		cl->clk_hw = __clk_get_hw(cl->clk);
    132	__clkdev_add(cl);
    133}
    134EXPORT_SYMBOL(clkdev_add);
    135
    136void clkdev_add_table(struct clk_lookup *cl, size_t num)
    137{
    138	mutex_lock(&clocks_mutex);
    139	while (num--) {
    140		cl->clk_hw = __clk_get_hw(cl->clk);
    141		list_add_tail(&cl->node, &clocks);
    142		cl++;
    143	}
    144	mutex_unlock(&clocks_mutex);
    145}
    146
    147#define MAX_DEV_ID	20
    148#define MAX_CON_ID	16
    149
    150struct clk_lookup_alloc {
    151	struct clk_lookup cl;
    152	char	dev_id[MAX_DEV_ID];
    153	char	con_id[MAX_CON_ID];
    154};
    155
    156static struct clk_lookup * __ref
    157vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
    158	va_list ap)
    159{
    160	struct clk_lookup_alloc *cla;
    161
    162	cla = kzalloc(sizeof(*cla), GFP_KERNEL);
    163	if (!cla)
    164		return NULL;
    165
    166	cla->cl.clk_hw = hw;
    167	if (con_id) {
    168		strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
    169		cla->cl.con_id = cla->con_id;
    170	}
    171
    172	if (dev_fmt) {
    173		vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
    174		cla->cl.dev_id = cla->dev_id;
    175	}
    176
    177	return &cla->cl;
    178}
    179
    180static struct clk_lookup *
    181vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
    182	va_list ap)
    183{
    184	struct clk_lookup *cl;
    185
    186	cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
    187	if (cl)
    188		__clkdev_add(cl);
    189
    190	return cl;
    191}
    192
    193/**
    194 * clkdev_create - allocate and add a clkdev lookup structure
    195 * @clk: struct clk to associate with all clk_lookups
    196 * @con_id: connection ID string on device
    197 * @dev_fmt: format string describing device name
    198 *
    199 * Returns a clk_lookup structure, which can be later unregistered and
    200 * freed.
    201 */
    202struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
    203	const char *dev_fmt, ...)
    204{
    205	struct clk_lookup *cl;
    206	va_list ap;
    207
    208	va_start(ap, dev_fmt);
    209	cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap);
    210	va_end(ap);
    211
    212	return cl;
    213}
    214EXPORT_SYMBOL_GPL(clkdev_create);
    215
    216/**
    217 * clkdev_hw_create - allocate and add a clkdev lookup structure
    218 * @hw: struct clk_hw to associate with all clk_lookups
    219 * @con_id: connection ID string on device
    220 * @dev_fmt: format string describing device name
    221 *
    222 * Returns a clk_lookup structure, which can be later unregistered and
    223 * freed.
    224 */
    225struct clk_lookup *clkdev_hw_create(struct clk_hw *hw, const char *con_id,
    226	const char *dev_fmt, ...)
    227{
    228	struct clk_lookup *cl;
    229	va_list ap;
    230
    231	va_start(ap, dev_fmt);
    232	cl = vclkdev_create(hw, con_id, dev_fmt, ap);
    233	va_end(ap);
    234
    235	return cl;
    236}
    237EXPORT_SYMBOL_GPL(clkdev_hw_create);
    238
    239int clk_add_alias(const char *alias, const char *alias_dev_name,
    240	const char *con_id, struct device *dev)
    241{
    242	struct clk *r = clk_get(dev, con_id);
    243	struct clk_lookup *l;
    244
    245	if (IS_ERR(r))
    246		return PTR_ERR(r);
    247
    248	l = clkdev_create(r, alias, alias_dev_name ? "%s" : NULL,
    249			  alias_dev_name);
    250	clk_put(r);
    251
    252	return l ? 0 : -ENODEV;
    253}
    254EXPORT_SYMBOL(clk_add_alias);
    255
    256/*
    257 * clkdev_drop - remove a clock dynamically allocated
    258 */
    259void clkdev_drop(struct clk_lookup *cl)
    260{
    261	mutex_lock(&clocks_mutex);
    262	list_del(&cl->node);
    263	mutex_unlock(&clocks_mutex);
    264	kfree(cl);
    265}
    266EXPORT_SYMBOL(clkdev_drop);
    267
    268static struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw,
    269						const char *con_id,
    270						const char *dev_id, ...)
    271{
    272	struct clk_lookup *cl;
    273	va_list ap;
    274
    275	va_start(ap, dev_id);
    276	cl = vclkdev_create(hw, con_id, dev_id, ap);
    277	va_end(ap);
    278
    279	return cl;
    280}
    281
    282static int do_clk_register_clkdev(struct clk_hw *hw,
    283	struct clk_lookup **cl, const char *con_id, const char *dev_id)
    284{
    285	if (IS_ERR(hw))
    286		return PTR_ERR(hw);
    287	/*
    288	 * Since dev_id can be NULL, and NULL is handled specially, we must
    289	 * pass it as either a NULL format string, or with "%s".
    290	 */
    291	if (dev_id)
    292		*cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
    293	else
    294		*cl = __clk_register_clkdev(hw, con_id, NULL);
    295
    296	return *cl ? 0 : -ENOMEM;
    297}
    298
    299/**
    300 * clk_register_clkdev - register one clock lookup for a struct clk
    301 * @clk: struct clk to associate with all clk_lookups
    302 * @con_id: connection ID string on device
    303 * @dev_id: string describing device name
    304 *
    305 * con_id or dev_id may be NULL as a wildcard, just as in the rest of
    306 * clkdev.
    307 *
    308 * To make things easier for mass registration, we detect error clks
    309 * from a previous clk_register() call, and return the error code for
    310 * those.  This is to permit this function to be called immediately
    311 * after clk_register().
    312 */
    313int clk_register_clkdev(struct clk *clk, const char *con_id,
    314	const char *dev_id)
    315{
    316	struct clk_lookup *cl;
    317
    318	if (IS_ERR(clk))
    319		return PTR_ERR(clk);
    320
    321	return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id,
    322					      dev_id);
    323}
    324EXPORT_SYMBOL(clk_register_clkdev);
    325
    326/**
    327 * clk_hw_register_clkdev - register one clock lookup for a struct clk_hw
    328 * @hw: struct clk_hw to associate with all clk_lookups
    329 * @con_id: connection ID string on device
    330 * @dev_id: format string describing device name
    331 *
    332 * con_id or dev_id may be NULL as a wildcard, just as in the rest of
    333 * clkdev.
    334 *
    335 * To make things easier for mass registration, we detect error clk_hws
    336 * from a previous clk_hw_register_*() call, and return the error code for
    337 * those.  This is to permit this function to be called immediately
    338 * after clk_hw_register_*().
    339 */
    340int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
    341	const char *dev_id)
    342{
    343	struct clk_lookup *cl;
    344
    345	return do_clk_register_clkdev(hw, &cl, con_id, dev_id);
    346}
    347EXPORT_SYMBOL(clk_hw_register_clkdev);
    348
    349static void devm_clkdev_release(struct device *dev, void *res)
    350{
    351	clkdev_drop(*(struct clk_lookup **)res);
    352}
    353
    354static int devm_clk_match_clkdev(struct device *dev, void *res, void *data)
    355{
    356	struct clk_lookup **l = res;
    357
    358	return *l == data;
    359}
    360
    361/**
    362 * devm_clk_release_clkdev - Resource managed clkdev lookup release
    363 * @dev: device this lookup is bound
    364 * @con_id: connection ID string on device
    365 * @dev_id: format string describing device name
    366 *
    367 * Drop the clkdev lookup created with devm_clk_hw_register_clkdev.
    368 * Normally this function will not need to be called and the resource
    369 * management code will ensure that the resource is freed.
    370 */
    371void devm_clk_release_clkdev(struct device *dev, const char *con_id,
    372			     const char *dev_id)
    373{
    374	struct clk_lookup *cl;
    375	int rval;
    376
    377	mutex_lock(&clocks_mutex);
    378	cl = clk_find(dev_id, con_id);
    379	mutex_unlock(&clocks_mutex);
    380
    381	WARN_ON(!cl);
    382	rval = devres_release(dev, devm_clkdev_release,
    383			      devm_clk_match_clkdev, cl);
    384	WARN_ON(rval);
    385}
    386EXPORT_SYMBOL(devm_clk_release_clkdev);
    387
    388/**
    389 * devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw
    390 * @dev: device this lookup is bound
    391 * @hw: struct clk_hw to associate with all clk_lookups
    392 * @con_id: connection ID string on device
    393 * @dev_id: format string describing device name
    394 *
    395 * con_id or dev_id may be NULL as a wildcard, just as in the rest of
    396 * clkdev.
    397 *
    398 * To make things easier for mass registration, we detect error clk_hws
    399 * from a previous clk_hw_register_*() call, and return the error code for
    400 * those.  This is to permit this function to be called immediately
    401 * after clk_hw_register_*().
    402 */
    403int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
    404				const char *con_id, const char *dev_id)
    405{
    406	int rval = -ENOMEM;
    407	struct clk_lookup **cl;
    408
    409	cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL);
    410	if (cl) {
    411		rval = do_clk_register_clkdev(hw, cl, con_id, dev_id);
    412		if (!rval)
    413			devres_add(dev, cl);
    414		else
    415			devres_free(cl);
    416	}
    417	return rval;
    418}
    419EXPORT_SYMBOL(devm_clk_hw_register_clkdev);