Sfoglia il codice sorgente

Merge bde84ad2fb13a2893bfc3ca976b00b14c5ba6cb1 on remote branch

Change-Id: I4cabe394b37da98e30d24d5cf8cb565ef4f7e875
Linux Build Service Account 1 anno fa
parent
commit
7fe07b55c8
10 ha cambiato i file con 2202 aggiunte e 324 eliminazioni
  1. 11 1
      Android.mk
  2. 1 0
      msm/Kbuild
  3. 565 315
      msm/synx/ipclite.c
  4. 39 3
      msm/synx/ipclite.h
  5. 4 5
      msm/synx/synx.c
  6. 1455 0
      msm/synx/test/ipclite_test.c
  7. 118 0
      msm/synx/test/ipclite_test.h
  8. 1 0
      pineapple.bzl
  9. 1 0
      synx_kernel_board.mk
  10. 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

+ 565 - 315
msm/synx/ipclite.c

@@ -23,11 +23,6 @@
 #include "ipclite_client.h"
 #include "ipclite.h"
 
-#define GLOBAL_ATOMICS_ENABLED	1
-#define GLOBAL_ATOMICS_DISABLED	0
-#define FIFO_FULL_RESERVE 8
-#define FIFO_ALIGNMENT 8
-
 static struct ipclite_info *ipclite;
 static struct ipclite_client synx_client;
 static struct ipclite_client test_client;
@@ -37,10 +32,10 @@ static struct ipclite_debug_inmem_buf *ipclite_dbg_inmem;
 static struct mutex ssr_mutex;
 static struct kobject *sysfs_kobj;
 
-static uint32_t enabled_hosts, partitions;
-static u32 global_atomic_support = GLOBAL_ATOMICS_ENABLED;
 static uint32_t ipclite_debug_level = IPCLITE_ERR | IPCLITE_WARN | IPCLITE_INFO;
 static uint32_t ipclite_debug_control = IPCLITE_DMESG_LOG, ipclite_debug_dump;
+static uint32_t enabled_hosts, partitions, major_ver, minor_ver;
+static uint64_t feature_mask;
 
 static inline bool is_host_enabled(uint32_t host)
 {
@@ -72,7 +67,7 @@ static void ipclite_inmem_log(const char *psztStr, ...)
 
 static void ipclite_dump_debug_struct(void)
 {
-	int i, host;
+	int i = 0, host = 0;
 	struct ipclite_debug_struct *temp_dbg_struct;
 
 	/* Check if debug structures are initialized */
@@ -82,7 +77,7 @@ static void ipclite_dump_debug_struct(void)
 	}
 
 	/* Check if debug structures are enabled before printing */
-	if (!(ipclite_debug_control & IPCLITE_DBG_STRUCT)) {
+	if (!(IS_DEBUG_CONFIG(IPCLITE_DBG_STRUCT))) {
 		pr_err("Debug Structures not enabled\n");
 		return;
 	}
@@ -143,7 +138,7 @@ static void ipclite_dump_debug_struct(void)
 
 static void ipclite_dump_inmem_logs(void)
 {
-	int i;
+	int i = 0;
 	uint32_t local_index = 0;
 
 	/* Check if debug and inmem structures are initialized */
@@ -153,7 +148,7 @@ static void ipclite_dump_inmem_logs(void)
 	}
 
 	/* Check if debug structures are enabled before printing */
-	if (!(ipclite_debug_control & IPCLITE_INMEM_LOG)) {
+	if (!(IS_DEBUG_CONFIG(IPCLITE_INMEM_LOG))) {
 		pr_err("In-Memory Logs not enabled\n");
 		return;
 	}
@@ -185,17 +180,16 @@ int ipclite_hw_mutex_acquire(void)
 	int ret;
 
 	if (unlikely(!ipclite)) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite not initialized");
+		pr_err("IPCLite not initialized\n");
 		return -ENOMEM;
 	}
 	ret = hwspin_lock_timeout_irqsave(ipclite->hwlock,
 					HWSPINLOCK_TIMEOUT, &ipclite->hw_mutex_flags);
 	if (ret) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Hw mutex lock acquire failed");
+		pr_err("Hw mutex lock acquire failed\n");
 		return ret;
 	}
 	ipclite->ipcmem.toc_data.host_info->hwlock_owner = IPCMEM_APPS;
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Hw mutex lock acquired");
 	return ret;
 }
 EXPORT_SYMBOL(ipclite_hw_mutex_acquire);
@@ -203,7 +197,7 @@ EXPORT_SYMBOL(ipclite_hw_mutex_acquire);
 int ipclite_hw_mutex_release(void)
 {
 	if (unlikely(!ipclite)) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite not initialized");
+		pr_err("IPCLite not initialized\n");
 		return -ENOMEM;
 	}
 	if (ipclite->ipcmem.toc_data.host_info->hwlock_owner != IPCMEM_APPS)
@@ -211,45 +205,61 @@ int ipclite_hw_mutex_release(void)
 
 	ipclite->ipcmem.toc_data.host_info->hwlock_owner = IPCMEM_INVALID_HOST;
 	hwspin_unlock_irqrestore(ipclite->hwlock, &ipclite->hw_mutex_flags);
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Hw mutex lock released");
 	return 0;
 }
 EXPORT_SYMBOL(ipclite_hw_mutex_release);
 
