diff options
author | Iliyan Malchev <malchev@google.com> | 2011-08-26 15:14:29 -0700 |
---|---|---|
committer | Iliyan Malchev <malchev@google.com> | 2011-08-26 15:14:29 -0700 |
commit | d5ea29096af4b41cf8b04f82fd6836b8c04ebd15 (patch) | |
tree | 1712b45e7d88706a61b9ed27560d4e965216afc8 /drivers | |
parent | 38b997c7f361c624c5d2967f28e74c4c3c07db85 (diff) | |
parent | a0312e9a048a45cbdb3e6a81e221153309c482b8 (diff) | |
download | kernel_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.c | 36 |
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); |