blob: 09d7c0dfe7f2d56d000ef6ac8a905c1dea8d03b5 [file] [log] [blame]
Eric Holmberg6275b602012-11-19 13:05:04 -07001/* arch/arm/mach-msm/smp2p_spinlock_test.c
2 *
3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <linux/debugfs.h>
15#include <linux/ctype.h>
16#include <linux/jiffies.h>
17#include <linux/delay.h>
18#include <linux/completion.h>
19#include <linux/remote_spinlock.h>
20#include <mach/msm_smsm.h>
21#include "smd_private.h"
22#include "smp2p_private.h"
23#include "smp2p_test_common.h"
24
25#define REMOTE_SPIN_PID 1
26#define RS_END_THIEF_PID_BIT 20
27#define RS_END_THIEF_MASK 0x00f00000
28
29/* Spinlock commands used for testing Apps<->RPM spinlocks. */
30enum RPM_SPINLOCK_CMDS {
31 RPM_CMD_INVALID,
32 RPM_CMD_START,
33 RPM_CMD_LOCKED,
34 RPM_CMD_UNLOCKED,
35 RPM_CMD_END,
36};
37
38/* Shared structure for testing Apps<->RPM spinlocks. */
39struct rpm_spinlock_test {
40 uint32_t apps_cmd;
41 uint32_t apps_lock_count;
42 uint32_t rpm_cmd;
43 uint32_t rpm_lock_count;
44};
45
46/**
47 * smp2p_ut_remote_spinlock_core - Verify remote spinlock.
48 *
49 * @s: Pointer to output file
50 * @remote_pid: Remote processor to test
51 * @use_trylock: Use trylock to prevent an Apps deadlock if the
52 * remote spinlock fails.
53 */
54static void smp2p_ut_remote_spinlock_core(struct seq_file *s, int remote_pid,
55 bool use_trylock)
56{
57 int failed = 0;
58 unsigned lock_count = 0;
59 struct msm_smp2p_out *handle = NULL;
60 int ret;
61 uint32_t test_request;
62 uint32_t test_response;
63 struct mock_cb_data cb_out;
64 struct mock_cb_data cb_in;
65 unsigned long flags;
66 unsigned n;
67 unsigned test_num;
68 bool have_lock;
69 bool timeout;
70 int failed_tmp;
71 int spinlock_owner;
72 remote_spinlock_t *smem_spinlock;
73
74 seq_printf(s, "Running %s for '%s' remote pid %d\n",
75 __func__, smp2p_pid_to_name(remote_pid), remote_pid);
76
77 cb_out.initialized = false;
78 cb_in.initialized = false;
79 mock_cb_data_init(&cb_out);
80 mock_cb_data_init(&cb_in);
81 do {
82 smem_spinlock = smem_get_remote_spinlock();
83 UT_ASSERT_PTR(smem_spinlock, !=, NULL);
84
85 /* Open output entry */
86 ret = msm_smp2p_out_open(remote_pid, SMP2P_RLPB_ENTRY_NAME,
87 &cb_out.nb, &handle);
88 UT_ASSERT_INT(ret, ==, 0);
89 UT_ASSERT_INT(
90 (int)wait_for_completion_timeout(
91 &cb_out.cb_completion, HZ * 2),
92 >, 0);
93 UT_ASSERT_INT(cb_out.cb_count, ==, 1);
94 UT_ASSERT_INT(cb_out.event_open, ==, 1);
95
96 /* Open inbound entry */
97 ret = msm_smp2p_in_register(remote_pid, SMP2P_RLPB_ENTRY_NAME,
98 &cb_in.nb);
99 UT_ASSERT_INT(ret, ==, 0);
100 UT_ASSERT_INT(
101 (int)wait_for_completion_timeout(
102 &cb_in.cb_completion, HZ * 2),
103 >, 0);
104 UT_ASSERT_INT(cb_in.cb_count, ==, 1);
105 UT_ASSERT_INT(cb_in.event_open, ==, 1);
106
107 /* Send start */
108 mock_cb_data_reset(&cb_in);
109 mock_cb_data_reset(&cb_out);
110 test_request = 0x0;
111 SMP2P_SET_RMT_CMD_TYPE_REQ(test_request);
112 SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_START);
113 SMP2P_SET_RMT_DATA(test_request, 0x0);
114 ret = msm_smp2p_out_write(handle, test_request);
115 UT_ASSERT_INT(ret, ==, 0);
116
117 UT_ASSERT_INT(
118 (int)wait_for_completion_timeout(
119 &cb_in.cb_completion, HZ * 2),
120 >, 0);
121 UT_ASSERT_INT(cb_in.cb_count, ==, 1);
122 UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
123 ret = msm_smp2p_in_read(remote_pid, SMP2P_RLPB_ENTRY_NAME,
124 &test_response);
125 UT_ASSERT_INT(ret, ==, 0);
126
127 test_response = SMP2P_GET_RMT_CMD(test_response);
128 if (test_response != SMP2P_LB_CMD_RSPIN_LOCKED &&
129 test_response != SMP2P_LB_CMD_RSPIN_UNLOCKED) {
130 /* invalid response from remote - abort test */
131 test_request = 0x0;
132 SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
133 SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END);
134 SMP2P_SET_RMT_DATA(test_request, 0x0);
135 ret = msm_smp2p_out_write(handle, test_request);
136 UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_LOCKED, ==,
137 test_response);
138 }
139
140 /* Run spinlock test */
141 if (use_trylock)
142 seq_printf(s, "\tUsing remote_spin_trylock\n");
143 else
144 seq_printf(s, "\tUsing remote_spin_lock\n");
145
146 flags = 0;
147 have_lock = false;
148 timeout = false;
149 spinlock_owner = 0;
150 test_request = 0x0;
151 SMP2P_SET_RMT_CMD_TYPE_REQ(test_request);
152 for (test_num = 0; !failed && test_num < 10000; ++test_num) {
153 /* try to acquire spinlock */
154 if (use_trylock) {
155 unsigned long j_start = jiffies;
156 while (!remote_spin_trylock_irqsave(
157 smem_spinlock, flags)) {
158 if (jiffies_to_msecs(jiffies - j_start)
159 > 1000) {
160 seq_printf(s,
161 "\tFail: Timeout trying to get the lock\n");
162 timeout = true;
163 break;
164 }
165 }
166 if (timeout)
167 break;
168 } else {
169 remote_spin_lock_irqsave(smem_spinlock, flags);
170 }
171 have_lock = true;
172 ++lock_count;
173
174 /* tell the remote side that we have the lock */
175 SMP2P_SET_RMT_DATA(test_request, lock_count);
176 SMP2P_SET_RMT_CMD(test_request,
177 SMP2P_LB_CMD_RSPIN_LOCKED);
178 ret = msm_smp2p_out_write(handle, test_request);
179 UT_ASSERT_INT(ret, ==, 0);
180
181 /* verify the other side doesn't say it has the lock */
182 for (n = 0; n < 1000; ++n) {
183 spinlock_owner =
184 remote_spin_owner(smem_spinlock);
185 if (spinlock_owner != REMOTE_SPIN_PID) {
186 /* lock stolen by remote side */
187 seq_printf(s,
188 "\tFail: Remote side (%d) stole lock (pid %d)\n",
189 remote_pid, spinlock_owner);
190 failed = true;
191 break;
192 }
193 spinlock_owner = 0;
194
195 ret = msm_smp2p_in_read(remote_pid,
196 SMP2P_RLPB_ENTRY_NAME, &test_response);
197 UT_ASSERT_INT(ret, ==, 0);
198 test_response =
199 SMP2P_GET_RMT_CMD(test_response);
200 UT_ASSERT_HEX(SMP2P_LB_CMD_RSPIN_UNLOCKED, ==,
201 test_response);
202 }
203 if (failed)
204 break;
205
206 /* tell remote side we are unlocked and release lock */
207 SMP2P_SET_RMT_CMD(test_request,
208 SMP2P_LB_CMD_RSPIN_UNLOCKED);
209 (void)msm_smp2p_out_write(handle, test_request);
210 have_lock = false;
211 remote_spin_unlock_irqrestore(smem_spinlock, flags);
212 }
213 if (have_lock)
214 remote_spin_unlock_irqrestore(smem_spinlock, flags);
215
216 /* End test */
217 mock_cb_data_reset(&cb_in);
218 SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END);
219 SMP2P_SET_RMT_DATA(test_request, lock_count |
220 (spinlock_owner << RS_END_THIEF_PID_BIT));
221 (void)msm_smp2p_out_write(handle, test_request);
222
223 failed_tmp = failed;
224 failed = false;
225 do {
226 UT_ASSERT_INT(
227 (int)wait_for_completion_timeout(
228 &cb_in.cb_completion, HZ * 2),
229 >, 0);
230 INIT_COMPLETION(cb_in.cb_completion);
231 ret = msm_smp2p_in_read(remote_pid,
232 SMP2P_RLPB_ENTRY_NAME, &test_response);
233 UT_ASSERT_INT(ret, ==, 0);
234 } while (!failed &&
235 SMP2P_GET_RMT_CMD(test_response) !=
236 SMP2P_LB_CMD_RSPIN_END);
237 if (failed)
238 break;
239 failed = failed_tmp;
240
241 test_response = SMP2P_GET_RMT_DATA(test_response);
242 seq_printf(s,
243 "\tLocked spinlock local %u times; remote %u times",
244 lock_count,
245 test_response & ((1 << RS_END_THIEF_PID_BIT) - 1)
246 );
247 if (test_response & RS_END_THIEF_MASK) {
248 seq_printf(s,
249 "Remote side reporting lock stolen by pid %d.\n",
250 SMP2P_GET_BITS(test_response,
251 RS_END_THIEF_MASK,
252 RS_END_THIEF_PID_BIT));
253 failed = 1;
254 }
255 seq_printf(s, "\n");
256
257 /* Cleanup */
258 ret = msm_smp2p_out_close(&handle);
259 UT_ASSERT_INT(ret, ==, 0);
260 UT_ASSERT_PTR(handle, ==, NULL);
261 ret = msm_smp2p_in_unregister(remote_pid,
262 SMP2P_RLPB_ENTRY_NAME, &cb_in.nb);
263 UT_ASSERT_INT(ret, ==, 0);
264
265 if (!failed && !timeout)
266 seq_printf(s, "\tOK\n");
267 } while (0);
268
269 if (failed) {
270 if (handle) {
271 /* send end command */
272 test_request = 0;
273 SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_RSPIN_END);
274 SMP2P_SET_RMT_DATA(test_request, lock_count);
275 (void)msm_smp2p_out_write(handle, test_request);
276 (void)msm_smp2p_out_close(&handle);
277 }
278 (void)msm_smp2p_in_unregister(remote_pid,
279 SMP2P_RLPB_ENTRY_NAME, &cb_in.nb);
280
281 pr_err("%s: Failed\n", __func__);
282 seq_printf(s, "\tFailed\n");
283 }
284}
285
286/**
287 * smp2p_ut_remote_spinlock_pid - Verify remote spinlock for a processor.
288 *
289 * @s: Pointer to output file
290 * @pid: Processor to test
291 * @use_trylock: Use trylock to prevent an Apps deadlock if the
292 * remote spinlock fails.
293 */
294static void smp2p_ut_remote_spinlock_pid(struct seq_file *s, int pid,
295 bool use_trylock)
296{
297 struct smp2p_interrupt_config *int_cfg;
298
299 int_cfg = smp2p_get_interrupt_config();
300 if (!int_cfg) {
301 seq_printf(s, "Remote processor config unavailable\n");
302 return;
303 }
304
305 if (pid >= SMP2P_NUM_PROCS || !int_cfg[pid].is_configured)
306 return;
307
308 msm_smp2p_deinit_rmt_lpb_proc(pid);
309 smp2p_ut_remote_spinlock_core(s, pid, use_trylock);
310 msm_smp2p_init_rmt_lpb_proc(pid);
311}
312
313/**
314 * smp2p_ut_remote_spinlock - Verify remote spinlock for all processors.
315 *
316 * @s: pointer to output file
317 */
318static void smp2p_ut_remote_spinlock(struct seq_file *s)
319{
320 int pid;
321
322 for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
323 smp2p_ut_remote_spinlock_pid(s, pid, false);
324}
325
326/**
327 * smp2p_ut_remote_spin_trylock - Verify remote trylock for all processors.
328 *
329 * @s: Pointer to output file
330 */
331static void smp2p_ut_remote_spin_trylock(struct seq_file *s)
332{
333 int pid;
334
335 for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
336 smp2p_ut_remote_spinlock_pid(s, pid, true);
337}
338
339/**
340 * smp2p_ut_remote_spinlock - Verify remote spinlock for all processors.
341 *
342 * @s: pointer to output file
343 *
344 * This test verifies inbound and outbound functionality for all
345 * configured remote processor.
346 */
347static void smp2p_ut_remote_spinlock_modem(struct seq_file *s)
348{
349 smp2p_ut_remote_spinlock_pid(s, SMP2P_MODEM_PROC, false);
350}
351
352static void smp2p_ut_remote_spinlock_adsp(struct seq_file *s)
353{
354 smp2p_ut_remote_spinlock_pid(s, SMP2P_AUDIO_PROC, false);
355}
356
357static void smp2p_ut_remote_spinlock_wcnss(struct seq_file *s)
358{
359 smp2p_ut_remote_spinlock_pid(s, SMP2P_WIRELESS_PROC, false);
360}
361
362/**
363 * smp2p_ut_remote_spinlock_rpm - Verify remote spinlock.
364 *
365 * @s: pointer to output file
366 * @remote_pid: Remote processor to test
367 */
368static void smp2p_ut_remote_spinlock_rpm(struct seq_file *s)
369{
370 int failed = 0;
371 unsigned long flags;
372 unsigned n;
373 unsigned test_num;
374 struct rpm_spinlock_test *data_ptr;
375 remote_spinlock_t *smem_spinlock;
376 bool have_lock;
377
378 seq_printf(s, "Running %s for Apps<->RPM Test\n",
379 __func__);
380 do {
381 smem_spinlock = smem_get_remote_spinlock();
382 UT_ASSERT_PTR(smem_spinlock, !=, NULL);
383
384 data_ptr = smem_alloc2(SMEM_ID_VENDOR0,
385 sizeof(struct rpm_spinlock_test));
386 UT_ASSERT_PTR(0, !=, data_ptr);
387
388 /* Send start */
389 writel_relaxed(0, &data_ptr->apps_lock_count);
390 writel_relaxed(RPM_CMD_START, &data_ptr->apps_cmd);
391
392 seq_printf(s, "\tWaiting for RPM to start test\n");
393 for (n = 0; n < 1000; ++n) {
394 if (readl_relaxed(&data_ptr->rpm_cmd) !=
395 RPM_CMD_INVALID)
396 break;
397 usleep(1000);
398 }
399 if (readl_relaxed(&data_ptr->rpm_cmd) == RPM_CMD_INVALID) {
400 /* timeout waiting for RPM */
401 writel_relaxed(RPM_CMD_INVALID, &data_ptr->apps_cmd);
402 UT_ASSERT_INT(RPM_CMD_LOCKED, !=, RPM_CMD_INVALID);
403 }
404
405 /* Run spinlock test */
406 flags = 0;
407 have_lock = false;
408 for (test_num = 0; !failed && test_num < 10000; ++test_num) {
409 /* acquire spinlock */
410 remote_spin_lock_irqsave(smem_spinlock, flags);
411 have_lock = true;
412 writel_relaxed(++data_ptr->apps_lock_count,
413 &data_ptr->apps_lock_count);
414 writel_relaxed(RPM_CMD_LOCKED, &data_ptr->apps_cmd);
415 /*
416 * Ensure that the remote side sees our lock has
417 * been acquired before we start polling their status.
418 */
419 wmb();
420
421 /* verify the other side doesn't say it has the lock */
422 for (n = 0; n < 1000; ++n) {
423 UT_ASSERT_HEX(RPM_CMD_UNLOCKED, ==,
424 readl_relaxed(&data_ptr->rpm_cmd));
425 }
426 if (failed)
427 break;
428
429 /* release spinlock */
430 have_lock = false;
431 writel_relaxed(RPM_CMD_UNLOCKED, &data_ptr->apps_cmd);
432 /*
433 * Ensure that our status-update write was committed
434 * before we unlock the spinlock.
435 */
436 wmb();
437 remote_spin_unlock_irqrestore(smem_spinlock, flags);
438 }
439 if (have_lock)
440 remote_spin_unlock_irqrestore(smem_spinlock, flags);
441
442 /* End test */
443 writel_relaxed(RPM_CMD_INVALID, &data_ptr->apps_cmd);
444 seq_printf(s,
445 "\tLocked spinlock local %u remote %u\n",
446 readl_relaxed(&data_ptr->apps_lock_count),
447 readl_relaxed(&data_ptr->rpm_lock_count));
448
449 if (!failed)
450 seq_printf(s, "\tOK\n");
451 } while (0);
452
453 if (failed) {
454 pr_err("%s: Failed\n", __func__);
455 seq_printf(s, "\tFailed\n");
456 }
457}
458
459static int __init smp2p_debugfs_init(void)
460{
461 /*
462 * Add Unit Test entries.
463 *
464 * The idea with unit tests is that you can run all of them
465 * from ADB shell by doing:
466 * adb shell
467 * cat ut*
468 *
469 * And if particular tests fail, you can then repeatedly run the
470 * failing tests as you debug and resolve the failing test.
471 */
472 smp2p_debug_create("ut_remote_spinlock",
473 smp2p_ut_remote_spinlock);
474 smp2p_debug_create("ut_remote_spin_trylock",
475 smp2p_ut_remote_spin_trylock);
476 smp2p_debug_create("ut_remote_spinlock_modem",
477 smp2p_ut_remote_spinlock_modem);
478 smp2p_debug_create("ut_remote_spinlock_adsp",
479 smp2p_ut_remote_spinlock_adsp);
480 smp2p_debug_create("ut_remote_spinlock_wcnss",
481 smp2p_ut_remote_spinlock_wcnss);
482 smp2p_debug_create("ut_remote_spinlock_rpm",
483 smp2p_ut_remote_spinlock_rpm);
484
485 return 0;
486}
487module_init(smp2p_debugfs_init);