android_kernel_oneplus_msm8998/drivers/soc/qcom/smp2p_test.c
Arun Kumar Neelakantam b0930c59a7 soc: qcom: smp2p: Fix simultaneous access of global loopback data
Running SMP2P tests from multiple threads causes simultaneous access to
the global loopback data and resulting into unexpected behavior.

Protect the global loopback data by synchronizing the SMP2P tests.

CRs-Fixed: 2041374
Change-Id: Ifb0e7ce5198af27602881a9132afb353f1a4fc2f
Signed-off-by: Arun Kumar Neelakantam <aneela@codeaurora.org>
2017-05-15 15:29:21 +05:30

1327 lines
37 KiB
C

/* drivers/soc/qcom/smp2p_test.c
*
* Copyright (c) 2013-2017, 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.
*/
#include <linux/debugfs.h>
#include <linux/ctype.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <soc/qcom/subsystem_restart.h>
#include "smp2p_private.h"
#include "smp2p_test_common.h"
/**
* smp2p_ut_local_basic - Basic sanity test using local loopback.
*
* @s: pointer to output file
*
* This test simulates a simple write and read
* when remote processor does not exist.
*/
static void smp2p_ut_local_basic(struct seq_file *s)
{
int failed = 0;
struct msm_smp2p_out *smp2p_obj;
struct msm_smp2p_remote_mock *rmp = NULL;
int ret;
uint32_t test_request;
uint32_t test_response = 0;
static struct mock_cb_data cb_data;
seq_printf(s, "Running %s\n", __func__);
mock_cb_data_init(&cb_data);
do {
/* initialize mock edge and start opening */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0,
sizeof(struct smp2p_smem_item));
msm_smp2p_set_remote_mock_exists(false);
ret = msm_smp2p_out_open(SMP2P_REMOTE_MOCK_PROC, "smp2p",
&cb_data.nb, &smp2p_obj);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
UT_ASSERT_INT(cb_data.cb_count, ==, 0);
rmp->rx_interrupt_count = 0;
/* simulate response from remote side */
rmp->remote_item.header.magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_APPS_PROC);
SMP2P_SET_VERSION(
rmp->remote_item.header.feature_version, 1);
SMP2P_SET_FEATURES(
rmp->remote_item.header.feature_version, 0);
SMP2P_SET_ENT_TOTAL(
rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(
rmp->remote_item.header.valid_total_ent, 0);
rmp->remote_item.header.flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
rmp->tx_interrupt();
/* verify port was opened */
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_data.cb_completion, HZ / 2), >, 0);
UT_ASSERT_INT(cb_data.cb_count, ==, 1);
UT_ASSERT_INT(cb_data.event_open, ==, 1);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
/* do write (test outbound entries) */
rmp->rx_interrupt_count = 0;
test_request = 0xC0DE;
ret = msm_smp2p_out_write(smp2p_obj, test_request);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
/* do read (test inbound entries) */
ret = msm_smp2p_out_read(smp2p_obj, &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(test_request, ==, test_response);
ret = msm_smp2p_out_close(&smp2p_obj);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_PTR(smp2p_obj, ==, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
(void)msm_smp2p_out_close(&smp2p_obj);
}
}
/**
* smp2p_ut_local_late_open - Verify post-negotiation opening.
*
* @s: pointer to output file
*
* Verify entry creation for opening entries after negotiation is complete.
*/
static void smp2p_ut_local_late_open(struct seq_file *s)
{
int failed = 0;
struct msm_smp2p_out *smp2p_obj;
struct msm_smp2p_remote_mock *rmp = NULL;
int ret;
uint32_t test_request;
uint32_t test_response = 0;
static struct mock_cb_data cb_data;
seq_printf(s, "Running %s\n", __func__);
mock_cb_data_init(&cb_data);
do {
/* initialize mock edge */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0,
sizeof(struct smp2p_smem_item));
rmp->remote_item.header.magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_APPS_PROC);
SMP2P_SET_VERSION(
rmp->remote_item.header.feature_version, 1);
SMP2P_SET_FEATURES(
rmp->remote_item.header.feature_version, 0);
SMP2P_SET_ENT_TOTAL(
rmp->remote_item.header.valid_total_ent,
SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(
rmp->remote_item.header.valid_total_ent, 0);
rmp->remote_item.header.flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
ret = msm_smp2p_out_open(SMP2P_REMOTE_MOCK_PROC, "smp2p",
&cb_data.nb, &smp2p_obj);
UT_ASSERT_INT(ret, ==, 0);
/* verify port was opened */
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_data.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_data.cb_count, ==, 1);
UT_ASSERT_INT(cb_data.event_open, ==, 1);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
/* do write (test outbound entries) */
rmp->rx_interrupt_count = 0;
test_request = 0xC0DE;
ret = msm_smp2p_out_write(smp2p_obj, test_request);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
/* do read (test inbound entries) */
ret = msm_smp2p_out_read(smp2p_obj, &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(test_request, ==, test_response);
ret = msm_smp2p_out_close(&smp2p_obj);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_PTR(smp2p_obj, ==, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
(void)msm_smp2p_out_close(&smp2p_obj);
}
}
/**
* smp2p_ut_local_early_open - Verify pre-negotiation opening.
*
* @s: pointer to output file
*
* Verify entry creation for opening entries before negotiation is complete.
*/
static void smp2p_ut_local_early_open(struct seq_file *s)
{
int failed = 0;
struct msm_smp2p_out *smp2p_obj;
struct msm_smp2p_remote_mock *rmp = NULL;
struct smp2p_smem *outbound_item;
int negotiation_state;
int ret;
uint32_t test_request;
uint32_t test_response = 0;
static struct mock_cb_data cb_data;
seq_printf(s, "Running %s\n", __func__);
mock_cb_data_init(&cb_data);
do {
/* initialize mock edge, but don't enable, yet */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0,
sizeof(struct smp2p_smem_item));
rmp->remote_item.header.magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_APPS_PROC);
SMP2P_SET_VERSION(
rmp->remote_item.header.feature_version, 1);
SMP2P_SET_FEATURES(
rmp->remote_item.header.feature_version, 0);
SMP2P_SET_ENT_TOTAL(
rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(
rmp->remote_item.header.valid_total_ent, 0);
rmp->remote_item.header.flags = 0x0;
msm_smp2p_set_remote_mock_exists(false);
UT_ASSERT_PTR(NULL, ==,
smp2p_get_in_item(SMP2P_REMOTE_MOCK_PROC));
/* initiate open, but verify it doesn't complete */
ret = msm_smp2p_out_open(SMP2P_REMOTE_MOCK_PROC, "smp2p",
&cb_data.nb, &smp2p_obj);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_data.cb_completion, HZ / 8),
==, 0);
UT_ASSERT_INT(cb_data.cb_count, ==, 0);
UT_ASSERT_INT(cb_data.event_open, ==, 0);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
outbound_item = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
&negotiation_state);
UT_ASSERT_PTR(outbound_item, !=, NULL);
UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENING);
UT_ASSERT_INT(0, ==,
SMP2P_GET_ENT_VALID(outbound_item->valid_total_ent));
/* verify that read/write don't work yet */
rmp->rx_interrupt_count = 0;
test_request = 0x0;
ret = msm_smp2p_out_write(smp2p_obj, test_request);
UT_ASSERT_INT(ret, ==, -ENODEV);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 0);
ret = msm_smp2p_out_read(smp2p_obj, &test_response);
UT_ASSERT_INT(ret, ==, -ENODEV);
/* allocate remote entry and verify open */
msm_smp2p_set_remote_mock_exists(true);
rmp->tx_interrupt();
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_data.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_data.cb_count, ==, 1);
UT_ASSERT_INT(cb_data.event_open, ==, 1);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
/* do write (test outbound entries) */
rmp->rx_interrupt_count = 0;
test_request = 0xC0DE;
ret = msm_smp2p_out_write(smp2p_obj, test_request);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
/* do read (test inbound entries) */
ret = msm_smp2p_out_read(smp2p_obj, &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(test_request, ==, test_response);
ret = msm_smp2p_out_close(&smp2p_obj);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_PTR(smp2p_obj, ==, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
(void)msm_smp2p_out_close(&smp2p_obj);
}
}
/**
* smp2p_ut_mock_loopback - Exercise the remote loopback using remote mock.
*
* @s: pointer to output file
*
* This test exercises the remote loopback code using
* remote mock object. The remote mock object simulates the remote
* processor sending remote loopback commands to the local processor.
*/
static void smp2p_ut_mock_loopback(struct seq_file *s)
{
int failed = 0;
struct msm_smp2p_remote_mock *rmp = NULL;
int ret;
uint32_t test_request = 0;
uint32_t test_response = 0;
struct msm_smp2p_out *local;
seq_printf(s, "Running %s\n", __func__);
do {
/* Initialize the mock edge */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
memset(&rmp->remote_item, 0,
sizeof(struct smp2p_smem_item));
rmp->remote_item.header.magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_APPS_PROC);
SMP2P_SET_VERSION(
rmp->remote_item.header.feature_version, 1);
SMP2P_SET_FEATURES(
rmp->remote_item.header.feature_version, 0);
SMP2P_SET_ENT_TOTAL(
rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(
rmp->remote_item.header.valid_total_ent, 1);
rmp->remote_item.header.flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
/* Create test entry and attach loopback server */
rmp->rx_interrupt_count = 0;
reinit_completion(&rmp->cb_completion);
strlcpy(rmp->remote_item.entries[0].name, "smp2p",
SMP2P_MAX_ENTRY_NAME);
rmp->remote_item.entries[0].entry = 0;
rmp->tx_interrupt();
local = msm_smp2p_init_rmt_lpb_proc(SMP2P_REMOTE_MOCK_PROC);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&rmp->cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 2);
/* Send Echo Command */
rmp->rx_interrupt_count = 0;
reinit_completion(&rmp->cb_completion);
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_ECHO);
SMP2P_SET_RMT_DATA(test_request, 10);
rmp->remote_item.entries[0].entry = test_request;
rmp->tx_interrupt();
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&rmp->cb_completion, HZ / 2),
>, 0);
/* Verify Echo Response */
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
ret = msm_smp2p_out_read(local,
&test_response);
UT_ASSERT_INT(ret, ==, 0);
test_response = SMP2P_GET_RMT_DATA(test_response);
UT_ASSERT_INT(test_response, ==, 10);
/* Send PINGPONG command */
test_request = 0;
test_response = 0;
rmp->rx_interrupt_count = 0;
reinit_completion(&rmp->cb_completion);
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_PINGPONG);
SMP2P_SET_RMT_DATA(test_request, 10);
rmp->remote_item.entries[0].entry = test_request;
rmp->tx_interrupt();
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&rmp->cb_completion, HZ / 2),
>, 0);
/* Verify PINGPONG Response */
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
ret = msm_smp2p_out_read(local, &test_response);
UT_ASSERT_INT(ret, ==, 0);
test_response = SMP2P_GET_RMT_DATA(test_response);
UT_ASSERT_INT(test_response, ==, 9);
/* Send CLEARALL command */
test_request = 0;
test_response = 0;
rmp->rx_interrupt_count = 0;
reinit_completion(&rmp->cb_completion);
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_CLEARALL);
SMP2P_SET_RMT_DATA(test_request, 10);
rmp->remote_item.entries[0].entry = test_request;
rmp->tx_interrupt();
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&rmp->cb_completion, HZ / 2),
>, 0);
/* Verify CLEARALL response */
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
ret = msm_smp2p_out_read(local, &test_response);
UT_ASSERT_INT(ret, ==, 0);
test_response = SMP2P_GET_RMT_DATA(test_response);
UT_ASSERT_INT(test_response, ==, 0);
ret = msm_smp2p_deinit_rmt_lpb_proc(SMP2P_REMOTE_MOCK_PROC);
UT_ASSERT_INT(ret, ==, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
msm_smp2p_deinit_rmt_lpb_proc(SMP2P_REMOTE_MOCK_PROC);
}
}
/**
* smp2p_ut_remote_inout_core - Verify inbound/outbound functionality.
*
* @s: pointer to output file
* @remote_pid: Remote processor to test
*
* This test verifies inbound/outbound functionality for the remote processor.
*/
static void smp2p_ut_remote_inout_core(struct seq_file *s, int remote_pid)
{
int failed = 0;
struct msm_smp2p_out *handle;
int ret;
uint32_t test_request;
uint32_t test_response = 0;
static struct mock_cb_data cb_out;
static struct mock_cb_data cb_in;
seq_printf(s, "Running %s for '%s' remote pid %d\n",
__func__, smp2p_pid_to_name(remote_pid), remote_pid);
mock_cb_data_init(&cb_out);
mock_cb_data_init(&cb_in);
do {
/* Open output entry */
ret = msm_smp2p_out_open(remote_pid, "smp2p",
&cb_out.nb, &handle);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_out.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_out.cb_count, ==, 1);
UT_ASSERT_INT(cb_out.event_open, ==, 1);
/* Open inbound entry */
ret = msm_smp2p_in_register(remote_pid, "smp2p",
&cb_in.nb);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_in.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in.cb_count, ==, 1);
UT_ASSERT_INT(cb_in.event_open, ==, 1);
/* Write an echo request */
mock_cb_data_reset(&cb_out);
mock_cb_data_reset(&cb_in);
test_request = 0x0;
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_ECHO);
SMP2P_SET_RMT_DATA(test_request, 0xAA55);
ret = msm_smp2p_out_write(handle, test_request);
UT_ASSERT_INT(ret, ==, 0);
/* Verify inbound reply */
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_in.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in.cb_count, ==, 1);
UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
UT_ASSERT_INT(SMP2P_GET_RMT_DATA(
cb_in.entry_data.current_value), ==, 0xAA55);
ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(0, ==, SMP2P_GET_RMT_CMD_TYPE(test_response));
UT_ASSERT_INT(SMP2P_LB_CMD_ECHO, ==,
SMP2P_GET_RMT_CMD(test_response));
UT_ASSERT_INT(0xAA55, ==, SMP2P_GET_RMT_DATA(test_response));
/* Write a clear all request */
mock_cb_data_reset(&cb_in);
test_request = 0x0;
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_CLEARALL);
SMP2P_SET_RMT_DATA(test_request, 0xAA55);
ret = msm_smp2p_out_write(handle, test_request);
UT_ASSERT_INT(ret, ==, 0);
/* Verify inbound reply */
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_in.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in.cb_count, ==, 1);
UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
UT_ASSERT_INT(SMP2P_GET_RMT_DATA(
cb_in.entry_data.current_value), ==, 0x0000);
ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(0, ==, SMP2P_GET_RMT_CMD_TYPE(test_response));
UT_ASSERT_INT(0x0000, ==, SMP2P_GET_RMT_DATA(test_response));
/* Write a decrement request */
mock_cb_data_reset(&cb_in);
test_request = 0x0;
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_LB_CMD_PINGPONG);
SMP2P_SET_RMT_DATA(test_request, 0xAA55);
ret = msm_smp2p_out_write(handle, test_request);
UT_ASSERT_INT(ret, ==, 0);
/* Verify inbound reply */
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_in.cb_completion, HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in.cb_count, ==, 1);
UT_ASSERT_INT(cb_in.event_entry_update, ==, 1);
UT_ASSERT_INT(SMP2P_GET_RMT_DATA(
cb_in.entry_data.current_value), ==, 0xAA54);
ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(0, ==, SMP2P_GET_RMT_CMD_TYPE(test_response));
UT_ASSERT_INT(SMP2P_LB_CMD_PINGPONG, ==,
SMP2P_GET_RMT_CMD(test_response));
UT_ASSERT_INT(0xAA54, ==, SMP2P_GET_RMT_DATA(test_response));
/* Test the ignore flag */
mock_cb_data_reset(&cb_in);
test_request = 0x0;
SMP2P_SET_RMT_CMD_TYPE(test_request, 1);
SMP2P_SET_RMT_CMD(test_request, SMP2P_RLPB_IGNORE);
SMP2P_SET_RMT_DATA(test_request, 0xAA55);
ret = msm_smp2p_out_write(handle, test_request);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&cb_in.cb_completion, HZ / 2),
==, 0);
UT_ASSERT_INT(cb_in.cb_count, ==, 0);
UT_ASSERT_INT(cb_in.event_entry_update, ==, 0);
ret = msm_smp2p_in_read(remote_pid, "smp2p", &test_response);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(0xAA54, ==, SMP2P_GET_RMT_DATA(test_response));
/* Cleanup */
ret = msm_smp2p_out_close(&handle);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_PTR(handle, ==, 0);
ret = msm_smp2p_in_unregister(remote_pid, "smp2p", &cb_in.nb);
UT_ASSERT_INT(ret, ==, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
if (handle)
(void)msm_smp2p_out_close(&handle);
(void)msm_smp2p_in_unregister(remote_pid, "smp2p", &cb_in.nb);
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
}
}
/**
* smp2p_ut_remote_inout - Verify inbound/outbound functionality for all.
*
* @s: pointer to output file
*
* This test verifies inbound and outbound functionality for all
* configured remote processor.
*/
static void smp2p_ut_remote_inout(struct seq_file *s)
{
struct smp2p_interrupt_config *int_cfg;
int pid;
int_cfg = smp2p_get_interrupt_config();
if (!int_cfg) {
seq_puts(s, "Remote processor config unavailable\n");
return;
}
for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
if (!int_cfg[pid].is_configured)
continue;
msm_smp2p_deinit_rmt_lpb_proc(pid);
smp2p_ut_remote_inout_core(s, pid);
msm_smp2p_init_rmt_lpb_proc(pid);
}
}
/**
* smp2p_ut_remote_out_max_entries_core - Verify open functionality.
*
* @s: pointer to output file
* @remote_pid: Remote processor for which the test is executed.
*
* This test verifies open functionality by creating maximum outbound entries.
*/
static void smp2p_ut_remote_out_max_entries_core(struct seq_file *s,
int remote_pid)
{
int j = 0;
int failed = 0;
struct msm_smp2p_out *handle[SMP2P_MAX_ENTRY];
int ret;
static struct mock_cb_data cb_out[SMP2P_MAX_ENTRY];
char entry_name[SMP2P_MAX_ENTRY_NAME];
int num_created;
seq_printf(s, "Running %s for '%s' remote pid %d\n",
__func__, smp2p_pid_to_name(remote_pid), remote_pid);
for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
handle[j] = NULL;
mock_cb_data_init(&cb_out[j]);
}
do {
num_created = 0;
for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
/* Open as many output entries as possible */
scnprintf((char *)entry_name, SMP2P_MAX_ENTRY_NAME,
"smp2p%d", j);
ret = msm_smp2p_out_open(remote_pid, entry_name,
&cb_out[j].nb, &handle[j]);
if (ret == -ENOMEM)
/* hit max number */
break;
UT_ASSERT_INT(ret, ==, 0);
++num_created;
}
if (failed)
break;
/* verify we created more than 1 entry */
UT_ASSERT_INT(num_created, <=, SMP2P_MAX_ENTRY);
UT_ASSERT_INT(num_created, >, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
}
/* cleanup */
for (j = 0; j < SMP2P_MAX_ENTRY; j++)
ret = msm_smp2p_out_close(&handle[j]);
}
/**
* smp2p_ut_remote_out_max_entries - Verify open for all configured processors.
*
* @s: pointer to output file
*
* This test verifies creating max number of entries for
* all configured remote processor.
*/
static void smp2p_ut_remote_out_max_entries(struct seq_file *s)
{
struct smp2p_interrupt_config *int_cfg;
int pid;
int_cfg = smp2p_get_interrupt_config();
if (!int_cfg) {
seq_puts(s, "Remote processor config unavailable\n");
return;
}
for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
if (!int_cfg[pid].is_configured)
continue;
smp2p_ut_remote_out_max_entries_core(s, pid);
}
}
/**
* smp2p_ut_local_in_max_entries - Verify registering and unregistering.
*
* @s: pointer to output file
*
* This test verifies registering and unregistering for inbound entries using
* the remote mock processor.
*/
static void smp2p_ut_local_in_max_entries(struct seq_file *s)
{
int j = 0;
int failed = 0;
struct msm_smp2p_remote_mock *rmp = NULL;
int ret;
static struct mock_cb_data cb_in[SMP2P_MAX_ENTRY];
static struct mock_cb_data cb_out;
seq_printf(s, "Running %s\n", __func__);
for (j = 0; j < SMP2P_MAX_ENTRY; j++)
mock_cb_data_init(&cb_in[j]);
mock_cb_data_init(&cb_out);
do {
/* Initialize mock edge */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0,
sizeof(struct smp2p_smem_item));
rmp->remote_item.header.magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_APPS_PROC);
SMP2P_SET_VERSION(
rmp->remote_item.header.feature_version, 1);
SMP2P_SET_FEATURES(
rmp->remote_item.header.feature_version, 0);
SMP2P_SET_ENT_TOTAL(
rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(
rmp->remote_item.header.valid_total_ent, 0);
rmp->remote_item.header.flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
/* Create Max Entries in the remote mock object */
for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
scnprintf(rmp->remote_item.entries[j].name,
SMP2P_MAX_ENTRY_NAME, "smp2p%d", j);
rmp->remote_item.entries[j].entry = 0;
rmp->tx_interrupt();
}
/* Register for in entries */
for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[j].name,
&(cb_in[j].nb));
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&(cb_in[j].cb_completion), HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in[j].cb_count, ==, 1);
UT_ASSERT_INT(cb_in[j].event_entry_update, ==, 0);
}
UT_ASSERT_INT(j, ==, SMP2P_MAX_ENTRY);
/* Unregister */
for (j = 0; j < SMP2P_MAX_ENTRY; j++) {
ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[j].name,
&(cb_in[j].nb));
UT_ASSERT_INT(ret, ==, 0);
}
UT_ASSERT_INT(j, ==, SMP2P_MAX_ENTRY);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
for (j = 0; j < SMP2P_MAX_ENTRY; j++)
ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[j].name,
&(cb_in[j].nb));
}
}
/**
* smp2p_ut_local_in_multiple - Verify Multiple Inbound Registration.
*
* @s: pointer to output file
*
* This test verifies multiple clients registering for same inbound entries
* using the remote mock processor.
*/
static void smp2p_ut_local_in_multiple(struct seq_file *s)
{
int failed = 0;
struct msm_smp2p_remote_mock *rmp = NULL;
int ret;
static struct mock_cb_data cb_in_1;
static struct mock_cb_data cb_in_2;
static struct mock_cb_data cb_out;
seq_printf(s, "Running %s\n", __func__);
mock_cb_data_init(&cb_in_1);
mock_cb_data_init(&cb_in_2);
mock_cb_data_init(&cb_out);
do {
/* Initialize mock edge */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0,
sizeof(struct smp2p_smem_item));
rmp->remote_item.header.magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(
rmp->remote_item.header.rem_loc_proc_id,
SMP2P_APPS_PROC);
SMP2P_SET_VERSION(
rmp->remote_item.header.feature_version, 1);
SMP2P_SET_FEATURES(
rmp->remote_item.header.feature_version, 0);
SMP2P_SET_ENT_TOTAL(
rmp->remote_item.header.valid_total_ent, 1);
SMP2P_SET_ENT_VALID(
rmp->remote_item.header.valid_total_ent, 0);
rmp->remote_item.header.flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
/* Create an Entry in the remote mock object */
scnprintf(rmp->remote_item.entries[0].name,
SMP2P_MAX_ENTRY_NAME, "smp2p%d", 1);
rmp->remote_item.entries[0].entry = 0;
rmp->tx_interrupt();
/* Register multiple clients for the inbound entry */
ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[0].name,
&cb_in_1.nb);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&(cb_in_1.cb_completion), HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in_1.cb_count, ==, 1);
UT_ASSERT_INT(cb_in_1.event_entry_update, ==, 0);
ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[0].name,
&cb_in_2.nb);
UT_ASSERT_INT(ret, ==, 0);
UT_ASSERT_INT(
(int)wait_for_completion_timeout(
&(cb_in_2.cb_completion), HZ / 2),
>, 0);
UT_ASSERT_INT(cb_in_2.cb_count, ==, 1);
UT_ASSERT_INT(cb_in_2.event_entry_update, ==, 0);
/* Unregister the clients */
ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[0].name,
&(cb_in_1.nb));
UT_ASSERT_INT(ret, ==, 0);
ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[0].name,
&(cb_in_2.nb));
UT_ASSERT_INT(ret, ==, 0);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[0].name,
&(cb_in_1.nb));
ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
rmp->remote_item.entries[0].name,
&(cb_in_2.nb));
}
}
/**
* smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
*
* @s: pointer to output file
*/
static void smp2p_ut_local_ssr_ack(struct seq_file *s)
{
int failed = 0;
struct msm_smp2p_remote_mock *rmp = NULL;
int ret;
seq_printf(s, "Running %s\n", __func__);
do {
struct smp2p_smem *rhdr;
struct smp2p_smem *lhdr;
int negotiation_state;
/* initialize v1 without SMP2P_FEATURE_SSR_ACK enabled */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rhdr = &rmp->remote_item.header;
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
rhdr->magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
SMP2P_SET_VERSION(rhdr->feature_version, 1);
SMP2P_SET_FEATURES(rhdr->feature_version, 0);
SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
rhdr->flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
rmp->tx_interrupt();
/* verify edge is open */
lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
&negotiation_state);
UT_ASSERT_PTR(NULL, !=, lhdr);
UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
/* verify no response to ack feature */
rmp->rx_interrupt_count = 0;
SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
rmp->tx_interrupt();
UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 0);
/* initialize v1 with SMP2P_FEATURE_SSR_ACK enabled */
ret = smp2p_reset_mock_edge();
UT_ASSERT_INT(ret, ==, 0);
rmp = msm_smp2p_get_remote_mock();
UT_ASSERT_PTR(rmp, !=, NULL);
rhdr = &rmp->remote_item.header;
rmp->rx_interrupt_count = 0;
memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
rhdr->magic = SMP2P_MAGIC;
SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
SMP2P_REMOTE_MOCK_PROC);
SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
SMP2P_SET_VERSION(rhdr->feature_version, 1);
SMP2P_SET_FEATURES(rhdr->feature_version,
SMP2P_FEATURE_SSR_ACK);
SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
rmp->rx_interrupt_count = 0;
rhdr->flags = 0x0;
msm_smp2p_set_remote_mock_exists(true);
rmp->tx_interrupt();
/* verify edge is open */
lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
&negotiation_state);
UT_ASSERT_PTR(NULL, !=, lhdr);
UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
/* verify response to ack feature */
rmp->rx_interrupt_count = 0;
SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
rmp->tx_interrupt();
UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
UT_ASSERT_INT(1, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
rmp->rx_interrupt_count = 0;
SMP2P_SET_RESTART_DONE(rhdr->flags, 0);
rmp->tx_interrupt();
UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
}
}
/**
* get_ssr_name_for_proc - Retrieve an SSR name from the provided list
*
* @names: List of possible processor names
* @name_len: The length of @names
* @index: Index into @names
*
* Return: Pointer to the next processor name, NULL in error conditions
*/
static char *get_ssr_name_for_proc(char *names[], size_t name_len, int index)
{
if (index >= name_len) {
pr_err("%s: SSR failed; check subsys name table\n",
__func__);
return NULL;
}
return names[index];
}
/**
* smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
*
* @s: pointer to output file
* @rpid: Remote processor ID
* @int_cfg: Interrupt config
*/
static void smp2p_ut_remotesubsys_ssr_ack(struct seq_file *s, uint32_t rpid,
struct smp2p_interrupt_config *int_cfg)
{
int failed = 0;
seq_printf(s, "Running %s\n", __func__);
do {
struct smp2p_smem *rhdr;
struct smp2p_smem *lhdr;
int negotiation_state;
int name_index;
int ret;
uint32_t ssr_done_start;
bool ssr_ack_enabled = false;
bool ssr_success = false;
char *name = NULL;
static char *mpss_names[] = {"modem", "mpss"};
static char *lpass_names[] = {"adsp", "lpass"};
static char *sensor_names[] = {"slpi", "dsps"};
static char *wcnss_names[] = {"wcnss"};
lhdr = smp2p_get_out_item(rpid, &negotiation_state);
UT_ASSERT_PTR(NULL, !=, lhdr);
UT_ASSERT_INT(SMP2P_EDGE_STATE_OPENED, ==, negotiation_state);
rhdr = smp2p_get_in_item(rpid);
UT_ASSERT_PTR(NULL, !=, rhdr);
/* get initial state of SSR flags */
if (SMP2P_GET_FEATURES(rhdr->feature_version)
& SMP2P_FEATURE_SSR_ACK)
ssr_ack_enabled = true;
else
ssr_ack_enabled = false;
ssr_done_start = SMP2P_GET_RESTART_DONE(rhdr->flags);
UT_ASSERT_INT(ssr_done_start, ==,
SMP2P_GET_RESTART_ACK(lhdr->flags));
/* trigger restart */
name_index = 0;
while (!ssr_success) {
switch (rpid) {
case SMP2P_MODEM_PROC:
name = get_ssr_name_for_proc(mpss_names,
ARRAY_SIZE(mpss_names),
name_index);
break;
case SMP2P_AUDIO_PROC:
name = get_ssr_name_for_proc(lpass_names,
ARRAY_SIZE(lpass_names),
name_index);
break;
case SMP2P_SENSOR_PROC:
name = get_ssr_name_for_proc(sensor_names,
ARRAY_SIZE(sensor_names),
name_index);
break;
case SMP2P_WIRELESS_PROC:
name = get_ssr_name_for_proc(wcnss_names,
ARRAY_SIZE(wcnss_names),
name_index);
break;
default:
pr_err("%s: Invalid proc ID %d given for ssr\n",
__func__, rpid);
}
if (!name) {
seq_puts(s, "\tSSR failed; check subsys name table\n");
failed = true;
break;
}
seq_printf(s, "Restarting '%s'\n", name);
ret = subsystem_restart(name);
if (ret == -ENODEV) {
seq_puts(s, "\tSSR call failed\n");
++name_index;
continue;
}
ssr_success = true;
}
if (failed)
break;
msleep(10*1000);
/* verify ack signaling */
if (ssr_ack_enabled) {
ssr_done_start ^= 1;
UT_ASSERT_INT(ssr_done_start, ==,
SMP2P_GET_RESTART_ACK(lhdr->flags));
UT_ASSERT_INT(ssr_done_start, ==,
SMP2P_GET_RESTART_DONE(rhdr->flags));
UT_ASSERT_INT(0, ==,
SMP2P_GET_RESTART_DONE(lhdr->flags));
seq_puts(s, "\tSSR ACK Enabled and Toggled\n");
} else {
UT_ASSERT_INT(0, ==,
SMP2P_GET_RESTART_DONE(lhdr->flags));
UT_ASSERT_INT(0, ==,
SMP2P_GET_RESTART_ACK(lhdr->flags));
UT_ASSERT_INT(0, ==,
SMP2P_GET_RESTART_DONE(rhdr->flags));
UT_ASSERT_INT(0, ==,
SMP2P_GET_RESTART_ACK(rhdr->flags));
seq_puts(s, "\tSSR ACK Disabled\n");
}
seq_puts(s, "\tOK\n");
} while (0);
if (failed) {
pr_err("%s: Failed\n", __func__);
seq_puts(s, "\tFailed\n");
}
}
/**
* smp2p_ut_remote_ssr_ack - Verify SSR Done/ACK Feature
*
* @s: pointer to output file
*
* Triggers SSR for each subsystem.
*/
static void smp2p_ut_remote_ssr_ack(struct seq_file *s)
{
struct smp2p_interrupt_config *int_cfg;
int pid;
int_cfg = smp2p_get_interrupt_config();
if (!int_cfg) {
seq_puts(s,
"Remote processor config unavailable\n");
return;
}
for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
if (!int_cfg[pid].is_configured)
continue;
msm_smp2p_deinit_rmt_lpb_proc(pid);
smp2p_ut_remotesubsys_ssr_ack(s, pid, &int_cfg[pid]);
msm_smp2p_init_rmt_lpb_proc(pid);
}
}
static struct dentry *dent;
static DEFINE_MUTEX(show_lock);
static int debugfs_show(struct seq_file *s, void *data)
{
void (*show)(struct seq_file *) = s->private;
mutex_lock(&show_lock);
show(s);
mutex_unlock(&show_lock);
return 0;
}
static int debug_open(struct inode *inode, struct file *file)
{
return single_open(file, debugfs_show, inode->i_private);
}
static const struct file_operations debug_ops = {
.open = debug_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
};
void smp2p_debug_create(const char *name,
void (*show)(struct seq_file *))
{
struct dentry *file;
file = debugfs_create_file(name, 0444, dent, show, &debug_ops);
if (!file)
pr_err("%s: unable to create file '%s'\n", __func__, name);
}
void smp2p_debug_create_u32(const char *name, uint32_t *value)
{
struct dentry *file;
file = debugfs_create_u32(name, S_IRUGO | S_IWUSR, dent, value);
if (!file)
pr_err("%s: unable to create file '%s'\n", __func__, name);
}
static int __init smp2p_debugfs_init(void)
{
dent = debugfs_create_dir("smp2p_test", 0);
if (IS_ERR(dent))
return PTR_ERR(dent);
/*
* Add Unit Test entries.
*
* The idea with unit tests is that you can run all of them
* from ADB shell by doing:
* adb shell
* cat ut*
*
* And if particular tests fail, you can then repeatedly run the
* failing tests as you debug and resolve the failing test.
*/
smp2p_debug_create("ut_local_basic",
smp2p_ut_local_basic);
smp2p_debug_create("ut_local_late_open",
smp2p_ut_local_late_open);
smp2p_debug_create("ut_local_early_open",
smp2p_ut_local_early_open);
smp2p_debug_create("ut_mock_loopback",
smp2p_ut_mock_loopback);
smp2p_debug_create("ut_remote_inout",
smp2p_ut_remote_inout);
smp2p_debug_create("ut_local_in_max_entries",
smp2p_ut_local_in_max_entries);
smp2p_debug_create("ut_remote_out_max_entries",
smp2p_ut_remote_out_max_entries);
smp2p_debug_create("ut_local_in_multiple",
smp2p_ut_local_in_multiple);
smp2p_debug_create("ut_local_ssr_ack",
smp2p_ut_local_ssr_ack);
smp2p_debug_create("ut_remote_ssr_ack",
smp2p_ut_remote_ssr_ack);
return 0;
}
module_init(smp2p_debugfs_init);