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 352c2e6ecfSDeepthi Dharwar static int max_idle_state; 362c2e6ecfSDeepthi Dharwar static struct cpuidle_state *cpuidle_state_table; 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 4309206b60SGautham R. Shenoy static struct stop_psscr_table stop_psscr_table[CPUIDLE_STATE_MAX]; 443005c597SShreyas B. Prabhu 4578eaa10fSShilpasri G Bhat static u64 snooze_timeout; 4678eaa10fSShilpasri G Bhat static bool snooze_timeout_en; 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 local_irq_enable(); 552c2e6ecfSDeepthi Dharwar set_thread_flag(TIF_POLLING_NRFLAG); 562c2e6ecfSDeepthi Dharwar 5778eaa10fSShilpasri G Bhat snooze_exit_time = get_tb() + snooze_timeout; 58591ac0cbSNicolas Pitre ppc64_runlatch_off(); 592c2e6ecfSDeepthi Dharwar while (!need_resched()) { 602c2e6ecfSDeepthi Dharwar HMT_low(); 612c2e6ecfSDeepthi Dharwar HMT_very_low(); 6278eaa10fSShilpasri G Bhat if (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(); 702c2e6ecfSDeepthi Dharwar return index; 712c2e6ecfSDeepthi Dharwar } 722c2e6ecfSDeepthi Dharwar 732c2e6ecfSDeepthi Dharwar static int nap_loop(struct cpuidle_device *dev, 742c2e6ecfSDeepthi Dharwar struct cpuidle_driver *drv, 752c2e6ecfSDeepthi Dharwar int index) 762c2e6ecfSDeepthi Dharwar { 77591ac0cbSNicolas Pitre ppc64_runlatch_off(); 782c2e6ecfSDeepthi Dharwar power7_idle(); 79591ac0cbSNicolas Pitre ppc64_runlatch_on(); 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); 1020d948730SPreeti U Murthy power7_sleep(); 1030d948730SPreeti U Murthy 1040d948730SPreeti U Murthy mtspr(SPRN_LPCR, old_lpcr); 1050d948730SPreeti U Murthy 1060d948730SPreeti U Murthy return index; 1070d948730SPreeti U Murthy } 108cc5a2f7bSpreeti #endif 1093005c597SShreyas B. Prabhu 1103005c597SShreyas B. Prabhu static int stop_loop(struct cpuidle_device *dev, 1113005c597SShreyas B. Prabhu struct cpuidle_driver *drv, 1123005c597SShreyas B. Prabhu int index) 1133005c597SShreyas B. Prabhu { 1143005c597SShreyas B. Prabhu ppc64_runlatch_off(); 11509206b60SGautham R. Shenoy power9_idle_stop(stop_psscr_table[index].val, 11609206b60SGautham R. Shenoy stop_psscr_table[index].mask); 1173005c597SShreyas B. Prabhu ppc64_runlatch_on(); 1183005c597SShreyas B. Prabhu return index; 1193005c597SShreyas B. Prabhu } 1203005c597SShreyas B. Prabhu 1212c2e6ecfSDeepthi Dharwar /* 1222c2e6ecfSDeepthi Dharwar * States for dedicated partition case. 1232c2e6ecfSDeepthi Dharwar */ 124169f3faeSShreyas B. Prabhu static struct cpuidle_state powernv_states[CPUIDLE_STATE_MAX] = { 1252c2e6ecfSDeepthi Dharwar { /* Snooze */ 1262c2e6ecfSDeepthi Dharwar .name = "snooze", 1272c2e6ecfSDeepthi Dharwar .desc = "snooze", 1282c2e6ecfSDeepthi Dharwar .exit_latency = 0, 1292c2e6ecfSDeepthi Dharwar .target_residency = 0, 130957efcedSShreyas B. Prabhu .enter = snooze_loop }, 1312c2e6ecfSDeepthi Dharwar }; 1322c2e6ecfSDeepthi Dharwar 13310fcca9dSSebastian Andrzej Siewior static int powernv_cpuidle_cpu_online(unsigned int cpu) 1342c2e6ecfSDeepthi Dharwar { 13510fcca9dSSebastian Andrzej Siewior struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); 1362c2e6ecfSDeepthi Dharwar 1372c2e6ecfSDeepthi Dharwar if (dev && cpuidle_get_driver()) { 1382c2e6ecfSDeepthi Dharwar cpuidle_pause_and_lock(); 1392c2e6ecfSDeepthi Dharwar cpuidle_enable_device(dev); 1402c2e6ecfSDeepthi Dharwar cpuidle_resume_and_unlock(); 14110fcca9dSSebastian Andrzej Siewior } 14210fcca9dSSebastian Andrzej Siewior return 0; 14310fcca9dSSebastian Andrzej Siewior } 1442c2e6ecfSDeepthi Dharwar 14510fcca9dSSebastian Andrzej Siewior static int powernv_cpuidle_cpu_dead(unsigned int cpu) 14610fcca9dSSebastian Andrzej Siewior { 14710fcca9dSSebastian Andrzej Siewior struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); 14810fcca9dSSebastian Andrzej Siewior 14910fcca9dSSebastian Andrzej Siewior if (dev && cpuidle_get_driver()) { 1502c2e6ecfSDeepthi Dharwar cpuidle_pause_and_lock(); 1512c2e6ecfSDeepthi Dharwar cpuidle_disable_device(dev); 1522c2e6ecfSDeepthi Dharwar cpuidle_resume_and_unlock(); 1532c2e6ecfSDeepthi Dharwar } 15410fcca9dSSebastian Andrzej Siewior return 0; 1552c2e6ecfSDeepthi Dharwar } 1562c2e6ecfSDeepthi Dharwar 1572c2e6ecfSDeepthi Dharwar /* 1582c2e6ecfSDeepthi Dharwar * powernv_cpuidle_driver_init() 1592c2e6ecfSDeepthi Dharwar */ 1602c2e6ecfSDeepthi Dharwar static int powernv_cpuidle_driver_init(void) 1612c2e6ecfSDeepthi Dharwar { 1622c2e6ecfSDeepthi Dharwar int idle_state; 1632c2e6ecfSDeepthi Dharwar struct cpuidle_driver *drv = &powernv_idle_driver; 1642c2e6ecfSDeepthi Dharwar 1652c2e6ecfSDeepthi Dharwar drv->state_count = 0; 1662c2e6ecfSDeepthi Dharwar 1672c2e6ecfSDeepthi Dharwar for (idle_state = 0; idle_state < max_idle_state; ++idle_state) { 1682c2e6ecfSDeepthi Dharwar /* Is the state not enabled? */ 1692c2e6ecfSDeepthi Dharwar if (cpuidle_state_table[idle_state].enter == NULL) 1702c2e6ecfSDeepthi Dharwar continue; 1712c2e6ecfSDeepthi Dharwar 1722c2e6ecfSDeepthi Dharwar drv->states[drv->state_count] = /* structure copy */ 1732c2e6ecfSDeepthi Dharwar cpuidle_state_table[idle_state]; 1742c2e6ecfSDeepthi Dharwar 1752c2e6ecfSDeepthi Dharwar drv->state_count += 1; 1762c2e6ecfSDeepthi Dharwar } 1772c2e6ecfSDeepthi Dharwar 178293d264fSVaidyanathan Srinivasan /* 179293d264fSVaidyanathan Srinivasan * On the PowerNV platform cpu_present may be less than cpu_possible in 180293d264fSVaidyanathan Srinivasan * cases when firmware detects the CPU, but it is not available to the 181293d264fSVaidyanathan Srinivasan * OS. If CONFIG_HOTPLUG_CPU=n, then such CPUs are not hotplugable at 182293d264fSVaidyanathan Srinivasan * run time and hence cpu_devices are not created for those CPUs by the 183293d264fSVaidyanathan Srinivasan * generic topology_init(). 184293d264fSVaidyanathan Srinivasan * 185293d264fSVaidyanathan Srinivasan * drv->cpumask defaults to cpu_possible_mask in 186293d264fSVaidyanathan Srinivasan * __cpuidle_driver_init(). This breaks cpuidle on PowerNV where 187293d264fSVaidyanathan Srinivasan * cpu_devices are not created for CPUs in cpu_possible_mask that 188293d264fSVaidyanathan Srinivasan * cannot be hot-added later at run time. 189293d264fSVaidyanathan Srinivasan * 190293d264fSVaidyanathan Srinivasan * Trying cpuidle_register_device() on a CPU without a cpu_device is 191293d264fSVaidyanathan Srinivasan * incorrect, so pass a correct CPU mask to the generic cpuidle driver. 192293d264fSVaidyanathan Srinivasan */ 193293d264fSVaidyanathan Srinivasan 194293d264fSVaidyanathan Srinivasan drv->cpumask = (struct cpumask *)cpu_present_mask; 195293d264fSVaidyanathan Srinivasan 1962c2e6ecfSDeepthi Dharwar return 0; 1972c2e6ecfSDeepthi Dharwar } 1982c2e6ecfSDeepthi Dharwar 1999e9fc6f0SGautham R. Shenoy static inline void add_powernv_state(int index, const char *name, 2009e9fc6f0SGautham R. Shenoy unsigned int flags, 2019e9fc6f0SGautham R. Shenoy int (*idle_fn)(struct cpuidle_device *, 2029e9fc6f0SGautham R. Shenoy struct cpuidle_driver *, 2039e9fc6f0SGautham R. Shenoy int), 2049e9fc6f0SGautham R. Shenoy unsigned int target_residency, 2059e9fc6f0SGautham R. Shenoy unsigned int exit_latency, 20609206b60SGautham R. Shenoy u64 psscr_val, u64 psscr_mask) 2079e9fc6f0SGautham R. Shenoy { 2089e9fc6f0SGautham R. Shenoy strlcpy(powernv_states[index].name, name, CPUIDLE_NAME_LEN); 2099e9fc6f0SGautham R. Shenoy strlcpy(powernv_states[index].desc, name, CPUIDLE_NAME_LEN); 2109e9fc6f0SGautham R. Shenoy powernv_states[index].flags = flags; 2119e9fc6f0SGautham R. Shenoy powernv_states[index].target_residency = target_residency; 2129e9fc6f0SGautham R. Shenoy powernv_states[index].exit_latency = exit_latency; 2139e9fc6f0SGautham R. Shenoy powernv_states[index].enter = idle_fn; 21409206b60SGautham R. Shenoy stop_psscr_table[index].val = psscr_val; 21509206b60SGautham R. Shenoy stop_psscr_table[index].mask = psscr_mask; 2169e9fc6f0SGautham R. Shenoy } 2179e9fc6f0SGautham R. Shenoy 2180888839cSPreeti U Murthy static int powernv_add_idle_states(void) 2190888839cSPreeti U Murthy { 2200888839cSPreeti U Murthy struct device_node *power_mgt; 2210888839cSPreeti U Murthy int nr_idle_states = 1; /* Snooze */ 2220888839cSPreeti U Murthy int dt_idle_states; 223957efcedSShreyas B. Prabhu u32 latency_ns[CPUIDLE_STATE_MAX]; 224957efcedSShreyas B. Prabhu u32 residency_ns[CPUIDLE_STATE_MAX]; 225957efcedSShreyas B. Prabhu u32 flags[CPUIDLE_STATE_MAX]; 2263005c597SShreyas B. Prabhu u64 psscr_val[CPUIDLE_STATE_MAX]; 22709206b60SGautham R. Shenoy u64 psscr_mask[CPUIDLE_STATE_MAX]; 2283005c597SShreyas B. Prabhu const char *names[CPUIDLE_STATE_MAX]; 22909206b60SGautham R. Shenoy u32 has_stop_states = 0; 23092c83ff5SPreeti U Murthy int i, rc; 2310888839cSPreeti U Murthy 2320888839cSPreeti U Murthy /* Currently we have snooze statically defined */ 2330888839cSPreeti U Murthy 2340888839cSPreeti U Murthy power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); 2350888839cSPreeti U Murthy if (!power_mgt) { 2360888839cSPreeti U Murthy pr_warn("opal: PowerMgmt Node not found\n"); 23792c83ff5SPreeti U Murthy goto out; 2380888839cSPreeti U Murthy } 2390888839cSPreeti U Murthy 24070734a78SPreeti U Murthy /* Read values of any property to determine the num of idle states */ 24170734a78SPreeti U Murthy dt_idle_states = of_property_count_u32_elems(power_mgt, "ibm,cpu-idle-state-flags"); 24270734a78SPreeti U Murthy if (dt_idle_states < 0) { 24370734a78SPreeti U Murthy pr_warn("cpuidle-powernv: no idle states found in the DT\n"); 24492c83ff5SPreeti U Murthy goto out; 24574aa51b5SPreeti U. Murthy } 24674aa51b5SPreeti U. Murthy 247957efcedSShreyas B. Prabhu /* 248957efcedSShreyas B. Prabhu * Since snooze is used as first idle state, max idle states allowed is 249957efcedSShreyas B. Prabhu * CPUIDLE_STATE_MAX -1 250957efcedSShreyas B. Prabhu */ 251957efcedSShreyas B. Prabhu if (dt_idle_states > CPUIDLE_STATE_MAX - 1) { 252957efcedSShreyas B. Prabhu pr_warn("cpuidle-powernv: discovered idle states more than allowed"); 253957efcedSShreyas B. Prabhu dt_idle_states = CPUIDLE_STATE_MAX - 1; 254957efcedSShreyas B. Prabhu } 255957efcedSShreyas B. Prabhu 25670734a78SPreeti U Murthy if (of_property_read_u32_array(power_mgt, 25770734a78SPreeti U Murthy "ibm,cpu-idle-state-flags", flags, dt_idle_states)) { 25870734a78SPreeti U Murthy pr_warn("cpuidle-powernv : missing ibm,cpu-idle-state-flags in DT\n"); 259957efcedSShreyas B. Prabhu goto out; 26070734a78SPreeti U Murthy } 2610888839cSPreeti U Murthy 262957efcedSShreyas B. Prabhu if (of_property_read_u32_array(power_mgt, 263957efcedSShreyas B. Prabhu "ibm,cpu-idle-state-latencies-ns", latency_ns, 264957efcedSShreyas B. Prabhu dt_idle_states)) { 26592c83ff5SPreeti U Murthy pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n"); 266957efcedSShreyas B. Prabhu goto out; 26792c83ff5SPreeti U Murthy } 2683005c597SShreyas B. Prabhu if (of_property_read_string_array(power_mgt, 2693005c597SShreyas B. Prabhu "ibm,cpu-idle-state-names", names, dt_idle_states) < 0) { 2703005c597SShreyas B. Prabhu pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-names in DT\n"); 2713005c597SShreyas B. Prabhu goto out; 2723005c597SShreyas B. Prabhu } 2733005c597SShreyas B. Prabhu 2743005c597SShreyas B. Prabhu /* 2753005c597SShreyas B. Prabhu * If the idle states use stop instruction, probe for psscr values 27609206b60SGautham R. Shenoy * and psscr mask which are necessary to specify required stop level. 2773005c597SShreyas B. Prabhu */ 27809206b60SGautham R. Shenoy has_stop_states = (flags[0] & 27909206b60SGautham R. Shenoy (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP)); 28009206b60SGautham R. Shenoy if (has_stop_states) { 2813005c597SShreyas B. Prabhu if (of_property_read_u64_array(power_mgt, 2823005c597SShreyas B. Prabhu "ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) { 28309206b60SGautham R. Shenoy pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n"); 2843005c597SShreyas B. Prabhu goto out; 2853005c597SShreyas B. Prabhu } 28692c83ff5SPreeti U Murthy 28709206b60SGautham R. Shenoy if (of_property_read_u64_array(power_mgt, 28809206b60SGautham R. Shenoy "ibm,cpu-idle-state-psscr-mask", 28909206b60SGautham R. Shenoy psscr_mask, dt_idle_states)) { 29009206b60SGautham R. Shenoy pr_warn("cpuidle-powernv:Missing ibm,cpu-idle-state-psscr-mask in DT\n"); 29109206b60SGautham R. Shenoy goto out; 29209206b60SGautham R. Shenoy } 29309206b60SGautham R. Shenoy } 29409206b60SGautham R. Shenoy 29592c83ff5SPreeti U Murthy rc = of_property_read_u32_array(power_mgt, 29692c83ff5SPreeti U Murthy "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states); 29792c83ff5SPreeti U Murthy 2980888839cSPreeti U Murthy for (i = 0; i < dt_idle_states; i++) { 2999e9fc6f0SGautham R. Shenoy unsigned int exit_latency, target_residency; 3003005c597SShreyas B. Prabhu /* 3013005c597SShreyas B. Prabhu * If an idle state has exit latency beyond 3023005c597SShreyas B. Prabhu * POWERNV_THRESHOLD_LATENCY_NS then don't use it 3033005c597SShreyas B. Prabhu * in cpu-idle. 3043005c597SShreyas B. Prabhu */ 3053005c597SShreyas B. Prabhu if (latency_ns[i] > POWERNV_THRESHOLD_LATENCY_NS) 3063005c597SShreyas B. Prabhu continue; 3079e9fc6f0SGautham R. Shenoy /* 3089e9fc6f0SGautham R. Shenoy * Firmware passes residency and latency values in ns. 3099e9fc6f0SGautham R. Shenoy * cpuidle expects it in us. 3109e9fc6f0SGautham R. Shenoy */ 3119e9fc6f0SGautham R. Shenoy exit_latency = latency_ns[i] / 1000; 3129e9fc6f0SGautham R. Shenoy if (!rc) 3139e9fc6f0SGautham R. Shenoy target_residency = residency_ns[i] / 1000; 3149e9fc6f0SGautham R. Shenoy else 3159e9fc6f0SGautham R. Shenoy target_residency = 0; 3160888839cSPreeti U Murthy 31709206b60SGautham R. Shenoy if (has_stop_states) { 31809206b60SGautham R. Shenoy int err = validate_psscr_val_mask(&psscr_val[i], 31909206b60SGautham R. Shenoy &psscr_mask[i], 32009206b60SGautham R. Shenoy flags[i]); 32109206b60SGautham R. Shenoy if (err) { 32209206b60SGautham R. Shenoy report_invalid_psscr_val(psscr_val[i], err); 32309206b60SGautham R. Shenoy continue; 32409206b60SGautham R. Shenoy } 32509206b60SGautham R. Shenoy } 32609206b60SGautham R. Shenoy 32792c83ff5SPreeti U Murthy /* 3289e9fc6f0SGautham R. Shenoy * For nap and fastsleep, use default target_residency 3299e9fc6f0SGautham R. Shenoy * values if f/w does not expose it. 33074aa51b5SPreeti U. Murthy */ 33170734a78SPreeti U Murthy if (flags[i] & OPAL_PM_NAP_ENABLED) { 3329e9fc6f0SGautham R. Shenoy if (!rc) 3339e9fc6f0SGautham R. Shenoy target_residency = 100; 3340888839cSPreeti U Murthy /* Add NAP state */ 3359e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, "Nap", 3369e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_NONE, nap_loop, 33709206b60SGautham R. Shenoy target_residency, exit_latency, 0, 0); 3383005c597SShreyas B. Prabhu } else if ((flags[i] & OPAL_PM_STOP_INST_FAST) && 3393005c597SShreyas B. Prabhu !(flags[i] & OPAL_PM_TIMEBASE_STOP)) { 3409e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, names[i], 3419e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_NONE, stop_loop, 3429e9fc6f0SGautham R. Shenoy target_residency, exit_latency, 34309206b60SGautham R. Shenoy psscr_val[i], psscr_mask[i]); 344cc5a2f7bSpreeti } 345cc5a2f7bSpreeti 346cc5a2f7bSpreeti /* 347cc5a2f7bSpreeti * All cpuidle states with CPUIDLE_FLAG_TIMER_STOP set must come 348cc5a2f7bSpreeti * within this config dependency check. 349cc5a2f7bSpreeti */ 350cc5a2f7bSpreeti #ifdef CONFIG_TICK_ONESHOT 351cc5a2f7bSpreeti if (flags[i] & OPAL_PM_SLEEP_ENABLED || 35270734a78SPreeti U Murthy flags[i] & OPAL_PM_SLEEP_ENABLED_ER1) { 3539e9fc6f0SGautham R. Shenoy if (!rc) 3549e9fc6f0SGautham R. Shenoy target_residency = 300000; 3550888839cSPreeti U Murthy /* Add FASTSLEEP state */ 3569e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, "FastSleep", 3579e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_TIMER_STOP, 3589e9fc6f0SGautham R. Shenoy fastsleep_loop, 35909206b60SGautham R. Shenoy target_residency, exit_latency, 0, 0); 3603005c597SShreyas B. Prabhu } else if ((flags[i] & OPAL_PM_STOP_INST_DEEP) && 3613005c597SShreyas B. Prabhu (flags[i] & OPAL_PM_TIMEBASE_STOP)) { 3629e9fc6f0SGautham R. Shenoy add_powernv_state(nr_idle_states, names[i], 3639e9fc6f0SGautham R. Shenoy CPUIDLE_FLAG_TIMER_STOP, stop_loop, 3649e9fc6f0SGautham R. Shenoy target_residency, exit_latency, 36509206b60SGautham R. Shenoy psscr_val[i], psscr_mask[i]); 3660888839cSPreeti U Murthy } 367cc5a2f7bSpreeti #endif 36892c83ff5SPreeti U Murthy nr_idle_states++; 36992c83ff5SPreeti U Murthy } 37092c83ff5SPreeti U Murthy out: 3710888839cSPreeti U Murthy return nr_idle_states; 3720888839cSPreeti U Murthy } 3730888839cSPreeti U Murthy 3742c2e6ecfSDeepthi Dharwar /* 3752c2e6ecfSDeepthi Dharwar * powernv_idle_probe() 3762c2e6ecfSDeepthi Dharwar * Choose state table for shared versus dedicated partition 3772c2e6ecfSDeepthi Dharwar */ 3782c2e6ecfSDeepthi Dharwar static int powernv_idle_probe(void) 3792c2e6ecfSDeepthi Dharwar { 3802c2e6ecfSDeepthi Dharwar if (cpuidle_disable != IDLE_NO_OVERRIDE) 3812c2e6ecfSDeepthi Dharwar return -ENODEV; 3822c2e6ecfSDeepthi Dharwar 383e4d54f71SStewart Smith if (firmware_has_feature(FW_FEATURE_OPAL)) { 3842c2e6ecfSDeepthi Dharwar cpuidle_state_table = powernv_states; 3850888839cSPreeti U Murthy /* Device tree can indicate more idle states */ 3860888839cSPreeti U Murthy max_idle_state = powernv_add_idle_states(); 38778eaa10fSShilpasri G Bhat if (max_idle_state > 1) { 38878eaa10fSShilpasri G Bhat snooze_timeout_en = true; 38978eaa10fSShilpasri G Bhat snooze_timeout = powernv_states[1].target_residency * 39078eaa10fSShilpasri G Bhat tb_ticks_per_usec; 39178eaa10fSShilpasri G Bhat } 3922c2e6ecfSDeepthi Dharwar } else 3932c2e6ecfSDeepthi Dharwar return -ENODEV; 3942c2e6ecfSDeepthi Dharwar 3952c2e6ecfSDeepthi Dharwar return 0; 3962c2e6ecfSDeepthi Dharwar } 3972c2e6ecfSDeepthi Dharwar 3982c2e6ecfSDeepthi Dharwar static int __init powernv_processor_idle_init(void) 3992c2e6ecfSDeepthi Dharwar { 4002c2e6ecfSDeepthi Dharwar int retval; 4012c2e6ecfSDeepthi Dharwar 4022c2e6ecfSDeepthi Dharwar retval = powernv_idle_probe(); 4032c2e6ecfSDeepthi Dharwar if (retval) 4042c2e6ecfSDeepthi Dharwar return retval; 4052c2e6ecfSDeepthi Dharwar 4062c2e6ecfSDeepthi Dharwar powernv_cpuidle_driver_init(); 4072c2e6ecfSDeepthi Dharwar retval = cpuidle_register(&powernv_idle_driver, NULL); 4082c2e6ecfSDeepthi Dharwar if (retval) { 4092c2e6ecfSDeepthi Dharwar printk(KERN_DEBUG "Registration of powernv driver failed.\n"); 4102c2e6ecfSDeepthi Dharwar return retval; 4112c2e6ecfSDeepthi Dharwar } 4122c2e6ecfSDeepthi Dharwar 41310fcca9dSSebastian Andrzej Siewior retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, 41410fcca9dSSebastian Andrzej Siewior "cpuidle/powernv:online", 41510fcca9dSSebastian Andrzej Siewior powernv_cpuidle_cpu_online, NULL); 41610fcca9dSSebastian Andrzej Siewior WARN_ON(retval < 0); 41710fcca9dSSebastian Andrzej Siewior retval = cpuhp_setup_state_nocalls(CPUHP_CPUIDLE_DEAD, 41810fcca9dSSebastian Andrzej Siewior "cpuidle/powernv:dead", NULL, 41910fcca9dSSebastian Andrzej Siewior powernv_cpuidle_cpu_dead); 42010fcca9dSSebastian Andrzej Siewior WARN_ON(retval < 0); 4212c2e6ecfSDeepthi Dharwar printk(KERN_DEBUG "powernv_idle_driver registered\n"); 4222c2e6ecfSDeepthi Dharwar return 0; 4232c2e6ecfSDeepthi Dharwar } 4242c2e6ecfSDeepthi Dharwar 4252c2e6ecfSDeepthi Dharwar device_initcall(powernv_processor_idle_init); 426