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

cpuidle.c (4058B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2012 Linaro Ltd.
      4 */
      5
      6#include <linux/cpuidle.h>
      7#include <linux/of.h>
      8#include <linux/of_device.h>
      9#include <asm/cpuidle.h>
     10
     11extern struct of_cpuidle_method __cpuidle_method_of_table[];
     12
     13static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel
     14	__used __section("__cpuidle_method_of_table_end");
     15
     16static struct cpuidle_ops cpuidle_ops[NR_CPUS] __ro_after_init;
     17
     18/**
     19 * arm_cpuidle_simple_enter() - a wrapper to cpu_do_idle()
     20 * @dev: not used
     21 * @drv: not used
     22 * @index: not used
     23 *
     24 * A trivial wrapper to allow the cpu_do_idle function to be assigned as a
     25 * cpuidle callback by matching the function signature.
     26 *
     27 * Returns the index passed as parameter
     28 */
     29int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
     30		struct cpuidle_driver *drv, int index)
     31{
     32	cpu_do_idle();
     33
     34	return index;
     35}
     36
     37/**
     38 * arm_cpuidle_suspend() - function to enter low power idle states
     39 * @index: an integer used as an identifier for the low level PM callbacks
     40 *
     41 * This function calls the underlying arch specific low level PM code as
     42 * registered at the init time.
     43 *
     44 * Returns the result of the suspend callback.
     45 */
     46int arm_cpuidle_suspend(int index)
     47{
     48	int cpu = smp_processor_id();
     49
     50	return cpuidle_ops[cpu].suspend(index);
     51}
     52
     53/**
     54 * arm_cpuidle_get_ops() - find a registered cpuidle_ops by name
     55 * @method: the method name
     56 *
     57 * Search in the __cpuidle_method_of_table array the cpuidle ops matching the
     58 * method name.
     59 *
     60 * Returns a struct cpuidle_ops pointer, NULL if not found.
     61 */
     62static const struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)
     63{
     64	struct of_cpuidle_method *m = __cpuidle_method_of_table;
     65
     66	for (; m->method; m++)
     67		if (!strcmp(m->method, method))
     68			return m->ops;
     69
     70	return NULL;
     71}
     72
     73/**
     74 * arm_cpuidle_read_ops() - Initialize the cpuidle ops with the device tree
     75 * @dn: a pointer to a struct device node corresponding to a cpu node
     76 * @cpu: the cpu identifier
     77 *
     78 * Get the method name defined in the 'enable-method' property, retrieve the
     79 * associated cpuidle_ops and do a struct copy. This copy is needed because all
     80 * cpuidle_ops are tagged __initconst and will be unloaded after the init
     81 * process.
     82 *
     83 * Return 0 on sucess, -ENOENT if no 'enable-method' is defined, -EOPNOTSUPP if
     84 * no cpuidle_ops is registered for the 'enable-method', or if either init or
     85 * suspend callback isn't defined.
     86 */
     87static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
     88{
     89	const char *enable_method;
     90	const struct cpuidle_ops *ops;
     91
     92	enable_method = of_get_property(dn, "enable-method", NULL);
     93	if (!enable_method)
     94		return -ENOENT;
     95
     96	ops = arm_cpuidle_get_ops(enable_method);
     97	if (!ops) {
     98		pr_warn("%pOF: unsupported enable-method property: %s\n",
     99			dn, enable_method);
    100		return -EOPNOTSUPP;
    101	}
    102
    103	if (!ops->init || !ops->suspend) {
    104		pr_warn("cpuidle_ops '%s': no init or suspend callback\n",
    105			enable_method);
    106		return -EOPNOTSUPP;
    107	}
    108
    109	cpuidle_ops[cpu] = *ops; /* structure copy */
    110
    111	pr_notice("cpuidle: enable-method property '%s'"
    112		  " found operations\n", enable_method);
    113
    114	return 0;
    115}
    116
    117/**
    118 * arm_cpuidle_init() - Initialize cpuidle_ops for a specific cpu
    119 * @cpu: the cpu to be initialized
    120 *
    121 * Initialize the cpuidle ops with the device for the cpu and then call
    122 * the cpu's idle initialization callback. This may fail if the underlying HW
    123 * is not operational.
    124 *
    125 * Returns:
    126 *  0 on success,
    127 *  -ENODEV if it fails to find the cpu node in the device tree,
    128 *  -EOPNOTSUPP if it does not find a registered and valid cpuidle_ops for
    129 *  this cpu,
    130 *  -ENOENT if it fails to find an 'enable-method' property,
    131 *  -ENXIO if the HW reports a failure or a misconfiguration,
    132 *  -ENOMEM if the HW report an memory allocation failure 
    133 */
    134int __init arm_cpuidle_init(int cpu)
    135{
    136	struct device_node *cpu_node = of_cpu_device_node_get(cpu);
    137	int ret;
    138
    139	if (!cpu_node)
    140		return -ENODEV;
    141
    142	ret = arm_cpuidle_read_ops(cpu_node, cpu);
    143	if (!ret)
    144		ret = cpuidle_ops[cpu].init(cpu_node, cpu);
    145
    146	of_node_put(cpu_node);
    147
    148	return ret;
    149}