[PATCH] soc: qcom: smd: Simplify multi channel handling

From: Bjorn Andersson
Date: Tue Aug 09 2016 - 20:39:27 EST


Multi-channel clients split between several drivers need a way to close
individual channels, as these drivers might be removed individually.
With this in place the responsibility of closing additionally opened
channels to the client as well only concerning smd about the primary
channel.

With this approach we will only trigger removal of SMD devices based on
the state of the primary channel, however we get in sync with how rpmsg
works.

Signed-off-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>
---

We do not have any drivers in the tree that will suffer from the loss of this.

drivers/soc/qcom/smd.c | 34 ++++++++++++++++------------------
include/linux/soc/qcom/smd.h | 7 +++++++
2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c
index ac1957dfdf24..63e72eb9baa7 100644
--- a/drivers/soc/qcom/smd.c
+++ b/drivers/soc/qcom/smd.c
@@ -197,7 +197,6 @@ struct qcom_smd_channel {
void *drvdata;

struct list_head list;
- struct list_head dev_list;
};

/**
@@ -891,8 +890,6 @@ static int qcom_smd_dev_remove(struct device *dev)
struct qcom_smd_device *qsdev = to_smd_device(dev);
struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
struct qcom_smd_channel *channel = qsdev->channel;
- struct qcom_smd_channel *tmp;
- struct qcom_smd_channel *ch;

qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING);

@@ -911,15 +908,9 @@ static int qcom_smd_dev_remove(struct device *dev)
if (qsdrv->remove)
qsdrv->remove(qsdev);

- /*
- * The client is now gone, close and release all channels associated
- * with this sdev
- */
- list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) {
- qcom_smd_channel_close(ch);
- list_del(&ch->dev_list);
- ch->qsdev = NULL;
- }
+ /* The client is now gone, close the primary channel */
+ qcom_smd_channel_close(channel);
+ channel->qsdev = NULL;

return 0;
}
@@ -1091,6 +1082,8 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
*
* Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
* ready.
+ *
+ * Any channels returned must be closed with a call to qcom_smd_close_channel()
*/
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
const char *name,
@@ -1120,15 +1113,21 @@ struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
return ERR_PTR(ret);
}

- /*
- * Append the list of channel to the channels associated with the sdev
- */
- list_add_tail(&channel->dev_list, &sdev->channel->dev_list);
-
return channel;
}
EXPORT_SYMBOL(qcom_smd_open_channel);

+/**
+ * qcom_smd_close_channel() - close an additionally opened channel
+ * @channel: channel handle, returned by qcom_smd_open_channel()
+ */
+void qcom_smd_close_channel(struct qcom_smd_channel *channel)
+{
+ qcom_smd_channel_close(channel);
+ channel->qsdev = NULL;
+}
+EXPORT_SYMBOL(qcom_smd_close_channel);
+
/*
* Allocate the qcom_smd_channel object for a newly found smd channel,
* retrieving and validating the smem items involved.
@@ -1150,7 +1149,6 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
if (!channel)
return ERR_PTR(-ENOMEM);

- INIT_LIST_HEAD(&channel->dev_list);
channel->edge = edge;
channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL);
if (!channel->name)
diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h
index 910ce1d9ba89..324b1decfffb 100644
--- a/include/linux/soc/qcom/smd.h
+++ b/include/linux/soc/qcom/smd.h
@@ -55,6 +55,7 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
const char *name,
qcom_smd_cb_t cb);
+void qcom_smd_close_channel(struct qcom_smd_channel *channel);
void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
@@ -83,6 +84,12 @@ qcom_smd_open_channel(struct qcom_smd_channel *channel,
return NULL;
}

+static inline void qcom_smd_close_channel(struct qcom_smd_channel *channel)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
{
/* This shouldn't be possible */
--
2.5.0