idle.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Idle functions for s390.
  4. *
  5. * Copyright IBM Corp. 2014
  6. *
  7. * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/kernel_stat.h>
  11. #include <linux/kprobes.h>
  12. #include <linux/notifier.h>
  13. #include <linux/init.h>
  14. #include <linux/cpu.h>
  15. #include <linux/sched/cputime.h>
  16. #include <asm/nmi.h>
  17. #include <asm/smp.h>
  18. #include "entry.h"
  19. static DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
  20. void enabled_wait(void)
  21. {
  22. struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
  23. unsigned long long idle_time;
  24. unsigned long psw_mask;
  25. trace_hardirqs_on();
  26. /* Wait for external, I/O or machine check interrupt. */
  27. psw_mask = PSW_KERNEL_BITS | PSW_MASK_WAIT | PSW_MASK_DAT |
  28. PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
  29. clear_cpu_flag(CIF_NOHZ_DELAY);
  30. /* Call the assembler magic in entry.S */
  31. psw_idle(idle, psw_mask);
  32. trace_hardirqs_off();
  33. /* Account time spent with enabled wait psw loaded as idle time. */
  34. write_seqcount_begin(&idle->seqcount);
  35. idle_time = idle->clock_idle_exit - idle->clock_idle_enter;
  36. idle->clock_idle_enter = idle->clock_idle_exit = 0ULL;
  37. idle->idle_time += idle_time;
  38. idle->idle_count++;
  39. account_idle_time(cputime_to_nsecs(idle_time));
  40. write_seqcount_end(&idle->seqcount);
  41. }
  42. NOKPROBE_SYMBOL(enabled_wait);
  43. static ssize_t show_idle_count(struct device *dev,
  44. struct device_attribute *attr, char *buf)
  45. {
  46. struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
  47. unsigned long long idle_count;
  48. unsigned int seq;
  49. do {
  50. seq = read_seqcount_begin(&idle->seqcount);
  51. idle_count = READ_ONCE(idle->idle_count);
  52. if (READ_ONCE(idle->clock_idle_enter))
  53. idle_count++;
  54. } while (read_seqcount_retry(&idle->seqcount, seq));
  55. return sprintf(buf, "%llu\n", idle_count);
  56. }
  57. DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
  58. static ssize_t show_idle_time(struct device *dev,
  59. struct device_attribute *attr, char *buf)
  60. {
  61. unsigned long long now, idle_time, idle_enter, idle_exit, in_idle;
  62. struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
  63. unsigned int seq;
  64. do {
  65. seq = read_seqcount_begin(&idle->seqcount);
  66. idle_time = READ_ONCE(idle->idle_time);
  67. idle_enter = READ_ONCE(idle->clock_idle_enter);
  68. idle_exit = READ_ONCE(idle->clock_idle_exit);
  69. } while (read_seqcount_retry(&idle->seqcount, seq));
  70. in_idle = 0;
  71. now = get_tod_clock();
  72. if (idle_enter) {
  73. if (idle_exit) {
  74. in_idle = idle_exit - idle_enter;
  75. } else if (now > idle_enter) {
  76. in_idle = now - idle_enter;
  77. }
  78. }
  79. idle_time += in_idle;
  80. return sprintf(buf, "%llu\n", idle_time >> 12);
  81. }
  82. DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
  83. u64 arch_cpu_idle_time(int cpu)
  84. {
  85. struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
  86. unsigned long long now, idle_enter, idle_exit, in_idle;
  87. unsigned int seq;
  88. do {
  89. seq = read_seqcount_begin(&idle->seqcount);
  90. idle_enter = READ_ONCE(idle->clock_idle_enter);
  91. idle_exit = READ_ONCE(idle->clock_idle_exit);
  92. } while (read_seqcount_retry(&idle->seqcount, seq));
  93. in_idle = 0;
  94. now = get_tod_clock();
  95. if (idle_enter) {
  96. if (idle_exit) {
  97. in_idle = idle_exit - idle_enter;
  98. } else if (now > idle_enter) {
  99. in_idle = now - idle_enter;
  100. }
  101. }
  102. return cputime_to_nsecs(in_idle);
  103. }
  104. void arch_cpu_idle_enter(void)
  105. {
  106. local_mcck_disable();
  107. }
  108. void arch_cpu_idle(void)
  109. {
  110. if (!test_cpu_flag(CIF_MCCK_PENDING))
  111. /* Halt the cpu and keep track of cpu time accounting. */
  112. enabled_wait();
  113. local_irq_enable();
  114. }
  115. void arch_cpu_idle_exit(void)
  116. {
  117. local_mcck_enable();
  118. if (test_cpu_flag(CIF_MCCK_PENDING))
  119. s390_handle_mcck();
  120. }
  121. void arch_cpu_idle_dead(void)
  122. {
  123. cpu_die();
  124. }