idle.c 3.3 KB

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