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-exynos.c (3357B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
      4 *		http://www.samsung.com
      5 *
      6 * Coupled cpuidle support based on the work of:
      7 *	Colin Cross <ccross@android.com>
      8 *	Daniel Lezcano <daniel.lezcano@linaro.org>
      9*/
     10
     11#include <linux/cpuidle.h>
     12#include <linux/cpu_pm.h>
     13#include <linux/export.h>
     14#include <linux/init.h>
     15#include <linux/platform_device.h>
     16#include <linux/of.h>
     17#include <linux/platform_data/cpuidle-exynos.h>
     18
     19#include <asm/suspend.h>
     20#include <asm/cpuidle.h>
     21
     22static atomic_t exynos_idle_barrier;
     23
     24static struct cpuidle_exynos_data *exynos_cpuidle_pdata;
     25static void (*exynos_enter_aftr)(void);
     26
     27static int exynos_enter_coupled_lowpower(struct cpuidle_device *dev,
     28					 struct cpuidle_driver *drv,
     29					 int index)
     30{
     31	int ret;
     32
     33	exynos_cpuidle_pdata->pre_enter_aftr();
     34
     35	/*
     36	 * Waiting all cpus to reach this point at the same moment
     37	 */
     38	cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
     39
     40	/*
     41	 * Both cpus will reach this point at the same time
     42	 */
     43	ret = dev->cpu ? exynos_cpuidle_pdata->cpu1_powerdown()
     44		       : exynos_cpuidle_pdata->cpu0_enter_aftr();
     45	if (ret)
     46		index = ret;
     47
     48	/*
     49	 * Waiting all cpus to finish the power sequence before going further
     50	 */
     51	cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
     52
     53	exynos_cpuidle_pdata->post_enter_aftr();
     54
     55	return index;
     56}
     57
     58static int exynos_enter_lowpower(struct cpuidle_device *dev,
     59				struct cpuidle_driver *drv,
     60				int index)
     61{
     62	int new_index = index;
     63
     64	/* AFTR can only be entered when cores other than CPU0 are offline */
     65	if (num_online_cpus() > 1 || dev->cpu != 0)
     66		new_index = drv->safe_state_index;
     67
     68	if (new_index == 0)
     69		return arm_cpuidle_simple_enter(dev, drv, new_index);
     70
     71	exynos_enter_aftr();
     72
     73	return new_index;
     74}
     75
     76static struct cpuidle_driver exynos_idle_driver = {
     77	.name			= "exynos_idle",
     78	.owner			= THIS_MODULE,
     79	.states = {
     80		[0] = ARM_CPUIDLE_WFI_STATE,
     81		[1] = {
     82			.enter			= exynos_enter_lowpower,
     83			.exit_latency		= 300,
     84			.target_residency	= 10000,
     85			.name			= "C1",
     86			.desc			= "ARM power down",
     87		},
     88	},
     89	.state_count = 2,
     90	.safe_state_index = 0,
     91};
     92
     93static struct cpuidle_driver exynos_coupled_idle_driver = {
     94	.name			= "exynos_coupled_idle",
     95	.owner			= THIS_MODULE,
     96	.states = {
     97		[0] = ARM_CPUIDLE_WFI_STATE,
     98		[1] = {
     99			.enter			= exynos_enter_coupled_lowpower,
    100			.exit_latency		= 5000,
    101			.target_residency	= 10000,
    102			.flags			= CPUIDLE_FLAG_COUPLED |
    103						  CPUIDLE_FLAG_TIMER_STOP,
    104			.name			= "C1",
    105			.desc			= "ARM power down",
    106		},
    107	},
    108	.state_count = 2,
    109	.safe_state_index = 0,
    110};
    111
    112static int exynos_cpuidle_probe(struct platform_device *pdev)
    113{
    114	int ret;
    115
    116	if (IS_ENABLED(CONFIG_SMP) &&
    117	    (of_machine_is_compatible("samsung,exynos4210") ||
    118	     of_machine_is_compatible("samsung,exynos3250"))) {
    119		exynos_cpuidle_pdata = pdev->dev.platform_data;
    120
    121		ret = cpuidle_register(&exynos_coupled_idle_driver,
    122				       cpu_possible_mask);
    123	} else {
    124		exynos_enter_aftr = (void *)(pdev->dev.platform_data);
    125
    126		ret = cpuidle_register(&exynos_idle_driver, NULL);
    127	}
    128
    129	if (ret) {
    130		dev_err(&pdev->dev, "failed to register cpuidle driver\n");
    131		return ret;
    132	}
    133
    134	return 0;
    135}
    136
    137static struct platform_driver exynos_cpuidle_driver = {
    138	.probe	= exynos_cpuidle_probe,
    139	.driver = {
    140		.name = "exynos_cpuidle",
    141	},
    142};
    143builtin_platform_driver(exynos_cpuidle_driver);