1026 lines
29 KiB
C
1026 lines
29 KiB
C
/* arch/arm/mach-msm/smp2p_test.c
|
|
*
|
|
* 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.
|
|
*/
|
|
#include <linux/debugfs.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/completion.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.reserved = 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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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.reserved = 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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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.reserved = 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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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.reserved = 0x0;
|
|
msm_smp2p_set_remote_mock_exists(true);
|
|
|
|
/* Create test entry and attach loopback server */
|
|
rmp->rx_interrupt_count = 0;
|
|
INIT_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;
|
|
INIT_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;
|
|
INIT_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;
|
|
INIT_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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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_printf(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_printf(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_printf(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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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_printf(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.reserved = 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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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.reserved = 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_printf(s, "\tOK\n");
|
|
} while (0);
|
|
|
|
if (failed) {
|
|
pr_err("%s: Failed\n", __func__);
|
|
seq_printf(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));
|
|
}
|
|
}
|
|
|
|
static struct dentry *dent;
|
|
|
|
static int debugfs_show(struct seq_file *s, void *data)
|
|
{
|
|
void (*show)(struct seq_file *) = s->private;
|
|
|
|
show(s);
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
return 0;
|
|
}
|
|
module_init(smp2p_debugfs_init);
|