[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[UNIKRAFT PATCH v5 05/10] plat/xen/drivers/net: Configure netfront tx queue



For each queue, either rx or tx, the packets references are kept in a Xen
shared ring. This patch introduces the initialization of tx shared ring. Each
time the driver will send a packet it will add a request on the tx shared ring
which will be serviced by the backend. Therefore we need to keep track of the
requests by keeping track of their IDs. Because our resources are limited, we
will maintain a pool of IDs (see `freelist` array) for this purpose.

Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx>
Signed-off-by: Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx>
---
 plat/xen/drivers/net/netfront.c | 109 ++++++++++++++++++++++++++++++++
 plat/xen/drivers/net/netfront.h |  32 ++++++++++
 2 files changed, 141 insertions(+)

diff --git a/plat/xen/drivers/net/netfront.c b/plat/xen/drivers/net/netfront.c
index 47ad4865..c9e09184 100644
--- a/plat/xen/drivers/net/netfront.c
+++ b/plat/xen/drivers/net/netfront.c
@@ -33,10 +33,12 @@
  * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
  */
 
+#include <string.h>
 #include <uk/assert.h>
 #include <uk/print.h>
 #include <uk/alloc.h>
 #include <uk/netdev_driver.h>
+#include <xen-x86/mm.h>
 #include <xenbus/xenbus.h>
 #include "netfront.h"
 #include "netfront_xb.h"
@@ -49,6 +51,84 @@
 
 static struct uk_alloc *drv_allocator;
 
+
+static void add_id_to_freelist(uint16_t id, uint16_t *freelist)
+{
+       freelist[id + 1] = freelist[0];
+       freelist[0]  = id;
+}
+
+static uint16_t get_id_from_freelist(uint16_t *freelist)
+{
+       uint16_t id;
+
+       id = freelist[0];
+       freelist[0] = freelist[id + 1];
+       return id;
+}
+
+static struct uk_netdev_tx_queue *netfront_txq_setup(struct uk_netdev *n,
+               uint16_t queue_id,
+               uint16_t nb_desc __unused,
+               struct uk_netdev_txqueue_conf *conf)
+{
+       int rc;
+       struct netfront_dev *nfdev;
+       struct uk_netdev_tx_queue *txq;
+       netif_tx_sring_t *sring;
+
+       UK_ASSERT(n != NULL);
+
+       nfdev = to_netfront_dev(n);
+       if (queue_id >= nfdev->max_queue_pairs) {
+               uk_pr_err("Invalid queue identifier: %"__PRIu16"\n", queue_id);
+               return ERR2PTR(-EINVAL);
+       }
+
+       txq  = &nfdev->txqs[queue_id];
+       UK_ASSERT(!txq->initialized);
+       txq->netfront_dev = nfdev;
+       txq->lqueue_id = queue_id;
+
+       /* Setup shared ring */
+       sring = uk_palloc(conf->a, 1);
+       if (!sring)
+               return ERR2PTR(-ENOMEM);
+       memset(sring, 0, PAGE_SIZE);
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&txq->ring, sring, PAGE_SIZE);
+       txq->ring_size = NET_TX_RING_SIZE;
+       txq->ring_ref = gnttab_grant_access(nfdev->xendev->otherend_id,
+               virt_to_mfn(sring), 0);
+       UK_ASSERT(txq->ring_ref != GRANT_INVALID_REF);
+
+       /* Setup event channel */
+       rc = evtchn_alloc_unbound(nfdev->xendev->otherend_id,
+                       NULL, NULL,
+                       &txq->evtchn);
+       if (rc) {
+               uk_pr_err("Error creating event channel: %d\n", rc);
+               gnttab_end_access(txq->ring_ref);
+               uk_pfree(conf->a, sring, 1);
+               return ERR2PTR(-rc);
+       }
+       /* Events are always disabled for tx queue */
+       mask_evtchn(txq->evtchn);
+
+       /* Initialize list of request ids */
+       uk_semaphore_init(&txq->sem, NET_TX_RING_SIZE);
+       for (uint16_t i = 0; i < NET_TX_RING_SIZE; i++) {
+               add_id_to_freelist(i, txq->freelist);
+               txq->gref[i] = GRANT_INVALID_REF;
+               txq->netbuf[i] = NULL;
+       }
+
+       txq->initialized = true;
+       nfdev->txqs_num++;
+
+       return txq;
+}
+
 static int netfront_rxtx_alloc(struct netfront_dev *nfdev,
                const struct uk_netdev_conf *conf)
 {
@@ -90,6 +170,33 @@ err_free_txrx:
        return rc;
 }
 
