1d405a98cSShreyas B. Prabhu /*
2d405a98cSShreyas B. Prabhu  * PowerNV cpuidle code
3d405a98cSShreyas B. Prabhu  *
4d405a98cSShreyas B. Prabhu  * Copyright 2015 IBM Corp.
5d405a98cSShreyas B. Prabhu  *
6d405a98cSShreyas B. Prabhu  * This program is free software; you can redistribute it and/or
7d405a98cSShreyas B. Prabhu  * modify it under the terms of the GNU General Public License
8d405a98cSShreyas B. Prabhu  * as published by the Free Software Foundation; either version
9d405a98cSShreyas B. Prabhu  * 2 of the License, or (at your option) any later version.
10d405a98cSShreyas B. Prabhu  */
11d405a98cSShreyas B. Prabhu 
12d405a98cSShreyas B. Prabhu #include <linux/types.h>
13d405a98cSShreyas B. Prabhu #include <linux/mm.h>
14d405a98cSShreyas B. Prabhu #include <linux/slab.h>
15d405a98cSShreyas B. Prabhu #include <linux/of.h>
165703d2f4SShreyas B. Prabhu #include <linux/device.h>
175703d2f4SShreyas B. Prabhu #include <linux/cpu.h>
18d405a98cSShreyas B. Prabhu 
19d405a98cSShreyas B. Prabhu #include <asm/firmware.h>
204bece972SMichael Ellerman #include <asm/machdep.h>
21d405a98cSShreyas B. Prabhu #include <asm/opal.h>
22d405a98cSShreyas B. Prabhu #include <asm/cputhreads.h>
23d405a98cSShreyas B. Prabhu #include <asm/cpuidle.h>
24d405a98cSShreyas B. Prabhu #include <asm/code-patching.h>
25d405a98cSShreyas B. Prabhu #include <asm/smp.h>
26d405a98cSShreyas B. Prabhu 
27d405a98cSShreyas B. Prabhu #include "powernv.h"
28d405a98cSShreyas B. Prabhu #include "subcore.h"
29d405a98cSShreyas B. Prabhu 
30bcef83a0SShreyas B. Prabhu /* Power ISA 3.0 allows for stop states 0x0 - 0xF */
31bcef83a0SShreyas B. Prabhu #define MAX_STOP_STATE	0xF
32bcef83a0SShreyas B. Prabhu 
33d405a98cSShreyas B. Prabhu static u32 supported_cpuidle_states;
34d405a98cSShreyas B. Prabhu 
35bcef83a0SShreyas B. Prabhu static int pnv_save_sprs_for_deep_states(void)
36d405a98cSShreyas B. Prabhu {
37d405a98cSShreyas B. Prabhu 	int cpu;
38d405a98cSShreyas B. Prabhu 	int rc;
39d405a98cSShreyas B. Prabhu 
40d405a98cSShreyas B. Prabhu 	/*
41446957baSAdam Buchbinder 	 * hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric across
42d405a98cSShreyas B. Prabhu 	 * all cpus at boot. Get these reg values of current cpu and use the
43446957baSAdam Buchbinder 	 * same across all cpus.
44d405a98cSShreyas B. Prabhu 	 */
45d405a98cSShreyas B. Prabhu 	uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
46d405a98cSShreyas B. Prabhu 	uint64_t hid0_val = mfspr(SPRN_HID0);
47d405a98cSShreyas B. Prabhu 	uint64_t hid1_val = mfspr(SPRN_HID1);
48d405a98cSShreyas B. Prabhu 	uint64_t hid4_val = mfspr(SPRN_HID4);
49d405a98cSShreyas B. Prabhu 	uint64_t hid5_val = mfspr(SPRN_HID5);
50d405a98cSShreyas B. Prabhu 	uint64_t hmeer_val = mfspr(SPRN_HMEER);
51d405a98cSShreyas B. Prabhu 
52d405a98cSShreyas B. Prabhu 	for_each_possible_cpu(cpu) {
53d405a98cSShreyas B. Prabhu 		uint64_t pir = get_hard_smp_processor_id(cpu);
54d405a98cSShreyas B. Prabhu 		uint64_t hsprg0_val = (uint64_t)&paca[cpu];
55d405a98cSShreyas B. Prabhu 
56bcef83a0SShreyas B. Prabhu 		if (!cpu_has_feature(CPU_FTR_ARCH_300)) {
57d405a98cSShreyas B. Prabhu 			/*
58bcef83a0SShreyas B. Prabhu 			 * HSPRG0 is used to store the cpu's pointer to paca.
59bcef83a0SShreyas B. Prabhu 			 * Hence last 3 bits are guaranteed to be 0. Program
60bcef83a0SShreyas B. Prabhu 			 * slw to restore HSPRG0 with 63rd bit set, so that
61bcef83a0SShreyas B. Prabhu 			 * when a thread wakes up at 0x100 we can use this bit
62bcef83a0SShreyas B. Prabhu 			 * to distinguish between fastsleep and deep winkle.
63bcef83a0SShreyas B. Prabhu 			 * This is not necessary with stop/psscr since PLS
64bcef83a0SShreyas B. Prabhu 			 * field of psscr indicates which state we are waking
65bcef83a0SShreyas B. Prabhu 			 * up from.
66d405a98cSShreyas B. Prabhu 			 */
67d405a98cSShreyas B. Prabhu 			hsprg0_val |= 1;
68bcef83a0SShreyas B. Prabhu 		}
69d405a98cSShreyas B. Prabhu 		rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
70d405a98cSShreyas B. Prabhu 		if (rc != 0)
71d405a98cSShreyas B. Prabhu 			return rc;
72d405a98cSShreyas B. Prabhu 
73d405a98cSShreyas B. Prabhu 		rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
74d405a98cSShreyas B. Prabhu 		if (rc != 0)
75d405a98cSShreyas B. Prabhu 			return rc;
76d405a98cSShreyas B. Prabhu 
77d405a98cSShreyas B. Prabhu 		/* HIDs are per core registers */
78d405a98cSShreyas B. Prabhu 		if (cpu_thread_in_core(cpu) == 0) {
79d405a98cSShreyas B. Prabhu 
80d405a98cSShreyas B. Prabhu 			rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);
81d405a98cSShreyas B. Prabhu 			if (rc != 0)
82d405a98cSShreyas B. Prabhu 				return rc;
83d405a98cSShreyas B. Prabhu 
84d405a98cSShreyas B. Prabhu 			rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);
85d405a98cSShreyas B. Prabhu 			if (rc != 0)
86d405a98cSShreyas B. Prabhu 				return rc;
87d405a98cSShreyas B. Prabhu 
88d405a98cSShreyas B. Prabhu 			rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);
89d405a98cSShreyas B. Prabhu 			if (rc != 0)
90d405a98cSShreyas B. Prabhu 				return rc;
91d405a98cSShreyas B. Prabhu 
92d405a98cSShreyas B. Prabhu 			rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);
93d405a98cSShreyas B. Prabhu 			if (rc != 0)
94d405a98cSShreyas B. Prabhu 				return rc;
95d405a98cSShreyas B. Prabhu 
96d405a98cSShreyas B. Prabhu 			rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);
97d405a98cSShreyas B. Prabhu 			if (rc != 0)
98d405a98cSShreyas B. Prabhu 				return rc;
99d405a98cSShreyas B. Prabhu 		}
100d405a98cSShreyas B. Prabhu 	}
101d405a98cSShreyas B. Prabhu 
102d405a98cSShreyas B. Prabhu 	return 0;
103d405a98cSShreyas B. Prabhu }
104d405a98cSShreyas B. Prabhu 
105d405a98cSShreyas B. Prabhu static void pnv_alloc_idle_core_states(void)
106d405a98cSShreyas B. Prabhu {
107d405a98cSShreyas B. Prabhu 	int i, j;
108d405a98cSShreyas B. Prabhu 	int nr_cores = cpu_nr_cores();
109d405a98cSShreyas B. Prabhu 	u32 *core_idle_state;
110d405a98cSShreyas B. Prabhu 
111d405a98cSShreyas B. Prabhu 	/*
112d405a98cSShreyas B. Prabhu 	 * core_idle_state - First 8 bits track the idle state of each thread
113d405a98cSShreyas B. Prabhu 	 * of the core. The 8th bit is the lock bit. Initially all thread bits
114d405a98cSShreyas B. Prabhu 	 * are set. They are cleared when the thread enters deep idle state
115d405a98cSShreyas B. Prabhu 	 * like sleep and winkle. Initially the lock bit is cleared.
116d405a98cSShreyas B. Prabhu 	 * The lock bit has 2 purposes
117d405a98cSShreyas B. Prabhu 	 * a. While the first thread is restoring core state, it prevents
118d405a98cSShreyas B. Prabhu 	 * other threads in the core from switching to process context.
119d405a98cSShreyas B. Prabhu 	 * b. While the last thread in the core is saving the core state, it
120d405a98cSShreyas B. Prabhu 	 * prevents a different thread from waking up.
121d405a98cSShreyas B. Prabhu 	 */
122d405a98cSShreyas B. Prabhu 	for (i = 0; i < nr_cores; i++) {
123d405a98cSShreyas B. Prabhu 		int first_cpu = i * threads_per_core;
124d405a98cSShreyas B. Prabhu 		int node = cpu_to_node(first_cpu);
125d405a98cSShreyas B. Prabhu 
126d405a98cSShreyas B. Prabhu 		core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
127d405a98cSShreyas B. Prabhu 		*core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
128d405a98cSShreyas B. Prabhu 
129d405a98cSShreyas B. Prabhu 		for (j = 0; j < threads_per_core; j++) {
130d405a98cSShreyas B. Prabhu 			int cpu = first_cpu + j;
131d405a98cSShreyas B. Prabhu 
132d405a98cSShreyas B. Prabhu 			paca[cpu].core_idle_state_ptr = core_idle_state;
133d405a98cSShreyas B. Prabhu 			paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
134d405a98cSShreyas B. Prabhu 			paca[cpu].thread_mask = 1 << j;
135d405a98cSShreyas B. Prabhu 		}
136d405a98cSShreyas B. Prabhu 	}
137d405a98cSShreyas B. Prabhu 
138d405a98cSShreyas B. Prabhu 	update_subcore_sibling_mask();
139d405a98cSShreyas B. Prabhu 
140bcef83a0SShreyas B. Prabhu 	if (supported_cpuidle_states & OPAL_PM_LOSE_FULL_CONTEXT)
141bcef83a0SShreyas B. Prabhu 		pnv_save_sprs_for_deep_states();
142d405a98cSShreyas B. Prabhu }
143d405a98cSShreyas B. Prabhu 
144d405a98cSShreyas B. Prabhu u32 pnv_get_supported_cpuidle_states(void)
145d405a98cSShreyas B. Prabhu {
146d405a98cSShreyas B. Prabhu 	return supported_cpuidle_states;
147d405a98cSShreyas B. Prabhu }
148d405a98cSShreyas B. Prabhu EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
149d405a98cSShreyas B. Prabhu 
1505703d2f4SShreyas B. Prabhu 
1515703d2f4SShreyas B. Prabhu static void pnv_fastsleep_workaround_apply(void *info)
1525703d2f4SShreyas B. Prabhu 
1535703d2f4SShreyas B. Prabhu {
1545703d2f4SShreyas B. Prabhu 	int rc;
1555703d2f4SShreyas B. Prabhu 	int *err = info;
1565703d2f4SShreyas B. Prabhu 
1575703d2f4SShreyas B. Prabhu 	rc = opal_config_cpu_idle_state(OPAL_CONFIG_IDLE_FASTSLEEP,
1585703d2f4SShreyas B. Prabhu 					OPAL_CONFIG_IDLE_APPLY);
1595703d2f4SShreyas B. Prabhu 	if (rc)
1605703d2f4SShreyas B. Prabhu 		*err = 1;
1615703d2f4SShreyas B. Prabhu }
1625703d2f4SShreyas B. Prabhu 
1635703d2f4SShreyas B. Prabhu /*
1645703d2f4SShreyas B. Prabhu  * Used to store fastsleep workaround state
1655703d2f4SShreyas B. Prabhu  * 0 - Workaround applied/undone at fastsleep entry/exit path (Default)
1665703d2f4SShreyas B. Prabhu  * 1 - Workaround applied once, never undone.
1675703d2f4SShreyas B. Prabhu  */
1685703d2f4SShreyas B. Prabhu static u8 fastsleep_workaround_applyonce;
1695703d2f4SShreyas B. Prabhu 
1705703d2f4SShreyas B. Prabhu static ssize_t show_fastsleep_workaround_applyonce(struct device *dev,
1715703d2f4SShreyas B. Prabhu 		struct device_attribute *attr, char *buf)
1725703d2f4SShreyas B. Prabhu {
1735703d2f4SShreyas B. Prabhu 	return sprintf(buf, "%u\n", fastsleep_workaround_applyonce);
1745703d2f4SShreyas B. Prabhu }
1755703d2f4SShreyas B. Prabhu 
1765703d2f4SShreyas B. Prabhu static ssize_t store_fastsleep_workaround_applyonce(struct device *dev,
1775703d2f4SShreyas B. Prabhu 		struct device_attribute *attr, const char *buf,
1785703d2f4SShreyas B. Prabhu 		size_t count)
1795703d2f4SShreyas B. Prabhu {
1805703d2f4SShreyas B. Prabhu 	cpumask_t primary_thread_mask;
1815703d2f4SShreyas B. Prabhu 	int err;
1825703d2f4SShreyas B. Prabhu 	u8 val;
1835703d2f4SShreyas B. Prabhu 
1845703d2f4SShreyas B. Prabhu 	if (kstrtou8(buf, 0, &val) || val != 1)
1855703d2f4SShreyas B. Prabhu 		return -EINVAL;
1865703d2f4SShreyas B. Prabhu 
1875703d2f4SShreyas B. Prabhu 	if (fastsleep_workaround_applyonce == 1)
1885703d2f4SShreyas B. Prabhu 		return count;
1895703d2f4SShreyas B. Prabhu 
1905703d2f4SShreyas B. Prabhu 	/*
1915703d2f4SShreyas B. Prabhu 	 * fastsleep_workaround_applyonce = 1 implies
1925703d2f4SShreyas B. Prabhu 	 * fastsleep workaround needs to be left in 'applied' state on all
1935703d2f4SShreyas B. Prabhu 	 * the cores. Do this by-
1945703d2f4SShreyas B. Prabhu 	 * 1. Patching out the call to 'undo' workaround in fastsleep exit path
1955703d2f4SShreyas B. Prabhu 	 * 2. Sending ipi to all the cores which have at least one online thread
1965703d2f4SShreyas B. Prabhu 	 * 3. Patching out the call to 'apply' workaround in fastsleep entry
1975703d2f4SShreyas B. Prabhu 	 * path
1985703d2f4SShreyas B. Prabhu 	 * There is no need to send ipi to cores which have all threads
1995703d2f4SShreyas B. Prabhu 	 * offlined, as last thread of the core entering fastsleep or deeper
2005703d2f4SShreyas B. Prabhu 	 * state would have applied workaround.
2015703d2f4SShreyas B. Prabhu 	 */
2025703d2f4SShreyas B. Prabhu 	err = patch_instruction(
2035703d2f4SShreyas B. Prabhu 		(unsigned int *)pnv_fastsleep_workaround_at_exit,
2045703d2f4SShreyas B. Prabhu 		PPC_INST_NOP);
2055703d2f4SShreyas B. Prabhu 	if (err) {
2065703d2f4SShreyas B. Prabhu 		pr_err("fastsleep_workaround_applyonce change failed while patching pnv_fastsleep_workaround_at_exit");
2075703d2f4SShreyas B. Prabhu 		goto fail;
2085703d2f4SShreyas B. Prabhu 	}
2095703d2f4SShreyas B. Prabhu 
2105703d2f4SShreyas B. Prabhu 	get_online_cpus();
2115703d2f4SShreyas B. Prabhu 	primary_thread_mask = cpu_online_cores_map();
2125703d2f4SShreyas B. Prabhu 	on_each_cpu_mask(&primary_thread_mask,
2135703d2f4SShreyas B. Prabhu 				pnv_fastsleep_workaround_apply,
2145703d2f4SShreyas B. Prabhu 				&err, 1);
2155703d2f4SShreyas B. Prabhu 	put_online_cpus();
2165703d2f4SShreyas B. Prabhu 	if (err) {
2175703d2f4SShreyas B. Prabhu 		pr_err("fastsleep_workaround_applyonce change failed while running pnv_fastsleep_workaround_apply");
2185703d2f4SShreyas B. Prabhu 		goto fail;
2195703d2f4SShreyas B. Prabhu 	}
2205703d2f4SShreyas B. Prabhu 
2215703d2f4SShreyas B. Prabhu 	err = patch_instruction(
2225703d2f4SShreyas B. Prabhu 		(unsigned int *)pnv_fastsleep_workaround_at_entry,
2235703d2f4SShreyas B. Prabhu 		PPC_INST_NOP);
2245703d2f4SShreyas B. Prabhu 	if (err) {
2255703d2f4SShreyas B. Prabhu 		pr_err("fastsleep_workaround_applyonce change failed while patching pnv_fastsleep_workaround_at_entry");
2265703d2f4SShreyas B. Prabhu 		goto fail;
2275703d2f4SShreyas B. Prabhu 	}
2285703d2f4SShreyas B. Prabhu 
2295703d2f4SShreyas B. Prabhu 	fastsleep_workaround_applyonce = 1;
2305703d2f4SShreyas B. Prabhu 
2315703d2f4SShreyas B. Prabhu 	return count;
2325703d2f4SShreyas B. Prabhu fail:
2335703d2f4SShreyas B. Prabhu 	return -EIO;
2345703d2f4SShreyas B. Prabhu }
2355703d2f4SShreyas B. Prabhu 
2365703d2f4SShreyas B. Prabhu static DEVICE_ATTR(fastsleep_workaround_applyonce, 0600,
2375703d2f4SShreyas B. Prabhu 			show_fastsleep_workaround_applyonce,
2385703d2f4SShreyas B. Prabhu 			store_fastsleep_workaround_applyonce);
2395703d2f4SShreyas B. Prabhu 
24009206b60SGautham R. Shenoy /*
24109206b60SGautham R. Shenoy  * The default stop state that will be used by ppc_md.power_save
24209206b60SGautham R. Shenoy  * function on platforms that support stop instruction.
24309206b60SGautham R. Shenoy  */
24409206b60SGautham R. Shenoy u64 pnv_default_stop_val;
24509206b60SGautham R. Shenoy u64 pnv_default_stop_mask;
246bcef83a0SShreyas B. Prabhu 
247bcef83a0SShreyas B. Prabhu /*
248bcef83a0SShreyas B. Prabhu  * Used for ppc_md.power_save which needs a function with no parameters
249bcef83a0SShreyas B. Prabhu  */
250bcef83a0SShreyas B. Prabhu static void power9_idle(void)
251d405a98cSShreyas B. Prabhu {
25209206b60SGautham R. Shenoy 	power9_idle_stop(pnv_default_stop_val, pnv_default_stop_mask);
253bcef83a0SShreyas B. Prabhu }
25409206b60SGautham R. Shenoy 
255bcef83a0SShreyas B. Prabhu /*
256bcef83a0SShreyas B. Prabhu  * First deep stop state. Used to figure out when to save/restore
257bcef83a0SShreyas B. Prabhu  * hypervisor context.
258bcef83a0SShreyas B. Prabhu  */
259bcef83a0SShreyas B. Prabhu u64 pnv_first_deep_stop_state = MAX_STOP_STATE;
260bcef83a0SShreyas B. Prabhu 
261bcef83a0SShreyas B. Prabhu /*
26209206b60SGautham R. Shenoy  * psscr value and mask of the deepest stop idle state.
26309206b60SGautham R. Shenoy  * Used when a cpu is offlined.
264c0691f9dSShreyas B. Prabhu  */
26509206b60SGautham R. Shenoy u64 pnv_deepest_stop_psscr_val;
26609206b60SGautham R. Shenoy u64 pnv_deepest_stop_psscr_mask;
267c0691f9dSShreyas B. Prabhu 
268c0691f9dSShreyas B. Prabhu /*
269a7cd88daSGautham R. Shenoy  * pnv_cpu_offline: A function that puts the CPU into the deepest
270a7cd88daSGautham R. Shenoy  * available platform idle state on a CPU-Offline.
271a7cd88daSGautham R. Shenoy  */
272a7cd88daSGautham R. Shenoy unsigned long pnv_cpu_offline(unsigned int cpu)
273a7cd88daSGautham R. Shenoy {
274a7cd88daSGautham R. Shenoy 	unsigned long srr1;
275a7cd88daSGautham R. Shenoy 
276a7cd88daSGautham R. Shenoy 	u32 idle_states = pnv_get_supported_cpuidle_states();
277a7cd88daSGautham R. Shenoy 
278a7cd88daSGautham R. Shenoy 	if (cpu_has_feature(CPU_FTR_ARCH_300)) {
279a7cd88daSGautham R. Shenoy 		srr1 = power9_idle_stop(pnv_deepest_stop_psscr_val,
280a7cd88daSGautham R. Shenoy 					pnv_deepest_stop_psscr_mask);
281a7cd88daSGautham R. Shenoy 	} else if (idle_states & OPAL_PM_WINKLE_ENABLED) {
282a7cd88daSGautham R. Shenoy 		srr1 = power7_winkle();
283a7cd88daSGautham R. Shenoy 	} else if ((idle_states & OPAL_PM_SLEEP_ENABLED) ||
284a7cd88daSGautham R. Shenoy 		   (idle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
285a7cd88daSGautham R. Shenoy 		srr1 = power7_sleep();
28690061231SGautham R. Shenoy 	} else if (idle_states & OPAL_PM_NAP_ENABLED) {
287a7cd88daSGautham R. Shenoy 		srr1 = power7_nap(1);
28890061231SGautham R. Shenoy 	} else {
28990061231SGautham R. Shenoy 		/* This is the fallback method. We emulate snooze */
29090061231SGautham R. Shenoy 		while (!generic_check_cpu_restart(cpu)) {
29190061231SGautham R. Shenoy 			HMT_low();
29290061231SGautham R. Shenoy 			HMT_very_low();
29390061231SGautham R. Shenoy 		}
29490061231SGautham R. Shenoy 		srr1 = 0;
29590061231SGautham R. Shenoy 		HMT_medium();
296a7cd88daSGautham R. Shenoy 	}
297a7cd88daSGautham R. Shenoy 
298a7cd88daSGautham R. Shenoy 	return srr1;
299a7cd88daSGautham R. Shenoy }
300a7cd88daSGautham R. Shenoy 
301a7cd88daSGautham R. Shenoy /*
302bcef83a0SShreyas B. Prabhu  * Power ISA 3.0 idle initialization.
303bcef83a0SShreyas B. Prabhu  *
304bcef83a0SShreyas B. Prabhu  * POWER ISA 3.0 defines a new SPR Processor stop Status and Control
305bcef83a0SShreyas B. Prabhu  * Register (PSSCR) to control idle behavior.
306bcef83a0SShreyas B. Prabhu  *
307bcef83a0SShreyas B. Prabhu  * PSSCR layout:
308bcef83a0SShreyas B. Prabhu  * ----------------------------------------------------------
309bcef83a0SShreyas B. Prabhu  * | PLS | /// | SD | ESL | EC | PSLL | /// | TR | MTL | RL |
310bcef83a0SShreyas B. Prabhu  * ----------------------------------------------------------
311bcef83a0SShreyas B. Prabhu  * 0      4     41   42    43   44     48    54   56    60
312bcef83a0SShreyas B. Prabhu  *
313bcef83a0SShreyas B. Prabhu  * PSSCR key fields:
314bcef83a0SShreyas B. Prabhu  *	Bits 0:3  - Power-Saving Level Status (PLS). This field indicates the
315bcef83a0SShreyas B. Prabhu  *	lowest power-saving state the thread entered since stop instruction was
316bcef83a0SShreyas B. Prabhu  *	last executed.
317bcef83a0SShreyas B. Prabhu  *
318bcef83a0SShreyas B. Prabhu  *	Bit 41 - Status Disable(SD)
319bcef83a0SShreyas B. Prabhu  *	0 - Shows PLS entries
320bcef83a0SShreyas B. Prabhu  *	1 - PLS entries are all 0
321bcef83a0SShreyas B. Prabhu  *
322bcef83a0SShreyas B. Prabhu  *	Bit 42 - Enable State Loss
323bcef83a0SShreyas B. Prabhu  *	0 - No state is lost irrespective of other fields
324bcef83a0SShreyas B. Prabhu  *	1 - Allows state loss
325bcef83a0SShreyas B. Prabhu  *
326bcef83a0SShreyas B. Prabhu  *	Bit 43 - Exit Criterion
327bcef83a0SShreyas B. Prabhu  *	0 - Exit from power-save mode on any interrupt
328bcef83a0SShreyas B. Prabhu  *	1 - Exit from power-save mode controlled by LPCR's PECE bits
329bcef83a0SShreyas B. Prabhu  *
330bcef83a0SShreyas B. Prabhu  *	Bits 44:47 - Power-Saving Level Limit
331bcef83a0SShreyas B. Prabhu  *	This limits the power-saving level that can be entered into.
332bcef83a0SShreyas B. Prabhu  *
333bcef83a0SShreyas B. Prabhu  *	Bits 60:63 - Requested Level
334bcef83a0SShreyas B. Prabhu  *	Used to specify which power-saving level must be entered on executing
335bcef83a0SShreyas B. Prabhu  *	stop instruction
33609206b60SGautham R. Shenoy  */
33709206b60SGautham R. Shenoy 
33809206b60SGautham R. Shenoy int validate_psscr_val_mask(u64 *psscr_val, u64 *psscr_mask, u32 flags)
33909206b60SGautham R. Shenoy {
34009206b60SGautham R. Shenoy 	int err = 0;
34109206b60SGautham R. Shenoy 
34209206b60SGautham R. Shenoy 	/*
34309206b60SGautham R. Shenoy 	 * psscr_mask == 0xf indicates an older firmware.
34409206b60SGautham R. Shenoy 	 * Set remaining fields of psscr to the default values.
34509206b60SGautham R. Shenoy 	 * See NOTE above definition of PSSCR_HV_DEFAULT_VAL
34609206b60SGautham R. Shenoy 	 */
34709206b60SGautham R. Shenoy 	if (*psscr_mask == 0xf) {
34809206b60SGautham R. Shenoy 		*psscr_val = *psscr_val | PSSCR_HV_DEFAULT_VAL;
34909206b60SGautham R. Shenoy 		*psscr_mask = PSSCR_HV_DEFAULT_MASK;
35009206b60SGautham R. Shenoy 		return err;
35109206b60SGautham R. Shenoy 	}
35209206b60SGautham R. Shenoy 
35309206b60SGautham R. Shenoy 	/*
35409206b60SGautham R. Shenoy 	 * New firmware is expected to set the psscr_val bits correctly.
35509206b60SGautham R. Shenoy 	 * Validate that the following invariants are correctly maintained by
35609206b60SGautham R. Shenoy 	 * the new firmware.
35709206b60SGautham R. Shenoy 	 * - ESL bit value matches the EC bit value.
35809206b60SGautham R. Shenoy 	 * - ESL bit is set for all the deep stop states.
35909206b60SGautham R. Shenoy 	 */
36009206b60SGautham R. Shenoy 	if (GET_PSSCR_ESL(*psscr_val) != GET_PSSCR_EC(*psscr_val)) {
36109206b60SGautham R. Shenoy 		err = ERR_EC_ESL_MISMATCH;
36209206b60SGautham R. Shenoy 	} else if ((flags & OPAL_PM_LOSE_FULL_CONTEXT) &&
36309206b60SGautham R. Shenoy 		GET_PSSCR_ESL(*psscr_val) == 0) {
36409206b60SGautham R. Shenoy 		err = ERR_DEEP_STATE_ESL_MISMATCH;
36509206b60SGautham R. Shenoy 	}
36609206b60SGautham R. Shenoy 
36709206b60SGautham R. Shenoy 	return err;
36809206b60SGautham R. Shenoy }
36909206b60SGautham R. Shenoy 
37009206b60SGautham R. Shenoy /*
37109206b60SGautham R. Shenoy  * pnv_arch300_idle_init: Initializes the default idle state, first
37209206b60SGautham R. Shenoy  *                        deep idle state and deepest idle state on
37309206b60SGautham R. Shenoy  *                        ISA 3.0 CPUs.
374bcef83a0SShreyas B. Prabhu  *
375bcef83a0SShreyas B. Prabhu  * @np: /ibm,opal/power-mgt device node
376bcef83a0SShreyas B. Prabhu  * @flags: cpu-idle-state-flags array
377bcef83a0SShreyas B. Prabhu  * @dt_idle_states: Number of idle state entries
378bcef83a0SShreyas B. Prabhu  * Returns 0 on success
379bcef83a0SShreyas B. Prabhu  */
380dd34c74cSGautham R. Shenoy static int __init pnv_power9_idle_init(struct device_node *np, u32 *flags,
381bcef83a0SShreyas B. Prabhu 					int dt_idle_states)
382bcef83a0SShreyas B. Prabhu {
383bcef83a0SShreyas B. Prabhu 	u64 *psscr_val = NULL;
38409206b60SGautham R. Shenoy 	u64 *psscr_mask = NULL;
38509206b60SGautham R. Shenoy 	u32 *residency_ns = NULL;
38609206b60SGautham R. Shenoy 	u64 max_residency_ns = 0;
387bcef83a0SShreyas B. Prabhu 	int rc = 0, i;
38809206b60SGautham R. Shenoy 	bool default_stop_found = false, deepest_stop_found = false;
389bcef83a0SShreyas B. Prabhu 
39009206b60SGautham R. Shenoy 	psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val), GFP_KERNEL);
39109206b60SGautham R. Shenoy 	psscr_mask = kcalloc(dt_idle_states, sizeof(*psscr_mask), GFP_KERNEL);
39209206b60SGautham R. Shenoy 	residency_ns = kcalloc(dt_idle_states, sizeof(*residency_ns),
393bcef83a0SShreyas B. Prabhu 			       GFP_KERNEL);
39409206b60SGautham R. Shenoy 
39509206b60SGautham R. Shenoy 	if (!psscr_val || !psscr_mask || !residency_ns) {
396bcef83a0SShreyas B. Prabhu 		rc = -1;
397bcef83a0SShreyas B. Prabhu 		goto out;
398bcef83a0SShreyas B. Prabhu 	}
39909206b60SGautham R. Shenoy 
400bcef83a0SShreyas B. Prabhu 	if (of_property_read_u64_array(np,
401bcef83a0SShreyas B. Prabhu 		"ibm,cpu-idle-state-psscr",
402bcef83a0SShreyas B. Prabhu 		psscr_val, dt_idle_states)) {
40309206b60SGautham R. Shenoy 		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n");
40409206b60SGautham R. Shenoy 		rc = -1;
40509206b60SGautham R. Shenoy 		goto out;
40609206b60SGautham R. Shenoy 	}
40709206b60SGautham R. Shenoy 
40809206b60SGautham R. Shenoy 	if (of_property_read_u64_array(np,
40909206b60SGautham R. Shenoy 				       "ibm,cpu-idle-state-psscr-mask",
41009206b60SGautham R. Shenoy 				       psscr_mask, dt_idle_states)) {
41109206b60SGautham R. Shenoy 		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr-mask in DT\n");
41209206b60SGautham R. Shenoy 		rc = -1;
41309206b60SGautham R. Shenoy 		goto out;
41409206b60SGautham R. Shenoy 	}
41509206b60SGautham R. Shenoy 
41609206b60SGautham R. Shenoy 	if (of_property_read_u32_array(np,
41709206b60SGautham R. Shenoy 				       "ibm,cpu-idle-state-residency-ns",
41809206b60SGautham R. Shenoy 					residency_ns, dt_idle_states)) {
41909206b60SGautham R. Shenoy 		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-residency-ns in DT\n");
420bcef83a0SShreyas B. Prabhu 		rc = -1;
421bcef83a0SShreyas B. Prabhu 		goto out;
422bcef83a0SShreyas B. Prabhu 	}
423bcef83a0SShreyas B. Prabhu 
424bcef83a0SShreyas B. Prabhu 	/*
42509206b60SGautham R. Shenoy 	 * Set pnv_first_deep_stop_state, pnv_deepest_stop_psscr_{val,mask},
42609206b60SGautham R. Shenoy 	 * and the pnv_default_stop_{val,mask}.
42709206b60SGautham R. Shenoy 	 *
428c0691f9dSShreyas B. Prabhu 	 * pnv_first_deep_stop_state should be set to the first stop
429c0691f9dSShreyas B. Prabhu 	 * level to cause hypervisor state loss.
43009206b60SGautham R. Shenoy 	 *
43109206b60SGautham R. Shenoy 	 * pnv_deepest_stop_{val,mask} should be set to values corresponding to
43209206b60SGautham R. Shenoy 	 * the deepest stop state.
43309206b60SGautham R. Shenoy 	 *
43409206b60SGautham R. Shenoy 	 * pnv_default_stop_{val,mask} should be set to values corresponding to
43509206b60SGautham R. Shenoy 	 * the shallowest (OPAL_PM_STOP_INST_FAST) loss-less stop state.
436bcef83a0SShreyas B. Prabhu 	 */
437bcef83a0SShreyas B. Prabhu 	pnv_first_deep_stop_state = MAX_STOP_STATE;
438bcef83a0SShreyas B. Prabhu 	for (i = 0; i < dt_idle_states; i++) {
43909206b60SGautham R. Shenoy 		int err;
440bcef83a0SShreyas B. Prabhu 		u64 psscr_rl = psscr_val[i] & PSSCR_RL_MASK;
441bcef83a0SShreyas B. Prabhu 
442bcef83a0SShreyas B. Prabhu 		if ((flags[i] & OPAL_PM_LOSE_FULL_CONTEXT) &&
443bcef83a0SShreyas B. Prabhu 		     (pnv_first_deep_stop_state > psscr_rl))
444bcef83a0SShreyas B. Prabhu 			pnv_first_deep_stop_state = psscr_rl;
445c0691f9dSShreyas B. Prabhu 
44609206b60SGautham R. Shenoy 		err = validate_psscr_val_mask(&psscr_val[i], &psscr_mask[i],
44709206b60SGautham R. Shenoy 					      flags[i]);
44809206b60SGautham R. Shenoy 		if (err) {
44909206b60SGautham R. Shenoy 			report_invalid_psscr_val(psscr_val[i], err);
45009206b60SGautham R. Shenoy 			continue;
45109206b60SGautham R. Shenoy 		}
45209206b60SGautham R. Shenoy 
45309206b60SGautham R. Shenoy 		if (max_residency_ns < residency_ns[i]) {
45409206b60SGautham R. Shenoy 			max_residency_ns = residency_ns[i];
45509206b60SGautham R. Shenoy 			pnv_deepest_stop_psscr_val = psscr_val[i];
45609206b60SGautham R. Shenoy 			pnv_deepest_stop_psscr_mask = psscr_mask[i];
45709206b60SGautham R. Shenoy 			deepest_stop_found = true;
45809206b60SGautham R. Shenoy 		}
45909206b60SGautham R. Shenoy 
46009206b60SGautham R. Shenoy 		if (!default_stop_found &&
46109206b60SGautham R. Shenoy 		    (flags[i] & OPAL_PM_STOP_INST_FAST)) {
46209206b60SGautham R. Shenoy 			pnv_default_stop_val = psscr_val[i];
46309206b60SGautham R. Shenoy 			pnv_default_stop_mask = psscr_mask[i];
46409206b60SGautham R. Shenoy 			default_stop_found = true;
46509206b60SGautham R. Shenoy 		}
46609206b60SGautham R. Shenoy 	}
46709206b60SGautham R. Shenoy 
46809206b60SGautham R. Shenoy 	if (!default_stop_found) {
46909206b60SGautham R. Shenoy 		pnv_default_stop_val = PSSCR_HV_DEFAULT_VAL;
47009206b60SGautham R. Shenoy 		pnv_default_stop_mask = PSSCR_HV_DEFAULT_MASK;
47109206b60SGautham R. Shenoy 		pr_warn("Setting default stop psscr val=0x%016llx,mask=0x%016llx\n",
47209206b60SGautham R. Shenoy 			pnv_default_stop_val, pnv_default_stop_mask);
47309206b60SGautham R. Shenoy 	}
47409206b60SGautham R. Shenoy 
47509206b60SGautham R. Shenoy 	if (!deepest_stop_found) {
47609206b60SGautham R. Shenoy 		pnv_deepest_stop_psscr_val = PSSCR_HV_DEFAULT_VAL;
47709206b60SGautham R. Shenoy 		pnv_deepest_stop_psscr_mask = PSSCR_HV_DEFAULT_MASK;
47809206b60SGautham R. Shenoy 		pr_warn("Setting default stop psscr val=0x%016llx,mask=0x%016llx\n",
47909206b60SGautham R. Shenoy 			pnv_deepest_stop_psscr_val,
48009206b60SGautham R. Shenoy 			pnv_deepest_stop_psscr_mask);
481bcef83a0SShreyas B. Prabhu 	}
482bcef83a0SShreyas B. Prabhu 
483bcef83a0SShreyas B. Prabhu out:
484bcef83a0SShreyas B. Prabhu 	kfree(psscr_val);
48509206b60SGautham R. Shenoy 	kfree(psscr_mask);
48609206b60SGautham R. Shenoy 	kfree(residency_ns);
487bcef83a0SShreyas B. Prabhu 	return rc;
488bcef83a0SShreyas B. Prabhu }
489bcef83a0SShreyas B. Prabhu 
490bcef83a0SShreyas B. Prabhu /*
491bcef83a0SShreyas B. Prabhu  * Probe device tree for supported idle states
492bcef83a0SShreyas B. Prabhu  */
493bcef83a0SShreyas B. Prabhu static void __init pnv_probe_idle_states(void)
494bcef83a0SShreyas B. Prabhu {
495bcef83a0SShreyas B. Prabhu 	struct device_node *np;
496d405a98cSShreyas B. Prabhu 	int dt_idle_states;
497bcef83a0SShreyas B. Prabhu 	u32 *flags = NULL;
498d405a98cSShreyas B. Prabhu 	int i;
499d405a98cSShreyas B. Prabhu 
500bcef83a0SShreyas B. Prabhu 	np = of_find_node_by_path("/ibm,opal/power-mgt");
501bcef83a0SShreyas B. Prabhu 	if (!np) {
502d405a98cSShreyas B. Prabhu 		pr_warn("opal: PowerMgmt Node not found\n");
503d405a98cSShreyas B. Prabhu 		goto out;
504d405a98cSShreyas B. Prabhu 	}
505bcef83a0SShreyas B. Prabhu 	dt_idle_states = of_property_count_u32_elems(np,
506d405a98cSShreyas B. Prabhu 			"ibm,cpu-idle-state-flags");
507d405a98cSShreyas B. Prabhu 	if (dt_idle_states < 0) {
508d405a98cSShreyas B. Prabhu 		pr_warn("cpuidle-powernv: no idle states found in the DT\n");
509d405a98cSShreyas B. Prabhu 		goto out;
510d405a98cSShreyas B. Prabhu 	}
511d405a98cSShreyas B. Prabhu 
512bcef83a0SShreyas B. Prabhu 	flags = kcalloc(dt_idle_states, sizeof(*flags),  GFP_KERNEL);
513bcef83a0SShreyas B. Prabhu 
514bcef83a0SShreyas B. Prabhu 	if (of_property_read_u32_array(np,
515d405a98cSShreyas B. Prabhu 			"ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
516d405a98cSShreyas B. Prabhu 		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
517bcef83a0SShreyas B. Prabhu 		goto out;
518bcef83a0SShreyas B. Prabhu 	}
519bcef83a0SShreyas B. Prabhu 
520bcef83a0SShreyas B. Prabhu 	if (cpu_has_feature(CPU_FTR_ARCH_300)) {
521dd34c74cSGautham R. Shenoy 		if (pnv_power9_idle_init(np, flags, dt_idle_states))
522bcef83a0SShreyas B. Prabhu 			goto out;
523d405a98cSShreyas B. Prabhu 	}
524d405a98cSShreyas B. Prabhu 
525d405a98cSShreyas B. Prabhu 	for (i = 0; i < dt_idle_states; i++)
526d405a98cSShreyas B. Prabhu 		supported_cpuidle_states |= flags[i];
527d405a98cSShreyas B. Prabhu 
528bcef83a0SShreyas B. Prabhu out:
529bcef83a0SShreyas B. Prabhu 	kfree(flags);
530bcef83a0SShreyas B. Prabhu }
531bcef83a0SShreyas B. Prabhu static int __init pnv_init_idle_states(void)
532bcef83a0SShreyas B. Prabhu {
533bcef83a0SShreyas B. Prabhu 
534bcef83a0SShreyas B. Prabhu 	supported_cpuidle_states = 0;
535bcef83a0SShreyas B. Prabhu 
536bcef83a0SShreyas B. Prabhu 	if (cpuidle_disable != IDLE_NO_OVERRIDE)
537bcef83a0SShreyas B. Prabhu 		goto out;
538bcef83a0SShreyas B. Prabhu 
539bcef83a0SShreyas B. Prabhu 	pnv_probe_idle_states();
540bcef83a0SShreyas B. Prabhu 
541d405a98cSShreyas B. Prabhu 	if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
542d405a98cSShreyas B. Prabhu 		patch_instruction(
543d405a98cSShreyas B. Prabhu 			(unsigned int *)pnv_fastsleep_workaround_at_entry,
544d405a98cSShreyas B. Prabhu 			PPC_INST_NOP);
545d405a98cSShreyas B. Prabhu 		patch_instruction(
546d405a98cSShreyas B. Prabhu 			(unsigned int *)pnv_fastsleep_workaround_at_exit,
547d405a98cSShreyas B. Prabhu 			PPC_INST_NOP);
5485703d2f4SShreyas B. Prabhu 	} else {
5495703d2f4SShreyas B. Prabhu 		/*
5505703d2f4SShreyas B. Prabhu 		 * OPAL_PM_SLEEP_ENABLED_ER1 is set. It indicates that
5515703d2f4SShreyas B. Prabhu 		 * workaround is needed to use fastsleep. Provide sysfs
5525703d2f4SShreyas B. Prabhu 		 * control to choose how this workaround has to be applied.
5535703d2f4SShreyas B. Prabhu 		 */
5545703d2f4SShreyas B. Prabhu 		device_create_file(cpu_subsys.dev_root,
5555703d2f4SShreyas B. Prabhu 				&dev_attr_fastsleep_workaround_applyonce);
556d405a98cSShreyas B. Prabhu 	}
5575703d2f4SShreyas B. Prabhu 
558d405a98cSShreyas B. Prabhu 	pnv_alloc_idle_core_states();
5595593e303SShreyas B. Prabhu 
5605593e303SShreyas B. Prabhu 	if (supported_cpuidle_states & OPAL_PM_NAP_ENABLED)
5615593e303SShreyas B. Prabhu 		ppc_md.power_save = power7_idle;
562bcef83a0SShreyas B. Prabhu 	else if (supported_cpuidle_states & OPAL_PM_STOP_INST_FAST)
563bcef83a0SShreyas B. Prabhu 		ppc_md.power_save = power9_idle;
564bcef83a0SShreyas B. Prabhu 
565d405a98cSShreyas B. Prabhu out:
566d405a98cSShreyas B. Prabhu 	return 0;
567d405a98cSShreyas B. Prabhu }
5684bece972SMichael Ellerman machine_subsys_initcall(powernv, pnv_init_idle_states);
569