Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 728d861e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: smp2p: add SSR boot-up handshake"

parents 423a4da6 302029bf
Loading
Loading
Loading
Loading
+45 −4
Original line number Diff line number Diff line
@@ -128,8 +128,10 @@ are currently used and are current valid.
  |                        section.                                           |
   ---------------------------------------------------------------------------
  | Feature      3 Bytes   Refer to Version                                   |
  | flags                  and Feature Negotiation  Must be set to zero.      |
  |                        section.                                           |
  | flags                  and Feature Negotiation                            |
  |                        section for details.                               |
  |   bit 0                SSR_ACK Feature          Supported when set to 1   |
  |   bits 1:31            Reserved                 Must be set to 0.         |
   ---------------------------------------------------------------------------
  | Entries      2 Bytes   Total number of          Must be 0 or greater.     |
  | Total                  entries.                                           |
@@ -137,7 +139,11 @@ are currently used and are current valid.
  | Entries      2 Bytes   Number of valid          Must be between 0         |
  | Valid                  entries.                 and Entries Total.        |
   ---------------------------------------------------------------------------
  | Reserved     4 Bytes   Reserved                 Must be set to 0.         |
  | Flags        4 Bytes                                                      |
  |   bit 0                RESTART_DONE             Toggle for every restart  |
  |   bit 1                RESTART_ACK              Toggle to ACK remote      |
  |                                                 RESTART_DONE              |
  |   bits 2:31            Reserved                 Must be set to 0.         |
   ---------------------------------------------------------------------------
                           Table 1 - SMEM Item Header

@@ -384,7 +390,42 @@ Subsystem Restart
SMP2P is unaffected by SubSystem Restart (SSR) on the high-level OS side and is
actually used as an underlying communication mechanism for SSR.  On the
peripheral system that is being restarted, SMP2P will zero out all existing
state entries upon reboot as part of the SMP2P initialization process.
state entries upon reboot as part of the SMP2P initialization process and if the
SSR_ACK feature is enabled, then it waits for an acknowledgement as outlined in
the following subsections.

SSR_ACK Feature - Reboot Use Case (Non-HLOS Only)
-------------------------------------------------
If a remote system boots up after an SSR and sees that the remote and local
version numbers and feature flags are equal, then it zeros out entry values.  If
the SSR_ACK feature is enabled, it will wait for an acknowledgement from the other
processor that it has seen the zero entry before completing the negotiation
sequence.

    if remote and local version numbers and feature flags are equal
        Zero out all entry values
        if SSR_ACK feature is enabled
            Set local RESTART_DONE flag to inverse of the remote RESTART_ACK
            Send interrupt to remote system
            Wait for interrupt and for remote RESTART_ACK to be equal to local
            RESTART_DONE
    Continue with normal negotiation sequence

Interrupt Use Case
------------------
For every interrupt triggered by a remote change, SMP2P will notify the client
of a change in state.  In addition, if the SSR_ACK feature is enabled, the SSR
handshaking will also be handled.

    if SSR_ACK feature is enabled
        if remote RESTART_DONE != local RESTART_ACK
            Notify client of entry change (will be * -> 0 transition)
            Toggle local RESTART_ACK
            Send interrupt to remote system
        else
            Notify client of entry change as usual
    else
        Notify client of entry change as usual

