idle.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
  62. unsigned long long now, idle_time, idle_enter, idle_exit;
  63. unsigned int seq;
  64. do {
  65. now = get_tod_clock();
  66. seq = read_seqcount_begin(&idle->seqcount);
  67. idle_time = READ_ONCE(idle->idle_time);
  68. idle_enter = READ_ONCE(idle->clock_idle_enter);
  69. idle_exit = READ_ONCE(idle->clock_idle_exit);
  70. } while (read_seqcount_retry(&idle->seqcount, seq));
  71. idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
  72. return sprintf(buf, "%llu\n", idle_time >> 12);
  73. }
  74. DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
  75. u64 arch_cpu_idle_time(int cpu)
  76. {
  77. struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
  78. unsigned long long now, idle_enter, idle_exit;
  79. unsigned int seq;
  80. do {
  81. now = get_tod_clock();
  82. seq = read_seqcount_begin(&idle->seqcount);
  83. idle_enter = READ_ONCE(idle->clock_idle_enter);
  84. idle_exit = READ_ONCE(idle->clock_idle_exit);
  85. } while (read_seqcount_retry(&idle->seqcount, seq));
  86. return cputime_to_nsecs(idle_enter ? ((idle_exit ?: now) - idle_enter) : 0);
  87. }
  88. void arch_cpu_idle_enter(void)
  89. {
  90. local_mcck_disable();
  91. }
  92. void arch_cpu_idle(void)
  93. {
  94. if (!test_cpu_flag(CIF_MCCK_PENDING))
  95. /* Halt the cpu and keep track of cpu time accounting. */
  96. enabled_wait();
  97. local_irq_enable();
  98. }
  99. void arch_cpu_idle_exit(void)
  100. {
  101. local_mcck_enable();
  102. if (test_cpu_flag(CIF_MCCK_PENDING))
  103. s390_handle_mcck();
  104. }
  105. void arch_cpu_idle_dead(void)
  106. {
  107. cpu_die();
  108. }