-
Notifications
You must be signed in to change notification settings - Fork 295
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
openamp: add new ops wait_tx_buffer() support #347
Conversation
5dc2783
to
df8c863
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a lot more documentation explaining what the new operation must do, and what values it returns.
@@ -333,6 +333,8 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, | |||
metal_mutex_release(&rdev->lock); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to hold the lock, or re-lock the device during rpmsg_virtio_wait_tx_buffer()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need, you can assume the simplest user's implementation of wait_tx_buffer() is metal_sleep_usec().
lib/rpmsg/rpmsg_virtio.c
Outdated
@@ -333,6 +333,8 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, | |||
metal_mutex_release(&rdev->lock); | |||
if (rp_hdr || !tick_count) | |||
break; | |||
if (rpmsg_virtio_wait_tx_buffer(rvdev) >= 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong. If it fails, the program waits twice, once in rpmsg_virtio_wait_tx_buffer(), and then in metal_sleep_usec().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If wait fails, that means hasn't wait, then we still need do metal_sleep_usec(), or will busyloop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please could you explain why you don't use rpmsg_trysend
API instead that set wait
to false
and so tick_count
to 0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is only one difference between a looping query mechanism and a waiting mechanism.
Of course, a waiting mechanism is more suitable for low power device.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point here is that I don't understand why you don't use "rpmsg_trysend" in an application loop instead.
you would generate your loop without waiting mechanism.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But, rpmsg_send/rpmsg_get_tx_payload_buffer is a public api, we can't limit how other team write the application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If wait fails, that means hasn't wait, then we still need do metal_sleep_usec(), or will busyloop.
So a function with "wait" in its name doesn't wait sometimes? This needs to be documented in the Doxygen comments. There needs to be enough documentation that a new user of the library can understand why they might need to implement this operation, and how to implement it properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point here is that I don't understand why you don't use "rpmsg_trysend" in an application loop instead.
you would generate your loop without waiting mechanism.
I agree with @arnopo. I don't understand why this needs to be in the library, rather than in application code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If wait fails, that means hasn't wait, then we still need do metal_sleep_usec(), or will busyloop.
Yes, wait fail mean it can't finish the work in some special case, so the common code need do the fallback action. In most case, wait success mean the buffer available and the framework can try again immediately.
So a function with "wait" in its name doesn't wait sometimes? This needs to be documented in the Doxygen comments. There needs to be enough documentation that a new user of the library can understand why they might need to implement this operation, and how to implement it properly.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if rpmsg_trysend
can do the job please detail what is missing
lib/rpmsg/rpmsg_virtio.c
Outdated
@@ -333,6 +333,8 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, | |||
metal_mutex_release(&rdev->lock); | |||
if (rp_hdr || !tick_count) | |||
break; | |||
if (rpmsg_virtio_wait_tx_buffer(rvdev) >= 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please could you explain why you don't use rpmsg_trysend
API instead that set wait
to false
and so tick_count
to 0
?
There is only one difference between a looping query mechanism and a waiting mechanism. |
An operation that simply checked if there is a tx buffer available could be useful to application writers. For example, there could be a special thread that monitored buffer usage, and if there were no buffers available, did some sort of maintenance on the buffer pool, or restarted the application. The point is that the handling of the out of buffers situation is best done by the application programmer. |
It's still a busy loop.
Are you sure this should be done by the application programmer, not BSP programmer?! I remember that there is a work group to define the general rpmsg service, could you tell me how the work group can avoid the busy polling in a platform dependent way by your propose. |
From the architecture perspective, the busy polling should be replaced by waiting a semaphore in OpenAMP framework, just like how Linux side do the same thing, but this require to change libmetal and open-amp. From our upstream experience, all my team member don't want to make any big change to libmetal or open-amp. |
Behavior depends on:
As you mentioned a rpmsg service layer is something that makes sense in OSes. But this layer is quite OS/project dependent. Make it generic would also introduce new design tradeoffs. Focusing on the PR itself: |
All these polices can be achieved with the wait_tx_buffer callback, without modifying the framework code.
Yes, that's why this patch provide the callback to give the porting layer a chance to handle this situation in a better way other than the poll loop.
Yes, but the framework shouldn't forbid the porting layer to do some optimization if they want.
First, we want to remove all poll loop for battery powered device. Second, the callback give many possibility other than simply sleep(e.g. wait semaphore, recursive dispatch...). |
More an library integration point that a feature point. From feature point of view be able to optimize the waiting is completly valid, that's why the rpmsg_trysend had been created. If @edmooring is ok let's move forward on your proposed implementation and see how smoothly this could be inserted. |
Yes, because the behavior that is needed can change, depending on the application. In many cases, the application/service developers work for a different company than the team that develops the BSP, and there are dozens of different teams from multiple organizations using the same BSP.
As @arnopo points out down below, this can be done at a higher level than the OpenAMP transport layer. Attempting to handle application-level policy decisions at the transport layer risks causing more problems later. |
1 similar comment
Yes, because the behavior that is needed can change, depending on the application. In many cases, the application/service developers work for a different company than the team that develops the BSP, and there are dozens of different teams from multiple organizations using the same BSP.
As @arnopo points out down below, this can be done at a higher level than the OpenAMP transport layer. Attempting to handle application-level policy decisions at the transport layer risks causing more problems later. |
64fd252
to
0c17630
Compare
05f138e
to
d991569
Compare
@arnopo as your suggestion, modify |
lib/remoteproc/remoteproc_virtio.c
Outdated
@@ -30,6 +30,19 @@ static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) | |||
rpvdev->notify(rpvdev->priv, vring_info->notifyid); | |||
} | |||
|
|||
static int rproc_virtio_wait_notified(struct virtio_device *vdev, | |||
struct virtqueue *vq) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static int rproc_virtio_notify_wait(struct virtqueue *vq)
lib/include/openamp/remoteproc.h
Outdated
* | ||
* return 0 means there is notify available, otherwise negative value. | ||
*/ | ||
int (*wait_notified)(struct remoteproc *rproc, uint32_t id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notify_wait> should we move before line 414?
@edmooring @arnopo @jjmcdn |
@edmooring @arnopo @jjmcdn |
056bdf3
to
16ed019
Compare
lib/rpmsg/rpmsg_virtio.c
Outdated
@@ -347,6 +347,13 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, | |||
metal_mutex_release(&rdev->lock); | |||
if (rp_hdr || !tick_count) | |||
break; | |||
|
|||
status = rpmsg_virtio_notify_wait(rvdev, rvdev->rvq); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create a more generic function that implement also the metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL);
something such as:
static inline int
rpmsg_virtio_wait_for_buffer(struct rpmsg_virtio_device *rvdev,
struct virtqueue *vq, int timeout)
{
if (rvdev->vdev->func->notify_wait) {
return rvdev->vdev->func->notify_wait(rvdev->vdev, vq, timeout) :
} else {
metal_sleep_usec(timeout);
return RPMSG_SUCCESS;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need pass param timeout to rpmsg_virtio_wait_for_buffer, and need tick_count--
.
So I change the caller.
lib/remoteproc/remoteproc_virtio.c
Outdated
@@ -179,6 +192,7 @@ static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { | |||
.get_features = rproc_virtio_get_features, | |||
.read_config = rproc_virtio_read_config, | |||
.notify = rproc_virtio_virtqueue_notify, | |||
.notify_wait = rproc_virtio_notify_wait, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned the feature is optional. seems better to declare it in remoteproc_virtio
(similar to rpvdev_notify_func) and add a new API to set it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a element of remoteproc_ops
, if user don't want this feature, then don't set the remoteproc_ops->wait_notified
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a element of
remoteproc_ops
, if user don't want this feature, then don't set theremoteproc_ops->wait_notified
That's true only if the remoteproc_ops is used. Here is an exemple of the use of rpmsg without remoteproc_ops:
https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c#L228
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arnopo Hi, I want to continue this PR. You mean add new api to set the rpvdev->wait_notifed
is add a new function called rproc_virtio_set_wait_notifed()
or add a new argument in rproc_virtio_create_vdev()
like this:
struct virtio_device *
rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid,
void *rsc, struct metal_io_region *rsc_io,
void *priv,
rpvdev_notify_func notify,
rpvdev_wait_notify_func wait_notifed,
virtio_dev_reset_cb rst_cb)
Both are good for me, but I think we should set the notify and wait_notifed function in same way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @CV-Bowen ,
I will need probably few time to remind all discussions on this PR, but concerning our point:
We are trying to not modify the existing API. As the wait_notifed is optional, I prefer the rproc_virtio_set_wait_notifed()
API.
Please notice also that we added more Doxygen documentation, so this PR needs rebase and some refresh .
This can avoid looping check tx buffer Signed-off-by: Guiding Li <[email protected]>
I close this one to avoid confusion. |
openamp: add new ops wait_tx_buffer() support
This can avoid looping check tx buffer