Debug
=====
+129 −5
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@ struct msm_smp2p_out {
 * @smem_edge_out: Pointer to outbound smem item.
 * @smem_edge_state: State of the outbound edge.
 * @ops_ptr: Pointer to internal version-specific SMEM item access functions.
 *
 * @feature_ssr_ack_enabled: SSR ACK Support Enabled
 * @restart_ack: Current cached state of the local ack bit
 */
struct smp2p_out_list_item {
	spinlock_t out_item_lock_lha1;
@@ -61,6 +64,9 @@ struct smp2p_out_list_item {
	struct smp2p_smem __iomem *smem_edge_out;
	enum msm_smp2p_edge_state smem_edge_state;
	struct smp2p_version_if *ops_ptr;

	bool feature_ssr_ack_enabled;
	bool restart_ack;
};
static struct smp2p_out_list_item out_list[SMP2P_NUM_PROCS];

@@ -115,6 +121,7 @@ static struct smp2p_in_list_item in_list[SMP2P_NUM_PROCS];
 *
 * @is_supported: True if this version is supported by SMP2P
 * @negotiate_features: Returns (sub)set of supported features
 * @negotiation_complete:  Called when negotiation has been completed
 * @find_entry: Finds existing / next empty entry
 * @create_entry: Creates a new entry
 * @read_entry: Reads the value of an entry
@@ -128,6 +135,7 @@ struct smp2p_version_if {
	/* common functions */
	bool is_supported;
	uint32_t (*negotiate_features)(uint32_t features);
	void (*negotiation_complete)(struct smp2p_out_list_item *);
	void (*find_entry)(struct smp2p_smem __iomem *item,
			uint32_t entries_total,	char *name,
			uint32_t **entry_ptr, int *empty_spot);
@@ -148,6 +156,7 @@ static void smp2p_send_interrupt(int remote_pid);

/* v0 (uninitialized SMEM item) interface functions */
static uint32_t smp2p_negotiate_features_v0(uint32_t features);
static void smp2p_negotiation_complete_v0(struct smp2p_out_list_item *out_item);
static void smp2p_find_entry_v0(struct smp2p_smem __iomem *item,
		uint32_t entries_total, char *name, uint32_t **entry_ptr,
		int *empty_spot);
@@ -160,6 +169,7 @@ static struct smp2p_smem __iomem *smp2p_in_validate_size_v0(int remote_pid,

/* v1 interface functions */
static uint32_t smp2p_negotiate_features_v1(uint32_t features);
static void smp2p_negotiation_complete_v1(struct smp2p_out_list_item *out_item);
static void smp2p_find_entry_v1(struct smp2p_smem __iomem *item,
		uint32_t entries_total, char *name, uint32_t **entry_ptr,
		int *empty_spot);
@@ -174,6 +184,7 @@ static struct smp2p_smem __iomem *smp2p_in_validate_size_v1(int remote_pid,
static struct smp2p_version_if version_if[] = {
	[0] = {
		.negotiate_features = smp2p_negotiate_features_v0,
		.negotiation_complete = smp2p_negotiation_complete_v0,
		.find_entry = smp2p_find_entry_v0,
		.create_entry = smp2p_out_create_v0,
		.read_entry = smp2p_out_read_v0,
@@ -184,6 +195,7 @@ static struct smp2p_version_if version_if[] = {
	[1] = {
		.is_supported = true,
		.negotiate_features = smp2p_negotiate_features_v1,
		.negotiation_complete = smp2p_negotiation_complete_v1,
		.find_entry = smp2p_find_entry_v1,
		.create_entry = smp2p_out_create_v1,
		.read_entry = smp2p_out_read_v1,
@@ -399,15 +411,76 @@ static void *smp2p_get_remote_smem_item(int remote_pid,
}

/**
 * smp2p_negotiate_features_v0 - Initial feature negotiation.
 * smp2p_ssr_ack_needed - Returns true if SSR ACK required
 *
 * @rpid: Remote processor ID
 *
 * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
 */
static bool smp2p_ssr_ack_needed(uint32_t rpid)
{
	bool ssr_done;

	if (!out_list[rpid].feature_ssr_ack_enabled)
		return false;

	ssr_done = SMP2P_GET_RESTART_DONE(in_list[rpid].smem_edge_in->flags);
	if (ssr_done != out_list[rpid].restart_ack)
		return true;

	return false;
}

/**
 * smp2p_do_ssr_ack - Handles SSR ACK
 *
 * @rpid: Remote processor ID
 *
 * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
 */
static void smp2p_do_ssr_ack(uint32_t rpid)
{
	bool ack;

	if (!smp2p_ssr_ack_needed(rpid))
		return;

	ack = !out_list[rpid].restart_ack;
	SMP2P_INFO("%s: ssr ack pid %d: %d -> %d\n", __func__, rpid,
			out_list[rpid].restart_ack, ack);
	out_list[rpid].restart_ack = ack;
	SMP2P_SET_RESTART_ACK(out_list[rpid].smem_edge_out->flags, ack);
	smp2p_send_interrupt(rpid);
}

/**
 * smp2p_negotiate_features_v1 - Initial feature negotiation.
 *
 * @features: Inbound feature set.
 * @returns: Supported features (will be a same/subset of @features).
 */
static uint32_t smp2p_negotiate_features_v1(uint32_t features)
{
	/* no supported features */
	return 0;
	return SMP2P_FEATURE_SSR_ACK;
}

/**
 * smp2p_negotiation_complete_v1 - Negotiation completed
 *
 * @out_item:   Pointer to the output item structure
 *
 * Can be used to do final configuration based upon the negotiated feature set.
 *
 * Must be called with out_item_lock_lha1 locked.
 */
static void smp2p_negotiation_complete_v1(struct smp2p_out_list_item *out_item)
{
	uint32_t features;

	features = SMP2P_GET_FEATURES(out_item->smem_edge_out->feature_version);

	if (features & SMP2P_FEATURE_SSR_ACK)
		out_item->feature_ssr_ack_enabled = true;
}

/**
@@ -706,6 +779,20 @@ static uint32_t smp2p_negotiate_features_v0(uint32_t features)
	return 0;
}

/**
 * smp2p_negotiation_complete_v0 - Negotiation completed
 *
 * @out_item:   Pointer to the output item structure
 *
 * Can be used to do final configuration based upon the negotiated feature set.
 */
static void smp2p_negotiation_complete_v0(struct smp2p_out_list_item *out_item)
{
	SMP2P_ERR("%s: invalid negotiation complete for v0 pid %d\n",
		__func__,
		SMP2P_GET_REMOTE_PID(out_item->smem_edge_out->rem_loc_proc_id));
}

/**
 * smp2p_find_entry_v0 - Stub function.
 *
@@ -885,7 +972,7 @@ void smp2p_init_header(struct smp2p_smem __iomem *header_ptr,
	SMP2P_SET_FEATURES(header_ptr->feature_version, features);
	SMP2P_SET_ENT_TOTAL(header_ptr->valid_total_ent, SMP2P_MAX_ENTRY);
	SMP2P_SET_ENT_VALID(header_ptr->valid_total_ent, 0);
	header_ptr->reserved = 0;
	header_ptr->flags = 0;

	/* ensure that all fields are valid before version is written */
	wmb();
@@ -992,8 +1079,9 @@ static int smp2p_do_negotiation(int remote_pid,
		struct msm_smp2p_out *pos;

		/* negotiation complete */
		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
		out_item->ops_ptr = &version_if[l_version];
		out_item->ops_ptr->negotiation_complete(out_item);
		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
		SMP2P_INFO(
			"%s: negotiation complete pid %d: State %d->%d F0x%08x\n",
			__func__, remote_pid, prev_state,
@@ -1528,9 +1616,41 @@ static irqreturn_t smp2p_interrupt_handler(int irq, void *data)
		smp2p_do_negotiation(remote_pid, &out_list[remote_pid]);

	if (out_list[remote_pid].smem_edge_state == SMP2P_EDGE_STATE_OPENED) {
		bool do_restart_ack;

		/*
		 * Follow double-check pattern for restart ack since:
		 * 1) we must notify clients of the X->0 transition
		 *    that is part of the restart
		 * 2) lock cannot be held during the
		 *    smp2p_in_edge_notify() call because clients may do
		 *    re-entrant calls into our APIs.
		 *
		 * smp2p_do_ssr_ack() will only do the ack if it is
		 * necessary to handle the race condition exposed by
		 * unlocking the spinlocks.
		 */
		spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
		do_restart_ack = smp2p_ssr_ack_needed(remote_pid);
		spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
		spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
			flags);

		smp2p_in_edge_notify(remote_pid);

		if (do_restart_ack) {
			spin_lock_irqsave(
				&out_list[remote_pid].out_item_lock_lha1,
				flags);
			spin_lock(&in_list[remote_pid].in_item_lock_lhb1);

			smp2p_do_ssr_ack(remote_pid);

			spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
			spin_unlock_irqrestore(
				&out_list[remote_pid].out_item_lock_lha1,
				flags);
		}
	} else {
		spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
			flags);
@@ -1565,6 +1685,8 @@ int smp2p_reset_mock_edge(void)
	out_list[rpid].smem_edge_out = NULL;
	out_list[rpid].ops_ptr = &version_if[0];
	out_list[rpid].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
	out_list[rpid].feature_ssr_ack_enabled = false;
	out_list[rpid].restart_ack = false;

	in_list[rpid].smem_edge_in = NULL;
	in_list[rpid].item_size = 0;
@@ -1699,6 +1821,8 @@ static int __init msm_smp2p_init(void)
		out_list[i].smem_edge_out = NULL;
		out_list[i].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
		out_list[i].ops_ptr = &version_if[0];
		out_list[i].feature_ssr_ack_enabled = false;
		out_list[i].restart_ack = false;

		spin_lock_init(&in_list[i].in_item_lock_lhb1);
		INIT_LIST_HEAD(&in_list[i].list);
+4 −2
Original line number Diff line number Diff line
@@ -141,9 +141,11 @@ static int smp2p_item_header3(char *buf, int max, struct smp2p_smem *item_ptr)
	}

	i += scnprintf(buf + i, max - i,
		"Entries Valid/Max: %d/%d",
		"Entries #/Max: %d/%d Flags: %c%c",
		SMP2P_GET_ENT_VALID(item_ptr->valid_total_ent),
		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent)
		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent),
		item_ptr->flags & SMP2P_FLAGS_RESTART_ACK_MASK ? 'A' : 'a',
		item_ptr->flags & SMP2P_FLAGS_RESTART_DONE_MASK ? 'D' : 'd'
		);

	return i;
+29 −3
Original line number Diff line number Diff line
@@ -20,8 +20,7 @@
#include "smp2p_private_api.h"

#define SMP2P_MAX_ENTRY 16
#define SMP2P_LOCAL_VERSION 1
#define SMP2P_LOCAL_FEATURE  0x0
#define SMP2P_FEATURE_SSR_ACK 0x1

/* SMEM Item Header Macros */
#define SMP2P_MAGIC 0x504D5324
@@ -37,6 +36,10 @@
#define SMP2P_ENT_TOTAL_BIT 0
#define SMP2P_ENT_VALID_MASK 0xffff0000
#define SMP2P_ENT_VALID_BIT 16
#define SMP2P_FLAGS_RESTART_DONE_BIT 0
#define SMP2P_FLAGS_RESTART_DONE_MASK 0x1
#define SMP2P_FLAGS_RESTART_ACK_BIT 1
#define SMP2P_FLAGS_RESTART_ACK_MASK 0x2

#define SMP2P_GET_BITS(hdr_val, mask, bit) \
	(((hdr_val) & (mask)) >> (bit))
@@ -77,6 +80,20 @@
	SMP2P_SET_BITS(hdr,  SMP2P_ENT_VALID_MASK, SMP2P_ENT_VALID_BIT,\
		entries)

#define SMP2P_GET_RESTART_DONE(hdr) \
	SMP2P_GET_BITS(hdr, SMP2P_FLAGS_RESTART_DONE_MASK, \
			SMP2P_FLAGS_RESTART_DONE_BIT)
#define SMP2P_SET_RESTART_DONE(hdr, value) \
	SMP2P_SET_BITS(hdr, SMP2P_FLAGS_RESTART_DONE_MASK, \
			SMP2P_FLAGS_RESTART_DONE_BIT, value)

#define SMP2P_GET_RESTART_ACK(hdr) \
	SMP2P_GET_BITS(hdr, SMP2P_FLAGS_RESTART_ACK_MASK, \
			SMP2P_FLAGS_RESTART_ACK_BIT)
#define SMP2P_SET_RESTART_ACK(hdr, value) \
	SMP2P_SET_BITS(hdr, SMP2P_FLAGS_RESTART_ACK_MASK, \
			SMP2P_FLAGS_RESTART_ACK_BIT, value)

/* Loopback Command Macros */
#define SMP2P_RMT_CMD_TYPE_MASK 0x80000000
#define SMP2P_RMT_CMD_TYPE_BIT 31
@@ -162,12 +179,21 @@ enum msm_smp2p_edge_state {
	SMP2P_EDGE_STATE_FAILED = 0xff,
};

/**
 * struct smp2p_smem - SMP2P SMEM Item Header
 *
 * @magic:  Set to "$SMP" -- used for identification / debug purposes
 * @feature_version:  Feature and version fields
 * @rem_loc_proc_id:  Remote (31:16) and Local (15:0) processor IDs
 * @valid_total_ent:  Valid (31:16) and total (15:0) entries
 * @flags:  Flags (bits 31:2 reserved)
 */
struct smp2p_smem {
	uint32_t magic;
	uint32_t feature_version;
	uint32_t rem_loc_proc_id;
	uint32_t valid_total_ent;
	uint32_t reserved;
	uint32_t flags;
};

struct smp2p_entry_v1 {
+222 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <mach/subsystem_restart.h>
#include "smp2p_private.h"
#include "smp2p_test_common.h"

@@ -77,7 +78,7 @@ static void smp2p_ut_local_basic(struct seq_file *s)
		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(
		rmp->remote_item.header.valid_total_ent, 0);
		rmp->remote_item.header.reserved = 0x0;
		rmp->remote_item.header.flags = 0x0;
		msm_smp2p_set_remote_mock_exists(true);
		rmp->tx_interrupt();

@@ -161,7 +162,7 @@ static void smp2p_ut_local_late_open(struct seq_file *s)
			SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(
		rmp->remote_item.header.valid_total_ent, 0);
		rmp->remote_item.header.reserved = 0x0;
		rmp->remote_item.header.flags = 0x0;

		msm_smp2p_set_remote_mock_exists(true);

@@ -251,7 +252,7 @@ static void smp2p_ut_local_early_open(struct seq_file *s)
		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(
		rmp->remote_item.header.valid_total_ent, 0);
		rmp->remote_item.header.reserved = 0x0;
		rmp->remote_item.header.flags = 0x0;

		msm_smp2p_set_remote_mock_exists(false);
		UT_ASSERT_PTR(NULL, ==,
@@ -369,7 +370,7 @@ static void smp2p_ut_mock_loopback(struct seq_file *s)
		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(
		rmp->remote_item.header.valid_total_ent, 1);
		rmp->remote_item.header.reserved = 0x0;
		rmp->remote_item.header.flags = 0x0;
		msm_smp2p_set_remote_mock_exists(true);

		/* Create test entry and attach loopback server */
@@ -794,7 +795,7 @@ static void smp2p_ut_local_in_max_entries(struct seq_file *s)
		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(
		rmp->remote_item.header.valid_total_ent, 0);
		rmp->remote_item.header.reserved = 0x0;
		rmp->remote_item.header.flags = 0x0;
		msm_smp2p_set_remote_mock_exists(true);

		/* Create Max Entries in the remote mock object */
@@ -892,7 +893,7 @@ static void smp2p_ut_local_in_multiple(struct seq_file *s)
		rmp->remote_item.header.valid_total_ent, 1);
		SMP2P_SET_ENT_VALID(
		rmp->remote_item.header.valid_total_ent, 0);
		rmp->remote_item.header.reserved = 0x0;
		rmp->remote_item.header.flags = 0x0;
		msm_smp2p_set_remote_mock_exists(true);

		/* Create an Entry in the remote mock object */
@@ -953,6 +954,217 @@ static void smp2p_ut_local_in_multiple(struct seq_file *s)
	}
}

/**
 * smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
 *
 * @s: pointer to output file
 */
static void smp2p_ut_local_ssr_ack(struct seq_file *s)
{
	int failed = 0;
	struct msm_smp2p_remote_mock *rmp = NULL;
	int ret;

	seq_printf(s, "Running %s\n", __func__);
	do {
		struct smp2p_smem *rhdr;
		struct smp2p_smem *lhdr;
		int negotiation_state;

		/* initialize v1 without SMP2P_FEATURE_SSR_ACK enabled */
		ret = smp2p_reset_mock_edge();
		UT_ASSERT_INT(ret, ==, 0);
		rmp = msm_smp2p_get_remote_mock();
		UT_ASSERT_PTR(rmp, !=, NULL);
		rhdr = &rmp->remote_item.header;

		rmp->rx_interrupt_count = 0;
		memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
		rhdr->magic = SMP2P_MAGIC;
		SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
				SMP2P_REMOTE_MOCK_PROC);
		SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
		SMP2P_SET_VERSION(rhdr->feature_version, 1);
		SMP2P_SET_FEATURES(rhdr->feature_version, 0);
		SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
		rhdr->flags = 0x0;
		msm_smp2p_set_remote_mock_exists(true);
		rmp->tx_interrupt();

		/* verify edge is open */
		lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
					&negotiation_state);
		UT_ASSERT_PTR(NULL, !=, lhdr);
		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);

		/* verify no response to ack feature */
		rmp->rx_interrupt_count = 0;
		SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
		rmp->tx_interrupt();
		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 0);

		/* initialize v1 with SMP2P_FEATURE_SSR_ACK enabled */
		ret = smp2p_reset_mock_edge();
		UT_ASSERT_INT(ret, ==, 0);
		rmp = msm_smp2p_get_remote_mock();
		UT_ASSERT_PTR(rmp, !=, NULL);
		rhdr = &rmp->remote_item.header;

		rmp->rx_interrupt_count = 0;
		memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
		rhdr->magic = SMP2P_MAGIC;
		SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
				SMP2P_REMOTE_MOCK_PROC);
		SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
		SMP2P_SET_VERSION(rhdr->feature_version, 1);
		SMP2P_SET_FEATURES(rhdr->feature_version,
				SMP2P_FEATURE_SSR_ACK);
		SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
		SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
		rmp->rx_interrupt_count = 0;
		rhdr->flags = 0x0;
		msm_smp2p_set_remote_mock_exists(true);
		rmp->tx_interrupt();

		/* verify edge is open */
		lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
					&negotiation_state);
		UT_ASSERT_PTR(NULL, !=, lhdr);
		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);

		/* verify response to ack feature */
		rmp->rx_interrupt_count = 0;
		SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
		rmp->tx_interrupt();
		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
		UT_ASSERT_INT(1, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);

		rmp->rx_interrupt_count = 0;
		SMP2P_SET_RESTART_DONE(rhdr->flags, 0);
		rmp->tx_interrupt();
		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);

		seq_puts(s, "\tOK\n");
	} while (0);

	if (failed) {
		pr_err("%s: Failed\n", __func__);
		seq_puts(s, "\tFailed\n");
	}
}