+static int netfront_txq_info_get(struct uk_netdev *n,
+               uint16_t queue_id,
+               struct uk_netdev_queue_info *qinfo)
+{
+       struct netfront_dev *nfdev;
+       struct uk_netdev_tx_queue *txq;
+       int rc = 0;
+
+       UK_ASSERT(n != NULL);
+       UK_ASSERT(qinfo != NULL);
+
+       nfdev = to_netfront_dev(n);
+       if (unlikely(queue_id >= nfdev->max_queue_pairs)) {
+               uk_pr_err("Invalid queue_id %"__PRIu16"\n", queue_id);
+               rc = -EINVAL;
+               goto exit;
+       }
+       txq = &nfdev->txqs[queue_id];
+       qinfo->nb_min = txq->ring_size;
+       qinfo->nb_max = txq->ring_size;
+       qinfo->nb_align = 1;
+       qinfo->nb_is_power_of_two = 1;
+
+exit:
+       return rc;
+}
+
 static int netfront_configure(struct uk_netdev *n,
                const struct uk_netdev_conf *conf)
 {
@@ -181,6 +288,8 @@ static unsigned int netfront_promisc_get(struct uk_netdev 
*n)
 
 static const struct uk_netdev_ops netfront_ops = {
        .configure = netfront_configure,
+       .txq_configure = netfront_txq_setup,
+       .txq_info_get = netfront_txq_info_get,
        .info_get = netfront_info_get,
        .einfo_get = netfront_einfo_get,
        .hwaddr_get = netfront_mac_get,
diff --git a/plat/xen/drivers/net/netfront.h b/plat/xen/drivers/net/netfront.h
index a811b092..2ac20b15 100644
--- a/plat/xen/drivers/net/netfront.h
+++ b/plat/xen/drivers/net/netfront.h
@@ -37,11 +37,42 @@
 #define __NETFRONT_H__
 
 #include <uk/netdev.h>
+#include <uk/semaphore.h>
+#include <xen/io/netif.h>
+#include <common/gnttab.h>
+#include <common/events.h>
+
+
+#define NET_TX_RING_SIZE __CONST_RING_SIZE(netif_tx, PAGE_SIZE)
 
 /**
  * internal structure to represent the transmit queue.
  */
 struct uk_netdev_tx_queue {
+       /* The netfront device */
+       struct netfront_dev *netfront_dev;
+       /* The libuknet queue identifier */
+       uint16_t lqueue_id;
+       /* True if initialized */
+       bool initialized;
+
+       /* Shared ring size */
+       uint16_t ring_size;
+       /* Shared ring */
+       netif_tx_front_ring_t ring;
+       /* Shared ring grant ref */
+       grant_ref_t ring_ref;
+       /* Queue event channel */
+       evtchn_port_t evtchn;
+
+       /* Free list protecting semaphore */
+       struct uk_semaphore sem;
+       /* Free list of transmitting request IDs */
+       uint16_t freelist[NET_TX_RING_SIZE + 1];
+       /* Grants for transmit buffers */
+       grant_ref_t gref[NET_TX_RING_SIZE];
+       /* Transmit packets addresses */
+       struct uk_netbuf *netbuf[NET_TX_RING_SIZE];
 };
 
 /**
@@ -63,6 +94,7 @@ struct netfront_dev {
        struct uk_netdev netdev;
 
        /* List of the Rx/Tx queues */
+       uint16_t txqs_num;
        struct uk_netdev_tx_queue *txqs;
        struct uk_netdev_rx_queue *rxqs;
        /* Maximum number of queue pairs */
-- 
2.20.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.