diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-05 13:05:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-05 13:05:40 -0500 |
commit | 67fb3b92b0f92a161e25370d437ae4ba08089e75 (patch) | |
tree | b48d6720d4af5e0282af9d1ecb404909515c7fc5 /drivers/rpmsg | |
parent | ae77c9583f424d8af0caf635a83dd0c267cb1052 (diff) | |
parent | c3388a075c8ac568f892c40bec919ba8ac4077f0 (diff) |
Merge tag 'rpmsg-v4.16' of git://github.com/andersson/remoteproc
Pull rpmsg updates from Bjorn Andersson:
"This fixes a few issues found in the SMD and GLINK drivers and
corrects the handling of SMD channels that are found in an
(previously) unexpected state"
* tag 'rpmsg-v4.16' of git://github.com/andersson/remoteproc:
rpmsg: smd: Fix double unlock in __qcom_smd_send()
rpmsg: glink: Fix missing mutex_init() in qcom_glink_alloc_channel()
rpmsg: smd: Don't hold the tx lock during wait
rpmsg: smd: Fail send on a closed channel
rpmsg: smd: Wake up all waiters
rpmsg: smd: Create device for all channels
rpmsg: smd: Perform handshake during open
rpmsg: glink: smem: Ensure ordering during tx
drivers: rpmsg: remove duplicate includes
remoteproc: qcom: Use PTR_ERR_OR_ZERO() in glink prob
Diffstat (limited to 'drivers/rpmsg')
-rw-r--r-- | drivers/rpmsg/qcom_glink_native.c | 1 | ||||
-rw-r--r-- | drivers/rpmsg/qcom_glink_smem.c | 5 | ||||
-rw-r--r-- | drivers/rpmsg/qcom_smd.c | 66 |
3 files changed, 54 insertions, 18 deletions
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 40d76d2a5eff..e0f31ed096a5 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c | |||
@@ -221,6 +221,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, | |||
221 | /* Setup glink internal glink_channel data */ | 221 | /* Setup glink internal glink_channel data */ |
222 | spin_lock_init(&channel->recv_lock); | 222 | spin_lock_init(&channel->recv_lock); |
223 | spin_lock_init(&channel->intent_lock); | 223 | spin_lock_init(&channel->intent_lock); |
224 | mutex_init(&channel->intent_req_lock); | ||
224 | 225 | ||
225 | channel->glink = glink; | 226 | channel->glink = glink; |
226 | channel->name = kstrdup(name, GFP_KERNEL); | 227 | channel->name = kstrdup(name, GFP_KERNEL); |
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 5cdaa5f8fb61..892f2b92a4d8 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c | |||
@@ -29,8 +29,6 @@ | |||
29 | #include <linux/workqueue.h> | 29 | #include <linux/workqueue.h> |
30 | #include <linux/list.h> | 30 | #include <linux/list.h> |
31 | 31 | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/rpmsg.h> | ||
34 | #include <linux/rpmsg/qcom_glink.h> | 32 | #include <linux/rpmsg/qcom_glink.h> |
35 | 33 | ||
36 | #include "qcom_glink_native.h" | 34 | #include "qcom_glink_native.h" |
@@ -185,6 +183,9 @@ static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe, | |||
185 | if (head >= pipe->native.length) | 183 | if (head >= pipe->native.length) |
186 | head -= pipe->native.length; | 184 | head -= pipe->native.length; |
187 | 185 | ||
186 | /* Ensure ordering of fifo and head update */ | ||
187 | wmb(); | ||
188 | |||
188 | *pipe->head = cpu_to_le32(head); | 189 | *pipe->head = cpu_to_le32(head); |
189 | } | 190 | } |
190 | 191 | ||
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index e540ca362d08..8428eba8cb73 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c | |||
@@ -200,6 +200,7 @@ struct qcom_smd_channel { | |||
200 | char *name; | 200 | char *name; |
201 | enum smd_channel_state state; | 201 | enum smd_channel_state state; |
202 | enum smd_channel_state remote_state; | 202 | enum smd_channel_state remote_state; |
203 | wait_queue_head_t state_change_event; | ||
203 | 204 | ||
204 | struct smd_channel_info_pair *info; | 205 | struct smd_channel_info_pair *info; |
205 | struct smd_channel_info_word_pair *info_word; | 206 | struct smd_channel_info_word_pair *info_word; |
@@ -570,13 +571,15 @@ static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel) | |||
570 | if (remote_state != channel->remote_state) { | 571 | if (remote_state != channel->remote_state) { |
571 | channel->remote_state = remote_state; | 572 | channel->remote_state = remote_state; |
572 | need_state_scan = true; | 573 | need_state_scan = true; |
574 | |||
575 | wake_up_interruptible_all(&channel->state_change_event); | ||
573 | } | 576 | } |
574 | /* Indicate that we have seen any state change */ | 577 | /* Indicate that we have seen any state change */ |
575 | SET_RX_CHANNEL_FLAG(channel, fSTATE, 0); | 578 | SET_RX_CHANNEL_FLAG(channel, fSTATE, 0); |
576 | 579 | ||
577 | /* Signal waiting qcom_smd_send() about the interrupt */ | 580 | /* Signal waiting qcom_smd_send() about the interrupt */ |
578 | if (!GET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) | 581 | if (!GET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) |
579 | wake_up_interruptible(&channel->fblockread_event); | 582 | wake_up_interruptible_all(&channel->fblockread_event); |
580 | 583 | ||
581 | /* Don't consume any data until we've opened the channel */ | 584 | /* Don't consume any data until we've opened the channel */ |
582 | if (channel->state != SMD_CHANNEL_OPENED) | 585 | if (channel->state != SMD_CHANNEL_OPENED) |
@@ -740,28 +743,37 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, | |||
740 | if (ret) | 743 | if (ret) |
741 | return ret; | 744 | return ret; |
742 | 745 | ||
743 | while (qcom_smd_get_tx_avail(channel) < tlen) { | 746 | while (qcom_smd_get_tx_avail(channel) < tlen && |
747 | channel->state == SMD_CHANNEL_OPENED) { | ||
744 | if (!wait) { | 748 | if (!wait) { |
745 | ret = -EAGAIN; | 749 | ret = -EAGAIN; |
746 | goto out; | 750 | goto out_unlock; |
747 | } | ||
748 | |||
749 | if (channel->state != SMD_CHANNEL_OPENED) { | ||
750 | ret = -EPIPE; | ||
751 | goto out; | ||
752 | } | 751 | } |
753 | 752 | ||
754 | SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0); | 753 | SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0); |
755 | 754 | ||
755 | /* Wait without holding the tx_lock */ | ||
756 | mutex_unlock(&channel->tx_lock); | ||
757 | |||
756 | ret = wait_event_interruptible(channel->fblockread_event, | 758 | ret = wait_event_interruptible(channel->fblockread_event, |
757 | qcom_smd_get_tx_avail(channel) >= tlen || | 759 | qcom_smd_get_tx_avail(channel) >= tlen || |
758 | channel->state != SMD_CHANNEL_OPENED); | 760 | channel->state != SMD_CHANNEL_OPENED); |
759 | if (ret) | 761 | if (ret) |
760 | goto out; | 762 | return ret; |
763 | |||
764 | ret = mutex_lock_interruptible(&channel->tx_lock); | ||
765 | if (ret) | ||
766 | return ret; | ||
761 | 767 | ||
762 | SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); | 768 | SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); |
763 | } | 769 | } |
764 | 770 | ||
771 | /* Fail if the channel was closed */ | ||
772 | if (channel->state != SMD_CHANNEL_OPENED) { | ||
773 | ret = -EPIPE; | ||
774 | goto out_unlock; | ||
775 | } | ||
776 | |||
765 | SET_TX_CHANNEL_FLAG(channel, fTAIL, 0); | 777 | SET_TX_CHANNEL_FLAG(channel, fTAIL, 0); |
766 | 778 | ||
767 | qcom_smd_write_fifo(channel, hdr, sizeof(hdr)); | 779 | qcom_smd_write_fifo(channel, hdr, sizeof(hdr)); |
@@ -774,7 +786,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, | |||
774 | 786 | ||
775 | qcom_smd_signal_channel(channel); | 787 | qcom_smd_signal_channel(channel); |
776 | 788 | ||
777 | out: | 789 | out_unlock: |
778 | mutex_unlock(&channel->tx_lock); | 790 | mutex_unlock(&channel->tx_lock); |
779 | 791 | ||
780 | return ret; | 792 | return ret; |
@@ -786,7 +798,9 @@ out: | |||
786 | static int qcom_smd_channel_open(struct qcom_smd_channel *channel, | 798 | static int qcom_smd_channel_open(struct qcom_smd_channel *channel, |
787 | rpmsg_rx_cb_t cb) | 799 | rpmsg_rx_cb_t cb) |
788 | { | 800 | { |
801 | struct qcom_smd_edge *edge = channel->edge; | ||
789 | size_t bb_size; | 802 | size_t bb_size; |
803 | int ret; | ||
790 | 804 | ||
791 | /* | 805 | /* |
792 | * Packets are maximum 4k, but reduce if the fifo is smaller | 806 | * Packets are maximum 4k, but reduce if the fifo is smaller |
@@ -798,9 +812,33 @@ static int qcom_smd_channel_open(struct qcom_smd_channel *channel, | |||
798 | 812 | ||
799 | qcom_smd_channel_set_callback(channel, cb); | 813 | qcom_smd_channel_set_callback(channel, cb); |
800 | qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING); | 814 | qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING); |
815 | |||
816 | /* Wait for remote to enter opening or opened */ | ||
817 | ret = wait_event_interruptible_timeout(channel->state_change_event, | ||
818 | channel->remote_state == SMD_CHANNEL_OPENING || | ||
819 | channel->remote_state == SMD_CHANNEL_OPENED, | ||
820 | HZ); | ||
821 | if (!ret) { | ||
822 | dev_err(&edge->dev, "remote side did not enter opening state\n"); | ||
823 | goto out_close_timeout; | ||
824 | } | ||
825 | |||
801 | qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED); | 826 | qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED); |
802 | 827 | ||
828 | /* Wait for remote to enter opened */ | ||
829 | ret = wait_event_interruptible_timeout(channel->state_change_event, | ||
830 | channel->remote_state == SMD_CHANNEL_OPENED, | ||
831 | HZ); | ||
832 | if (!ret) { | ||
833 | dev_err(&edge->dev, "remote side did not enter open state\n"); | ||
834 | goto out_close_timeout; | ||
835 | } | ||
836 | |||
803 | return 0; | 837 | return 0; |
838 | |||
839 | out_close_timeout: | ||
840 | qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED); | ||
841 | return -ETIMEDOUT; | ||
804 | } | 842 | } |
805 | 843 | ||
806 | /* | 844 | /* |
@@ -1055,6 +1093,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed | |||
1055 | mutex_init(&channel->tx_lock); | 1093 | mutex_init(&channel->tx_lock); |
1056 | spin_lock_init(&channel->recv_lock); | 1094 | spin_lock_init(&channel->recv_lock); |
1057 | init_waitqueue_head(&channel->fblockread_event); | 1095 | init_waitqueue_head(&channel->fblockread_event); |
1096 | init_waitqueue_head(&channel->state_change_event); | ||
1058 | 1097 | ||
1059 | info = qcom_smem_get(edge->remote_pid, smem_info_item, &info_size); | 1098 | info = qcom_smem_get(edge->remote_pid, smem_info_item, &info_size); |
1060 | if (IS_ERR(info)) { | 1099 | if (IS_ERR(info)) { |
@@ -1161,7 +1200,7 @@ static void qcom_channel_scan_worker(struct work_struct *work) | |||
1161 | dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name); | 1200 | dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name); |
1162 | set_bit(i, edge->allocated[tbl]); | 1201 | set_bit(i, edge->allocated[tbl]); |
1163 | 1202 | ||
1164 | wake_up_interruptible(&edge->new_channel_event); | 1203 | wake_up_interruptible_all(&edge->new_channel_event); |
1165 | } | 1204 | } |
1166 | } | 1205 | } |
1167 | 1206 | ||
@@ -1195,11 +1234,6 @@ static void qcom_channel_state_worker(struct work_struct *work) | |||
1195 | if (channel->state != SMD_CHANNEL_CLOSED) | 1234 | if (channel->state != SMD_CHANNEL_CLOSED) |
1196 | continue; | 1235 | continue; |
1197 | 1236 | ||
1198 | remote_state = GET_RX_CHANNEL_INFO(channel, state); | ||
1199 | if (remote_state != SMD_CHANNEL_OPENING && | ||
1200 | remote_state != SMD_CHANNEL_OPENED) | ||
1201 | continue; | ||
1202 | |||
1203 | if (channel->registered) | 1237 | if (channel->registered) |
1204 | continue; | 1238 | continue; |
1205 | 1239 | ||