/**
 * smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
 *
 * @s: pointer to output file
 * @rpid: Remote processor ID
 * @int_cfg: Interrupt config
 */
static void smp2p_ut_remotesubsys_ssr_ack(struct seq_file *s, uint32_t rpid,
		struct smp2p_interrupt_config *int_cfg)
{
	int failed = 0;

	seq_printf(s, "Running %s\n", __func__);
	do {
		struct smp2p_smem *rhdr;
		struct smp2p_smem *lhdr;
		int negotiation_state;
		bool ssr_ack_enabled;
		uint32_t ssr_done_start;

		lhdr = smp2p_get_out_item(rpid, &negotiation_state);
		UT_ASSERT_PTR(NULL, !=, lhdr);
		UT_ASSERT_INT(SMP2P_EDGE_STATE_OPENED, ==, negotiation_state);

		rhdr = smp2p_get_in_item(rpid);
		UT_ASSERT_PTR(NULL, !=, rhdr);

		/* get initial state of SSR flags */
		if (SMP2P_GET_FEATURES(rhdr->feature_version)
				& SMP2P_FEATURE_SSR_ACK)
			ssr_ack_enabled = true;
		else
			ssr_ack_enabled = false;

		ssr_done_start = SMP2P_GET_RESTART_DONE(rhdr->flags);
		UT_ASSERT_INT(ssr_done_start, ==,
				SMP2P_GET_RESTART_ACK(lhdr->flags));

		/* trigger restart */
		seq_printf(s, "Restarting '%s'\n", int_cfg->name);
		subsystem_restart(int_cfg->name);
		msleep(10*1000);

		/* verify ack signaling */
		if (ssr_ack_enabled) {
			ssr_done_start ^= 1;
			UT_ASSERT_INT(ssr_done_start, ==,
					SMP2P_GET_RESTART_ACK(lhdr->flags));
			UT_ASSERT_INT(ssr_done_start, ==,
					SMP2P_GET_RESTART_DONE(rhdr->flags));
			UT_ASSERT_INT(0, ==,
					SMP2P_GET_RESTART_DONE(lhdr->flags));
			seq_puts(s, "\tSSR ACK Enabled and Toggled\n");
		} else {
			UT_ASSERT_INT(0, ==,
					SMP2P_GET_RESTART_DONE(lhdr->flags));
			UT_ASSERT_INT(0, ==,
					SMP2P_GET_RESTART_ACK(lhdr->flags));

			UT_ASSERT_INT(0, ==,
					SMP2P_GET_RESTART_DONE(rhdr->flags));
			UT_ASSERT_INT(0, ==,
					SMP2P_GET_RESTART_ACK(rhdr->flags));
			seq_puts(s, "\tSSR ACK Disabled\n");
		}

		seq_puts(s, "\tOK\n");
	} while (0);

