Commit a9ceb78bc75c (cpuidle,menu: use interactivity_req to disable polling) exposed a bug in menu_select() causing it to return -1 on systems with CPUIDLE_DRIVER_STATE_START equal to zero, although it should have returned 0. As a result, idle states are not entered by CPUs on those systems. Namely, on the systems in question data->last_state_idx is initially equal to -1 and the above commit modified the condition that would have caused it to be changed to 0 to be less likely to trigger which exposed the problem. However, setting data->last_state_idx initially to -1 doesn't make sense at all and on the affected systems it should always be set to CPUIDLE_DRIVER_STATE_START (ie. 0) unconditionally, so make that happen.
Unified · Split
| @@ -294,8 +294,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) · 293 unmodified lines | |||
| 294 | data->needs_update = 0; | 294 | data->needs_update = 0; |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1; | ||
| 298 | |||
| 299 | /* Special case when user has set very strict latency requirement */ | 297 | /* Special case when user has set very strict latency requirement */ |
| 300 | if (unlikely(latency_req == 0)) | 298 | if (unlikely(latency_req == 0)) |
| 301 | return 0; | 299 | return 0; |
| @@ -326,14 +324,19 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) · 24 unmodified lines | |||
| 326 | if (latency_req > interactivity_req) | 324 | if (latency_req > interactivity_req) |
| 327 | latency_req = interactivity_req; | 325 | latency_req = interactivity_req; |
| 328 | 326 | ||
| 329 | /* | 327 | if (CPUIDLE_DRIVER_STATE_START > 0) { |
| 330 | * We want to default to C1 (hlt), not to busy polling | 328 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1; |
| 331 | * unless the timer is happening really really soon. | 329 | /* |
| 332 | */ | 330 | * We want to default to C1 (hlt), not to busy polling |
| 333 | if (interactivity_req > 20 && | 331 | * unless the timer is happening really really soon. |
| 334 | !drv->states[CPUIDLE_DRIVER_STATE_START].disabled && | 332 | */ |
| 335 | dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0) | 333 | if (interactivity_req > 20 && |
| 334 | !drv->states[CPUIDLE_DRIVER_STATE_START].disabled && | ||
| 335 | dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0) | ||
| 336 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START; | ||
| 337 | } else { | ||
| 336 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START; | 338 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START; |
| 339 | } | ||
| 337 | 340 | ||
| 338 | /* | 341 | /* |
| 339 | * Find the idle state with the lowest power while satisfying | 342 | * Find the idle state with the lowest power while satisfying |