Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpmsg: wait endpoint ready in rpmsg_send #238

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 42 additions & 17 deletions lib/include/openamp/rpmsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <metal/compiler.h>
#include <metal/mutex.h>
#include <metal/list.h>
#include <metal/sleep.h>
#include <metal/utilities.h>
#include <string.h>
#include <stdbool.h>
Expand All @@ -32,6 +33,12 @@ extern "C" {
#define RPMSG_RESERVED_ADDRESSES (1024)
#define RPMSG_ADDR_ANY 0xFFFFFFFF

/* Total tick count for 15secs - 1usec tick. */
#define RPMSG_TICK_COUNT 15000000

/* Time to wait - In multiple of 1 msecs. */
#define RPMSG_TICKS_PER_INTERVAL 1000

/* Error macros. */
#define RPMSG_SUCCESS 0
#define RPMSG_ERROR_BASE -2000
Expand Down Expand Up @@ -173,6 +180,19 @@ int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
uint32_t dst, const void *data, int len,
int wait);

/**
* is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send
*
* @ept: pointer to rpmsg endpoint
*
* Returns 1 if the rpmsg endpoint has both local addr and destination
* addr set, 0 otherwise
*/
static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept)
{
return ept && ept->rdev && ept->dest_addr != RPMSG_ADDR_ANY;
}

/**
* @brief Send a message across to the remote processor
*
Expand All @@ -192,11 +212,20 @@ int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data,
int len)
{
int tc = 0;

if (!ept)
return RPMSG_ERR_PARAM;

return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data,
len, true);
for (; tc < RPMSG_TICK_COUNT; tc += RPMSG_TICKS_PER_INTERVAL) {
if (is_rpmsg_ept_ready(ept))
return rpmsg_send_offchannel_raw(ept, ept->addr,
ept->dest_addr,
data, len, true);
metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As previously discussed this imposes a way of implementing to other platforms which would not want to wait on first message, and not be blocked because channel has been closed by remote side (RPMSG_NS_DESTROY).

Look to me that test in rpmsg_send_offchannel_raw is enough to protect from a non initialized destination address .
The loop should be implement in application if necessary, to keep flexibility in the lib usage.

@edmooring
Any opinion on this?

Copy link
Collaborator Author

@xiaoxiang781216 xiaoxiang781216 Nov 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this change doesn't forbid the user do the loop in application, user has all possible choice:

  1. Call rpmsg_try_send and check the return value
  2. Check dest_addr before call rpmsg_send
  3. Let rpmsg_send to do the check

With this patch, user can still do item 1 and item 2 as they want, but item 3 can protect user if they forget to do the check.
BTW, it also follow the same behaviour when the vring buffer exhaust:
https://github.com/OpenAMP/open-amp/blob/master/lib/rpmsg/rpmsg_virtio.c#L305

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Arnaud. This changes the behavior of an existing API in a way that could be very surprising to a user by introducing a possible 15 second delay in their application.
This should be done in an application, where the user knows what conditions they might be expected and can set timeout values and retry patterns in a way that is best for them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's see how many user will report this issue and then decide whether a common solution is needed.

return RPMSG_ERR_ADDR;
}

/**
Expand Down Expand Up @@ -508,11 +537,20 @@ static inline int rpmsg_sendto_nocopy(struct rpmsg_endpoint *ept,
static inline int rpmsg_send_nocopy(struct rpmsg_endpoint *ept,
const void *data, int len)
{
int tc = 0;

if (!ept)
return RPMSG_ERR_PARAM;

return rpmsg_send_offchannel_nocopy(ept, ept->addr,
ept->dest_addr, data, len);
for (; tc < RPMSG_TICK_COUNT; tc += RPMSG_TICKS_PER_INTERVAL) {
if (is_rpmsg_ept_ready(ept))
return rpmsg_send_offchannel_nocopy(ept, ept->addr,
ept->dest_addr,
data, len);
metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL);
}

return RPMSG_ERR_ADDR;
}

/**
Expand Down Expand Up @@ -557,19 +595,6 @@ int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
*/
void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);

/**
* @brief Check if the rpmsg endpoint ready to send
*
* @param ept Pointer to rpmsg endpoint
*
* @return 1 if the rpmsg endpoint has both local addr and destination
* addr set, 0 otherwise
*/
static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept)
{
return ept && ept->rdev && ept->dest_addr != RPMSG_ADDR_ANY;
}

#if defined __cplusplus
}
#endif
Expand Down
7 changes: 0 additions & 7 deletions lib/rpmsg/rpmsg_virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*/

#include <metal/alloc.h>
#include <metal/sleep.h>
#include <metal/utilities.h>
#include <openamp/rpmsg_virtio.h>
#include <openamp/virtqueue.h>
Expand All @@ -18,12 +17,6 @@

#define RPMSG_NUM_VRINGS 2

/* Total tick count for 15secs - 1usec tick. */
#define RPMSG_TICK_COUNT 15000000

/* Time to wait - In multiple of 1 msecs. */
#define RPMSG_TICKS_PER_INTERVAL 1000

/*
* Get the buffer held counter value.
* If 0 the buffer can be released
Expand Down
Loading