diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-05-05 17:22:39 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-05-05 17:22:40 -0600 |
| commit | 375fb2964fd726d47368d55a12a1ddd33f3b268c (patch) | |
| tree | 4144efeebb520780e4de36d0e6462a744a2426ba /kernel | |
| parent | e21bff20d36cf0fb5fbe62d02ade9ee0858bd8d5 (diff) | |
| parent | 7fa8b4c857a2e0148b951e7a8547f74ed55a42ae (diff) | |
Promotion of kernel.lnx.4.4-160504.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
998828 I757329e68af439701b8f065c99a6a4b0c390cba2 msm: mdss: Add mdp capability to expose writeback interf
980569 I97ff3d53c12ed163ae5dbec184ed9445c901459e msm: ipa: Fix suspend bit clearing on disconnected pipe
954074 If98ef69e2474f1c50670c2605afe9769a4e0fb39 PFK: ice: change to non-atomic scm calls
1011902 Ie94ffce93d28d08610310885e4f257ebdbc15dd1 msm: vidc: Allow zero length qbuf
978768 I22696b17ec6ff11b1a378df9611eb8ab4be01358 msm: mdss: hdmi: update switch node on hpd off
1011445 I53bcd8293f7587ddba64ed0e019b77eee62b5e72 icnss: Enable SMMU BYPASS mode
993480 I61a48353428b3faa042fbc85e259b33c7f23bdb0 msm: kgsl: Remove harmless preemption log message
1011086 985182 I39d3d234222b6136ab0e68367e13c1276dce61f6 soc: qcom: rpm_master_stat: Add additional debug stats
1000506 Ie742148fe3b04677365a7247a89c2bed412e4d31 msm: ipa: Fix to update the descriptor length in SG scen
973565 If54caf008c654f488986a279bd19bea97457dc2c msm: kgsl: Disable ISENSE CGC
1003233 Ic36aaa86b7799c962a1128d16f0ec670698e8570 defconfig: arm64: msm: Enable IOMMU debug tracking
987074 Iae380e0f44dd53bee8ff4cec347a6b9a632b1f84 msm: kgsl: Don't spam kmsg due to invalid IOCTL requests
1005492 Ibc5ee5145dee3980ddca3d9922663eb96420d011 msm: ipa: odu: change IPC logging to common buffer
971156 Ibdf6fef6f3f700f3c5315c228c0473e47fb62163 msm: kgsl: Purge unused #defines
989004 Id5f244a57a2b991a10b603ef7236193d4282fd0f msm: kgsl: Remove superfluous NULL checks when reading t
1011110 I2000cab0a56a890cbd5503306a794e6b9b295db6 msm: camera: Correct hardware register settings for CSIP
1002547 Ifbecd46f8e3f8e93d846da3dfc72f7ef70687589 msm: cpp: Ignore input validation for sof freeze/unfreez
1007342 I904ee0b08079972b181f53fdc5a6022871da74e8 irqchip: irq-msm: Remove pinctrl_irq_dummy(..) hook
1005036 I8cd2403bed66141c99ccf8b9c57e59b936c1d90e clk: msm: clock-gcc-cobalt: Add clock reset support for
994283 I611155901e928fa8d9bbcbdf2511cd98aa36df2c ipa: Fix holb monitor response handling from Uc
1007342 I9016aadac88483c8547ed1a40cb6c55909f347cf irqchip: irq-msm: Delete irq-msm.c
1001217 1008552 Id326c73f78f3fadb5193a1e840f295d764fb013b msm: vidc: Set constrained intra refresh property
1010331 I50231b6c219e6a54379f6b94a23486a320ade09e ARM: dts: msm: update VDD_GFX CPR parameters for msmcoba
1010111 I7f254f579182effbc1f1a3d49c3c917d3c7af162 msm: thermal: Make boot-up mitigation optional
993738 Ie615ef440ab613f0b4f0601500188068440c29fe msm: camera: Avoid uninitialized variables
1009871 I57496aeb47d907f540a25c854ef7b35c6b5ab399 msm: jpeg: Expose JPEG DMA max downscale to user space
1007822 I23800a58459b0d9b15168cbef409374495e59ee1 edac: cortex: Update the CPU name
978768 I9556c6457258598e6b6758573bb0263d53e612da msm: mdss: hdmi: check for scrambler override
971174 Iaa113c8414a2d2d8f92b3cb21eaf2e422f273454 msm: kgsl: Add MMU offset mapping functions
1010111 If144319371a5c65f193ffac8fb9852a836125966 msm: thermal: Reorganize KTM probe function
1007266 Icb876f16cac9471c523f3ef5b5fd3ede9d5d597c msm: thermal: Prolong KTM mitigation till thermal-engine
1010111 Ica59aeb0c94581e3c37b5b7df16c187ced45c28a msm: thermal: Remove proactive vdd restriction during pr
1009268 I2d38454fce77a895f0aaf18e01f7d0c9f3c64692 regulator: cpr3-mmss-regulator: update reference voltage
1007459 Ic9dd60923198f38117843e9e087287fac294c197 defconfig: msmcortex: Enable workqueue watchdog
1010715 I2144bacc11190b92d14b00480dd538e27d13c3e1 ARM: dts: msm: Add qcom,msm-imem-diag-dload node on msmc
972831 I005041820e3721536693c892f5bc1d8d977dd770 defconfig: msm: sde: Add config for v4l2 sde rotator dri
1001770 I622fd971201b6c0001212a696c3d12aea409c11b Revert "spmi: pmic_arb: use handle_fasteoi_irq handler"
1010595 Ie1b74b6a3eac563ee34865655b046f71411aca65 AndroidKernel.mk: Enforce KERNEL_OBJ generation
1000754 If66039ff752741e44b00175a7cc73681e7ca16ae Revert "ARM: dts: msm: disable UFS LPM modes for msmcoba
986130 I552094c64bd9fb360ddd73022fe21a403c245b2f msm_11ad: keep rf_clk3 on during wil6210 activity
1006743 I9b565a34e2068bf575974eaf3dc9f7820bdd7a96 mm/page_owner: ask users about default setting of PAGE_O
992317 I43e08ccefbf2d3911191b2aad5168979956e1626 msm: kgsl: Dump 64KB of preemption record in snapshot
1011086 Ie5c9236ad34ea61a375a4a3ae1f1d91fda0a9ccf drivers: soc: qcom: rpm_stats: Switch to use arch_counte
994759 Ib3006067e184bf97adf75971ab96b2c673909eba ARM: dts: msm: Set the high bank bit value for MSMcobalt
1006743 I35602327d75945c35126ce2d657803d786a44121 defconfig: msmcortex: Enable PAGE_OWNER and DEBUG_PAGEAL
1009871 Idb3780f0ce3d8c0b3f659aee2c0806b20c7f1379 ARM: dts: msm: Add JPEG DMA max downscale node for msmco
1002205 I789cdec6f056b17a605f3454e6cd5702542c454f msm: ipa: Fix to accessing ipa_q6_clnt handle
1009142 Idae5097ee0247589885328c9e55b65f981a261c2 ARM: dts: msm: update VDD_APC CPR settings for msmcobalt
999965 I2d7d74e48ce80aa18cab2d42191db8d5edb4a076 msm: ipa: Fix to release IPA clock during ap suspend
1009142 I6a6cb1096cc91ac995dbc36c8edaaa20c392e6c8 ARM: dts: msm: enable VDD_APC CPR HW closed-loop operati
984991 Id5a5128edb379308fa91b53062b6773af1b6de18 msm: ipa: Fix to QMI initialization and polling state
1008505 Ie3d3889cc6c35011f239468ddf465c553a6b1c97 msm: mdss: Skip setting up Qseed3 for non-vig pipes
1003233 I65e7fe7d8f94ba3ac6a3d9030f15fd5a0b97c188 ARM: dts: msm: Add IOMMU test device nodes for 8996 and
1010715 I076928436a8b1b4d1c3ee7e48db9b3314ec1fc05 usb: gadget: f_diag: Update serial_number with dload_coo
1007344 I0bf7b33c3584f3d6cf5ef58dfe72be46212041da lib: memtest: Add MEMTEST_ENABLE_DEFAULT option
1011110 Ieee68a709a1f56d53bd2746fa28fbd76195270b0 ARM: dts: msm: Correct camera nodes for msmcobalt
1000756 I2d2e651ba554812198d721892e14ca1a61a34027 ARM: dts: msm: setup external clock sources for DSI cloc
1009142 I6af5a0bd5ddb5fdb22585f9da34524475f49233f regulator: cprh-kbss-regulator: update corner switch del
1007459 Id7dfbbd2701128a942b1bcac2299e07a66db8657 workqueue: implement lockup detector
978768 Ib48c02b2b89f7fdb347afd3a02d8b6b7c1c03e85 msm: mdss: hdmi: refactor event handler
971172 If426fb7599be0a79b6f37b8008a2310b1c006e93 msm: kgsl: Clean up adreno trace code
1007351 Iff58832a535227ea071ce5b14d537d9993f9dfc2 lib: Makefile: Ignore Kasan errors reported from the fin
1011086 Ibceaa8f948e203c39e3df55b135c0a394f39ca5f qcom: Port rpm logs and stats driver from 3.18 to 4.4 ke
1007809 I4b68c0e658316b2958d8c9536c3e80e01faf55a4 ARM: dts: msm: Venus PIL clock voting update for MSMCOBA
1010331 Id4beb16d0324ec9c3d62d6d1ead664e215acaaf1 ARM: dts: msm: enable VDD_GFX closed-loop CPR for msmcob
1008505 Icc6ee5e2ba60d7f619393518b4f06aee6f784f3d msm: mdss: update bus scaling macro
1005492 I31acc2008800d213cc69003f9781fee04b5935aa msm: ipa3: mhi: add IPC logging to common buffer
1005492 I69f3536e297eae8453370b44f66ec0f520f16cd5 msm: ipa3: rmnet_ipa: add IPC logging to common buffer
1003233 I6a5802aff5bab99d29c6ed9d953a203cbd8015bb iommu/iommu-debug: Add dummy driver for standalone testi
999530 Iddb5e882e1324e0382359109b86ebcaa26b3d851 defconfig: arm64: msm: enable service notifier and locat
1009865 I70db6555d236857c5a8d62a337afdc9fec22c97f icnss: Add SMMU support
991396 Idb248e1270b79b51e53de687793030a047fe6c73 msm: ipa: Fix memory free issue
971398 Id1e3e0f756ac1c9a0ff4f4e6ce073e80e31473b8 msm: kgsl: Check for failure in coresight initialization
977862 Icac7fb4355ee1fd07e7127ea5c2721665e279272 msm: kgsl: Use a page pool to reduce allocation time
1009471 If11cd577d30c22d79544f4668e08ccf269237236 net: ipc_router: Fail to send resume_tx for local commun
988861 Ifc3ec45297c2a29ad6f7d70dd0bd59238ac8cc3d msm: kgsl: Fix overflow in sharedmem read/write function
978768 Ia305e1eb5d3da1dfbf868650e5ee84018255476b msm: mdss: hdmi: add dynamic fps support
1009810 Ief99a7af7e3f8147469b1b5a68da973ab26a988b ARM: dts: msm: Remove the duplicated RTB dt entry
989231 I2cec6c6f9fe7aea0e2276b01133f8c3505b9919f msm: ipa3: Move IPA headers building to IPAHAL
1010329 I01210f48d32d7d6cb32f4977e52fb46acd33b1ba clk: msm: clock-gcc-cobalt: Add SVS2 frequencies for som
1007515 Iae73d82f6797b8d0628a3f5a31a916d0a43206df defconfig: msm: Enable config parameter for regulatory d
978768 I5b73d3b558af576b5114c42b63260bb688f2d8d1 msm: mdss: hdmi: refactor initialization of features
1007459 I6fe77926acd4240458cab29d399f81d8739a16c0 watchdog: introduce touch_softlockup_watchdog_sched()
1006609 I17d4cc0a38770f0c5067fa8047cd63e7bf085e48 ASoC: msm: audio-effects: misc fixes in h/w accelerated
978768 I52b11f19f576e13e197e8c576a9c5ada54416f5e msm: mdss: fb: reconfigure panel if output format has ch
Change-Id: Ida9a27fac0393dff4104005d722604014da57d7b
CRs-Fixed: 1009871, 986130, 1000756, 1000506, 1000754, 1009142, 1010329, 1005492, 971172, 999965, 1007344, 973565, 1001770, 992317, 1007342, 994283, 1010111, 987074, 984991, 1007266, 1002205, 1001217, 985182, 1007515, 1009810, 1006609, 1006743, 999530, 993480, 1008505, 993738, 972831, 978768, 971174, 1005036, 1007822, 1010595, 954074, 977862, 1011086, 1007809, 1003233, 1010715, 1009865, 1007459, 1011445, 1011110, 980569, 994759, 1010331, 989004, 1007351, 971398, 1009471, 989231, 988861, 1008552, 1011902, 971156, 1009268, 998828, 991396, 1002547
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched/clock.c | 2 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 6 | ||||
| -rw-r--r-- | kernel/watchdog.c | 18 | ||||
| -rw-r--r-- | kernel/workqueue.c | 174 |
4 files changed, 192 insertions, 8 deletions
diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c index caf4041f5b0a..bc54e84675da 100644 --- a/kernel/sched/clock.c +++ b/kernel/sched/clock.c @@ -354,7 +354,7 @@ void sched_clock_idle_wakeup_event(u64 delta_ns) return; sched_clock_tick(); - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); } EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 89dcc6cafa07..7f0f1d8d46b0 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -163,7 +163,7 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs) * when we go busy again does not account too much ticks. */ if (ts->tick_stopped) { - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); if (is_idle_task(current)) ts->idle_jiffies++; } @@ -450,7 +450,7 @@ static void tick_nohz_update_jiffies(ktime_t now) tick_do_update_jiffies64(now); local_irq_restore(flags); - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); } /* @@ -721,7 +721,7 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) update_cpu_load_nohz(); calc_load_exit_idle(); - touch_softlockup_watchdog(); + touch_softlockup_watchdog_sched(); /* * Cancel the scheduled timer and restore the tick */ diff --git a/kernel/watchdog.c b/kernel/watchdog.c index d12d5b86a555..b40f7f35413d 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -20,6 +20,7 @@ #include <linux/smpboot.h> #include <linux/sched/rt.h> #include <linux/tick.h> +#include <linux/workqueue.h> #include <asm/irq_regs.h> #include <linux/kvm_para.h> @@ -232,7 +233,15 @@ static void __touch_watchdog(void) __this_cpu_write(watchdog_touch_ts, get_timestamp()); } -void touch_softlockup_watchdog(void) +/** + * touch_softlockup_watchdog_sched - touch watchdog on scheduler stalls + * + * Call when the scheduler may have stalled for legitimate reasons + * preventing the watchdog task from executing - e.g. the scheduler + * entering idle state. This should only be used for scheduler events. + * Use touch_softlockup_watchdog() for everything else. + */ +void touch_softlockup_watchdog_sched(void) { /* * Preemption can be enabled. It doesn't matter which CPU's timestamp @@ -240,6 +249,12 @@ void touch_softlockup_watchdog(void) */ raw_cpu_write(watchdog_touch_ts, 0); } + +void touch_softlockup_watchdog(void) +{ + touch_softlockup_watchdog_sched(); + wq_watchdog_touch(raw_smp_processor_id()); +} EXPORT_SYMBOL(touch_softlockup_watchdog); void touch_all_softlockup_watchdogs(void) @@ -253,6 +268,7 @@ void touch_all_softlockup_watchdogs(void) */ for_each_watchdog_cpu(cpu) per_cpu(watchdog_touch_ts, cpu) = 0; + wq_watchdog_touch(-1); } #ifdef CONFIG_HARDLOCKUP_DETECTOR diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 15dacf9590cb..58fe79122a61 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -149,6 +149,8 @@ struct worker_pool { int id; /* I: pool ID */ unsigned int flags; /* X: flags */ + unsigned long watchdog_ts; /* L: watchdog timestamp */ + struct list_head worklist; /* L: list of pending works */ int nr_workers; /* L: total number of workers */ @@ -1084,6 +1086,8 @@ static void pwq_activate_delayed_work(struct work_struct *work) struct pool_workqueue *pwq = get_work_pwq(work); trace_workqueue_activate_work(work); + if (list_empty(&pwq->pool->worklist)) + pwq->pool->watchdog_ts = jiffies; move_linked_works(work, &pwq->pool->worklist, NULL); __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); pwq->nr_active++; @@ -1386,6 +1390,8 @@ retry: trace_workqueue_activate_work(work); pwq->nr_active++; worklist = &pwq->pool->worklist; + if (list_empty(worklist)) + pwq->pool->watchdog_ts = jiffies; } else { work_flags |= WORK_STRUCT_DELAYED; worklist = &pwq->delayed_works; @@ -2159,6 +2165,8 @@ recheck: list_first_entry(&pool->worklist, struct work_struct, entry); + pool->watchdog_ts = jiffies; + if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) { /* optimization path, not strictly necessary */ process_one_work(worker, work); @@ -2242,6 +2250,7 @@ repeat: struct pool_workqueue, mayday_node); struct worker_pool *pool = pwq->pool; struct work_struct *work, *n; + bool first = true; __set_current_state(TASK_RUNNING); list_del_init(&pwq->mayday_node); @@ -2258,9 +2267,14 @@ repeat: * process'em. */ WARN_ON_ONCE(!list_empty(scheduled)); - list_for_each_entry_safe(work, n, &pool->worklist, entry) - if (get_work_pwq(work) == pwq) + list_for_each_entry_safe(work, n, &pool->worklist, entry) { + if (get_work_pwq(work) == pwq) { + if (first) + pool->watchdog_ts = jiffies; move_linked_works(work, scheduled, &n); + } + first = false; + } if (!list_empty(scheduled)) { process_scheduled_works(rescuer); @@ -3071,6 +3085,7 @@ static int init_worker_pool(struct worker_pool *pool) pool->cpu = -1; pool->node = NUMA_NO_NODE; pool->flags |= POOL_DISASSOCIATED; + pool->watchdog_ts = jiffies; INIT_LIST_HEAD(&pool->worklist); INIT_LIST_HEAD(&pool->idle_list); hash_init(pool->busy_hash); @@ -4310,7 +4325,9 @@ void show_workqueue_state(void) pr_info("pool %d:", pool->id); pr_cont_pool_info(pool); - pr_cont(" workers=%d", pool->nr_workers); + pr_cont(" hung=%us workers=%d", + jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000, + pool->nr_workers); if (pool->manager) pr_cont(" manager: %d", task_pid_nr(pool->manager->task)); @@ -5169,6 +5186,154 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq) static void workqueue_sysfs_unregister(struct workqueue_struct *wq) { } #endif /* CONFIG_SYSFS */ +/* + * Workqueue watchdog. + * + * Stall may be caused by various bugs - missing WQ_MEM_RECLAIM, illegal + * flush dependency, a concurrency managed work item which stays RUNNING + * indefinitely. Workqueue stalls can be very difficult to debug as the + * usual warning mechanisms don't trigger and internal workqueue state is + * largely opaque. + * + * Workqueue watchdog monitors all worker pools periodically and dumps + * state if some pools failed to make forward progress for a while where + * forward progress is defined as the first item on ->worklist changing. + * + * This mechanism is controlled through the kernel parameter + * "workqueue.watchdog_thresh" which can be updated at runtime through the + * corresponding sysfs parameter file. + */ +#ifdef CONFIG_WQ_WATCHDOG + +static void wq_watchdog_timer_fn(unsigned long data); + +static unsigned long wq_watchdog_thresh = 30; +static struct timer_list wq_watchdog_timer = + TIMER_DEFERRED_INITIALIZER(wq_watchdog_timer_fn, 0, 0); + +static unsigned long wq_watchdog_touched = INITIAL_JIFFIES; +static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES; + +static void wq_watchdog_reset_touched(void) +{ + int cpu; + + wq_watchdog_touched = jiffies; + for_each_possible_cpu(cpu) + per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies; +} + +static void wq_watchdog_timer_fn(unsigned long data) +{ + unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ; + bool lockup_detected = false; + struct worker_pool *pool; + int pi; + + if (!thresh) + return; + + rcu_read_lock(); + + for_each_pool(pool, pi) { + unsigned long pool_ts, touched, ts; + + if (list_empty(&pool->worklist)) + continue; + + /* get the latest of pool and touched timestamps */ + pool_ts = READ_ONCE(pool->watchdog_ts); + touched = READ_ONCE(wq_watchdog_touched); + + if (time_after(pool_ts, touched)) + ts = pool_ts; + else + ts = touched; + + if (pool->cpu >= 0) { + unsigned long cpu_touched = + READ_ONCE(per_cpu(wq_watchdog_touched_cpu, + pool->cpu)); + if (time_after(cpu_touched, ts)) + ts = cpu_touched; + } + + /* did we stall? */ + if (time_after(jiffies, ts + thresh)) { + lockup_detected = true; + pr_emerg("BUG: workqueue lockup - pool"); + pr_cont_pool_info(pool); + pr_cont(" stuck for %us!\n", + jiffies_to_msecs(jiffies - pool_ts) / 1000); + } + } + + rcu_read_unlock(); + + if (lockup_detected) + show_workqueue_state(); + + wq_watchdog_reset_touched(); + mod_timer(&wq_watchdog_timer, jiffies + thresh); +} + +void wq_watchdog_touch(int cpu) +{ + if (cpu >= 0) + per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies; + else + wq_watchdog_touched = jiffies; +} + +static void wq_watchdog_set_thresh(unsigned long thresh) +{ + wq_watchdog_thresh = 0; + del_timer_sync(&wq_watchdog_timer); + + if (thresh) { + wq_watchdog_thresh = thresh; + wq_watchdog_reset_touched(); + mod_timer(&wq_watchdog_timer, jiffies + thresh * HZ); + } +} + +static int wq_watchdog_param_set_thresh(const char *val, + const struct kernel_param *kp) +{ + unsigned long thresh; + int ret; + + ret = kstrtoul(val, 0, &thresh); + if (ret) + return ret; + + if (system_wq) + wq_watchdog_set_thresh(thresh); + else + wq_watchdog_thresh = thresh; + + return 0; +} + +static const struct kernel_param_ops wq_watchdog_thresh_ops = { + .set = wq_watchdog_param_set_thresh, + .get = param_get_ulong, +}; + +module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh, + 0644); + +static void wq_watchdog_init(void) +{ + wq_watchdog_set_thresh(wq_watchdog_thresh); +} + +#else /* CONFIG_WQ_WATCHDOG */ + +static inline void wq_watchdog_init(void) { } + +#endif /* CONFIG_WQ_WATCHDOG */ + static void __init wq_numa_init(void) { cpumask_var_t *tbl; @@ -5292,6 +5457,9 @@ static int __init init_workqueues(void) !system_unbound_wq || !system_freezable_wq || !system_power_efficient_wq || !system_freezable_power_efficient_wq); + + wq_watchdog_init(); + return 0; } early_initcall(init_workqueues); |
