aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/netmap/netmap_kern.h
diff options
context:
space:
mode:
authorLuigi Rizzo <luigi@FreeBSD.org>2014-01-06 12:53:15 +0000
committerLuigi Rizzo <luigi@FreeBSD.org>2014-01-06 12:53:15 +0000
commit17885a7bfde9d164e45a9833bb172215c55739f9 (patch)
tree529a5d218d5f4d073c5ad30a4b484d1b412ea226 /sys/dev/netmap/netmap_kern.h
parent0979970a1d4ffa9c13361e91760891d96864ceee (diff)
Notes
Diffstat (limited to 'sys/dev/netmap/netmap_kern.h')
-rw-r--r--sys/dev/netmap/netmap_kern.h488
1 files changed, 273 insertions, 215 deletions
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 9381cd4cedd3..74a46297ff3d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011-2013 Matteo Landi, Luigi Rizzo. All rights reserved.
- * Copyright (C) 2013 Universita` di Pisa. All rights reserved.
+ * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
+ * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,7 +53,7 @@
#define NM_SELINFO_T struct selinfo
#define MBUF_LEN(m) ((m)->m_pkthdr.len)
#define MBUF_IFP(m) ((m)->m_pkthdr.rcvif)
-#define NM_SEND_UP(ifp, m) ((ifp)->if_input)(ifp, m)
+#define NM_SEND_UP(ifp, m) ((NA(ifp))->if_input)(ifp, m)
#define NM_ATOMIC_T volatile int // XXX ?
/* atomic operations */
@@ -76,7 +76,11 @@ struct hrtimer {
#define NM_SELINFO_T wait_queue_head_t
#define MBUF_LEN(m) ((m)->len)
#define MBUF_IFP(m) ((m)->dev)
-#define NM_SEND_UP(ifp, m) netif_rx(m)
+#define NM_SEND_UP(ifp, m) \
+ do { \
+ m->priority = NM_MAGIC_PRIORITY; \
+ netif_rx(m); \
+ } while (0)
#define NM_ATOMIC_T volatile long unsigned int
@@ -125,9 +129,9 @@ struct hrtimer {
do { \
struct timeval __xxts; \
microtime(&__xxts); \
- printf("%03d.%06d %s [%d] " format "\n", \
+ printf("%03d.%06d [%4d] %-25s " format "\n", \
(int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \
- __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+ __LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while (0)
/* rate limited, lps indicates how many per second */
@@ -158,15 +162,23 @@ extern NMG_LOCK_T netmap_global_lock;
* a ring across system calls.
*
* nr_hwcur index of the next buffer to refill.
- * It corresponds to ring->cur - ring->reserved
+ * It corresponds to ring->head
+ * at the time the system call returns.
*
- * nr_hwavail the number of slots "owned" by userspace.
- * nr_hwavail =:= ring->avail + ring->reserved
+ * nr_hwtail index of the first buffer owned by the kernel.
+ * On RX, hwcur->hwtail are receive buffers
+ * not yet released. hwcur is advanced following
+ * ring->head, hwtail is advanced on incoming packets,
+ * and a wakeup is generated when hwtail passes ring->cur
+ * On TX, hwcur->rcur have been filled by the sender
+ * but not sent yet to the NIC; rcur->hwtail are available
+ * for new transmissions, and hwtail->hwcur-1 are pending
+ * transmissions not yet acknowledged.
*
* The indexes in the NIC and netmap rings are offset by nkr_hwofs slots.
* This is so that, on a reset, buffers owned by userspace are not
* modified by the kernel. In particular:
- * RX rings: the next empty buffer (hwcur + hwavail + hwofs) coincides with
+ * RX rings: the next empty buffer (hwtail + hwofs) coincides with
* the next empty buffer as known by the hardware (next_to_check or so).
* TX rings: hwcur + hwofs coincides with next_to_send
*
@@ -184,44 +196,76 @@ extern NMG_LOCK_T netmap_global_lock;
* from nr_hwlease, advances it, then does the
* copy outside the lock.
* In RX rings (used for VALE ports),
- * nkr_hwcur + nkr_hwavail <= nkr_hwlease < nkr_hwcur+N-1
+ * nkr_hwtail <= nkr_hwlease < nkr_hwcur+N-1
* In TX rings (used for NIC or host stack ports)
- * nkr_hwcur <= nkr_hwlease < nkr_hwcur+ nkr_hwavail
+ * nkr_hwcur <= nkr_hwlease < nkr_hwtail
* nkr_leases array of nkr_num_slots where writers can report
* completion of their block. NR_NOSLOT (~0) indicates
* that the writer has not finished yet
* nkr_lease_idx index of next free slot in nr_leases, to be assigned
*
* The kring is manipulated by txsync/rxsync and generic netmap function.
- * q_lock is used to arbitrate access to the kring from within the netmap
- * code, and this and other protections guarantee that there is never
- * more than 1 concurrent call to txsync or rxsync. So we are free
- * to manipulate the kring from within txsync/rxsync without any extra
- * locks.
+ *
+ * Concurrent rxsync or txsync on the same ring are prevented through
+ * by nm_kr_lock() which in turn uses nr_busy. This is all we need
+ * for NIC rings, and for TX rings attached to the host stack.
+ *
+ * RX rings attached to the host stack use an mbq (rx_queue) on both
+ * rxsync_from_host() and netmap_transmit(). The mbq is protected
+ * by its internal lock.
+ *
+ * RX rings attached to the VALE switch are accessed by both sender
+ * and receiver. They are protected through the q_lock on the RX ring.
*/
struct netmap_kring {
- struct netmap_ring *ring;
- uint32_t nr_hwcur;
- uint32_t nr_hwavail;
- uint32_t nr_kflags; /* private driver flags */
- int32_t nr_hwreserved;
-#define NKR_PENDINTR 0x1 // Pending interrupt.
- uint32_t nkr_num_slots;
- int32_t nkr_hwofs; /* offset between NIC and netmap ring */
+ struct netmap_ring *ring;
+
+ uint32_t nr_hwcur;
+ uint32_t nr_hwtail;
+
+ /*
+ * Copies of values in user rings, so we do not need to look
+ * at the ring (which could be modified). These are set in the
+ * *sync_prologue()/finalize() routines.
+ */
+ uint32_t rhead;
+ uint32_t rcur;
+ uint32_t rtail;
+
+ uint32_t nr_kflags; /* private driver flags */
+#define NKR_PENDINTR 0x1 // Pending interrupt.
+ uint32_t nkr_num_slots;
+
+ /*
+ * On a NIC reset, the NIC ring indexes may be reset but the
+ * indexes in the netmap rings remain the same. nkr_hwofs
+ * keeps track of the offset between the two.
+ */
+ int32_t nkr_hwofs;
uint16_t nkr_slot_flags; /* initial value for flags */
+
+ /* last_reclaim is opaque marker to help reduce the frequency
+ * of operations such as reclaiming tx buffers. A possible use
+ * is set it to ticks and do the reclaim only once per tick.
+ */
+ uint64_t last_reclaim;
+
+
+ NM_SELINFO_T si; /* poll/select wait queue */
+ NM_LOCK_T q_lock; /* protects kring and ring. */
+ NM_ATOMIC_T nr_busy; /* prevent concurrent syscalls */
+
struct netmap_adapter *na;
- struct nm_bdg_fwd *nkr_ft;
- uint32_t *nkr_leases;
-#define NR_NOSLOT ((uint32_t)~0)
- uint32_t nkr_hwlease;
- uint32_t nkr_lease_idx;
- NM_SELINFO_T si; /* poll/select wait queue */
- NM_LOCK_T q_lock; /* protects kring and ring. */
- NM_ATOMIC_T nr_busy; /* prevent concurrent syscalls */
+ /* The folloiwing fields are for VALE switch support */
+ struct nm_bdg_fwd *nkr_ft;
+ uint32_t *nkr_leases;
+#define NR_NOSLOT ((uint32_t)~0) /* used in nkr_*lease* */
+ uint32_t nkr_hwlease;
+ uint32_t nkr_lease_idx;
- volatile int nkr_stopped;
+ volatile int nkr_stopped; // XXX what for ?
/* support for adapters without native netmap support.
* On tx rings we preallocate an array of tx buffers
@@ -230,8 +274,11 @@ struct netmap_kring {
* XXX who writes to the rx queue ?
*/
struct mbuf **tx_pool;
- u_int nr_ntc; /* Emulation of a next-to-clean RX ring pointer. */
- struct mbq rx_queue; /* A queue for intercepted rx mbufs. */
+ // u_int nr_ntc; /* Emulation of a next-to-clean RX ring pointer. */
+ struct mbq rx_queue; /* intercepted rx mbufs. */
+
+ uint32_t ring_id; /* debugging */
+ char name[64]; /* diagnostic */
} __attribute__((__aligned__(64)));
@@ -243,6 +290,15 @@ nm_next(uint32_t i, uint32_t lim)
return unlikely (i == lim) ? 0 : i + 1;
}
+
+/* return the previous index, with wraparound */
+static inline uint32_t
+nm_prev(uint32_t i, uint32_t lim)
+{
+ return unlikely (i == 0) ? lim : i - 1;
+}
+
+
/*
*
* Here is the layout for the Rx and Tx rings.
@@ -253,36 +309,36 @@ nm_next(uint32_t i, uint32_t lim)
| | | |
|XXX free slot XXX| |XXX free slot XXX|
+-----------------+ +-----------------+
- | |<-hwcur | |<-hwcur
- | reserved h | | (ready |
- +----------- w -+ | to be |
- cur->| a | | sent) h |
- | v | +---------- w |
- | a | cur->| (being a |
- | i | | prepared) v |
- | avail l | | a |
- +-----------------+ + a ------ i +
- | | ... | v l |<-hwlease
- | (being | ... | a | ...
- | prepared) | ... | i | ...
- +-----------------+ ... | l | ...
- | |<-hwlease +-----------------+
+head->| owned by user |<-hwcur | not sent to nic |<-hwcur
+ | | | yet |
+ +-----------------+ | |
+ cur->| available to | | |
+ | user, not read | +-----------------+
+ | yet | cur->| (being |
+ | | | prepared) |
| | | |
+ +-----------------+ + ------ +
+tail->| |<-hwtail | |<-hwlease
+ | (being | ... | | ...
+ | prepared) | ... | | ...
+ +-----------------+ ... | | ...
+ | |<-hwlease +-----------------+
+ | | tail->| |<-hwtail
| | | |
| | | |
| | | |
+-----------------+ +-----------------+
- * The cur/avail (user view) and hwcur/hwavail (kernel view)
+ * The cur/tail (user view) and hwcur/hwtail (kernel view)
* are used in the normal operation of the card.
*
* When a ring is the output of a switch port (Rx ring for
* a VALE port, Tx ring for the host stack or NIC), slots
* are reserved in blocks through 'hwlease' which points
* to the next unused slot.
- * On an Rx ring, hwlease is always after hwavail,
- * and completions cause avail to advance.
- * On a Tx ring, hwlease is always between cur and hwavail,
+ * On an Rx ring, hwlease is always after hwtail,
+ * and completions cause hwtail to advance.
+ * On a Tx ring, hwlease is always between cur and hwtail,
* and completions cause cur to advance.
*
* nm_kr_space() returns the maximum number of slots that
@@ -294,7 +350,6 @@ nm_next(uint32_t i, uint32_t lim)
-
enum txrx { NR_RX = 0, NR_TX = 1 };
/*
@@ -349,6 +404,7 @@ struct netmap_adapter {
*/
struct netmap_kring *tx_rings; /* array of TX rings. */
struct netmap_kring *rx_rings; /* array of RX rings. */
+
void *tailroom; /* space below the rings array */
/* (used for leases) */
@@ -360,11 +416,38 @@ struct netmap_adapter {
*/
int (*if_transmit)(struct ifnet *, struct mbuf *);
+ /* copy of if_input for netmap_send_up() */
+ void (*if_input)(struct ifnet *, struct mbuf *);
+
/* references to the ifnet and device routines, used by
* the generic netmap functions.
*/
struct ifnet *ifp; /* adapter is ifp->if_softc */
+ /*---- callbacks for this netmap adapter -----*/
+ /*
+ * nm_dtor() is the cleanup routine called when destroying
+ * the adapter.
+ *
+ * nm_register() is called on NIOCREGIF and close() to enter
+ * or exit netmap mode on the NIC
+ *
+ * nm_txsync() pushes packets to the underlying hw/switch
+ *
+ * nm_rxsync() collects packets from the underlying hw/switch
+ *
+ * nm_config() returns configuration information from the OS
+ *
+ * nm_krings_create() XXX
+ *
+ * nm_krings_delete() XXX
+ *
+ * nm_notify() is used to act after data have become available.
+ * For hw devices this is typically a selwakeup(),
+ * but for NIC/host ports attached to a switch (or vice-versa)
+ * we also need to invoke the 'txsync' code downstream.
+ */
+
/* private cleanup */
void (*nm_dtor)(struct netmap_adapter *);
@@ -403,6 +486,7 @@ struct netmap_adapter {
void *na_private;
};
+
/*
* If the NIC is owned by the kernel
* (i.e., bridge), neither another bridge nor user can use it;
@@ -433,13 +517,15 @@ struct netmap_vp_adapter { /* VALE software port */
u_int offset; /* Offset of ethernet header for each packet. */
};
+
struct netmap_hw_adapter { /* physical device */
struct netmap_adapter up;
struct net_device_ops nm_ndo; // XXX linux only
};
-struct netmap_generic_adapter { /* non-native device */
+
+struct netmap_generic_adapter { /* emulated device */
struct netmap_hw_adapter up;
/* Pointer to a previously used netmap adapter. */
@@ -455,16 +541,20 @@ struct netmap_generic_adapter { /* non-native device */
struct hrtimer mit_timer;
int mit_pending;
+#ifdef linux
+ netdev_tx_t (*save_start_xmit)(struct mbuf *, struct ifnet *);
+#endif
};
#ifdef WITH_VALE
-/* bridge wrapper for non VALE ports. It is used to connect real devices to the bridge.
+/*
+ * Bridge wrapper for non VALE ports attached to a VALE switch.
*
- * The real device must already have its own netmap adapter (hwna). The
- * bridge wrapper and the hwna adapter share the same set of netmap rings and
- * buffers, but they have two separate sets of krings descriptors, with tx/rx
- * meanings swapped:
+ * The real device must already have its own netmap adapter (hwna).
+ * The bridge wrapper and the hwna adapter share the same set of
+ * netmap rings and buffers, but they have two separate sets of
+ * krings descriptors, with tx/rx meanings swapped:
*
* netmap
* bwrap krings rings krings hwna
@@ -478,23 +568,28 @@ struct netmap_generic_adapter { /* non-native device */
* | | +------+ +-----+ +------+ | |
* +------+ +------+
*
- * - packets coming from the bridge go to the brwap rx rings, which are also the
- * hwna tx rings. The bwrap notify callback will then complete the hwna tx
- * (see netmap_bwrap_notify).
- * - packets coming from the outside go to the hwna rx rings, which are also the
- * bwrap tx rings. The (overwritten) hwna notify method will then complete
- * the bridge tx (see netmap_bwrap_intr_notify).
+ * - packets coming from the bridge go to the brwap rx rings,
+ * which are also the hwna tx rings. The bwrap notify callback
+ * will then complete the hwna tx (see netmap_bwrap_notify).
*
- * The bridge wrapper may optionally connect the hwna 'host' rings to the
- * bridge. This is done by using a second port in the bridge and connecting it
- * to the 'host' netmap_vp_adapter contained in the netmap_bwrap_adapter.
- * The brwap host adapter cross-links the hwna host rings in the same way as shown above.
+ * - packets coming from the outside go to the hwna rx rings,
+ * which are also the bwrap tx rings. The (overwritten) hwna
+ * notify method will then complete the bridge tx
+ * (see netmap_bwrap_intr_notify).
*
- * - packets coming from the bridge and directed to host stack are handled by the
- * bwrap host notify callback (see netmap_bwrap_host_notify)
- * - packets coming from the host stack are still handled by the overwritten
- * hwna notify callback (netmap_bwrap_intr_notify), but are diverted to the
- * host adapter depending on the ring number.
+ * The bridge wrapper may optionally connect the hwna 'host' rings
+ * to the bridge. This is done by using a second port in the
+ * bridge and connecting it to the 'host' netmap_vp_adapter
+ * contained in the netmap_bwrap_adapter. The brwap host adapter
+ * cross-links the hwna host rings in the same way as shown above.
+ *
+ * - packets coming from the bridge and directed to the host stack
+ * are handled by the bwrap host notify callback
+ * (see netmap_bwrap_host_notify)
+ *
+ * - packets coming from the host stack are still handled by the
+ * overwritten hwna notify callback (netmap_bwrap_intr_notify),
+ * but are diverted to the host adapter depending on the ring number.
*
*/
struct netmap_bwrap_adapter {
@@ -505,103 +600,39 @@ struct netmap_bwrap_adapter {
/* backup of the hwna notify callback */
int (*save_notify)(struct netmap_adapter *,
u_int ring, enum txrx, int flags);
- /* When we attach a physical interface to the bridge, we
+
+ /*
+ * When we attach a physical interface to the bridge, we
* allow the controlling process to terminate, so we need
* a place to store the netmap_priv_d data structure.
- * This is only done when physical interfaces are attached to a bridge.
+ * This is only done when physical interfaces
+ * are attached to a bridge.
*/
struct netmap_priv_d *na_kpriv;
};
-/*
- * Available space in the ring. Only used in VALE code
- */
-static inline uint32_t
-nm_kr_space(struct netmap_kring *k, int is_rx)
-{
- int space;
-
- if (is_rx) {
- int busy = k->nkr_hwlease - k->nr_hwcur + k->nr_hwreserved;
- if (busy < 0)
- busy += k->nkr_num_slots;
- space = k->nkr_num_slots - 1 - busy;
- } else {
- space = k->nr_hwcur + k->nr_hwavail - k->nkr_hwlease;
- if (space < 0)
- space += k->nkr_num_slots;
- }
-#if 0
- // sanity check
- if (k->nkr_hwlease >= k->nkr_num_slots ||
- k->nr_hwcur >= k->nkr_num_slots ||
- k->nr_hwavail >= k->nkr_num_slots ||
- busy < 0 ||
- busy >= k->nkr_num_slots) {
- D("invalid kring, cur %d avail %d lease %d lease_idx %d lim %d", k->nr_hwcur, k->nr_hwavail, k->nkr_hwlease,
- k->nkr_lease_idx, k->nkr_num_slots);
- }
-#endif
- return space;
-}
-
-
+#endif /* WITH_VALE */
-/* make a lease on the kring for N positions. return the
- * lease index
- */
+/* return slots reserved to rx clients; used in drivers */
static inline uint32_t
-nm_kr_lease(struct netmap_kring *k, u_int n, int is_rx)
+nm_kr_rxspace(struct netmap_kring *k)
{
- uint32_t lim = k->nkr_num_slots - 1;
- uint32_t lease_idx = k->nkr_lease_idx;
+ int space = k->nr_hwtail - k->nr_hwcur;
+ if (space < 0)
+ space += k->nkr_num_slots;
+ ND("preserving %d rx slots %d -> %d", space, k->nr_hwcur, k->nr_hwtail);
- k->nkr_leases[lease_idx] = NR_NOSLOT;
- k->nkr_lease_idx = nm_next(lease_idx, lim);
-
- if (n > nm_kr_space(k, is_rx)) {
- D("invalid request for %d slots", n);
- panic("x");
- }
- /* XXX verify that there are n slots */
- k->nkr_hwlease += n;
- if (k->nkr_hwlease > lim)
- k->nkr_hwlease -= lim + 1;
-
- if (k->nkr_hwlease >= k->nkr_num_slots ||
- k->nr_hwcur >= k->nkr_num_slots ||
- k->nr_hwavail >= k->nkr_num_slots ||
- k->nkr_lease_idx >= k->nkr_num_slots) {
- D("invalid kring %s, cur %d avail %d lease %d lease_idx %d lim %d",
- k->na->ifp->if_xname,
- k->nr_hwcur, k->nr_hwavail, k->nkr_hwlease,
- k->nkr_lease_idx, k->nkr_num_slots);
- }
- return lease_idx;
+ return space;
}
-#endif /* WITH_VALE */
-/* return update position */
-static inline uint32_t
-nm_kr_rxpos(struct netmap_kring *k)
+/* True if no space in the tx ring. only valid after txsync_prologue */
+static inline int
+nm_kr_txempty(struct netmap_kring *kring)
{
- uint32_t pos = k->nr_hwcur + k->nr_hwavail;
- if (pos >= k->nkr_num_slots)
- pos -= k->nkr_num_slots;
-#if 0
- if (pos >= k->nkr_num_slots ||
- k->nkr_hwlease >= k->nkr_num_slots ||
- k->nr_hwcur >= k->nkr_num_slots ||
- k->nr_hwavail >= k->nkr_num_slots ||
- k->nkr_lease_idx >= k->nkr_num_slots) {
- D("invalid kring, cur %d avail %d lease %d lease_idx %d lim %d", k->nr_hwcur, k->nr_hwavail, k->nkr_hwlease,
- k->nkr_lease_idx, k->nkr_num_slots);
- }
-#endif
- return pos;
+ return kring->rcur == kring->nr_hwtail;
}
@@ -613,11 +644,13 @@ nm_kr_rxpos(struct netmap_kring *k)
#define NM_KR_BUSY 1
#define NM_KR_STOPPED 2
+
static __inline void nm_kr_put(struct netmap_kring *kr)
{
NM_ATOMIC_CLEAR(&kr->nr_busy);
}
+
static __inline int nm_kr_tryget(struct netmap_kring *kr)
{
/* check a first time without taking the lock
@@ -640,7 +673,7 @@ static __inline int nm_kr_tryget(struct netmap_kring *kr)
/*
- * The following are support routines used by individual drivers to
+ * The following functions are used by individual drivers to
* support netmap operation.
*
* netmap_attach() initializes a struct netmap_adapter, allocating the
@@ -666,7 +699,17 @@ struct netmap_slot *netmap_reset(struct netmap_adapter *na,
enum txrx tx, u_int n, u_int new_cur);
int netmap_ring_reinit(struct netmap_kring *);
-/* set/clear native flags. XXX maybe also if_transmit ? */
+/* default functions to handle rx/tx interrupts */
+int netmap_rx_irq(struct ifnet *, u_int, u_int *);
+#define netmap_tx_irq(_n, _q) netmap_rx_irq(_n, _q, NULL)
+void netmap_common_irq(struct ifnet *, u_int, u_int *work_done);
+
+void netmap_disable_all_rings(struct ifnet *);
+void netmap_enable_all_rings(struct ifnet *);
+void netmap_disable_ring(struct netmap_kring *kr);
+
+
+/* set/clear native flags and if_transmit/netdev_ops */
static inline void
nm_set_native_flags(struct netmap_adapter *na)
{
@@ -685,6 +728,7 @@ nm_set_native_flags(struct netmap_adapter *na)
#endif
}
+
static inline void
nm_clear_native_flags(struct netmap_adapter *na)
{
@@ -701,36 +745,58 @@ nm_clear_native_flags(struct netmap_adapter *na)
#endif
}
+
/*
- * validates parameters in the ring/kring, returns a value for cur,
- * and the 'new_slots' value in the argument.
- * If any error, returns cur > lim to force a reinit.
+ * validates parameters in the ring/kring, returns a value for head
+ * If any error, returns ring_size to force a reinit.
*/
-u_int nm_txsync_prologue(struct netmap_kring *, u_int *);
+uint32_t nm_txsync_prologue(struct netmap_kring *);
+
/*
- * validates parameters in the ring/kring, returns a value for cur,
+ * validates parameters in the ring/kring, returns a value for head,
* and the 'reserved' value in the argument.
- * If any error, returns cur > lim to force a reinit.
+ * If any error, returns ring_size lim to force a reinit.
*/
-u_int nm_rxsync_prologue(struct netmap_kring *, u_int *);
+uint32_t nm_rxsync_prologue(struct netmap_kring *);
+
/*
- * update kring and ring at the end of txsync
+ * update kring and ring at the end of txsync.
*/
static inline void
-nm_txsync_finalize(struct netmap_kring *kring, u_int cur)
+nm_txsync_finalize(struct netmap_kring *kring)
{
- /* recompute hwreserved */
- kring->nr_hwreserved = cur - kring->nr_hwcur;
- if (kring->nr_hwreserved < 0)
- kring->nr_hwreserved += kring->nkr_num_slots;
+ /* update ring head/tail to what the kernel knows */
+ kring->ring->tail = kring->rtail = kring->nr_hwtail;
+ kring->ring->head = kring->rhead = kring->nr_hwcur;
+
+ /* note, head/rhead/hwcur might be behind cur/rcur
+ * if no carrier
+ */
+ ND(5, "%s now hwcur %d hwtail %d head %d cur %d tail %d",
+ kring->name, kring->nr_hwcur, kring->nr_hwtail,
+ kring->rhead, kring->rcur, kring->rtail);
+}
- /* update avail and reserved to what the kernel knows */
- kring->ring->avail = kring->nr_hwavail;
- kring->ring->reserved = kring->nr_hwreserved;
+
+/*
+ * update kring and ring at the end of rxsync
+ */
+static inline void
+nm_rxsync_finalize(struct netmap_kring *kring)
+{
+ /* tell userspace that there might be new packets */
+ //struct netmap_ring *ring = kring->ring;
+ ND("head %d cur %d tail %d -> %d", ring->head, ring->cur, ring->tail,
+ kring->nr_hwtail);
+ kring->ring->tail = kring->rtail = kring->nr_hwtail;
+ /* make a copy of the state for next round */
+ kring->rhead = kring->ring->head;
+ kring->rcur = kring->ring->cur;
}
+
/* check/fix address and len in tx rings */
#if 1 /* debug version */
#define NM_CHECK_ADDR_LEN(_a, _l) do { \
@@ -755,6 +821,8 @@ nm_txsync_finalize(struct netmap_kring *kring, u_int cur)
int netmap_update_config(struct netmap_adapter *na);
int netmap_krings_create(struct netmap_adapter *na, u_int ntx, u_int nrx, u_int tailroom);
void netmap_krings_delete(struct netmap_adapter *na);
+int netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwait);
+
struct netmap_if *
netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
@@ -766,10 +834,13 @@ u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create);
int netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na);
+
#ifdef WITH_VALE
/*
- * The following bridge-related interfaces are used by other kernel modules
- * In the version that only supports unicast or broadcast, the lookup
+ * The following bridge-related functions are used by other
+ * kernel modules.
+ *
+ * VALE only supports unicast or broadcast. The lookup
* function can return 0 .. NM_BDG_MAXPORTS-1 for regular ports,
* NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 for unknown.
* XXX in practice "unknown" might be handled same as broadcast.
@@ -799,8 +870,6 @@ int netmap_bdg_ctl(struct nmreq *nmr, bdg_lookup_fn_t func);
/* Various prototypes */
int netmap_poll(struct cdev *dev, int events, struct thread *td);
-
-
int netmap_init(void);
void netmap_fini(void);
int netmap_get_memory(struct netmap_priv_d* p);
@@ -811,7 +880,8 @@ int netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct t
/* netmap_adapter creation/destruction */
#define NM_IFPNAME(ifp) ((ifp) ? (ifp)->if_xname : "zombie")
-#define NM_DEBUG_PUTGET 1
+
+// #define NM_DEBUG_PUTGET 1
#ifdef NM_DEBUG_PUTGET
@@ -844,12 +914,15 @@ int netmap_adapter_put(struct netmap_adapter *na);
#endif /* !NM_DEBUG_PUTGET */
+/*
+ * module variables
+ */
extern u_int netmap_buf_size;
#define NETMAP_BUF_SIZE netmap_buf_size // XXX remove
-extern int netmap_mitigate;
+extern int netmap_mitigate; // XXX not really used
extern int netmap_no_pendintr;
-extern u_int netmap_total_buffers;
-extern char *netmap_buffer_base;
+extern u_int netmap_total_buffers; // global allocator
+extern char *netmap_buffer_base; // global allocator
extern int netmap_verbose; // XXX debugging
enum { /* verbose flags */
NM_VERB_ON = 1, /* generic verbose */
@@ -908,7 +981,7 @@ extern int netmap_generic_ringsize;
#ifdef __FreeBSD__
-/* Callback invoked by the dma machinery after a successfull dmamap_load */
+/* Callback invoked by the dma machinery after a successful dmamap_load */
static void netmap_dmamap_cb(__unused void *arg,
__unused bus_dma_segment_t * segs, __unused int nseg, __unused int error)
{
@@ -1053,31 +1126,27 @@ BDG_NMB(struct netmap_adapter *na, struct netmap_slot *slot)
lut[0].vaddr : lut[i].vaddr;
}
-/* default functions to handle rx/tx interrupts */
-int netmap_rx_irq(struct ifnet *, u_int, u_int *);
-#define netmap_tx_irq(_n, _q) netmap_rx_irq(_n, _q, NULL)
-void netmap_common_irq(struct ifnet *, u_int, u_int *work_done);
void netmap_txsync_to_host(struct netmap_adapter *na);
-void netmap_disable_all_rings(struct ifnet *);
-void netmap_enable_all_rings(struct ifnet *);
-void netmap_disable_ring(struct netmap_kring *kr);
-/* Structure associated to each thread which registered an interface.
+/*
+ * Structure associated to each thread which registered an interface.
*
* The first 4 fields of this structure are written by NIOCREGIF and
* read by poll() and NIOC?XSYNC.
- * There is low contention among writers (actually, a correct user program
- * should have no contention among writers) and among writers and readers,
- * so we use a single global lock to protect the structure initialization.
- * Since initialization involves the allocation of memory, we reuse the memory
- * allocator lock.
+ *
+ * There is low contention among writers (a correct user program
+ * should have none) and among writers and readers, so we use a
+ * single global lock to protect the structure initialization;
+ * since initialization involves the allocation of memory,
+ * we reuse the memory allocator lock.
+ *
* Read access to the structure is lock free. Readers must check that
* np_nifp is not NULL before using the other fields.
- * If np_nifp is NULL initialization has not been performed, so they should
- * return an error to userlevel.
+ * If np_nifp is NULL initialization has not been performed,
+ * so they should return an error to userspace.
*
* The ref_done field is used to regulate access to the refcount in the
* memory allocator. The refcount must be incremented at most once for
@@ -1091,38 +1160,29 @@ struct netmap_priv_d {
struct netmap_if * volatile np_nifp; /* netmap if descriptor. */
struct netmap_adapter *np_na;
- int np_ringid; /* from the ioctl */
- u_int np_qfirst, np_qlast; /* range of rings to scan */
- uint16_t np_txpoll;
+ int np_ringid; /* from the ioctl */
+ u_int np_qfirst, np_qlast; /* range of rings to scan */
+ uint16_t np_txpoll;
struct netmap_mem_d *np_mref; /* use with NMG_LOCK held */
/* np_refcount is only used on FreeBSD */
- int np_refcount; /* use with NMG_LOCK held */
+ int np_refcount; /* use with NMG_LOCK held */
};
/*
* generic netmap emulation for devices that do not have
* native netmap support.
- * XXX generic_netmap_register() is only exported to implement
- * nma_is_generic().
*/
-int generic_netmap_register(struct netmap_adapter *na, int enable);
int generic_netmap_attach(struct ifnet *ifp);
int netmap_catch_rx(struct netmap_adapter *na, int intercept);
void generic_rx_handler(struct ifnet *ifp, struct mbuf *m);;
-void netmap_catch_packet_steering(struct netmap_generic_adapter *na, int enable);
+void netmap_catch_tx(struct netmap_generic_adapter *na, int enable);
int generic_xmit_frame(struct ifnet *ifp, struct mbuf *m, void *addr, u_int len, u_int ring_nr);
int generic_find_num_desc(struct ifnet *ifp, u_int *tx, u_int *rx);
void generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq);
-static __inline int
-nma_is_generic(struct netmap_adapter *na)
-{
- return na->nm_register == generic_netmap_register;
-}
-
/*
* netmap_mitigation API. This is used by the generic adapter
* to reduce the number of interrupt requests/selwakeup
@@ -1134,6 +1194,4 @@ void netmap_mitigation_restart(struct netmap_generic_adapter *na);
int netmap_mitigation_active(struct netmap_generic_adapter *na);
void netmap_mitigation_cleanup(struct netmap_generic_adapter *na);
-// int generic_timer_handler(struct hrtimer *t);
-
#endif /* _NET_NETMAP_KERN_H_ */