FROMLIST: rpmsg: core: Add rx done hooks

In order to reduce the amount of copies in the rpmsg framework, it is
necessary for clients to take brief ownership of the receive buffer.

Add the capability for clients to notify the rpmsg framework and the
underlying transports when it is going to hold onto a buffer and also
notify when the client is done with the buffer.

In the .rx_cb of the rpmsg drivers, if they wish to use the received
buffer at a later point, they should return RPMSG_DEFER. Otherwise
returning RPMSG_HANDLED (0) will signal the framework that the client
is done with the resources and can continue with cleanup.

The clients should check if their rpmsg endpoint supports the rx_done
operation with the new state variable in the rpmsg_endpoint since not
all endpoints will have the ability to support this operation.

Bug: 235577039
Link: https://lore.kernel.org/lkml/1654651005-15475-2-git-send-email-quic_clew@quicinc.com/
Change-Id: I008ae73d54f9d8319e9dbcafd7d9c7007fa4f234
Signed-off-by: Chris Lew <quic_clew@quicinc.com>
This commit is contained in:
Chris Lew
2022-06-03 13:34:08 -07:00
committed by Carlos Llamas
parent 60a6ad4211
commit a4f64634ad
3 changed files with 45 additions and 0 deletions

View File

@@ -366,6 +366,26 @@ int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear)
} }
EXPORT_SYMBOL(rpmsg_set_signals); 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. * match a rpmsg channel with a channel info struct.
* this is used to make sure we're not creating rpmsg devices for channels * this is used to make sure we're not creating rpmsg devices for channels

View File

@@ -77,6 +77,7 @@ struct rpmsg_endpoint_ops {
void *data, int len); void *data, int len);
__poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp,
poll_table *wait); poll_table *wait);
int (*rx_done)(struct rpmsg_endpoint *ept, void *data);
int (*get_signals)(struct rpmsg_endpoint *ept); int (*get_signals)(struct rpmsg_endpoint *ept);
int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear); int (*set_signals)(struct rpmsg_endpoint *ept, u32 set, u32 clear);
}; };

View File

@@ -62,6 +62,18 @@ struct rpmsg_device {
const struct rpmsg_device_ops *ops; 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_cb_t)(struct rpmsg_device *, void *, int, void *, u32);
typedef int (*rpmsg_rx_sig_t)(struct rpmsg_device *, void *, u32, 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: rx callback handler
* @cb_lock: must be taken before accessing/changing @cb * @cb_lock: must be taken before accessing/changing @cb
* @sig_cb: rx serial signal handler * @sig_cb: rx serial signal handler
* @rx_done: if set, rpmsg endpoint supports rpmsg_rx_done
* @addr: local rpmsg address * @addr: local rpmsg address
* @priv: private data for the driver's use * @priv: private data for the driver's use
* *
@@ -95,6 +108,7 @@ struct rpmsg_endpoint {
rpmsg_rx_cb_t cb; rpmsg_rx_cb_t cb;
struct mutex cb_lock; struct mutex cb_lock;
rpmsg_rx_sig_t sig_cb; rpmsg_rx_sig_t sig_cb;
bool rx_done;
u32 addr; u32 addr;
void *priv; 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_get_signals(struct rpmsg_endpoint *ept);
int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear); int rpmsg_set_signals(struct rpmsg_endpoint *ept, u32 set, u32 clear);
int rpmsg_rx_done(struct rpmsg_endpoint *ept, void *data);
#else #else
static inline int rpmsg_register_device(struct rpmsg_device *rpdev) 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; 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) */ #endif /* IS_ENABLED(CONFIG_RPMSG) */
/* use a macro to avoid include chaining to get THIS_MODULE */ /* use a macro to avoid include chaining to get THIS_MODULE */