summaryrefslogtreecommitdiffstats
path: root/drivers/rpmsg
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2018-02-13 14:04:11 -0500
committerBjorn Andersson <bjorn.andersson@linaro.org>2018-03-19 22:52:17 -0400
commit33e3820dda8876792bd8135db633c741a07263be (patch)
tree263a1d4b53c52ba6860056d00fa6f9d9edb4c570 /drivers/rpmsg
parentbe5acd246daa04edad9d758b8be37e5e2f989243 (diff)
rpmsg: smd: Use spinlock in tx path
By switching the tx_lock to a spinlock we allow clients to use rpmsg_trysend() from atomic context. The mutex was interruptable as it was previously held for the duration of some client waiting for available space in the FIFO, but this was recently changed to only be held temporarily - allowing us to replace it with a spinlock. Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Diffstat (limited to 'drivers/rpmsg')
-rw-r--r--drivers/rpmsg/qcom_smd.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
index ff8101a768bc..76b1c00b4a19 100644
--- a/drivers/rpmsg/qcom_smd.c
+++ b/drivers/rpmsg/qcom_smd.c
@@ -205,7 +205,7 @@ struct qcom_smd_channel {
205 struct smd_channel_info_pair *info; 205 struct smd_channel_info_pair *info;
206 struct smd_channel_info_word_pair *info_word; 206 struct smd_channel_info_word_pair *info_word;
207 207
208 struct mutex tx_lock; 208 spinlock_t tx_lock;
209 wait_queue_head_t fblockread_event; 209 wait_queue_head_t fblockread_event;
210 210
211 void *tx_fifo; 211 void *tx_fifo;
@@ -729,6 +729,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
729{ 729{
730 __le32 hdr[5] = { cpu_to_le32(len), }; 730 __le32 hdr[5] = { cpu_to_le32(len), };
731 int tlen = sizeof(hdr) + len; 731 int tlen = sizeof(hdr) + len;
732 unsigned long flags;
732 int ret; 733 int ret;
733 734
734 /* Word aligned channels only accept word size aligned data */ 735 /* Word aligned channels only accept word size aligned data */
@@ -739,9 +740,11 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
739 if (tlen >= channel->fifo_size) 740 if (tlen >= channel->fifo_size)
740 return -EINVAL; 741 return -EINVAL;
741 742
742 ret = mutex_lock_interruptible(&channel->tx_lock); 743 /* Highlight the fact that if we enter the loop below we might sleep */
743 if (ret) 744 if (wait)
744 return ret; 745 might_sleep();
746
747 spin_lock_irqsave(&channel->tx_lock, flags);
745 748
746 while (qcom_smd_get_tx_avail(channel) < tlen && 749 while (qcom_smd_get_tx_avail(channel) < tlen &&
747 channel->state == SMD_CHANNEL_OPENED) { 750 channel->state == SMD_CHANNEL_OPENED) {
@@ -753,7 +756,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
753 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0); 756 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0);
754 757
755 /* Wait without holding the tx_lock */ 758 /* Wait without holding the tx_lock */
756 mutex_unlock(&channel->tx_lock); 759 spin_unlock_irqrestore(&channel->tx_lock, flags);
757 760
758 ret = wait_event_interruptible(channel->fblockread_event, 761 ret = wait_event_interruptible(channel->fblockread_event,
759 qcom_smd_get_tx_avail(channel) >= tlen || 762 qcom_smd_get_tx_avail(channel) >= tlen ||
@@ -761,9 +764,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
761 if (ret) 764 if (ret)
762 return ret; 765 return ret;
763 766
764 ret = mutex_lock_interruptible(&channel->tx_lock); 767 spin_lock_irqsave(&channel->tx_lock, flags);
765 if (ret)
766 return ret;
767 768
768 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); 769 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
769 } 770 }
@@ -787,7 +788,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data,
787 qcom_smd_signal_channel(channel); 788 qcom_smd_signal_channel(channel);
788 789
789out_unlock: 790out_unlock:
790 mutex_unlock(&channel->tx_lock); 791 spin_unlock_irqrestore(&channel->tx_lock, flags);
791 792
792 return ret; 793 return ret;
793} 794}
@@ -1090,7 +1091,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
1090 if (!channel->name) 1091 if (!channel->name)
1091 return ERR_PTR(-ENOMEM); 1092 return ERR_PTR(-ENOMEM);
1092 1093
1093 mutex_init(&channel->tx_lock); 1094 spin_lock_init(&channel->tx_lock);
1094 spin_lock_init(&channel->recv_lock); 1095 spin_lock_init(&channel->recv_lock);
1095 init_waitqueue_head(&channel->fblockread_event); 1096 init_waitqueue_head(&channel->fblockread_event);
1096 init_waitqueue_head(&channel->state_change_event); 1097 init_waitqueue_head(&channel->state_change_event);