Skip to content

Commit 8e5b477

Browse files
committed
Merge branches 'pm-cpufreq' and 'pm-cpuidle'
Merge cpufreq and cpuidle updates for 5.16-rc1: - Fix cpu->pstate.turbo_freq initialization in intel_pstate (Zhang Rui). - Make intel_pstate process HWP Guaranteed change notifications from the processor (Srinivas Pandruvada). - Fix typo in cpufreq.h (Rafael Wysocki). - Fix tegra driver to handle BPMP errors properly (Mikko Perttunen). - Fix the parameter usage of the newly added perf-domain API (Hector Yuan). - Minor cleanups to cppc, vexpress and s3c244x drivers (Han Wang, Guenter Roeck, and Arnd Bergmann). - Fix kobject memory leaks in cpuidle error paths (Anel Orazgaliyeva). - Make intel_idle enable interrupts before entering C1 on some Xeon processor models (Artem Bityutskiy). * pm-cpufreq: cpufreq: Fix parameter in parse_perf_domain() cpufreq: intel_pstate: Fix cpu->pstate.turbo_freq initialization cpufreq: Fix typo in cpufreq.h cpufreq: intel_pstate: Process HWP Guaranteed change notification cpufreq: tegra186/tegra194: Handle errors in BPMP response cpufreq: remove useless INIT_LIST_HEAD() cpufreq: s3c244x: add fallthrough comments for switch cpufreq: vexpress: Drop unused variable * pm-cpuidle: cpuidle: Fix kobject memory leaks in error paths intel_idle: enable interrupts before C1 on Xeons
3 parents b62b306 + 19ea8a0 + e5f5a66 commit 8e5b477

File tree

8 files changed

+143
-15
lines changed

8 files changed

+143
-15
lines changed

drivers/cpufreq/cppc_cpufreq.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,6 @@ static int __init cppc_cpufreq_init(void)
741741
if ((acpi_disabled) || !acpi_cpc_valid())
742742
return -ENODEV;
743743

744-
INIT_LIST_HEAD(&cpu_data_list);
745-
746744
cppc_check_hisi_workaround();
747745
cppc_freq_invariance_init();
748746

drivers/cpufreq/intel_pstate.c

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <asm/cpu_device_id.h>
3333
#include <asm/cpufeature.h>
3434
#include <asm/intel-family.h>
35+
#include "../drivers/thermal/intel/thermal_interrupt.h"
3536

3637
#define INTEL_PSTATE_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC)
3738

