diff options
| -rw-r--r-- | drivers/remoteproc/qcom_common.c | 2 | ||||
| -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 |
4 files changed, 55 insertions, 19 deletions
diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index d487040b528b..e9b5f2a98c4d 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c | |||
| @@ -57,7 +57,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev) | |||
| 57 | 57 | ||
| 58 | glink->edge = qcom_glink_smem_register(glink->dev, glink->node); | 58 | glink->edge = qcom_glink_smem_register(glink->dev, glink->node); |
| 59 | 59 | ||
| 60 | return IS_ERR(glink->edge) ? PTR_ERR(glink->edge) : 0; | 60 | return PTR_ERR_OR_ZERO(glink->edge); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static void glink_subdev_remove(struct rproc_subdev *subdev) | 63 | static void glink_subdev_remove(struct rproc_subdev *subdev) |
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 | ||
