Skip to content

Commit b32187e

Browse files
GUIDINGLIarnopo
authored andcommitted
openamp: change rx/tx buffer hold flag to count
Before this commit, if rpmsg_hold_rx_buffer() is called in the endpoint callback to hold current rx buffer and call rpmsg_release_rx_buffer() to release this buffer immediately, this rx buffer will be returned to the virtqueue twice: 1. the first time is in rpmsg_virtio_release_rx_buffer() 2. and the second time is in rpmsg_virtio_return_buffer() after ept->cb() Follow shows this process: rpmsg_virtio_rx_callback() - get rp_hdr - ept->cb(data = RPMSG_LOCATE_DATA(rp_hdr)) - rpsmg_hold_rx_buffer(data) - rpmsg_release_rx_buffer(data) return buffer to virtqueue - rpmsg_virtio_return_buffer(data) return same buffer to virtqueue again So this commit changes the HELD flag in rp_hdr to count to avoid this use case and also supports hold/release rx buffer recursively. Signed-off-by: Guiding Li <[email protected]> Signed-off-by: Yin Tao <[email protected]> Signed-off-by: Bowen Wang <[email protected]>
1 parent 62a003d commit b32187e

File tree

2 files changed

+84
-30
lines changed

2 files changed

+84
-30
lines changed

lib/rpmsg/rpmsg_internal.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ extern "C" {
2828
#define RPMSG_ASSERT(_exp, _msg) metal_assert(_exp)
2929
#endif
3030

31-
#define RPMSG_BUF_HELD (1U << 31) /* Flag to suggest to hold the buffer */
31+
/* Mask to get the rpmsg buffer held counter from rpmsg_hdr reserved field */
32+
#define RPMSG_BUF_HELD_SHIFT 16
33+
#define RPMSG_BUF_HELD_MASK (0xFFFFU << RPMSG_BUF_HELD_SHIFT)
3234

3335
#define RPMSG_LOCATE_HDR(p) \
3436
((struct rpmsg_hdr *)((unsigned char *)(p) - sizeof(struct rpmsg_hdr)))

lib/rpmsg/rpmsg_virtio.c

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@
2424
/* Time to wait - In multiple of 1 msecs. */
2525
#define RPMSG_TICKS_PER_INTERVAL 1000
2626

27+
/*
28+
* Get the buffer held counter value.
29+
* If 0 the buffer can be released
30+
*/
31+
#define RPMSG_BUF_HELD_COUNTER(rp_hdr) \
32+
(((rp_hdr)->reserved & RPMSG_BUF_HELD_MASK) >> RPMSG_BUF_HELD_SHIFT)
33+
34+
/* Increase buffer held counter */
35+
#define RPMSG_BUF_HELD_INC(rp_hdr) \
36+
((rp_hdr)->reserved += 1 << RPMSG_BUF_HELD_SHIFT)
37+
38+
/* Decrease buffer held counter */
39+
#define RPMSG_BUF_HELD_DEC(rp_hdr) \
40+
((rp_hdr)->reserved -= 1 << RPMSG_BUF_HELD_SHIFT)
41+
42+
/* Get the buffer index */
43+
#define RPMSG_BUF_INDEX(rphdr) \
44+
((uint16_t)((rp_hdr)->reserved & ~RPMSG_BUF_HELD_MASK))
45+
2746
/**
2847
* struct vbuff_reclaimer_t - vring buffer recycler
2948
*
@@ -272,37 +291,70 @@ static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev)
272291
}
273292
#endif /*!VIRTIO_DRIVER_ONLY*/
274293

294+
/**
295+
* @internal
296+
*
297+
* @brief Check whether rpmsg buffer needs to be released or not
298+
*
299+
* @param rp_hdr Pointer to rpmsg buffer header
300+
*
301+
* @return true indicates this buffer needs to be released
302+
*/
303+
static bool rpmsg_virtio_buf_held_dec_test(struct rpmsg_hdr *rp_hdr)
304+
{
305+
/* Check the held counter first */
306+
if (RPMSG_BUF_HELD_COUNTER(rp_hdr) <= 0) {
307+
metal_err("unexpected buffer held counter\r\n");
308+
return false;
309+
}
310+
311+
/* Decrease the held counter */
312+
RPMSG_BUF_HELD_DEC(rp_hdr);
313+
314+
/* Check whether to release the buffer */
315+
if (RPMSG_BUF_HELD_COUNTER(rp_hdr) > 0)
316+
return false;
317+
318+
return true;
319+
}
320+
275321
static void rpmsg_virtio_hold_rx_buffer(struct rpmsg_device *rdev, void *rxbuf)
276322
{
277-
struct rpmsg_hdr *rp_hdr;
323+
metal_mutex_acquire(&rdev->lock);
324+
RPMSG_BUF_HELD_INC(RPMSG_LOCATE_HDR(rxbuf));
325+
metal_mutex_release(&rdev->lock);
326+
}
278327

279-
(void)rdev;
328+
static bool rpmsg_virtio_release_rx_buffer_nolock(struct rpmsg_virtio_device *rvdev,
329+
struct rpmsg_hdr *rp_hdr)
330+
{
331+
uint16_t idx;
332+
uint32_t len;
280333

281-
rp_hdr = RPMSG_LOCATE_HDR(rxbuf);
334+
/* The reserved field contains buffer index */
335+
idx = RPMSG_BUF_INDEX(rp_hdr);
336+
/* Return buffer on virtqueue. */
337+
len = virtqueue_get_buffer_length(rvdev->rvq, idx);
338+
rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx);
282339

283-
/* Set held status to keep buffer */
284-
rp_hdr->reserved |= RPMSG_BUF_HELD;
340+
return true;
285341
}
286342

