On 2014/10/24 23:36, Peter Zijlstra wrote:
>> +
>> +static void freezer_idle(int cpu)
>> +{
>> +    struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
>> +    struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
>> +
>> +    stop_critical_timings();
>> +
>> +    while (suspend_freeze_wake == -1) {
>> +            int next_state;
>> +
>> +            /*
>> +             * interrupt must be disabled before cpu enters idle
>> +             */
>> +            local_irq_disable();
>> +
>> +            next_state = cpuidle_select(drv, dev);
>> +            if (next_state < 0) {
>> +                    arch_cpu_idle();
>> +                    continue;
>> +            }
>> +            /*
>> +             * cpuidle_enter will return with interrupt enabled
>> +             */
>> +            cpuidle_enter(drv, dev, next_state);
>> +    }
>> +
>> +    if (suspend_freeze_wake == cpu)
>> +            kick_all_cpus_sync();
>> +
> 
> So I disabled IRQs here
> 
>> +    start_critical_timings();
>> +}
>> +
>> +static void freezer_resume_tk(int cpu)
>> +{
>> +    if (tick_do_timer_cpu != cpu)
>> +            return;
>> +
>>      cpuidle_pause();
>>      cpuidle_use_deepest_state(false);
>> +
> 
> Such that they would still be disabled here
> 
>> +    local_irq_disable();
>> +    timekeeping_resume();
>> +    local_irq_enable();
>> +}
>> +
>> +static void freezer_resume_clkevt(int cpu)
>> +{
>> +    if (tick_do_timer_cpu == cpu)
>> +            return;
>> +
>> +    touch_softlockup_watchdog();
>> +    clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
> 
> And here.
> 
>> +    local_irq_disable();
>> +    hrtimers_resume();
>> +    local_irq_enable();
>> +}
>> +
>> +typedef void (*freezer_fn)(int);
>> +
>> +static freezer_fn freezer_func[FREEZER_EXIT] = {
>> +    NULL,
>> +    freezer_pick_tk,
>> +    freezer_suspend_clkevt,
>> +    freezer_suspend_tk,
>> +    freezer_idle,
>> +    freezer_resume_tk,
>> +    freezer_resume_clkevt,
>> +};
> 
> Because this is a stop_machine callback, which are nominally run with
> IRQs disabled.
> 
>> +static int freezer_stopper_fn(void *arg)
>> +{
>> +    struct freezer_data *fd = arg;
>> +    enum freezer_state state = FREEZER_NONE;
>> +    int cpu = smp_processor_id();
>> +
>> +    do {
>> +            cpu_relax();
>> +            if (fd->state != state) {
>> +                    state = fd->state;
>> +                    if (freezer_func[state])
>> +                            (*freezer_func[state])(cpu);
>> +                    ack_state(fd);
>> +            }
>> +    } while (fd->state != FREEZER_EXIT);
>> +    return 0;
>> +}
> 
> Now I suppose the problem is with cpu_pause() which needs IPIs to
> complete? 
Yes, cpu_pause() will invoke smp IPI functions which need interrupt is
enabled. So I changed irq ops like above. Actually, I have an early
version to move cpuidle_pause()/cpuidle_resume() out of stop_machine(),
that might be a better solution?

Thanks,
-Aubrey

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to