Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2#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 the
 24	 * +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");
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2#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 the
 24	 * +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");