// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2022, STMicroelectronics * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek <monstr@monstr.eu> * Copyright (c) 2012, PetaLogix * Copyright (c) 2011, Texas Instruments, Inc. * Copyright (c) 2011, Google, Inc. * * Based on rpmsg performance statistics driver by Michal Simek, which in turn * was based on TI & Google OMX rpmsg driver.
*/
/** * struct rpmsg_eptdev - endpoint device context * @dev: endpoint device * @cdev: cdev for the endpoint device * @rpdev: underlaying rpmsg device * @chinfo: info used to open the endpoint * @ept_lock: synchronization of @ept modifications * @ept: rpmsg endpoint reference, when open * @queue_lock: synchronization of @queue operations * @queue: incoming message queue * @readq: wait object for incoming queue * @default_ept: set to channel default endpoint if the default endpoint should be re-used * on device open to prevent endpoint address update. * @remote_flow_restricted: to indicate if the remote has requested for flow to be limited * @remote_flow_updated: to indicate if the flow control has been requested
*/ struct rpmsg_eptdev { struct device dev; struct cdev cdev;
mutex_lock(&eptdev->ept_lock);
eptdev->rpdev = NULL; if (eptdev->ept) { /* The default endpoint is released by the rpmsg core */ if (!eptdev->default_ept)
rpmsg_destroy_ept(eptdev->ept);
eptdev->ept = NULL;
}
mutex_unlock(&eptdev->ept_lock);
/* wake up any blocked readers */
wake_up_interruptible(&eptdev->readq);
mutex_lock(&eptdev->ept_lock); if (eptdev->ept) {
mutex_unlock(&eptdev->ept_lock); return -EBUSY;
}
if (!eptdev->rpdev) {
mutex_unlock(&eptdev->ept_lock); return -ENETRESET;
}
get_device(dev);
/* * If the default_ept is set, the rpmsg device default endpoint is used. * Else a new endpoint is created on open that will be destroyed on release.
*/ if (eptdev->default_ept)
ept = eptdev->default_ept; else
ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
if (!ept) {
dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
put_device(dev);
mutex_unlock(&eptdev->ept_lock); return -EINVAL;
}
/* Close the endpoint, if it's not already destroyed by the parent */
mutex_lock(&eptdev->ept_lock); if (eptdev->ept) { if (!eptdev->default_ept)
rpmsg_destroy_ept(eptdev->ept);
eptdev->ept = NULL;
}
mutex_unlock(&eptdev->ept_lock);
eptdev->remote_flow_updated = false;
/* Discard all SKBs */
skb_queue_purge(&eptdev->queue);
/* Wait for data in the queue */ if (skb_queue_empty(&eptdev->queue)) {
spin_unlock_irqrestore(&eptdev->queue_lock, flags);
if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
/* Wait until we get data or the endpoint goes away */ if (wait_event_interruptible(eptdev->readq,
!skb_queue_empty(&eptdev->queue) ||
!eptdev->ept)) return -ERESTARTSYS;
/* We lost the endpoint while waiting */ if (!eptdev->ept) return -EPIPE;
spin_lock_irqsave(&eptdev->queue_lock, flags);
}
skb = skb_dequeue(&eptdev->queue);
spin_unlock_irqrestore(&eptdev->queue_lock, flags); if (!skb) return -EFAULT;
use = min_t(size_t, iov_iter_count(to), skb->len); if (copy_to_iter(skb->data, use, to) != use)
use = -EFAULT;
switch (cmd) { case RPMSG_GET_OUTGOING_FLOWCONTROL:
eptdev->remote_flow_updated = false;
ret = put_user(eptdev->remote_flow_restricted, (int __user *)arg); break; case RPMSG_SET_INCOMING_FLOWCONTROL: if (arg > 1) {
ret = -EINVAL; break;
}
set = !!arg;
ret = rpmsg_set_flow_control(eptdev->ept, set, eptdev->chinfo.dst); break; case RPMSG_DESTROY_EPT_IOCTL: /* Don't allow to destroy a default endpoint. */ if (eptdev->default_ept) {
ret = -EINVAL; break;
}
ret = rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL); break; default:
ret = -EINVAL;
}
eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, dev); if (IS_ERR(eptdev)) return PTR_ERR(eptdev);
/* Set the default_ept to the rpmsg device endpoint */
eptdev->default_ept = rpdev->ept;
/* * The rpmsg_ept_cb uses *priv parameter to get its rpmsg_eptdev context. * Storedit in default_ept *priv field.
*/
eptdev->default_ept->priv = eptdev;
return rpmsg_chrdev_eptdev_add(eptdev, chinfo);
}
staticvoid rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
{ int ret;
ret = device_for_each_child(&rpdev->dev, NULL, rpmsg_chrdev_eptdev_destroy); if (ret)
dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.