wti.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Support for warning track interruption
  4. *
  5. * Copyright IBM Corp. 2023
  6. */
  7. #include <linux/cpu.h>
  8. #include <linux/debugfs.h>
  9. #include <linux/kallsyms.h>
  10. #include <linux/smpboot.h>
  11. #include <linux/irq.h>
  12. #include <uapi/linux/sched/types.h>
  13. #include <asm/debug.h>
  14. #include <asm/diag.h>
  15. #include <asm/sclp.h>
  16. #define WTI_DBF_LEN 64
  17. struct wti_debug {
  18. unsigned long missed;
  19. unsigned long addr;
  20. pid_t pid;
  21. };
  22. struct wti_state {
  23. /* debug data for s390dbf */
  24. struct wti_debug dbg;
  25. /*
  26. * Represents the real-time thread responsible to
  27. * acknowledge the warning-track interrupt and trigger
  28. * preliminary and postliminary precautions.
  29. */
  30. struct task_struct *thread;
  31. /*
  32. * If pending is true, the real-time thread must be scheduled.
  33. * If not, a wake up of that thread will remain a noop.
  34. */
  35. bool pending;
  36. };
  37. static DEFINE_PER_CPU(struct wti_state, wti_state);
  38. static debug_info_t *wti_dbg;
  39. /*
  40. * During a warning-track grace period, interrupts are disabled
  41. * to prevent delays of the warning-track acknowledgment.
  42. *
  43. * Once the CPU is physically dispatched again, interrupts are
  44. * re-enabled.
  45. */
  46. static void wti_irq_disable(void)
  47. {
  48. unsigned long flags;
  49. struct ctlreg cr6;
  50. local_irq_save(flags);
  51. local_ctl_store(6, &cr6);
  52. /* disable all I/O interrupts */
  53. cr6.val &= ~0xff000000UL;
  54. local_ctl_load(6, &cr6);
  55. local_irq_restore(flags);
  56. }
  57. static void wti_irq_enable(void)
  58. {
  59. unsigned long flags;
  60. struct ctlreg cr6;
  61. local_irq_save(flags);
  62. local_ctl_store(6, &cr6);
  63. /* enable all I/O interrupts */
  64. cr6.val |= 0xff000000UL;
  65. local_ctl_load(6, &cr6);
  66. local_irq_restore(flags);
  67. }
  68. static void store_debug_data(struct wti_state *st)
  69. {
  70. struct pt_regs *regs = get_irq_regs();
  71. st->dbg.pid = current->pid;
  72. st->dbg.addr = 0;
  73. if (!user_mode(regs))
  74. st->dbg.addr = regs->psw.addr;
  75. }
  76. static void wti_interrupt(struct ext_code ext_code,
  77. unsigned int param32, unsigned long param64)
  78. {
  79. struct wti_state *st = this_cpu_ptr(&wti_state);
  80. inc_irq_stat(IRQEXT_WTI);
  81. wti_irq_disable();
  82. store_debug_data(st);
  83. st->pending = true;
  84. wake_up_process(st->thread);
  85. }
  86. static int wti_pending(unsigned int cpu)
  87. {
  88. struct wti_state *st = per_cpu_ptr(&wti_state, cpu);
  89. return st->pending;
  90. }
  91. static void wti_dbf_grace_period(struct wti_state *st)
  92. {
  93. struct wti_debug *wdi = &st->dbg;
  94. char buf[WTI_DBF_LEN];
  95. if (wdi->addr)
  96. snprintf(buf, sizeof(buf), "%d %pS", wdi->pid, (void *)wdi->addr);
  97. else
  98. snprintf(buf, sizeof(buf), "%d <user>", wdi->pid);
  99. debug_text_event(wti_dbg, 2, buf);
  100. wdi->missed++;
  101. }
  102. static int wti_show(struct seq_file *seq, void *v)
  103. {
  104. struct wti_state *st;
  105. int cpu;
  106. cpus_read_lock();
  107. seq_puts(seq, " ");
  108. for_each_online_cpu(cpu)
  109. seq_printf(seq, "CPU%-8d", cpu);
  110. seq_putc(seq, '\n');
  111. for_each_online_cpu(cpu) {
  112. st = per_cpu_ptr(&wti_state, cpu);
  113. seq_printf(seq, " %10lu", st->dbg.missed);
  114. }
  115. seq_putc(seq, '\n');
  116. cpus_read_unlock();
  117. return 0;
  118. }
  119. DEFINE_SHOW_ATTRIBUTE(wti);
  120. static void wti_thread_fn(unsigned int cpu)
  121. {
  122. struct wti_state *st = per_cpu_ptr(&wti_state, cpu);
  123. st->pending = false;
  124. /*
  125. * Yield CPU voluntarily to the hypervisor. Control
  126. * resumes when hypervisor decides to dispatch CPU
  127. * to this LPAR again.
  128. */
  129. if (diag49c(DIAG49C_SUBC_ACK))
  130. wti_dbf_grace_period(st);
  131. wti_irq_enable();
  132. }
  133. static struct smp_hotplug_thread wti_threads = {
  134. .store = &wti_state.thread,
  135. .thread_should_run = wti_pending,
  136. .thread_fn = wti_thread_fn,
  137. .thread_comm = "cpuwti/%u",
  138. .selfparking = false,
  139. };
  140. static int __init wti_init(void)
  141. {
  142. struct sched_param wti_sched_param = { .sched_priority = MAX_RT_PRIO - 1 };
  143. struct dentry *wti_dir;
  144. struct wti_state *st;
  145. int cpu, rc;
  146. rc = -EOPNOTSUPP;
  147. if (!sclp.has_wti)
  148. goto out;
  149. rc = smpboot_register_percpu_thread(&wti_threads);
  150. if (WARN_ON(rc))
  151. goto out;
  152. for_each_online_cpu(cpu) {
  153. st = per_cpu_ptr(&wti_state, cpu);
  154. sched_setscheduler(st->thread, SCHED_FIFO, &wti_sched_param);
  155. }
  156. rc = register_external_irq(EXT_IRQ_WARNING_TRACK, wti_interrupt);
  157. if (rc) {
  158. pr_warn("Couldn't request external interrupt 0x1007\n");
  159. goto out_thread;
  160. }
  161. irq_subclass_register(IRQ_SUBCLASS_WARNING_TRACK);
  162. rc = diag49c(DIAG49C_SUBC_REG);
  163. if (rc) {
  164. pr_warn("Failed to register warning track interrupt through DIAG 49C\n");
  165. rc = -EOPNOTSUPP;
  166. goto out_subclass;
  167. }
  168. wti_dir = debugfs_create_dir("wti", arch_debugfs_dir);
  169. debugfs_create_file("stat", 0400, wti_dir, NULL, &wti_fops);
  170. wti_dbg = debug_register("wti", 1, 1, WTI_DBF_LEN);
  171. if (!wti_dbg) {
  172. rc = -ENOMEM;
  173. goto out_debug_register;
  174. }
  175. rc = debug_register_view(wti_dbg, &debug_hex_ascii_view);
  176. if (rc)
  177. goto out_debug_register;
  178. goto out;
  179. out_debug_register:
  180. debug_unregister(wti_dbg);
  181. out_subclass:
  182. irq_subclass_unregister(IRQ_SUBCLASS_WARNING_TRACK);
  183. unregister_external_irq(EXT_IRQ_WARNING_TRACK, wti_interrupt);
  184. out_thread:
  185. smpboot_unregister_percpu_thread(&wti_threads);
  186. out:
  187. return rc;
  188. }
  189. late_initcall(wti_init);