This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 504af7a1fa drivers/virtio-net: Support VIRTIO_F_ANY_LAYOUT
504af7a1fa is described below
commit 504af7a1fae0bdf76ea42b5235ad9a0ff5466725
Author: Zhe Weng <[email protected]>
AuthorDate: Tue May 21 19:59:49 2024 +0800
drivers/virtio-net: Support VIRTIO_F_ANY_LAYOUT
According to Virtual I/O Spec:
When using legacy interfaces, transitional drivers which have not
negotiated VIRTIO_F_ANY_LAYOUT MUST use a single descriptor for the struct
virtio_net_hdr on both transmit and receive, with the network data in the
following descriptors.
https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-2280006
(Section 5.1.6.6)
Signed-off-by: Zhe Weng <[email protected]>
---
drivers/virtio/virtio-net.c | 135 ++++++++++++++++++++++++------------------
include/nuttx/virtio/virtio.h | 6 ++
2 files changed, 84 insertions(+), 57 deletions(-)
diff --git a/drivers/virtio/virtio-net.c b/drivers/virtio/virtio-net.c
index 93d94818b1..ce0afc88bb 100644
--- a/drivers/virtio/virtio-net.c
+++ b/drivers/virtio/virtio-net.c
@@ -40,6 +40,8 @@
* Pre-processor Definitions
****************************************************************************/
+/* Virtio net feature bits */
+
#define VIRTIO_NET_F_MAC 5
/* Virtio net header size and packet buffer size */
@@ -193,6 +195,77 @@ static const struct netdev_ops_s g_virtio_net_ops =
* Private Functions
****************************************************************************/
+/****************************************************************************
+ * Name: virtio_net_addbuffer
+ ****************************************************************************/
+
+static int virtio_net_addbuffer(FAR struct netdev_lowerhalf_s *dev,
+ FAR struct virtqueue *vq, FAR netpkt_t *pkt,
+ unsigned int vq_id)
+{
+ FAR struct virtio_net_priv_s *priv = (FAR struct virtio_net_priv_s *)dev;
+ FAR struct virtio_net_llhdr_s *hdr;
+ struct virtqueue_buf vb[VIRTIO_NET_MAX_NIOB + 1];
+ struct iovec iov[VIRTIO_NET_MAX_NIOB];
+ int iov_cnt;
+ int i;
+
+ /* Convert netpkt to virtqueue_buf */
+
+ iov_cnt = netpkt_to_iov(dev, pkt, iov, VIRTIO_NET_MAX_NIOB);
+
+ /* Alloc cookie and net header from transport layer */
+
+ hdr = (FAR struct virtio_net_llhdr_s *)
+ ((FAR uint8_t *)iov[0].iov_base - VIRTIO_NET_LLHDRSIZE);
+ DEBUGASSERT((FAR uint8_t *)hdr >= netpkt_getbase(pkt));
+ memset(&hdr->vhdr, 0, sizeof(hdr->vhdr));
+ hdr->pkt = pkt;
+
+ /* Prepare buffers depends on the feature VIRTIO_F_ANY_LAYOUT */
+
+ if (virtio_has_feature(priv->vdev, VIRTIO_F_ANY_LAYOUT))
+ {
+ /* Append the virtio net header to the first buffer */
+
+ vb[0].buf = &hdr->vhdr;
+ vb[0].len = iov[0].iov_len + VIRTIO_NET_HDRSIZE;
+
+#if VIRTIO_NET_MAX_NIOB > 1
+ for (i = 1; i < iov_cnt; i++)
+ {
+ vb[i].buf = iov[i].iov_base;
+ vb[i].len = iov[i].iov_len;
+ }
+#endif
+ }
+ else
+ {
+ /* Buffer 0 is only for virtio net header */
+
+ vb[0].buf = &hdr->vhdr;
+ vb[0].len = VIRTIO_NET_HDRSIZE;
+
+ for (i = 0; i < iov_cnt; i++)
+ {
+ vb[i + 1].buf = iov[i].iov_base;
+ vb[i + 1].len = iov[i].iov_len;
+ }
+
+ iov_cnt++;
+ }
+
+ vrtinfo("Fill vq=%u, hdr=%p, count=%d\n", vq_id, hdr, iov_cnt);
+ if (vq_id == VIRTIO_NET_RX)
+ {
+ return virtqueue_add_buffer(vq, vb, 0, iov_cnt, hdr);
+ }
+ else
+ {
+ return virtqueue_add_buffer(vq, vb, iov_cnt, 0, hdr);
+ }
+}
+
/****************************************************************************
* Name: virtio_net_rxfill
****************************************************************************/
@@ -201,11 +274,7 @@ static void virtio_net_rxfill(FAR struct
netdev_lowerhalf_s *dev)
{
FAR struct virtio_net_priv_s *priv = (FAR struct virtio_net_priv_s *)dev;
FAR struct virtqueue *vq = priv->vdev->vrings_info[VIRTIO_NET_RX].vq;
- FAR struct virtio_net_llhdr_s *hdr;
- struct virtqueue_buf vb[VIRTIO_NET_MAX_NIOB];
- struct iovec iov[VIRTIO_NET_MAX_NIOB];
FAR netpkt_t *pkt;
- int iov_cnt;
int i;
for (i = 0; i < priv->bufnum; i++)
@@ -229,30 +298,9 @@ static void virtio_net_rxfill(FAR struct
netdev_lowerhalf_s *dev)
break;
}
- /* Convert netpkt to virtqueue_buf */
-
- iov_cnt = netpkt_to_iov(dev, pkt, iov, VIRTIO_NET_MAX_NIOB);
- for (i = 0; i < iov_cnt; i++)
- {
- vb[i].buf = iov[i].iov_base;
- vb[i].len = iov[i].iov_len;
- }
-
- /* Alloc cookie and net header from transport layer */
-
- hdr = (FAR struct virtio_net_llhdr_s *)
- ((FAR uint8_t *)vb[0].buf - VIRTIO_NET_LLHDRSIZE);
- DEBUGASSERT((FAR uint8_t *)hdr >= netpkt_getbase(pkt));
- memset(&hdr->vhdr, 0, sizeof(hdr->vhdr));
- hdr->pkt = pkt;
-
- /* Buffer 0, the virtio net header */
+ /* Add buffer to RX virtqueue */
- vb[0].buf = &hdr->vhdr;
- vb[0].len += VIRTIO_NET_HDRSIZE;
-
- vrtinfo("Fill rx, hdr=%p, count=%d\n", hdr, iov_cnt);
- virtqueue_add_buffer(vq, vb, 0, iov_cnt, hdr);
+ virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_RX);
}
if (i > 0)
@@ -360,11 +408,6 @@ static int virtio_net_send(FAR struct netdev_lowerhalf_s
*dev,
{
FAR struct virtio_net_priv_s *priv = (FAR struct virtio_net_priv_s *)dev;
FAR struct virtqueue *vq = priv->vdev->vrings_info[VIRTIO_NET_TX].vq;
- FAR struct virtio_net_llhdr_s *hdr;
- struct virtqueue_buf vb[VIRTIO_NET_MAX_NIOB];
- struct iovec iov[VIRTIO_NET_MAX_NIOB];
- int iov_cnt;
- int i;
/* Check the send length */
@@ -374,32 +417,9 @@ static int virtio_net_send(FAR struct netdev_lowerhalf_s
*dev,
return -EINVAL;
}
- /* Convert netpkt to virtqueue_buf */
-
- iov_cnt = netpkt_to_iov(dev, pkt, iov, VIRTIO_NET_MAX_NIOB);
- for (i = 0; i < iov_cnt; i++)
- {
- vb[i].buf = iov[i].iov_base;
- vb[i].len = iov[i].iov_len;
- }
-
- /* Prepare virtio net header */
-
- hdr = (FAR struct virtio_net_llhdr_s *)
- ((FAR uint8_t *)vb[0].buf - VIRTIO_NET_LLHDRSIZE);
- DEBUGASSERT((FAR uint8_t *)hdr >= netpkt_getbase(pkt));
- hdr->pkt = pkt;
- memset(&hdr->vhdr, 0, sizeof(hdr->vhdr));
-
- /* Buffer 0 is the virtio net header */
-
- vb[0].buf = &hdr->vhdr;
- vb[0].len += VIRTIO_NET_HDRSIZE;
-
/* Add buffer to vq and notify the other side */
- vrtinfo("Send, hdr=%p, count=%d\n", hdr, iov_cnt);
- virtqueue_add_buffer(vq, vb, iov_cnt, 0, hdr);
+ virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_TX);
virtqueue_kick(vq);
/* Try return Netpkt TX buffer to upper-half. */
@@ -534,7 +554,8 @@ static int virtio_net_init(FAR struct virtio_net_priv_s
*priv,
/* Initialize the virtio device */
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER);
- virtio_negotiate_features(vdev, 1 << VIRTIO_NET_F_MAC);
+ virtio_negotiate_features(vdev, (1UL << VIRTIO_NET_F_MAC) |
+ (1UL << VIRTIO_F_ANY_LAYOUT));
virtio_set_status(vdev, VIRTIO_CONFIG_FEATURES_OK);
vqnames[VIRTIO_NET_RX] = "virtio_net_rx";
diff --git a/include/nuttx/virtio/virtio.h b/include/nuttx/virtio/virtio.h
index 061cb04f55..7ad756b527 100644
--- a/include/nuttx/virtio/virtio.h
+++ b/include/nuttx/virtio/virtio.h
@@ -38,6 +38,12 @@
* Pre-processor Definitions
****************************************************************************/
+/* Virtio common feature bits */
+
+#define VIRTIO_F_ANY_LAYOUT 27
+
+/* Virtio helper functions */
+
#define virtio_has_feature(vdev, fbit) \
(((vdev)->features & (1UL << (fbit))) != 0)