trace_irqsoff.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. /*
  2. * trace irqs off critical timings
  3. *
  4. * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  5. * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
  6. *
  7. * From code in the latency_tracer, that is:
  8. *
  9. * Copyright (C) 2004-2006 Ingo Molnar
  10. * Copyright (C) 2004 Nadia Yvette Chambers
  11. */
  12. #include <linux/kallsyms.h>
  13. #include <linux/uaccess.h>
  14. #include <linux/module.h>
  15. #include <linux/ftrace.h>
  16. #include <mt-plat/mtk_sched_mon.h>
  17. #include "trace.h"
  18. #define CREATE_TRACE_POINTS
  19. #include <trace/events/preemptirq.h>
  20. #if defined(CONFIG_IRQSOFF_TRACER) || defined(CONFIG_PREEMPT_TRACER)
  21. static struct trace_array *irqsoff_trace __read_mostly;
  22. static int tracer_enabled __read_mostly;
  23. static DEFINE_PER_CPU(int, tracing_cpu);
  24. static DEFINE_RAW_SPINLOCK(max_trace_lock);
  25. enum {
  26. TRACER_IRQS_OFF = (1 << 1),
  27. TRACER_PREEMPT_OFF = (1 << 2),
  28. };
  29. static int trace_type __read_mostly;
  30. static int save_flags;
  31. static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
  32. static int start_irqsoff_tracer(struct trace_array *tr, int graph);
  33. #ifdef CONFIG_PREEMPT_TRACER
  34. static inline int
  35. preempt_trace(void)
  36. {
  37. return ((trace_type & TRACER_PREEMPT_OFF) && preempt_count());
  38. }
  39. #else
  40. # define preempt_trace() (0)
  41. #endif
  42. #ifdef CONFIG_IRQSOFF_TRACER
  43. static inline int
  44. irq_trace(void)
  45. {
  46. return ((trace_type & TRACER_IRQS_OFF) &&
  47. irqs_disabled());
  48. }
  49. #else
  50. # define irq_trace() (0)
  51. #endif
  52. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  53. static int irqsoff_display_graph(struct trace_array *tr, int set);
  54. # define is_graph(tr) ((tr)->trace_flags & TRACE_ITER_DISPLAY_GRAPH)
  55. #else
  56. static inline int irqsoff_display_graph(struct trace_array *tr, int set)
  57. {
  58. return -EINVAL;
  59. }
  60. # define is_graph(tr) false
  61. #endif
  62. /*
  63. * Sequence count - we record it when starting a measurement and
  64. * skip the latency if the sequence has changed - some other section
  65. * did a maximum and could disturb our measurement with serial console
  66. * printouts, etc. Truly coinciding maximum latencies should be rare
  67. * and what happens together happens separately as well, so this doesn't
  68. * decrease the validity of the maximum found:
  69. */
  70. static __cacheline_aligned_in_smp unsigned long max_sequence;
  71. #ifdef CONFIG_FUNCTION_TRACER
  72. /*
  73. * Prologue for the preempt and irqs off function tracers.
  74. *
  75. * Returns 1 if it is OK to continue, and data->disabled is
  76. * incremented.
  77. * 0 if the trace is to be ignored, and data->disabled
  78. * is kept the same.
  79. *
  80. * Note, this function is also used outside this ifdef but
  81. * inside the #ifdef of the function graph tracer below.
  82. * This is OK, since the function graph tracer is
  83. * dependent on the function tracer.
  84. */
  85. static int func_prolog_dec(struct trace_array *tr,
  86. struct trace_array_cpu **data,
  87. unsigned long *flags)
  88. {
  89. long disabled;
  90. int cpu;
  91. /*
  92. * Does not matter if we preempt. We test the flags
  93. * afterward, to see if irqs are disabled or not.
  94. * If we preempt and get a false positive, the flags
  95. * test will fail.
  96. */
  97. cpu = raw_smp_processor_id();
  98. if (likely(!per_cpu(tracing_cpu, cpu)))
  99. return 0;
  100. local_save_flags(*flags);
  101. /*
  102. * Slight chance to get a false positive on tracing_cpu,
  103. * although I'm starting to think there isn't a chance.
  104. * Leave this for now just to be paranoid.
  105. */
  106. if (!irqs_disabled_flags(*flags) && !preempt_count())
  107. return 0;
  108. *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
  109. disabled = atomic_inc_return(&(*data)->disabled);
  110. if (likely(disabled == 1))
  111. return 1;
  112. atomic_dec(&(*data)->disabled);
  113. return 0;
  114. }
  115. /*
  116. * irqsoff uses its own tracer function to keep the overhead down:
  117. */
  118. static void
  119. irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip,
  120. struct ftrace_ops *op, struct pt_regs *pt_regs)
  121. {
  122. struct trace_array *tr = irqsoff_trace;
  123. struct trace_array_cpu *data;
  124. unsigned long flags;
  125. if (!func_prolog_dec(tr, &data, &flags))
  126. return;
  127. trace_function(tr, ip, parent_ip, flags, preempt_count());
  128. atomic_dec(&data->disabled);
  129. }
  130. #endif /* CONFIG_FUNCTION_TRACER */
  131. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  132. static int irqsoff_display_graph(struct trace_array *tr, int set)
  133. {
  134. int cpu;
  135. if (!(is_graph(tr) ^ set))
  136. return 0;
  137. stop_irqsoff_tracer(irqsoff_trace, !set);
  138. for_each_possible_cpu(cpu)
  139. per_cpu(tracing_cpu, cpu) = 0;
  140. tr->max_latency = 0;
  141. tracing_reset_online_cpus(&irqsoff_trace->trace_buffer);
  142. return start_irqsoff_tracer(irqsoff_trace, set);
  143. }
  144. static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
  145. {
  146. struct trace_array *tr = irqsoff_trace;
  147. struct trace_array_cpu *data;
  148. unsigned long flags;
  149. int ret;
  150. int pc;
  151. if (ftrace_graph_ignore_func(trace))
  152. return 0;
  153. /*
  154. * Do not trace a function if it's filtered by set_graph_notrace.
  155. * Make the index of ret stack negative to indicate that it should
  156. * ignore further functions. But it needs its own ret stack entry
  157. * to recover the original index in order to continue tracing after
  158. * returning from the function.
  159. */
  160. if (ftrace_graph_notrace_addr(trace->func))
  161. return 1;
  162. if (!func_prolog_dec(tr, &data, &flags))
  163. return 0;
  164. pc = preempt_count();
  165. ret = __trace_graph_entry(tr, trace, flags, pc);
  166. atomic_dec(&data->disabled);
  167. return ret;
  168. }
  169. static void irqsoff_graph_return(struct ftrace_graph_ret *trace)
  170. {
  171. struct trace_array *tr = irqsoff_trace;
  172. struct trace_array_cpu *data;
  173. unsigned long flags;
  174. int pc;
  175. ftrace_graph_addr_finish(trace);
  176. if (!func_prolog_dec(tr, &data, &flags))
  177. return;
  178. pc = preempt_count();
  179. __trace_graph_return(tr, trace, flags, pc);
  180. atomic_dec(&data->disabled);
  181. }
  182. static void irqsoff_trace_open(struct trace_iterator *iter)
  183. {
  184. if (is_graph(iter->tr))
  185. graph_trace_open(iter);
  186. }
  187. static void irqsoff_trace_close(struct trace_iterator *iter)
  188. {
  189. if (iter->private)
  190. graph_trace_close(iter);
  191. }
  192. #define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_CPU | \
  193. TRACE_GRAPH_PRINT_PROC | \
  194. TRACE_GRAPH_PRINT_ABS_TIME | \
  195. TRACE_GRAPH_PRINT_DURATION)
  196. static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
  197. {
  198. /*
  199. * In graph mode call the graph tracer output function,
  200. * otherwise go with the TRACE_FN event handler
  201. */
  202. if (is_graph(iter->tr))
  203. return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
  204. return TRACE_TYPE_UNHANDLED;
  205. }
  206. static void irqsoff_print_header(struct seq_file *s)
  207. {
  208. struct trace_array *tr = irqsoff_trace;
  209. if (is_graph(tr))
  210. print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
  211. else
  212. trace_default_header(s);
  213. }
  214. static void
  215. __trace_function(struct trace_array *tr,
  216. unsigned long ip, unsigned long parent_ip,
  217. unsigned long flags, int pc)
  218. {
  219. if (is_graph(tr))
  220. trace_graph_function(tr, ip, parent_ip, flags, pc);
  221. else
  222. trace_function(tr, ip, parent_ip, flags, pc);
  223. }
  224. #else
  225. #define __trace_function trace_function
  226. #ifdef CONFIG_FUNCTION_TRACER
  227. static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
  228. {
  229. return -1;
  230. }
  231. #endif
  232. static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
  233. {
  234. return TRACE_TYPE_UNHANDLED;
  235. }
  236. static void irqsoff_trace_open(struct trace_iterator *iter) { }
  237. static void irqsoff_trace_close(struct trace_iterator *iter) { }
  238. #ifdef CONFIG_FUNCTION_TRACER
  239. static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
  240. static void irqsoff_print_header(struct seq_file *s)
  241. {
  242. trace_default_header(s);
  243. }
  244. #else
  245. static void irqsoff_print_header(struct seq_file *s)
  246. {
  247. trace_latency_header(s);
  248. }
  249. #endif /* CONFIG_FUNCTION_TRACER */
  250. #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
  251. /*
  252. * Should this new latency be reported/recorded?
  253. */
  254. static bool report_latency(struct trace_array *tr, u64 delta)
  255. {
  256. if (tracing_thresh) {
  257. if (delta < tracing_thresh)
  258. return false;
  259. } else {
  260. if (delta <= tr->max_latency)
  261. return false;
  262. }
  263. return true;
  264. }
  265. static void
  266. check_critical_timing(struct trace_array *tr,
  267. struct trace_array_cpu *data,
  268. unsigned long parent_ip,
  269. int cpu)
  270. {
  271. u64 T0, T1, delta;
  272. unsigned long flags;
  273. int pc;
  274. T0 = data->preempt_timestamp;
  275. T1 = ftrace_now(cpu);
  276. delta = T1-T0;
  277. local_save_flags(flags);
  278. pc = preempt_count();
  279. if (!report_latency(tr, delta))
  280. goto out;
  281. raw_spin_lock_irqsave(&max_trace_lock, flags);
  282. /* check if we are still the max latency */
  283. if (!report_latency(tr, delta))
  284. goto out_unlock;
  285. __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc);
  286. /* Skip 5 functions to get to the irq/preempt enable function */
  287. __trace_stack(tr, flags, 5, pc);
  288. if (data->critical_sequence != max_sequence)
  289. goto out_unlock;
  290. data->critical_end = parent_ip;
  291. if (likely(!is_tracing_stopped())) {
  292. tr->max_latency = delta;
  293. update_max_tr_single(tr, current, cpu);
  294. }
  295. max_sequence++;
  296. out_unlock:
  297. raw_spin_unlock_irqrestore(&max_trace_lock, flags);
  298. out:
  299. data->critical_sequence = max_sequence;
  300. data->preempt_timestamp = ftrace_now(cpu);
  301. __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc);
  302. }
  303. static inline void
  304. start_critical_timing(unsigned long ip, unsigned long parent_ip)
  305. {
  306. int cpu;
  307. struct trace_array *tr = irqsoff_trace;
  308. struct trace_array_cpu *data;
  309. unsigned long flags;
  310. if (!tracer_enabled || !tracing_is_enabled())
  311. return;
  312. cpu = raw_smp_processor_id();
  313. if (per_cpu(tracing_cpu, cpu))
  314. return;
  315. data = per_cpu_ptr(tr->trace_buffer.data, cpu);
  316. if (unlikely(!data) || atomic_read(&data->disabled))
  317. return;
  318. atomic_inc(&data->disabled);
  319. data->critical_sequence = max_sequence;
  320. data->preempt_timestamp = ftrace_now(cpu);
  321. data->critical_start = parent_ip ? : ip;
  322. local_save_flags(flags);
  323. __trace_function(tr, ip, parent_ip, flags, preempt_count());
  324. per_cpu(tracing_cpu, cpu) = 1;
  325. atomic_dec(&data->disabled);
  326. }
  327. static inline void
  328. stop_critical_timing(unsigned long ip, unsigned long parent_ip)
  329. {
  330. int cpu;
  331. struct trace_array *tr = irqsoff_trace;
  332. struct trace_array_cpu *data;
  333. unsigned long flags;
  334. cpu = raw_smp_processor_id();
  335. /* Always clear the tracing cpu on stopping the trace */
  336. if (unlikely(per_cpu(tracing_cpu, cpu)))
  337. per_cpu(tracing_cpu, cpu) = 0;
  338. else
  339. return;
  340. if (!tracer_enabled || !tracing_is_enabled())
  341. return;
  342. data = per_cpu_ptr(tr->trace_buffer.data, cpu);
  343. if (unlikely(!data) ||
  344. !data->critical_start || atomic_read(&data->disabled))
  345. return;
  346. atomic_inc(&data->disabled);
  347. local_save_flags(flags);
  348. __trace_function(tr, ip, parent_ip, flags, preempt_count());
  349. check_critical_timing(tr, data, parent_ip ? : ip, cpu);
  350. data->critical_start = 0;
  351. atomic_dec(&data->disabled);
  352. }
  353. /* start and stop critical timings used to for stoppage (in idle) */
  354. void start_critical_timings(void)
  355. {
  356. if (preempt_trace() || irq_trace())
  357. start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  358. }
  359. EXPORT_SYMBOL_GPL(start_critical_timings);
  360. void stop_critical_timings(void)
  361. {
  362. if (preempt_trace() || irq_trace())
  363. stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  364. }
  365. EXPORT_SYMBOL_GPL(stop_critical_timings);
  366. #ifdef CONFIG_IRQSOFF_TRACER
  367. #ifdef CONFIG_PROVE_LOCKING
  368. void time_hardirqs_on(unsigned long a0, unsigned long a1)
  369. {
  370. if (!preempt_trace() && irq_trace())
  371. stop_critical_timing(a0, a1);
  372. }
  373. void time_hardirqs_off(unsigned long a0, unsigned long a1)
  374. {
  375. if (!preempt_trace() && irq_trace())
  376. start_critical_timing(a0, a1);
  377. }
  378. #else /* !CONFIG_PROVE_LOCKING */
  379. /*
  380. * We are only interested in hardirq on/off events:
  381. */
  382. static inline void tracer_hardirqs_on(void)
  383. {
  384. if (!preempt_trace() && irq_trace())
  385. stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  386. }
  387. static inline void tracer_hardirqs_off(void)
  388. {
  389. if (!preempt_trace() && irq_trace())
  390. start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  391. }
  392. static inline void tracer_hardirqs_on_caller(unsigned long caller_addr)
  393. {
  394. if (!preempt_trace() && irq_trace())
  395. stop_critical_timing(CALLER_ADDR0, caller_addr);
  396. }
  397. static inline void tracer_hardirqs_off_caller(unsigned long caller_addr)
  398. {
  399. if (!preempt_trace() && irq_trace())
  400. start_critical_timing(CALLER_ADDR0, caller_addr);
  401. }
  402. #endif /* CONFIG_PROVE_LOCKING */
  403. #endif /* CONFIG_IRQSOFF_TRACER */
  404. #ifdef CONFIG_PREEMPT_TRACER
  405. static inline void tracer_preempt_on(unsigned long a0, unsigned long a1)
  406. {
  407. if (preempt_trace() && !irq_trace())
  408. stop_critical_timing(a0, a1);
  409. }
  410. static inline void tracer_preempt_off(unsigned long a0, unsigned long a1)
  411. {
  412. if (preempt_trace() && !irq_trace())
  413. start_critical_timing(a0, a1);
  414. }
  415. #endif /* CONFIG_PREEMPT_TRACER */
  416. #ifdef CONFIG_FUNCTION_TRACER
  417. static bool function_enabled;
  418. static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
  419. {
  420. int ret;
  421. /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
  422. if (function_enabled || (!set && !(tr->trace_flags & TRACE_ITER_FUNCTION)))
  423. return 0;
  424. if (graph)
  425. ret = register_ftrace_graph(&irqsoff_graph_return,
  426. &irqsoff_graph_entry);
  427. else
  428. ret = register_ftrace_function(tr->ops);
  429. if (!ret)
  430. function_enabled = true;
  431. return ret;
  432. }
  433. static void unregister_irqsoff_function(struct trace_array *tr, int graph)
  434. {
  435. if (!function_enabled)
  436. return;
  437. if (graph)
  438. unregister_ftrace_graph();
  439. else
  440. unregister_ftrace_function(tr->ops);
  441. function_enabled = false;
  442. }
  443. static int irqsoff_function_set(struct trace_array *tr, u32 mask, int set)
  444. {
  445. if (!(mask & TRACE_ITER_FUNCTION))
  446. return 0;
  447. if (set)
  448. register_irqsoff_function(tr, is_graph(tr), 1);
  449. else
  450. unregister_irqsoff_function(tr, is_graph(tr));
  451. return 1;
  452. }
  453. #else
  454. static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
  455. {
  456. return 0;
  457. }
  458. static void unregister_irqsoff_function(struct trace_array *tr, int graph) { }
  459. static inline int irqsoff_function_set(struct trace_array *tr, u32 mask, int set)
  460. {
  461. return 0;
  462. }
  463. #endif /* CONFIG_FUNCTION_TRACER */
  464. static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set)
  465. {
  466. struct tracer *tracer = tr->current_trace;
  467. if (irqsoff_function_set(tr, mask, set))
  468. return 0;
  469. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  470. if (mask & TRACE_ITER_DISPLAY_GRAPH)
  471. return irqsoff_display_graph(tr, set);
  472. #endif
  473. return trace_keep_overwrite(tracer, mask, set);
  474. }
  475. static int start_irqsoff_tracer(struct trace_array *tr, int graph)
  476. {
  477. int ret;
  478. ret = register_irqsoff_function(tr, graph, 0);
  479. if (!ret && tracing_is_enabled())
  480. tracer_enabled = 1;
  481. else
  482. tracer_enabled = 0;
  483. return ret;
  484. }
  485. static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
  486. {
  487. tracer_enabled = 0;
  488. unregister_irqsoff_function(tr, graph);
  489. }
  490. static bool irqsoff_busy;
  491. static int __irqsoff_tracer_init(struct trace_array *tr)
  492. {
  493. if (irqsoff_busy)
  494. return -EBUSY;
  495. save_flags = tr->trace_flags;
  496. /* non overwrite screws up the latency tracers */
  497. set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
  498. set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
  499. tr->max_latency = 0;
  500. irqsoff_trace = tr;
  501. /* make sure that the tracer is visible */
  502. smp_wmb();
  503. ftrace_init_array_ops(tr, irqsoff_tracer_call);
  504. /* Only toplevel instance supports graph tracing */
  505. if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL &&
  506. is_graph(tr))))
  507. printk(KERN_ERR "failed to start irqsoff tracer\n");
  508. irqsoff_busy = true;
  509. return 0;
  510. }
  511. static void irqsoff_tracer_reset(struct trace_array *tr)
  512. {
  513. int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
  514. int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
  515. stop_irqsoff_tracer(tr, is_graph(tr));
  516. set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
  517. set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
  518. ftrace_reset_array_ops(tr);
  519. irqsoff_busy = false;
  520. }
  521. static void irqsoff_tracer_start(struct trace_array *tr)
  522. {
  523. tracer_enabled = 1;
  524. }
  525. static void irqsoff_tracer_stop(struct trace_array *tr)
  526. {
  527. tracer_enabled = 0;
  528. }
  529. #ifdef CONFIG_IRQSOFF_TRACER
  530. static int irqsoff_tracer_init(struct trace_array *tr)
  531. {
  532. trace_type = TRACER_IRQS_OFF;
  533. return __irqsoff_tracer_init(tr);
  534. }
  535. static struct tracer irqsoff_tracer __read_mostly =
  536. {
  537. .name = "irqsoff",
  538. .init = irqsoff_tracer_init,
  539. .reset = irqsoff_tracer_reset,
  540. .start = irqsoff_tracer_start,
  541. .stop = irqsoff_tracer_stop,
  542. .print_max = true,
  543. .print_header = irqsoff_print_header,
  544. .print_line = irqsoff_print_line,
  545. .flag_changed = irqsoff_flag_changed,
  546. #ifdef CONFIG_FTRACE_SELFTEST
  547. .selftest = trace_selftest_startup_irqsoff,
  548. #endif
  549. .open = irqsoff_trace_open,
  550. .close = irqsoff_trace_close,
  551. .allow_instances = true,
  552. .use_max_tr = true,
  553. };
  554. # define register_irqsoff(trace) register_tracer(&trace)
  555. #else
  556. # define register_irqsoff(trace) do { } while (0)
  557. #endif
  558. #ifdef CONFIG_PREEMPT_TRACER
  559. static int preemptoff_tracer_init(struct trace_array *tr)
  560. {
  561. trace_type = TRACER_PREEMPT_OFF;
  562. return __irqsoff_tracer_init(tr);
  563. }
  564. static struct tracer preemptoff_tracer __read_mostly =
  565. {
  566. .name = "preemptoff",
  567. .init = preemptoff_tracer_init,
  568. .reset = irqsoff_tracer_reset,
  569. .start = irqsoff_tracer_start,
  570. .stop = irqsoff_tracer_stop,
  571. .print_max = true,
  572. .print_header = irqsoff_print_header,
  573. .print_line = irqsoff_print_line,
  574. .flag_changed = irqsoff_flag_changed,
  575. #ifdef CONFIG_FTRACE_SELFTEST
  576. .selftest = trace_selftest_startup_preemptoff,
  577. #endif
  578. .open = irqsoff_trace_open,
  579. .close = irqsoff_trace_close,
  580. .allow_instances = true,
  581. .use_max_tr = true,
  582. };
  583. # define register_preemptoff(trace) register_tracer(&trace)
  584. #else
  585. # define register_preemptoff(trace) do { } while (0)
  586. #endif
  587. #if defined(CONFIG_IRQSOFF_TRACER) && \
  588. defined(CONFIG_PREEMPT_TRACER)
  589. static int preemptirqsoff_tracer_init(struct trace_array *tr)
  590. {
  591. trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF;
  592. return __irqsoff_tracer_init(tr);
  593. }
  594. static struct tracer preemptirqsoff_tracer __read_mostly =
  595. {
  596. .name = "preemptirqsoff",
  597. .init = preemptirqsoff_tracer_init,
  598. .reset = irqsoff_tracer_reset,
  599. .start = irqsoff_tracer_start,
  600. .stop = irqsoff_tracer_stop,
  601. .print_max = true,
  602. .print_header = irqsoff_print_header,
  603. .print_line = irqsoff_print_line,
  604. .flag_changed = irqsoff_flag_changed,
  605. #ifdef CONFIG_FTRACE_SELFTEST
  606. .selftest = trace_selftest_startup_preemptirqsoff,
  607. #endif
  608. .open = irqsoff_trace_open,
  609. .close = irqsoff_trace_close,
  610. .allow_instances = true,
  611. .use_max_tr = true,
  612. };
  613. # define register_preemptirqsoff(trace) register_tracer(&trace)
  614. #else
  615. # define register_preemptirqsoff(trace) do { } while (0)
  616. #endif
  617. __init static int init_irqsoff_tracer(void)
  618. {
  619. register_irqsoff(irqsoff_tracer);
  620. register_preemptoff(preemptoff_tracer);
  621. register_preemptirqsoff(preemptirqsoff_tracer);
  622. return 0;
  623. }
  624. core_initcall(init_irqsoff_tracer);
  625. #endif /* IRQSOFF_TRACER || PREEMPTOFF_TRACER */
  626. #ifndef CONFIG_IRQSOFF_TRACER
  627. static inline void tracer_hardirqs_on(void) { }
  628. static inline void tracer_hardirqs_off(void) { }
  629. static inline void tracer_hardirqs_on_caller(unsigned long caller_addr) { }
  630. static inline void tracer_hardirqs_off_caller(unsigned long caller_addr) { }
  631. #endif
  632. #ifndef CONFIG_PREEMPT_TRACER
  633. static inline void tracer_preempt_on(unsigned long a0, unsigned long a1) { }
  634. static inline void tracer_preempt_off(unsigned long a0, unsigned long a1) { }
  635. #endif
  636. #if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PROVE_LOCKING)
  637. /* Per-cpu variable to prevent redundant calls when IRQs already off */
  638. static DEFINE_PER_CPU(int, tracing_irq_cpu);
  639. void trace_hardirqs_on(void)
  640. {
  641. if (!this_cpu_read(tracing_irq_cpu))
  642. return;
  643. trace_irq_enable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
  644. trace_hardirqs_on_time();
  645. tracer_hardirqs_on();
  646. this_cpu_write(tracing_irq_cpu, 0);
  647. }
  648. EXPORT_SYMBOL(trace_hardirqs_on);
  649. void trace_hardirqs_off(void)
  650. {
  651. if (this_cpu_read(tracing_irq_cpu))
  652. return;
  653. this_cpu_write(tracing_irq_cpu, 1);
  654. trace_irq_disable_rcuidle(CALLER_ADDR0, CALLER_ADDR1);
  655. trace_hardirqs_off_time();
  656. tracer_hardirqs_off();
  657. }
  658. EXPORT_SYMBOL(trace_hardirqs_off);
  659. __visible void trace_hardirqs_on_caller(unsigned long caller_addr)
  660. {
  661. if (!this_cpu_read(tracing_irq_cpu))
  662. return;
  663. trace_irq_enable_rcuidle(CALLER_ADDR0, caller_addr);
  664. tracer_hardirqs_on_caller(caller_addr);
  665. this_cpu_write(tracing_irq_cpu, 0);
  666. }
  667. EXPORT_SYMBOL(trace_hardirqs_on_caller);
  668. __visible void trace_hardirqs_off_caller(unsigned long caller_addr)
  669. {
  670. if (this_cpu_read(tracing_irq_cpu))
  671. return;
  672. this_cpu_write(tracing_irq_cpu, 1);
  673. trace_irq_disable_rcuidle(CALLER_ADDR0, caller_addr);
  674. tracer_hardirqs_off_caller(caller_addr);
  675. }
  676. EXPORT_SYMBOL(trace_hardirqs_off_caller);
  677. /*
  678. * Stubs:
  679. */
  680. void trace_softirqs_on(unsigned long ip)
  681. {
  682. }
  683. void trace_softirqs_off(unsigned long ip)
  684. {
  685. }
  686. inline void print_irqtrace_events(struct task_struct *curr)
  687. {
  688. }
  689. #endif
  690. #if defined(CONFIG_PREEMPT_TRACER) || \
  691. (defined(CONFIG_DEBUG_PREEMPT) && defined(CONFIG_PREEMPTIRQ_EVENTS))
  692. void trace_preempt_on(unsigned long a0, unsigned long a1)
  693. {
  694. trace_preempt_enable_rcuidle(a0, a1);
  695. trace_preempt_on_time();
  696. tracer_preempt_on(a0, a1);
  697. }
  698. void trace_preempt_off(unsigned long a0, unsigned long a1)
  699. {
  700. trace_preempt_disable_rcuidle(a0, a1);
  701. trace_preempt_off_time();
  702. tracer_preempt_off(a0, a1);
  703. }
  704. #endif