@@ -219,6 +220,7 @@ struct global_params {
219220
* @sched_flags: Store scheduler flags for possible cross CPU update
220221
* @hwp_boost_min: Last HWP boosted min performance
221222
* @suspended: Whether or not the driver has been suspended.
223+
* @hwp_notify_work: workqueue for HWP notifications.
222224
*
223225
* This structure stores per CPU instance data for all CPUs.
224226
*/
@@ -257,6 +259,7 @@ struct cpudata {
257259
unsigned int sched_flags;
258260
u32 hwp_boost_min;
259261
bool suspended;
262+
struct delayed_work hwp_notify_work;
260263
};
261264

262265
static struct cpudata **all_cpu_data;
@@ -537,7 +540,8 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
537540
* scaling factor is too high, so recompute it to make the HWP_CAP
538541
* highest performance correspond to the maximum turbo frequency.
539542
*/
540-
if (turbo_freq < cpu->pstate.turbo_pstate * scaling) {
543+
cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
544+
if (turbo_freq < cpu->pstate.turbo_freq) {
541545
cpu->pstate.turbo_freq = turbo_freq;
542546
scaling = DIV_ROUND_UP(turbo_freq, cpu->pstate.turbo_pstate);
543547
cpu->pstate.scaling = scaling;
@@ -985,11 +989,15 @@ static void intel_pstate_hwp_set(unsigned int cpu)
985989
wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
986990
}
987991

992+
static void intel_pstate_disable_hwp_interrupt(struct cpudata *cpudata);
993+
988994
static void intel_pstate_hwp_offline(struct cpudata *cpu)
989995
{
990996
u64 value = READ_ONCE(cpu->hwp_req_cached);
991997
int min_perf;
992998

999+
intel_pstate_disable_hwp_interrupt(cpu);
1000+
9931001
if (boot_cpu_has(X86_FEATURE_HWP_EPP)) {
9941002
/*
9951003
* In case the EPP has been set to "performance" by the
@@ -1053,6 +1061,9 @@ static int intel_pstate_suspend(struct cpufreq_policy *policy)
10531061

10541062
cpu->suspended = true;
10551063

1064+
/* disable HWP interrupt and cancel any pending work */
1065+
intel_pstate_disable_hwp_interrupt(cpu);
1066+
10561067
return 0;
10571068
}
10581069

@@ -1546,15 +1557,105 @@ static void intel_pstate_sysfs_hide_hwp_dynamic_boost(void)
15461557

15471558
/************************** sysfs end ************************/
15481559

1560+
static void intel_pstate_notify_work(struct work_struct *work)
1561+
{
1562+
struct cpudata *cpudata =
1563+
container_of(to_delayed_work(work), struct cpudata, hwp_notify_work);
1564+
1565+
cpufreq_update_policy(cpudata->cpu);
1566+
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0);
1567+
}
1568+
1569+
static DEFINE_SPINLOCK(hwp_notify_lock);
1570+
static cpumask_t hwp_intr_enable_mask;
1571+
1572+
void notify_hwp_interrupt(void)
1573+
{
1574+
unsigned int this_cpu = smp_processor_id();
1575+
struct cpudata *cpudata;
1576+
unsigned long flags;
1577+
u64 value;
1578+
1579+
if (!READ_ONCE(hwp_active) || !boot_cpu_has(X86_FEATURE_HWP_NOTIFY))
1580+
return;
1581+
1582+
rdmsrl_safe(MSR_HWP_STATUS, &value);
1583+
if (!(value & 0x01))
1584+
return;
1585+
1586+
spin_lock_irqsave(&hwp_notify_lock, flags);
1587+
1588+
if (!cpumask_test_cpu(this_cpu, &hwp_intr_enable_mask))
1589+
goto ack_intr;
1590+
1591+
/*
1592+
* Currently we never free all_cpu_data. And we can't reach here
1593+
* without this allocated. But for safety for future changes, added
1594+
* check.
1595+
*/
1596+
if (unlikely(!READ_ONCE(all_cpu_data)))
1597+
goto ack_intr;
1598+
1599+
/*
1600+
* The free is done during cleanup, when cpufreq registry is failed.
1601+
* We wouldn't be here if it fails on init or switch status. But for
1602+
* future changes, added check.
1603+
*/
1604+
cpudata = READ_ONCE(all_cpu_data[this_cpu]);
1605+
if (unlikely(!cpudata))
1606+
goto ack_intr;
1607+
1608+
schedule_delayed_work(&cpudata->hwp_notify_work, msecs_to_jiffies(10));
1609+
1610+
spin_unlock_irqrestore(&hwp_notify_lock, flags);
1611+
1612+
return;
1613+
1614+
ack_intr:
1615+
wrmsrl_safe(MSR_HWP_STATUS, 0);
1616+
spin_unlock_irqrestore(&hwp_notify_lock, flags);
1617+
}
1618+
1619+
static void intel_pstate_disable_hwp_interrupt(struct cpudata *cpudata)
1620+
{
1621+
unsigned long flags;
1622+
1623+
/* wrmsrl_on_cpu has to be outside spinlock as this can result in IPC */
1624+
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
1625+
1626+
spin_lock_irqsave(&hwp_notify_lock, flags);
1627+
if (cpumask_test_and_clear_cpu(cpudata->cpu, &hwp_intr_enable_mask))
1628+
cancel_delayed_work(&cpudata->hwp_notify_work);
1629+
spin_unlock_irqrestore(&hwp_notify_lock, flags);
1630+
}
1631+
1632+
static void intel_pstate_enable_hwp_interrupt(struct cpudata *cpudata)
1633+
{
1634+
/* Enable HWP notification interrupt for guaranteed performance change */
1635+
if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) {
1636+
unsigned long flags;
1637+
1638+
spin_lock_irqsave(&hwp_notify_lock, flags);
1639+
INIT_DELAYED_WORK(&cpudata->hwp_notify_work, intel_pstate_notify_work);
1640+
cpumask_set_cpu(cpudata->cpu, &hwp_intr_enable_mask);
1641+
spin_unlock_irqrestore(&hwp_notify_lock, flags);
1642+
1643+
/* wrmsrl_on_cpu has to be outside spinlock as this can result in IPC */
1644+
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x01);
1645+
}
1646+
}
1647+
15491648
static void intel_pstate_hwp_enable(struct cpudata *cpudata)
15501649
{
1551-
/* First disable HWP notification interrupt as we don't process them */
1650+
/* First disable HWP notification interrupt till we activate again */
15521651
if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY))
15531652
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
15541653

