| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * OMAP4+ CPU idle Routines |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2011-2013 Texas Instruments, Inc. |
|---|
| 5 | 6 | * Santosh Shilimkar <santosh.shilimkar@ti.com> |
|---|
| 6 | 7 | * Rajendra Nayak <rnayak@ti.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 10 | | - * published by the Free Software Foundation. |
|---|
| 11 | 8 | */ |
|---|
| 12 | 9 | |
|---|
| 13 | 10 | #include <linux/sched.h> |
|---|
| .. | .. |
|---|
| 125 | 122 | { |
|---|
| 126 | 123 | struct idle_statedata *cx = state_ptr + index; |
|---|
| 127 | 124 | u32 mpuss_can_lose_context = 0; |
|---|
| 125 | + int error; |
|---|
| 128 | 126 | |
|---|
| 129 | 127 | /* |
|---|
| 130 | 128 | * CPU0 has to wait and stay ON until CPU1 is OFF state. |
|---|
| .. | .. |
|---|
| 153 | 151 | (cx->mpu_logic_state == PWRDM_POWER_OFF); |
|---|
| 154 | 152 | |
|---|
| 155 | 153 | /* Enter broadcast mode for periodic timers */ |
|---|
| 156 | | - tick_broadcast_enable(); |
|---|
| 154 | + RCU_NONIDLE(tick_broadcast_enable()); |
|---|
| 157 | 155 | |
|---|
| 158 | 156 | /* Enter broadcast mode for one-shot timers */ |
|---|
| 159 | | - tick_broadcast_enter(); |
|---|
| 157 | + RCU_NONIDLE(tick_broadcast_enter()); |
|---|
| 160 | 158 | |
|---|
| 161 | 159 | /* |
|---|
| 162 | 160 | * Call idle CPU PM enter notifier chain so that |
|---|
| 163 | 161 | * VFP and per CPU interrupt context is saved. |
|---|
| 164 | 162 | */ |
|---|
| 165 | | - cpu_pm_enter(); |
|---|
| 163 | + error = cpu_pm_enter(); |
|---|
| 164 | + if (error) |
|---|
| 165 | + goto cpu_pm_out; |
|---|
| 166 | 166 | |
|---|
| 167 | 167 | if (dev->cpu == 0) { |
|---|
| 168 | 168 | pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); |
|---|
| 169 | | - omap_set_pwrdm_state(mpu_pd, cx->mpu_state); |
|---|
| 169 | + RCU_NONIDLE(omap_set_pwrdm_state(mpu_pd, cx->mpu_state)); |
|---|
| 170 | 170 | |
|---|
| 171 | 171 | /* |
|---|
| 172 | 172 | * Call idle CPU cluster PM enter notifier chain |
|---|
| 173 | 173 | * to save GIC and wakeupgen context. |
|---|
| 174 | 174 | */ |
|---|
| 175 | | - if (mpuss_can_lose_context) |
|---|
| 176 | | - cpu_cluster_pm_enter(); |
|---|
| 175 | + if (mpuss_can_lose_context) { |
|---|
| 176 | + error = cpu_cluster_pm_enter(); |
|---|
| 177 | + if (error) { |
|---|
| 178 | + index = 0; |
|---|
| 179 | + cx = state_ptr + index; |
|---|
| 180 | + pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); |
|---|
| 181 | + RCU_NONIDLE(omap_set_pwrdm_state(mpu_pd, cx->mpu_state)); |
|---|
| 182 | + mpuss_can_lose_context = 0; |
|---|
| 183 | + } |
|---|
| 184 | + } |
|---|
| 177 | 185 | } |
|---|
| 178 | 186 | |
|---|
| 179 | 187 | omap4_enter_lowpower(dev->cpu, cx->cpu_state); |
|---|
| .. | .. |
|---|
| 186 | 194 | mpuss_can_lose_context) |
|---|
| 187 | 195 | gic_dist_disable(); |
|---|
| 188 | 196 | |
|---|
| 189 | | - clkdm_deny_idle(cpu_clkdm[1]); |
|---|
| 190 | | - omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON); |
|---|
| 191 | | - clkdm_allow_idle(cpu_clkdm[1]); |
|---|
| 197 | + RCU_NONIDLE(clkdm_deny_idle(cpu_clkdm[1])); |
|---|
| 198 | + RCU_NONIDLE(omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON)); |
|---|
| 199 | + RCU_NONIDLE(clkdm_allow_idle(cpu_clkdm[1])); |
|---|
| 192 | 200 | |
|---|
| 193 | 201 | if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && |
|---|
| 194 | 202 | mpuss_can_lose_context) { |
|---|
| .. | .. |
|---|
| 201 | 209 | } |
|---|
| 202 | 210 | |
|---|
| 203 | 211 | /* |
|---|
| 204 | | - * Call idle CPU PM exit notifier chain to restore |
|---|
| 205 | | - * VFP and per CPU IRQ context. |
|---|
| 206 | | - */ |
|---|
| 207 | | - cpu_pm_exit(); |
|---|
| 208 | | - |
|---|
| 209 | | - /* |
|---|
| 210 | 212 | * Call idle CPU cluster PM exit notifier chain |
|---|
| 211 | 213 | * to restore GIC and wakeupgen context. |
|---|
| 212 | 214 | */ |
|---|
| 213 | 215 | if (dev->cpu == 0 && mpuss_can_lose_context) |
|---|
| 214 | 216 | cpu_cluster_pm_exit(); |
|---|
| 215 | 217 | |
|---|
| 216 | | - tick_broadcast_exit(); |
|---|
| 218 | + /* |
|---|
| 219 | + * Call idle CPU PM exit notifier chain to restore |
|---|
| 220 | + * VFP and per CPU IRQ context. |
|---|
| 221 | + */ |
|---|
| 222 | + cpu_pm_exit(); |
|---|
| 223 | + |
|---|
| 224 | +cpu_pm_out: |
|---|
| 225 | + RCU_NONIDLE(tick_broadcast_exit()); |
|---|
| 217 | 226 | |
|---|
| 218 | 227 | fail: |
|---|
| 219 | 228 | cpuidle_coupled_parallel_barrier(dev, &abort_barrier); |
|---|