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

Commit 5dbb0750 authored by Chris Lew's avatar Chris Lew
Browse files

soc: qcom: smp2p: Add restart ack feature



Add support for subsystem restart detection. When this feature bit is
set, the remote processor will tell us when it is reinitialized. All
clients registered for falling edge interrupts will be notified when
the smp2p entries are cleared for ssr.

Change-Id: Id82f8b93e83dcd8ad3ed92fdea36f111014ff1e9
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 19901440
Loading
Loading
Loading
Loading
+104 −29
Original line number Diff line number Diff line
@@ -40,8 +40,12 @@
#define SMP2P_MAX_ENTRY_NAME 16

#define SMP2P_FEATURE_SSR_ACK 0x1
#define SMP2P_FLAGS_RESTART_DONE_BIT 0
#define SMP2P_FLAGS_RESTART_ACK_BIT 1

#define SMP2P_MAGIC 0x504d5324
#define SMP2P_VERSION	1
#define SMP2P_FEATURES	SMP2P_FEATURE_SSR_ACK

/**
 * struct smp2p_smem_item - in memory communication structure
@@ -135,6 +139,10 @@ struct qcom_smp2p {

	unsigned valid_entries;

	bool ssr_ack_enabled;
	bool ssr_ack;
	bool open;

	unsigned local_pid;
	unsigned remote_pid;

@@ -163,42 +171,64 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
	}
}

/**
 * qcom_smp2p_intr() - interrupt handler for incoming notifications
 * @irq:	unused
 * @data:	smp2p driver context
 *
 * Handle notifications from the remote side to handle newly allocated entries
 * or any changes to the state bits of existing entries.
 */
static irqreturn_t qcom_smp2p_intr(int irq, void *data)
static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p)
{
	struct smp2p_smem_item *in;
	struct smp2p_entry *entry;
	struct qcom_smp2p *smp2p = data;
	unsigned long status;
	unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND];
	unsigned pid = smp2p->remote_pid;
	size_t size;
	int irq_pin;
	char buf[SMP2P_MAX_ENTRY_NAME];
	struct smp2p_smem_item *in = smp2p->in;
	bool restart;

	if (!smp2p->ssr_ack_enabled)
		return false;

	restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT);
	if (restart == smp2p->ssr_ack)
		return false;

	return true;
}

static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p)
{
	struct smp2p_smem_item *out = smp2p->out;
	u32 ack;
	u32 val;
	int i;

	in = smp2p->in;
	smp2p->ssr_ack = ack = !smp2p->ssr_ack;
	ack = ack << SMP2P_FLAGS_RESTART_ACK_BIT;

	/* Acquire smem item, if not already found */
	if (!in) {
		in = qcom_smem_get(pid, smem_id, &size);
		if (IS_ERR(in)) {
			dev_err(smp2p->dev,
				"Unable to acquire remote smp2p item\n");
			return IRQ_HANDLED;
	val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT);
	val |= ack;
	out->flags = val;

	qcom_smp2p_kick(smp2p);
}

		smp2p->in = in;
static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p)
{
	struct smp2p_smem_item *out = smp2p->out;
	struct smp2p_smem_item *in = smp2p->in;
	u32 features;

	if (in->version == out->version) {
		features = in->features & out->features;
		out->features = features;

		if (features & SMP2P_FEATURE_SSR_ACK)
			smp2p->ssr_ack_enabled = true;

		smp2p->open = true;
	}
}

static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
{
	struct smp2p_smem_item *in = smp2p->in;
	struct smp2p_entry *entry;
	unsigned long status;
	int irq_pin;
	char buf[SMP2P_MAX_ENTRY_NAME];
	u32 val;
	int i;

	/* Match newly created entries */
	for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
		list_for_each_entry(entry, &smp2p->inbound, node) {
@@ -240,6 +270,50 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)
			}
		}
	}
}

/**
 * qcom_smp2p_intr() - interrupt handler for incoming notifications
 * @irq:	unused
 * @data:	smp2p driver context
 *
 * Handle notifications from the remote side to handle newly allocated entries
 * or any changes to the state bits of existing entries.
 */
static irqreturn_t qcom_smp2p_intr(int irq, void *data)
{
	struct smp2p_smem_item *in;
	struct qcom_smp2p *smp2p = data;
	unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND];
	unsigned int pid = smp2p->remote_pid;
	size_t size;

	in = smp2p->in;

	/* Acquire smem item, if not already found */
	if (!in) {
		in = qcom_smem_get(pid, smem_id, &size);
		if (IS_ERR(in)) {
			dev_err(smp2p->dev,
				"Unable to acquire remote smp2p item\n");
			return IRQ_HANDLED;
		}

		smp2p->in = in;
	}

	if (!smp2p->open)
		qcom_smp2p_negotiate(smp2p);

	if (smp2p->open) {
		bool do_restart;

		do_restart = qcom_smp2p_check_ssr(smp2p);
		qcom_smp2p_notify_in(smp2p);

		if (do_restart)
			qcom_smp2p_do_ssr_ack(smp2p);
	}

	return IRQ_HANDLED;
}
@@ -397,13 +471,14 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
	out->remote_pid = smp2p->remote_pid;
	out->total_entries = SMP2P_MAX_ENTRY;
	out->valid_entries = 0;
	out->features = SMP2P_FEATURES;

	/*
	 * Make sure the rest of the header is written before we validate the
	 * item by writing a valid version number.
	 */
	wmb();
	out->version = 1;
	out->version = SMP2P_VERSION;

	qcom_smp2p_kick(smp2p);