140 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#include <linux/module.h>3 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 17static DEFINE_PER_CPU(long, long_counter);18static DEFINE_PER_CPU(unsigned long, ulong_counter);19 20static int __init percpu_test_init(void)21{22 /*23 * volatile prevents compiler from optimizing it uses, otherwise the24 * +ul_one/-ul_one below would replace with inc/dec instructions.25 */26 volatile unsigned int ui_one = 1;27 long l = 0;28 unsigned long ul = 0;29 30 pr_info("percpu test start\n");31 32 preempt_disable();33 34 l += -1;35 __this_cpu_add(long_counter, -1);36 CHECK(l, long_counter, -1);37 38 l += 1;39 __this_cpu_add(long_counter, 1);40 CHECK(l, long_counter, 0);41 42 ul = 0;43 __this_cpu_write(ulong_counter, 0);44 45 ul += 1UL;46 __this_cpu_add(ulong_counter, 1UL);47 CHECK(ul, ulong_counter, 1);48 49 ul += -1UL;50 __this_cpu_add(ulong_counter, -1UL);51 CHECK(ul, ulong_counter, 0);52 53 ul += -(unsigned long)1;54 __this_cpu_add(ulong_counter, -(unsigned long)1);55 CHECK(ul, ulong_counter, -1);56 57 ul = 0;58 __this_cpu_write(ulong_counter, 0);59 60 ul -= 1;61 __this_cpu_dec(ulong_counter);62 CHECK(ul, ulong_counter, -1);63 CHECK(ul, ulong_counter, ULONG_MAX);64 65 l += -ui_one;66 __this_cpu_add(long_counter, -ui_one);67 CHECK(l, long_counter, 0xffffffff);68 69 l += ui_one;70 __this_cpu_add(long_counter, ui_one);71 CHECK(l, long_counter, (long)0x100000000LL);72 73 74 l = 0;75 __this_cpu_write(long_counter, 0);76 77 l -= ui_one;78 __this_cpu_sub(long_counter, ui_one);79 CHECK(l, long_counter, -1);80 81 l = 0;82 __this_cpu_write(long_counter, 0);83 84 l += ui_one;85 __this_cpu_add(long_counter, ui_one);86 CHECK(l, long_counter, 1);87 88 l += -ui_one;89 __this_cpu_add(long_counter, -ui_one);90 CHECK(l, long_counter, (long)0x100000000LL);91 92 l = 0;93 __this_cpu_write(long_counter, 0);94 95 l -= ui_one;96 this_cpu_sub(long_counter, ui_one);97 CHECK(l, long_counter, -1);98 CHECK(l, long_counter, ULONG_MAX);99 100 ul = 0;101 __this_cpu_write(ulong_counter, 0);102 103 ul += ui_one;104 __this_cpu_add(ulong_counter, ui_one);105 CHECK(ul, ulong_counter, 1);106 107 ul = 0;108 __this_cpu_write(ulong_counter, 0);109 110 ul -= ui_one;111 __this_cpu_sub(ulong_counter, ui_one);112 CHECK(ul, ulong_counter, -1);113 CHECK(ul, ulong_counter, ULONG_MAX);114 115 ul = 3;116 __this_cpu_write(ulong_counter, 3);117 118 ul = this_cpu_sub_return(ulong_counter, ui_one);119 CHECK(ul, ulong_counter, 2);120 121 ul = __this_cpu_sub_return(ulong_counter, ui_one);122 CHECK(ul, ulong_counter, 1);123 124 preempt_enable();125 126 pr_info("percpu test done\n");127 return -EAGAIN; /* Fail will directly unload the module */128}129 130static void __exit percpu_test_exit(void)131{132}133 134module_init(percpu_test_init)135module_exit(percpu_test_exit)136 137MODULE_LICENSE("GPL");138MODULE_AUTHOR("Greg Thelen");139MODULE_DESCRIPTION("percpu operations test");140