mirror of
https://github.com/torvalds/linux.git
synced 2026-07-30 11:11:26 +02:00
kernel/sched/walt: ensure em_pd creation before rebuild_sched_domains
rebuild_sched_domains() is called during walt_init with the assumption that cpufreq_online has actually completed before the execution of walt_init. This is only partially true. cpufreq_online() will notify update_topology_flags_workfn once the policies have been created. However, the em creation is after this point in time. This creates a race condition between cpufreq_online's creation of the energy model through it's call to register_em(policy), and walt's execution of rebuild_sched_domains. If walt init completes quickly, and rebuild_sched_domains() is executed quickly, it is possible it will complete before the energy model is registered. Thus, the perf domains will still be unpopulated, and the error detection for perf domains will cause the system to crash. Address this by ensuring that the energy model has run for each cpu in the system by checking the same field that em_create_pd must populate for build_perf_domains to work properly, the em_pd field in the cpu device. Additionally ensure that this is only attempted if the domains are not yet setup properly and it is known that corrective action must take place. Change-Id: I8f5150fe4e2e37b3820e809232f26ff207723601 Signed-off-by: Stephen Dickey <quic_dickey@quicinc.com>
This commit is contained in:
parent
c15a0101ac
commit
8327be044c
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/qcom-cpufreq-hw.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/arch_topology.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <trace/hooks/sched.h>
|
||||
#include <trace/hooks/cpufreq.h>
|
||||
|
|
@ -4443,12 +4444,37 @@ static void android_rvh_update_thermal_stats(void *unused, int cpu)
|
|||
}
|
||||
|
||||
static DECLARE_COMPLETION(rebuild_domains_completion);
|
||||
static void rebuild_sd_workfn(struct work_struct *work);
|
||||
static DECLARE_WORK(rebuild_sd_work, rebuild_sd_workfn);
|
||||
|
||||
/** rebuild_sd_workfn
|
||||
*
|
||||
* rebuild the sched domains (and therefore the perf
|
||||
* domains). It is absolutely necessary that the
|
||||
* em_pds are created for each cpu device before
|
||||
* proceeding, and this must complete for walt to
|
||||
* function properly.
|
||||
*/
|
||||
static void rebuild_sd_workfn(struct work_struct *work)
|
||||
{
|
||||
int cpu;
|
||||
struct device *cpu_dev;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
cpu_dev = get_cpu_device(cpu);
|
||||
if (cpu_dev->em_pd)
|
||||
continue;
|
||||
|
||||
WARN_ONCE(true, "must wait for perf domains to be created");
|
||||
schedule_work(&rebuild_sd_work);
|
||||
|
||||
/* do not rebuild domains yet, and do not complete this action */
|
||||
return;
|
||||
}
|
||||
|
||||
rebuild_sched_domains();
|
||||
complete(&rebuild_domains_completion);
|
||||
}
|
||||
static DECLARE_WORK(rebuild_sd_work, rebuild_sd_workfn);
|
||||
|
||||
static void walt_do_sched_yield(void *unused, struct rq *rq)
|
||||
{
|
||||
|
|
@ -4585,8 +4611,22 @@ static void walt_init(struct work_struct *work)
|
|||
walt_cfs_init();
|
||||
walt_halt_init();
|
||||
wait_for_completion_interruptible(&tick_sched_clock_completion);
|
||||
schedule_work(&rebuild_sd_work);
|
||||
wait_for_completion_interruptible(&rebuild_domains_completion);
|
||||
|
||||
if (!rcu_dereference(rd->pd)) {
|
||||
/*
|
||||
* perf domains not properly configured. this is a must as
|
||||
* create_util_to_cost depends on rd->pd being properly
|
||||
* initialized.
|
||||
*/
|
||||
schedule_work(&rebuild_sd_work);
|
||||
wait_for_completion_interruptible(&rebuild_domains_completion);
|
||||
}
|
||||
|
||||
if (!rcu_dereference(rd->pd))
|
||||
WALT_BUG(WALT_BUG_WALT, NULL,
|
||||
"root domain's perf-domain values not initialized rd->pd=%d.",
|
||||
rd->pd);
|
||||
|
||||
stop_machine(walt_init_stop_handler, NULL, NULL);
|
||||
|
||||
hdr = register_sysctl_table(walt_base_table);
|
||||
|
|
@ -4604,11 +4644,6 @@ static void walt_init(struct work_struct *work)
|
|||
}
|
||||
|
||||
topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_ARCH, cpu_online_mask);
|
||||
|
||||
if (!rcu_dereference(rd->pd))
|
||||
WALT_BUG(WALT_BUG_WALT, NULL,
|
||||
"root domain's perf-domain values not initialized rd->pd=%d.",
|
||||
rd->pd);
|
||||
}
|
||||
|
||||
static DECLARE_WORK(walt_init_work, walt_init);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user