+/* Atomic Functions Start */
 void ipclite_atomic_init_u32(ipclite_atomic_uint32_t *addr, uint32_t data)
 {
+	BUG_ON(addr == NULL);
+
 	atomic_set(addr, data);
 }
 EXPORT_SYMBOL(ipclite_atomic_init_u32);
 
 void ipclite_atomic_init_i32(ipclite_atomic_int32_t *addr, int32_t data)
 {
+	BUG_ON(addr == NULL);
+
 	atomic_set(addr, data);
 }
 EXPORT_SYMBOL(ipclite_atomic_init_i32);
 
 void ipclite_global_atomic_store_u32(ipclite_atomic_uint32_t *addr, uint32_t data)
 {
+	BUG_ON(addr == NULL);
+
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	atomic_set(addr, data);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 }
 EXPORT_SYMBOL(ipclite_global_atomic_store_u32);
 
 void ipclite_global_atomic_store_i32(ipclite_atomic_int32_t *addr, int32_t data)
 {
+	BUG_ON(addr == NULL);
+
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	atomic_set(addr, data);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 }
 EXPORT_SYMBOL(ipclite_global_atomic_store_i32);
 
 uint32_t ipclite_global_atomic_load_u32(ipclite_atomic_uint32_t *addr)
 {
-	uint32_t ret;
+	uint32_t ret = 0;
+
+	BUG_ON(addr == NULL);
 
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	ret = atomic_read(addr);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 
 	return ret;
@@ -258,10 +268,14 @@ EXPORT_SYMBOL(ipclite_global_atomic_load_u32);
 
 int32_t ipclite_global_atomic_load_i32(ipclite_atomic_int32_t *addr)
 {
-	int32_t ret;
+	int32_t ret = 0;
+
+	BUG_ON(addr == NULL);
 
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	ret = atomic_read(addr);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 
 	return ret;
@@ -270,11 +284,14 @@ EXPORT_SYMBOL(ipclite_global_atomic_load_i32);
 
 uint32_t ipclite_global_test_and_set_bit(uint32_t nr, ipclite_atomic_uint32_t *addr)
 {
-	uint32_t ret;
-	uint32_t mask = (1 << nr);
+	uint32_t ret = 0, mask = (1 << nr);
+
+	BUG_ON(addr == NULL);
 
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	ret = atomic_fetch_or(mask, addr);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 
 	return ret;
@@ -283,11 +300,14 @@ EXPORT_SYMBOL(ipclite_global_test_and_set_bit);
 
 uint32_t ipclite_global_test_and_clear_bit(uint32_t nr, ipclite_atomic_uint32_t *addr)
 {
-	uint32_t ret;
-	uint32_t mask = (1 << nr);
+	uint32_t ret = 0, mask = (1 << nr);
+
+	BUG_ON(addr == NULL);
 
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	ret = atomic_fetch_and(~mask, addr);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 
 	return ret;
@@ -298,8 +318,12 @@ int32_t ipclite_global_atomic_inc(ipclite_atomic_int32_t *addr)
 {
 	int32_t ret = 0;
 
+	BUG_ON(addr == NULL);
+
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	ret = atomic_fetch_add(1, addr);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 
 	return ret;
@@ -310,19 +334,23 @@ int32_t ipclite_global_atomic_dec(ipclite_atomic_int32_t *addr)
 {
 	int32_t ret = 0;
 
+	BUG_ON(addr == NULL);
+
 	ATOMIC_HW_MUTEX_ACQUIRE;
+
 	ret = atomic_fetch_sub(1, addr);
+
 	ATOMIC_HW_MUTEX_RELEASE;
 
 	return ret;
 }
 EXPORT_SYMBOL(ipclite_global_atomic_dec);
+/* Atomic Functions End */
 
 static size_t ipcmem_rx_avail(struct ipclite_fifo *rx_fifo)
 {
-	size_t len;
-	u32 head;
-	u32 tail;
+	size_t len = 0;
+	u32 head = 0, tail = 0;
 
 	head = le32_to_cpu(*rx_fifo->head);
 	tail = le32_to_cpu(*rx_fifo->tail);
@@ -345,8 +373,8 @@ static size_t ipcmem_rx_avail(struct ipclite_fifo *rx_fifo)
 static void ipcmem_rx_peak(struct ipclite_fifo *rx_fifo,
 			       void *data, size_t count)
 {
-	size_t len;
-	u32 tail;
+	size_t len = 0;
+	u32 tail = 0;
 
 	tail = le32_to_cpu(*rx_fifo->tail);
 
@@ -367,7 +395,7 @@ static void ipcmem_rx_peak(struct ipclite_fifo *rx_fifo,
 static void ipcmem_rx_advance(struct ipclite_fifo *rx_fifo,
 				  size_t count, uint32_t core_id)
 {
-	u32 tail;
+	u32 tail = 0;
 
 	tail = le32_to_cpu(*rx_fifo->tail);
 
@@ -378,7 +406,7 @@ static void ipcmem_rx_advance(struct ipclite_fifo *rx_fifo,
 	*rx_fifo->tail = cpu_to_le32(tail);
 
 	/* Storing the debug data in debug structures */
-	if (ipclite_debug_control & IPCLITE_DBG_STRUCT) {
+	if (IS_DEBUG_CONFIG(IPCLITE_DBG_STRUCT)) {
 		ipclite_dbg_struct->dbg_info_host[core_id].prev_rx_wr_index[1] =
 				ipclite_dbg_struct->dbg_info_host[core_id].prev_rx_wr_index[0];
 		ipclite_dbg_struct->dbg_info_host[core_id].prev_rx_wr_index[0] =
@@ -398,9 +426,7 @@ static void ipcmem_rx_advance(struct ipclite_fifo *rx_fifo,
 
 static size_t ipcmem_tx_avail(struct ipclite_fifo *tx_fifo)
 {
-	u32 head;
-	u32 tail;
-	u32 avail;
+	u32 head = 0, tail = 0, avail = 0;
 
 	head = le32_to_cpu(*tx_fifo->head);
 	tail = le32_to_cpu(*tx_fifo->tail);
@@ -425,7 +451,7 @@ static unsigned int ipcmem_tx_write_one(struct ipclite_fifo *tx_fifo,
 					    unsigned int head,
 					    const void *data, size_t count)
 {
-	size_t len;
+	size_t len = 0;
 
 	if (WARN_ON_ONCE(head > tx_fifo->length))
 		return head;
@@ -447,7 +473,7 @@ static unsigned int ipcmem_tx_write_one(struct ipclite_fifo *tx_fifo,
 static void ipcmem_tx_write(struct ipclite_fifo *tx_fifo,
 			const void *data, size_t dlen, uint32_t core_id, uint32_t signal_id)
 {
-	unsigned int head;
+	unsigned int head = 0;
 
 	head = le32_to_cpu(*tx_fifo->head);
 	head = ipcmem_tx_write_one(tx_fifo, head, data, dlen);
@@ -465,7 +491,7 @@ static void ipcmem_tx_write(struct ipclite_fifo *tx_fifo,
 						*tx_fifo->head, core_id, signal_id);
 
 	/* Storing the debug data in debug structures */
-	if (ipclite_debug_control & IPCLITE_DBG_STRUCT) {
+	if (IS_DEBUG_CONFIG(IPCLITE_DBG_STRUCT)) {
 		ipclite_dbg_struct->dbg_info_host[core_id].prev_tx_wr_index[1] =
 				ipclite_dbg_struct->dbg_info_host[core_id].prev_tx_wr_index[0];
 		ipclite_dbg_struct->dbg_info_host[core_id].prev_tx_wr_index[0] =
@@ -516,8 +542,8 @@ static void ipclite_tx_write(struct ipclite_channel *channel,
 
 static int ipclite_rx_data(struct ipclite_channel *channel, size_t avail)
 {
-	uint64_t data;
 	int ret = 0;
+	uint64_t data = 0;
 
 	if (avail < sizeof(data)) {
 		IPCLITE_OS_LOG(IPCLITE_ERR, "Not enough data in fifo, Core : %d Signal : %d\n",
@@ -538,8 +564,8 @@ static int ipclite_rx_data(struct ipclite_channel *channel, size_t avail)
 
 static int ipclite_rx_test_data(struct ipclite_channel *channel, size_t avail)
 {
-	uint64_t data;
 	int ret = 0;
+	uint64_t data = 0;
 
 	if (avail < sizeof(data)) {
 		IPCLITE_OS_LOG(IPCLITE_ERR, "Not enough data in fifo, Core : %d Signal : %d\n",
@@ -560,11 +586,11 @@ static int ipclite_rx_test_data(struct ipclite_channel *channel, size_t avail)
 
 static irqreturn_t ipclite_intr(int irq, void *data)
 {
+	int ret = 0;
+	unsigned int avail = 0;
+	uint64_t msg = 0;
 	struct ipclite_channel *channel;
 	struct ipclite_irq_info *irq_info;
-	unsigned int avail = 0;
-	int ret = 0;
-	uint64_t msg;
 
 	irq_info = (struct ipclite_irq_info *)data;
 	channel = container_of(irq_info, struct ipclite_channel, irq_info[irq_info->signal_id]);
@@ -573,7 +599,7 @@ static irqreturn_t ipclite_intr(int irq, void *data)
 							channel->remote_pid, irq_info->signal_id);
 
 	/* Storing the debug data in debug structures */
-	if (ipclite_debug_control & IPCLITE_DBG_STRUCT) {
+	if (IS_DEBUG_CONFIG(IPCLITE_DBG_STRUCT)) {
 		ipclite_dbg_struct->dbg_info_host[channel->remote_pid].num_intr++;
 		ipclite_dbg_struct->dbg_info_overall.last_recv_host_id = channel->remote_pid;
 		ipclite_dbg_struct->dbg_info_overall.last_sigid_recv = irq_info->signal_id;
@@ -589,7 +615,7 @@ static irqreturn_t ipclite_intr(int irq, void *data)
 		}
 		IPCLITE_OS_LOG(IPCLITE_DBG, "checking messages in rx_fifo done\n");
 	} else if (irq_info->signal_id == IPCLITE_VERSION_SIGNAL) {
-		IPCLITE_OS_LOG(IPCLITE_DBG, "Versioning is currently not enabled\n");
+		IPCLITE_OS_LOG(IPCLITE_DBG, "Versioning is not enabled using IPCC signals\n");
 	} else if (irq_info->signal_id == IPCLITE_TEST_SIGNAL) {
 		for (;;) {
 			avail = ipclite_rx_avail(channel);
@@ -610,8 +636,8 @@ static irqreturn_t ipclite_intr(int irq, void *data)
 static int ipclite_tx(struct ipclite_channel *channel,
 			uint64_t data, size_t dlen, uint32_t ipclite_signal)
 {
-	unsigned long flags;
 	int ret = 0;
+	unsigned long flags;
 
 	if (channel->status != ACTIVE) {
 		if (channel->status == IN_PROGRESS && *channel->gstatus_ptr == ACTIVE) {
@@ -639,41 +665,7 @@ static int ipclite_tx(struct ipclite_channel *channel,
 	return ret;
 }
 
-static int ipclite_send_debug_info(int32_t proc_id)
-{
-	int ret = 0;
-	struct ipclite_channel *channel;
-
-	if (proc_id < 0 || proc_id >= IPCMEM_NUM_HOSTS) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid proc_id : %d\n", proc_id);
-		return -EINVAL;
-	}
-	channel = &ipclite->channel[proc_id];
-
-	if (channel->status != ACTIVE) {
-		if (channel->status == IN_PROGRESS && *channel->gstatus_ptr == ACTIVE) {
-			channel->status = ACTIVE;
-		} else {
-			IPCLITE_OS_LOG(IPCLITE_ERR, "Cannot Send, Core %d is Inactive\n", proc_id);
-			return -EOPNOTSUPP;
-		}
-	}
-
-	ret = mbox_send_message(channel->irq_info[IPCLITE_DEBUG_SIGNAL].mbox_chan, NULL);
-	if (ret < 0) {
-		IPCLITE_OS_LOG(IPCLITE_ERR,
-				"Debug Signal sending failed to Core : %d Signal : %d ret : %d\n",
-							proc_id, IPCLITE_DEBUG_SIGNAL, ret);
-		return ret;
-	}
-
-	IPCLITE_OS_LOG(IPCLITE_DBG,
-				"Debug Signal send completed to core : %d signal : %d ret : %d\n",
-							proc_id, IPCLITE_DEBUG_SIGNAL, ret);
-	return 0;
-}
-
-int ipclite_ssr_update(int32_t proc_id)
+static int ipclite_notify_core(int32_t proc_id, int32_t signal_id)
 {
 	int ret = 0;
 	struct ipclite_channel *channel;
@@ -693,156 +685,26 @@ int ipclite_ssr_update(int32_t proc_id)
 		}
 	}
 
-	ret = mbox_send_message(channel->irq_info[IPCLITE_SSR_SIGNAL].mbox_chan, NULL);
+	ret = mbox_send_message(channel->irq_info[signal_id].mbox_chan, NULL);
 	if (ret < 0) {
 		IPCLITE_OS_LOG(IPCLITE_ERR,
-				"SSR Signal sending failed to Core : %d Signal : %d ret : %d\n",
-							proc_id, IPCLITE_SSR_SIGNAL, ret);
+				"Signal sending failed to Core : %d Signal : %d ret : %d\n",
+									proc_id, signal_id, ret);
 		return ret;
 	}
 
 	IPCLITE_OS_LOG(IPCLITE_DBG,
-				"SSR Signal send completed to core : %d signal : %d ret : %d\n",
-							proc_id, IPCLITE_SSR_SIGNAL, ret);
-	return 0;
-}
-
-void ipclite_recover(enum ipcmem_host_type core_id)
-{
-	int ret, host, host0, host1;
-	uint32_t p;
-
-	IPCLITE_OS_LOG(IPCLITE_DBG, "IPCLite Recover - Crashed Core : %d\n", core_id);
-
-	/* verify and reset the hw mutex lock */
-	if (core_id == ipclite->ipcmem.toc_data.host_info->hwlock_owner) {
-		ipclite->ipcmem.toc_data.host_info->hwlock_owner = IPCMEM_INVALID_HOST;
-		hwspin_unlock_raw(ipclite->hwlock);
-		IPCLITE_OS_LOG(IPCLITE_DBG, "HW Lock Reset\n");
-	}
-
-	mutex_lock(&ssr_mutex);
-	/* Set the Global Channel Status to 0 to avoid Race condition */
-	for (p = 0; p < partitions; p++) {
-		host0 = ipclite->ipcmem.toc_data.partition_entry[p].host0;
-		host1 = ipclite->ipcmem.toc_data.partition_entry[p].host1;
-		if (host0 != core_id && host1 != core_id)
-			continue;
-
-		ipclite_global_atomic_store_i32((ipclite_atomic_int32_t *)
-			(&(ipclite->ipcmem.partition[p]->hdr.status)), 0);
-
-		IPCLITE_OS_LOG(IPCLITE_DBG, "Global Channel Status : [%d][%d] : %d\n",
-					host0, host1, ipclite->ipcmem.partition[p]->hdr.status);
-	}
-
-	/* Resets the TX/RX queue */
-	*(ipclite->channel[core_id].tx_fifo->head) = 0;
-	*(ipclite->channel[core_id].rx_fifo->tail) = 0;
-
-	IPCLITE_OS_LOG(IPCLITE_DBG, "TX Fifo Reset : %d\n",
-						*(ipclite->channel[core_id].tx_fifo->head));
-	IPCLITE_OS_LOG(IPCLITE_DBG, "RX Fifo Reset : %d\n",
-						*(ipclite->channel[core_id].rx_fifo->tail));
-
-	/* Increment the Global Channel Status for APPS and crashed core*/
-	ipclite_global_atomic_inc((ipclite_atomic_int32_t *)
-					ipclite->channel[core_id].gstatus_ptr);
-
-	ipclite->channel[core_id].status = *ipclite->channel[core_id].gstatus_ptr;
-
-	/* Update other cores about SSR */
-	for (host = 1; host < IPCMEM_NUM_HOSTS; host++) {
-		if (!is_host_enabled(host) || host == core_id)
-			continue;
-		ret = ipclite_ssr_update(host);
-		if (ret < 0)
-			IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to send SSR update to core %d\n", host);
-		else
-			IPCLITE_OS_LOG(IPCLITE_DBG, "SSR update sent to core %d\n", host);
-	}
-	mutex_unlock(&ssr_mutex);
-
-	/* Dump the debug information */
-	if (ipclite_debug_dump & IPCLITE_DUMP_SSR) {
-		ipclite_dump_debug_struct();
-		ipclite_dump_inmem_logs();
-	}
-
-	return;
-}
-EXPORT_SYMBOL(ipclite_recover);
-
-int ipclite_msg_send(int32_t proc_id, uint64_t data)
-{
-	int ret = 0;
-
-	if (proc_id < 0 || proc_id >= IPCMEM_NUM_HOSTS) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid proc_id : %d\n", proc_id);
-		return -EINVAL;
-	}
-
-	ret = ipclite_tx(&ipclite->channel[proc_id], data, sizeof(data),
-								IPCLITE_MSG_SIGNAL);
-
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Message send complete to core : %d signal : %d ret : %d\n",
-								proc_id, IPCLITE_MSG_SIGNAL, ret);
-	return ret;
-}
-EXPORT_SYMBOL(ipclite_msg_send);
-
-int ipclite_register_client(IPCLite_Client cb_func_ptr, void *priv)
-{
-	if (!cb_func_ptr) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid callback pointer\n");
-		return -EINVAL;
-	}
-	synx_client.callback = cb_func_ptr;
-	synx_client.priv_data = priv;
-	synx_client.reg_complete = 1;
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Client Registration completed\n");
-	return 0;
-}
-EXPORT_SYMBOL(ipclite_register_client);
-
-int ipclite_test_msg_send(int32_t proc_id, uint64_t data)
-{
-	int ret = 0;
-
-	if (proc_id < 0 || proc_id >= IPCMEM_NUM_HOSTS) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid proc_id : %d\n", proc_id);
-		return -EINVAL;
-	}
-
-	ret = ipclite_tx(&ipclite->channel[proc_id], data, sizeof(data),
-									IPCLITE_TEST_SIGNAL);
-
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Test Msg send complete to core : %d signal : %d ret : %d\n",
-								proc_id, IPCLITE_TEST_SIGNAL, ret);
-	return ret;
-}
-EXPORT_SYMBOL(ipclite_test_msg_send);
-
-int ipclite_register_test_client(IPCLite_Client cb_func_ptr, void *priv)
-{
-	if (!cb_func_ptr) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid callback pointer\n");
-		return -EINVAL;
-	}
-	test_client.callback = cb_func_ptr;
-	test_client.priv_data = priv;
-	test_client.reg_complete = 1;
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Test Client Registration Completed\n");
+			"Signal send completed to core : %d signal : %d ret : %d\n",
+									proc_id, signal_id, ret);
 	return 0;
 }
-EXPORT_SYMBOL(ipclite_register_test_client);
 
 static int map_ipcmem(struct ipclite_info *ipclite, const char *name)
 {
+	int ret = 0;
 	struct device *dev;
 	struct device_node *np;
 	struct resource r;
-	int ret = 0;
 
 	dev = ipclite->dev;
 
@@ -1004,15 +866,14 @@ static int32_t setup_partitions(struct ipclite_mem *ipcmem, uint32_t base_offset
 	/*Set up info to parse partition entries*/
 	ipcmem->toc_data.partition_info->num_entries = partitions = num_entry;
 	ipcmem->toc_data.partition_info->entry_size = sizeof(struct ipcmem_partition_entry);
+
 	return 0;
 }
 
 static int32_t ipcmem_init(struct ipclite_mem *ipcmem, struct device_node *pn)
 {
-	int ret;
-	uint32_t remote_pid;
-	uint32_t host_count = 0;
-	uint32_t gmem_offset = 0;
+	int ret = 0;
+	uint32_t remote_pid = 0, host_count = 0, gmem_offset = 0;
 	struct device_node *cn;
 
 	for_each_available_child_of_node(pn, cn) {
@@ -1053,6 +914,7 @@ static int32_t ipcmem_init(struct ipclite_mem *ipcmem, struct device_node *pn)
 
 	ipcmem->toc->hdr.init_done = IPCMEM_INIT_COMPLETED;
 	IPCLITE_OS_LOG(IPCLITE_DBG, "Ipcmem init completed\n");
+
 	return 0;
 }
 
@@ -1060,7 +922,7 @@ static int ipclite_channel_irq_init(struct device *parent, struct device_node *n
 								struct ipclite_channel *channel)
 {
 	int ret = 0;
-	u32 index;
+	u32 index = 0;
 	struct ipclite_irq_info *irq_info;
 	struct device *dev;
 	char strs[MAX_CHANNEL_SIGNALS][IPCLITE_SIGNAL_LABEL_SIZE] = {
@@ -1081,8 +943,7 @@ static int ipclite_channel_irq_init(struct device *parent, struct device_node *n
 		return ret;
 	}
 
-	ret = of_property_read_u32(dev->of_node, "index",
-				   &index);
+	ret = of_property_read_u32(dev->of_node, "index", &index);
 	if (ret) {
 		IPCLITE_OS_LOG(IPCLITE_ERR, "failed to parse index\n");
 		goto err_dev;
@@ -1114,7 +975,8 @@ static int ipclite_channel_irq_init(struct device *parent, struct device_node *n
 		goto err_dev;
 	}
 	IPCLITE_OS_LOG(IPCLITE_DBG, "Interrupt init completed, ret = %d\n", ret);
-	return 0;
+
+	return ret;
 
 err_dev:
 	device_unregister(dev);
@@ -1122,34 +984,10 @@ err_dev:
 	return ret;
 }
 
-int32_t get_global_partition_info(struct global_region_info *global_ipcmem)
-{
-	struct ipcmem_global_partition *global_partition;
-
-	if (!ipclite) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite not initialized\n");
-		return -ENOMEM;
-	}
-
-	if (!global_ipcmem)
-		return -EINVAL;
-
-	global_partition = ipclite->ipcmem.global_partition;
-	global_ipcmem->virt_base = (void *)((char *)global_partition +
-							global_partition->hdr.region_offset);
-	global_ipcmem->size = (size_t)(global_partition->hdr.region_size);
-
-	IPCLITE_OS_LOG(IPCLITE_DBG, "base = %p, size=%lx\n", global_ipcmem->virt_base,
-									global_ipcmem->size);
-	return 0;
-}
-EXPORT_SYMBOL(get_global_partition_info);
-
 static struct ipcmem_partition_header *get_ipcmem_partition_hdr(struct ipclite_mem ipcmem, int local_pid,
 								int remote_pid)
 {
-	uint32_t p;
-	uint32_t found = -1;
+	uint32_t p = 0, found = -1;
 
 	for (p = 0; p < partitions; p++) {
 		if (ipcmem.toc_data.partition_entry[p].host0 == local_pid
@@ -1178,16 +1016,13 @@ static void ipclite_channel_release(struct device *dev)
 static int ipclite_channel_init(struct device *parent,
 								struct device_node *node)
 {
+	int ret = 0;
+	u32 local_pid = 0, remote_pid = 0;
+	u32 *descs = NULL;
 	struct ipclite_fifo *rx_fifo;
 	struct ipclite_fifo *tx_fifo;
-
 	struct device *dev;
-	u32 local_pid, remote_pid, global_atomic;
-	u32 *descs;
-	int ret = 0;
-
 	struct device_node *child;
-
 	struct ipcmem_partition_header *partition_hdr;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1217,14 +1052,6 @@ static int ipclite_channel_init(struct device *parent,
 	}
 	IPCLITE_OS_LOG(IPCLITE_DBG, "remote_pid = %d, local_pid=%d\n", remote_pid, local_pid);
 
-	ret = of_property_read_u32(dev->of_node, "global_atomic", &global_atomic);
-	if (ret) {
-		dev_err(dev, "failed to parse global_atomic\n");
-		goto err_put_dev;
-	}
-	if (global_atomic == 0)
-		global_atomic_support = GLOBAL_ATOMICS_DISABLED;
-
 	rx_fifo = devm_kzalloc(dev, sizeof(*rx_fifo), GFP_KERNEL);
 	tx_fifo = devm_kzalloc(dev, sizeof(*tx_fifo), GFP_KERNEL);
 	if (!rx_fifo || !tx_fifo) {
@@ -1327,6 +1154,7 @@ static void probe_subsystem(struct device *dev, struct device_node *np)
 		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite Channel init failed\n");
 }
 
+/* IPCLite Debug related functions start */
 static ssize_t ipclite_dbg_lvl_write(struct kobject *kobj,
 				struct kobj_attribute *attr, const char *buf, size_t count)
 {
@@ -1355,7 +1183,7 @@ static ssize_t ipclite_dbg_lvl_write(struct kobject *kobj,
 	for (host = 1; host < IPCMEM_NUM_HOSTS; host++) {
 		if (!is_host_enabled(host))
 			continue;
-		ret = ipclite_send_debug_info(host);
+		ret = ipclite_notify_core(host, IPCLITE_DEBUG_SIGNAL);
 		if (ret < 0)
 			IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to send the debug info %d\n", host);
 		else
@@ -1393,7 +1221,7 @@ static ssize_t ipclite_dbg_ctrl_write(struct kobject *kobj,
 	for (host = 1; host < IPCMEM_NUM_HOSTS; host++) {
 		if (!is_host_enabled(host))
 			continue;
-		ret = ipclite_send_debug_info(host);
+		ret = ipclite_notify_core(host, IPCLITE_DEBUG_SIGNAL);
 		if (ret < 0)
 			IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to send the debug info %d\n", host);
 		else
@@ -1471,7 +1299,7 @@ static int ipclite_debug_sysfs_setup(void)
 	return ret;
 }
 
-static int ipclite_debug_info_setup(void)
+static int ipclite_debug_mem_setup(void)
 {
 	/* Setting up the Debug Structures */
 	ipclite_dbg_info = (struct ipclite_debug_info *)(((char *)ipclite->ipcmem.mem.virt_base +
@@ -1500,44 +1328,112 @@ static int ipclite_debug_info_setup(void)
 	return 0;
 }
 
-static int ipclite_probe(struct platform_device *pdev)
+static int ipclite_debug_setup(void)
 {
 	int ret = 0;
-	int hwlock_id;
-	struct ipcmem_region *mem;
-	struct device_node *cn;
-	struct device_node *pn = pdev->dev.of_node;
-	struct ipclite_channel broadcast;
 
-	ipclite = kzalloc(sizeof(*ipclite), GFP_KERNEL);
-	if (!ipclite) {
-		ret = -ENOMEM;
-		goto error;
+	/* Set up sysfs for debug */
+	ret = ipclite_debug_sysfs_setup();
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to Set up IPCLite Debug Sysfs\n");
+		return ret;
 	}
 
-	ipclite->dev = &pdev->dev;
-
-	hwlock_id = of_hwspin_lock_get_id(pn, 0);
-	if (hwlock_id < 0) {
-		if (hwlock_id != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "failed to retrieve hwlock\n");
-		ret = hwlock_id;
-		goto release;
+	/* Mapping Debug Memory */
+	ret = ipclite_debug_mem_setup();
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to Set up IPCLite Debug Structures\n");
+		return ret;
 	}
-	IPCLITE_OS_LOG(IPCLITE_DBG, "Hwlock id retrieved, hwlock_id=%d\n", hwlock_id);
 
-	ipclite->hwlock = hwspin_lock_request_specific(hwlock_id);
-	if (!ipclite->hwlock) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to assign hwlock_id\n");
-		ret = -ENXIO;
-		goto release;
-	}
+	/* Update the Global Debug variable for FW cores */
+	ipclite_dbg_info->debug_level = ipclite_debug_level;
+	ipclite_dbg_info->debug_control = ipclite_debug_control;
+
+	return ret;
+}
+/* IPCLite Debug related functions end */
+
+/* IPCLite Features setup related functions start */
+static int ipclite_feature_setup(struct device_node *pn)
+{
+	int ret = 0;
+	uint32_t feature_mask_l = 0, feature_mask_h = 0;
+
+	/* Parse the feature related DT entries and store the values locally */
+	ret = of_property_read_u32(pn, "feature_mask_low", &feature_mask_l);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "failed to parse feature_mask_low\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(pn, "feature_mask_high", &feature_mask_h);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "failed to parse feature_mask_high\n");
+		return ret;
+	}
+
+	/* Combine feature_mask_low and feature_mask_high into 64-bit feature_mask */
+	feature_mask = (uint64_t) feature_mask_h << 32 | feature_mask_l;
+
+	/* Update the feature mask to TOC for FW */
+	ipclite->ipcmem.toc->hdr.feature_mask = feature_mask;
+
+	/* Set up Global Atomics Feature*/
+	if (!(IS_FEATURE_CONFIG(IPCLITE_GLOBAL_ATOMIC)))
+		IPCLITE_OS_LOG(IPCLITE_INFO, "IPCLite Global Atomic Support Disabled\n");
+
+	/* Set up Test Suite Feature*/
+	if (!(IS_FEATURE_CONFIG(IPCLITE_TEST_SUITE)))
+		IPCLITE_OS_LOG(IPCLITE_INFO, "IPCLite Test Suite Disabled\n");
+
+	return ret;
+}
+/* IPCLite Features setup related functions end */
+
+/* API Definition Start - Minor Version 0*/
+static int ipclite_init_v0(struct platform_device *pdev)
+{
+	int ret = 0, hwlock_id = 0;
+	struct ipcmem_region *mem;
+	struct device_node *cn;
+	struct device_node *pn = pdev->dev.of_node;
+	struct ipclite_channel broadcast;
+
+	/* Allocate memory for IPCLite */
+	ipclite = kzalloc(sizeof(*ipclite), GFP_KERNEL);
+	if (!ipclite) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite Memory Allocation Failed\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	ipclite->dev = &pdev->dev;
+
+	/* Parse HW Lock from DT */
+	hwlock_id = of_hwspin_lock_get_id(pn, 0);
+	if (hwlock_id < 0) {
+		if (hwlock_id != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to retrieve hwlock\n");
+		ret = hwlock_id;
+		goto release;
+	}
+	IPCLITE_OS_LOG(IPCLITE_DBG, "Hwlock id retrieved, hwlock_id=%d\n", hwlock_id);
+
+	/* Reserve a HWSpinLock for later use */
+	ipclite->hwlock = hwspin_lock_request_specific(hwlock_id);
+	if (!ipclite->hwlock) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to assign hwlock_id\n");
+		ret = -ENXIO;
+		goto release;
+	}
 	IPCLITE_OS_LOG(IPCLITE_DBG, "Hwlock id assigned successfully, hwlock=%p\n",
 									ipclite->hwlock);
 
 	/* Initializing Local Mutex Lock for SSR functionality */
 	mutex_init(&ssr_mutex);
 
+	/* Map to IPCLite Memory */
 	ret = map_ipcmem(ipclite, "memory-region");
 	if (ret) {
 		IPCLITE_OS_LOG(IPCLITE_ERR, "failed to map ipcmem\n");
@@ -1552,47 +1448,44 @@ static int ipclite_probe(struct platform_device *pdev)
 		goto release;
 	}
 
-	/* Set up sysfs for debug  */
-	ret = ipclite_debug_sysfs_setup();
-	if (ret) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to Set up IPCLite Debug Sysfs\n");
-		goto release;
-	}
-
-	/* Mapping Debug Memory */
-	ret = ipclite_debug_info_setup();
-	if (ret) {
-		IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to Set up IPCLite Debug Structures\n");
-		goto release;
-	}
-
 	/* Setup Channel for each Remote Subsystem */
 	for_each_available_child_of_node(pn, cn)
 		probe_subsystem(&pdev->dev, cn);
-	/* Broadcast init_done signal to all subsystems once mbox channels
-	 * are set up
-	 */
+
+	/* Broadcast init_done signal to all subsystems once mbox channels are set up */
 	broadcast = ipclite->channel[IPCMEM_APPS];
-	ret = mbox_send_message(broadcast.irq_info[IPCLITE_MEM_INIT_SIGNAL].mbox_chan,
-								 NULL);
+	ret = mbox_send_message(broadcast.irq_info[IPCLITE_MEM_INIT_SIGNAL].mbox_chan, NULL);
 	if (ret < 0)
 		goto mem_release;
 
 	mbox_client_txdone(broadcast.irq_info[IPCLITE_MEM_INIT_SIGNAL].mbox_chan, 0);
 
-	if (global_atomic_support) {
-		ipclite->ipcmem.toc->hdr.feature_mask |= GLOBAL_ATOMIC_SUPPORT_BMSK;
+	/* Debug Setup */
+	ret = ipclite_debug_setup();
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite Debug Setup Failed\n");
+		goto release;
+	}
+
+	/* Features Setup */
+	ret = ipclite_feature_setup(pn);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite Features Setup Failed\n");
+		goto release;
 	}
-	IPCLITE_OS_LOG(IPCLITE_DBG, "global_atomic_support : %d\n", global_atomic_support);
+
+	/* Update TOC with version entries for FW */
+	ipclite->ipcmem.toc->hdr.major_version = major_ver;
+	ipclite->ipcmem.toc->hdr.minor_version = minor_ver;
 
 	/* Should be called after all Global TOC related init is done */
 	insert_magic_number();
 
-	/* Update the Global Debug variable for FW cores */
-	ipclite_dbg_info->debug_level = ipclite_debug_level;
-	ipclite_dbg_info->debug_control = ipclite_debug_control;
+	IPCLITE_OS_LOG(IPCLITE_INFO, "IPCLite Version : %d.%d Feature Mask : 0x%llx\n",
+						major_ver, minor_ver, feature_mask);
+
+	IPCLITE_OS_LOG(IPCLITE_INFO, "IPCLite Probe Completed Successfully\n");
 
-	IPCLITE_OS_LOG(IPCLITE_INFO, "IPCLite probe completed successfully\n");
 	return ret;
 
 mem_release:
@@ -1605,6 +1498,363 @@ mem_release:
 release:
 	kfree(ipclite);
 	ipclite = NULL;
+error:
+	return ret;
+}
+
+static int ipclite_register_client_v0(IPCLite_Client cb_func_ptr, void *priv)
+{
+	if (!cb_func_ptr) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid callback pointer\n");
+		return -EINVAL;
+	}
+
+	synx_client.callback = cb_func_ptr;
+	synx_client.priv_data = priv;
+	synx_client.reg_complete = 1;
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "Client Registration completed\n");
+
+	return 0;
+}
+
+static int ipclite_register_test_client_v0(IPCLite_Client cb_func_ptr, void *priv)
+{
+	if (!cb_func_ptr) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid callback pointer\n");
+		return -EINVAL;
+	}
+
+	test_client.callback = cb_func_ptr;
+	test_client.priv_data = priv;
+	test_client.reg_complete = 1;
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "Test Client Registration Completed\n");
+
+	return 0;
+}
+
+static int ipclite_msg_send_v0(int32_t proc_id, uint64_t data)
+{
+	int ret = 0;
+
+	/* Check for valid core id */
+	if (proc_id < 0 || proc_id >= IPCMEM_NUM_HOSTS) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid proc_id : %d\n", proc_id);
+		return -EINVAL;
+	}
+
+	/* Send the data to the core */
+	ret = ipclite_tx(&ipclite->channel[proc_id], data, sizeof(data), IPCLITE_MSG_SIGNAL);
+	if (ret < 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Message send failed to core : %d signal:%d ret:%d\n",
+								proc_id, IPCLITE_MSG_SIGNAL, ret);
+		return ret;
+	}
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "Message send complete to core : %d signal : %d ret : %d\n",
+								proc_id, IPCLITE_MSG_SIGNAL, ret);
+	return ret;
+}
+
+static int ipclite_test_msg_send_v0(int32_t proc_id, uint64_t data)
+{
+	int ret = 0;
+
+	/* Check for valid core id */
+	if (proc_id < 0 || proc_id >= IPCMEM_NUM_HOSTS) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Invalid proc_id : %d\n", proc_id);
+		return -EINVAL;
+	}
+
+	/* Send the data to the core */
+	ret = ipclite_tx(&ipclite->channel[proc_id], data, sizeof(data), IPCLITE_TEST_SIGNAL);
+	if (ret < 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Message send failed to core : %d signal:%d ret:%d\n",
+								proc_id, IPCLITE_TEST_SIGNAL, ret);
+		return ret;
+	}
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "Test Msg send complete to core : %d signal : %d ret : %d\n",
+								proc_id, IPCLITE_TEST_SIGNAL, ret);
+	return ret;
+}
+
+static int32_t get_global_partition_info_v0(struct global_region_info *global_ipcmem)
+{
+	struct ipcmem_global_partition *global_partition;
+
+	if (!ipclite) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite not initialized\n");
+		return -ENOMEM;
+	}
+
+	if (!global_ipcmem)
+		return -EINVAL;
+
+	global_partition = ipclite->ipcmem.global_partition;
+	global_ipcmem->virt_base = (void *)((char *)global_partition +
+							global_partition->hdr.region_offset);
+	global_ipcmem->size = (size_t)(global_partition->hdr.region_size);
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "base = %p, size=%lx\n", global_ipcmem->virt_base,
+									global_ipcmem->size);
+	return 0;
+}
+
+static void ipclite_recover_v0(enum ipcmem_host_type core_id)
+{
+	int ret = 0, host = 0, host0 = 0, host1 = 0;
+	uint32_t p = 0;
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "IPCLite Recover - Crashed Core : %d\n", core_id);
+
+	/* verify and reset the hw mutex lock */
+	if (core_id == ipclite->ipcmem.toc_data.host_info->hwlock_owner) {
+		ipclite->ipcmem.toc_data.host_info->hwlock_owner = IPCMEM_INVALID_HOST;
+		hwspin_unlock_raw(ipclite->hwlock);
+		IPCLITE_OS_LOG(IPCLITE_DBG, "HW Lock Reset\n");
+	}
+
+	mutex_lock(&ssr_mutex);
+
+	/* Set the Global Channel Status to 0 to avoid Race condition */
+	for (p = 0; p < partitions; p++) {
+		host0 = ipclite->ipcmem.toc_data.partition_entry[p].host0;
+		host1 = ipclite->ipcmem.toc_data.partition_entry[p].host1;
+		if (host0 != core_id && host1 != core_id)
+			continue;
+
+		ipclite_global_atomic_store_i32((ipclite_atomic_int32_t *)
+			(&(ipclite->ipcmem.partition[p]->hdr.status)), 0);
+
+		IPCLITE_OS_LOG(IPCLITE_DBG, "Global Channel Status : [%d][%d] : %d\n",
+					host0, host1, ipclite->ipcmem.partition[p]->hdr.status);
+	}
+
+	/* Resets the TX/RX queue */
+	*(ipclite->channel[core_id].tx_fifo->head) = 0;
+	*(ipclite->channel[core_id].rx_fifo->tail) = 0;
+
+	IPCLITE_OS_LOG(IPCLITE_DBG, "TX Fifo Reset : %d\n",
+						*(ipclite->channel[core_id].tx_fifo->head));
+	IPCLITE_OS_LOG(IPCLITE_DBG, "RX Fifo Reset : %d\n",
+						*(ipclite->channel[core_id].rx_fifo->tail));
+
+	/* Increment the Global Channel Status for APPS and crashed core*/
+	ipclite_global_atomic_inc((ipclite_atomic_int32_t *)
+					ipclite->channel[core_id].gstatus_ptr);
+
+	ipclite->channel[core_id].status = *ipclite->channel[core_id].gstatus_ptr;
+
+	/* Update other cores about SSR */
+	for (host = 1; host < IPCMEM_NUM_HOSTS; host++) {
+		if (!is_host_enabled(host) || host == core_id)
+			continue;
+		ret = ipclite_notify_core(host, IPCLITE_SSR_SIGNAL);
+		if (ret < 0)
+			IPCLITE_OS_LOG(IPCLITE_ERR, "Failed to send SSR update to core %d\n", host);
+		else
+			IPCLITE_OS_LOG(IPCLITE_DBG, "SSR update sent to core %d\n", host);
+	}
+
+	mutex_unlock(&ssr_mutex);
+
+	/* Dump the debug information */
+	if (ipclite_debug_dump & IPCLITE_DUMP_SSR) {
+		ipclite_dump_debug_struct();
+		ipclite_dump_inmem_logs();
+	}
+}
+/* API Definition End - Minor Version 0*/
+
+/* Versioned Functions Start */
+int ipclite_init(struct platform_device *pdev)
+{
+	if (api_list_t.init == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return -EINVAL;
+	}
+
+	return api_list_t.init(pdev);
+}
+
+int ipclite_register_client(IPCLite_Client cb_func_ptr, void *priv)
+{
+	if (api_list_t.register_client == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return -EINVAL;
+	}
+
+	return api_list_t.register_client(cb_func_ptr, priv);
+}
+EXPORT_SYMBOL(ipclite_register_client);
+
+int ipclite_register_test_client(IPCLite_Client cb_func_ptr, void *priv)
+{
+	if (api_list_t.register_test_client == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return -EINVAL;
+	}
+
+	return api_list_t.register_test_client(cb_func_ptr, priv);
+}
+EXPORT_SYMBOL(ipclite_register_test_client);
+
+int ipclite_msg_send(int32_t proc_id, uint64_t data)
+{
+	if (api_list_t.msg_send == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return -EINVAL;
+	}
+
+	return api_list_t.msg_send(proc_id, data);
+}
+EXPORT_SYMBOL(ipclite_msg_send);
+
+int ipclite_test_msg_send(int32_t proc_id, uint64_t data)
+{
+	if (api_list_t.test_msg_send == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return -EINVAL;
+	}
+
+	return api_list_t.test_msg_send(proc_id, data);
+}
+EXPORT_SYMBOL(ipclite_test_msg_send);
+
+void ipclite_recover(enum ipcmem_host_type core_id)
+{
+	if (api_list_t.recover == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return;
+	}
+
+	api_list_t.recover(core_id);
+}
+EXPORT_SYMBOL(ipclite_recover);
+
+int32_t get_global_partition_info(struct global_region_info *global_ipcmem)
+{
+	if (api_list_t.partition_info == NULL) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "Unassigned function : %s", __func__);
+		return -EINVAL;
+	}
+
+	return api_list_t.partition_info(global_ipcmem);
+}
+EXPORT_SYMBOL(get_global_partition_info);
+/* Versioned Functions End */
+
+/* List of APIs  based on the version */
+struct ipclite_api_list api_list_version[] = {
+	/* Minor Version 0 */
+	{
+		.init = ipclite_init_v0,
+		.register_client = ipclite_register_client_v0,
+		.register_test_client = ipclite_register_test_client_v0,
+		.msg_send = ipclite_msg_send_v0,
+		.test_msg_send = ipclite_test_msg_send_v0,
+		.partition_info = get_global_partition_info_v0,
+		.recover = ipclite_recover_v0,
+	},
+};
+
+/* IPCLite Version setup related functions start */
+static int ipclite_update_version_api(struct ipclite_api_list *res_str,
+						struct ipclite_api_list *ver_str)
+{
+	if (res_str == NULL || ver_str == NULL)
+		return -EINVAL;
+
+	/* Register APIs based on the version */
+	res_str->init = (ver_str->init != NULL) ?
+		ver_str->init : res_str->init;
+
+	res_str->register_client = (ver_str->register_client != NULL) ?
+		ver_str->register_client : res_str->register_client;
+	res_str->register_test_client = (ver_str->register_test_client != NULL) ?
+		ver_str->register_test_client : res_str->register_test_client;
+
+	res_str->msg_send = (ver_str->msg_send != NULL) ?
+		ver_str->msg_send : res_str->msg_send;
+	res_str->test_msg_send = (ver_str->test_msg_send != NULL) ?
+		ver_str->test_msg_send : res_str->test_msg_send;
+
+	res_str->partition_info = (ver_str->partition_info != NULL) ?
+		ver_str->partition_info : res_str->partition_info;
+	res_str->recover = (ver_str->recover != NULL) ?
+		ver_str->recover : res_str->recover;
+
+	return 0;
+}
+
+static int ipclite_register_api(void)
+{
+	int ret = 0, ver_itr = 0;
+
+	/* Register APIs based on the version */
+	for (ver_itr = 0; ver_itr <= minor_ver; ver_itr++) {
+		ret = ipclite_update_version_api(&api_list_t, &api_list_version[ver_itr]);
+		if (ret != 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int ipclite_version_setup(struct device_node *pn)
+{
+	int ret = 0;
+
+	/* Parse the version related DT entries and store the values locally */
+	ret = of_property_read_u32(pn, "major_version", &major_ver);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "failed to parse major_vesion\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(pn, "minor_version", &minor_ver);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "failed to parse minor_vesion\n");
+		return ret;
+	}
+
+	/* Verify IPCLite Version - if version does not match crash the system */
+	BUG_ON(major_ver != MAJOR_VERSION || minor_ver > MINOR_VERSION);
+
+	return ret;
+}
+/* IPCLite Version setup related functions end */
+
+/* Start of IPCLite Init*/
+static int ipclite_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	/* Version Setup */
+	ret = ipclite_version_setup(pdev->dev.of_node);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite Version Setup Failed\n");
+		goto error;
+	}
+
+	/* Register API Setup */
+	ret = ipclite_register_api();
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite API Registration Failed\n");
+		goto error;
+	}
+
+	/* IPCLite Init */
+	ret = ipclite_init(pdev);
+	if (ret != 0) {
+		IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite Init Failed\n");
+		goto error;
+	}
+
+	return ret;
+
 error:
 	IPCLITE_OS_LOG(IPCLITE_ERR, "IPCLite probe failed\n");
 	return ret;

+ 39 - 3
msm/synx/ipclite.h

@@ -10,21 +10,26 @@
 #include <linux/mailbox_controller.h>
 #include "ipclite_client.h"
 
+/* version related entries */
+#define MAJOR_VERSION		1
+#define MINOR_VERSION		0
+
 #define IPCMEM_INIT_COMPLETED	0x1
 #define ACTIVE_CHANNEL			0x1
 
 #define IPCMEM_TOC_SIZE			(4*1024)
 #define IPCMEM_TOC_VAR_OFFSET	0x100
-#define MAX_CHANNEL_SIGNALS		6
 
 #define GLOBAL_ATOMIC_SUPPORT_BMSK 0x1UL
 
+/* IPCC signal info */
 #define IPCLITE_MSG_SIGNAL		0
 #define IPCLITE_MEM_INIT_SIGNAL 1
 #define IPCLITE_VERSION_SIGNAL  2
 #define IPCLITE_TEST_SIGNAL		3
 #define IPCLITE_SSR_SIGNAL		4
 #define IPCLITE_DEBUG_SIGNAL	5
+#define MAX_CHANNEL_SIGNALS		6
 
 /** Flag definitions for the entries */
 #define IPCMEM_FLAGS_ENABLE_READ_PROTECTION   (0x01)
@@ -41,6 +46,11 @@
 /* Timeout (ms) for the trylock of remote spinlocks */
 #define HWSPINLOCK_TIMEOUT	1000
 
+/* queue related entries */
+#define FIFO_FULL_RESERVE		8
+#define FIFO_ALIGNMENT			8
+
+/* debug related entries */
 #define IPCLITE_DEBUG_INFO_SIZE		256
 #define IPCLITE_CORE_DBG_LABEL		"APSS:"
 #define IPCLITE_LOG_MSG_SIZE		100
@@ -51,6 +61,7 @@
 
 #define ADD_OFFSET(x, y)	((void *)((size_t)x + y))
 
+/* IPCLite Logging Mechanism */
 #define IPCLITE_OS_LOG(__level, __fmt, arg...) \
 	do { \
 		if (ipclite_debug_level & __level) { \
@@ -63,8 +74,28 @@
 		} \
 	} while (0)
 
-#define ATOMIC_HW_MUTEX_ACQUIRE (global_atomic_support ?: ipclite_hw_mutex_acquire())
-#define ATOMIC_HW_MUTEX_RELEASE (global_atomic_support ?: ipclite_hw_mutex_release())
+/* IPCLite Debug enable status */
+#define IS_DEBUG_CONFIG(ipclite_debug) (ipclite_debug_control & ipclite_debug)
+
+/* IPCLite Feature enable status */
+#define IS_FEATURE_CONFIG(ipclite_feature) (feature_mask & ipclite_feature)
+
+/* Global Atomic status */
+#define ATOMIC_HW_MUTEX_ACQUIRE \
+(IS_FEATURE_CONFIG(IPCLITE_GLOBAL_ATOMIC) ?: ipclite_hw_mutex_acquire())
+#define ATOMIC_HW_MUTEX_RELEASE \
+(IS_FEATURE_CONFIG(IPCLITE_GLOBAL_ATOMIC) ?: ipclite_hw_mutex_release())
+
+/* API Structure */
+struct ipclite_api_list {
+	int (*init)(struct platform_device *pdev);
+	int32_t (*register_client)(IPCLite_Client cb_func_ptr, void *priv);
+	int32_t (*register_test_client)(IPCLite_Client cb_func_ptr, void *priv);
+	int32_t (*msg_send)(int32_t proc_id, uint64_t data);
+	int32_t (*test_msg_send)(int32_t proc_id, uint64_t data);
+	int32_t (*partition_info)(struct global_region_info *global_ipcmem);
+	void (*recover)(enum ipcmem_host_type core_id);
+} api_list_t;
 
 /**
  * enum ipclite_channel_status - channel status
@@ -79,6 +110,11 @@ enum ipclite_channel_status {
 	ACTIVE					= 2,
 };
 
+enum ipclite_feature_mask {
+	IPCLITE_GLOBAL_ATOMIC = 0x0001ULL,
+	IPCLITE_TEST_SUITE = 0x0002ULL,
+};
+
 enum ipclite_debug_level {
 	IPCLITE_ERR  = 0x0001,
 	IPCLITE_WARN = 0x0002,

+ 4 - 5
msm/synx/synx.c

@@ -694,7 +694,8 @@ void synx_signal_handler(struct work_struct *cb_dispatch)
 		goto fail;
 	}
 
-	if (rc == SYNX_SUCCESS)
+	if (rc == SYNX_SUCCESS && synx_util_get_object_status(synx_obj)
+		!= SYNX_STATE_ACTIVE)
 		rc = synx_native_signal_core(synx_obj, status,
 			(signal_cb->flag & SYNX_SIGNAL_FROM_CALLBACK) ?
 			true : false, signal_cb->ext_sync_id);
@@ -990,8 +991,8 @@ int synx_async_wait(struct synx_session *session,
 				synx_native_signal_fence(synx_obj, status);
 		}
 	}
-	else
-		status = synx_util_get_object_status(synx_obj);
+
+	status = synx_util_get_object_status(synx_obj);
 
 	synx_cb->session = session;
 	synx_cb->idx = idx;
@@ -1374,7 +1375,6 @@ int synx_wait(struct synx_session *session,
 			else
 				synx_native_signal_fence(synx_obj, rc);
 			mutex_unlock(&synx_obj->obj_lock);
-			goto status;
 		}
 	}
 
@@ -1388,7 +1388,6 @@ int synx_wait(struct synx_session *session,
 		goto fail;
 	}
 
-status:
 	mutex_lock(&synx_obj->obj_lock);
 	rc = synx_util_get_object_status(synx_obj);
 	mutex_unlock(&synx_obj->obj_lock);

+ 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",
+    ],
+)