Преглед изворни кода

msm: synx: ipclite: Testing for IPCLite

1. Enables user to test all features of IPCLite.
2. Sends testing pings and receives replies to verify proper
functionality.
3. Allows end user to configure test with various testing parameters.

Change-Id: Id22ee40990cfe750301d1c03d6215f49a03bae47
Signed-off-by: Nagendra Jamadagni <[email protected]>
Nagendra Jamadagni пре 2 година
родитељ
комит
b0fd26d5a8
7 измењених фајлова са 1594 додато и 1 уклоњено
  1. 11 1
      Android.mk
  2. 1 0
      msm/Kbuild
  3. 1455 0
      msm/synx/test/ipclite_test.c
  4. 118 0
      msm/synx/test/ipclite_test.h
  5. 1 0
      pineapple.bzl
  6. 1 0
      synx_kernel_board.mk
  7. 7 0
      synx_modules.bzl

+ 11 - 1
Android.mk

@@ -22,7 +22,7 @@ DLKM_DIR   := $(TOP)/device/qcom/common/dlkm
 
 LOCAL_PATH := $(call my-dir)
 LOCAL_MODULE_DDK_BUILD := true
-LOCAL_MODULE_KO_DIRS := msm/synx/synx-driver.ko msm/synx/ipclite.ko
+LOCAL_MODULE_KO_DIRS := msm/synx/synx-driver.ko msm/synx/ipclite.ko msm/synx/test/ipclite_test.ko
 
 include $(CLEAR_VARS)
 # For incremental compilation
@@ -53,6 +53,16 @@ LOCAL_MODULE      := ipclite.ko
 LOCAL_MODULE_KBUILD_NAME := msm/synx/ipclite.ko
 LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
 #BOARD_VENDOR_KERNEL_MODULES += $(LOCAL_MODULE_PATH)/$(LOCAL_MODULE)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+
+include $(CLEAR_VARS)
+# For incremental compilation
+LOCAL_SRC_FILES   := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*)
+$(info LOCAL_SRC_FILES = $(LOCAL_SRC_FILES))
+LOCAL_MODULE      := ipclite_test.ko
+LOCAL_MODULE_KBUILD_NAME := msm/synx/test/ipclite_test.ko
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+#BOARD_VENDOR_KERNEL_MODULES += $(LOCAL_MODULE_PATH)/$(LOCAL_MODULE)
 
 # print out variables
 $(info KBUILD_OPTIONS = $(KBUILD_OPTIONS))

+ 1 - 0
msm/Kbuild

@@ -34,4 +34,5 @@ endif
 
 obj-m += synx-driver.o
 obj-m += synx/ipclite.o
+obj-m += synx/test/ipclite_test.o
 synx-driver-objs := synx/synx.o synx/synx_global.o synx/synx_util.o synx/synx_debugfs.o

+ 1455 - 0
msm/synx/test/ipclite_test.c

@@ -0,0 +1,1455 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <linux/kthread.h>
+#include <linux/string.h>
+#include <linux/bits.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include "ipclite_test.h"
+
+struct kobject *sysfs_dir;
+
+static int threads_started, threads_completed, cores_completed;
+static bool ssr_complete;
+/* data_lock spinlock is used to increment ping counters in thread safe manner.
+ * core_wq to ensure all the cores have completed the test before next step.
+ * ssr_wq to wait during ssr operation.
+ * reply_wq to wait on replies to ping sent.
+ * thread_wq to wait on all threads local to APPS to complete
+ * test_done is a completion barrier which ensures test case is completed
+ * crash_done is a completion barrier which ensures ssr crash is completed
+ */
+DEFINE_SPINLOCK(data_lock);
+DECLARE_WAIT_QUEUE_HEAD(core_wq);
+DECLARE_WAIT_QUEUE_HEAD(ssr_wq);
+DECLARE_WAIT_QUEUE_HEAD(reply_wq);
+DECLARE_WAIT_QUEUE_HEAD(thread_wq);
+DECLARE_COMPLETION(test_done);
+DECLARE_COMPLETION(crash_done);
+
+static struct ipclite_thread_data wakeup_check, bg_pings;
+static struct ipclite_thread_data thread_data;
+
+struct handle_t *handle_ptr;
+static int handle_data[512];
+static struct ipclite_test_data *data;
+
+static void init_test_params(void)
+{
+	data->test_params.wait = 1;
+	data->test_params.num_pings = 1000;
+	data->test_params.num_itr = 1;
+	data->test_params.selected_senders = 1;
+	data->test_params.selected_receivers = 1;
+	data->test_params.enabled_cores = IPCLITE_TEST_ALL_CORES;
+	data->test_params.selected_test_case = 0;
+	data->test_params.num_thread = 1;
+	data->test_params.num_senders = 1;
+	data->test_params.num_receivers = 1;
+}
+/* Function to pack the different fields into one 64 bit message value
+ * 1 byte header of constant patter 01010101
+ * 1 byte to store the parameter type
+ * 1 byte to store the test case id
+ * 3 bytes to store the value of parameter in payload
+ * 1 byte to store test start/stop information
+ * 1 byte to store test pass/fail information
+ */
+static uint64_t get_param_macro(uint64_t parameter_info, uint64_t test_info,
+				uint64_t payload_info, uint64_t start_stop_info,
+				uint64_t pass_fail_info)
+{
+	uint64_t param_macro = 0;
+
+	parameter_info &= GENMASK_ULL(7, 0);
+	test_info &= GENMASK_ULL(7, 0);
+	payload_info &= GENMASK_ULL(23, 0);
+	start_stop_info &= GENMASK_ULL(7, 0);
+	pass_fail_info &= GENMASK_ULL(7, 0);
+
+	param_macro = ((uint64_t)IPCLITE_TEST_HEADER) << 56;
+	param_macro |= parameter_info << 48;
+	param_macro |= test_info << 40;
+	param_macro |= payload_info << 16;
+	param_macro |= start_stop_info << 8;
+	param_macro |= pass_fail_info;
+
+	return param_macro;
+}
+
+static inline bool is_enabled_core(int core_id)
+{
+	return (data->test_params.enabled_cores & BIT(core_id)) ? true : false;
+}
+
+static inline bool is_selected_receiver(int core_id)
+{
+	return (data->test_params.selected_receivers & BIT(core_id)) ? true : false;
+}
+
+static inline bool is_selected_sender(int core_id)
+{
+	return (data->test_params.selected_senders & BIT(core_id)) ? true : false;
+}
+
+static void ping_receive(struct ipclite_test_data *data)
+{
+	pr_debug("Successfully received a ping\n");
+	data->pings_received[data->client_id]++;
+	wake_up_interruptible(&reply_wq);
+}
+
+static int check_pings(struct ipclite_test_data *data)
+{
+	for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+		if (!is_selected_receiver(i))
+			continue;
+		if (data->pings_sent[i] != data->pings_received[i])
+			return -IPCLITE_TEST_FAIL;
+	}
+	return 0;
+}
+
+static void ping_all_enabled_cores(u64 msg)
+{
+	for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+		if (i == IPCMEM_APPS || !is_enabled_core(i))
+			continue;
+		ipclite_test_msg_send(i, msg);
+	}
+}
+
+static void ping_sel_senders(uint64_t msg)
+{
+	for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+		if (i == IPCMEM_APPS || !(data->test_params.selected_senders & BIT(i)))
+			continue;
+		ipclite_test_msg_send(i, msg);
+	}
+}
+
+static int thread_init(struct ipclite_thread_data *th_data, void *data_ptr, void *fptr)
+{
+	th_data->data = data_ptr;
+	th_data->run = false;
+	init_waitqueue_head(&th_data->wq);
+	th_data->thread = kthread_run(fptr, th_data, "test thread");
+	if (IS_ERR(th_data->thread)) {
+		pr_err("Thread creation failed\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ping_selected_receivers(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+	int ret = 0;
+	uint64_t macro_to_ping = get_param_macro(TEST_CASE,
+						data->test_params.selected_test_case,
+						PING_SEND, 0, 0);
+	bool fail = false;
+
+	while (!kthread_should_stop()) {
+
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+
+		for (int i = 0; i < data->test_params.num_pings/data->test_params.num_thread; ++i) {
+			for (int j = 0; j < IPCMEM_NUM_HOSTS; ++j) {
+				if (!is_selected_receiver(j))
+					continue;
+				ret = ipclite_test_msg_send(j, macro_to_ping);
+				if (ret == 0) {
+					spin_lock(&data_lock);
+					data->pings_sent[j]++;
+					spin_unlock(&data_lock);
+				} else
+					fail = true;
+				/* If wait is enabled and number of pings to wait on is sent,
+				 * Wait for replies or timeout
+				 */
+				if (data->test_params.wait != 0 &&
+							(i+1) % data->test_params.wait == 0) {
+					ret = wait_event_interruptible_timeout(reply_wq,
+								check_pings(data) == 0,
+								msecs_to_jiffies(1000));
+					if (ret < 1)
+						pr_err("Timeout occurred\n");
+				}
+			}
+		}
+		pr_debug("Completed iteration. Marking thread as completed\n");
+		spin_lock(&data_lock);
+		threads_completed++;
+		wake_up_interruptible(&thread_wq);
+		spin_unlock(&data_lock);
+	}
+
+	return fail ? -IPCLITE_TEST_FAIL : 0;
+}
+
+static int negative_tests(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	int ret = 0, fail = 0;
+	uint64_t param;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+		pr_info("Test 1: Sending messages to disabled cores\n");
+		for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+			if (!is_selected_receiver(i))
+				continue;
+			param = get_param_macro(TEST_CASE, NEGATIVE,
+						PING_SEND, 0, 0);
+			ret = ipclite_test_msg_send(i, param);
+			if (ret == 0) {
+				pr_err("TEST FAILED\n");
+				fail++;
+			}
+		}
+		if (!fail)
+			pr_info("TEST PASSED\n");
+
+		pr_info("Test 2: Passing NULL to get_global_parition_info\n");
+		ret = get_global_partition_info(NULL);
+		if (ret == 0) {
+			pr_err("TEST FAILED\n");
+			fail++;
+		} else
+			pr_info("TEST PASSED\n");
+
+		if (fail != 0)
+			pr_err("Negative TEST FAILED\n");
+		else
+			pr_info("Negative TEST PASSED\n");
+
+		param = get_param_macro(TEST_CASE, NEGATIVE, 0,
+					IPCLITE_TEST_STOP, 0);
+		ipclite_test_msg_send(IPCMEM_APPS, param);
+		wait_event_interruptible_timeout(core_wq,
+						cores_completed == data->test_params.num_senders,
+						msecs_to_jiffies(1000));
+		complete(&test_done);
+	}
+	return fail == 0 ? 0 : -IPCLITE_TEST_FAIL;
+}
+
+static int hw_unlock_test(void *hw_mutex_byte)
+{
+	int ret = 0;
+	uint64_t param;
+
+	if (!hw_mutex_byte) {
+		pr_err("Byte for hardware mutex testing is not initialized.\n");
+		return -EFAULT;
+	}
+
+	pr_info("Testing HW Mutex Lock Acquire Functionality\n");
+	*((int *)(hw_mutex_byte)) = -1;
+	pr_debug("The initial value of the byte is %d\n", *((int *)(hw_mutex_byte)));
+	pr_debug("Locking the mutex from APPS Side\n");
+
+	ret = ipclite_hw_mutex_acquire();
+	if (ret != 0) {
+		pr_err("Could not acquire hw mutex from APPS side\n");
+		return ret;
+	}
+
+	pr_debug("Setting the value of the byte to %d\n", IPCMEM_APPS);
+	*((int *)(hw_mutex_byte)) = IPCMEM_APPS;
+	pr_debug("The new value of the byte is %d\n", *((int *)(hw_mutex_byte)));
+
+	for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+		if (i == IPCMEM_APPS || !is_selected_receiver(i))
+			continue;
+		pr_debug("Pinging %s to try and release the locked mutex\n",
+						core_name[i]);
+		param = get_param_macro(TEST_CASE, HW_MUTEX,
+					HW_MUTEX_RELEASE,
+					IPCLITE_TEST_START, 0);
+		ipclite_test_msg_send(i, param);
+		// Wait for timeout here
+		udelay(1000);
+	}
+
+	if (*((int *)(hw_mutex_byte)) != IPCMEM_APPS)
+		return -IPCLITE_TEST_FAIL;
+
+	ret = ipclite_hw_mutex_release();
+	if (ret != 0)
+		pr_err("Could not release mutex lock successfully\n");
+	return ret;
+}
+
+static int hw_mutex_test(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+	int ret = 0;
+	void *addr = data->global_memory->virt_base;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+
+		ret = hw_unlock_test(addr);
+
+		if (ret == 0)
+			pr_info("HW Unlock Test Passed.\n");
+		else
+			pr_info("HW Unlock Test Failed.\n");
+
+		complete(&test_done);
+	}
+	return  ret;
+}
+/* Ping cores which are not selected for ssr in the background */
+static int send_bg_pings(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+	int ret;
+	uint64_t param;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+
+		while (!ssr_complete && !kthread_should_stop()) {
+			for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+				if (i == data->ssr_client || !is_selected_receiver(i))
+					continue;
+				param = get_param_macro(TEST_CASE,
+							SSR,
+							PING_SEND, 0, 0);
+				ret = ipclite_test_msg_send(i, param);
+				if (ret != 0)
+					pr_err("Unable to ping core %d\n", i);
+			}
+			wait_event_interruptible_timeout(ssr_wq,
+							ssr_complete,
+							msecs_to_jiffies(1000));
+		}
+		pr_debug("SSR recovery of core %d completed. Exiting thread\n",
+								data->ssr_client);
+	}
+	return 0;
+}
+/* Wait for 30s and then send pings one to by one to see if core wakeup
+ *   is completed
+ */
+static int ssr_wakeup_check(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+	int count = 0, ret = 0;
+	uint64_t param;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+
+		ssr_complete = false;
+		msleep_interruptible(30000);
+		while (count < 10) {
+			pr_debug("Sent ping number %d to check if wakeup is completed\n",
+							count);
+			param = get_param_macro(TEST_CASE, SSR,
+						SSR_WAKEUP,
+						IPCLITE_TEST_START, 0);
+			ret = ipclite_test_msg_send(data->ssr_client, param);
+			++count;
+			wait_event_interruptible_timeout(ssr_wq,
+							ssr_complete,
+							msecs_to_jiffies(1000));
+		}
+		if (count == 10 && !ssr_complete) {
+			pr_info("FW Core wakeup failed.\n");
+			return -IPCLITE_TEST_FAIL;
+		}
+		pr_info("FW Core wakeup completed successfully.\n");
+		pr_info("Going for non crashing testing.\n");
+		param = get_param_macro(TEST_CASE, PING, 0,
+					IPCLITE_TEST_START, 0);
+		ipclite_test_msg_send(data->ssr_client, param);
+		complete(&crash_done);
+	}
+	return 0;
+}
+
+static int ssr_test(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+	uint64_t param = 0;
+	int ret = 0;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+
+		ssr_complete = false;
+		ret = thread_init(&wakeup_check, data, ssr_wakeup_check);
+
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			return -EINVAL;
+		}
+
+		ret = thread_init(&bg_pings, data, send_bg_pings);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			kthread_stop(wakeup_check.thread);
+			return -EINVAL;
+		}
+		pr_info("Starting on SSR test for core %d\n", data->ssr_client);
+		memset(data->pings_sent, 0, sizeof(data->pings_sent));
+		memset(data->pings_received, 0, sizeof(data->pings_received));
+		param = get_param_macro(TEST_CASE, SSR,
+					SSR_CRASHING, IPCLITE_TEST_START, 0);
+		ipclite_test_msg_send(data->ssr_client, param);
+		wait_for_completion(&crash_done);
+		kthread_stop(wakeup_check.thread);
+		kthread_stop(bg_pings.thread);
+		complete(&test_done);
+	}
+	return 0;
+}
+
+static int inc_byte(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	ipclite_atomic_uint32_t *addr = t_data->data;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+		for (int i = 0; i < data->test_params.num_itr; ++i)
+			ipclite_global_atomic_inc(addr);
+		threads_completed++;
+		wake_up_interruptible(&thread_wq);
+	}
+	return 0;
+}
+
+static int dec_byte(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	ipclite_atomic_uint32_t *addr = t_data->data;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+		for (int i = 0; i < data->test_params.num_itr; ++i)
+			ipclite_global_atomic_dec(addr);
+		threads_completed++;
+		wake_up_interruptible(&thread_wq);
+	}
+	return 0;
+}
+
+static int global_atomics_test(void *byte, int test_number)
+{
+	int ret = 0;
+	int total_increment = 0;
+	uint64_t param;
+	bool fail = false;
+	struct ipclite_thread_data ga_t1, ga_t2;
+
+
+	if (!byte) {
+		pr_err("Byte not initialized. Test Failed\n");
+		return -EFAULT;
+	}
+	pr_debug("The initial value of the byte is %x\n", *((int *)byte));
+
+	threads_completed = 0;
+	threads_started = 0;
+
+	switch (test_number) {
+	case GLOBAL_ATOMICS_INC:
+		ret = thread_init(&ga_t1, byte, inc_byte);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			return -EINVAL;
+		}
+		ret = thread_init(&ga_t2, byte, inc_byte);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			kthread_stop(ga_t1.thread);
+			return -EINVAL;
+		}
+		break;
+	case GLOBAL_ATOMICS_DEC:
+		ret = thread_init(&ga_t1, byte, dec_byte);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			return -EINVAL;
+		}
+		ret = thread_init(&ga_t2, byte, dec_byte);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			kthread_stop(ga_t1.thread);
+			return -EINVAL;
+		}
+		break;
+	case GLOBAL_ATOMICS_INC_DEC:
+		ret = thread_init(&ga_t1, byte, inc_byte);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			return -EINVAL;
+		}
+		ret = thread_init(&ga_t2, byte, dec_byte);
+		if (ret != 0) {
+			pr_err("Thread creation failed\n");
+			kthread_stop(ga_t1.thread);
+			return -EINVAL;
+		}
+		break;
+	default:
+		pr_err("Wrong input provided\n");
+		return -EINVAL;
+	}
+	param = get_param_macro(TEST_CASE,
+				GLOBAL_ATOMIC,
+				test_number,
+				IPCLITE_TEST_START, 0);
+
+	for (int i = 0; i < IPCMEM_NUM_HOSTS; ++i) {
+		if (i == IPCMEM_APPS || !is_selected_receiver(i))
+			continue;
+		ret = ipclite_test_msg_send(i, param);
+		if (ret == 0)
+			threads_started += 2;
+	}
+	if (is_selected_receiver(IPCMEM_APPS)) {
+		ga_t1.run = true;
+		wake_up_interruptible(&ga_t1.wq);
+		ga_t2.run = true;
+		wake_up_interruptible(&ga_t2.wq);
+		threads_started += 2;
+	}
+	/* Wait for all threads to complete or timeout */
+	ret = wait_event_interruptible_timeout(thread_wq,
+					threads_started == 2 * data->test_params.num_receivers &&
+					threads_completed == 2 * data->test_params.num_receivers,
+					msecs_to_jiffies(1000));
+	if (ret < 1)
+		pr_err("Threads could not complete successfully\n");
+
+	pr_debug("The value of the byte is %x\n", *((int *)byte));
+	/* Stopping threads if they have not already completed before evaluation */
+	kthread_stop(ga_t1.thread);
+	kthread_stop(ga_t2.thread);
+
+	total_increment = 2 * data->test_params.num_receivers * data->test_params.num_itr;
+
+	switch (test_number) {
+	case GLOBAL_ATOMICS_INC:
+		if (*((int *)byte) == total_increment)
+			pr_info("Increment Successful.\n");
+		else {
+			pr_err("Increment Failed.\n");
+			fail = true;
+		}
+		break;
+	case GLOBAL_ATOMICS_DEC:
+		if (*((int *)byte) == 0)
+			pr_info("Decrement Successful\n");
+		else {
+			pr_err("Decrement Failed\n");
+			fail = true;
+		}
+		break;
+	case GLOBAL_ATOMICS_INC_DEC:
+		if (*((int *)byte) == 0)
+			pr_info("Increment and Decrement Successful\n");
+		else {
+			pr_err("Increment and Decrement Failed\n");
+			fail = true;
+		}
+		break;
+	default:
+		pr_err("Wrong input provided\n");
+		return -EINVAL;
+	}
+
+	return fail ? -IPCLITE_TEST_FAIL : 0;
+}
+
+static inline uint32_t bitops_count_trailing_one(uint32_t x)
+{
+	uint32_t mask = 0;
+
+	for (int i = 0; i < BITS(ipclite_atomic_uint32_t); i++) {
+		mask = 1 << i;
+		if (!(x & mask))
+			return i;
+	}
+	return BITS(ipclite_atomic_uint32_t);
+}
+
+/**
+ * @brief Finds the first zero in the bitmap
+ *
+ * @param bmap_addr pointer to bitmap
+ * @param size the size of the bitmap indicated in number of bits
+ * @return uint32_t index of the first zero
+ */
+static uint32_t bitops_util_find_first_zero(uint32_t *bmap_addr, uint32_t size)
+{
+	uint32_t res = 0;
+
+	for (int i = 0; i * BITS(ipclite_atomic_uint32_t) < size; i++) {
+		if (bmap_addr[i] != ~(uint32_t)0) {
+			res = i * BITS(ipclite_atomic_uint32_t) +
+				bitops_count_trailing_one(bmap_addr[i]);
+			return res < size ? res : size;
+		}
+	}
+	return size;
+}
+
+static int alloc_index(int *bitmap_base)
+{
+	uint32_t prev = 0, index = 0;
+
+	do {
+		index = bitops_util_find_first_zero((unsigned int *) bitmap_base,
+							NUM_HANDLES);
+		if (index > NUM_HANDLES) {
+			pr_err("No Memory Error. Exiting\n");
+			break;
+		}
+		prev = ipclite_global_test_and_set_bit(index % 32,
+					(ipclite_atomic_uint32_t *)(bitmap_base + index/32));
+		if ((prev & (1UL << (index % 32))) == 0)
+			break;
+	} while (true);
+	return index;
+}
+
+void clear_index(int *bitmap_base, uint32_t index)
+{
+	uint32_t addr_idx = index/32, ii = index % 32;
+
+	if (bitmap_base == NULL) {
+		pr_err("Invalid pointer passed\n");
+		return;
+	}
+	ipclite_global_test_and_clear_bit(ii, (ipclite_atomic_uint32_t *)(bitmap_base + addr_idx));
+}
+
+static int global_atomics_test_set_clear(struct ipclite_test_data *data)
+{
+	int index = 0, ret = 0;
+	bool fail = false;
+	uint64_t param;
+
+	handle_ptr = data->global_memory->virt_base;
+	pr_info("Starting global atomics Test 4. Starting allocation of index\n");
+	pr_debug("The total number of handles is %d\n", NUM_HANDLES);
+	pr_debug("Global Base : %p\n", handle_ptr);
+	for (int itr = 0; itr < data->test_params.num_itr; itr++) {
+		threads_started = 0;
+		threads_completed = 0;
+		for (int j = 0; j < IPCMEM_NUM_HOSTS; ++j) {
+			if (j == IPCMEM_APPS || !is_selected_receiver(j))
+				continue;
+			param = get_param_macro(TEST_CASE,
+						GLOBAL_ATOMIC,
+						GLOBAL_ATOMICS_SET_CLR,
+						IPCLITE_TEST_START, 0);
+			ret = ipclite_test_msg_send(j, param);
+			if (ret == 0)
+				threads_started++;
+		}
+		if (is_selected_receiver(IPCMEM_APPS)) {
+			threads_started++;
+			for (int i = 0; i < 512; ++i) {
+				index = alloc_index((int *)handle_ptr);
+				handle_data[i] = index;
+				handle_ptr->handle_data[index] = IPCMEM_APPS;
+			}
+
+			for (int i = 0; i < 512; ++i) {
+				index = handle_data[i];
+				if (handle_ptr->handle_data[index] != IPCMEM_APPS) {
+					pr_err("Handle data has been overwritten.\n");
+					pr_err("This is a bug : Core : %d Index : %d\n",
+						handle_ptr->handle_data[index], index);
+					fail = true;
+				}
+			}
+
+			for (int i = 0; i < 512; ++i) {
+				index = handle_data[i];
+				clear_index((int *)handle_ptr, index);
+			}
+			threads_completed++;
+			if (fail)
+				break;
+		}
+		wait_event_interruptible_timeout(thread_wq,
+				threads_started == data->test_params.num_receivers &&
+				threads_completed == data->test_params.num_receivers,
+				msecs_to_jiffies(1000));
+	}
+	if (!fail)
+		pr_info("Global Atomics Set and Clear test passed successfully\n");
+	return fail ? -IPCLITE_TEST_FAIL  : 0;
+}
+
+static int global_atomics_test_wrapper(void *data_ptr)
+{
+	int result = 0, ret = 0;
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+	void *addr = data->global_memory->virt_base;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+		*((int *)addr) = 0;
+		result = global_atomics_test(addr, GLOBAL_ATOMICS_INC);
+		result &= global_atomics_test(addr, GLOBAL_ATOMICS_DEC);
+		result &= global_atomics_test(addr, GLOBAL_ATOMICS_INC_DEC);
+		result &= global_atomics_test_set_clear(data);
+		if (result != 0) {
+			pr_err("Global Atomics TEST FAILED\n");
+			ret = -IPCLITE_TEST_FAIL;
+		} else {
+			pr_info("Global Atomics TEST PASSED\n");
+			ret = 0;
+		}
+		complete(&test_done);
+	}
+	return ret;
+}
+
+static int ping_test(void *data_ptr)
+{
+	int ret = 0;
+	uint64_t param_macro;
+	struct ipclite_test_data *data = data_ptr;
+	struct ipclite_thread_data th_arr[IPCLITE_TEST_MAX_THREADS];
+	int count;
+
+	memset(data->pings_sent, 0, sizeof(data->pings_sent));
+	memset(data->pings_received, 0, sizeof(data->pings_received));
+	threads_completed = 0;
+	param_macro = 0;
+	for (count = 0; count < data->test_params.num_thread; ++count) {
+		ret = thread_init(&th_arr[count], data, ping_selected_receivers);
+		if (ret != 0)
+			break;
+	}
+	if (count != data->test_params.num_thread)
+		while (count > 0) {
+			kthread_stop(th_arr[count-1].thread);
+			--count;
+		}
+	if (ret != 0) {
+		pr_err("Threads could not be initialized. Ping Test Failed\n");
+		return ret;
+	}
+	for (threads_started = 0; threads_started < data->test_params.num_thread;
+							++threads_started) {
+		th_arr[threads_started].run = true;
+		wake_up_interruptible(&th_arr[threads_started].wq);
+	}
+	ret = wait_event_interruptible_timeout(thread_wq,
+				threads_started == data->test_params.num_thread &&
+				threads_completed == data->test_params.num_thread,
+				msecs_to_jiffies(1000) * data->test_params.num_thread);
+	if (ret < 1) {
+		pr_err("Threads not completed successfully. Only completed %d threads\n",
+						threads_completed);
+		return ret;
+
+	}
+	pr_info("All threads completed successfully.\n");
+	pr_debug("Going for checking\n");
+	/*Wait for the queue to get processed before checking if all replies are received*/
+	if (!data->test_params.wait)
+		msleep_interruptible(1000);
+	ret = check_pings(data);
+
+	if (ret == 0)
+		pr_debug("All replies received successfully.\n");
+	else
+		pr_debug("All replies not received successfully.\n");
+
+	while (count > 0) {
+		kthread_stop(th_arr[count-1].thread);
+		--count;
+	}
+	param_macro = get_param_macro(TEST_CASE, PING, 0,
+					IPCLITE_TEST_STOP, 0);
+	ipclite_test_msg_send(IPCMEM_APPS, param_macro);
+	return ret;
+}
+
+static int wrapper_ping_test(void *data_ptr)
+{
+	int ret = 0;
+	uint64_t param_macro;
+	struct ipclite_thread_data *t_data = data_ptr;
+	struct ipclite_test_data *data = t_data->data;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+
+		for (int i = 0; i < data->test_params.num_itr; ++i) {
+			cores_completed = 0;
+			param_macro = get_param_macro(TEST_CASE,
+							PING,
+							0, IPCLITE_TEST_START, 0);
+			/* Ping all senders to start sending messages.
+			 *  If APPS is one of the senders start sending
+			 */
+			ping_sel_senders(param_macro);
+			if (is_selected_sender(IPCMEM_APPS))
+				ping_test(data);
+			wait_event_interruptible_timeout(core_wq,
+						cores_completed == data->test_params.num_senders,
+						msecs_to_jiffies(1000));
+			ret = check_pings(data);
+			if (ret != 0)
+				pr_info("Iteration %d of ping test failed\n", i+1);
+			else
+				pr_info("Iteration %d of ping test passed\n", i+1);
+		}
+	if (is_selected_sender(IPCMEM_APPS))
+		complete(&test_done);
+	}
+	return 0;
+}
+
+static int debug_tests(void *data_ptr)
+{
+	struct ipclite_thread_data *t_data = data_ptr;
+	uint64_t param;
+	int disabled_core = ffz(data->test_params.enabled_cores);
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(t_data->wq, t_data->run);
+		if (kthread_should_stop())
+			break;
+		t_data->run = false;
+		param = get_param_macro(TEST_CASE, DEBUG,
+					PING_SEND, 0, 0);
+		if (disabled_core == IPCMEM_NUM_HOSTS)
+			pr_err("All cores are enabled. No Disabled cores\n");
+		/* Pinging one enabled and disabled cores to get the error and dbg prints */
+		if (disabled_core < IPCMEM_NUM_HOSTS)
+			ipclite_test_msg_send(disabled_core, param);
+
+		param = get_param_macro(TEST_CASE, PING, 0,
+						IPCLITE_TEST_STOP, 0);
+		ipclite_test_msg_send(IPCMEM_APPS, param);
+		wait_event_interruptible_timeout(core_wq,
+						cores_completed == data->test_params.num_senders,
+						msecs_to_jiffies(1000));
+		complete(&test_done);
+	}
+	return 0;
+}
+
+static void ipclite_test_set_enabled_cores(void)
+{
+	if (data->test_params.enabled_cores < 0 ||
+					data->test_params.enabled_cores > IPCLITE_TEST_ALL_CORES) {
+		pr_err("Invalid parameter value given to enabled cores\n");
+		data->test_params.enabled_cores = IPCLITE_TEST_ALL_CORES;
+		return;
+	}
+	pr_info("Enabled cores set to %d\n", data->test_params.enabled_cores);
+}
+
+static void ipclite_test_set_wait(void)
+{
+	uint64_t param;
+
+	if (data->test_params.wait < 0) {
+		pr_err("Invalid parameter value given to wait\n");
+		data->test_params.wait = 1;
+		return;
+	}
+
+	pr_info("wait set to %d\n", data->test_params.wait);
+
+	param = get_param_macro(WAIT, 0, data->test_params.wait, 0, 0);
+	ping_all_enabled_cores(param);
+}
+
+static void ipclite_test_set_num_pings(void)
+{
+	uint64_t param;
+
+	pr_info("num_pings set to %d\n", data->test_params.num_pings);
+
+	param = get_param_macro(NUM_PINGS, 0,
+				data->test_params.num_pings, 0, 0);
+	ping_all_enabled_cores(param);
+}
+
+static void ipclite_test_set_num_itr(void)
+{
+	uint64_t param;
+
+	pr_info("num_itr set to %d\n", data->test_params.num_itr);
+
+	param = get_param_macro(NUM_ITR, 1,
+				data->test_params.num_itr, 0, 0);
+	ping_all_enabled_cores(param);
+}
+
+static void ipclite_test_set_receivers(void)
+{
+	uint64_t param;
+
+	if (data->test_params.selected_receivers < 0 ||
+		data->test_params.selected_receivers > IPCLITE_TEST_ALL_CORES) {
+		pr_err("Invalid parameter value given to selected_receivers\n");
+		data->test_params.selected_receivers = 1;
+		data->test_params.num_receivers = 1;
+		return;
+	}
+	/* Check number of 1s using hamming weight function.
+	 * Number of 1s is number of receivers
+	 */
+	data->test_params.num_receivers = hweight_long(data->test_params.selected_receivers);
+
+	pr_info("selected_receivers set to %d\n", data->test_params.selected_receivers);
+
+	param = get_param_macro(RECEIVER_LIST, 0,
+				data->test_params.selected_receivers, 0, 0);
+	ping_all_enabled_cores(param);
+}
+
+static void ipclite_test_set_senders(void)
+{
+	if (data->test_params.selected_senders < 0 ||
+		data->test_params.selected_senders > IPCLITE_TEST_ALL_CORES) {
+		pr_err("Invalid parameter value given to selected_senders\n");
+		data->test_params.selected_senders = 1;
+		data->test_params.num_senders = 1;
+		return;
+	}
+
+	/* Check number of 1s using hamming weight function. */
+	data->test_params.num_senders = hweight_long(data->test_params.selected_senders);
+
+	pr_info("selected_senders set to %d\n", data->test_params.selected_senders);
+}
+
+static void ipclite_test_set_num_threads(void)
+{
+	uint64_t param;
+
+	if (data->test_params.num_thread < 0 ||
+					data->test_params.num_thread > IPCLITE_TEST_MAX_THREADS) {
+		pr_err("Invalid parameter value given to num_thread\n");
+		data->test_params.num_thread = 1;
+		return;
+	}
+
+	pr_info("num_thread set to %d\n", data->test_params.num_thread);
+
+	param = get_param_macro(NUM_THREADS, 0,
+				data->test_params.num_thread, 0, 0);
+	ping_all_enabled_cores(param);
+}
+
+static void ipclite_test_set_test(void)
+{
+	uint64_t param;
+	int ret = 0;
+
+	if (data->test_params.selected_test_case < 0 || data->test_params.selected_test_case > 8) {
+		pr_err("Invalid parameter value given to test_case\n");
+		data->test_params.selected_test_case = 0;
+		return;
+	}
+
+	pr_info("selected_test_case set to %d\n", data->test_params.selected_test_case);
+	param = get_param_macro(TEST_CASE,
+				data->test_params.selected_test_case, 0,
+				IPCLITE_TEST_START, 0);
+
+	switch (data->test_params.selected_test_case) {
+	case PING:
+		ret = thread_init(&thread_data, data, wrapper_ping_test);
+		if (ret != 0) {
+			pr_err("Could not create thread for testing\n");
+			return;
+		}
+		thread_data.run = true;
+		wake_up_interruptible(&thread_data.wq);
+		break;
+	case NEGATIVE:
+		ping_sel_senders(param);
+		if (is_selected_sender(IPCMEM_APPS)) {
+			pr_info("Starting test %d for core %s\n",
+				NEGATIVE, core_name[IPCMEM_APPS]);
+			ret = thread_init(&thread_data, data, negative_tests);
+			if (ret != 0) {
+				pr_err("Could not create thread for testing\n");
+				return;
+			}
+			thread_data.run = true;
+			wake_up_interruptible(&thread_data.wq);
+		}
+		break;
+	case GLOBAL_ATOMIC:
+		ret = thread_init(&thread_data, data, global_atomics_test_wrapper);
+		if (ret != 0) {
+			pr_err("Could not create thread for testing\n");
+			return;
+		}
+		thread_data.run = true;
+		wake_up_interruptible(&thread_data.wq);
+		break;
+	case DEBUG:
+		ping_sel_senders(param);
+		if (is_selected_sender(IPCMEM_APPS)) {
+			ret = thread_init(&thread_data, data, debug_tests);
+			if (ret != 0) {
+				pr_err("Could not create thread for testing\n");
+				return;
+			}
+			thread_data.run = true;
+			wake_up_interruptible(&thread_data.wq);
+		}
+		break;
+	case SSR:
+		if (data->test_params.num_senders != 1) {
+			pr_err("SSR Testing requires only 1 core to be selected\n");
+			return;
+		}
+		/* Find first set (ffs) to get the bit position/index of sender */
+		data->ssr_client = ffs(data->test_params.selected_senders) - 1;
+		if (data->ssr_client == 0 || !is_enabled_core(data->ssr_client)) {
+			pr_err("Invalid core selected for SSR Testing\n");
+			return;
+		}
+		pr_info("Starting test %d for core %s\n",
+			SSR, core_name[data->ssr_client]);
+		ret = thread_init(&thread_data, data, ssr_test);
+		if (ret != 0) {
+			pr_err("Could not create thread for testing\n");
+			return;
+		}
+		thread_data.run = true;
+		wake_up_interruptible(&thread_data.wq);
+		break;
+	case HW_MUTEX:
+		if (data->test_params.num_senders != 1) {
+			pr_err("HW Mutex Testing requires only 1 core to be selected\n");
+			return;
+		}
+
+		if (is_selected_sender(IPCMEM_APPS)) {
+			pr_info("Starting test %d for core %s\n",
+				HW_MUTEX, core_name[IPCMEM_APPS]);
+			ret = thread_init(&thread_data, data, hw_mutex_test);
+			if (ret != 0) {
+				pr_err("Could not create thread for testing\n");
+				return;
+			}
+			thread_data.run = true;
+			wake_up_interruptible(&thread_data.wq);
+		} else
+			ping_sel_senders(param);
+		break;
+	default:
+		pr_err("Wrong input provided\n");
+		return;
+	}
+	wait_for_completion(&test_done);
+	if (thread_data.thread != NULL)
+		ret = kthread_stop(thread_data.thread);
+	if (ret != 0)
+		pr_err("Test did not complete successfully\n");
+	else
+		pr_info("Test completed successfully\n");
+}
+
+static int parse_param(char **temp_buf, int *addr)
+{
+	char *token;
+	int ret;
+
+	token = strsep(temp_buf, " ");
+	if (!token) {
+		pr_err("Token value is NULL in parse param\n");
+		return -EINVAL;
+	}
+	ret = kstrtoint(token, 0, addr);
+	if (ret < 0) {
+		pr_err("Parameter value not read correctly\n");
+		return ret;
+	}
+	return 0;
+}
+
+static ssize_t ipclite_test_params_write(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					const char *buf, size_t count)
+{
+	char *temp_buf = kmalloc(strlen(buf)+1, GFP_KERNEL);
+	char *temp_ptr = temp_buf;
+	int ret, param = 0;
+
+	if (!temp_buf) {
+		pr_err("Memory not allocated\n");
+		return -EINVAL;
+	}
+
+	ret = strscpy(temp_buf, buf, strlen(buf)+1);
+
+	if (ret < 0) {
+		pr_err("User input is too large\n");
+		goto exit;
+	}
+
+	ret = parse_param(&temp_buf, &param);
+	if (ret != 0)
+		goto exit;
+
+	if (param  == ENABLED_CORES) {
+		ret = parse_param(&temp_buf, &data->test_params.enabled_cores);
+		if (ret == 0)
+			ipclite_test_set_enabled_cores();
+		goto exit;
+	} else
+		data->test_params.selected_test_case = param;
+
+	switch (data->test_params.selected_test_case) {
+	case PING:
+		ret = parse_param(&temp_buf, &data->test_params.selected_senders);
+		if (ret != 0)
+			break;
+		ipclite_test_set_senders();
+		ret = parse_param(&temp_buf, &data->test_params.selected_receivers);
+		if (ret != 0)
+			break;
+		ipclite_test_set_receivers();
+		ret = parse_param(&temp_buf, &data->test_params.num_pings);
+		if (ret != 0)
+			break;
+		ipclite_test_set_num_pings();
+		ret = parse_param(&temp_buf, &data->test_params.wait);
+		if (ret != 0)
+			break;
+		ipclite_test_set_wait();
+		ret = parse_param(&temp_buf, &data->test_params.num_itr);
+		if (ret != 0)
+			break;
+		ipclite_test_set_num_itr();
+		ret = parse_param(&temp_buf, &data->test_params.num_thread);
+		if (ret != 0)
+			break;
+		ipclite_test_set_num_threads();
+		break;
+	case NEGATIVE:
+		ret = parse_param(&temp_buf, &data->test_params.selected_senders);
+		if (ret != 0)
+			break;
+		ipclite_test_set_senders();
+		ret = parse_param(&temp_buf, &data->test_params.selected_receivers);
+		if (ret != 0)
+			break;
+		ipclite_test_set_receivers();
+		break;
+	case GLOBAL_ATOMIC:
+		ret = parse_param(&temp_buf, &data->test_params.selected_receivers);
+		if (ret != 0)
+			break;
+		ipclite_test_set_receivers();
+		ret = parse_param(&temp_buf, &data->test_params.num_itr);
+		if (ret != 0)
+			break;
+		ipclite_test_set_num_itr();
+		break;
+	case DEBUG:
+		ret = parse_param(&temp_buf, &data->test_params.selected_senders);
+		if (ret != 0)
+			break;
+		ipclite_test_set_senders();
+		break;
+	case SSR:
+		ret = parse_param(&temp_buf, &data->test_params.selected_senders);
+		if (ret != 0)
+			break;
+		ipclite_test_set_senders();
+		ret = parse_param(&temp_buf, &data->test_params.selected_receivers);
+		if (ret != 0)
+			break;
+		ipclite_test_set_receivers();
+		ret = parse_param(&temp_buf, &data->test_params.num_pings);
+		if (ret != 0)
+			break;
+		ipclite_test_set_num_pings();
+		break;
+	case HW_MUTEX:
+		ret = parse_param(&temp_buf, &data->test_params.selected_senders);
+		if (ret != 0)
+			break;
+		ipclite_test_set_senders();
+		ret = parse_param(&temp_buf, &data->test_params.selected_receivers);
+		if (ret != 0)
+			break;
+		ipclite_test_set_receivers();
+		break;
+	default:
+		pr_err("Wrong input provided\n");
+		goto exit;
+	}
+	if (ret == 0)
+		ipclite_test_set_test();
+exit:
+	kfree(temp_ptr);
+	return count;
+}
+
+
+
+static int ipclite_test_callback_fn(unsigned int client_id, long long msg,
+					void *data_ptr)
+{
+	struct ipclite_test_data *data = data_ptr;
+	uint64_t header, parameter_info, test_info, payload_info,
+			start_stop_info, pass_fail_info;
+	uint64_t reply_macro;
+	int ret = 0;
+
+	/* Unpack the different bit fields from message value */
+	header = (msg & GENMASK(63, 56))>>56;
+	parameter_info = (msg & GENMASK(55, 48))>>48;
+	test_info = (msg & GENMASK(47, 40))>>40;
+	payload_info = (msg & GENMASK(39, 16))>>16;
+	start_stop_info = (msg & GENMASK(15, 8))>>8;
+	pass_fail_info = (msg & GENMASK(7, 0));
+
+	if (!data) {
+		pr_err("Callback data pointer not loaded successfully\n");
+		return -EFAULT;
+	}
+
+	data->client_id = client_id;
+
+	if (header != IPCLITE_TEST_HEADER) {
+		pr_err("Corrupted message packed received\n");
+		return -EINVAL;
+	}
+
+	pr_debug("The message received is %lx\n", msg);
+
+	switch (test_info) {
+	case PING:
+	case NEGATIVE:
+	case DEBUG:
+		if (payload_info == PING_SEND) {
+			reply_macro = get_param_macro(TEST_CASE,
+							test_info,
+							PING_REPLY,
+							0, 0);
+			ipclite_test_msg_send(client_id, reply_macro);
+			break;
+		}
+		if (payload_info == PING_REPLY) {
+			ping_receive(data);
+			break;
+		}
+		if (pass_fail_info == IPCLITE_TEST_PASS)
+			pr_info("Test passed on core %s\n", core_name[client_id]);
+		else if (pass_fail_info == IPCLITE_TEST_FAIL)
+			pr_info("Test failed on core %s\n", core_name[client_id]);
+		if (start_stop_info == IPCLITE_TEST_STOP) {
+			++cores_completed;
+			if (cores_completed == data->test_params.num_senders)
+				pr_info("Test completed on all cores\n");
+			if (is_selected_sender(IPCMEM_APPS))
+				wake_up_interruptible(&core_wq);
+			else
+				complete(&test_done);
+		}
+		break;
+	case HW_MUTEX:
+		if (start_stop_info == IPCLITE_TEST_START) {
+			ret = ipclite_hw_mutex_release();
+			if (ret == 0)
+				*((int *)data->global_memory->virt_base) = IPCMEM_APPS;
+			reply_macro = get_param_macro(TEST_CASE,
+							test_info,
+							HW_MUTEX_RELEASE,
+							IPCLITE_TEST_STOP, 0);
+			ipclite_test_msg_send(client_id, reply_macro);
+
+		}
+		if (pass_fail_info == IPCLITE_TEST_PASS)
+			pr_info("HW Unlock Test passed on core %s\n",
+					core_name[client_id]);
+		else if (pass_fail_info == IPCLITE_TEST_FAIL)
+			pr_info("HW Unlock Test failed on core %s\n",
+					core_name[client_id]);
+		if (start_stop_info == IPCLITE_TEST_STOP)
+			complete(&test_done);
+		break;
+	case SSR:
+		if (payload_info == PING_SEND) {
+			reply_macro = get_param_macro(TEST_CASE,
+							test_info,
+							PING_REPLY,
+							0, 0);
+			data->pings_received[client_id]++;
+			ipclite_test_msg_send(client_id, reply_macro);
+			if (data->pings_received[client_id] == data->test_params.num_pings) {
+				pr_info("Waking up ssr_wakeup_check_thread.\n");
+				pr_info("Signaling other cores to make sure there is no other crash\n");
+				wakeup_check.run = true;
+				wake_up_interruptible(&wakeup_check.wq);
+				bg_pings.run = true;
+				wake_up_interruptible(&bg_pings.wq);
+			}
+		}
+		if (payload_info == SSR_WAKEUP) {
+			if (start_stop_info == IPCLITE_TEST_STOP) {
+				ssr_complete = true;
+				pr_info("%s wakeup completed\n",
+						core_name[client_id]);
+				wake_up_interruptible(&ssr_wq);
+			}
+		}
+		if (pass_fail_info == IPCLITE_TEST_PASS)
+			pr_info("Test %d passed on core %s\n",
+						test_info, core_name[client_id]);
+		else if (pass_fail_info == IPCLITE_TEST_FAIL)
+			pr_info("Test %d failed on core %s\n",
+					test_info, core_name[client_id]);
+		break;
+	case GLOBAL_ATOMIC:
+		if (start_stop_info == IPCLITE_TEST_STOP) {
+			pr_debug("%s completed Global Atomics Test.\n",
+						core_name[client_id]);
+			if (payload_info == GLOBAL_ATOMICS_SET_CLR)
+				threads_completed++;
+			else
+				threads_completed += 2;
+			wake_up_interruptible(&thread_wq);
+		}
+		break;
+	default:
+		pr_info("Wrong input given\n");
+	}
+	return 0;
+}
+
+struct kobj_attribute ipclite_test_params = __ATTR(ipclite_test_params,
+							0660,
+							NULL,
+							ipclite_test_params_write);
+
+static int ipclite_test_sysfs_node_setup(void)
+{
+	int ret = 0;
+
+	sysfs_dir = kobject_create_and_add("ipclite_test", kernel_kobj);
+	if (sysfs_dir == NULL) {
+		pr_err("Cannot create sysfs directory\n");
+		return -ENOENT;
+	}
+
+	ret = sysfs_create_file(sysfs_dir, &ipclite_test_params.attr);
+	if (ret) {
+		pr_err("Cannot create sysfs file for ipclite test module. Error - %d\n",
+			ret);
+		return -ENOENT;
+	}
+	return 0;
+}
+
+static int __init ipclite_test_init(void)
+{
+	int ret = 0;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	data->global_memory = kzalloc(sizeof(*(data->global_memory)),
+						GFP_KERNEL);
+	if (!data->global_memory) {
+		kfree(data);
+		data = NULL;
+		return -ENOMEM;
+	}
+	ret = get_global_partition_info(data->global_memory);
+	if (ret != 0) {
+		pr_err("Unable to load global partition information\n");
+		goto bail;
+	}
+
+	ret = ipclite_register_test_client(ipclite_test_callback_fn, data);
+	if (ret != 0) {
+		pr_err("Could not register client\n");
+		goto bail;
+	}
+
+	ret = ipclite_test_sysfs_node_setup();
+	if (ret != 0) {
+		pr_err("Failed to create sysfs interface\n");
+		goto bail;
+	}
+
+	init_test_params();
+	return 0;
+bail:
+	kfree(data->global_memory);
+	kfree(data);
+	data = NULL;
+	return ret;
+}
+
+static void __exit ipclite_test_exit(void)
+{
+	pr_info("Removing IPCLite Test Module\n");
+	sysfs_remove_file(sysfs_dir, &ipclite_test_params.attr);
+	kobject_put(sysfs_dir);
+	kfree(data->global_memory);
+	kfree(data);
+	data = NULL;
+}
+
+module_init(ipclite_test_init);
+module_exit(ipclite_test_exit);
+
+MODULE_LICENSE("GPL v2");

