static void pnv_alloc_idle_core_states(void) { int i, j; int nr_cores = cpu_nr_cores(); u32 *core_idle_state; /* * core_idle_state - The lower 8 bits track the idle state of * each thread of the core. * * The most significant bit is the lock bit. * * Initially all the bits corresponding to threads_per_core * are set. They are cleared when the thread enters deep idle * state like sleep and winkle/stop. * * Initially the lock bit is cleared. The lock bit has 2 * purposes: * a. While the first thread in the core waking up from * idle is restoring core state, it prevents other * threads in the core from switching to process * context. * b. While the last thread in the core is saving the * core state, it prevents a different thread from * waking up. */ for (i = 0; i < nr_cores; i++) { int first_cpu = i * threads_per_core; int node = cpu_to_node(first_cpu); size_t paca_ptr_array_size; core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node); *core_idle_state = (1 << threads_per_core) - 1; paca_ptr_array_size = (threads_per_core * sizeof(struct paca_struct *)); for (j = 0; j < threads_per_core; j++) { int cpu = first_cpu + j; paca[cpu].core_idle_state_ptr = core_idle_state; paca[cpu].thread_idle_state = PNV_THREAD_RUNNING; paca[cpu].thread_mask = 1 << j; if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) continue; paca[cpu].thread_sibling_pacas = kmalloc_node(paca_ptr_array_size, GFP_KERNEL, node); } } update_subcore_sibling_mask(); if (supported_cpuidle_states & OPAL_PM_LOSE_FULL_CONTEXT) pnv_save_sprs_for_deep_states(); }
static void pnv_alloc_idle_core_states(void) { int i, j; int nr_cores = cpu_nr_cores(); u32 *core_idle_state; /* * core_idle_state - First 8 bits track the idle state of each thread * of the core. The 8th bit is the lock bit. Initially all thread bits * are set. They are cleared when the thread enters deep idle state * like sleep and winkle. Initially the lock bit is cleared. * The lock bit has 2 purposes * a. While the first thread is restoring core state, it prevents * other threads in the core from switching to process context. * b. While the last thread in the core is saving the core state, it * prevents a different thread from waking up. */ for (i = 0; i < nr_cores; i++) { int first_cpu = i * threads_per_core; int node = cpu_to_node(first_cpu); core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node); *core_idle_state = PNV_CORE_IDLE_THREAD_BITS; for (j = 0; j < threads_per_core; j++) { int cpu = first_cpu + j; paca[cpu].core_idle_state_ptr = core_idle_state; paca[cpu].thread_idle_state = PNV_THREAD_RUNNING; paca[cpu].thread_mask = 1 << j; } } update_subcore_sibling_mask(); if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED) pnv_save_sprs_for_winkle(); }
static void pnv_alloc_idle_core_states(void) { int i, j; int nr_cores = cpu_nr_cores(); u32 *core_idle_state; /* * core_idle_state - The lower 8 bits track the idle state of * each thread of the core. * * The most significant bit is the lock bit. * * Initially all the bits corresponding to threads_per_core * are set. They are cleared when the thread enters deep idle * state like sleep and winkle/stop. * * Initially the lock bit is cleared. The lock bit has 2 * purposes: * a. While the first thread in the core waking up from * idle is restoring core state, it prevents other * threads in the core from switching to process * context. * b. While the last thread in the core is saving the * core state, it prevents a different thread from * waking up. */ for (i = 0; i < nr_cores; i++) { int first_cpu = i * threads_per_core; int node = cpu_to_node(first_cpu); size_t paca_ptr_array_size; core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node); *core_idle_state = (1 << threads_per_core) - 1; paca_ptr_array_size = (threads_per_core * sizeof(struct paca_struct *)); for (j = 0; j < threads_per_core; j++) { int cpu = first_cpu + j; paca_ptrs[cpu]->core_idle_state_ptr = core_idle_state; paca_ptrs[cpu]->thread_idle_state = PNV_THREAD_RUNNING; paca_ptrs[cpu]->thread_mask = 1 << j; if (!cpu_has_feature(CPU_FTR_POWER9_DD1)) continue; paca_ptrs[cpu]->thread_sibling_pacas = kmalloc_node(paca_ptr_array_size, GFP_KERNEL, node); } } update_subcore_sibling_mask(); if (supported_cpuidle_states & OPAL_PM_LOSE_FULL_CONTEXT) { int rc = pnv_save_sprs_for_deep_states(); if (likely(!rc)) return; /* * The stop-api is unable to restore hypervisor * resources on wakeup from platform idle states which * lose full context. So disable such states. */ supported_cpuidle_states &= ~OPAL_PM_LOSE_FULL_CONTEXT; pr_warn("cpuidle-powernv: Disabling idle states that lose full context\n"); pr_warn("cpuidle-powernv: Idle power-savings, CPU-Hotplug affected\n"); if (cpu_has_feature(CPU_FTR_ARCH_300) && (pnv_deepest_stop_flag & OPAL_PM_LOSE_FULL_CONTEXT)) { /* * Use the default stop state for CPU-Hotplug * if available. */ if (default_stop_found) { pnv_deepest_stop_psscr_val = pnv_default_stop_val; pnv_deepest_stop_psscr_mask = pnv_default_stop_mask; pr_warn("cpuidle-powernv: Offlined CPUs will stop with psscr = 0x%016llx\n", pnv_deepest_stop_psscr_val); } else { /* Fallback to snooze loop for CPU-Hotplug */ deepest_stop_found = false; pr_warn("cpuidle-powernv: Offlined CPUs will busy wait\n"); } } } }