Commit d0e936ad authored by Srinivas Pandruvada's avatar Srinivas Pandruvada Committed by Rafael J. Wysocki

cpufreq: intel_pstate: Process HWP Guaranteed change notification

It is possible that HWP guaranteed ratio is changed in response to
change in power and thermal limits. For example when Intel Speed Select
performance profile is changed or there is change in TDP, hardware can
send notifications. It is possible that the guaranteed ratio is
increased. This creates an issue when turbo is disabled, as the old
limits set in MSR_HWP_REQUEST are still lower and hardware will clip
to older limits.

This change enables HWP interrupt and process HWP interrupts. When
guaranteed is changed, calls cpufreq_update_policy() so that driver
callbacks are called to update to new HWP limits. This callback
is called from a delayed workqueue of 10ms to avoid frequent updates.
Signed-off-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 950809cd
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/intel-family.h> #include <asm/intel-family.h>
#include "../drivers/thermal/intel/thermal_interrupt.h"
#define INTEL_PSTATE_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC) #define INTEL_PSTATE_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC)
...@@ -219,6 +220,7 @@ struct global_params { ...@@ -219,6 +220,7 @@ struct global_params {
* @sched_flags: Store scheduler flags for possible cross CPU update * @sched_flags: Store scheduler flags for possible cross CPU update
* @hwp_boost_min: Last HWP boosted min performance * @hwp_boost_min: Last HWP boosted min performance
* @suspended: Whether or not the driver has been suspended. * @suspended: Whether or not the driver has been suspended.
* @hwp_notify_work: workqueue for HWP notifications.
* *
* This structure stores per CPU instance data for all CPUs. * This structure stores per CPU instance data for all CPUs.
*/ */
...@@ -257,6 +259,7 @@ struct cpudata { ...@@ -257,6 +259,7 @@ struct cpudata {
unsigned int sched_flags; unsigned int sched_flags;
u32 hwp_boost_min; u32 hwp_boost_min;
bool suspended; bool suspended;
struct delayed_work hwp_notify_work;
}; };
static struct cpudata **all_cpu_data; static struct cpudata **all_cpu_data;
...@@ -1625,6 +1628,40 @@ static void intel_pstate_sysfs_hide_hwp_dynamic_boost(void) ...@@ -1625,6 +1628,40 @@ static void intel_pstate_sysfs_hide_hwp_dynamic_boost(void)
/************************** sysfs end ************************/ /************************** sysfs end ************************/
static void intel_pstate_notify_work(struct work_struct *work)
{
mutex_lock(&intel_pstate_driver_lock);
cpufreq_update_policy(smp_processor_id());
wrmsrl(MSR_HWP_STATUS, 0);
mutex_unlock(&intel_pstate_driver_lock);
}
void notify_hwp_interrupt(void)
{
unsigned int this_cpu = smp_processor_id();
struct cpudata *cpudata;
u64 value;
if (!hwp_active || !boot_cpu_has(X86_FEATURE_HWP_NOTIFY))
return;
rdmsrl(MSR_HWP_STATUS, value);
if (!(value & 0x01))
return;
cpudata = all_cpu_data[this_cpu];
schedule_delayed_work_on(this_cpu, &cpudata->hwp_notify_work, msecs_to_jiffies(10));
}
static void intel_pstate_enable_hwp_interrupt(struct cpudata *cpudata)
{
/* Enable HWP notification interrupt for guaranteed performance change */
if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) {
INIT_DELAYED_WORK(&cpudata->hwp_notify_work, intel_pstate_notify_work);
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x01);
}
}
static void intel_pstate_hwp_enable(struct cpudata *cpudata) static void intel_pstate_hwp_enable(struct cpudata *cpudata)
{ {
/* First disable HWP notification interrupt as we don't process them */ /* First disable HWP notification interrupt as we don't process them */
...@@ -1634,6 +1671,8 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata) ...@@ -1634,6 +1671,8 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata)
wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1); wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
if (cpudata->epp_default == -EINVAL) if (cpudata->epp_default == -EINVAL)
cpudata->epp_default = intel_pstate_get_epp(cpudata, 0); cpudata->epp_default = intel_pstate_get_epp(cpudata, 0);
intel_pstate_enable_hwp_interrupt(cpudata);
} }
static int atom_get_min_pstate(void) static int atom_get_min_pstate(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment