aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c25
-rw-r--r--include/linux/rpmsg.h3
2 files changed, 22 insertions, 6 deletions
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 9623327ba509..39d3aa41adda 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -227,6 +227,7 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
227 } 227 }
228 228
229 kref_init(&ept->refcount); 229 kref_init(&ept->refcount);
230 mutex_init(&ept->cb_lock);
230 231
231 ept->rpdev = rpdev; 232 ept->rpdev = rpdev;
232 ept->cb = cb; 233 ept->cb = cb;
@@ -324,10 +325,16 @@ EXPORT_SYMBOL(rpmsg_create_ept);
324static void 325static void
325__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) 326__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
326{ 327{
328 /* make sure new inbound messages can't find this ept anymore */
327 mutex_lock(&vrp->endpoints_lock); 329 mutex_lock(&vrp->endpoints_lock);
328 idr_remove(&vrp->endpoints, ept->addr); 330 idr_remove(&vrp->endpoints, ept->addr);
329 mutex_unlock(&vrp->endpoints_lock); 331 mutex_unlock(&vrp->endpoints_lock);
330 332
333 /* make sure in-flight inbound messages won't invoke cb anymore */
334 mutex_lock(&ept->cb_lock);
335 ept->cb = NULL;
336 mutex_unlock(&ept->cb_lock);
337
331 kref_put(&ept->refcount, __ept_release); 338 kref_put(&ept->refcount, __ept_release);
332} 339}
333 340
@@ -821,14 +828,20 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
821 828
822 mutex_unlock(&vrp->endpoints_lock); 829 mutex_unlock(&vrp->endpoints_lock);
823 830
824 if (ept && ept->cb) 831 if (ept) {
825 ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src); 832 /* make sure ept->cb doesn't go away while we use it */
826 else 833 mutex_lock(&ept->cb_lock);
827 dev_warn(dev, "msg received with no recepient\n");
828 834
829 /* farewell, ept, we don't need you anymore */ 835 if (ept->cb)
830 if (ept) 836 ept->cb(ept->rpdev, msg->data, msg->len, ept->priv,
837 msg->src);
838
839 mutex_unlock(&ept->cb_lock);
840
841 /* farewell, ept, we don't need you anymore */
831 kref_put(&ept->refcount, __ept_release); 842 kref_put(&ept->refcount, __ept_release);
843 } else
844 dev_warn(dev, "msg received with no recepient\n");
832 845
833 /* publish the real size of the buffer */ 846 /* publish the real size of the buffer */
834 sg_init_one(&sg, msg, RPMSG_BUF_SIZE); 847 sg_init_one(&sg, msg, RPMSG_BUF_SIZE);
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 195f373590b8..82a673905edb 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -39,6 +39,7 @@
39#include <linux/device.h> 39#include <linux/device.h>
40#include <linux/mod_devicetable.h> 40#include <linux/mod_devicetable.h>
41#include <linux/kref.h> 41#include <linux/kref.h>
42#include <linux/mutex.h>
42 43
43/* The feature bitmap for virtio rpmsg */ 44/* The feature bitmap for virtio rpmsg */
44#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ 45#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
@@ -123,6 +124,7 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
123 * @rpdev: rpmsg channel device 124 * @rpdev: rpmsg channel device
124 * @refcount: when this drops to zero, the ept is deallocated 125 * @refcount: when this drops to zero, the ept is deallocated
125 * @cb: rx callback handler 126 * @cb: rx callback handler
127 * @cb_lock: must be taken before accessing/changing @cb
126 * @addr: local rpmsg address 128 * @addr: local rpmsg address
127 * @priv: private data for the driver's use 129 * @priv: private data for the driver's use
128 * 130 *
@@ -144,6 +146,7 @@ struct rpmsg_endpoint {
144 struct rpmsg_channel *rpdev; 146 struct rpmsg_channel *rpdev;
145 struct kref refcount; 147 struct kref refcount;
146 rpmsg_rx_cb_t cb; 148 rpmsg_rx_cb_t cb;
149 struct mutex cb_lock;
147 u32 addr; 150 u32 addr;
148 void *priv; 151 void *priv;
149}; 152};