	if (failed) {
		pr_err("%s: Failed\n", __func__);
		seq_puts(s, "\tFailed\n");
	}
}

/**
 * smp2p_ut_remote_ssr_ack - Verify SSR Done/ACK Feature
 *
 * @s: pointer to output file
 *
 * Triggers SSR for each subsystem.
 */
static void smp2p_ut_remote_ssr_ack(struct seq_file *s)
{
	struct smp2p_interrupt_config *int_cfg;
	int pid;

	int_cfg = smp2p_get_interrupt_config();
	if (!int_cfg) {
		seq_puts(s,
			"Remote processor config unavailable\n");
		return;
	}

	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
		if (!int_cfg[pid].is_configured)
			continue;

		msm_smp2p_deinit_rmt_lpb_proc(pid);
		smp2p_ut_remotesubsys_ssr_ack(s, pid, &int_cfg[pid]);
		msm_smp2p_init_rmt_lpb_proc(pid);
	}
}

static struct dentry *dent;

static int debugfs_show(struct seq_file *s, void *data)
@@ -1019,6 +1231,10 @@ static int __init smp2p_debugfs_init(void)
			smp2p_ut_remote_out_max_entries);
	smp2p_debug_create("ut_local_in_multiple",
			smp2p_ut_local_in_multiple);
	smp2p_debug_create("ut_local_ssr_ack",
			smp2p_ut_local_ssr_ack);
	smp2p_debug_create("ut_remote_ssr_ack",
			smp2p_ut_remote_ssr_ack);

	return 0;
}