diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 7f8b4cd626a..c3d4c0b6c29 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -4,7 +4,7 @@ * Copyright (C) 2001 Russell King * (C) 2003 Venkatesh Pallipadi . * Jun Nakajima - * (c) 2013 The Linux Foundation. All rights reserved. + * (c) 2013, 2015 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -108,6 +108,7 @@ struct cpu_dbs_info_s { struct task_struct *sync_thread; wait_queue_head_t sync_wq; atomic_t src_sync_cpu; + atomic_t being_woken; atomic_t sync_enabled; }; static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info); @@ -1087,7 +1088,16 @@ static int dbs_migration_notify(struct notifier_block *nb, &per_cpu(od_cpu_dbs_info, target_cpu); atomic_set(&target_dbs_info->src_sync_cpu, (int)arg); - wake_up(&target_dbs_info->sync_wq); + /* + * Avoid issuing recursive wakeup call, as sync thread itself could be + * seen as migrating triggering this notification. Note that sync thread + * of a cpu could be running for a short while with its affinity broken + * because of CPU hotplug. + */ + if (!atomic_cmpxchg(&target_dbs_info->being_woken, 0, 1)) { + wake_up(&target_dbs_info->sync_wq); + atomic_set(&target_dbs_info->being_woken, 0); + } return NOTIFY_OK; } @@ -1442,6 +1452,7 @@ static int __init cpufreq_gov_dbs_init(void) dbs_work->cpu = i; atomic_set(&this_dbs_info->src_sync_cpu, -1); + atomic_set(&this_dbs_info->being_woken, 0); init_waitqueue_head(&this_dbs_info->sync_wq); this_dbs_info->sync_thread = kthread_run(dbs_sync_thread,