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