18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * lib/smp_processor_id.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * DEBUG_PREEMPT variant of smp_processor_id().
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/export.h>
88c2ecf20Sopenharmony_ci#include <linux/kprobes.h>
98c2ecf20Sopenharmony_ci#include <linux/sched.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cinoinstr static
128c2ecf20Sopenharmony_ciunsigned int check_preemption_disabled(const char *what1, const char *what2)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	int this_cpu = raw_smp_processor_id();
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	if (likely(preempt_count()))
178c2ecf20Sopenharmony_ci		goto out;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	if (irqs_disabled())
208c2ecf20Sopenharmony_ci		goto out;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	/*
238c2ecf20Sopenharmony_ci	 * Kernel threads bound to a single CPU can safely use
248c2ecf20Sopenharmony_ci	 * smp_processor_id():
258c2ecf20Sopenharmony_ci	 */
268c2ecf20Sopenharmony_ci	if (current->nr_cpus_allowed == 1)
278c2ecf20Sopenharmony_ci		goto out;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	/*
308c2ecf20Sopenharmony_ci	 * It is valid to assume CPU-locality during early bootup:
318c2ecf20Sopenharmony_ci	 */
328c2ecf20Sopenharmony_ci	if (system_state < SYSTEM_SCHEDULING)
338c2ecf20Sopenharmony_ci		goto out;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/*
368c2ecf20Sopenharmony_ci	 * Avoid recursion:
378c2ecf20Sopenharmony_ci	 */
388c2ecf20Sopenharmony_ci	preempt_disable_notrace();
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	instrumentation_begin();
418c2ecf20Sopenharmony_ci	if (!printk_ratelimit())
428c2ecf20Sopenharmony_ci		goto out_enable;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	printk(KERN_ERR "BUG: using %s%s() in preemptible [%08x] code: %s/%d\n",
458c2ecf20Sopenharmony_ci		what1, what2, preempt_count() - 1, current->comm, current->pid);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	printk("caller is %pS\n", __builtin_return_address(0));
488c2ecf20Sopenharmony_ci	dump_stack();
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciout_enable:
518c2ecf20Sopenharmony_ci	instrumentation_end();
528c2ecf20Sopenharmony_ci	preempt_enable_no_resched_notrace();
538c2ecf20Sopenharmony_ciout:
548c2ecf20Sopenharmony_ci	return this_cpu;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cinoinstr unsigned int debug_smp_processor_id(void)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	return check_preemption_disabled("smp_processor_id", "");
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(debug_smp_processor_id);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cinoinstr void __this_cpu_preempt_check(const char *op)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	check_preemption_disabled("__this_cpu_", op);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__this_cpu_preempt_check);
68