aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2016-08-09 20:39:19 -0400
committerAndy Gross <andy.gross@linaro.org>2016-08-23 16:46:32 -0400
commit0a0c08cae01b33b29abd24608d3800986546f0af (patch)
treec047938279e11f342f97c99cac844216284ce682
parent3a1281848830fcb3202cfd7ffe62d19641471d05 (diff)
soc: qcom: smd: Simplify multi channel handling
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@linaro.org> Signed-off-by: Andy Gross <andy.gross@linaro.org>
-rw-r--r--drivers/soc/qcom/smd.c34
-rw-r--r--include/linux/soc/qcom/smd.h7
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 {
197 void *drvdata; 197 void *drvdata;
198 198
199 struct list_head list; 199 struct list_head list;
200 struct list_head dev_list;
201}; 200};
202 201
203/** 202/**
@@ -891,8 +890,6 @@ static int qcom_smd_dev_remove(struct device *dev)
891 struct qcom_smd_device *qsdev = to_smd_device(dev); 890 struct qcom_smd_device *qsdev = to_smd_device(dev);
892 struct qcom_smd_driver *qsdrv = to_smd_driver(dev); 891 struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
893 struct qcom_smd_channel *channel = qsdev->channel; 892 struct qcom_smd_channel *channel = qsdev->channel;
894 struct qcom_smd_channel *tmp;
895 struct qcom_smd_channel *ch;
896 893
897 qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING); 894 qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING);
898 895
@@ -911,15 +908,9 @@ static int qcom_smd_dev_remove(struct device *dev)
911 if (qsdrv->remove) 908 if (qsdrv->remove)
912 qsdrv->remove(qsdev); 909 qsdrv->remove(qsdev);
913 910
914 /* 911 /* The client is now gone, close the primary channel */
915 * The client is now gone, close and release all channels associated 912 qcom_smd_channel_close(channel);
916 * with this sdev 913 channel->qsdev = NULL;
917 */
918 list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) {
919 qcom_smd_channel_close(ch);
920 list_del(&ch->dev_list);
921 ch->qsdev = NULL;
922 }
923 914
924 return 0; 915 return 0;
925} 916}
@@ -1091,6 +1082,8 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
1091 * 1082 *
1092 * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't 1083 * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
1093 * ready. 1084 * ready.
1085 *
1086 * Any channels returned must be closed with a call to qcom_smd_close_channel()
1094 */ 1087 */
1095struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent, 1088struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
1096 const char *name, 1089 const char *name,
@@ -1120,15 +1113,21 @@ struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
1120 return ERR_PTR(ret); 1113 return ERR_PTR(ret);
1121 } 1114 }
1122 1115
1123 /*
1124 * Append the list of channel to the channels associated with the sdev
1125 */
1126 list_add_tail(&channel->dev_list, &sdev->channel->dev_list);
1127
1128 return channel; 1116 return channel;
1129} 1117}
1130EXPORT_SYMBOL(qcom_smd_open_channel); 1118EXPORT_SYMBOL(qcom_smd_open_channel);
1131 1119
1120/**
1121 * qcom_smd_close_channel() - close an additionally opened channel
1122 * @channel: channel handle, returned by qcom_smd_open_channel()
1123 */
1124void qcom_smd_close_channel(struct qcom_smd_channel *channel)
1125{
1126 qcom_smd_channel_close(channel);
1127 channel->qsdev = NULL;
1128}
1129EXPORT_SYMBOL(qcom_smd_close_channel);
1130
1132/* 1131/*
1133 * Allocate the qcom_smd_channel object for a newly found smd channel, 1132 * Allocate the qcom_smd_channel object for a newly found smd channel,
1134 * retrieving and validating the smem items involved. 1133 * 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
1150 if (!channel) 1149 if (!channel)
1151 return ERR_PTR(-ENOMEM); 1150 return ERR_PTR(-ENOMEM);
1152 1151
1153 INIT_LIST_HEAD(&channel->dev_list);
1154 channel->edge = edge; 1152 channel->edge = edge;
1155 channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL); 1153 channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL);
1156 if (!channel->name) 1154 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);
55struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel, 55struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
56 const char *name, 56 const char *name,
57 qcom_smd_cb_t cb); 57 qcom_smd_cb_t cb);
58void qcom_smd_close_channel(struct qcom_smd_channel *channel);
58void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel); 59void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
59void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data); 60void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
60int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); 61int 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,
83 return NULL; 84 return NULL;
84} 85}
85 86
87static inline void qcom_smd_close_channel(struct qcom_smd_channel *channel)
88{
89 /* This shouldn't be possible */
90 WARN_ON(1);
91}
92
86static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel) 93static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
87{ 94{
88 /* This shouldn't be possible */ 95 /* This shouldn't be possible */