isolation.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Housekeeping management. Manage the targets for routine code that can run on
  3. * any CPU: unbound workqueues, timers, kthreads and any offloadable work.
  4. *
  5. * Copyright (C) 2017 Red Hat, Inc., Frederic Weisbecker
  6. * Copyright (C) 2017-2018 SUSE, Frederic Weisbecker
  7. *
  8. */
  9. #include "sched.h"
  10. DEFINE_STATIC_KEY_FALSE(housekeeping_overriden);
  11. EXPORT_SYMBOL_GPL(housekeeping_overriden);
  12. static cpumask_var_t housekeeping_mask;
  13. static unsigned int housekeeping_flags;
  14. int housekeeping_any_cpu(enum hk_flags flags)
  15. {
  16. if (static_branch_unlikely(&housekeeping_overriden))
  17. if (housekeeping_flags & flags)
  18. return cpumask_any_and(housekeeping_mask, cpu_online_mask);
  19. return smp_processor_id();
  20. }
  21. EXPORT_SYMBOL_GPL(housekeeping_any_cpu);
  22. const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
  23. {
  24. if (static_branch_unlikely(&housekeeping_overriden))
  25. if (housekeeping_flags & flags)
  26. return housekeeping_mask;
  27. return cpu_possible_mask;
  28. }
  29. EXPORT_SYMBOL_GPL(housekeeping_cpumask);
  30. void housekeeping_affine(struct task_struct *t, enum hk_flags flags)
  31. {
  32. if (static_branch_unlikely(&housekeeping_overriden))
  33. if (housekeeping_flags & flags)
  34. set_cpus_allowed_ptr(t, housekeeping_mask);
  35. }
  36. EXPORT_SYMBOL_GPL(housekeeping_affine);
  37. bool housekeeping_test_cpu(int cpu, enum hk_flags flags)
  38. {
  39. if (static_branch_unlikely(&housekeeping_overriden))
  40. if (housekeeping_flags & flags)
  41. return cpumask_test_cpu(cpu, housekeeping_mask);
  42. return true;
  43. }
  44. EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
  45. void __init housekeeping_init(void)
  46. {
  47. if (!housekeeping_flags)
  48. return;
  49. static_branch_enable(&housekeeping_overriden);
  50. if (housekeeping_flags & HK_FLAG_TICK)
  51. sched_tick_offload_init();
  52. /* We need at least one CPU to handle housekeeping work */
  53. WARN_ON_ONCE(cpumask_empty(housekeeping_mask));
  54. }
  55. static int __init housekeeping_setup(char *str, enum hk_flags flags)
  56. {
  57. cpumask_var_t non_housekeeping_mask;
  58. int err;
  59. alloc_bootmem_cpumask_var(&non_housekeeping_mask);
  60. err = cpulist_parse(str, non_housekeeping_mask);
  61. if (err < 0 || cpumask_last(non_housekeeping_mask) >= nr_cpu_ids) {
  62. pr_warn("Housekeeping: nohz_full= or isolcpus= incorrect CPU range\n");
  63. free_bootmem_cpumask_var(non_housekeeping_mask);
  64. return 0;
  65. }
  66. if (!housekeeping_flags) {
  67. alloc_bootmem_cpumask_var(&housekeeping_mask);
  68. cpumask_andnot(housekeeping_mask,
  69. cpu_possible_mask, non_housekeeping_mask);
  70. if (cpumask_empty(housekeeping_mask))
  71. cpumask_set_cpu(smp_processor_id(), housekeeping_mask);
  72. } else {
  73. cpumask_var_t tmp;
  74. alloc_bootmem_cpumask_var(&tmp);
  75. cpumask_andnot(tmp, cpu_possible_mask, non_housekeeping_mask);
  76. if (!cpumask_equal(tmp, housekeeping_mask)) {
  77. pr_warn("Housekeeping: nohz_full= must match isolcpus=\n");
  78. free_bootmem_cpumask_var(tmp);
  79. free_bootmem_cpumask_var(non_housekeeping_mask);
  80. return 0;
  81. }
  82. free_bootmem_cpumask_var(tmp);
  83. }
  84. if ((flags & HK_FLAG_TICK) && !(housekeeping_flags & HK_FLAG_TICK)) {
  85. if (IS_ENABLED(CONFIG_NO_HZ_FULL)) {
  86. tick_nohz_full_setup(non_housekeeping_mask);
  87. } else {
  88. pr_warn("Housekeeping: nohz unsupported."
  89. " Build with CONFIG_NO_HZ_FULL\n");
  90. free_bootmem_cpumask_var(non_housekeeping_mask);
  91. return 0;
  92. }
  93. }
  94. housekeeping_flags |= flags;
  95. free_bootmem_cpumask_var(non_housekeeping_mask);
  96. return 1;
  97. }
  98. static int __init housekeeping_nohz_full_setup(char *str)
  99. {
  100. unsigned int flags;
  101. flags = HK_FLAG_TICK | HK_FLAG_WQ | HK_FLAG_TIMER | HK_FLAG_RCU | HK_FLAG_MISC;
  102. return housekeeping_setup(str, flags);
  103. }
  104. __setup("nohz_full=", housekeeping_nohz_full_setup);
  105. static int __init housekeeping_isolcpus_setup(char *str)
  106. {
  107. unsigned int flags = 0;
  108. while (isalpha(*str)) {
  109. if (!strncmp(str, "nohz,", 5)) {
  110. str += 5;
  111. flags |= HK_FLAG_TICK;
  112. continue;
  113. }
  114. if (!strncmp(str, "domain,", 7)) {
  115. str += 7;
  116. flags |= HK_FLAG_DOMAIN;
  117. continue;
  118. }
  119. pr_warn("isolcpus: Error, unknown flag\n");
  120. return 0;
  121. }
  122. /* Default behaviour for isolcpus without flags */
  123. if (!flags)
  124. flags |= HK_FLAG_DOMAIN;
  125. return housekeeping_setup(str, flags);
  126. }
  127. __setup("isolcpus=", housekeeping_isolcpus_setup);