Skip to content
  • Rafael J. Wysocki's avatar
    intel_pstate: Do not call wrmsrl_on_cpu() with disabled interrupts · fdfdb2b1
    Rafael J. Wysocki authored
    After commit a4675fbc (cpufreq: intel_pstate: Replace timers with
    utilization update callbacks) wrmsrl_on_cpu() cannot be called in the
    intel_pstate_adjust_busy_pstate() path as that is executed with
    disabled interrupts.  However, atom_set_pstate() called from there
    via intel_pstate_set_pstate() uses wrmsrl_on_cpu() to update the
    IA32_PERF_CTL MSR which triggers the WARN_ON_ONCE() in
    smp_call_function_single().
    
    The reason why wrmsrl_on_cpu() is used by atom_set_pstate() is
    because intel_pstate_set_pstate() calling it is also invoked during
    the initialization and cleanup of the driver and in those cases it is
    not guaranteed to be run on the CPU that is being updated.  However,
    in the case when intel_pstate_set_pstate() is called by
    intel_pstate_adjust_busy_pstate(), wrmsrl() can be used to update
    the register safely.  Moreover, intel_pstate_set_pstate() already
    contains code that only is executed if the function is called by
    intel_pstate_adjust_busy_pstate() and there is a special argument
    passed to it because of that.
    
    To fix the problem at hand, rearrange the code taking the above
    observations into account.
    
    First, replace the ->set() callback in struct pstate_funcs with a
    ->get_val() one that will return the value to be written to the
    IA32_PERF_CTL MSR without updating the register.
    
    Second, split intel_pstate_set_pstate() into two functions,
    intel_pstate_update_pstate() to be called by
    intel_pstate_adjust_busy_pstate() that will contain all of the
    intel_pstate_set_pstate() code which only needs to be executed in
    that case and will use wrmsrl() to update the MSR (after obtaining
    the value to write to it from the ->get_val() callback), and
    intel_pstate_set_min_pstate() to be invoked during the
    initialization and cleanup that will set the P-state to the
    minimum one and will update the MSR using wrmsrl_on_cpu().
    
    Finally, move the code shared between intel_pstate_update_pstate()
    and intel_pstate_set_min_pstate() to a new static inline function
    intel_pstate_record_pstate() and make them both call it.
    
    Of course, that unifies the handling of the IA32_PERF_CTL MSR writes
    between Atom and Core.
    
    Fixes: a4675fbc
    
     (cpufreq: intel_pstate: Replace timers with utilization update callbacks)
    Reported-and-tested-by: default avatarJosh Boyer <jwboyer@fedoraproject.org>
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    fdfdb2b1