1 #include "splat-internal.h"
3 #define SPLAT_SUBSYSTEM_ATOMIC 0x0b00
4 #define SPLAT_ATOMIC_NAME "atomic"
5 #define SPLAT_ATOMIC_DESC "Kernel Atomic Tests"
7 #define SPLAT_ATOMIC_TEST1_ID 0x0b01
8 #define SPLAT_ATOMIC_TEST1_NAME "64-bit"
9 #define SPLAT_ATOMIC_TEST1_DESC "Validate 64-bit atomic ops"
11 #define SPLAT_ATOMIC_TEST_MAGIC 0x43435454UL
12 #define SPLAT_ATOMIC_INIT_VALUE 10000000UL
15 SPLAT_ATOMIC_INC_64
= 0,
16 SPLAT_ATOMIC_DEC_64
= 1,
17 SPLAT_ATOMIC_ADD_64
= 2,
18 SPLAT_ATOMIC_SUB_64
= 3,
19 SPLAT_ATOMIC_ADD_64_NV
= 4,
20 SPLAT_ATOMIC_SUB_64_NV
= 5,
21 SPLAT_ATOMIC_COUNT_64
= 6
24 typedef struct atomic_priv
{
25 unsigned long ap_magic
;
28 wait_queue_head_t ap_waitq
;
29 volatile uint64_t ap_atomic
;
30 volatile uint64_t ap_atomic_exited
;
36 splat_atomic_work(void *priv
)
42 ap
= (atomic_priv_t
*)priv
;
43 ASSERT(ap
->ap_magic
== SPLAT_ATOMIC_TEST_MAGIC
);
45 spin_lock(&ap
->ap_lock
);
47 wake_up(&ap
->ap_waitq
);
48 spin_unlock(&ap
->ap_lock
);
50 splat_vprint(ap
->ap_file
, SPLAT_ATOMIC_TEST1_NAME
,
51 "Thread %d successfully started: %lu/%lu\n", op
,
52 (long unsigned)ap
->ap_atomic
,
53 (long unsigned)ap
->ap_atomic_exited
);
55 for (i
= 0; i
< SPLAT_ATOMIC_INIT_VALUE
/ 10; i
++) {
57 /* Periodically sleep to mix up the ordering */
58 if ((i
% (SPLAT_ATOMIC_INIT_VALUE
/ 100)) == 0) {
59 splat_vprint(ap
->ap_file
, SPLAT_ATOMIC_TEST1_NAME
,
60 "Thread %d sleeping: %lu/%lu\n", op
,
61 (long unsigned)ap
->ap_atomic
,
62 (long unsigned)ap
->ap_atomic_exited
);
63 set_current_state(TASK_INTERRUPTIBLE
);
64 schedule_timeout(HZ
/ 100);
68 case SPLAT_ATOMIC_INC_64
:
69 atomic_inc_64(&ap
->ap_atomic
);
71 case SPLAT_ATOMIC_DEC_64
:
72 atomic_dec_64(&ap
->ap_atomic
);
74 case SPLAT_ATOMIC_ADD_64
:
75 atomic_add_64(&ap
->ap_atomic
, 3);
77 case SPLAT_ATOMIC_SUB_64
:
78 atomic_sub_64(&ap
->ap_atomic
, 3);
80 case SPLAT_ATOMIC_ADD_64_NV
:
81 atomic_add_64_nv(&ap
->ap_atomic
, 5);
83 case SPLAT_ATOMIC_SUB_64_NV
:
84 atomic_sub_64_nv(&ap
->ap_atomic
, 5);
91 atomic_inc_64(&ap
->ap_atomic_exited
);
93 splat_vprint(ap
->ap_file
, SPLAT_ATOMIC_TEST1_NAME
,
94 "Thread %d successfully exited: %lu/%lu\n", op
,
95 (long unsigned)ap
->ap_atomic
,
96 (long unsigned)ap
->ap_atomic_exited
);
98 wake_up(&ap
->ap_waitq
);
103 splat_atomic_test1_cond(atomic_priv_t
*ap
)
105 return (ap
->ap_atomic_exited
== SPLAT_ATOMIC_COUNT_64
);
109 splat_atomic_test1(struct file
*file
, void *arg
)
116 ap
.ap_magic
= SPLAT_ATOMIC_TEST_MAGIC
;
118 spin_lock_init(&ap
.ap_lock
);
119 init_waitqueue_head(&ap
.ap_waitq
);
120 ap
.ap_atomic
= SPLAT_ATOMIC_INIT_VALUE
;
121 ap
.ap_atomic_exited
= 0;
123 for (i
= 0; i
< SPLAT_ATOMIC_COUNT_64
; i
++) {
124 spin_lock(&ap
.ap_lock
);
127 thr
= (kthread_t
*)thread_create(NULL
, 0, splat_atomic_work
,
132 /* Prepare to wait, the new thread will wake us once it
133 * has made a copy of the unique private passed data */
134 prepare_to_wait(&ap
.ap_waitq
, &wait
, TASK_UNINTERRUPTIBLE
);
135 spin_unlock(&ap
.ap_lock
);
139 wait_event_interruptible(ap
.ap_waitq
, splat_atomic_test1_cond(&ap
));
141 if (ap
.ap_atomic
!= SPLAT_ATOMIC_INIT_VALUE
) {
142 splat_vprint(file
, SPLAT_ATOMIC_TEST1_NAME
,
143 "Final value %lu does not match initial value %lu\n",
144 (long unsigned)ap
.ap_atomic
, SPLAT_ATOMIC_INIT_VALUE
);
148 splat_vprint(file
, SPLAT_ATOMIC_TEST1_NAME
,
149 "Success initial and final values match, %lu == %lu\n",
150 (long unsigned)ap
.ap_atomic
, SPLAT_ATOMIC_INIT_VALUE
);
156 splat_atomic_init(void)
158 splat_subsystem_t
*sub
;
160 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
164 memset(sub
, 0, sizeof(*sub
));
165 strncpy(sub
->desc
.name
, SPLAT_ATOMIC_NAME
, SPLAT_NAME_SIZE
);
166 strncpy(sub
->desc
.desc
, SPLAT_ATOMIC_DESC
, SPLAT_DESC_SIZE
);
167 INIT_LIST_HEAD(&sub
->subsystem_list
);
168 INIT_LIST_HEAD(&sub
->test_list
);
169 spin_lock_init(&sub
->test_lock
);
170 sub
->desc
.id
= SPLAT_SUBSYSTEM_ATOMIC
;
172 SPLAT_TEST_INIT(sub
, SPLAT_ATOMIC_TEST1_NAME
, SPLAT_ATOMIC_TEST1_DESC
,
173 SPLAT_ATOMIC_TEST1_ID
, splat_atomic_test1
);
179 splat_atomic_fini(splat_subsystem_t
*sub
)
182 SPLAT_TEST_FINI(sub
, SPLAT_ATOMIC_TEST1_ID
);
188 splat_atomic_id(void) {
189 return SPLAT_SUBSYSTEM_ATOMIC
;