15551654
wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
15561655
if (cpudata->epp_default == -EINVAL)
15571656
cpudata->epp_default = intel_pstate_get_epp(cpudata, 0);
1657+
1658+
intel_pstate_enable_hwp_interrupt(cpudata);
15581659
}
15591660

15601661
static int atom_get_min_pstate(void)
@@ -2266,7 +2367,7 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
22662367
if (!cpu)
22672368
return -ENOMEM;
22682369

2269-
all_cpu_data[cpunum] = cpu;
2370+
WRITE_ONCE(all_cpu_data[cpunum], cpu);
22702371

22712372
cpu->cpu = cpunum;
22722373

@@ -2929,8 +3030,10 @@ static void intel_pstate_driver_cleanup(void)
29293030
if (intel_pstate_driver == &intel_pstate)
29303031
intel_pstate_clear_update_util_hook(cpu);
29313032

3033+
spin_lock(&hwp_notify_lock);
29323034
kfree(all_cpu_data[cpu]);
2933-
all_cpu_data[cpu] = NULL;
3035+
WRITE_ONCE(all_cpu_data[cpu], NULL);
3036+
spin_unlock(&hwp_notify_lock);
29343037
}
29353038
}
29363039
cpus_read_unlock();
@@ -3199,6 +3302,7 @@ static bool intel_pstate_hwp_is_enabled(void)
31993302

