12c2e6ecfSDeepthi Dharwar /* 22c2e6ecfSDeepthi Dharwar * cpuidle-powernv - idle state cpuidle driver. 32c2e6ecfSDeepthi Dharwar * Adapted from drivers/cpuidle/cpuidle-pseries 42c2e6ecfSDeepthi Dharwar * 52c2e6ecfSDeepthi Dharwar */ 62c2e6ecfSDeepthi Dharwar 72c2e6ecfSDeepthi Dharwar #include <linux/kernel.h> 82c2e6ecfSDeepthi Dharwar #include <linux/module.h> 92c2e6ecfSDeepthi Dharwar #include <linux/init.h> 102c2e6ecfSDeepthi Dharwar #include <linux/moduleparam.h> 112c2e6ecfSDeepthi Dharwar #include <linux/cpuidle.h> 122c2e6ecfSDeepthi Dharwar #include <linux/cpu.h> 132c2e6ecfSDeepthi Dharwar #include <linux/notifier.h> 140d948730SPreeti U Murthy #include <linux/clockchips.h> 150888839cSPreeti U Murthy #include <linux/of.h> 1692c83ff5SPreeti U Murthy #include <linux/slab.h> 172c2e6ecfSDeepthi Dharwar 182c2e6ecfSDeepthi Dharwar #include <asm/machdep.h> 192c2e6ecfSDeepthi Dharwar #include <asm/firmware.h> 208eb8ac89SShreyas B. Prabhu #include <asm/opal.h> 21591ac0cbSNicolas Pitre #include <asm/runlatch.h> 2209206b60SGautham R. Shenoy #include <asm/cpuidle.h> 232c2e6ecfSDeepthi Dharwar 249e9fc6f0SGautham R. Shenoy /* 259e9fc6f0SGautham R. Shenoy * Expose only those Hardware idle states via the cpuidle framework 269e9fc6f0SGautham R. Shenoy * that have latency value below POWERNV_THRESHOLD_LATENCY_NS. 279e9fc6f0SGautham R. Shenoy */ 283005c597SShreyas B. Prabhu #define POWERNV_THRESHOLD_LATENCY_NS 200000 293005c597SShreyas B. Prabhu 30ed61390bSAndrew Donnellan static struct cpuidle_driver powernv_idle_driver = { 312c2e6ecfSDeepthi Dharwar .name = "powernv_idle", 322c2e6ecfSDeepthi Dharwar .owner = THIS_MODULE, 332c2e6ecfSDeepthi Dharwar }; 342c2e6ecfSDeepthi Dharwar 35624e46d0SNicholas Piggin static int max_idle_state __read_mostly; 36624e46d0SNicholas Piggin static struct cpuidle_state *cpuidle_state_table __read_mostly; 373005c597SShreyas B. Prabhu 3809206b60SGautham R. Shenoy struct stop_psscr_table { 3909206b60SGautham R. Shenoy u64 val; 4009206b60SGautham R. Shenoy u64 mask; 4109206b60SGautham R. Shenoy }; 4209206b60SGautham R. Shenoy 43624e46d0SNicholas Piggin static struct stop_psscr_table stop_psscr_table[CPUIDLE_STATE_MAX] __read_mostly; 443005c597SShreyas B. Prabhu 45624e46d0SNicholas Piggin static u64 snooze_timeout __read_mostly; 46624e46d0SNicholas Piggin static bool snooze_timeout_en __read_mostly; 472c2e6ecfSDeepthi Dharwar 482c2e6ecfSDeepthi Dharwar static int snooze_loop(struct cpuidle_device *dev, 492c2e6ecfSDeepthi Dharwar struct cpuidle_driver *drv, 502c2e6ecfSDeepthi Dharwar int index) 512c2e6ecfSDeepthi Dharwar { 5278eaa10fSShilpasri G Bhat u64 snooze_exit_time; 5378eaa10fSShilpasri G Bhat 542c2e6ecfSDeepthi Dharwar set_thread_flag(TIF_POLLING_NRFLAG); 552c2e6ecfSDeepthi Dharwar 563fc5ee92SNicholas Piggin local_irq_enable(); 573fc5ee92SNicholas Piggin 5878eaa10fSShilpasri G Bhat snooze_exit_time = get_tb() + snooze_timeout; 59591ac0cbSNicolas Pitre ppc64_runlatch_off(); 602c2e6ecfSDeepthi Dharwar HMT_very_low(); 6126eb48a9SAnton Blanchard while (!need_resched()) { 620baa91cbSAnton Blanchard if (likely(snooze_timeout_en) && get_tb() > snooze_exit_time) 6378eaa10fSShilpasri G Bhat break; 642c2e6ecfSDeepthi Dharwar } 652c2e6ecfSDeepthi Dharwar 662c2e6ecfSDeepthi Dharwar HMT_medium(); 67591ac0cbSNicolas Pitre ppc64_runlatch_on(); 682c2e6ecfSDeepthi Dharwar clear_thread_flag(TIF_POLLING_NRFLAG); 692c2e6ecfSDeepthi Dharwar smp_mb(); 703fc5ee92SNicholas Piggin 712c2e6ecfSDeepthi Dharwar return index; 722c2e6ecfSDeepthi Dharwar } 732c2e6ecfSDeepthi Dharwar 742c2e6ecfSDeepthi Dharwar static int nap_loop(struct cpuidle_device *dev, 752c2e6ecfSDeepthi Dharwar struct cpuidle_driver *drv, 762c2e6ecfSDeepthi Dharwar int index) 772c2e6ecfSDeepthi Dharwar { 782201f994SNicholas Piggin power7_idle_type(PNV_THREAD_NAP); 792201f994SNicholas Piggin 802c2e6ecfSDeepthi Dharwar return index; 812c2e6ecfSDeepthi Dharwar } 822c2e6ecfSDeepthi Dharwar 83cc5a2f7bSpreeti /* Register for fastsleep only in oneshot mode of broadcast */ 84cc5a2f7bSpreeti #ifdef CONFIG_TICK_ONESHOT 850d948730SPreeti U Murthy static int fastsleep_loop(struct cpuidle_device *dev, 860d948730SPreeti U Murthy struct cpuidle_driver *drv, 870d948730SPreeti U Murthy int index) 880d948730SPreeti U Murthy { 890d948730SPreeti U Murthy unsigned long old_lpcr = mfspr(SPRN_LPCR); 900d948730SPreeti U Murthy unsigned long new_lpcr; 910d948730SPreeti U Murthy 920d948730SPreeti U Murthy if (unlikely(system_state < SYSTEM_RUNNING)) 930d948730SPreeti U Murthy return index; 940d948730SPreeti U Murthy 950d948730SPreeti U Murthy new_lpcr = old_lpcr; 969b6a68d9SMichael Neuling /* Do not exit powersave upon decrementer as we've setup the timer 979b6a68d9SMichael Neuling * offload. 980d948730SPreeti U Murthy */ 999b6a68d9SMichael Neuling new_lpcr &= ~LPCR_PECE1; 1000d948730SPreeti U Murthy 1010d948730SPreeti U Murthy mtspr(SPRN_LPCR, new_lpcr); 1022201f994SNicholas Piggin 1032201f994SNicholas Piggin power7_idle_type(PNV_THREAD_SLEEP); 1040d948730SPreeti U Murthy 1050d948730SPreeti U Murthy mtspr(SPRN_LPCR, old_lpcr); 1060d948730SPreeti U Murthy 1070d948730SPreeti U Murthy return index; 1080d948730SPreeti U Murthy } 109cc5a2f7bSpreeti #endif 1103005c597SShreyas B. Prabhu 1113005c597SShreyas B. Prabhu static int stop_loop(struct cpuidle_device *dev, 1123005c597SShreyas B. Prabhu struct cpuidle_driver *drv, 1133005c597SShreyas B. Prabhu int index) 1143005c597SShreyas B. Prabhu { 1152201f994SNicholas Piggin power9_idle_type(stop_psscr_table[index].val, 11609206b60SGautham R. Shenoy stop_psscr_table[index].mask); 1173005c597SShreyas B. Prabhu return index; 1183005c597SShreyas B. Prabhu } 1193005c597SShreyas B. Prabhu 1202c2e6ecfSDeepthi Dharwar /* 1212c2e6ecfSDeepthi Dharwar * States for dedicated partition case. 1222c2e6ecfSDeepthi Dharwar */ 123169f3faeSShreyas B. Prabhu static struct cpuidle_state powernv_states[CPUIDLE_STATE_MAX] = { 1242c2e6ecfSDeepthi Dharwar { /* Snooze */ 1252c2e6ecfSDeepthi Dharwar .name = "snooze", 1262c2e6ecfSDeepthi Dharwar .desc = "snooze", 1272c2e6ecfSDeepthi Dharwar .exit_latency = 0, 1282c2e6ecfSDeepthi Dharwar .target_residency = 0, 129957efcedSShreyas B. Prabhu .enter = snooze_loop }, 1302c2e6ecfSDeepthi Dharwar }; 1312c2e6ecfSDeepthi Dharwar 13210fcca9dSSebastian Andrzej Siewior static int powernv_cpuidle_cpu_online(unsigned int cpu) 1332c2e6ecfSDeepthi Dharwar { 13410fcca9dSSebastian Andrzej Siewior struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); 1352c2e6ecfSDeepthi Dharwar 1362c2e6ecfSDeepthi Dharwar if (dev && cpuidle_get_driver()) { 1372c2e6ecfSDeepthi Dharwar cpuidle_pause_and_lock(); 1382c2e6ecfSDeepthi Dharwar cpuidle_enable_device(dev); 1392c2e6ecfSDeepthi Dharwar cpuidle_resume_and_unlock(); 14010fcca9dSSebastian Andrzej Siewior } 14110fcca9dSSebastian Andrzej Siewior return 0; 14210fcca9dSSebastian Andrzej Siewior } 1432c2e6ecfSDeepthi Dharwar 14410fcca9dSSebastian Andrzej Siewior static int powernv_cpuidle_cpu_dead(unsigned int cpu) 14510fcca9dSSebastian Andrzej Siewior { 14610fcca9dSSebastian Andrzej Siewior struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); 14710fcca9dSSebastian Andrzej Siewior 14810fcca9dSSebastian Andrzej Siewior if (dev && cpuidle_get_driver()) { 1492c2e6ecfSDeepthi Dharwar cpuidle_pause_and_lock(); 1502c2e6ecfSDeepthi Dharwar cpuidle_disable_device(dev); 1512c2e6ecfSDeepthi Dharwar cpuidle_resume_and_unlock(); 1522c2e6ecfSDeepthi Dharwar } 15310fcca9dSSebastian Andrzej Siewior return 0; 1542c2e6ecfSDeepthi Dharwar } 1552c2e6ecfSDeepthi Dharwar 1562c2e6ecfSDeepthi Dharwar /* 1572c2e6ecfSDeepthi Dharwar * powernv_cpuidle_driver_init() 1582c2e6ecfSDeepthi Dharwar */ 1592c2e6ecfSDeepthi Dharwar static int powernv_cpuidle_driver_init(void) 1602c2e6ecfSDeepthi Dharwar { 1612c2e6ecfSDeepthi Dharwar int idle_state; 1622c2e6ecfSDeepthi Dharwar struct cpuidle_driver *drv = &powernv_idle_driver; 1632c2e6ecfSDeepthi Dharwar 1642c2e6ecfSDeepthi Dharwar drv->state_count = 0; 1652c2e6ecfSDeepthi Dharwar 1662c2e6ecfSDeepthi Dharwar for (idle_state = 0; idle_state < max_idle_state; ++idle_state) { 1672c2e6ecfSDeepthi Dharwar /* Is the state not enabled? */ 1682c2e6ecfSDeepthi Dharwar if (cpuidle_state_table[idle_state].enter == NULL) 1692c2e6ecfSDeepthi Dharwar continue; 1702c2e6ecfSDeepthi Dharwar 1712c2e6ecfSDeepthi Dharwar drv->states[drv->state_count] = /* structure copy */ 1722c2e6ecfSDeepthi Dharwar cpuidle_state_table[idle_state]; 1732c2e6ecfSDeepthi Dharwar 1742c2e6ecfSDeepthi Dharwar drv->state_count += 1; 1752c2e6ecfSDeepthi Dharwar } 1762c2e6ecfSDeepthi Dharwar 177293d264fSVaidyanathan Srinivasan /* 178293d264fSVaidyanathan Srinivasan * On the PowerNV platform cpu_present may be less than cpu_possible in 179293d264fSVaidyanathan Srinivasan * cases when firmware detects the CPU, but it is not available to the 180293d264fSVaidyanathan Srinivasan * OS. If CONFIG_HOTPLUG_CPU=n, then such CPUs are not hotplugable at 181293d264fSVaidyanathan Srinivasan * run time and hence cpu_devices are not created for those CPUs by the 182293d264fSVaidyanathan Srinivasan * generic topology_init(). 183293d264fSVaidyanathan Srinivasan * 184293d264fSVaidyanathan Srinivasan * drv->cpumask defaults to cpu_possible_mask in 185293d264fSVaidyanathan Srinivasan * __cpuidle_driver_init(). This breaks cpuidle on PowerNV where 186293d264fSVaidyanathan Srinivasan * cpu_devices are not created for CPUs in cpu_possible_mask that 187293d264fSVaidyanathan Srinivasan * cannot be hot-added later at run time. 188293d264fSVaidyanathan Srinivasan * 189293d264fSVaidyanathan Srinivasan * Trying cpuidle_register_device() on a CPU without a cpu_device is 190293d264fSVaidyanathan Srinivasan * incorrect, so pass a correct CPU mask to the generic cpuidle driver. 191293d264fSVaidyanathan Srinivasan */ 192293d264fSVaidyanathan Srinivasan 193293d264fSVaidyanathan Srinivasan drv->cpumask = (struct cpumask *)cpu_present_mask; 194293d264fSVaidyanathan Srinivasan 1952c2e6ecfSDeepthi Dharwar return 0; 1962c2e6ecfSDeepthi Dharwar } 1972c2e6ecfSDeepthi Dharwar 1989e9fc6f0SGautham R. Shenoy static inline void add_powernv_state(int index, const char *name, 1999e9fc6f0SGautham R. Shenoy unsigned int flags, 2009e9fc6f0SGautham R. Shenoy int (*idle_fn)(struct cpuidle_device *, 2019e9fc6f0SGautham R. Shenoy struct cpuidle_driver *, 2029e9fc6f0SGautham R. Shenoy int), 2039e9fc6f0SGautham R. Shenoy unsigned int target_residency, 2049e9fc6f0SGautham R. Shenoy unsigned int exit_latency, 20509206b60SGautham R. Shenoy u64 psscr_val, u64 psscr_mask) 2069e9fc6f0SGautham R. Shenoy { 2079e9fc6f0SGautham R. Shenoy strlcpy(powernv_states[index].name, name, CPUIDLE_NAME_LEN); 2089e9fc6f0SGautham R. Shenoy strlcpy(powernv_states[index].desc, name, CPUIDLE_NAME_LEN); 2099e9fc6f0SGautham R. Shenoy powernv_states[index].flags = flags; 2109e9fc6f0SGautham R. Shenoy powernv_states[index].target_residency = target_residency; 2119e9fc6f0SGautham R. Shenoy powernv_states[index].exit_latency = exit_latency; 2129e9fc6f0SGautham R. Shenoy powernv_states[index].enter = idle_fn; 21309206b60SGautham R. Shenoy stop_psscr_table[index].val = psscr_val; 21409206b60SGautham R. Shenoy stop_psscr_table[index].mask = psscr_mask; 2159e9fc6f0SGautham R. Shenoy } 2169e9fc6f0SGautham R. Shenoy 217ecad4502SGautham R. Shenoy /* 218ecad4502SGautham R. Shenoy * Returns 0 if prop1_len == prop2_len. Else returns -1 219ecad4502SGautham R. Shenoy */ 220ecad4502SGautham R. Shenoy static inline int validate_dt_prop_sizes(const char *prop1, int prop1_len, 221ecad4502SGautham R. Shenoy const char *prop2, int prop2_len) 222ecad4502SGautham R. Shenoy { 223ecad4502SGautham R. Shenoy if (prop1_len == prop2_len) 224ecad4502SGautham R. Shenoy return 0; 225ecad4502SGautham R. Shenoy 226ecad4502SGautham R. Shenoy pr_warn("cpuidle-powernv: array sizes don't match for %s and %s\n", 227ecad4502SGautham R. Shenoy prop1, prop2); 228ecad4502SGautham R. Shenoy return -1; 229ecad4502SGautham R. Shenoy } 230ecad4502SGautham R. Shenoy 2310888839cSPreeti U Murthy static int powernv_add_idle_states(void) 2320888839cSPreeti U Murthy { 2330888839cSPreeti U Murthy struct device_node *power_mgt; 2340888839cSPreeti U Murthy int nr_idle_states = 1; /* Snooze */ 235ecad4502SGautham R. Shenoy int dt_idle_states, count; 236957efcedSShreyas B. Prabhu u32 latency_ns[CPUIDLE_STATE_MAX]; 237957efcedSShreyas B. Prabhu u32 residency_ns[CPUIDLE_STATE_MAX]; 238957efcedSShreyas B. Prabhu u32 flags[CPUIDLE_STATE_MAX]; 2393005c597SShreyas B. Prabhu u64 psscr_val[CPUIDLE_STATE_MAX]; 24009206b60SGautham R. Shenoy u64 psscr_mask[CPUIDLE_STATE_MAX]; 2413005c597SShreyas B. Prabhu const char *names[CPUIDLE_STATE_MAX]; 24209206b60SGautham R. Shenoy u32 has_stop_states = 0; 24392c83ff5SPreeti U Murthy int i, rc; 2440888839cSPreeti U Murthy 2450888839cSPreeti U Murthy /* Currently we have snooze statically defined */ 2460888839cSPreeti U Murthy 2470888839cSPreeti U Murthy power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); 2480888839cSPreeti U Murthy if (!power_mgt) { 2490888839cSPreeti U Murthy pr_warn("opal: PowerMgmt Node not found\n"); 25092c83ff5SPreeti U Murthy goto out; 2510888839cSPreeti U Murthy } 2520888839cSPreeti U Murthy 25370734a78SPreeti U Murthy /* Read values of any property to determine the num of idle states */ 25470734a78SPreeti U Murthy dt_idle_states = of_property_count_u32_elems(power_mgt, "ibm,cpu-idle-state-flags"); 25570734a78SPreeti U Murthy if (dt_idle_states < 0) { 25670734a78SPreeti U Murthy pr_warn("cpuidle-powernv: no idle states found in the DT\n"); 25792c83ff5SPreeti U Murthy goto out; 25874aa51b5SPreeti U. Murthy } 25974aa51b5SPreeti U. Murthy 260ecad4502SGautham R. Shenoy count = of_property_count_u32_elems(power_mgt, 261ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-latencies-ns"); 262ecad4502SGautham R. Shenoy 263ecad4502SGautham R. Shenoy if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", dt_idle_states, 264ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-latencies-ns", 265ecad4502SGautham R. Shenoy count) != 0) 266ecad4502SGautham R. Shenoy goto out; 267ecad4502SGautham R. Shenoy 268ecad4502SGautham R. Shenoy count = of_property_count_strings(power_mgt, 269ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-names"); 270ecad4502SGautham R. Shenoy if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", dt_idle_states, 271ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-names", 272ecad4502SGautham R. Shenoy count) != 0) 273ecad4502SGautham R. Shenoy goto out; 274ecad4502SGautham R. Shenoy 275957efcedSShreyas B. Prabhu /* 276957efcedSShreyas B. Prabhu * Since snooze is used as first idle state, max idle states allowed is 277957efcedSShreyas B. Prabhu * CPUIDLE_STATE_MAX -1 278957efcedSShreyas B. Prabhu */ 279957efcedSShreyas B. Prabhu if (dt_idle_states > CPUIDLE_STATE_MAX - 1) { 280957efcedSShreyas B. Prabhu pr_warn("cpuidle-powernv: discovered idle states more than allowed"); 281957efcedSShreyas B. Prabhu dt_idle_states = CPUIDLE_STATE_MAX - 1; 282957efcedSShreyas B. Prabhu } 283957efcedSShreyas B. Prabhu 28470734a78SPreeti U Murthy if (of_property_read_u32_array(power_mgt, 28570734a78SPreeti U Murthy "ibm,cpu-idle-state-flags", flags, dt_idle_states)) { 28670734a78SPreeti U Murthy pr_warn("cpuidle-powernv : missing ibm,cpu-idle-state-flags in DT\n"); 287957efcedSShreyas B. Prabhu goto out; 28870734a78SPreeti U Murthy } 2890888839cSPreeti U Murthy 290957efcedSShreyas B. Prabhu if (of_property_read_u32_array(power_mgt, 291957efcedSShreyas B. Prabhu "ibm,cpu-idle-state-latencies-ns", latency_ns, 292957efcedSShreyas B. Prabhu dt_idle_states)) { 29392c83ff5SPreeti U Murthy pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n"); 294957efcedSShreyas B. Prabhu goto out; 29592c83ff5SPreeti U Murthy } 2963005c597SShreyas B. Prabhu if (of_property_read_string_array(power_mgt, 2973005c597SShreyas B. Prabhu "ibm,cpu-idle-state-names", names, dt_idle_states) < 0) { 2983005c597SShreyas B. Prabhu pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-names in DT\n"); 2993005c597SShreyas B. Prabhu goto out; 3003005c597SShreyas B. Prabhu } 3013005c597SShreyas B. Prabhu 3023005c597SShreyas B. Prabhu /* 3033005c597SShreyas B. Prabhu * If the idle states use stop instruction, probe for psscr values 30409206b60SGautham R. Shenoy * and psscr mask which are necessary to specify required stop level. 3053005c597SShreyas B. Prabhu */ 30609206b60SGautham R. Shenoy has_stop_states = (flags[0] & 30709206b60SGautham R. Shenoy (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP)); 30809206b60SGautham R. Shenoy if (has_stop_states) { 309ecad4502SGautham R. Shenoy count = of_property_count_u64_elems(power_mgt, 310ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-psscr"); 311ecad4502SGautham R. Shenoy if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", 312ecad4502SGautham R. Shenoy dt_idle_states, 313ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-psscr", 314ecad4502SGautham R. Shenoy count) != 0) 315ecad4502SGautham R. Shenoy goto out; 316ecad4502SGautham R. Shenoy 317ecad4502SGautham R. Shenoy count = of_property_count_u64_elems(power_mgt, 318ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-psscr-mask"); 319ecad4502SGautham R. Shenoy if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", 320ecad4502SGautham R. Shenoy dt_idle_states, 321ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-psscr-mask", 322ecad4502SGautham R. Shenoy count) != 0) 323ecad4502SGautham R. Shenoy goto out; 324ecad4502SGautham R. Shenoy 3253005c597SShreyas B. Prabhu if (of_property_read_u64_array(power_mgt, 3263005c597SShreyas B. Prabhu "ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) { 32709206b60SGautham R. Shenoy pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n"); 3283005c597SShreyas B. Prabhu goto out; 3293005c597SShreyas B. Prabhu } 33092c83ff5SPreeti U Murthy 33109206b60SGautham R. Shenoy if (of_property_read_u64_array(power_mgt, 33209206b60SGautham R. Shenoy "ibm,cpu-idle-state-psscr-mask", 33309206b60SGautham R. Shenoy psscr_mask, dt_idle_states)) { 33409206b60SGautham R. Shenoy pr_warn("cpuidle-powernv:Missing ibm,cpu-idle-state-psscr-mask in DT\n"); 33509206b60SGautham R. Shenoy goto out; 33609206b60SGautham R. Shenoy } 33709206b60SGautham R. Shenoy } 33809206b60SGautham R. Shenoy 339ecad4502SGautham R. Shenoy count = of_property_count_u32_elems(power_mgt, 340ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-residency-ns"); 341ecad4502SGautham R. Shenoy 342ecad4502SGautham R. Shenoy if (count < 0) { 343ecad4502SGautham R. Shenoy rc = count; 344ecad4502SGautham R. Shenoy } else if (validate_dt_prop_sizes("ibm,cpu-idle-state-flags", 345ecad4502SGautham R. Shenoy dt_idle_states, 346ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-residency-ns", 347ecad4502SGautham R. Shenoy count) != 0) { 348ecad4502SGautham R. Shenoy goto out; 349ecad4502SGautham R. Shenoy } else { 35092c83ff5SPreeti U Murthy rc = of_property_read_u32_array(power_mgt, 351ecad4502SGautham R. Shenoy "ibm,cpu-idle-state-residency-ns", 352ecad4502SGautham R. Shenoy residency_ns, dt_idle_states); 353ecad4502SGautham R. Shenoy } 35492c83ff5SPreeti U Murthy 3550888839cSPreeti U Murthy for (i = 0; i < dt_idle_states; i++) { 3569e9fc6f0SGautham R. Shenoy unsigned int exit_latency, target_residency; 357f9122ee4SGautham R. Shenoy bool stops_timebase = false; 3583005c597SShreyas B. Prabhu /* 3593005c597SShreyas B. Prabhu * If an idle state has exit latency beyond 3603005c597SShreyas B. Prabhu * POWERNV_THRESHOLD_LATENCY_NS then don't use it 3613005c597SShreyas B. Prabhu * in cpu-idle. 3623005c597SShreyas B. Prabhu */ 3633005c597SShreyas B. Prabhu if (latency_ns[i] > POWERNV_THRESHOLD_LATENCY_NS) 3643005c597SShreyas B. Prabhu continue; 3659e9fc6f0SGautham R. Shenoy /* 3669e9fc6f0SGautham R. Shenoy * Firmware passes residency and latency values in ns. 3679e9fc6f0SGautham R. Shenoy * cpuidle expects it in us. 3689e9fc6f0SGautham R. Shenoy */ 3699e9fc6f0SGautham R. Shenoy exit_latency = latency_ns[i] / 1000; 3709e9fc6f0SGautham R. Shenoy if (!rc) 3719e9fc6f0SGautham R. Shenoy target_residency = residency_ns[i] / 1000; 3729e9fc6f0SGautham R. Shenoy else 3739e9fc6f0SGautham R. Shenoy target_residency = 0; 3740888839cSPreeti U Murthy 37509206b60SGautham R. Shenoy if (has_stop_states) { 37609206b60SGautham R. Shenoy int err = validate_psscr_val_mask(&psscr_val[i], 37709206b60SGautham R. Shenoy &psscr_mask[i], 37809206b60SGautham R. Shenoy flags[i]); 37909206b60SGautham R. Shenoy if (err) { 38009206b60SGautham R. Shenoy report_invalid_psscr_val(psscr_val[i], err); 38109206b60SGautham R. Shenoy continue; 38209206b60SGautham R. Shenoy } 38309206b60SGautham R. Shenoy } 38409206b60SGautham R. Shenoy 385f9122ee4SGautham R. Shenoy if (flags[i] & OPAL_PM_TIMEBASE_STOP) 386f9122ee4SGautham R. Shenoy stops_timebase = true; 387f9122ee4SGautham R. Shenoy 38892c83ff5SPreeti U Murthy /* 3899e9fc6f0SGautham R. Shenoy * For nap and fastsleep, use default target_residency 3909e9fc6f0SGautham R. Shenoy * values if f/w does not expose it. 39174aa51b5SPreeti U. Murthy */ 39270734a78SPreeti U Murthy if (flags[i] & OPAL_PM_NAP_ENABLED) { 3939e9fc6f0SGautham R. Shenoy if (!rc) 3949e9fc6f0SGautham R. Shenoy target_residency = 100; 3950888839cSPreeti U Murthy /* Add NAP state */ 3969e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, "Nap", 3979e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_NONE, nap_loop, 39809206b60SGautham R. Shenoy target_residency, exit_latency, 0, 0); 399f9122ee4SGautham R. Shenoy } else if (has_stop_states && !stops_timebase) { 4009e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, names[i], 4019e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_NONE, stop_loop, 4029e9fc6f0SGautham R. Shenoy target_residency, exit_latency, 40309206b60SGautham R. Shenoy psscr_val[i], psscr_mask[i]); 404cc5a2f7bSpreeti } 405cc5a2f7bSpreeti 406cc5a2f7bSpreeti /* 407cc5a2f7bSpreeti * All cpuidle states with CPUIDLE_FLAG_TIMER_STOP set must come 408cc5a2f7bSpreeti * within this config dependency check. 409cc5a2f7bSpreeti */ 410cc5a2f7bSpreeti #ifdef CONFIG_TICK_ONESHOT 411f9122ee4SGautham R. Shenoy else if (flags[i] & OPAL_PM_SLEEP_ENABLED || 41270734a78SPreeti U Murthy flags[i] & OPAL_PM_SLEEP_ENABLED_ER1) { 4139e9fc6f0SGautham R. Shenoy if (!rc) 4149e9fc6f0SGautham R. Shenoy target_residency = 300000; 4150888839cSPreeti U Murthy /* Add FASTSLEEP state */ 4169e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, "FastSleep", 4179e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_TIMER_STOP, 4189e9fc6f0SGautham R. Shenoy fastsleep_loop, 41909206b60SGautham R. Shenoy target_residency, exit_latency, 0, 0); 420f9122ee4SGautham R. Shenoy } else if (has_stop_states && stops_timebase) { 4219e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, names[i], 4229e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_TIMER_STOP, stop_loop, 4239e9fc6f0SGautham R. Shenoy target_residency, exit_latency, 42409206b60SGautham R. Shenoy psscr_val[i], psscr_mask[i]); 4250888839cSPreeti U Murthy } 426cc5a2f7bSpreeti #endif 427f9122ee4SGautham R. Shenoy else 428f9122ee4SGautham R. Shenoy continue; 42992c83ff5SPreeti U Murthy nr_idle_states++; 43092c83ff5SPreeti U Murthy } 43192c83ff5SPreeti U Murthy out: 4320888839cSPreeti U Murthy return nr_idle_states; 4330888839cSPreeti U Murthy } 4340888839cSPreeti U Murthy 4352c2e6ecfSDeepthi Dharwar /* 4362c2e6ecfSDeepthi Dharwar * powernv_idle_probe() 4372c2e6ecfSDeepthi Dharwar * Choose state table for shared versus dedicated partition 4382c2e6ecfSDeepthi Dharwar */ 4392c2e6ecfSDeepthi Dharwar static int powernv_idle_probe(void) 4402c2e6ecfSDeepthi Dharwar { 4412c2e6ecfSDeepthi Dharwar if (cpuidle_disable != IDLE_NO_OVERRIDE) 4422c2e6ecfSDeepthi Dharwar return -ENODEV; 4432c2e6ecfSDeepthi Dharwar 444e4d54f71SStewart Smith if (firmware_has_feature(FW_FEATURE_OPAL)) { 4452c2e6ecfSDeepthi Dharwar cpuidle_state_table = powernv_states; 4460888839cSPreeti U Murthy /* Device tree can indicate more idle states */ 4470888839cSPreeti U Murthy max_idle_state = powernv_add_idle_states(); 44878eaa10fSShilpasri G Bhat if (max_idle_state > 1) { 44978eaa10fSShilpasri G Bhat snooze_timeout_en = true; 45078eaa10fSShilpasri G Bhat snooze_timeout = powernv_states[1].target_residency * 45178eaa10fSShilpasri G Bhat tb_ticks_per_usec; 45278eaa10fSShilpasri G Bhat } 4532c2e6ecfSDeepthi Dharwar } else 4542c2e6ecfSDeepthi Dharwar return -ENODEV; 4552c2e6ecfSDeepthi Dharwar 4562c2e6ecfSDeepthi Dharwar return 0; 4572c2e6ecfSDeepthi Dharwar } 4582c2e6ecfSDeepthi Dharwar 4592c2e6ecfSDeepthi Dharwar static int __init powernv_processor_idle_init(void) 4602c2e6ecfSDeepthi Dharwar { 4612c2e6ecfSDeepthi Dharwar int retval; 4622c2e6ecfSDeepthi Dharwar 4632c2e6ecfSDeepthi Dharwar retval = powernv_idle_probe(); 4642c2e6ecfSDeepthi Dharwar if (retval) 4652c2e6ecfSDeepthi Dharwar return retval; 4662c2e6ecfSDeepthi Dharwar 4672c2e6ecfSDeepthi Dharwar powernv_cpuidle_driver_init(); 4682c2e6ecfSDeepthi Dharwar retval = cpuidle_register(&powernv_idle_driver, NULL); 4692c2e6ecfSDeepthi Dharwar if (retval) { 4702c2e6ecfSDeepthi Dharwar printk(KERN_DEBUG "Registration of powernv driver failed.\n"); 4712c2e6ecfSDeepthi Dharwar return retval; 4722c2e6ecfSDeepthi Dharwar } 4732c2e6ecfSDeepthi Dharwar 47410fcca9dSSebastian Andrzej Siewior retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, 47510fcca9dSSebastian Andrzej Siewior "cpuidle/powernv:online", 47610fcca9dSSebastian Andrzej Siewior powernv_cpuidle_cpu_online, NULL); 47710fcca9dSSebastian Andrzej Siewior WARN_ON(retval < 0); 47810fcca9dSSebastian Andrzej Siewior retval = cpuhp_setup_state_nocalls(CPUHP_CPUIDLE_DEAD, 47910fcca9dSSebastian Andrzej Siewior "cpuidle/powernv:dead", NULL, 48010fcca9dSSebastian Andrzej Siewior powernv_cpuidle_cpu_dead); 48110fcca9dSSebastian Andrzej Siewior WARN_ON(retval < 0); 4822c2e6ecfSDeepthi Dharwar printk(KERN_DEBUG "powernv_idle_driver registered\n"); 4832c2e6ecfSDeepthi Dharwar return 0; 4842c2e6ecfSDeepthi Dharwar } 4852c2e6ecfSDeepthi Dharwar 4862c2e6ecfSDeepthi Dharwar device_initcall(powernv_processor_idle_init); 487