Skip to content

Commit 659ed6e

Browse files
committed
Merge tag 'pm-5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael Wysocki: "These fix up recent intel_idle driver changes and fix some ARM cpufreq driver issues. Specifics: - Fix issues with the Qualcomm's cpufreq driver (Dmitry Baryshkov, Vladimir Zapolskiy). - Fix memory leak with the Sun501 driver (Xiaobing Luo). - Make intel_idle enable C1E promotion on all CPUs when C1E is preferred to C1 (Artem Bityutskiy). - Make C6 optimization on Sapphire Rapids added recently work as expected if both C1E and C1 are "preferred" (Artem Bityutskiy)" * tag 'pm-5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: intel_idle: Fix SPR C6 optimization intel_idle: Fix the 'preferred_cstates' module parameter 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
2 parents f12d31c + edbd977 commit 659ed6e

File tree

3 files changed

+75
-26
lines changed

3 files changed

+75
-26
lines changed

drivers/cpufreq/qcom-cpufreq-hw.c

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@
2424
#define CLK_HW_DIV 2
2525
#define LUT_TURBO_IND 1
2626

27+
#define GT_IRQ_STATUS BIT(2)
28+
2729
#define HZ_PER_KHZ 1000
2830

2931
struct qcom_cpufreq_soc_data {
3032
u32 reg_enable;
33+
u32 reg_domain_state;
3134
u32 reg_dcvs_ctrl;
3235
u32 reg_freq_lut;
3336
u32 reg_volt_lut;
37+
u32 reg_intr_clr;
3438
u32 reg_current_vote;
3539
u32 reg_perf_state;
3640
u8 lut_row_size;
@@ -280,37 +284,46 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
280284
}
281285
}
282286

283-
static unsigned int qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
287+
static unsigned long qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
284288
{
285-
unsigned int val = readl_relaxed(data->base + data->soc_data->reg_current_vote);
289+
unsigned int lval;
290+
291+
if (data->soc_data->reg_current_vote)
292+
lval = readl_relaxed(data->base + data->soc_data->reg_current_vote) & 0x3ff;
293+
else
294+
lval = readl_relaxed(data->base + data->soc_data->reg_domain_state) & 0xff;
286295

287-
return (val & 0x3FF) * 19200;
296+
return lval * xo_rate;
288297
}
289298

