| /* arch/arm/mach-msm/smp2p_test_common.h |
| * |
| * Copyright (c) 2013, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| #ifndef _ARCH_ARM_MACH_MSM_SMP2P_TEST_COMMON_H_ |
| #define _ARCH_ARM_MACH_MSM_SMP2P_TEST_COMMON_H_ |
| |
| #include <linux/debugfs.h> |
| |
| /** |
| * Unit test assertion for logging test cases. |
| * |
| * @a lval |
| * @b rval |
| * @cmp comparison operator |
| * |
| * Assertion fails if (@a cmp @b) is not true which then |
| * logs the function and line number where the error occurred |
| * along with the values of @a and @b. |
| * |
| * Assumes that the following local variables exist: |
| * @s - sequential output file pointer |
| * @failed - set to true if test fails |
| */ |
| #define UT_ASSERT_INT(a, cmp, b) \ |
| { \ |
| int a_tmp = (a); \ |
| int b_tmp = (b); \ |
| if (!((a_tmp)cmp(b_tmp))) { \ |
| seq_printf(s, \ |
| "%s:%d Fail: " #a "(%d) " #cmp " " #b "(%d)\n", \ |
| __func__, __LINE__, \ |
| a_tmp, b_tmp); \ |
| failed = 1; \ |
| break; \ |
| } \ |
| } |
| |
| #define UT_ASSERT_PTR(a, cmp, b) \ |
| { \ |
| void *a_tmp = (a); \ |
| void *b_tmp = (b); \ |
| if (!((a_tmp)cmp(b_tmp))) { \ |
| seq_printf(s, \ |
| "%s:%d Fail: " #a "(%p) " #cmp " " #b "(%p)\n", \ |
| __func__, __LINE__, \ |
| a_tmp, b_tmp); \ |
| failed = 1; \ |
| break; \ |
| } \ |
| } |
| |
| #define UT_ASSERT_UINT(a, cmp, b) \ |
| { \ |
| unsigned a_tmp = (a); \ |
| unsigned b_tmp = (b); \ |
| if (!((a_tmp)cmp(b_tmp))) { \ |
| seq_printf(s, \ |
| "%s:%d Fail: " #a "(%u) " #cmp " " #b "(%u)\n", \ |
| __func__, __LINE__, \ |
| a_tmp, b_tmp); \ |
| failed = 1; \ |
| break; \ |
| } \ |
| } |
| |
| #define UT_ASSERT_HEX(a, cmp, b) \ |
| { \ |
| unsigned a_tmp = (a); \ |
| unsigned b_tmp = (b); \ |
| if (!((a_tmp)cmp(b_tmp))) { \ |
| seq_printf(s, \ |
| "%s:%d Fail: " #a "(%x) " #cmp " " #b "(%x)\n", \ |
| __func__, __LINE__, \ |
| a_tmp, b_tmp); \ |
| failed = 1; \ |
| break; \ |
| } \ |
| } |
| |
| /** |
| * In-range unit test assertion for test cases. |
| * |
| * @a lval |
| * @minv Minimum value |
| * @maxv Maximum value |
| * |
| * Assertion fails if @a is not on the exclusive range minv, maxv |
| * ((@a < @minv) or (@a > @maxv)). In the failure case, the macro |
| * logs the function and line number where the error occurred along |
| * with the values of @a and @minv, @maxv. |
| * |
| * Assumes that the following local variables exist: |
| * @s - sequential output file pointer |
| * @failed - set to true if test fails |
| */ |
| #define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \ |
| { \ |
| int a_tmp = (a); \ |
| int minv_tmp = (minv); \ |
| int maxv_tmp = (maxv); \ |
| if (((a_tmp) < (minv_tmp)) || ((a_tmp) > (maxv_tmp))) { \ |
| seq_printf(s, \ |
| "%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \ |
| #a "(%d) > " #maxv "(%d)\n", \ |
| __func__, __LINE__, \ |
| a_tmp, minv_tmp, a_tmp, maxv_tmp); \ |
| failed = 1; \ |
| break; \ |
| } \ |
| } |
| |
| /* Structure to track state changes for the notifier callback. */ |
| struct mock_cb_data { |
| bool initialized; |
| spinlock_t lock; |
| struct notifier_block nb; |
| |
| /* events */ |
| struct completion cb_completion; |
| int cb_count; |
| int event_open; |
| int event_entry_update; |
| struct msm_smp2p_update_notif entry_data; |
| }; |
| |
| void smp2p_debug_create(const char *name, void (*show)(struct seq_file *)); |
| static inline int smp2p_test_notify(struct notifier_block *self, |
| unsigned long event, void *data); |
| |
| /** |
| * Reset mock callback data to default values. |
| * |
| * @cb: Mock callback data |
| */ |
| static inline void mock_cb_data_reset(struct mock_cb_data *cb) |
| { |
| INIT_COMPLETION(cb->cb_completion); |
| cb->cb_count = 0; |
| cb->event_open = 0; |
| cb->event_entry_update = 0; |
| memset(&cb->entry_data, 0, |
| sizeof(struct msm_smp2p_update_notif)); |
| } |
| |
| |
| /** |
| * Initialize mock callback data. |
| * |
| * @cb: Mock callback data |
| */ |
| static inline void mock_cb_data_init(struct mock_cb_data *cb) |
| { |
| if (!cb->initialized) { |
| init_completion(&cb->cb_completion); |
| spin_lock_init(&cb->lock); |
| cb->initialized = true; |
| cb->nb.notifier_call = smp2p_test_notify; |
| memset(&cb->entry_data, 0, |
| sizeof(struct msm_smp2p_update_notif)); |
| } |
| mock_cb_data_reset(cb); |
| } |
| |
| /** |
| * Notifier function passed into SMP2P for testing. |
| * |
| * @self: Pointer to calling notifier block |
| * @event: Event |
| * @data: Event-specific data |
| * @returns: 0 |
| */ |
| static inline int smp2p_test_notify(struct notifier_block *self, |
| unsigned long event, void *data) |
| { |
| struct mock_cb_data *cb_data_ptr; |
| unsigned long flags; |
| |
| cb_data_ptr = container_of(self, struct mock_cb_data, nb); |
| |
| spin_lock_irqsave(&cb_data_ptr->lock, flags); |
| |
| switch (event) { |
| case SMP2P_OPEN: |
| ++cb_data_ptr->event_open; |
| if (data) { |
| cb_data_ptr->entry_data = |
| *(struct msm_smp2p_update_notif *)(data); |
| } |
| break; |
| case SMP2P_ENTRY_UPDATE: |
| ++cb_data_ptr->event_entry_update; |
| if (data) { |
| cb_data_ptr->entry_data = |
| *(struct msm_smp2p_update_notif *)(data); |
| } |
| break; |
| default: |
| pr_err("%s Unknown event\n", __func__); |
| break; |
| } |
| |
| ++cb_data_ptr->cb_count; |
| complete(&cb_data_ptr->cb_completion); |
| spin_unlock_irqrestore(&cb_data_ptr->lock, flags); |
| return 0; |
| } |
| #endif /* _ARCH_ARM_MACH_MSM_SMP2P_TEST_COMMON_H_ */ |