lkml.org 
[lkml]   [2021]   [Sep]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 1/1] soc: qcom: smp2p: add feature negotiation and ssr ack feature support
Date
This patch adds feature negotiation and ssr ack feature between
local and remote host. Local host can negotiate on common features
supported with remote host.
---
drivers/soc/qcom/smp2p.c | 151 ++++++++++++++++++++++++++++++++---------------
1 file changed, 104 insertions(+), 47 deletions(-)

diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
index 38585a7..1c6ad1c 100644
--- a/drivers/soc/qcom/smp2p.c
+++ b/drivers/soc/qcom/smp2p.c
@@ -14,7 +14,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
@@ -41,8 +40,11 @@
#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_FEATURES SMP2P_FEATURE_SSR_ACK

/**
* struct smp2p_smem_item - in memory communication structure
@@ -113,7 +115,6 @@ struct smp2p_entry {
* struct qcom_smp2p - device driver context
* @dev: device driver handle
* @in: pointer to the inbound smem item
- * @out: pointer to the outbound smem item
* @smem_items: ids of the two smem items
* @valid_entries: already scanned inbound entries
* @local_pid: processor id of the inbound edge
@@ -136,6 +137,10 @@ struct qcom_smp2p {

unsigned valid_entries;

+ bool ssr_ack_enabled;
+ bool ssr_ack;
+ bool open;
+
unsigned local_pid;
unsigned remote_pid;

@@ -163,22 +168,59 @@ 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 = 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;
+
+ ack = !smp2p->ssr_ack;
+ smp2p->ssr_ack = ack;
+ ack = ack << SMP2P_FLAGS_RESTART_ACK_BIT;
+
+ val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT);
+ val |= ack;
+ out->flags = val;
+
+ qcom_smp2p_kick(smp2p);
+}
+
+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;
struct smp2p_entry *entry;
- struct qcom_smp2p *smp2p = data;
- unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND];
- unsigned pid = smp2p->remote_pid;
- size_t size;
int irq_pin;
u32 status;
char buf[SMP2P_MAX_ENTRY_NAME];
@@ -187,18 +229,6 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)

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;
- }
-
/* Match newly created entries */
for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
list_for_each_entry(entry, &smp2p->inbound, node) {
@@ -210,7 +240,7 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)
}
}
smp2p->valid_entries = i;
-
+
/* Fire interrupts based on any value changes */
list_for_each_entry(entry, &smp2p->inbound, node) {
/* Ignore entries not yet allocated by the remote side */
@@ -237,7 +267,52 @@ 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");
+ goto out;
+ }
+
+ 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);
+ }
+
+out:
return IRQ_HANDLED;
}

@@ -393,6 +468,7 @@ 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
@@ -539,26 +615,9 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
goto unwind_interfaces;
}

- /*
- * Treat smp2p interrupt as wakeup source, but keep it disabled
- * by default. User space can decide enabling it depending on its
- * use cases. For example if remoteproc crashes and device wants
- * to handle it immediatedly (e.g. to not miss phone calls) it can
- * enable wakeup source from user space, while other devices which
- * do not have proper autosleep feature may want to handle it with
- * other wakeup events (e.g. Power button) instead waking up immediately.
- */
- device_set_wakeup_capable(&pdev->dev, true);
-
- ret = dev_pm_set_wake_irq(&pdev->dev, irq);
- if (ret)
- goto set_wake_irq_fail;

return 0;

-set_wake_irq_fail:
- dev_pm_clear_wake_irq(&pdev->dev);
-
unwind_interfaces:
list_for_each_entry(entry, &smp2p->inbound, node)
irq_domain_remove(entry->domain);
@@ -583,8 +642,6 @@ static int qcom_smp2p_remove(struct platform_device *pdev)
struct qcom_smp2p *smp2p = platform_get_drvdata(pdev);
struct smp2p_entry *entry;

- dev_pm_clear_wake_irq(&pdev->dev);
-
list_for_each_entry(entry, &smp2p->inbound, node)
irq_domain_remove(entry->domain);

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
\
 
 \ /
  Last update: 2021-09-30 17:33    [W:0.150 / U:1.496 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site