290299
static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
291300
{
292301
struct cpufreq_policy *policy = data->policy;
293-
int cpu = cpumask_first(policy->cpus);
302+
int cpu = cpumask_first(policy->related_cpus);
294303
struct device *dev = get_cpu_device(cpu);
295304
unsigned long freq_hz, throttled_freq;
296305
struct dev_pm_opp *opp;
297-
unsigned int freq;
298306

299307
/*
300308
* Get the h/w throttled frequency, normalize it using the
301309
* registered opp table and use it to calculate thermal pressure.
302310
*/
303-
freq = qcom_lmh_get_throttle_freq(data);
304-
freq_hz = freq * HZ_PER_KHZ;
311+
freq_hz = qcom_lmh_get_throttle_freq(data);
305312

306313
opp = dev_pm_opp_find_freq_floor(dev, &freq_hz);
307314
if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
308-
dev_pm_opp_find_freq_ceil(dev, &freq_hz);
315+
opp = dev_pm_opp_find_freq_ceil(dev, &freq_hz);
316+
317+
if (IS_ERR(opp)) {
318+
dev_warn(dev, "Can't find the OPP for throttling: %pe!\n", opp);
319+
} else {
320+
throttled_freq = freq_hz / HZ_PER_KHZ;
309321

310-
throttled_freq = freq_hz / HZ_PER_KHZ;
322+
/* Update thermal pressure (the boost frequencies are accepted) */
323+
arch_update_thermal_pressure(policy->related_cpus, throttled_freq);
311324

312-
/* Update thermal pressure (the boost frequencies are accepted) */
313-
arch_update_thermal_pressure(policy->related_cpus, throttled_freq);
325+
dev_pm_opp_put(opp);
326+
}
314327

315328
/*
316329
* 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)
350363
disable_irq_nosync(c_data->throttle_irq);
351364
schedule_delayed_work(&c_data->throttle_work, 0);
352365

366+
if (c_data->soc_data->reg_intr_clr)
367+
writel_relaxed(GT_IRQ_STATUS,
368+
c_data->base + c_data->soc_data->reg_intr_clr);
369+
353370
return IRQ_HANDLED;
354371
}
355372

@@ -365,9 +382,11 @@ static const struct qcom_cpufreq_soc_data qcom_soc_data = {
365382

366383
static const struct qcom_cpufreq_soc_data epss_soc_data = {
367384
.reg_enable = 0x0,
385+
.reg_domain_state = 0x20,
368386
.reg_dcvs_ctrl = 0xb0,
369387
.reg_freq_lut = 0x100,
370388
.reg_volt_lut = 0x200,
389+
.reg_intr_clr = 0x308,
371390
.reg_perf_state = 0x320,
372391
.lut_row_size = 4,
373392
};
@@ -417,16 +436,39 @@ static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
417436
return 0;
418437
}
419438

420-
static void qcom_cpufreq_hw_lmh_exit(struct qcom_cpufreq_data *data)
439+
static int qcom_cpufreq_hw_cpu_online(struct cpufreq_policy *policy)
440+
{
441+
struct qcom_cpufreq_data *data = policy->driver_data;
442+
struct platform_device *pdev = cpufreq_get_driver_data();
443+
int ret;
444+
445+
ret = irq_set_affinity_hint(data->throttle_irq, policy->cpus);
446+
if (ret)
447+
dev_err(&pdev->dev, "Failed to set CPU affinity of %s[%d]\n",
448+
data->irq_name, data->throttle_irq);
449+
450+
return ret;
451+
}
452+
453+
static int qcom_cpufreq_hw_cpu_offline(struct cpufreq_policy *policy)
421454
{
455+
struct qcom_cpufreq_data *data = policy->driver_data;
456+
422457
if (data->throttle_irq <= 0)
423-
return;
458+
return 0;
424459

425460
mutex_lock(&data->throttle_lock);
426461
data->cancel_throttle = true;
427462
mutex_unlock(&data->throttle_lock);
428463

429464
cancel_delayed_work_sync(&data->throttle_work);
465+
irq_set_affinity_hint(data->throttle_irq, NULL);
466+
467+
return 0;
468+
}
469+
470+
static void qcom_cpufreq_hw_lmh_exit(struct qcom_cpufreq_data *data)
471+
{
430472
free_irq(data->throttle_irq, data);
431473
}
432474

@@ -583,6 +625,8 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
583625
.get = qcom_cpufreq_hw_get,
584626
.init = qcom_cpufreq_hw_cpu_init,
585627
.exit = qcom_cpufreq_hw_cpu_exit,
628+
.online = qcom_cpufreq_hw_cpu_online,
629+
.offline = qcom_cpufreq_hw_cpu_offline,
586630
.register_em = cpufreq_register_em_with_opp,
587631
.fast_switch = qcom_cpufreq_hw_fast_switch,
588632
.name = "qcom-cpufreq-hw",

drivers/cpufreq/sun50i-cpufreq-nvmem.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,10 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
9898
return -ENOMEM;
9999

100100
ret = sun50i_cpufreq_get_efuse(&speed);
101-
if (ret)
101+
if (ret) {
102+
kfree(opp_tables);
102103
return ret;
104+
}
103105

104106
snprintf(name, MAX_NAME_LEN, "speed%d", speed);
105107

drivers/idle/intel_idle.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,12 @@ static unsigned int preferred_states_mask;
6969
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
7070

7171
static unsigned long auto_demotion_disable_flags;
72-
static bool disable_promotion_to_c1e;
72+
73+
static enum {
74+
C1E_PROMOTION_PRESERVE,
75+
C1E_PROMOTION_ENABLE,
76+
C1E_PROMOTION_DISABLE
77+
} c1e_promotion = C1E_PROMOTION_PRESERVE;
7378

7479
struct idle_cpu {
7580
struct cpuidle_state *state_table;
@@ -1398,8 +1403,6 @@ static inline void intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) { }
13981403
static inline bool intel_idle_off_by_default(u32 mwait_hint) { return false; }
13991404
#endif /* !CONFIG_ACPI_PROCESSOR_CSTATE */
14001405

1401-
static void c1e_promotion_enable(void);
1402-
14031406
/**
14041407
* ivt_idle_state_table_update - Tune the idle states table for Ivy Town.
14051408
*
@@ -1578,17 +1581,14 @@ static void __init spr_idle_state_table_update(void)
15781581
unsigned long long msr;
15791582

15801583
/* Check if user prefers C1E over C1. */
1581-
if (preferred_states_mask & BIT(2)) {
1582-
if (preferred_states_mask & BIT(1))
1583-
/* Both can't be enabled, stick to the defaults. */
1584-
return;
1585-
1584+
if ((preferred_states_mask & BIT(2)) &&
1585+
!(preferred_states_mask & BIT(1))) {
1586+
/* Disable C1 and enable C1E. */
15861587
spr_cstates[0].flags |= CPUIDLE_FLAG_UNUSABLE;
15871588
spr_cstates[1].flags &= ~CPUIDLE_FLAG_UNUSABLE;
15881589

15891590
/* Enable C1E using the "C1E promotion" bit. */
1590-
c1e_promotion_enable();
1591-
disable_promotion_to_c1e = false;
1591+
c1e_promotion = C1E_PROMOTION_ENABLE;
15921592
}
15931593

15941594
/*
@@ -1754,7 +1754,9 @@ static int intel_idle_cpu_init(unsigned int cpu)
17541754
if (auto_demotion_disable_flags)
17551755
auto_demotion_disable();
17561756

1757-
if (disable_promotion_to_c1e)
1757+
if (c1e_promotion == C1E_PROMOTION_ENABLE)
1758+
c1e_promotion_enable();
1759+
else if (c1e_promotion == C1E_PROMOTION_DISABLE)
17581760
c1e_promotion_disable();
17591761

17601762
return 0;
@@ -1833,7 +1835,8 @@ static int __init intel_idle_init(void)
18331835
if (icpu) {
18341836
cpuidle_state_table = icpu->state_table;
18351837
auto_demotion_disable_flags = icpu->auto_demotion_disable_flags;
1836-
disable_promotion_to_c1e = icpu->disable_promotion_to_c1e;
1838+
if (icpu->disable_promotion_to_c1e)
1839+
c1e_promotion = C1E_PROMOTION_DISABLE;
18371840
if (icpu->use_acpi || force_use_acpi)
18381841
intel_idle_acpi_cst_extract();
18391842
} else if (!intel_idle_acpi_cst_extract()) {

0 commit comments

Comments
 (0)