|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [UNIKRAFT PATCH v4 06/12] plat/xen/drivers/net: Configure netfront tx queue
Hi Sharan,
Please see inline.
On 10/22/20 2:53 PM, Sharan Santhanam wrote:
> Hello Costin,
>
> Please find the comments inline:
>
> Thanks & Regards
>
> Sharan
>
> On 8/13/20 10:53 AM, Costin Lupu wrote:
>> 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 | 108 ++++++++++++++++++++++++++++++++
>> plat/xen/drivers/net/netfront.h | 30 +++++++++
>> 2 files changed, 138 insertions(+)
>>
>> diff --git a/plat/xen/drivers/net/netfront.c
>> b/plat/xen/drivers/net/netfront.c
>> index ddbb4b70..3c936743 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,83 @@
>> 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 __unused)
>> +{
>> + 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(drv_allocator, 1);
>
> Shouldn't the allocator from the txqueue_conf be used here while
>
> setting up the ring
>
I see, I wasn't aware of that.
>> + 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(drv_allocator, 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->initialized = true;
>> + nfdev->txqs_num++;
>> +
>> + return txq;
>> +}
>> +
>> static int netfront_rxtx_alloc(struct netfront_dev *nfdev,
>> const struct uk_netdev_conf *conf)
>> {
>> @@ -90,6 +169,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->txqs_num)) {
>
> txqs_num is updated only after the queue is configured. The
>
> txq_info_get should be called before the txq_configure. This
>
> would provide the user of netdev the information needed to
>
> configure the txq.
>
Yeah, nfdev->max_queue_pairs should make more sense.
>> + 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 = PAGE_SIZE;
>> + qinfo->nb_is_power_of_two = 1;
>> +
>> +exit:
>> + return rc;
>> +}
>> +
>> static int netfront_configure(struct uk_netdev *n,
>> const struct uk_netdev_conf *conf)
>> {
>> @@ -179,6 +285,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..d3f603b3 100644
>> --- a/plat/xen/drivers/net/netfront.h
>> +++ b/plat/xen/drivers/net/netfront.h
>> @@ -37,11 +37,40 @@
>> #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];
>> };
>> /**
>> @@ -63,6 +92,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 */
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |