diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 452da4905db0..79d6961663a9 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -366,6 +366,26 @@ int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear) } EXPORT_SYMBOL(rpmsg_set_signals); +/** + * rpmsg_rx_done() - release resources related to @data from a @rx_cb + * @ept: the rpmsg endpoint + * @data: payload from a message + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_rx_done(struct rpmsg_endpoint *ept, void *data) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->rx_done) + return -ENXIO; + if (!ept->rx_done) + return -EINVAL; + + return ept->ops->rx_done(ept, data); +} +EXPORT_SYMBOL(rpmsg_rx_done); + /* * match a rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index a175f1f20382..63cb74ea68d6 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -77,6 +77,7 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*rx_done)(struct rpmsg_endpoint *ept, void *data); int (*get_signals)(struct rpmsg_endpoint *ept); int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); }; diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 7a66652e8be6..e301b2269400 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -62,6 +62,18 @@ struct rpmsg_device { const struct rpmsg_device_ops *ops; }; +/** + * rpmsg rx callback return definitions + * @RPMSG_HANDLED: rpmsg user is done processing data, framework can free the + * resources related to the buffer + * @RPMSG_DEFER: rpmsg user is not done processing data, framework will hold + * onto resources related to the buffer until rpmsg_rx_done is + * called. User should check their endpoint to see if rx_done + * is a supported operation. + */ +#define RPMSG_HANDLED 0 +#define RPMSG_DEFER 1 + typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); @@ -72,6 +84,7 @@ typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, u32); * @cb: rx callback handler * @cb_lock: must be taken before accessing/changing @cb * @sig_cb: rx serial signal handler + * @rx_done: if set, rpmsg endpoint supports rpmsg_rx_done * @addr: local rpmsg address * @priv: private data for the driver's use * @@ -95,6 +108,7 @@ struct rpmsg_endpoint { rpmsg_rx_cb_t cb; struct mutex cb_lock; rpmsg_rx_sig_t sig_cb; + bool rx_done; u32 addr; void *priv; @@ -196,6 +210,8 @@ __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, int rpmsg_get_signals(struct rpmsg_endpoint *ept); int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear); +int rpmsg_rx_done(struct rpmsg_endpoint *ept, void *data); + #else static inline int rpmsg_register_device(struct rpmsg_device *rpdev) @@ -323,6 +339,14 @@ static inline int rpmsg_set_signals(struct rpmsg_endpoint *ept, return -ENXIO; } +static inline int rpmsg_rx_done(struct rpmsg_endpoint *ept, void *data) +{ + /* 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 */