aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2011-08-26 15:14:29 -0700
committerIliyan Malchev <malchev@google.com>2011-08-26 15:14:29 -0700
commitd5ea29096af4b41cf8b04f82fd6836b8c04ebd15 (patch)
tree1712b45e7d88706a61b9ed27560d4e965216afc8 /drivers
parent38b997c7f361c624c5d2967f28e74c4c3c07db85 (diff)
parenta0312e9a048a45cbdb3e6a81e221153309c482b8 (diff)
downloadkernel_samsung_espresso10-d5ea29096af4b41cf8b04f82fd6836b8c04ebd15.zip
kernel_samsung_espresso10-d5ea29096af4b41cf8b04f82fd6836b8c04ebd15.tar.gz
kernel_samsung_espresso10-d5ea29096af4b41cf8b04f82fd6836b8c04ebd15.tar.bz2
Merge branch 'linux-omap-3.0' into android-omap-3.0
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 33d3a49..bd6408a 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -420,9 +420,8 @@ static void *get_a_buf(struct virtproc_info *vrp)
unsigned int len;
void *buf = NULL;
- /* protect svq from simultaneous concurrent manipulations */
- mutex_lock(&vrp->svq_lock);
-
+ /* make sure the descriptors are updated before reading */
+ rmb();
/* either pick the next unused buffer */
if (vrp->last_sbuf < vrp->num_bufs / 2)
buf = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
@@ -430,7 +429,6 @@ static void *get_a_buf(struct virtproc_info *vrp)
else
buf = virtqueue_get_buf(vrp->svq, &len);
- mutex_unlock(&vrp->svq_lock);
return buf;
}
@@ -457,10 +455,18 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
return -EMSGSIZE;
}
+ /*
+ * protect svq from simultaneous concurrent manipulations,
+ * and serialize the sending of messages
+ */
+ if (mutex_lock_interruptible(&vrp->svq_lock))
+ return -ERESTARTSYS;
/* grab a buffer */
msg = get_a_buf(vrp);
- if (!msg && !wait)
- return -ENOMEM;
+ if (!msg && !wait) {
+ err = -ENOMEM;
+ goto out;
+ }
/* no free buffer ? wait for one (but bail after 15 seconds) */
if (!msg) {
@@ -480,12 +486,15 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
/* on success, suppress "tx-complete" interrupts again */
virtqueue_disable_cb(vrp->svq);
- if (err < 0)
- return -ERESTARTSYS;
+ if (err < 0) {
+ err = -ERESTARTSYS;
+ goto out;
+ }
if (!msg) {
dev_err(dev, "timeout waiting for buffer\n");
- return -ETIMEDOUT;
+ err = -ETIMEDOUT;
+ goto out;
}
}
@@ -506,15 +515,14 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
sim_addr = vrp->sim_base + offset;
sg_init_one(&sg, sim_addr, sizeof(*msg) + len);
- /* protect svq from simultaneous concurrent manipulations */
- mutex_lock(&vrp->svq_lock);
-
/* add message to the remote processor's virtqueue */
err = virtqueue_add_buf_gfp(vrp->svq, &sg, 1, 0, msg, GFP_KERNEL);
if (err < 0) {
dev_err(dev, "virtqueue_add_buf_gfp failed: %d\n", err);
goto out;
}
+ /* descriptors must be written before kicking remote processor */
+ wmb();
/* tell the remote processor it has a pending message to read */
virtqueue_kick(vrp->svq);
@@ -538,6 +546,8 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
struct device *dev = &rvq->vdev->dev;
int err;
+ /* make sure the descriptors are updated before reading */
+ rmb();
msg = virtqueue_get_buf(rvq, &len);
if (!msg) {
dev_err(dev, "uhm, incoming signal, but no used buffer ?\n");
@@ -570,6 +580,8 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
dev_err(dev, "failed to add a virtqueue buffer: %d\n", err);
return;
}
+ /* descriptors must be written before kicking remote processor */
+ wmb();
/* tell the remote processor we added another available rx buffer */
virtqueue_kick(vrp->rvq);