aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/netmap
diff options
context:
space:
mode:
authorVincenzo Maffione <vmaffione@FreeBSD.org>2019-08-25 20:16:03 +0000
committerVincenzo Maffione <vmaffione@FreeBSD.org>2019-08-25 20:16:03 +0000
commitdf4e516f0f816b8b59819d30e9a52c6f75703dc2 (patch)
treee1a8428a22cc0d0ad56b8a1166c858b93b947b3a /sys/dev/netmap
parent8da08d512350c970787781496090bd7757bc0468 (diff)
Notes
Diffstat (limited to 'sys/dev/netmap')
-rw-r--r--sys/dev/netmap/netmap_pt.c1498
1 files changed, 0 insertions, 1498 deletions
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
deleted file mode 100644
index bf7872ff2a9a..000000000000
--- a/sys/dev/netmap/netmap_pt.c
+++ /dev/null
@@ -1,1498 +0,0 @@
-/*
- * Copyright (C) 2015 Stefano Garzarella
- * Copyright (C) 2016 Vincenzo Maffione
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-/*
- * common headers
- */
-#if defined(__FreeBSD__)
-#include <sys/cdefs.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/types.h>
-#include <sys/selinfo.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <net/if_var.h>
-#include <machine/bus.h>
-
-//#define usleep_range(_1, _2)
-#define usleep_range(_1, _2) \
- pause_sbt("ptnetmap-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE)
-
-#elif defined(linux)
-#include <bsd_glue.h>
-#endif
-
-#include <net/netmap.h>
-#include <dev/netmap/netmap_kern.h>
-#include <net/netmap_virt.h>
-#include <dev/netmap/netmap_mem2.h>
-
-#ifdef WITH_PTNETMAP_HOST
-
-/* RX cycle without receive any packets */
-#define PTN_RX_DRY_CYCLES_MAX 10
-
-/* Limit Batch TX to half ring.
- * Currently disabled, since it does not manage NS_MOREFRAG, which
- * results in random drops in the VALE txsync. */
-//#define PTN_TX_BATCH_LIM(_n) ((_n >> 1))
-
-//#define BUSY_WAIT
-
-#define NETMAP_PT_DEBUG /* Enables communication debugging. */
-#ifdef NETMAP_PT_DEBUG
-#define DBG(x) x
-#else
-#define DBG(x)
-#endif
-
-
-#undef RATE
-//#define RATE /* Enables communication statistics. */
-#ifdef RATE
-#define IFRATE(x) x
-struct rate_batch_stats {
- unsigned long sync;
- unsigned long sync_dry;
- unsigned long pkt;
-};
-
-struct rate_stats {
- unsigned long gtxk; /* Guest --> Host Tx kicks. */
- unsigned long grxk; /* Guest --> Host Rx kicks. */
- unsigned long htxk; /* Host --> Guest Tx kicks. */
- unsigned long hrxk; /* Host --> Guest Rx Kicks. */
- unsigned long btxwu; /* Backend Tx wake-up. */
- unsigned long brxwu; /* Backend Rx wake-up. */
- struct rate_batch_stats txbs;
- struct rate_batch_stats rxbs;
-};
-
-struct rate_context {
- struct timer_list timer;
- struct rate_stats new;
- struct rate_stats old;
-};
-
-#define RATE_PERIOD 2
-static void
-rate_callback(unsigned long arg)
-{
- struct rate_context * ctx = (struct rate_context *)arg;
- struct rate_stats cur = ctx->new;
- struct rate_batch_stats *txbs = &cur.txbs;
- struct rate_batch_stats *rxbs = &cur.rxbs;
- struct rate_batch_stats *txbs_old = &ctx->old.txbs;
- struct rate_batch_stats *rxbs_old = &ctx->old.rxbs;
- uint64_t tx_batch, rx_batch;
- unsigned long txpkts, rxpkts;
- unsigned long gtxk, grxk;
- int r;
-
- txpkts = txbs->pkt - txbs_old->pkt;
- rxpkts = rxbs->pkt - rxbs_old->pkt;
-
- tx_batch = ((txbs->sync - txbs_old->sync) > 0) ?
- txpkts / (txbs->sync - txbs_old->sync): 0;
- rx_batch = ((rxbs->sync - rxbs_old->sync) > 0) ?
- rxpkts / (rxbs->sync - rxbs_old->sync): 0;
-
- /* Fix-up gtxk and grxk estimates. */
- gtxk = (cur.gtxk - ctx->old.gtxk) - (cur.btxwu - ctx->old.btxwu);
- grxk = (cur.grxk - ctx->old.grxk) - (cur.brxwu - ctx->old.brxwu);
-
- printk("txpkts = %lu Hz\n", txpkts/RATE_PERIOD);
- printk("gtxk = %lu Hz\n", gtxk/RATE_PERIOD);
- printk("htxk = %lu Hz\n", (cur.htxk - ctx->old.htxk)/RATE_PERIOD);
- printk("btxw = %lu Hz\n", (cur.btxwu - ctx->old.btxwu)/RATE_PERIOD);
- printk("rxpkts = %lu Hz\n", rxpkts/RATE_PERIOD);
- printk("grxk = %lu Hz\n", grxk/RATE_PERIOD);
- printk("hrxk = %lu Hz\n", (cur.hrxk - ctx->old.hrxk)/RATE_PERIOD);
- printk("brxw = %lu Hz\n", (cur.brxwu - ctx->old.brxwu)/RATE_PERIOD);
- printk("txbatch = %llu avg\n", tx_batch);
- printk("rxbatch = %llu avg\n", rx_batch);
- printk("\n");
-
- ctx->old = cur;
- r = mod_timer(&ctx->timer, jiffies +
- msecs_to_jiffies(RATE_PERIOD * 1000));
- if (unlikely(r))
- D("[ptnetmap] Error: mod_timer()\n");
-}
-
-static void
-rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail,
- uint32_t act_tail, uint32_t num_slots)
-{
- int n = (int)act_tail - pre_tail;
-
- if (n) {
- if (n < 0)
- n += num_slots;
-
- bf->sync++;
- bf->pkt += n;
- } else {
- bf->sync_dry++;
- }
-}
-
-#else /* !RATE */
-#define IFRATE(x)
-#endif /* RATE */
-
-struct ptnetmap_state {
- /* Kthreads. */
- struct nm_kctx **kctxs;
-
- /* Shared memory with the guest (TX/RX) */
- struct ptnet_csb_gh __user *csb_gh;
- struct ptnet_csb_hg __user *csb_hg;
-
- bool stopped;
-
- /* Netmap adapter wrapping the backend. */
- struct netmap_pt_host_adapter *pth_na;
-
- IFRATE(struct rate_context rate_ctx;)
-};
-
-static inline void
-ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring)
-{
- D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
- " rtail: %d head: %d cur: %d tail: %d",
- title, kring->name, kring->nr_hwcur,
- kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
- kring->ring->head, kring->ring->cur, kring->ring->tail);
-}
-
-/*
- * TX functions to set/get and to handle host/guest kick.
- */
-
-
-/* Enable or disable guest --> host kicks. */
-static inline void
-pthg_kick_enable(struct ptnet_csb_hg __user *pthg, uint32_t val)
-{
- CSB_WRITE(pthg, host_need_kick, val);
-}
-
-/* Are guest interrupt enabled or disabled? */
-static inline uint32_t
-ptgh_intr_enabled(struct ptnet_csb_gh __user *ptgh)
-{
- uint32_t v;
-
- CSB_READ(ptgh, guest_need_kick, v);
-
- return v;
-}
-
-/* Handle TX events: from the guest or from the backend */
-static void
-ptnetmap_tx_handler(void *data, int is_kthread)
-{
- struct netmap_kring *kring = data;
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)kring->na->na_private;
- struct ptnetmap_state *ptns = pth_na->ptns;
- struct ptnet_csb_gh __user *ptgh;
- struct ptnet_csb_hg __user *pthg;
- struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
- bool more_txspace = false;
- struct nm_kctx *kth;
- uint32_t num_slots;
- int batch;
- IFRATE(uint32_t pre_tail);
-
- if (unlikely(!ptns)) {
- D("ERROR ptnetmap state is NULL");
- return;
- }
-
- if (unlikely(ptns->stopped)) {
- RD(1, "backend netmap is being stopped");
- return;
- }
-
- if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
- D("ERROR nm_kr_tryget()");
- return;
- }
-
- /* This is a guess, to be fixed in the rate callback. */
- IFRATE(ptns->rate_ctx.new.gtxk++);
-
- /* Get TX ptgh/pthg pointer from the CSB. */
- ptgh = ptns->csb_gh + kring->ring_id;
- pthg = ptns->csb_hg + kring->ring_id;
- kth = ptns->kctxs[kring->ring_id];
-
- num_slots = kring->nkr_num_slots;
-
- /* Disable guest --> host notifications. */
- pthg_kick_enable(pthg, 0);
- /* Copy the guest kring pointers from the CSB */
- ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-
- for (;;) {
- /* If guest moves ahead too fast, let's cut the move so
- * that we don't exceed our batch limit. */
- batch = shadow_ring.head - kring->nr_hwcur;
- if (batch < 0)
- batch += num_slots;
-
-#ifdef PTN_TX_BATCH_LIM
- if (batch > PTN_TX_BATCH_LIM(num_slots)) {
- uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
-
- if (head_lim >= num_slots)
- head_lim -= num_slots;
- ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
- head_lim);
- shadow_ring.head = head_lim;
- batch = PTN_TX_BATCH_LIM(num_slots);
- }
-#endif /* PTN_TX_BATCH_LIM */
-
- if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
- shadow_ring.flags |= NAF_FORCE_RECLAIM;
- }
-
- /* Netmap prologue */
- shadow_ring.tail = kring->rtail;
- if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
- /* Reinit ring and enable notifications. */
- netmap_ring_reinit(kring);
- pthg_kick_enable(pthg, 1);
- break;
- }
-
- if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
- ptnetmap_kring_dump("pre txsync", kring);
- }
-
- IFRATE(pre_tail = kring->rtail);
- if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
- /* Reenable notifications. */
- pthg_kick_enable(pthg, 1);
- D("ERROR txsync()");
- break;
- }
-
- /*
- * Finalize
- * Copy host hwcur and hwtail into the CSB for the guest sync(), and
- * do the nm_sync_finalize.
- */
- ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur,
- kring->nr_hwtail);
- if (kring->rtail != kring->nr_hwtail) {
- /* Some more room available in the parent adapter. */
- kring->rtail = kring->nr_hwtail;
- more_txspace = true;
- }
-
- IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.txbs, pre_tail,
- kring->rtail, num_slots));
-
- if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
- ptnetmap_kring_dump("post txsync", kring);
- }
-
-#ifndef BUSY_WAIT
- /* Interrupt the guest if needed. */
- if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
- /* Disable guest kick to avoid sending unnecessary kicks */
- nm_os_kctx_send_irq(kth);
- IFRATE(ptns->rate_ctx.new.htxk++);
- more_txspace = false;
- }
-#endif
- /* Read CSB to see if there is more work to do. */
- ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
- if (shadow_ring.head == kring->rhead) {
- /*
- * No more packets to transmit. We enable notifications and
- * go to sleep, waiting for a kick from the guest when new
- * new slots are ready for transmission.
- */
- if (is_kthread) {
- usleep_range(1,1);
- }
- /* Reenable notifications. */
- pthg_kick_enable(pthg, 1);
- /* Doublecheck. */
- ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
- if (shadow_ring.head != kring->rhead) {
- /* We won the race condition, there are more packets to
- * transmit. Disable notifications and do another cycle */
- pthg_kick_enable(pthg, 0);
- continue;
- }
- break;
- }
-
- if (nm_kr_txempty(kring)) {
- /* No more available TX slots. We stop waiting for a notification
- * from the backend (netmap_tx_irq). */
- ND(1, "TX ring");
- break;
- }
-#endif
- if (unlikely(ptns->stopped)) {
- D("backend netmap is being stopped");
- break;
- }
- }
-
- nm_kr_put(kring);
-
- if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
- nm_os_kctx_send_irq(kth);
- IFRATE(ptns->rate_ctx.new.htxk++);
- }
-}
-
-/* Called on backend nm_notify when there is no worker thread. */
-static void
-ptnetmap_tx_nothread_notify(void *data)
-{
- struct netmap_kring *kring = data;
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)kring->na->na_private;
- struct ptnetmap_state *ptns = pth_na->ptns;
-
- if (unlikely(!ptns)) {
- D("ERROR ptnetmap state is NULL");
- return;
- }
-
- if (unlikely(ptns->stopped)) {
- D("backend netmap is being stopped");
- return;
- }
-
- /* We cannot access the CSB here (to check ptgh->guest_need_kick),
- * unless we switch address space to the one of the guest. For now
- * we unconditionally inject an interrupt. */
- nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]);
- IFRATE(ptns->rate_ctx.new.htxk++);
- ND(1, "%s interrupt", kring->name);
-}
-
-/*
- * We need RX kicks from the guest when (tail == head-1), where we wait
- * for the guest to refill.
- */
-#ifndef BUSY_WAIT
-static inline int
-ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head)
-{
- return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
- kring->nkr_num_slots - 1));
-}
-#endif /* !BUSY_WAIT */
-
-/* Handle RX events: from the guest or from the backend */
-static void
-ptnetmap_rx_handler(void *data, int is_kthread)
-{
- struct netmap_kring *kring = data;
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)kring->na->na_private;
- struct ptnetmap_state *ptns = pth_na->ptns;
- struct ptnet_csb_gh __user *ptgh;
- struct ptnet_csb_hg __user *pthg;
- struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
- struct nm_kctx *kth;
- uint32_t num_slots;
- int dry_cycles = 0;
- bool some_recvd = false;
- IFRATE(uint32_t pre_tail);
-
- if (unlikely(!ptns || !ptns->pth_na)) {
- D("ERROR ptnetmap state %p, ptnetmap host adapter %p", ptns,
- ptns ? ptns->pth_na : NULL);
- return;
- }
-
- if (unlikely(ptns->stopped)) {
- RD(1, "backend netmap is being stopped");
- return;
- }
-
- if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
- D("ERROR nm_kr_tryget()");
- return;
- }
-
- /* This is a guess, to be fixed in the rate callback. */
- IFRATE(ptns->rate_ctx.new.grxk++);
-
- /* Get RX ptgh and pthg pointers from the CSB. */
- ptgh = ptns->csb_gh + (pth_na->up.num_tx_rings + kring->ring_id);
- pthg = ptns->csb_hg + (pth_na->up.num_tx_rings + kring->ring_id);
- kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id];
-
- num_slots = kring->nkr_num_slots;
-
- /* Disable notifications. */
- pthg_kick_enable(pthg, 0);
- /* Copy the guest kring pointers from the CSB */
- ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-
- for (;;) {
- uint32_t hwtail;
-
- /* Netmap prologue */
- shadow_ring.tail = kring->rtail;
- if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
- /* Reinit ring and enable notifications. */
- netmap_ring_reinit(kring);
- pthg_kick_enable(pthg, 1);
- break;
- }
-
- if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
- ptnetmap_kring_dump("pre rxsync", kring);
- }
-
- IFRATE(pre_tail = kring->rtail);
- if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
- /* Reenable notifications. */
- pthg_kick_enable(pthg, 1);
- D("ERROR rxsync()");
- break;
- }
- /*
- * Finalize
- * Copy host hwcur and hwtail into the CSB for the guest sync()
- */
- hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
- ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur, hwtail);
- if (kring->rtail != hwtail) {
- kring->rtail = hwtail;
- some_recvd = true;
- dry_cycles = 0;
- } else {
- dry_cycles++;
- }
-
- IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.rxbs, pre_tail,
- kring->rtail, num_slots));
-
- if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
- ptnetmap_kring_dump("post rxsync", kring);
- }
-
-#ifndef BUSY_WAIT
- /* Interrupt the guest if needed. */
- if (some_recvd && ptgh_intr_enabled(ptgh)) {
- /* Disable guest kick to avoid sending unnecessary kicks */
- nm_os_kctx_send_irq(kth);
- IFRATE(ptns->rate_ctx.new.hrxk++);
- some_recvd = false;
- }
-#endif
- /* Read CSB to see if there is more work to do. */
- ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
- if (ptnetmap_norxslots(kring, shadow_ring.head)) {
- /*
- * No more slots available for reception. We enable notification and
- * go to sleep, waiting for a kick from the guest when new receive
- * slots are available.
- */
- usleep_range(1,1);
- /* Reenable notifications. */
- pthg_kick_enable(pthg, 1);
- /* Doublecheck. */
- ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
- if (!ptnetmap_norxslots(kring, shadow_ring.head)) {
- /* We won the race condition, more slots are available. Disable
- * notifications and do another cycle. */
- pthg_kick_enable(pthg, 0);
- continue;
- }
- break;
- }
-
- hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
- if (unlikely(hwtail == kring->rhead ||
- dry_cycles >= PTN_RX_DRY_CYCLES_MAX)) {
- /* No more packets to be read from the backend. We stop and
- * wait for a notification from the backend (netmap_rx_irq). */
- ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
- hwtail, kring->rhead, dry_cycles);
- break;
- }
-#endif
- if (unlikely(ptns->stopped)) {
- D("backend netmap is being stopped");
- break;
- }
- }
-
- nm_kr_put(kring);
-
- /* Interrupt the guest if needed. */
- if (some_recvd && ptgh_intr_enabled(ptgh)) {
- nm_os_kctx_send_irq(kth);
- IFRATE(ptns->rate_ctx.new.hrxk++);
- }
-}
-
-#ifdef NETMAP_PT_DEBUG
-static void
-ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
-{
- int k;
-
- D("ptnetmap configuration:");
- D(" CSB @%p@:%p, num_rings=%u, cfgtype %08x", cfg->csb_gh,
- cfg->csb_hg, cfg->num_rings, cfg->cfgtype);
- for (k = 0; k < cfg->num_rings; k++) {
- switch (cfg->cfgtype) {
- case PTNETMAP_CFGTYPE_QEMU: {
- struct ptnetmap_cfgentry_qemu *e =
- (struct ptnetmap_cfgentry_qemu *)(cfg+1) + k;
- D(" ring #%d: ioeventfd=%lu, irqfd=%lu", k,
- (unsigned long)e->ioeventfd,
- (unsigned long)e->irqfd);
- break;
- }
-
- case PTNETMAP_CFGTYPE_BHYVE:
- {
- struct ptnetmap_cfgentry_bhyve *e =
- (struct ptnetmap_cfgentry_bhyve *)(cfg+1) + k;
- D(" ring #%d: wchan=%lu, ioctl_fd=%lu, "
- "ioctl_cmd=%lu, msix_msg_data=%lu, msix_addr=%lu",
- k, (unsigned long)e->wchan,
- (unsigned long)e->ioctl_fd,
- (unsigned long)e->ioctl_cmd,
- (unsigned long)e->ioctl_data.msg_data,
- (unsigned long)e->ioctl_data.addr);
- break;
- }
- }
- }
-
-}
-#endif /* NETMAP_PT_DEBUG */
-
-/* Copy actual state of the host ring into the CSB for the guest init */
-static int
-ptnetmap_kring_snapshot(struct netmap_kring *kring,
- struct ptnet_csb_gh __user *ptgh,
- struct ptnet_csb_hg __user *pthg)
-{
- if (CSB_WRITE(ptgh, head, kring->rhead))
- goto err;
- if (CSB_WRITE(ptgh, cur, kring->rcur))
- goto err;
-
- if (CSB_WRITE(pthg, hwcur, kring->nr_hwcur))
- goto err;
- if (CSB_WRITE(pthg, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
- goto err;
-
- DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);)
-
- return 0;
-err:
- return EFAULT;
-}
-
-static struct netmap_kring *
-ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
-{
- if (k < pth_na->up.num_tx_rings) {
- return pth_na->up.tx_rings[k];
- }
- return pth_na->up.rx_rings[k - pth_na->up.num_tx_rings];
-}
-
-static int
-ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na)
-{
- struct ptnetmap_state *ptns = pth_na->ptns;
- struct netmap_kring *kring;
- unsigned int num_rings;
- int err = 0, k;
-
- num_rings = pth_na->up.num_tx_rings +
- pth_na->up.num_rx_rings;
-
- for (k = 0; k < num_rings; k++) {
- kring = ptnetmap_kring(pth_na, k);
- err |= ptnetmap_kring_snapshot(kring, ptns->csb_gh + k,
- ptns->csb_hg + k);
- }
-
- return err;
-}
-
-/*
- * Functions to create kernel contexts, and start/stop the workers.
- */
-
-static int
-ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
- struct ptnetmap_cfg *cfg, int use_tx_kthreads)
-{
- struct ptnetmap_state *ptns = pth_na->ptns;
- struct nm_kctx_cfg nmk_cfg;
- unsigned int num_rings;
- uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
- unsigned int expected_cfgtype = 0;
- int k;
-
-#if defined(__FreeBSD__)
- expected_cfgtype = PTNETMAP_CFGTYPE_BHYVE;
-#elif defined(linux)
- expected_cfgtype = PTNETMAP_CFGTYPE_QEMU;
-#endif
- if (cfg->cfgtype != expected_cfgtype) {
- D("Unsupported cfgtype %u", cfg->cfgtype);
- return EINVAL;
- }
-
- num_rings = pth_na->up.num_tx_rings +
- pth_na->up.num_rx_rings;
-
- for (k = 0; k < num_rings; k++) {
- nmk_cfg.attach_user = 1; /* attach kthread to user process */
- nmk_cfg.worker_private = ptnetmap_kring(pth_na, k);
- nmk_cfg.type = k;
- if (k < pth_na->up.num_tx_rings) {
- nmk_cfg.worker_fn = ptnetmap_tx_handler;
- nmk_cfg.use_kthread = use_tx_kthreads;
- nmk_cfg.notify_fn = ptnetmap_tx_nothread_notify;
- } else {
- nmk_cfg.worker_fn = ptnetmap_rx_handler;
- nmk_cfg.use_kthread = 1;
- }
-
- ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
- cfg_entries + k * cfg->entry_size);
- if (ptns->kctxs[k] == NULL) {
- goto err;
- }
- }
-
- return 0;
-err:
- for (k = 0; k < num_rings; k++) {
- if (ptns->kctxs[k]) {
- nm_os_kctx_destroy(ptns->kctxs[k]);
- ptns->kctxs[k] = NULL;
- }
- }
- return EFAULT;
-}
-
-static int
-ptnetmap_start_kctx_workers(struct netmap_pt_host_adapter *pth_na)
-{
- struct ptnetmap_state *ptns = pth_na->ptns;
- int num_rings;
- int error;
- int k;
-
- if (!ptns) {
- D("BUG ptns is NULL");
- return EFAULT;
- }
-
- ptns->stopped = false;
-
- num_rings = ptns->pth_na->up.num_tx_rings +
- ptns->pth_na->up.num_rx_rings;
- for (k = 0; k < num_rings; k++) {
- //nm_os_kctx_worker_setaff(ptns->kctxs[k], xxx);
- error = nm_os_kctx_worker_start(ptns->kctxs[k]);
- if (error) {
- return error;
- }
- }
-
- return 0;
-}
-
-static void
-ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
-{
- struct ptnetmap_state *ptns = pth_na->ptns;
- int num_rings;
- int k;
-
- if (!ptns) {
- /* Nothing to do. */
- return;
- }
-
- ptns->stopped = true;
-
- num_rings = ptns->pth_na->up.num_tx_rings +
- ptns->pth_na->up.num_rx_rings;
- for (k = 0; k < num_rings; k++) {
- nm_os_kctx_worker_stop(ptns->kctxs[k]);
- }
-}
-
-static int nm_unused_notify(struct netmap_kring *, int);
-static int nm_pt_host_notify(struct netmap_kring *, int);
-
-/* Create ptnetmap state and switch parent adapter to ptnetmap mode. */
-static int
-ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
- struct ptnetmap_cfg *cfg)
-{
- int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */
- struct ptnetmap_state *ptns;
- unsigned int num_rings;
- int ret, i;
-
- /* Check if ptnetmap state is already there. */
- if (pth_na->ptns) {
- D("ERROR adapter %p already in ptnetmap mode", pth_na->parent);
- return EINVAL;
- }
-
- num_rings = pth_na->up.num_tx_rings + pth_na->up.num_rx_rings;
-
- if (num_rings != cfg->num_rings) {
- D("ERROR configuration mismatch, expected %u rings, found %u",
- num_rings, cfg->num_rings);
- return EINVAL;
- }
-
- if (!use_tx_kthreads && na_is_generic(pth_na->parent)) {
- D("ERROR ptnetmap direct transmission not supported with "
- "passed-through emulated adapters");
- return EOPNOTSUPP;
- }
-
- ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kctxs));
- if (!ptns) {
- return ENOMEM;
- }
-
- ptns->kctxs = (struct nm_kctx **)(ptns + 1);
- ptns->stopped = true;
-
- /* Cross-link data structures. */
- pth_na->ptns = ptns;
- ptns->pth_na = pth_na;
-
- /* Store the CSB address provided by the hypervisor. */
- ptns->csb_gh = cfg->csb_gh;
- ptns->csb_hg = cfg->csb_hg;
-
- DBG(ptnetmap_print_configuration(cfg));
-
- /* Create kernel contexts. */
- if ((ret = ptnetmap_create_kctxs(pth_na, cfg, use_tx_kthreads))) {
- D("ERROR ptnetmap_create_kctxs()");
- goto err;
- }
- /* Copy krings state into the CSB for the guest initialization */
- if ((ret = ptnetmap_krings_snapshot(pth_na))) {
- D("ERROR ptnetmap_krings_snapshot()");
- goto err;
- }
-
- /* Overwrite parent nm_notify krings callback, and
- * clear NAF_BDG_MAYSLEEP if needed. */
- pth_na->parent->na_private = pth_na;
- pth_na->parent_nm_notify = pth_na->parent->nm_notify;
- pth_na->parent->nm_notify = nm_unused_notify;
- pth_na->parent_na_flags = pth_na->parent->na_flags;
- if (!use_tx_kthreads) {
- /* VALE port txsync is executed under spinlock on Linux, so
- * we need to make sure the bridge cannot sleep. */
- pth_na->parent->na_flags &= ~NAF_BDG_MAYSLEEP;
- }
-
- for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
- pth_na->up.rx_rings[i]->save_notify =
- pth_na->up.rx_rings[i]->nm_notify;
- pth_na->up.rx_rings[i]->nm_notify = nm_pt_host_notify;
- }
- for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
- pth_na->up.tx_rings[i]->save_notify =
- pth_na->up.tx_rings[i]->nm_notify;
- pth_na->up.tx_rings[i]->nm_notify = nm_pt_host_notify;
- }
-
-#ifdef RATE
- memset(&ptns->rate_ctx, 0, sizeof(ptns->rate_ctx));
- setup_timer(&ptns->rate_ctx.timer, &rate_callback,
- (unsigned long)&ptns->rate_ctx);
- if (mod_timer(&ptns->rate_ctx.timer, jiffies + msecs_to_jiffies(1500)))
- D("[ptn] Error: mod_timer()\n");
-#endif
-
- DBG(D("[%s] ptnetmap configuration DONE", pth_na->up.name));
-
- return 0;
-
-err:
- pth_na->ptns = NULL;
- nm_os_free(ptns);
- return ret;
-}
-
-/* Switch parent adapter back to normal mode and destroy
- * ptnetmap state. */
-static void
-ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
-{
- struct ptnetmap_state *ptns = pth_na->ptns;
- int num_rings;
- int i;
-
- if (!ptns) {
- /* Nothing to do. */
- return;
- }
-
- /* Restore parent adapter callbacks. */
- pth_na->parent->nm_notify = pth_na->parent_nm_notify;
- pth_na->parent->na_private = NULL;
- pth_na->parent->na_flags = pth_na->parent_na_flags;
-
- for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
- pth_na->up.rx_rings[i]->nm_notify =
- pth_na->up.rx_rings[i]->save_notify;
- pth_na->up.rx_rings[i]->save_notify = NULL;
- }
- for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
- pth_na->up.tx_rings[i]->nm_notify =
- pth_na->up.tx_rings[i]->save_notify;
- pth_na->up.tx_rings[i]->save_notify = NULL;
- }
-
- /* Destroy kernel contexts. */
- num_rings = ptns->pth_na->up.num_tx_rings +
- ptns->pth_na->up.num_rx_rings;
- for (i = 0; i < num_rings; i++) {
- nm_os_kctx_destroy(ptns->kctxs[i]);
- ptns->kctxs[i] = NULL;
- }
-
- IFRATE(del_timer(&ptns->rate_ctx.timer));
-
- nm_os_free(ptns);
-
- pth_na->ptns = NULL;
-
- DBG(D("[%s] ptnetmap deleted", pth_na->up.name));
-}
-
-/*
- * Called by netmap_ioctl().
- * Operation is indicated in nr_name.
- *
- * Called without NMG_LOCK.
- */
-int
-ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na)
-{
- struct netmap_pt_host_adapter *pth_na;
- struct ptnetmap_cfg *cfg = NULL;
- int error = 0;
-
- DBG(D("name: %s", nr_name));
-
- if (!nm_ptnetmap_host_on(na)) {
- D("ERROR Netmap adapter %p is not a ptnetmap host adapter",
- na);
- return ENXIO;
- }
- pth_na = (struct netmap_pt_host_adapter *)na;
-
- NMG_LOCK();
- if (create) {
- /* Read hypervisor configuration from userspace. */
- /* TODO */
- if (!cfg) {
- goto out;
- }
- /* Create ptnetmap state (kctxs, ...) and switch parent
- * adapter to ptnetmap mode. */
- error = ptnetmap_create(pth_na, cfg);
- nm_os_free(cfg);
- if (error) {
- goto out;
- }
- /* Start kthreads. */
- error = ptnetmap_start_kctx_workers(pth_na);
- if (error)
- ptnetmap_delete(pth_na);
- } else {
- /* Stop kthreads. */
- ptnetmap_stop_kctx_workers(pth_na);
- /* Switch parent adapter back to normal mode and destroy
- * ptnetmap state (kthreads, ...). */
- ptnetmap_delete(pth_na);
- }
-out:
- NMG_UNLOCK();
-
- return error;
-}
-
-/* nm_notify callbacks for ptnetmap */
-static int
-nm_pt_host_notify(struct netmap_kring *kring, int flags)
-{
- struct netmap_adapter *na = kring->na;
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)na->na_private;
- struct ptnetmap_state *ptns;
- int k;
-
- /* First check that the passthrough port is not being destroyed. */
- if (unlikely(!pth_na)) {
- return NM_IRQ_COMPLETED;
- }
-
- ptns = pth_na->ptns;
- if (unlikely(!ptns || ptns->stopped)) {
- return NM_IRQ_COMPLETED;
- }
-
- k = kring->ring_id;
-
- /* Notify kthreads (wake up if needed) */
- if (kring->tx == NR_TX) {
- ND(1, "TX backend irq");
- IFRATE(ptns->rate_ctx.new.btxwu++);
- } else {
- k += pth_na->up.num_tx_rings;
- ND(1, "RX backend irq");
- IFRATE(ptns->rate_ctx.new.brxwu++);
- }
- nm_os_kctx_worker_wakeup(ptns->kctxs[k]);
-
- return NM_IRQ_COMPLETED;
-}
-
-static int
-nm_unused_notify(struct netmap_kring *kring, int flags)
-{
- D("BUG this should never be called");
- return ENXIO;
-}
-
-/* nm_config callback for bwrap */
-static int
-nm_pt_host_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)na;
- struct netmap_adapter *parent = pth_na->parent;
- int error;
-
- //XXX: maybe calling parent->nm_config is better
-
- /* forward the request */
- error = netmap_update_config(parent);
-
- info->num_rx_rings = na->num_rx_rings = parent->num_rx_rings;
- info->num_tx_rings = na->num_tx_rings = parent->num_tx_rings;
- info->num_tx_descs = na->num_tx_desc = parent->num_tx_desc;
- info->num_rx_descs = na->num_rx_desc = parent->num_rx_desc;
- info->rx_buf_maxsize = na->rx_buf_maxsize = parent->rx_buf_maxsize;
-
- return error;
-}
-
-/* nm_krings_create callback for ptnetmap */
-static int
-nm_pt_host_krings_create(struct netmap_adapter *na)
-{
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)na;
- struct netmap_adapter *parent = pth_na->parent;
- enum txrx t;
- int error;
-
- DBG(D("%s", pth_na->up.name));
-
- /* create the parent krings */
- error = parent->nm_krings_create(parent);
- if (error) {
- return error;
- }
-
- /* A ptnetmap host adapter points the very same krings
- * as its parent adapter. These pointer are used in the
- * TX/RX worker functions. */
- na->tx_rings = parent->tx_rings;
- na->rx_rings = parent->rx_rings;
- na->tailroom = parent->tailroom;
-
- for_rx_tx(t) {
- struct netmap_kring *kring;
-
- /* Parent's kring_create function will initialize
- * its own na->si. We have to init our na->si here. */
- nm_os_selinfo_init(&na->si[t]);
-
- /* Force the mem_rings_create() method to create the
- * host rings independently on what the regif asked for:
- * these rings are needed by the guest ptnetmap adapter
- * anyway. */
- kring = NMR(na, t)[nma_get_nrings(na, t)];
- kring->nr_kflags |= NKR_NEEDRING;
- }
-
- return 0;
-}
-
-/* nm_krings_delete callback for ptnetmap */
-static void
-nm_pt_host_krings_delete(struct netmap_adapter *na)
-{
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)na;
- struct netmap_adapter *parent = pth_na->parent;
-
- DBG(D("%s", pth_na->up.name));
-
- parent->nm_krings_delete(parent);
-
- na->tx_rings = na->rx_rings = na->tailroom = NULL;
-}
-
-/* nm_register callback */
-static int
-nm_pt_host_register(struct netmap_adapter *na, int onoff)
-{
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)na;
- struct netmap_adapter *parent = pth_na->parent;
- int error;
- DBG(D("%s onoff %d", pth_na->up.name, onoff));
-
- if (onoff) {
- /* netmap_do_regif has been called on the ptnetmap na.
- * We need to pass the information about the
- * memory allocator to the parent before
- * putting it in netmap mode
- */
- parent->na_lut = na->na_lut;
- }
-
- /* forward the request to the parent */
- error = parent->nm_register(parent, onoff);
- if (error)
- return error;
-
-
- if (onoff) {
- na->na_flags |= NAF_NETMAP_ON | NAF_PTNETMAP_HOST;
- } else {
- ptnetmap_delete(pth_na);
- na->na_flags &= ~(NAF_NETMAP_ON | NAF_PTNETMAP_HOST);
- }
-
- return 0;
-}
-
-/* nm_dtor callback */
-static void
-nm_pt_host_dtor(struct netmap_adapter *na)
-{
- struct netmap_pt_host_adapter *pth_na =
- (struct netmap_pt_host_adapter *)na;
- struct netmap_adapter *parent = pth_na->parent;
-
- DBG(D("%s", pth_na->up.name));
-
- /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor
- * didn't do it. */
- ptnetmap_stop_kctx_workers(pth_na);
- ptnetmap_delete(pth_na);
-
- parent->na_flags &= ~NAF_BUSY;
-
- netmap_adapter_put(pth_na->parent);
- pth_na->parent = NULL;
-}
-
-/* check if nmr is a request for a ptnetmap adapter that we can satisfy */
-int
-netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
- struct netmap_mem_d *nmd, int create)
-{
- struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
- struct nmreq_register preq;
- struct netmap_adapter *parent; /* target adapter */
- struct netmap_pt_host_adapter *pth_na;
- struct ifnet *ifp = NULL;
- int error;
-
- /* Check if it is a request for a ptnetmap adapter */
- if ((req->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
- return 0;
- }
-
- D("Requesting a ptnetmap host adapter");
-
- pth_na = nm_os_malloc(sizeof(*pth_na));
- if (pth_na == NULL) {
- D("ERROR malloc");
- return ENOMEM;
- }
-
- /* first, try to find the adapter that we want to passthrough
- * We use the same req, after we have turned off the ptnetmap flag.
- * In this way we can potentially passthrough everything netmap understands.
- */
- memcpy(&preq, req, sizeof(preq));
- preq.nr_flags &= ~(NR_PTNETMAP_HOST);
- hdr->nr_body = (uintptr_t)&preq;
- error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
- hdr->nr_body = (uintptr_t)req;
- if (error) {
- D("parent lookup failed: %d", error);
- goto put_out_noputparent;
- }
- DBG(D("found parent: %s", parent->name));
-
- /* make sure the interface is not already in use */
- if (NETMAP_OWNED_BY_ANY(parent)) {
- D("NIC %s busy, cannot ptnetmap", parent->name);
- error = EBUSY;
- goto put_out;
- }
-
- pth_na->parent = parent;
-
- /* Follow netmap_attach()-like operations for the host
- * ptnetmap adapter. */
-
- //XXX pth_na->up.na_flags = parent->na_flags;
- pth_na->up.num_rx_rings = parent->num_rx_rings;
- pth_na->up.num_tx_rings = parent->num_tx_rings;
- pth_na->up.num_tx_desc = parent->num_tx_desc;
- pth_na->up.num_rx_desc = parent->num_rx_desc;
-
- pth_na->up.nm_dtor = nm_pt_host_dtor;
- pth_na->up.nm_register = nm_pt_host_register;
-
- /* Reuse parent's adapter txsync and rxsync methods. */
- pth_na->up.nm_txsync = parent->nm_txsync;
- pth_na->up.nm_rxsync = parent->nm_rxsync;
-
- pth_na->up.nm_krings_create = nm_pt_host_krings_create;
- pth_na->up.nm_krings_delete = nm_pt_host_krings_delete;
- pth_na->up.nm_config = nm_pt_host_config;
-
- /* Set the notify method only or convenience, it will never
- * be used, since - differently from default krings_create - we
- * ptnetmap krings_create callback inits kring->nm_notify
- * directly. */
- pth_na->up.nm_notify = nm_unused_notify;
-
- pth_na->up.nm_mem = netmap_mem_get(parent->nm_mem);
-
- pth_na->up.na_flags |= NAF_HOST_RINGS;
-
- error = netmap_attach_common(&pth_na->up);
- if (error) {
- D("ERROR netmap_attach_common()");
- goto put_out;
- }
-
- *na = &pth_na->up;
- /* set parent busy, because attached for ptnetmap */
- parent->na_flags |= NAF_BUSY;
- strncpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
- strcat(pth_na->up.name, "-PTN");
- netmap_adapter_get(*na);
-
- DBG(D("%s ptnetmap request DONE", pth_na->up.name));
-
- /* drop the reference to the ifp, if any */
- if (ifp)
- if_rele(ifp);
-
- return 0;
-
-put_out:
- netmap_adapter_put(parent);
- if (ifp)
- if_rele(ifp);
-put_out_noputparent:
- nm_os_free(pth_na);
- return error;
-}
-#endif /* WITH_PTNETMAP_HOST */
-
-#ifdef WITH_PTNETMAP_GUEST
-/*
- * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
- * These routines are reused across the different operating systems supported
- * by netmap.
- */
-
-/*
- * Reconcile host and guest views of the transmit ring.
- *
- * Guest user wants to transmit packets up to the one before ring->head,
- * and guest kernel knows tx_ring->hwcur is the first packet unsent
- * by the host kernel.
- *
- * We push out as many packets as possible, and possibly
- * reclaim buffers from previously completed transmission.
- *
- * Notifications from the host are enabled only if the user guest would
- * block (no space in the ring).
- */
-bool
-netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
- struct netmap_kring *kring, int flags)
-{
- bool notify = false;
-
- /* Disable notifications */
- ptgh->guest_need_kick = 0;
-
- /*
- * First part: tell the host (updating the CSB) to process the new
- * packets.
- */
- kring->nr_hwcur = pthg->hwcur;
- ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
-
- /* Ask for a kick from a guest to the host if needed. */
- if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
- && NM_ACCESS_ONCE(pthg->host_need_kick)) ||
- (flags & NAF_FORCE_RECLAIM)) {
- ptgh->sync_flags = flags;
- notify = true;
- }
-
- /*
- * Second part: reclaim buffers for completed transmissions.
- */
- if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
- ptnetmap_guest_read_kring_csb(pthg, kring);
- }
-
- /*
- * No more room in the ring for new transmissions. The user thread will
- * go to sleep and we need to be notified by the host when more free
- * space is available.
- */
- if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
- /* Reenable notifications. */
- ptgh->guest_need_kick = 1;
- /* Double check */
- ptnetmap_guest_read_kring_csb(pthg, kring);
- /* If there is new free space, disable notifications */
- if (unlikely(!nm_kr_txempty(kring))) {
- ptgh->guest_need_kick = 0;
- }
- }
-
- ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
- kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
- kring->rhead, kring->rcur, kring->nr_hwtail);
-
- return notify;
-}
-
-/*
- * Reconcile host and guest view of the receive ring.
- *
- * Update hwcur/hwtail from host (reading from CSB).
- *
- * If guest user has released buffers up to the one before ring->head, we
- * also give them to the host.
- *
- * Notifications from the host are enabled only if the user guest would
- * block (no more completed slots in the ring).
- */
-bool
-netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
- struct netmap_kring *kring, int flags)
-{
- bool notify = false;
-
- /* Disable notifications */
- ptgh->guest_need_kick = 0;
-
- /*
- * First part: import newly received packets, by updating the kring
- * hwtail to the hwtail known from the host (read from the CSB).
- * This also updates the kring hwcur.
- */
- ptnetmap_guest_read_kring_csb(pthg, kring);
- kring->nr_kflags &= ~NKR_PENDINTR;
-
- /*
- * Second part: tell the host about the slots that guest user has
- * released, by updating cur and head in the CSB.
- */
- if (kring->rhead != kring->nr_hwcur) {
- ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
- kring->rhead);
- /* Ask for a kick from the guest to the host if needed. */
- if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
- ptgh->sync_flags = flags;
- notify = true;
- }
- }
-
- /*
- * No more completed RX slots. The user thread will go to sleep and
- * we need to be notified by the host when more RX slots have been
- * completed.
- */
- if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
- /* Reenable notifications. */
- ptgh->guest_need_kick = 1;
- /* Double check */
- ptnetmap_guest_read_kring_csb(pthg, kring);
- /* If there are new slots, disable notifications. */
- if (!nm_kr_rxempty(kring)) {
- ptgh->guest_need_kick = 0;
- }
- }
-
- ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
- kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
- kring->rhead, kring->rcur, kring->nr_hwtail);
-
- return notify;
-}
-
-/*
- * Callbacks for ptnet drivers: nm_krings_create, nm_krings_delete, nm_dtor.
- */
-int
-ptnet_nm_krings_create(struct netmap_adapter *na)
-{
- struct netmap_pt_guest_adapter *ptna =
- (struct netmap_pt_guest_adapter *)na; /* Upcast. */
- struct netmap_adapter *na_nm = &ptna->hwup.up;
- struct netmap_adapter *na_dr = &ptna->dr.up;
- int ret;
-
- if (ptna->backend_regifs) {
- return 0;
- }
-
- /* Create krings on the public netmap adapter. */
- ret = netmap_hw_krings_create(na_nm);
- if (ret) {
- return ret;
- }
-
- /* Copy krings into the netmap adapter private to the driver. */
- na_dr->tx_rings = na_nm->tx_rings;
- na_dr->rx_rings = na_nm->rx_rings;
-
- return 0;
-}
-
-void
-ptnet_nm_krings_delete(struct netmap_adapter *na)
-{
- struct netmap_pt_guest_adapter *ptna =
- (struct netmap_pt_guest_adapter *)na; /* Upcast. */
- struct netmap_adapter *na_nm = &ptna->hwup.up;
- struct netmap_adapter *na_dr = &ptna->dr.up;
-
- if (ptna->backend_regifs) {
- return;
- }
-
- na_dr->tx_rings = NULL;
- na_dr->rx_rings = NULL;
-
- netmap_hw_krings_delete(na_nm);
-}
-
-void
-ptnet_nm_dtor(struct netmap_adapter *na)
-{
- struct netmap_pt_guest_adapter *ptna =
- (struct netmap_pt_guest_adapter *)na;
-
- netmap_mem_put(ptna->dr.up.nm_mem);
- memset(&ptna->dr, 0, sizeof(ptna->dr));
- netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp);
-}
-
-int
-netmap_pt_guest_attach(struct netmap_adapter *arg,
- unsigned int nifp_offset, unsigned int memid)
-{
- struct netmap_pt_guest_adapter *ptna;
- struct ifnet *ifp = arg ? arg->ifp : NULL;
- int error;
-
- /* get allocator */
- arg->nm_mem = netmap_mem_pt_guest_new(ifp, nifp_offset, memid);
- if (arg->nm_mem == NULL)
- return ENOMEM;
- arg->na_flags |= NAF_MEM_OWNER;
- error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter), 1);
- if (error)
- return error;
-
- /* get the netmap_pt_guest_adapter */
- ptna = (struct netmap_pt_guest_adapter *) NA(ifp);
-
- /* Initialize a separate pass-through netmap adapter that is going to
- * be used by the ptnet driver only, and so never exposed to netmap
- * applications. We only need a subset of the available fields. */
- memset(&ptna->dr, 0, sizeof(ptna->dr));
- ptna->dr.up.ifp = ifp;
- ptna->dr.up.nm_mem = netmap_mem_get(ptna->hwup.up.nm_mem);
- ptna->dr.up.nm_config = ptna->hwup.up.nm_config;
-
- ptna->backend_regifs = 0;
-
- return 0;
-}
-
-#endif /* WITH_PTNETMAP_GUEST */