Commit 687fcad8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rpmsg-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc

Pull rpmsg updates from Bjorn Andersson:
 "This contains a number of bug fixes to the GLINK transport driver, an
  off-by-one in the GLINK smem driver and a memory leak fix in the rpmsg
  char driver"

* tag 'rpmsg-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc:
  rpmsg: Fix Kconfig indentation
  rpmsg: char: Simplify 'rpmsg_eptdev_release()'
  rpmsg: glink: Free pending deferred work on remove
  rpmsg: glink: Don't send pending rx_done during remove
  rpmsg: glink: Fix rpmsg_register_device err handling
  rpmsg: glink: Put an extra reference during cleanup
  rpmsg: glink: Fix use after free in open_ack TIMEOUT case
  rpmsg: glink: Fix reuse intents memory leak issue
  rpmsg: glink: Set tail pointer to 0 at end of FIFO
  rpmsg: char: release allocated memory
parents 5e3b06d3 8cf9b615
...@@ -21,7 +21,7 @@ config RPMSG_QCOM_GLINK_NATIVE ...@@ -21,7 +21,7 @@ config RPMSG_QCOM_GLINK_NATIVE
config RPMSG_QCOM_GLINK_RPM config RPMSG_QCOM_GLINK_RPM
tristate "Qualcomm RPM Glink driver" tristate "Qualcomm RPM Glink driver"
select RPMSG_QCOM_GLINK_NATIVE select RPMSG_QCOM_GLINK_NATIVE
depends on HAS_IOMEM depends on HAS_IOMEM
depends on MAILBOX depends on MAILBOX
help help
......
...@@ -241,10 +241,31 @@ static void qcom_glink_channel_release(struct kref *ref) ...@@ -241,10 +241,31 @@ static void qcom_glink_channel_release(struct kref *ref)
{ {
struct glink_channel *channel = container_of(ref, struct glink_channel, struct glink_channel *channel = container_of(ref, struct glink_channel,
refcount); refcount);
struct glink_core_rx_intent *intent;
struct glink_core_rx_intent *tmp;
unsigned long flags; unsigned long flags;
int iid;
/* cancel pending rx_done work */
cancel_work_sync(&channel->intent_work);
spin_lock_irqsave(&channel->intent_lock, flags); spin_lock_irqsave(&channel->intent_lock, flags);
/* Free all non-reuse intents pending rx_done work */
list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) {
if (!intent->reuse) {
kfree(intent->data);
kfree(intent);
}
}
idr_for_each_entry(&channel->liids, tmp, iid) {
kfree(tmp->data);
kfree(tmp);
}
idr_destroy(&channel->liids); idr_destroy(&channel->liids);
idr_for_each_entry(&channel->riids, tmp, iid)
kfree(tmp);
idr_destroy(&channel->riids); idr_destroy(&channel->riids);
spin_unlock_irqrestore(&channel->intent_lock, flags); spin_unlock_irqrestore(&channel->intent_lock, flags);
...@@ -1094,13 +1115,12 @@ static int qcom_glink_create_remote(struct qcom_glink *glink, ...@@ -1094,13 +1115,12 @@ static int qcom_glink_create_remote(struct qcom_glink *glink,
close_link: close_link:
/* /*
* Send a close request to "undo" our open-ack. The close-ack will * Send a close request to "undo" our open-ack. The close-ack will
* release the last reference. * release qcom_glink_send_open_req() reference and the last reference
* will be relesed after receiving remote_close or transport unregister
* by calling qcom_glink_native_remove().
*/ */
qcom_glink_send_close_req(glink, channel); qcom_glink_send_close_req(glink, channel);
/* Release qcom_glink_send_open_req() reference */
kref_put(&channel->refcount, qcom_glink_channel_release);
return ret; return ret;
} }
...@@ -1415,15 +1435,13 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, ...@@ -1415,15 +1435,13 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
ret = rpmsg_register_device(rpdev); ret = rpmsg_register_device(rpdev);
if (ret) if (ret)
goto free_rpdev; goto rcid_remove;
channel->rpdev = rpdev; channel->rpdev = rpdev;
} }
return 0; return 0;
free_rpdev:
kfree(rpdev);
rcid_remove: rcid_remove:
spin_lock_irqsave(&glink->idr_lock, flags); spin_lock_irqsave(&glink->idr_lock, flags);
idr_remove(&glink->rcids, channel->rcid); idr_remove(&glink->rcids, channel->rcid);
...@@ -1544,6 +1562,18 @@ static void qcom_glink_work(struct work_struct *work) ...@@ -1544,6 +1562,18 @@ static void qcom_glink_work(struct work_struct *work)
} }
} }
static void qcom_glink_cancel_rx_work(struct qcom_glink *glink)
{
struct glink_defer_cmd *dcmd;
struct glink_defer_cmd *tmp;
/* cancel any pending deferred rx_work */
cancel_work_sync(&glink->rx_work);
list_for_each_entry_safe(dcmd, tmp, &glink->rx_queue, node)
kfree(dcmd);
}
struct qcom_glink *qcom_glink_native_probe(struct device *dev, struct qcom_glink *qcom_glink_native_probe(struct device *dev,
unsigned long features, unsigned long features,
struct qcom_glink_pipe *rx, struct qcom_glink_pipe *rx,
...@@ -1619,23 +1649,24 @@ void qcom_glink_native_remove(struct qcom_glink *glink) ...@@ -1619,23 +1649,24 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
struct glink_channel *channel; struct glink_channel *channel;
int cid; int cid;
int ret; int ret;
unsigned long flags;
disable_irq(glink->irq); disable_irq(glink->irq);
cancel_work_sync(&glink->rx_work); qcom_glink_cancel_rx_work(glink);
ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device); ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
if (ret) if (ret)
dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
spin_lock_irqsave(&glink->idr_lock, flags);
/* Release any defunct local channels, waiting for close-ack */ /* Release any defunct local channels, waiting for close-ack */
idr_for_each_entry(&glink->lcids, channel, cid) idr_for_each_entry(&glink->lcids, channel, cid)
kref_put(&channel->refcount, qcom_glink_channel_release); kref_put(&channel->refcount, qcom_glink_channel_release);
/* Release any defunct local channels, waiting for close-req */
idr_for_each_entry(&glink->rcids, channel, cid)
kref_put(&channel->refcount, qcom_glink_channel_release);
idr_destroy(&glink->lcids); idr_destroy(&glink->lcids);
idr_destroy(&glink->rcids); idr_destroy(&glink->rcids);
spin_unlock_irqrestore(&glink->idr_lock, flags);
mbox_free_channel(glink->mbox_chan); mbox_free_channel(glink->mbox_chan);
} }
EXPORT_SYMBOL_GPL(qcom_glink_native_remove); EXPORT_SYMBOL_GPL(qcom_glink_native_remove);
......
...@@ -105,7 +105,7 @@ static void glink_smem_rx_advance(struct qcom_glink_pipe *np, ...@@ -105,7 +105,7 @@ static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
tail = le32_to_cpu(*pipe->tail); tail = le32_to_cpu(*pipe->tail);
tail += count; tail += count;
if (tail > pipe->native.length) if (tail >= pipe->native.length)
tail -= pipe->native.length; tail -= pipe->native.length;
*pipe->tail = cpu_to_le32(tail); *pipe->tail = cpu_to_le32(tail);
......
...@@ -146,7 +146,6 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) ...@@ -146,7 +146,6 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
{ {
struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
struct device *dev = &eptdev->dev; struct device *dev = &eptdev->dev;
struct sk_buff *skb;
/* Close the endpoint, if it's not already destroyed by the parent */ /* Close the endpoint, if it's not already destroyed by the parent */
mutex_lock(&eptdev->ept_lock); mutex_lock(&eptdev->ept_lock);
...@@ -157,10 +156,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) ...@@ -157,10 +156,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
mutex_unlock(&eptdev->ept_lock); mutex_unlock(&eptdev->ept_lock);
/* Discard all SKBs */ /* Discard all SKBs */
while (!skb_queue_empty(&eptdev->queue)) { skb_queue_purge(&eptdev->queue);
skb = skb_dequeue(&eptdev->queue);
kfree_skb(skb);
}
put_device(dev); put_device(dev);
...@@ -227,8 +223,10 @@ static ssize_t rpmsg_eptdev_write_iter(struct kiocb *iocb, ...@@ -227,8 +223,10 @@ static ssize_t rpmsg_eptdev_write_iter(struct kiocb *iocb,
if (!kbuf) if (!kbuf)
return -ENOMEM; return -ENOMEM;
if (!copy_from_iter_full(kbuf, len, from)) if (!copy_from_iter_full(kbuf, len, from)) {
return -EFAULT; ret = -EFAULT;
goto free_kbuf;
}
if (mutex_lock_interruptible(&eptdev->ept_lock)) { if (mutex_lock_interruptible(&eptdev->ept_lock)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment