[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v3 2/4] lib/uknetdev: Flag-based status report on rx and tx functions
Introduce flag based status return codes on receive and transmit functions. They are replacing the current enum-like return codes. The flags are able to inform the API user about additional driver states (e.g., queue underruns). Signed-off-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> --- lib/uknetdev/include/uk/netdev.h | 107 ++++++++++++++++++++++---- lib/uknetdev/include/uk/netdev_core.h | 11 +++ plat/drivers/virtio/virtio_net.c | 91 +++++++++++++--------- 3 files changed, 158 insertions(+), 51 deletions(-) diff --git a/lib/uknetdev/include/uk/netdev.h b/lib/uknetdev/include/uk/netdev.h index 18878400..88b89135 100644 --- a/lib/uknetdev/include/uk/netdev.h +++ b/lib/uknetdev/include/uk/netdev.h @@ -438,12 +438,18 @@ static inline int uk_netdev_rxq_intr_disable(struct uk_netdev *dev, * Reference to netbuf pointer which will be point to the received packet * after the function call. `pkt` has never to be `NULL`. * @return - * - (0): No packet available - * - (1): `pkt` points to received netbuf - * - (2): `pkt` points to received netbuf but more received packets are - * available on the receive queue. When interrupts are used, they are - * disabled until 1 is returned on subsequent calls - * - (<0): Error code from driver + * - (>=0): Positive value with status flags + * - UK_NETDEV_STATUS_SUCCESS: `pkt` points to received netbuf. Whenever + * this flag is not set, there was no packet received. + * - UK_NETDEV_STATUS_MORE: Indicates that more received packets are + * available on the receive queue. When interrupts are used, they are + * disabled until this flag is unset by a subsequent call. + * This flag may only be set together with UK_NETDEV_STATUS_SUCCESS. + * - UK_NETDEV_STATUS_UNDERRUN: Informs that some available slots of the + * receive queue could not be programmed with a receive buffer. The + * user-provided receive buffer allocator function returned with an error + * (e.g., out of memory). + * - (<0): Negative value with error code from driver, no packet is returned. */ static inline int uk_netdev_rx_one(struct uk_netdev *dev, uint16_t queue_id, struct uk_netbuf **pkt) @@ -474,13 +480,15 @@ static inline int uk_netdev_rx_one(struct uk_netdev *dev, uint16_t queue_id, * for doing a transmission - inspect `nb_encap` with uk_netdev_info_get(). * `pkt` has never to be `NULL`. * @return - * - (0): No space left on transmit queue, `pkt` is not sent - * - (1): `pkt` was successfully put to the transmit queue, - * queue is currently full - * - (2): `pkt` was successfully put to the transmit queue, - * there is still at least one descriptor available for a - * subsequent transmission - * - (<0): Error code from driver, `pkt` is not sent + * - (>=0): Positive value with status flags + * - UK_NETDEV_STATUS_SUCCESS: `pkt` was successfully put to the transmit + * queue. Whenever this flag is not set, there was no space left on the + * transmit queue to send `pkt`. + * - UK_NETDEV_STATUS_MORE: Indicates there is still at least one descriptor + * available for a subsequent transmission. If the flag is unset means + * that the transmit queue is full. + * This flag may only be set together with UK_NETDEV_STATUS_SUCCESS. + * - (<0): Negative value with error code from driver, no packet was sent. */ static inline int uk_netdev_tx_one(struct uk_netdev *dev, uint16_t queue_id, struct uk_netbuf *pkt) @@ -495,6 +503,79 @@ static inline int uk_netdev_tx_one(struct uk_netdev *dev, uint16_t queue_id, return dev->tx_one(dev, dev->_tx_queue[queue_id], pkt); } +/** + * Tests for status flags returned by `uk_netdev_rx_one` or `uk_netdev_tx_one`. + * When the functions returned an error code or one of the selected flags is + * unset, this macro returns False. + * + * @param status + * Return status (int) + * @param flag + * Flag(s) to test + * @return + * - (True): All flags are set and status is not negative + * - (False): At least one flag is not set or status is negative + */ +#define uk_netdev_status_test_set(status, flag) \ + (((int)(status) & ((int)(flag) | INT_MIN)) == (flag)) + +/** + * Tests for unset status flags returned by `uk_netdev_rx_one` or + * `uk_netdev_tx_one`. When the functions returned an error code or one of the + * selected the flags is set, this macro returns False. + * + * @param status + * Return status (int) + * @param flag + * Flag(s) to test + * @return + * - (True): Flags are not set and status is not negative + * - (False): At least one flag is set or status is negative + */ +#define uk_netdev_status_test_unset(status, flag) \ + (((int)(status) & ((int)(flag) | INT_MIN)) == (0x0)) + +/** + * Tests if the return status of `uk_netdev_rx_one` or `uk_netdev_tx_one` + * indicates a successful operation (e.g., packet sent or received). + * + * @param status + * Return status (int) + * @return + * - (True): Operation was successful + * - (False): Operation was unsuccessful or error happend + */ +#define uk_netdev_status_successful(status) \ + uk_netdev_status_test_set((status), UK_NETDEV_STATUS_SUCCESS) + +/** + * Tests if the return status of `uk_netdev_rx_one` or `uk_netdev_tx_one` + * indicates that the operation should be retried (e.g., packet sent or + * received). + * + * @param status + * Return status (int) + * @return + * - (True): Operation should be retried + * - (False): Operation was successful or error happened + */ +#define uk_netdev_status_notready(status) \ + uk_netdev_status_test_unset((status), UK_NETDEV_STATUS_SUCCESS) + +/** + * Tests if the return status of `uk_netdev_rx_one` or `uk_netdev_tx_one` + * indicates that the last operation can be successfully repeatet again. + * + * @param status + * Return status (int) + * @return + * - (True): Flag UK_NETDEV_STATUS_MORE is set + * - (False): Operation was successful or error happened + */ +#define uk_netdev_status_more(status) \ + uk_netdev_status_test_set((status), (UK_NETDEV_STATUS_SUCCESS \ + | UK_NETDEV_STATUS_MORE)) + #ifdef __cplusplus } #endif diff --git a/lib/uknetdev/include/uk/netdev_core.h b/lib/uknetdev/include/uk/netdev_core.h index d30886de..f877f1e7 100644 --- a/lib/uknetdev/include/uk/netdev_core.h +++ b/lib/uknetdev/include/uk/netdev_core.h @@ -285,6 +285,17 @@ typedef int (*uk_netdev_rxq_intr_enable_t)(struct uk_netdev *dev, typedef int (*uk_netdev_rxq_intr_disable_t)(struct uk_netdev *dev, struct uk_netdev_rx_queue *queue); +/** + * Status code flags returned by rx and tx functions + */ +/** Successful operation (packet received or transmitted). */ +#define UK_NETDEV_STATUS_SUCCESS (0x1) +/** More room available for operation (e.g., still space on queue for sending + or more packets available on receive queue */ +#define UK_NETDEV_STATUS_MORE (0x2) +/** Queue underrun (e.g., out-of-memory when allocating new receive buffers). */ +#define UK_NETDEV_STATUS_UNDERRUN (0x4) + /** Driver callback type to retrieve one packet from a RX queue. */ typedef int (*uk_netdev_rx_one_t)(struct uk_netdev *dev, struct uk_netdev_rx_queue *queue, diff --git a/plat/drivers/virtio/virtio_net.c b/plat/drivers/virtio/virtio_net.c index 24ef63b0..cb771efe 100644 --- a/plat/drivers/virtio/virtio_net.c +++ b/plat/drivers/virtio/virtio_net.c @@ -213,8 +213,8 @@ static int virtio_netdev_rxq_dequeue(struct uk_netdev_rx_queue *rxq, static int virtio_netdev_rxq_enqueue(struct uk_netdev_rx_queue *rxq, struct uk_netbuf *netbuf); static int virtio_netdev_recv_done(struct virtqueue *vq, void *priv); -static void virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq, - __u16 num, int notify); +static int virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq, + __u16 num, int notify); /** * Static global constants @@ -268,12 +268,13 @@ static void virtio_netdev_xmit_free(struct uk_netdev_tx_queue *txq) #define RX_FILLUP_BATCHLEN 64 -static void virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq, - __u16 nb_desc, - int notify) +static int virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq, + __u16 nb_desc, + int notify) { struct uk_netbuf *netbuf[RX_FILLUP_BATCHLEN]; int rc = 0; + int status = 0x0; __u16 i, j; __u16 req; __u16 cnt = 0; @@ -305,7 +306,8 @@ static void virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq, */ for (j = i; j < cnt; j++) uk_netbuf_free(netbuf[j]); - return; + status |= UK_NETDEV_STATUS_UNDERRUN; + return status; } filled += 2; } @@ -313,6 +315,7 @@ static void virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq, if (unlikely(cnt < req)) { uk_pr_debug("Incomplete fill-up of netbufs on receive virtqueue %p: Out of memory", rxq); + status |= UK_NETDEV_STATUS_UNDERRUN; goto out; } } @@ -326,6 +329,8 @@ out: */ if (notify && filled) virtqueue_host_notify(rxq->vq); + + return status; } static int virtio_netdev_xmit(struct uk_netdev *dev, @@ -337,6 +342,7 @@ static int virtio_netdev_xmit(struct uk_netdev *dev, struct virtio_net_hdr_padded *padded_hdr; int16_t header_sz = sizeof(*padded_hdr); int rc = 0; + int status = 0x0; size_t total_len = 0; __u8 *buf_start; size_t buf_len; @@ -361,7 +367,7 @@ static int virtio_netdev_xmit(struct uk_netdev *dev, if (unlikely(rc != 1)) { uk_pr_err("Failed to prepend virtio header\n"); rc = -ENOSPC; - goto exit; + goto err_exit; } vhdr = pkt->data; @@ -388,18 +394,18 @@ static int virtio_netdev_xmit(struct uk_netdev *dev, rc = uk_sglist_append(&queue->sg, vhdr, sizeof(*vhdr)); if (unlikely(rc != 0)) { uk_pr_err("Failed to append to the sg list\n"); - goto exit; + goto err_remove_vhdr; } rc = uk_sglist_append(&queue->sg, buf_start, buf_len); if (unlikely(rc != 0)) { uk_pr_err("Failed to append to the sg list\n"); - goto exit; + goto err_remove_vhdr; } if (pkt->next) { rc = uk_sglist_append_netbuf(&queue->sg, pkt->next); if (unlikely(rc != 0)) { uk_pr_err("Failed to append to the sg list\n"); - goto exit; + goto err_remove_vhdr; } } @@ -408,7 +414,7 @@ static int virtio_netdev_xmit(struct uk_netdev *dev, uk_pr_err("Packet size too big: %lu, max:%u\n", total_len, VIRTIO_PKT_BUFFER_LEN); rc = -ENOTSUP; - goto remove_vhdr; + goto err_remove_vhdr; } /** @@ -417,31 +423,34 @@ static int virtio_netdev_xmit(struct uk_netdev *dev, rc = virtqueue_buffer_enqueue(queue->vq, pkt, &queue->sg, queue->sg.sg_nseg, 0); if (likely(rc >= 0)) { + status |= UK_NETDEV_STATUS_SUCCESS; /** * Notify the host the new buffer. */ virtqueue_host_notify(queue->vq); /** * When there is further space available in the ring - * return 2 else 1. + * return UK_NETDEV_STATUS_MORE. */ - rc = likely(rc > 0) ? 2 : 1; + status |= likely(rc > 0) ? UK_NETDEV_STATUS_MORE : 0x0; } else if (rc == -ENOSPC) { uk_pr_debug("No more descriptor available\n"); - rc = 0; - goto remove_vhdr; + /** + * Remove header before exiting because we could not send + */ + uk_netbuf_header(pkt, -header_sz); } else { uk_pr_err("Failed to enqueue descriptors into the ring: %d\n", rc); - goto remove_vhdr; + goto err_remove_vhdr; } + return status; -exit: - return rc; - -remove_vhdr: +err_remove_vhdr: uk_netbuf_header(pkt, -header_sz); - goto exit; +err_exit: + UK_ASSERT(rc < 0); + return rc; } static int virtio_netdev_rxq_enqueue(struct uk_netdev_rx_queue *rxq, @@ -529,8 +538,8 @@ static int virtio_netdev_recv(struct uk_netdev *dev, struct uk_netdev_rx_queue *queue, struct uk_netbuf **pkt) { + int status = 0x0; int rc = 0; - int cnt = 0; UK_ASSERT(dev && queue); UK_ASSERT(pkt); @@ -545,14 +554,14 @@ static int virtio_netdev_recv(struct uk_netdev *dev, uk_pr_err("Failed to dequeue the packet: %d\n", rc); goto err_exit; } - cnt = (*pkt) ? 1 : 0; - virtio_netdev_rx_fillup(queue, (queue->nb_desc - rc), 1); + status |= (*pkt) ? UK_NETDEV_STATUS_SUCCESS : 0x0; + status |= virtio_netdev_rx_fillup(queue, (queue->nb_desc - rc), 1); /* Enable interrupt only when user had previously enabled it */ if (queue->intr_enabled & VTNET_INTR_USR_EN_MASK) { /* Need to enable the interrupt on the last packet */ rc = virtqueue_intr_enable(queue->vq); - if (rc == 1 && cnt == 0) { + if (rc == 1 && !(*pkt)) { /** * Packet arrive after reading the queue and before * enabling the interrupt @@ -563,29 +572,35 @@ static int virtio_netdev_recv(struct uk_netdev *dev, rc); goto err_exit; } + status |= UK_NETDEV_STATUS_SUCCESS; + /* Need to enable the interrupt on the last packet */ rc = virtqueue_intr_enable(queue->vq); - cnt = (rc == 1) ? 2 : 1; - /* Since we received something, we need to fillup */ - virtio_netdev_rx_fillup(queue, (queue->nb_desc - rc), 1); - } else if (cnt > 0) { - /* When there is packet in the buffer */ - cnt = (rc == 1) ? 2 : 1; + status |= (rc == 1) ? UK_NETDEV_STATUS_MORE : 0x0; + + /* + * Since we received something, we need to fillup + * and notify + */ + status |= virtio_netdev_rx_fillup(queue, + (queue->nb_desc - rc), + 1); + } else if (*pkt) { + /* When we originally got a packet and there is more */ + status |= (rc == 1) ? UK_NETDEV_STATUS_MORE : 0x0; } - } else if (cnt > 0) { + } else if (*pkt) { /** * For polling case, we report always there are further * packets unless the queue is empty. */ - cnt = 2; + status |= UK_NETDEV_STATUS_MORE; } - -exit: - return cnt; + return status; err_exit: - cnt = rc; - goto exit; + UK_ASSERT(rc < 0); + return rc; } static struct uk_netdev_rx_queue *virtio_netdev_rx_queue_setup( -- 2.17.2 (Apple Git-113) _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |