rpmsg updates for v5.5
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. -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAl3ivUUbHGJqb3JuLmFu ZGVyc3NvbkBsaW5hcm8ub3JnAAoJEAsfOT8Nma3FiR8QAMPgnnBEYn+DTl2PnTrG AGbac4cvyyCqSR3KoclXfosFEDBLO4O6ph3UiYTF0Kn5R5Tapd8pymDJXoinOb+h YhDxsfg8ddcaHpHQHhxlLCRP1jtXfTVekSZqJ20wDkEqFiIvVx5tBjd2muPlLDYP qpiF9hUGSQfWUf/M/Ci5s2UEs533ANL1WKmxK4VrXW9ePOIAK+OS3aQpXdOIWKhb /CGYn9+njEsa50SNUjlgKYB0225Fn04wCycIbB8fHavB0nJ7J+Cyr0fnrj89ICbn 9F3uGItO9Fk4xoDZ5v6znYoT2ch+LSbcoZ2YVJaqrLWjMM2XzattvH11rX1wuro0 tRqOGO6X5ztK3q+n5w4Sg2hecHobjZlL+j7gNuAT5r0cyIjyCrSzaJeQij6bgtRA cTp/LlqWck2qVGeXbfFHvyfrZQrGD72lg0vxoE+dqwX55PQ15C25v40LULVR0YeS oRI8o5Qv6fv9aKSf5SRJIRdXg0rWdmLU7q9pzrdlF4hw++RCvVdvKUTqCLvQQxLw TZi6YkEjsZEOpXM5KmqRAjJ+KsRp2lJsyW0wLU0b/8zzuZmRiTIHZ6PMk8ThTCGM ka8Y3YGOAR+ShaK5z0u56fktaqQSYhVRyS/WmIiQZ/zvlpQRCtwPnQptcIxjlVbL FK9IU1ARADI8CqXTz1j0V/tt =qkoA -----END PGP SIGNATURE----- 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 memorypull/758/head
commit
687fcad8a3
|
|
@ -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)
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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,
|
||||||
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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue