forked from Minki/linux
cpufreq arm fixes for 5.18-rc5
- Fix issues with the Qualcomm's cpufreq driver (Dmitry Baryshkov and Vladimir Zapolskiy). - Fix memory leak with the Sun501 driver (Xiaobing Luo). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmJnlhUACgkQ0rkcPK6B Ehxa7RAAi+RNRFIluLn1oZzsJPa0DlBk5C+mxlyXEnJuLypsuBGHxXYnvdduy+8O Ji3UxjUj1nnNmj4cYwVHLrkbIL3rpP7reCrsoTYcX9iMlwSYY6cOJjJSyrg53XtB tbzhf/23+zPUzfZdMSM9m4myTY052/iqj2paUWeoPAHCB4a4ADAq60NSFN6ZQGZg VuEQHWjY7j+Mgqc61Q/ZUf1YuM4njR5wtHu6qw7orimnSMqsEOpeSZLvQjJj9JWr fYc2LR7Lg2ilWzCjdFJbwsR93XDhm62bT0p9tQdkaGRZQmFLEwqngpC03dgsqtLJ Pbr/hQgvAnM+dyDa8xIAkSLTlTIb16q8+V6lbMZFoMmKJvL0+wgXnWywdh07jq9z KEbrm3ECnqJWJ0iIZEvkeIupn0FIRkVgwCcL5wweF3Q46uyGuJCqLko83YZgFfjK NUlu92vKLKVN3F6ZKm5T4koDwlvPzy+PdkTPOXFxHsQi7o7BiEcoHe4axQ9biPmD HFlDQORfhRcT/blJoPmldIcL26R86CcACo8d5mEK2pQFUxcKVAETxxdE6zJDFd59 9BXhQAMAnVDJ0Lu++o7OsTteeL1Gp9pDTvhVFQfnjapNtcr6SeLI+SqNSes6oiD2 AHjXPv17gnGB1duAqgqbqyGMMWYQ86X0QeFWSdua/4gPlo0TYyw= =HauS -----END PGP SIGNATURE----- Merge tag 'cpufreq-arm-fixes-5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm Pull ARM cpufreq fixes for 5.18-rc5 from Viresh Kumar: "- Fix issues with the Qualcomm's cpufreq driver (Dmitry Baryshkov and Vladimir Zapolskiy). - Fix memory leak with the Sun501 driver (Xiaobing Luo)." * tag 'cpufreq-arm-fixes-5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: cpufreq: qcom-cpufreq-hw: Clear dcvs interrupts cpufreq: fix memory leak in sun50i_cpufreq_nvmem_probe cpufreq: qcom-cpufreq-hw: Fix throttle frequency value on EPSS platforms cpufreq: qcom-hw: provide online/offline operations cpufreq: qcom-hw: fix the opp entries refcounting cpufreq: qcom-hw: fix the race between LMH worker and cpuhp cpufreq: qcom-hw: drop affinity hint before freeing the IRQ
This commit is contained in:
commit
0f03610b20
@ -24,13 +24,17 @@
|
||||
#define CLK_HW_DIV 2
|
||||
#define LUT_TURBO_IND 1
|
||||
|
||||
#define GT_IRQ_STATUS BIT(2)
|
||||
|
||||
#define HZ_PER_KHZ 1000
|
||||
|
||||
struct qcom_cpufreq_soc_data {
|
||||
u32 reg_enable;
|
||||
u32 reg_domain_state;
|
||||
u32 reg_dcvs_ctrl;
|
||||
u32 reg_freq_lut;
|
||||
u32 reg_volt_lut;
|
||||
u32 reg_intr_clr;
|
||||
u32 reg_current_vote;
|
||||
u32 reg_perf_state;
|
||||
u8 lut_row_size;
|
||||
@ -280,37 +284,46 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
|
||||
static unsigned long qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
|
||||
{
|
||||
unsigned int val = readl_relaxed(data->base + data->soc_data->reg_current_vote);
|
||||
unsigned int lval;
|
||||
|
||||
return (val & 0x3FF) * 19200;
|
||||
if (data->soc_data->reg_current_vote)
|
||||
lval = readl_relaxed(data->base + data->soc_data->reg_current_vote) & 0x3ff;
|
||||
else
|
||||
lval = readl_relaxed(data->base + data->soc_data->reg_domain_state) & 0xff;
|
||||
|
||||
return lval * xo_rate;
|
||||
}
|
||||
|
||||
static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data->policy;
|
||||
int cpu = cpumask_first(policy->cpus);
|
||||
int cpu = cpumask_first(policy->related_cpus);
|
||||
struct device *dev = get_cpu_device(cpu);
|
||||
unsigned long freq_hz, throttled_freq;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned int freq;
|
||||
|
||||
/*
|
||||
* Get the h/w throttled frequency, normalize it using the
|
||||
* registered opp table and use it to calculate thermal pressure.
|
||||
*/
|
||||
freq = qcom_lmh_get_throttle_freq(data);
|
||||
freq_hz = freq * HZ_PER_KHZ;
|
||||
freq_hz = qcom_lmh_get_throttle_freq(data);
|
||||
|
||||
opp = dev_pm_opp_find_freq_floor(dev, &freq_hz);
|
||||
if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
|
||||
dev_pm_opp_find_freq_ceil(dev, &freq_hz);
|
||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq_hz);
|
||||
|
||||
throttled_freq = freq_hz / HZ_PER_KHZ;
|
||||
if (IS_ERR(opp)) {
|
||||
dev_warn(dev, "Can't find the OPP for throttling: %pe!\n", opp);
|
||||
} else {
|
||||
throttled_freq = freq_hz / HZ_PER_KHZ;
|
||||
|
||||
/* Update thermal pressure (the boost frequencies are accepted) */
|
||||
arch_update_thermal_pressure(policy->related_cpus, throttled_freq);
|
||||
/* Update thermal pressure (the boost frequencies are accepted) */
|
||||
arch_update_thermal_pressure(policy->related_cpus, throttled_freq);
|
||||
|
||||
dev_pm_opp_put(opp);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the unlikely case policy is unregistered do not enable
|
||||
@ -350,6 +363,10 @@ static irqreturn_t qcom_lmh_dcvs_handle_irq(int irq, void *data)
|
||||
disable_irq_nosync(c_data->throttle_irq);
|
||||
schedule_delayed_work(&c_data->throttle_work, 0);
|
||||
|
||||
if (c_data->soc_data->reg_intr_clr)
|
||||
writel_relaxed(GT_IRQ_STATUS,
|
||||
c_data->base + c_data->soc_data->reg_intr_clr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -365,9 +382,11 @@ static const struct qcom_cpufreq_soc_data qcom_soc_data = {
|
||||
|
||||
static const struct qcom_cpufreq_soc_data epss_soc_data = {
|
||||
.reg_enable = 0x0,
|
||||
.reg_domain_state = 0x20,
|
||||
.reg_dcvs_ctrl = 0xb0,
|
||||
.reg_freq_lut = 0x100,
|
||||
.reg_volt_lut = 0x200,
|
||||
.reg_intr_clr = 0x308,
|
||||
.reg_perf_state = 0x320,
|
||||
.lut_row_size = 4,
|
||||
};
|
||||
@ -417,16 +436,39 @@ static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_cpufreq_hw_lmh_exit(struct qcom_cpufreq_data *data)
|
||||
static int qcom_cpufreq_hw_cpu_online(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct qcom_cpufreq_data *data = policy->driver_data;
|
||||
struct platform_device *pdev = cpufreq_get_driver_data();
|
||||
int ret;
|
||||
|
||||
ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
|
||||
data->irq_name, data->throttle_irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_cpufreq_hw_cpu_offline(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct qcom_cpufreq_data *data = policy->driver_data;
|
||||
|
||||
if (data->throttle_irq <= 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
mutex_lock(&data->throttle_lock);
|
||||
data->cancel_throttle = true;
|
||||
mutex_unlock(&data->throttle_lock);
|
||||
|
||||
cancel_delayed_work_sync(&data->throttle_work);
|
||||
irq_set_affinity_hint(data->throttle_irq, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_cpufreq_hw_lmh_exit(struct qcom_cpufreq_data *data)
|
||||
{
|
||||
free_irq(data->throttle_irq, data);
|
||||
}
|
||||
|
||||
@ -583,6 +625,8 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
|
||||
.get = qcom_cpufreq_hw_get,
|
||||
.init = qcom_cpufreq_hw_cpu_init,
|
||||
.exit = qcom_cpufreq_hw_cpu_exit,
|
||||
.online = qcom_cpufreq_hw_cpu_online,
|
||||
.offline = qcom_cpufreq_hw_cpu_offline,
|
||||
.register_em = cpufreq_register_em_with_opp,
|
||||
.fast_switch = qcom_cpufreq_hw_fast_switch,
|
||||
.name = "qcom-cpufreq-hw",
|
||||
|
@ -98,8 +98,10 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sun50i_cpufreq_get_efuse(&speed);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
kfree(opp_tables);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snprintf(name, MAX_NAME_LEN, "speed%d", speed);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user