32003303
static int __init intel_pstate_init(void)
32013304
{
3305+
static struct cpudata **_all_cpu_data;
32023306
const struct x86_cpu_id *id;
32033307
int rc;
32043308

@@ -3224,7 +3328,7 @@ static int __init intel_pstate_init(void)
32243328
* deal with it.
32253329
*/
32263330
if ((!no_hwp && boot_cpu_has(X86_FEATURE_HWP_EPP)) || hwp_forced) {
3227-
hwp_active++;
3331+
WRITE_ONCE(hwp_active, 1);
32283332
hwp_mode_bdw = id->driver_data;
32293333
intel_pstate.attr = hwp_cpufreq_attrs;
32303334
intel_cpufreq.attr = hwp_cpufreq_attrs;
@@ -3275,10 +3379,12 @@ static int __init intel_pstate_init(void)
32753379

32763380
pr_info("Intel P-state driver initializing\n");
32773381

3278-
all_cpu_data = vzalloc(array_size(sizeof(void *), num_possible_cpus()));
3279-
if (!all_cpu_data)
3382+
_all_cpu_data = vzalloc(array_size(sizeof(void *), num_possible_cpus()));
3383+
if (!_all_cpu_data)
32803384
return -ENOMEM;
32813385

3386+
WRITE_ONCE(all_cpu_data, _all_cpu_data);
3387+
32823388
intel_pstate_request_control_from_smm();
32833389

32843390
intel_pstate_sysfs_expose_params();

drivers/cpufreq/s3c2440-cpufreq.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,14 @@ static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
173173

174174
case 6:
175175
camdiv |= S3C2440_CAMDIVN_HCLK3_HALF;
176+
fallthrough;
176177
case 3:
177178
clkdiv |= S3C2440_CLKDIVN_HDIVN_3_6;
178179
break;
179180

180181
case 8:
181182
camdiv |= S3C2440_CAMDIVN_HCLK4_HALF;
183+
fallthrough;
182184
case 4:
183185
clkdiv |= S3C2440_CLKDIVN_HDIVN_4_8;
184186
break;

drivers/cpufreq/tegra186-cpufreq.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ static struct cpufreq_frequency_table *init_vhint_table(
159159
table = ERR_PTR(err);
160160
goto free;
161161
}
162+
if (msg.rx.ret) {
163+
table = ERR_PTR(-EINVAL);
164+
goto free;
165+
}
162166

163167
for (i = data->vfloor; i <= data->vceil; i++) {
164168
u16 ndiv = data->ndiv[i];

drivers/cpufreq/tegra194-cpufreq.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
242242

243243
smp_call_function_single(policy->cpu, get_cpu_cluster, &cl, true);
244244

245-
if (cl >= data->num_clusters)
245+
if (cl >= data->num_clusters || !data->tables[cl])
246246
return -EINVAL;
247247

248248
/* set same policy for all cpus in a cluster */
@@ -310,6 +310,12 @@ init_freq_table(struct platform_device *pdev, struct tegra_bpmp *bpmp,
310310
err = tegra_bpmp_transfer(bpmp, &msg);
311311
if (err)
312312
return ERR_PTR(err);
313+
if (msg.rx.ret == -BPMP_EINVAL) {
314+
/* Cluster not available */
315+
return NULL;
316+
}
317+
if (msg.rx.ret)
318+
return ERR_PTR(-EINVAL);
313319

314320
/*
315321
* Make sure frequency table step is a multiple of mdiv to match

drivers/cpuidle/sysfs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
488488
&kdev->kobj, "state%d", i);
489489
if (ret) {
490490
kobject_put(&kobj->kobj);
491+
kfree(kobj);
491492
goto error_state;
492493
}
493494
cpuidle_add_s2idle_attr_group(kobj);
@@ -619,6 +620,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
619620
&kdev->kobj, "driver");
620621
if (ret) {
621622
kobject_put(&kdrv->kobj);
623+
kfree(kdrv);
622624
return ret;
623625
}
624626

@@ -705,17 +707,18 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev)
705707
if (!kdev)
706708
return -ENOMEM;
707709
kdev->dev = dev;
708-
dev->kobj_dev = kdev;
709710

710711
init_completion(&kdev->kobj_unregister);
711712

712713
error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
713714
"cpuidle");
714715
if (error) {
715716
kobject_put(&kdev->kobj);
717+
kfree(kdev);
716718
return error;
717719
}
718720

721+
dev->kobj_dev = kdev;
719722
kobject_uevent(&kdev->kobj, KOBJ_ADD);
720723

721724
return 0;

drivers/idle/intel_idle.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ static struct cpuidle_state *cpuidle_state_table __initdata;
8888

8989
static unsigned int mwait_substates __initdata;
9090

91+
/*
92+
* Enable interrupts before entering the C-state. On some platforms and for
93+
* some C-states, this may measurably decrease interrupt latency.
94+
*/
95+
#define CPUIDLE_FLAG_IRQ_ENABLE BIT(14)
96+
9197
/*
9298
* Enable this state by default even if the ACPI _CST does not list it.
9399
*/
@@ -127,6 +133,9 @@ static __cpuidle int intel_idle(struct cpuidle_device *dev,
127133
unsigned long eax = flg2MWAIT(state->flags);
128134
unsigned long ecx = 1; /* break on interrupt flag */
129135

136+
if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE)
137+
local_irq_enable();
138+
130139
mwait_idle_with_hints(eax, ecx);
131140

132141
return index;
@@ -698,7 +707,7 @@ static struct cpuidle_state skx_cstates[] __initdata = {
698707
{
699708
.name = "C1",
700709
.desc = "MWAIT 0x00",
701-
.flags = MWAIT2flg(0x00),
710+
.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_IRQ_ENABLE,
702711
.exit_latency = 2,
703712
.target_residency = 2,
704713
.enter = &intel_idle,
@@ -727,7 +736,7 @@ static struct cpuidle_state icx_cstates[] __initdata = {
727736
{
728737
.name = "C1",
729738
.desc = "MWAIT 0x00",
730-
.flags = MWAIT2flg(0x00),
739+
.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_IRQ_ENABLE,
731740
.exit_latency = 1,
732741
.target_residency = 1,
733742
.enter = &intel_idle,

include/linux/cpufreq.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ struct cpufreq_driver {
385385
/* flags */
386386

387387
/*
388-
* Set by drivers that need to update internale upper and lower boundaries along
388+
* Set by drivers that need to update internal upper and lower boundaries along
389389
* with the target frequency and so the core and governors should also invoke
390390
* the diver if the target frequency does not change, but the policy min or max
391391
* may have changed.
@@ -1041,7 +1041,7 @@ static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_
10411041
if (cpu == pcpu)
10421042
continue;
10431043

1044-
ret = parse_perf_domain(pcpu, list_name, cell_name);
1044+
ret = parse_perf_domain(cpu, list_name, cell_name);
10451045
if (ret < 0)
10461046
continue;
10471047

0 commit comments

Comments
 (0)