+ 118 - 0
msm/synx/test/ipclite_test.h

@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include "../ipclite_client.h"
+#include "../ipclite.h"
+
+/* General testing related configurations */
+#define IPCLITE_TEST_MAX_THREADS 5
+#define IPCLITE_TEST_HEADER 0xaa
+#define IPCLITE_TEST_ALL_CORES GENMASK(IPCMEM_NUM_HOSTS - 1, 0)
+
+/* Synx Usecase related definitions */
+#define NUM_HANDLES   4096
+#define BITMAP_SIZE   (NUM_HANDLES/32)
+#define BITS(x) (sizeof(x)*8)
+
+struct handle_t {
+	int handle_bitmap[BITMAP_SIZE];
+	int handle_data[NUM_HANDLES];
+};
+
+/* Flags for Pass, Fail, Start, and Stop */
+#define IPCLITE_TEST_PASS 2
+#define IPCLITE_TEST_FAIL 1
+
+#define IPCLITE_TEST_START 2
+#define IPCLITE_TEST_STOP 1
+
+/* List of Cases Available for Testing */
+enum ipclite_test_type {
+	PING		= 1,
+	NEGATIVE	= 2,
+	GLOBAL_ATOMIC	= 3,
+	DEBUG		= 4,
+	SSR		= 5,
+	HW_MUTEX	= 6,
+};
+
+/* List of sysfs parameters */
+enum ipclite_test_param {
+	TEST_CASE	= 1,
+	SENDER_LIST	= 2,
+	RECEIVER_LIST	= 3,
+	NUM_PINGS	= 4,
+	WAIT		= 5,
+	NUM_ITR		= 6,
+	NUM_THREADS	= 7,
+	ENABLED_CORES	= 8,
+};
+
+/* List of subtests for HW Mutex Test */
+enum ipclite_test_hw_mutex_subtest {
+	HW_MUTEX_RELEASE	= 1,
+};
+
+/* List of messages for SSR Testing */
+enum ipclite_test_ssr_subtest {
+	SSR_CRASHING	= 1,
+	SSR_WAKEUP	= 2,
+};
+
+/* List of subtest for Global Atomics Testing */
+enum ipclite_test_global_atomics_subtest {
+	GLOBAL_ATOMICS_INC	= 1,
+	GLOBAL_ATOMICS_DEC	= 2,
+	GLOBAL_ATOMICS_INC_DEC	= 3,
+	GLOBAL_ATOMICS_SET_CLR	= 4,
+};
+
+/* Types of pings and replies to be sent and received */
+enum ipclite_test_ping {
+	PING_SEND	= 10,
+	PING_REPLY	= 11,
+};
+
+static char core_name[IPCMEM_NUM_HOSTS][13] = {
+					"IPCMEM_APPS",
+					"IPCMEM_MODEM",
+					"IPCMEM_LPASS",
+					"IPCMEM_SLPI",
+					"IPCMEM_GPU",
+					"IPCMEM_CDSP",
+					"IPCMEM_CVP",
+					"IPCMEM_CAM",
+					"IPCMEM_VPU"
+};
+
+struct ipclite_test_params {
+	int wait;
+	int num_pings;
+	int num_itr;
+	int selected_senders;
+	int selected_receivers;
+	int selected_test_case;
+	int enabled_cores;
+	int num_thread;
+	int num_senders;
+	int num_receivers;
+};
+
+struct ipclite_test_data {
+	int pings_sent[IPCMEM_NUM_HOSTS];
+	int pings_received[IPCMEM_NUM_HOSTS];
+	int client_id;
+	struct global_region_info *global_memory;
+	struct ipclite_test_params test_params;
+	int ssr_client;
+};
+
+struct ipclite_thread_data {
+	struct task_struct *thread;
+	void *data;
+	wait_queue_head_t wq;
+	bool run;
+};
+
+static int ipclite_test_callback_fn(unsigned int client_id, long long  msg, void *d);

+ 1 - 0
pineapple.bzl

@@ -8,6 +8,7 @@ def define_pineapple():
         modules = [
             "synx-driver",
             "ipclite",
+            "ipclite_test",
         ],
         config_options = [
             "TARGET_SYNX_ENABLE",

+ 1 - 0
synx_kernel_board.mk

@@ -13,6 +13,7 @@ ifeq ($(TARGET_SYNX_ENABLE), true)
 ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true)
 BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/synx-driver.ko
 BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/ipclite.ko
+BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/ipclite_test.ko
 BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/synx-driver.ko
 BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/ipclite.ko
 #BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += $(KERNEL_MODULES_OUT)/synx-driver.ko

+ 7 - 0
synx_modules.bzl

@@ -23,3 +23,10 @@ register_synx_module(
         "synx/ipclite.c",
     ],
 )
+register_synx_module(
+    name = "ipclite_test",
+    path = "msm",
+    srcs = [
+        "synx/test/ipclite_test.c",
+    ],
+)