287343
static void rpmsg_virtio_release_rx_buffer(struct rpmsg_device *rdev,
288344
void *rxbuf)
289345
{
290346
struct rpmsg_virtio_device *rvdev;
291347
struct rpmsg_hdr *rp_hdr;
292-
uint16_t idx;
293-
uint32_t len;
294348

295349
rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev);
296350
rp_hdr = RPMSG_LOCATE_HDR(rxbuf);
297-
/* The reserved field contains buffer index */
298-
idx = (uint16_t)(rp_hdr->reserved & ~RPMSG_BUF_HELD);
299351

300352
metal_mutex_acquire(&rdev->lock);
301-
/* Return buffer on virtqueue. */
302-
len = virtqueue_get_buffer_length(rvdev->rvq, idx);
303-
rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx);
304-
/* Tell peer we return some rx buffers */
305-
virtqueue_kick(rvdev->rvq);
353+
if (rpmsg_virtio_buf_held_dec_test(rp_hdr)) {
354+
rpmsg_virtio_release_rx_buffer_nolock(rvdev, rp_hdr);
355+
/* Tell peer we return some rx buffers */
356+
virtqueue_kick(rvdev->rvq);
357+
}
306358
metal_mutex_release(&rdev->lock);
307359
}
308360

@@ -361,6 +413,9 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev,
361413
/* Store the index into the reserved field to be used when sending */
362414
rp_hdr->reserved = idx;
363415

416+
/* Increase the held counter to hold this Tx buffer */
417+
RPMSG_BUF_HELD_INC(rp_hdr);
418+
364419
/* Actual data buffer size is vring buffer size minus header length */
365420
*len -= sizeof(struct rpmsg_hdr);
366421
return RPMSG_LOCATE_DATA(rp_hdr);
@@ -424,20 +479,20 @@ static int rpmsg_virtio_release_tx_buffer(struct rpmsg_device *rdev, void *txbuf
424479
struct rpmsg_hdr *rp_hdr = RPMSG_LOCATE_HDR(txbuf);
425480
void *vbuff = rp_hdr; /* only used to avoid warning on the cast of a packed structure */
426481
struct vbuff_reclaimer_t *r_desc = (struct vbuff_reclaimer_t *)vbuff;
427-
uint16_t idx;
428-
429-
/*
430-
* Reuse the RPMsg buffer to temporary store the vbuff_reclaimer_t structure.
431-
* Stores the index locally before overwriting the RPMsg header.
432-
*/
433-
idx = rp_hdr->reserved;
434482

435483
rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev);
436484

437485
metal_mutex_acquire(&rdev->lock);
438486

439-
r_desc->idx = idx;
440-
metal_list_add_tail(&rvdev->reclaimer, &r_desc->node);
487+
/* Check whether to release the Tx buffer */
488+
if (rpmsg_virtio_buf_held_dec_test(rp_hdr)) {
489+
/*
490+
* Reuse the RPMsg buffer to temporary store the vbuff_reclaimer_t structure.
491+
* Store the index locally before overwriting the RPMsg header.
492+
*/
493+
r_desc->idx = RPMSG_BUF_INDEX(rp_hdr);
494+
metal_list_add_tail(&rvdev->reclaimer, &r_desc->node);
495+
}
441496

442497
metal_mutex_release(&rdev->lock);
443498

@@ -534,6 +589,7 @@ static void rpmsg_virtio_rx_callback(struct virtqueue *vq)
534589
metal_mutex_acquire(&rdev->lock);
535590
ept = rpmsg_get_ept_from_addr(rdev, rp_hdr->dst);
536591
rpmsg_ept_incref(ept);
592+
RPMSG_BUF_HELD_INC(rp_hdr);
537593
metal_mutex_release(&rdev->lock);
538594

539595
if (ept) {
@@ -553,12 +609,8 @@ static void rpmsg_virtio_rx_callback(struct virtqueue *vq)
553609

554610
metal_mutex_acquire(&rdev->lock);
555611
rpmsg_ept_decref(ept);
556-
557-
/* Check whether callback wants to hold buffer */
558-
if (!(rp_hdr->reserved & RPMSG_BUF_HELD)) {
559-
/* No, return used buffers. */
560-
rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx);
561-
}
612+
if (rpmsg_virtio_buf_held_dec_test(rp_hdr))
613+
rpmsg_virtio_release_rx_buffer_nolock(rvdev, rp_hdr);
562614

563615
rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx);
564616
if (!rp_hdr) {

0 commit comments

Comments
 (0)