Message ID | 1681807721-32343-4-git-send-email-quic_sarannya@quicinc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | rpmsg signaling/flowcontrol patches | expand |
On 4/18/23 10:48, Sarannya S wrote: > From: Chris Lew <quic_clew@quicinc.com> > > Add RPMSG_GET_SIGNAL_IOCTL and RPMSG_SET_SIGNAL_IOCTL ioctl support for > rpmsg char device nodes to get/set the low level transport signals. Quite difficult to follow this series as there are two V5... If I am not mistaken the comment from Bjorn in the first V5[1] has not been addressed [1] https://www.spinics.net/lists/linux-arm-msm/msg145036.html Regards Arnaud > > Signed-off-by: Chris Lew <quic_clew@quicinc.com> > Signed-off-by: Deepak Kumar Singh <quic_deesin@quicinc.com> > Signed-off-by: Sarannya S <quic_sarannya@quicinc.com> > --- > drivers/rpmsg/rpmsg_char.c | 58 ++++++++++++++++++++++++++++++++++++++++------ > include/linux/rpmsg.h | 15 ++++++++++++ > include/uapi/linux/rpmsg.h | 12 +++++++++- > 3 files changed, 77 insertions(+), 8 deletions(-) > > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c > index a271fce..efe14f8 100644 > --- a/drivers/rpmsg/rpmsg_char.c > +++ b/drivers/rpmsg/rpmsg_char.c > @@ -23,6 +23,7 @@ > #include <linux/rpmsg.h> > #include <linux/skbuff.h> > #include <linux/slab.h> > +#include <linux/termios.h> > #include <linux/uaccess.h> > #include <uapi/linux/rpmsg.h> > > @@ -68,6 +69,8 @@ struct rpmsg_eptdev { > struct sk_buff_head queue; > wait_queue_head_t readq; > > + u32 remote_signals; > + bool flow_control; > }; > > int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data) > @@ -110,7 +113,22 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, > skb_queue_tail(&eptdev->queue, skb); > spin_unlock(&eptdev->queue_lock); > > - /* wake up any blocking processes, waiting for new data */ > + wake_up_interruptible(&eptdev->readq); > + > + return 0; > +} > + > +static int rpmsg_ept_flow_cb(struct rpmsg_device *rpdev, void *priv, bool enable) > +{ > + struct rpmsg_eptdev *eptdev = priv; > + > + if (enable) > + eptdev->remote_signals = RPMSG_FLOW_CONTROL_ON; > + else > + eptdev->remote_signals = 0; > + > + eptdev->flow_control = true; > + > wake_up_interruptible(&eptdev->readq); > > return 0; > @@ -152,6 +170,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) > return -EINVAL; > } > > + ept->flow_cb = rpmsg_ept_flow_cb; > eptdev->ept = ept; > filp->private_data = eptdev; > mutex_unlock(&eptdev->ept_lock); > @@ -172,6 +191,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) > eptdev->ept = NULL; > } > mutex_unlock(&eptdev->ept_lock); > + eptdev->flow_control = false; > > /* Discard all SKBs */ > skb_queue_purge(&eptdev->queue); > @@ -285,6 +305,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) > if (!skb_queue_empty(&eptdev->queue)) > mask |= EPOLLIN | EPOLLRDNORM; > > + if (eptdev->flow_control) > + mask |= EPOLLPRI; > + > mutex_lock(&eptdev->ept_lock); > mask |= rpmsg_poll(eptdev->ept, filp, wait); > mutex_unlock(&eptdev->ept_lock); > @@ -297,14 +320,35 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, > { > struct rpmsg_eptdev *eptdev = fp->private_data; > > - if (cmd != RPMSG_DESTROY_EPT_IOCTL) > - return -EINVAL; > + bool set; > + u32 val; > + int ret; > > - /* Don't allow to destroy a default endpoint. */ > - if (eptdev->default_ept) > - return -EINVAL; > + switch (cmd) { > + case RPMSG_GET_SIGNAL_IOCTL: > + eptdev->flow_control = false; > + ret = put_user(eptdev->remote_signals, (int __user *)arg); > + break; > + case RPMSG_SET_SIGNAL_IOCTL: > + ret = get_user(val, (int __user *)arg); > + if (ret) > + break; > + set = (val & RPMSG_FLOW_CONTROL_ON) ? true : false; > + ret = rpmsg_set_flow_control(eptdev->ept, set); > + 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; > + } > > - return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL); > + return ret; > } > > static const struct file_operations rpmsg_eptdev_fops = { > diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h > index 523c98b..cc7a917 100644 > --- a/include/linux/rpmsg.h > +++ b/include/linux/rpmsg.h > @@ -64,12 +64,14 @@ struct rpmsg_device { > }; > > typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); > +typedef int (*rpmsg_flowcontrol_cb_t)(struct rpmsg_device *, void *, bool); > > /** > * struct rpmsg_endpoint - binds a local rpmsg address to its user > * @rpdev: rpmsg channel device > * @refcount: when this drops to zero, the ept is deallocated > * @cb: rx callback handler > + * @flow_cb: remote flow control callback handler > * @cb_lock: must be taken before accessing/changing @cb > * @addr: local rpmsg address > * @priv: private data for the driver's use > @@ -92,6 +94,7 @@ struct rpmsg_endpoint { > struct rpmsg_device *rpdev; > struct kref refcount; > rpmsg_rx_cb_t cb; > + rpmsg_flowcontrol_cb_t flow_cb; > struct mutex cb_lock; > u32 addr; > void *priv; > @@ -106,6 +109,7 @@ struct rpmsg_endpoint { > * @probe: invoked when a matching rpmsg channel (i.e. device) is found > * @remove: invoked when the rpmsg channel is removed > * @callback: invoked when an inbound message is received on the channel > + * @flowcontrol: invoked when remote side flow control status is received > */ > struct rpmsg_driver { > struct device_driver drv; > @@ -113,6 +117,7 @@ struct rpmsg_driver { > int (*probe)(struct rpmsg_device *dev); > void (*remove)(struct rpmsg_device *dev); > int (*callback)(struct rpmsg_device *, void *, int, void *, u32); > + int (*flowcontrol)(struct rpmsg_device *, void *, bool); > }; > > static inline u16 rpmsg16_to_cpu(struct rpmsg_device *rpdev, __rpmsg16 val) > @@ -192,6 +197,8 @@ __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, > > ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept); > > +int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool enable); > + > #else > > static inline int rpmsg_register_device_override(struct rpmsg_device *rpdev, > @@ -316,6 +323,14 @@ static inline ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept) > return -ENXIO; > } > > +static inline int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool enable) > +{ > + /* This shouldn't be possible */ > + WARN_ON(1); > + > + return -ENXIO; > +} > + > #endif /* IS_ENABLED(CONFIG_RPMSG) */ > > /* use a macro to avoid include chaining to get THIS_MODULE */ > diff --git a/include/uapi/linux/rpmsg.h b/include/uapi/linux/rpmsg.h > index 1637e68..c549649 100644 > --- a/include/uapi/linux/rpmsg.h > +++ b/include/uapi/linux/rpmsg.h > @@ -10,7 +10,7 @@ > #include <linux/types.h> > > #define RPMSG_ADDR_ANY 0xFFFFFFFF > - > +#define RPMSG_FLOW_CONTROL_ON 0x001 > /** > * struct rpmsg_endpoint_info - endpoint info representation > * @name: name of service > @@ -43,4 +43,14 @@ struct rpmsg_endpoint_info { > */ > #define RPMSG_RELEASE_DEV_IOCTL _IOW(0xb5, 0x4, struct rpmsg_endpoint_info) > > +/** > + * Get the remote rpmsg char device's flow control signal. > + */ > +#define RPMSG_GET_SIGNAL_IOCTL _IOW(0xb5, 0x5, struct rpmsg_endpoint_info) > + > +/** > + * Set the flow control for the local rpmsg char device. > + */ > +#define RPMSG_SET_SIGNAL_IOCTL _IOW(0xb5, 0x6, struct rpmsg_endpoint_info) > + > #endif
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a271fce..efe14f8 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -23,6 +23,7 @@ #include <linux/rpmsg.h> #include <linux/skbuff.h> #include <linux/slab.h> +#include <linux/termios.h> #include <linux/uaccess.h> #include <uapi/linux/rpmsg.h> @@ -68,6 +69,8 @@ struct rpmsg_eptdev { struct sk_buff_head queue; wait_queue_head_t readq; + u32 remote_signals; + bool flow_control; }; int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data) @@ -110,7 +113,22 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, skb_queue_tail(&eptdev->queue, skb); spin_unlock(&eptdev->queue_lock); - /* wake up any blocking processes, waiting for new data */ + wake_up_interruptible(&eptdev->readq); + + return 0; +} + +static int rpmsg_ept_flow_cb(struct rpmsg_device *rpdev, void *priv, bool enable) +{ + struct rpmsg_eptdev *eptdev = priv; + + if (enable) + eptdev->remote_signals = RPMSG_FLOW_CONTROL_ON; + else + eptdev->remote_signals = 0; + + eptdev->flow_control = true; + wake_up_interruptible(&eptdev->readq); return 0; @@ -152,6 +170,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->flow_cb = rpmsg_ept_flow_cb; eptdev->ept = ept; filp->private_data = eptdev; mutex_unlock(&eptdev->ept_lock); @@ -172,6 +191,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(&eptdev->ept_lock); + eptdev->flow_control = false; /* Discard all SKBs */ skb_queue_purge(&eptdev->queue); @@ -285,6 +305,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(&eptdev->queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->flow_control) + mask |= EPOLLPRI; + mutex_lock(&eptdev->ept_lock); mask |= rpmsg_poll(eptdev->ept, filp, wait); mutex_unlock(&eptdev->ept_lock); @@ -297,14 +320,35 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, { struct rpmsg_eptdev *eptdev = fp->private_data; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + bool set; + u32 val; + int ret; - /* Don't allow to destroy a default endpoint. */ - if (eptdev->default_ept) - return -EINVAL; + switch (cmd) { + case RPMSG_GET_SIGNAL_IOCTL: + eptdev->flow_control = false; + ret = put_user(eptdev->remote_signals, (int __user *)arg); + break; + case RPMSG_SET_SIGNAL_IOCTL: + ret = get_user(val, (int __user *)arg); + if (ret) + break; + set = (val & RPMSG_FLOW_CONTROL_ON) ? true : false; + ret = rpmsg_set_flow_control(eptdev->ept, set); + 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; + } - return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 523c98b..cc7a917 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -64,12 +64,14 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_flowcontrol_cb_t)(struct rpmsg_device *, void *, bool); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user * @rpdev: rpmsg channel device * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler + * @flow_cb: remote flow control callback handler * @cb_lock: must be taken before accessing/changing @cb * @addr: local rpmsg address * @priv: private data for the driver's use @@ -92,6 +94,7 @@ struct rpmsg_endpoint { struct rpmsg_device *rpdev; struct kref refcount; rpmsg_rx_cb_t cb; + rpmsg_flowcontrol_cb_t flow_cb; struct mutex cb_lock; u32 addr; void *priv; @@ -106,6 +109,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.e. device) is found * @remove: invoked when the rpmsg channel is removed * @callback: invoked when an inbound message is received on the channel + * @flowcontrol: invoked when remote side flow control status is received */ struct rpmsg_driver { struct device_driver drv; @@ -113,6 +117,7 @@ struct rpmsg_driver { int (*probe)(struct rpmsg_device *dev); void (*remove)(struct rpmsg_device *dev); int (*callback)(struct rpmsg_device *, void *, int, void *, u32); + int (*flowcontrol)(struct rpmsg_device *, void *, bool); }; static inline u16 rpmsg16_to_cpu(struct rpmsg_device *rpdev, __rpmsg16 val) @@ -192,6 +197,8 @@ __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept); +int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool enable); + #else static inline int rpmsg_register_device_override(struct rpmsg_device *rpdev, @@ -316,6 +323,14 @@ static inline ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept) return -ENXIO; } +static inline int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool enable) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + #endif /* IS_ENABLED(CONFIG_RPMSG) */ /* use a macro to avoid include chaining to get THIS_MODULE */ diff --git a/include/uapi/linux/rpmsg.h b/include/uapi/linux/rpmsg.h index 1637e68..c549649 100644 --- a/include/uapi/linux/rpmsg.h +++ b/include/uapi/linux/rpmsg.h @@ -10,7 +10,7 @@ #include <linux/types.h> #define RPMSG_ADDR_ANY 0xFFFFFFFF - +#define RPMSG_FLOW_CONTROL_ON 0x001 /** * struct rpmsg_endpoint_info - endpoint info representation * @name: name of service @@ -43,4 +43,14 @@ struct rpmsg_endpoint_info { */ #define RPMSG_RELEASE_DEV_IOCTL _IOW(0xb5, 0x4, struct rpmsg_endpoint_info) +/** + * Get the remote rpmsg char device's flow control signal. + */ +#define RPMSG_GET_SIGNAL_IOCTL _IOW(0xb5, 0x5, struct rpmsg_endpoint_info) + +/** + * Set the flow control for the local rpmsg char device. + */ +#define RPMSG_SET_SIGNAL_IOCTL _IOW(0xb5, 0x6, struct rpmsg_endpoint_info) + #endif