mirror of
https://github.com/apache/nuttx.git
synced 2026-05-28 03:45:50 +08:00
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 <wengzhe@xiaomi.com>
This commit is contained in:
+78
-57
@@ -40,6 +40,8 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Virtio net feature bits */
|
||||||
|
|
||||||
#define VIRTIO_NET_F_MAC 5
|
#define VIRTIO_NET_F_MAC 5
|
||||||
|
|
||||||
/* Virtio net header size and packet buffer size */
|
/* Virtio net header size and packet buffer size */
|
||||||
@@ -193,6 +195,77 @@ static const struct netdev_ops_s g_virtio_net_ops =
|
|||||||
* Private Functions
|
* 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
|
* 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 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 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;
|
FAR netpkt_t *pkt;
|
||||||
int iov_cnt;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < priv->bufnum; i++)
|
for (i = 0; i < priv->bufnum; i++)
|
||||||
@@ -229,30 +298,9 @@ static void virtio_net_rxfill(FAR struct netdev_lowerhalf_s *dev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert netpkt to virtqueue_buf */
|
/* Add buffer to RX virtqueue */
|
||||||
|
|
||||||
iov_cnt = netpkt_to_iov(dev, pkt, iov, VIRTIO_NET_MAX_NIOB);
|
virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_RX);
|
||||||
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 */
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i > 0)
|
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 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 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 */
|
/* Check the send length */
|
||||||
|
|
||||||
@@ -374,32 +417,9 @@ static int virtio_net_send(FAR struct netdev_lowerhalf_s *dev,
|
|||||||
return -EINVAL;
|
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 */
|
/* Add buffer to vq and notify the other side */
|
||||||
|
|
||||||
vrtinfo("Send, hdr=%p, count=%d\n", hdr, iov_cnt);
|
virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_TX);
|
||||||
virtqueue_add_buffer(vq, vb, iov_cnt, 0, hdr);
|
|
||||||
virtqueue_kick(vq);
|
virtqueue_kick(vq);
|
||||||
|
|
||||||
/* Try return Netpkt TX buffer to upper-half. */
|
/* 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 */
|
/* Initialize the virtio device */
|
||||||
|
|
||||||
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER);
|
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);
|
virtio_set_status(vdev, VIRTIO_CONFIG_FEATURES_OK);
|
||||||
|
|
||||||
vqnames[VIRTIO_NET_RX] = "virtio_net_rx";
|
vqnames[VIRTIO_NET_RX] = "virtio_net_rx";
|
||||||
|
|||||||
@@ -38,6 +38,12 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Virtio common feature bits */
|
||||||
|
|
||||||
|
#define VIRTIO_F_ANY_LAYOUT 27
|
||||||
|
|
||||||
|
/* Virtio helper functions */
|
||||||
|
|
||||||
#define virtio_has_feature(vdev, fbit) \
|
#define virtio_has_feature(vdev, fbit) \
|
||||||
(((vdev)->features & (1UL << (fbit))) != 0)
|
(((vdev)->features & (1UL << (fbit))) != 0)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user