percpu_test.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/limits.h>
  3. #include <linux/module.h>
  4. /* validate @native and @pcp counter values match @expected */
  5. #define CHECK(native, pcp, expected) \
  6. do { \
  7. WARN((native) != (expected), \
  8. "raw %ld (0x%lx) != expected %lld (0x%llx)", \
  9. (native), (native), \
  10. (long long)(expected), (long long)(expected)); \
  11. WARN(__this_cpu_read(pcp) != (expected), \
  12. "pcp %ld (0x%lx) != expected %lld (0x%llx)", \
  13. __this_cpu_read(pcp), __this_cpu_read(pcp), \
  14. (long long)(expected), (long long)(expected)); \
  15. } while (0)
  16. static DEFINE_PER_CPU(long, long_counter);
  17. static DEFINE_PER_CPU(unsigned long, ulong_counter);
  18. static int __init percpu_test_init(void)
  19. {
  20. /*
  21. * volatile prevents compiler from optimizing it uses, otherwise the
  22. * +ul_one/-ul_one below would replace with inc/dec instructions.
  23. */
  24. volatile unsigned int ui_one = 1;
  25. unsigned long long ull = 0;
  26. unsigned long ul = 0;
  27. long l = 0;
  28. pr_info("percpu test start\n");
  29. preempt_disable();
  30. l += -1;
  31. __this_cpu_add(long_counter, -1);
  32. CHECK(l, long_counter, -1);
  33. l += 1;
  34. __this_cpu_add(long_counter, 1);
  35. CHECK(l, long_counter, 0);
  36. ul = 0;
  37. __this_cpu_write(ulong_counter, 0);
  38. ul += 1UL;
  39. __this_cpu_add(ulong_counter, 1UL);
  40. CHECK(ul, ulong_counter, 1);
  41. ul += -1UL;
  42. __this_cpu_add(ulong_counter, -1UL);
  43. CHECK(ul, ulong_counter, 0);
  44. ul += -(unsigned long)1;
  45. __this_cpu_add(ulong_counter, -(unsigned long)1);
  46. CHECK(ul, ulong_counter, -1);
  47. ul = 0;
  48. __this_cpu_write(ulong_counter, 0);
  49. ul -= 1;
  50. __this_cpu_dec(ulong_counter);
  51. CHECK(ul, ulong_counter, -1);
  52. CHECK(ul, ulong_counter, ULONG_MAX);
  53. l += -ui_one;
  54. __this_cpu_add(long_counter, -ui_one);
  55. CHECK(l, long_counter, 0xffffffff);
  56. l += ui_one;
  57. __this_cpu_add(long_counter, ui_one);
  58. CHECK(l, long_counter, (long)0x100000000LL);
  59. l = 0;
  60. __this_cpu_write(long_counter, 0);
  61. l -= ui_one;
  62. __this_cpu_sub(long_counter, ui_one);
  63. CHECK(l, long_counter, -1);
  64. l = 0;
  65. __this_cpu_write(long_counter, 0);
  66. l += ui_one;
  67. __this_cpu_add(long_counter, ui_one);
  68. CHECK(l, long_counter, 1);
  69. l += -ui_one;
  70. __this_cpu_add(long_counter, -ui_one);
  71. CHECK(l, long_counter, (long)0x100000000LL);
  72. l = 0;
  73. __this_cpu_write(long_counter, 0);
  74. l -= ui_one;
  75. this_cpu_sub(long_counter, ui_one);
  76. CHECK(l, long_counter, -1);
  77. CHECK(l, long_counter, ULONG_MAX);
  78. ul = 0;
  79. __this_cpu_write(ulong_counter, 0);
  80. ul += ui_one;
  81. __this_cpu_add(ulong_counter, ui_one);
  82. CHECK(ul, ulong_counter, 1);
  83. ul = 0;
  84. __this_cpu_write(ulong_counter, 0);
  85. ul -= ui_one;
  86. __this_cpu_sub(ulong_counter, ui_one);
  87. CHECK(ul, ulong_counter, -1);
  88. CHECK(ul, ulong_counter, ULONG_MAX);
  89. ul = ull = 0;
  90. __this_cpu_write(ulong_counter, 0);
  91. ul = ull += UINT_MAX;
  92. __this_cpu_add(ulong_counter, ull);
  93. CHECK(ul, ulong_counter, UINT_MAX);
  94. ul = 3;
  95. __this_cpu_write(ulong_counter, 3);
  96. ul = this_cpu_sub_return(ulong_counter, ui_one);
  97. CHECK(ul, ulong_counter, 2);
  98. ul = __this_cpu_sub_return(ulong_counter, ui_one);
  99. CHECK(ul, ulong_counter, 1);
  100. preempt_enable();
  101. pr_info("percpu test done\n");
  102. return -EAGAIN; /* Fail will directly unload the module */
  103. }
  104. static void __exit percpu_test_exit(void)
  105. {
  106. }
  107. module_init(percpu_test_init)
  108. module_exit(percpu_test_exit)
  109. MODULE_LICENSE("GPL");
  110. MODULE_AUTHOR("Greg Thelen");
  111. MODULE_DESCRIPTION("percpu operations test");