aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/netmap
diff options
context:
space:
mode:
authorLuigi Rizzo <luigi@FreeBSD.org>2012-05-17 15:02:51 +0000
committerLuigi Rizzo <luigi@FreeBSD.org>2012-05-17 15:02:51 +0000
commitff78552d0cd5733e887481436794860af5c87275 (patch)
tree75820565dca0a52fecc351a34300ef7b41b3fff9 /sys/dev/netmap
parent5da0d12406866662f5214acb681caee06bb7b97f (diff)
Notes
Diffstat (limited to 'sys/dev/netmap')
-rw-r--r--sys/dev/netmap/if_em_netmap.h194
-rw-r--r--sys/dev/netmap/if_igb_netmap.h213
-rw-r--r--sys/dev/netmap/if_lem_netmap.h212
-rw-r--r--sys/dev/netmap/if_re_netmap.h181
-rw-r--r--sys/dev/netmap/ixgbe_netmap.h316
-rw-r--r--sys/dev/netmap/netmap.c987
-rw-r--r--sys/dev/netmap/netmap_kern.h101
7 files changed, 893 insertions, 1311 deletions
diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index 8b0c7e88b79b..8a3893e3b1a4 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -25,49 +25,25 @@
/*
* $FreeBSD$
- * $Id: if_em_netmap.h 9802 2011-12-02 18:42:37Z luigi $
+ * $Id: if_em_netmap.h 10627 2012-02-23 19:37:15Z luigi $
*
- * netmap changes for if_em.
+ * netmap support for em.
*
- * For structure and details on the individual functions please see
- * ixgbe_netmap.h
+ * For more details on netmap support please see ixgbe_netmap.h
*/
+
#include <net/netmap.h>
#include <sys/selinfo.h>
#include <vm/vm.h>
#include <vm/pmap.h> /* vtophys ? */
#include <dev/netmap/netmap_kern.h>
+
static void em_netmap_block_tasks(struct adapter *);
static void em_netmap_unblock_tasks(struct adapter *);
-static int em_netmap_reg(struct ifnet *, int onoff);
-static int em_netmap_txsync(struct ifnet *, u_int, int);
-static int em_netmap_rxsync(struct ifnet *, u_int, int);
-static void em_netmap_lock_wrapper(struct ifnet *, int, u_int);
-static void
-em_netmap_attach(struct adapter *adapter)
-{
- struct netmap_adapter na;
-
- bzero(&na, sizeof(na));
- na.ifp = adapter->ifp;
- na.separate_locks = 1;
- na.num_tx_desc = adapter->num_tx_desc;
- na.num_rx_desc = adapter->num_rx_desc;
- na.nm_txsync = em_netmap_txsync;
- na.nm_rxsync = em_netmap_rxsync;
- na.nm_lock = em_netmap_lock_wrapper;
- na.nm_register = em_netmap_reg;
- netmap_attach(&na, adapter->num_queues);
-}
-
-
-/*
- * wrapper to export locks to the generic code
- */
static void
em_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int queueid)
{
@@ -137,8 +113,9 @@ em_netmap_unblock_tasks(struct adapter *adapter)
}
}
+
/*
- * register-unregister routine
+ * Register/unregister routine
*/
static int
em_netmap_reg(struct ifnet *ifp, int onoff)
@@ -170,7 +147,7 @@ em_netmap_reg(struct ifnet *ifp, int onoff)
}
} else {
fail:
- /* restore if_transmit */
+ /* return to non-netmap mode */
ifp->if_transmit = na->if_transmit;
ifp->if_capenable &= ~IFCAP_NETMAP;
em_init_locked(adapter); /* also enable intr */
@@ -179,18 +156,19 @@ fail:
return (error);
}
+
/*
- * Reconcile hardware and user view of the transmit ring.
+ * Reconcile kernel and user view of the transmit ring.
*/
static int
em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
{
struct adapter *adapter = ifp->if_softc;
struct tx_ring *txr = &adapter->tx_rings[ring_nr];
- struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_adapter *na = NA(ifp);
struct netmap_kring *kring = &na->tx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
+ u_int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
/* generate an interrupt approximately every half ring */
int report_frequency = kring->nkr_num_slots >> 1;
@@ -204,18 +182,17 @@ em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
BUS_DMASYNC_POSTREAD);
- /* check for new packets to send.
- * j indexes the netmap ring, l indexes the nic ring, and
- * j = kring->nr_hwcur, l = E1000_TDT (not tracked),
- * j == (l + kring->nkr_hwofs) % ring_size
+ /*
+ * Process new packets to send. j is the current index in the
+ * netmap ring, l is the corresponding index in the NIC ring.
*/
j = kring->nr_hwcur;
- if (j != k) { /* we have packets to send */
- l = j - kring->nkr_hwofs;
- if (l < 0)
- l += lim + 1;
- while (j != k) {
+ if (j != k) { /* we have new packets to send */
+ l = netmap_idx_k2n(kring, j);
+ for (n = 0; j != k; n++) {
+ /* slot is the current slot in the netmap ring */
struct netmap_slot *slot = &ring->slot[j];
+ /* curr is the current slot in the nic ring */
struct e1000_tx_desc *curr = &txr->tx_base[l];
struct em_buffer *txbuf = &txr->tx_buffers[l];
int flags = ((slot->flags & NS_REPORT) ||
@@ -223,7 +200,8 @@ em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
E1000_TXD_CMD_RS : 0;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
- int len = slot->len;
+ u_int len = slot->len;
+
if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) {
if (do_lock)
EM_TX_UNLOCK(txr);
@@ -231,26 +209,21 @@ em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
}
slot->flags &= ~NS_REPORT;
- curr->upper.data = 0;
- curr->lower.data =
- htole32(adapter->txd_cmd | len |
- (E1000_TXD_CMD_EOP | flags) );
if (slot->flags & NS_BUF_CHANGED) {
curr->buffer_addr = htole64(paddr);
/* buffer has changed, reload map */
netmap_reload_map(txr->txtag, txbuf->map, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
-
+ curr->upper.data = 0;
+ curr->lower.data = htole32(adapter->txd_cmd | len |
+ (E1000_TXD_CMD_EOP | flags) );
bus_dmamap_sync(txr->txtag, txbuf->map,
BUS_DMASYNC_PREWRITE);
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
- kring->nr_hwcur = k;
-
- /* decrease avail by number of sent packets */
+ kring->nr_hwcur = k; /* the saved ring->cur */
kring->nr_hwavail -= n;
bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
@@ -262,9 +235,9 @@ em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
if (n == 0 || kring->nr_hwavail < 1) {
int delta;
- /* record completed transmissions using THD. */
+ /* record completed transmissions using TDH */
l = E1000_READ_REG(&adapter->hw, E1000_TDH(ring_nr));
- if (l >= kring->nkr_num_slots) { /* XXX can happen */
+ if (l >= kring->nkr_num_slots) { /* XXX can it happen ? */
D("TDH wrap %d", l);
l -= kring->nkr_num_slots;
}
@@ -277,7 +250,7 @@ em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
kring->nr_hwavail += delta;
}
}
- /* update avail to what the hardware knows */
+ /* update avail to what the kernel knows */
ring->avail = kring->nr_hwavail;
if (do_lock)
@@ -285,6 +258,7 @@ em_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
return 0;
}
+
/*
* Reconcile kernel and user view of the receive ring.
*/
@@ -293,10 +267,12 @@ em_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
{
struct adapter *adapter = ifp->if_softc;
struct rx_ring *rxr = &adapter->rx_rings[ring_nr];
- struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_adapter *na = NA(ifp);
struct netmap_kring *kring = &na->rx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n, lim = kring->nkr_num_slots - 1;
+ u_int j, l, n, lim = kring->nkr_num_slots - 1;
+ int force_update = do_lock || kring->nr_kflags & NKR_PENDINTR;
+ u_int k = ring->cur, resvd = ring->reserved;
k = ring->cur;
if (k > lim)
@@ -304,53 +280,51 @@ em_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
if (do_lock)
EM_RX_LOCK(rxr);
+
/* XXX check sync modes */
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- /* import newly received packets into the netmap ring.
- * j is an index in the netmap ring, l in the NIC ring, and
- * j = (kring->nr_hwcur + kring->nr_hwavail) % ring_size
- * l = rxr->next_to_check;
- * and
- * j == (l + kring->nkr_hwofs) % ring_size
+ /*
+ * Import newly received packets into the netmap ring.
+ * j is an index in the netmap ring, l in the NIC ring.
*/
l = rxr->next_to_check;
- j = l + kring->nkr_hwofs;
- /* here nkr_hwofs can be negative so must check for j < 0 */
- if (j < 0)
- j += lim + 1;
- else if (j > lim)
- j -= lim + 1;
- for (n = 0; ; n++) {
- struct e1000_rx_desc *curr = &rxr->rx_base[l];
+ j = netmap_idx_n2k(kring, l);
+ if (netmap_no_pendintr || force_update) {
+ for (n = 0; ; n++) {
+ struct e1000_rx_desc *curr = &rxr->rx_base[l];
+ uint32_t staterr = le32toh(curr->status);
- if ((curr->status & E1000_RXD_STAT_DD) == 0)
- break;
- ring->slot[j].len = le16toh(curr->length);
- bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[l].map,
- BUS_DMASYNC_POSTREAD);
- j = (j == lim) ? 0 : j + 1;
- /* make sure next_to_refresh follows next_to_check */
- rxr->next_to_refresh = l; // XXX
- l = (l == lim) ? 0 : l + 1;
- }
- if (n) {
- rxr->next_to_check = l;
- kring->nr_hwavail += n;
+ if ((staterr & E1000_RXD_STAT_DD) == 0)
+ break;
+ ring->slot[j].len = le16toh(curr->length);
+ bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[l].map,
+ BUS_DMASYNC_POSTREAD);
+ j = (j == lim) ? 0 : j + 1;
+ /* make sure next_to_refresh follows next_to_check */
+ rxr->next_to_refresh = l; // XXX
+ l = (l == lim) ? 0 : l + 1;
+ }
+ if (n) { /* update the state variables */
+ rxr->next_to_check = l;
+ kring->nr_hwavail += n;
+ }
+ kring->nr_kflags &= ~NKR_PENDINTR;
}
- /* skip past packets that userspace has already processed */
- j = kring->nr_hwcur;
- if (j != k) { /* userspace has read some packets. */
- n = 0;
- l = j - kring->nkr_hwofs; /* NIC ring index */
- /* here nkr_hwofs can be negative so check for l > lim */
- if (l < 0)
- l += lim + 1;
- else if (l > lim)
- l -= lim + 1;
- while (j != k) {
+ /* skip past packets that userspace has released */
+ j = kring->nr_hwcur; /* netmap ring index */
+ if (resvd > 0) {
+ if (resvd + ring->avail >= lim + 1) {
+ D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
+ ring->reserved = resvd = 0; // XXX panic...
+ }
+ k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;
+ }
+ if (j != k) { /* userspace has released some packets. */
+ l = netmap_idx_k2n(kring, j); /* NIC ring index */
+ for (n = 0; j != k; n++) {
struct netmap_slot *slot = &ring->slot[j];
struct e1000_rx_desc *curr = &rxr->rx_base[l];
struct em_buffer *rxbuf = &rxr->rx_buffers[l];
@@ -363,20 +337,17 @@ em_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
return netmap_ring_reinit(kring);
}
- curr->status = 0;
if (slot->flags & NS_BUF_CHANGED) {
curr->buffer_addr = htole64(paddr);
/* buffer has changed, reload map */
netmap_reload_map(rxr->rxtag, rxbuf->map, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
-
+ curr->status = 0;
bus_dmamap_sync(rxr->rxtag, rxbuf->map,
BUS_DMASYNC_PREREAD);
-
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
kring->nr_hwavail -= n;
kring->nr_hwcur = k;
@@ -390,8 +361,29 @@ em_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), l);
}
/* tell userspace that there are new packets */
- ring->avail = kring->nr_hwavail ;
+ ring->avail = kring->nr_hwavail - resvd;
if (do_lock)
EM_RX_UNLOCK(rxr);
return 0;
}
+
+
+static void
+em_netmap_attach(struct adapter *adapter)
+{
+ struct netmap_adapter na;
+
+ bzero(&na, sizeof(na));
+
+ na.ifp = adapter->ifp;
+ na.separate_locks = 1;
+ na.num_tx_desc = adapter->num_tx_desc;
+ na.num_rx_desc = adapter->num_rx_desc;
+ na.nm_txsync = em_netmap_txsync;
+ na.nm_rxsync = em_netmap_rxsync;
+ na.nm_lock = em_netmap_lock_wrapper;
+ na.nm_register = em_netmap_reg;
+ netmap_attach(&na, adapter->num_queues);
+}
+
+/* end of file */
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index 0ee455f3e9e5..8ba13ee6af61 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -25,42 +25,19 @@
/*
* $FreeBSD$
- * $Id: if_igb_netmap.h 9802 2011-12-02 18:42:37Z luigi $
+ * $Id: if_igb_netmap.h 10627 2012-02-23 19:37:15Z luigi $
*
- * netmap modifications for igb
- * contribured by Ahmed Kooli
+ * Netmap support for igb, partly contributed by Ahmed Kooli
+ * For details on netmap support please see ixgbe_netmap.h
*/
+
#include <net/netmap.h>
#include <sys/selinfo.h>
#include <vm/vm.h>
#include <vm/pmap.h> /* vtophys ? */
#include <dev/netmap/netmap_kern.h>
-static int igb_netmap_reg(struct ifnet *, int onoff);
-static int igb_netmap_txsync(struct ifnet *, u_int, int);
-static int igb_netmap_rxsync(struct ifnet *, u_int, int);
-static void igb_netmap_lock_wrapper(struct ifnet *, int, u_int);
-
-
-static void
-igb_netmap_attach(struct adapter *adapter)
-{
- struct netmap_adapter na;
-
- bzero(&na, sizeof(na));
-
- na.ifp = adapter->ifp;
- na.separate_locks = 1;
- na.num_tx_desc = adapter->num_tx_desc;
- na.num_rx_desc = adapter->num_rx_desc;
- na.nm_txsync = igb_netmap_txsync;
- na.nm_rxsync = igb_netmap_rxsync;
- na.nm_lock = igb_netmap_lock_wrapper;
- na.nm_register = igb_netmap_reg;
- netmap_attach(&na, adapter->num_queues);
-}
-
/*
* wrapper to export locks to the generic code
@@ -95,8 +72,7 @@ igb_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int queueid)
/*
- * support for netmap register/unregisted. We are already under core lock.
- * only called on the first init or the last unregister.
+ * register-unregister routine
*/
static int
igb_netmap_reg(struct ifnet *ifp, int onoff)
@@ -106,7 +82,7 @@ igb_netmap_reg(struct ifnet *ifp, int onoff)
int error = 0;
if (na == NULL)
- return EINVAL;
+ return EINVAL; /* no netmap support here */
igb_disable_intr(adapter);
@@ -116,7 +92,6 @@ igb_netmap_reg(struct ifnet *ifp, int onoff)
if (onoff) {
ifp->if_capenable |= IFCAP_NETMAP;
- /* save if_transmit to restore it later */
na->if_transmit = ifp->if_transmit;
ifp->if_transmit = netmap_start;
@@ -130,7 +105,7 @@ fail:
/* restore if_transmit */
ifp->if_transmit = na->if_transmit;
ifp->if_capenable &= ~IFCAP_NETMAP;
- igb_init_locked(adapter); /* also enables intr */
+ igb_init_locked(adapter); /* also enable intr */
}
return (error);
}
@@ -144,10 +119,10 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
{
struct adapter *adapter = ifp->if_softc;
struct tx_ring *txr = &adapter->tx_rings[ring_nr];
- struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_adapter *na = NA(ifp);
struct netmap_kring *kring = &na->tx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
+ u_int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
/* generate an interrupt approximately every half ring */
int report_frequency = kring->nkr_num_slots >> 1;
@@ -161,31 +136,31 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
BUS_DMASYNC_POSTREAD);
- /* update avail to what the hardware knows */
- ring->avail = kring->nr_hwavail;
-
- j = kring->nr_hwcur; /* netmap ring index */
+ /* check for new packets to send.
+ * j indexes the netmap ring, l indexes the nic ring, and
+ * j = kring->nr_hwcur, l = E1000_TDT (not tracked),
+ * j == (l + kring->nkr_hwofs) % ring_size
+ */
+ j = kring->nr_hwcur;
if (j != k) { /* we have new packets to send */
- u32 olinfo_status = 0;
-
- l = j - kring->nkr_hwofs; /* NIC ring index */
- if (l < 0)
- l += lim + 1;
/* 82575 needs the queue index added */
- if (adapter->hw.mac.type == e1000_82575)
- olinfo_status |= txr->me << 4;
+ u32 olinfo_status =
+ (adapter->hw.mac.type == e1000_82575) ? (txr->me << 4) : 0;
- while (j != k) {
+ l = netmap_idx_k2n(kring, j);
+ for (n = 0; j != k; n++) {
+ /* slot is the current slot in the netmap ring */
struct netmap_slot *slot = &ring->slot[j];
- struct igb_tx_buffer *txbuf = &txr->tx_buffers[l];
+ /* curr is the current slot in the nic ring */
union e1000_adv_tx_desc *curr =
(union e1000_adv_tx_desc *)&txr->tx_base[l];
- uint64_t paddr;
- void *addr = PNMB(slot, &paddr);
+ struct igb_tx_buffer *txbuf = &txr->tx_buffers[l];
int flags = ((slot->flags & NS_REPORT) ||
j == 0 || j == report_frequency) ?
E1000_ADVTXD_DCMD_RS : 0;
- int len = slot->len;
+ uint64_t paddr;
+ void *addr = PNMB(slot, &paddr);
+ u_int len = slot->len;
if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) {
if (do_lock)
@@ -194,8 +169,13 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
}
slot->flags &= ~NS_REPORT;
- // XXX do we need to set the address ?
+ if (slot->flags & NS_BUF_CHANGED) {
+ /* buffer has changed, reload map */
+ netmap_reload_map(txr->txtag, txbuf->map, addr);
+ slot->flags &= ~NS_BUF_CHANGED;
+ }
curr->read.buffer_addr = htole64(paddr);
+ // XXX check olinfo and cmd_type_len
curr->read.olinfo_status =
htole32(olinfo_status |
(len<< E1000_ADVTXD_PAYLEN_SHIFT));
@@ -204,23 +184,14 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
E1000_ADVTXD_DCMD_IFCS |
E1000_ADVTXD_DCMD_DEXT |
E1000_ADVTXD_DCMD_EOP | flags);
- if (slot->flags & NS_BUF_CHANGED) {
- /* buffer has changed, reload map */
- netmap_reload_map(txr->txtag, txbuf->map, addr);
- slot->flags &= ~NS_BUF_CHANGED;
- }
bus_dmamap_sync(txr->txtag, txbuf->map,
BUS_DMASYNC_PREWRITE);
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
- kring->nr_hwcur = k;
-
- /* decrease avail by number of sent packets */
+ kring->nr_hwcur = k; /* the saved ring->cur */
kring->nr_hwavail -= n;
- ring->avail = kring->nr_hwavail;
/* Set the watchdog XXX ? */
txr->queue_status = IGB_QUEUE_WORKING;
@@ -231,23 +202,28 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), l);
}
+
if (n == 0 || kring->nr_hwavail < 1) {
int delta;
- /* record completed transmission using TDH */
+ /* record completed transmissions using TDH */
l = E1000_READ_REG(&adapter->hw, E1000_TDH(ring_nr));
- if (l >= kring->nkr_num_slots) /* XXX can it happen ? */
+ if (l >= kring->nkr_num_slots) { /* XXX can it happen ? */
+ D("TDH wrap %d", l);
l -= kring->nkr_num_slots;
+ }
delta = l - txr->next_to_clean;
if (delta) {
- /* new tx were completed */
+ /* some completed, increment hwavail. */
if (delta < 0)
delta += kring->nkr_num_slots;
txr->next_to_clean = l;
kring->nr_hwavail += delta;
- ring->avail = kring->nr_hwavail;
}
}
+ /* update avail to what the kernel knows */
+ ring->avail = kring->nr_hwavail;
+
if (do_lock)
IGB_TX_UNLOCK(txr);
return 0;
@@ -262,10 +238,12 @@ igb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
{
struct adapter *adapter = ifp->if_softc;
struct rx_ring *rxr = &adapter->rx_rings[ring_nr];
- struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_adapter *na = NA(ifp);
struct netmap_kring *kring = &na->rx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n, lim = kring->nkr_num_slots - 1;
+ u_int j, l, n, lim = kring->nkr_num_slots - 1;
+ int force_update = do_lock || kring->nr_kflags & NKR_PENDINTR;
+ u_int k = ring->cur, resvd = ring->reserved;
k = ring->cur;
if (k > lim)
@@ -274,45 +252,48 @@ igb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
if (do_lock)
IGB_RX_LOCK(rxr);
- /* Sync the ring. */
+ /* XXX check sync modes */
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ /*
+ * import newly received packets into the netmap ring.
+ * j is an index in the netmap ring, l in the NIC ring.
+ */
l = rxr->next_to_check;
- j = l + kring->nkr_hwofs;
- if (j > lim)
- j -= lim + 1;
- for (n = 0; ; n++) {
- union e1000_adv_rx_desc *curr = &rxr->rx_base[l];
- uint32_t staterr = le32toh(curr->wb.upper.status_error);
+ j = netmap_idx_n2k(kring, l);
+ if (netmap_no_pendintr || force_update) {
+ for (n = 0; ; n++) {
+ union e1000_adv_rx_desc *curr = &rxr->rx_base[l];
+ uint32_t staterr = le32toh(curr->wb.upper.status_error);
- if ((staterr & E1000_RXD_STAT_DD) == 0)
- break;
- ring->slot[j].len = le16toh(curr->wb.upper.length);
-
- bus_dmamap_sync(rxr->ptag,
- rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD);
- j = (j == lim) ? 0 : j + 1;
- l = (l == lim) ? 0 : l + 1;
- }
- if (n) {
- rxr->next_to_check = l;
- kring->nr_hwavail += n;
+ if ((staterr & E1000_RXD_STAT_DD) == 0)
+ break;
+ ring->slot[j].len = le16toh(curr->wb.upper.length);
+ bus_dmamap_sync(rxr->ptag,
+ rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD);
+ j = (j == lim) ? 0 : j + 1;
+ l = (l == lim) ? 0 : l + 1;
+ }
+ if (n) { /* update the state variables */
+ rxr->next_to_check = l;
+ kring->nr_hwavail += n;
+ }
+ kring->nr_kflags &= ~NKR_PENDINTR;
}
- /* skip past packets that userspace has already processed,
- * making them available for reception.
- * advance nr_hwcur and issue a bus_dmamap_sync on the
- * buffers so it is safe to write to them.
- * Also increase nr_hwavail
- */
- j = kring->nr_hwcur;
- l = kring->nr_hwcur - kring->nkr_hwofs;
- if (l < 0)
- l += lim + 1;
- if (j != k) { /* userspace has read some packets. */
- n = 0;
- while (j != k) {
+ /* skip past packets that userspace has released */
+ j = kring->nr_hwcur; /* netmap ring index */
+ if (resvd > 0) {
+ if (resvd + ring->avail >= lim + 1) {
+ D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
+ ring->reserved = resvd = 0; // XXX panic...
+ }
+ k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;
+ }
+ if (j != k) { /* userspace has released some packets. */
+ l = netmap_idx_k2n(kring, j);
+ for (n = 0; j != k; n++) {
struct netmap_slot *slot = ring->slot + j;
union e1000_adv_rx_desc *curr = &rxr->rx_base[l];
struct igb_rx_buf *rxbuf = rxr->rx_buffers + l;
@@ -325,33 +306,51 @@ igb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
return netmap_ring_reinit(kring);
}
- curr->wb.upper.status_error = 0;
- curr->read.pkt_addr = htole64(paddr);
if (slot->flags & NS_BUF_CHANGED) {
netmap_reload_map(rxr->ptag, rxbuf->pmap, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
-
+ curr->read.pkt_addr = htole64(paddr);
+ curr->wb.upper.status_error = 0;
bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
BUS_DMASYNC_PREREAD);
-
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
kring->nr_hwavail -= n;
- kring->nr_hwcur = ring->cur;
+ kring->nr_hwcur = k;
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
- /* IMPORTANT: we must leave one free slot in the ring,
+ /*
+ * IMPORTANT: we must leave one free slot in the ring,
* so move l back by one unit
*/
l = (l == 0) ? lim : l - 1;
E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), l);
}
/* tell userspace that there are new packets */
- ring->avail = kring->nr_hwavail ;
+ ring->avail = kring->nr_hwavail - resvd;
if (do_lock)
IGB_RX_UNLOCK(rxr);
return 0;
}
+
+
+static void
+igb_netmap_attach(struct adapter *adapter)
+{
+ struct netmap_adapter na;
+
+ bzero(&na, sizeof(na));
+
+ na.ifp = adapter->ifp;
+ na.separate_locks = 1;
+ na.num_tx_desc = adapter->num_tx_desc;
+ na.num_rx_desc = adapter->num_rx_desc;
+ na.nm_txsync = igb_netmap_txsync;
+ na.nm_rxsync = igb_netmap_rxsync;
+ na.nm_lock = igb_netmap_lock_wrapper;
+ na.nm_register = igb_netmap_reg;
+ netmap_attach(&na, adapter->num_queues);
+}
+/* end of file */
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index 5ce93b914847..9f24580a9e8d 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -23,14 +23,14 @@
* SUCH DAMAGE.
*/
+
/*
* $FreeBSD$
- * $Id: if_lem_netmap.h 9802 2011-12-02 18:42:37Z luigi $
+ * $Id: if_lem_netmap.h 10627 2012-02-23 19:37:15Z luigi $
*
- * netmap support for if_lem.c
+ * netmap support for "lem"
*
- * For structure and details on the individual functions please see
- * ixgbe_netmap.h
+ * For details on netmap support please see ixgbe_netmap.h
*/
#include <net/netmap.h>
@@ -39,32 +39,6 @@
#include <vm/pmap.h> /* vtophys ? */
#include <dev/netmap/netmap_kern.h>
-static int lem_netmap_reg(struct ifnet *, int onoff);
-static int lem_netmap_txsync(struct ifnet *, u_int, int);
-static int lem_netmap_rxsync(struct ifnet *, u_int, int);
-static void lem_netmap_lock_wrapper(struct ifnet *, int, u_int);
-
-
-SYSCTL_NODE(_dev, OID_AUTO, lem, CTLFLAG_RW, 0, "lem card");
-
-static void
-lem_netmap_attach(struct adapter *adapter)
-{
- struct netmap_adapter na;
-
- bzero(&na, sizeof(na));
-
- na.ifp = adapter->ifp;
- na.separate_locks = 1;
- na.num_tx_desc = adapter->num_tx_desc;
- na.num_rx_desc = adapter->num_rx_desc;
- na.nm_txsync = lem_netmap_txsync;
- na.nm_rxsync = lem_netmap_rxsync;
- na.nm_lock = lem_netmap_lock_wrapper;
- na.nm_register = lem_netmap_reg;
- netmap_attach(&na, 1);
-}
-
static void
lem_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int ringid)
@@ -96,7 +70,7 @@ lem_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int ringid)
/*
- * Register/unregister routine
+ * Register/unregister
*/
static int
lem_netmap_reg(struct ifnet *ifp, int onoff)
@@ -113,7 +87,6 @@ lem_netmap_reg(struct ifnet *ifp, int onoff)
/* Tell the stack that the interface is no longer active */
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
- /* lem_netmap_block_tasks(adapter); */
#ifndef EM_LEGACY_IRQ // XXX do we need this ?
taskqueue_block(adapter->tq);
taskqueue_drain(adapter->tq, &adapter->rxtx_task);
@@ -122,9 +95,6 @@ lem_netmap_reg(struct ifnet *ifp, int onoff)
if (onoff) {
ifp->if_capenable |= IFCAP_NETMAP;
- /* save if_transmit to restore it when exiting.
- * XXX what about if_start and if_qflush ?
- */
na->if_transmit = ifp->if_transmit;
ifp->if_transmit = netmap_start;
@@ -135,10 +105,10 @@ lem_netmap_reg(struct ifnet *ifp, int onoff)
}
} else {
fail:
- /* restore non-netmap mode */
+ /* return to non-netmap mode */
ifp->if_transmit = na->if_transmit;
ifp->if_capenable &= ~IFCAP_NETMAP;
- lem_init_locked(adapter); /* also enables intr */
+ lem_init_locked(adapter); /* also enable intr */
}
#ifndef EM_LEGACY_IRQ
@@ -156,14 +126,15 @@ static int
lem_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
{
struct adapter *adapter = ifp->if_softc;
- struct netmap_adapter *na = NA(adapter->ifp);
- struct netmap_kring *kring = &na->tx_rings[0];
+ struct netmap_adapter *na = NA(ifp);
+ struct netmap_kring *kring = &na->tx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
+ u_int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
/* generate an interrupt approximately every half ring */
int report_frequency = kring->nkr_num_slots >> 1;
+ /* take a copy of ring->cur now, and never read it again */
k = ring->cur;
if (k > lim)
return netmap_ring_reinit(kring);
@@ -172,25 +143,25 @@ lem_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
EM_TX_LOCK(adapter);
bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
BUS_DMASYNC_POSTREAD);
-
- /* update avail to what the hardware knows */
- ring->avail = kring->nr_hwavail;
-
- j = kring->nr_hwcur; /* points into the netmap ring */
+ /*
+ * Process new packets to send. j is the current index in the
+ * netmap ring, l is the corresponding index in the NIC ring.
+ */
+ j = kring->nr_hwcur;
if (j != k) { /* we have new packets to send */
- l = j - kring->nkr_hwofs; /* points into the NIC ring */
- if (l < 0)
- l += lim + 1;
- while (j != k) {
+ l = netmap_idx_k2n(kring, j);
+ for (n = 0; j != k; n++) {
+ /* slot is the current slot in the netmap ring */
struct netmap_slot *slot = &ring->slot[j];
+ /* curr is the current slot in the nic ring */
struct e1000_tx_desc *curr = &adapter->tx_desc_base[l];
struct em_buffer *txbuf = &adapter->tx_buffer_area[l];
- uint64_t paddr;
- void *addr = PNMB(slot, &paddr);
int flags = ((slot->flags & NS_REPORT) ||
j == 0 || j == report_frequency) ?
E1000_TXD_CMD_RS : 0;
- int len = slot->len;
+ uint64_t paddr;
+ void *addr = PNMB(slot, &paddr);
+ u_int len = slot->len;
if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) {
if (do_lock)
@@ -199,28 +170,24 @@ lem_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
}
slot->flags &= ~NS_REPORT;
- curr->upper.data = 0;
- curr->lower.data =
- htole32( adapter->txd_cmd | len |
- (E1000_TXD_CMD_EOP | flags) );
if (slot->flags & NS_BUF_CHANGED) {
- curr->buffer_addr = htole64(paddr);
/* buffer has changed, reload map */
netmap_reload_map(adapter->txtag, txbuf->map, addr);
+ curr->buffer_addr = htole64(paddr);
slot->flags &= ~NS_BUF_CHANGED;
}
+ curr->upper.data = 0;
+ curr->lower.data =
+ htole32( adapter->txd_cmd | len |
+ (E1000_TXD_CMD_EOP | flags) );
bus_dmamap_sync(adapter->txtag, txbuf->map,
BUS_DMASYNC_PREWRITE);
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
- kring->nr_hwcur = k;
-
- /* decrease avail by number of sent packets */
+ kring->nr_hwcur = k; /* the saved ring->cur */
kring->nr_hwavail -= n;
- ring->avail = kring->nr_hwavail;
bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -233,19 +200,21 @@ lem_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
/* record completed transmissions using TDH */
l = E1000_READ_REG(&adapter->hw, E1000_TDH(0));
- if (l >= kring->nkr_num_slots) { /* can it happen ? */
+ if (l >= kring->nkr_num_slots) { /* XXX can it happen ? */
D("bad TDH %d", l);
l -= kring->nkr_num_slots;
}
delta = l - adapter->next_tx_to_clean;
if (delta) {
+ /* some tx completed, increment hwavail. */
if (delta < 0)
delta += kring->nkr_num_slots;
adapter->next_tx_to_clean = l;
kring->nr_hwavail += delta;
- ring->avail = kring->nr_hwavail;
}
}
+ /* update avail to what the kernel knows */
+ ring->avail = kring->nr_hwavail;
if (do_lock)
EM_TX_UNLOCK(adapter);
@@ -260,57 +229,68 @@ static int
lem_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
{
struct adapter *adapter = ifp->if_softc;
- struct netmap_adapter *na = NA(adapter->ifp);
- struct netmap_kring *kring = &na->rx_rings[0];
+ struct netmap_adapter *na = NA(ifp);
+ struct netmap_kring *kring = &na->rx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n, lim = kring->nkr_num_slots - 1;
+ int j, l, n, lim = kring->nkr_num_slots - 1;
+ int force_update = do_lock || kring->nr_kflags & NKR_PENDINTR;
+ u_int k = ring->cur, resvd = ring->reserved;
- k = ring->cur;
if (k > lim)
return netmap_ring_reinit(kring);
if (do_lock)
EM_RX_LOCK(adapter);
+
/* XXX check sync modes */
bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- /* import newly received packets into the netmap ring */
- l = adapter->next_rx_desc_to_check; /* points into the NIC ring */
- j = l + kring->nkr_hwofs; /* points into the netmap ring */
- if (j > lim)
- j -= lim + 1;
- for (n = 0; ; n++) {
- struct e1000_rx_desc *curr = &adapter->rx_desc_base[l];
- int len;
-
- if ((curr->status & E1000_RXD_STAT_DD) == 0)
- break;
- len = le16toh(curr->length) - 4; // CRC
+ /*
+ * Import newly received packets into the netmap ring.
+ * j is an index in the netmap ring, l in the NIC ring.
+ */
+ l = adapter->next_rx_desc_to_check;
+ j = netmap_idx_n2k(kring, l);
+ if (netmap_no_pendintr || force_update) {
+ for (n = 0; ; n++) {
+ struct e1000_rx_desc *curr = &adapter->rx_desc_base[l];
+ uint32_t staterr = le32toh(curr->status);
+ int len;
- if (len < 0) {
- D("bogus pkt size at %d", j);
- len = 0;
+ if ((staterr & E1000_RXD_STAT_DD) == 0)
+ break;
+ len = le16toh(curr->length) - 4; // CRC
+ if (len < 0) {
+ D("bogus pkt size at %d", j);
+ len = 0;
+ }
+ ring->slot[j].len = len;
+ bus_dmamap_sync(adapter->rxtag,
+ adapter->rx_buffer_area[l].map,
+ BUS_DMASYNC_POSTREAD);
+ j = (j == lim) ? 0 : j + 1;
+ l = (l == lim) ? 0 : l + 1;
}
- ring->slot[j].len = len;
- bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[l].map,
- BUS_DMASYNC_POSTREAD);
- j = (j == lim) ? 0 : j + 1;
- l = (l == lim) ? 0 : l + 1;
- }
- if (n) {
- adapter->next_rx_desc_to_check = l;
- kring->nr_hwavail += n;
+ if (n) { /* update the state variables */
+ adapter->next_rx_desc_to_check = l;
+ kring->nr_hwavail += n;
+ }
+ kring->nr_kflags &= ~NKR_PENDINTR;
}
- /* skip past packets that userspace has already processed */
- j = kring->nr_hwcur; /* netmap ring index */
- if (j != k) { /* userspace has read some packets. */
- n = 0;
- l = j - kring->nkr_hwofs; /* NIC ring index */
- if (l < 0)
- l += lim + 1;
- while (j != k) {
+ /* skip past packets that userspace has released */
+ j = kring->nr_hwcur; /* netmap ring index */
+ if (resvd > 0) {
+ if (resvd + ring->avail >= lim + 1) {
+ D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
+ ring->reserved = resvd = 0; // XXX panic...
+ }
+ k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;
+ }
+ if (j != k) { /* userspace has released some packets. */
+ l = netmap_idx_k2n(kring, j); /* NIC ring index */
+ for (n = 0; j != k; n++) {
struct netmap_slot *slot = &ring->slot[j];
struct e1000_rx_desc *curr = &adapter->rx_desc_base[l];
struct em_buffer *rxbuf = &adapter->rx_buffer_area[l];
@@ -322,20 +302,20 @@ lem_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
EM_RX_UNLOCK(adapter);
return netmap_ring_reinit(kring);
}
- curr->status = 0;
+
if (slot->flags & NS_BUF_CHANGED) {
- curr->buffer_addr = htole64(paddr);
- /* buffer has changed, and reload map */
+ /* buffer has changed, reload map */
netmap_reload_map(adapter->rxtag, rxbuf->map, addr);
+ curr->buffer_addr = htole64(paddr);
slot->flags &= ~NS_BUF_CHANGED;
}
+ curr->status = 0;
bus_dmamap_sync(adapter->rxtag, rxbuf->map,
BUS_DMASYNC_PREREAD);
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
kring->nr_hwavail -= n;
kring->nr_hwcur = k;
@@ -348,12 +328,30 @@ lem_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
l = (l == 0) ? lim : l - 1;
E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), l);
}
-
/* tell userspace that there are new packets */
- ring->avail = kring->nr_hwavail ;
-
+ ring->avail = kring->nr_hwavail - resvd;
if (do_lock)
EM_RX_UNLOCK(adapter);
return 0;
}
+
+
+static void
+lem_netmap_attach(struct adapter *adapter)
+{
+ struct netmap_adapter na;
+
+ bzero(&na, sizeof(na));
+
+ na.ifp = adapter->ifp;
+ na.separate_locks = 1;
+ na.num_tx_desc = adapter->num_tx_desc;
+ na.num_rx_desc = adapter->num_rx_desc;
+ na.nm_txsync = lem_netmap_txsync;
+ na.nm_rxsync = lem_netmap_rxsync;
+ na.nm_lock = lem_netmap_lock_wrapper;
+ na.nm_register = lem_netmap_reg;
+ netmap_attach(&na, 1);
+}
+
/* end of file */
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index af8e21a486ba..bdd57035b7b5 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -25,40 +25,19 @@
/*
* $FreeBSD$
- * $Id: if_re_netmap.h 10075 2011-12-25 22:55:48Z luigi $
+ * $Id: if_re_netmap.h 10609 2012-02-22 19:44:58Z luigi $
*
- * netmap support for if_re
+ * netmap support for "re"
+ * For details on netmap support please see ixgbe_netmap.h
*/
+
#include <net/netmap.h>
#include <sys/selinfo.h>
#include <vm/vm.h>
#include <vm/pmap.h> /* vtophys ? */
#include <dev/netmap/netmap_kern.h>
-static int re_netmap_reg(struct ifnet *, int onoff);
-static int re_netmap_txsync(struct ifnet *, u_int, int);
-static int re_netmap_rxsync(struct ifnet *, u_int, int);
-static void re_netmap_lock_wrapper(struct ifnet *, int, u_int);
-
-static void
-re_netmap_attach(struct rl_softc *sc)
-{
- struct netmap_adapter na;
-
- bzero(&na, sizeof(na));
-
- na.ifp = sc->rl_ifp;
- na.separate_locks = 0;
- na.num_tx_desc = sc->rl_ldata.rl_tx_desc_cnt;
- na.num_rx_desc = sc->rl_ldata.rl_rx_desc_cnt;
- na.nm_txsync = re_netmap_txsync;
- na.nm_rxsync = re_netmap_rxsync;
- na.nm_lock = re_netmap_lock_wrapper;
- na.nm_register = re_netmap_reg;
- netmap_attach(&na, 1);
-}
-
/*
* wrapper to export locks to the generic code
@@ -170,14 +149,13 @@ re_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
kring->nr_hwavail += n;
}
- /* update avail to what the hardware knows */
+ /* update avail to what the kernel knows */
ring->avail = kring->nr_hwavail;
j = kring->nr_hwcur;
if (j != k) { /* we have new packets to send */
- n = 0;
l = sc->rl_ldata.rl_tx_prodidx;
- while (j != k) {
+ for (n = 0; j != k; n++) {
struct netmap_slot *slot = &ring->slot[j];
struct rl_desc *desc = &sc->rl_ldata.rl_tx_list[l];
int cmd = slot->len | RL_TDESC_CMD_EOF |
@@ -210,13 +188,10 @@ re_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
txd[l].tx_dmamap, BUS_DMASYNC_PREWRITE);
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
sc->rl_ldata.rl_tx_prodidx = l;
- kring->nr_hwcur = k;
-
- /* decrease avail by number of sent packets */
- ring->avail -= n;
+ kring->nr_hwcur = k; /* the saved ring->cur */
+ ring->avail -= n; // XXX see others
kring->nr_hwavail = ring->avail;
bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
@@ -243,7 +218,9 @@ re_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
struct netmap_adapter *na = NA(sc->rl_ifp);
struct netmap_kring *kring = &na->rx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n, lim = kring->nkr_num_slots - 1;
+ int j, l, n, lim = kring->nkr_num_slots - 1;
+ int force_update = do_lock || kring->nr_kflags & NKR_PENDINTR;
+ u_int k = ring->cur, resvd = ring->reserved;
k = ring->cur;
if (k > lim)
@@ -257,52 +234,57 @@ re_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
/*
+ * Import newly received packets into the netmap ring.
+ * j is an index in the netmap ring, l in the NIC ring.
+ *
* The device uses all the buffers in the ring, so we need
* another termination condition in addition to RL_RDESC_STAT_OWN
* cleared (all buffers could have it cleared. The easiest one
* is to limit the amount of data reported up to 'lim'
*/
l = sc->rl_ldata.rl_rx_prodidx; /* next pkt to check */
- j = l + kring->nkr_hwofs;
- for (n = kring->nr_hwavail; n < lim ; n++) {
- struct rl_desc *cur_rx = &sc->rl_ldata.rl_rx_list[l];
- uint32_t rxstat = le32toh(cur_rx->rl_cmdstat);
- uint32_t total_len;
+ j = netmap_idx_n2k(kring, l); /* the kring index */
+ if (netmap_no_pendintr || force_update) {
+ for (n = kring->nr_hwavail; n < lim ; n++) {
+ struct rl_desc *cur_rx = &sc->rl_ldata.rl_rx_list[l];
+ uint32_t rxstat = le32toh(cur_rx->rl_cmdstat);
+ uint32_t total_len;
- if ((rxstat & RL_RDESC_STAT_OWN) != 0)
- break;
- total_len = rxstat & sc->rl_rxlenmask;
- /* XXX subtract crc */
- total_len = (total_len < 4) ? 0 : total_len - 4;
- kring->ring->slot[j].len = total_len;
- /* sync was in re_newbuf() */
- bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
- rxd[l].rx_dmamap, BUS_DMASYNC_POSTREAD);
- j = (j == lim) ? 0 : j + 1;
- l = (l == lim) ? 0 : l + 1;
- }
- if (n != kring->nr_hwavail) {
- sc->rl_ldata.rl_rx_prodidx = l;
- sc->rl_ifp->if_ipackets += n - kring->nr_hwavail;
- kring->nr_hwavail = n;
+ if ((rxstat & RL_RDESC_STAT_OWN) != 0)
+ break;
+ total_len = rxstat & sc->rl_rxlenmask;
+ /* XXX subtract crc */
+ total_len = (total_len < 4) ? 0 : total_len - 4;
+ kring->ring->slot[j].len = total_len;
+ /* sync was in re_newbuf() */
+ bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
+ rxd[l].rx_dmamap, BUS_DMASYNC_POSTREAD);
+ j = (j == lim) ? 0 : j + 1;
+ l = (l == lim) ? 0 : l + 1;
+ }
+ if (n != kring->nr_hwavail) {
+ sc->rl_ldata.rl_rx_prodidx = l;
+ sc->rl_ifp->if_ipackets += n - kring->nr_hwavail;
+ kring->nr_hwavail = n;
+ }
+ kring->nr_kflags &= ~NKR_PENDINTR;
}
- /* skip past packets that userspace has already processed,
- * making them available for reception.
- * advance nr_hwcur and issue a bus_dmamap_sync on the
- * buffers so it is safe to write to them.
- * Also increase nr_hwavail
- */
+ /* skip past packets that userspace has released */
j = kring->nr_hwcur;
- if (j != k) { /* userspace has read some packets. */
- n = 0;
- l = kring->nr_hwcur - kring->nkr_hwofs;
- if (l < 0)
- l += lim + 1;
- while (j != k) {
+ if (resvd > 0) {
+ if (resvd + ring->avail >= lim + 1) {
+ D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
+ ring->reserved = resvd = 0; // XXX panic...
+ }
+ k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;
+ }
+ if (j != k) { /* userspace has released some packets. */
+ l = netmap_idx_k2n(kring, j); /* the NIC index */
+ for (n = 0; j != k; n++) {
struct netmap_slot *slot = ring->slot + j;
struct rl_desc *desc = &sc->rl_ldata.rl_rx_list[l];
- int cmd = na->buff_size | RL_RDESC_CMD_OWN;
+ int cmd = NETMAP_BUF_SIZE | RL_RDESC_CMD_OWN;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
@@ -315,20 +297,19 @@ re_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
if (l == lim) /* mark end of ring */
cmd |= RL_RDESC_CMD_EOR;
- desc->rl_cmdstat = htole32(cmd);
slot->flags &= ~NS_REPORT;
if (slot->flags & NS_BUF_CHANGED) {
- desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
- desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
netmap_reload_map(sc->rl_ldata.rl_rx_mtag,
rxd[l].rx_dmamap, addr);
+ desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
+ desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
slot->flags &= ~NS_BUF_CHANGED;
}
+ desc->rl_cmdstat = htole32(cmd);
bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
rxd[l].rx_dmamap, BUS_DMASYNC_PREREAD);
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
kring->nr_hwavail -= n;
kring->nr_hwcur = k;
@@ -339,7 +320,7 @@ re_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
}
/* tell userspace that there are new packets */
- ring->avail = kring->nr_hwavail;
+ ring->avail = kring->nr_hwavail - resvd;
if (do_lock)
RL_UNLOCK(sc);
return 0;
@@ -368,15 +349,10 @@ re_netmap_tx_init(struct rl_softc *sc)
/* l points in the netmap ring, i points in the NIC ring */
for (i = 0; i < n; i++) {
- void *addr;
uint64_t paddr;
- struct netmap_kring *kring = &na->tx_rings[0];
- int l = i + kring->nkr_hwofs;
-
- if (l >= n)
- l -= n;
+ int l = netmap_idx_n2k(&na->tx_rings[0], i);
+ void *addr = PNMB(slot + l, &paddr);
- addr = PNMB(slot + l, &paddr);
desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
desc[i].rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
netmap_load_map(sc->rl_ldata.rl_tx_mtag,
@@ -391,19 +367,21 @@ re_netmap_rx_init(struct rl_softc *sc)
struct netmap_slot *slot = netmap_reset(na, NR_RX, 0, 0);
struct rl_desc *desc = sc->rl_ldata.rl_rx_list;
uint32_t cmdstat;
- int i, n;
+ int i, n, max_avail;
if (!slot)
return;
n = sc->rl_ldata.rl_rx_desc_cnt;
+ /*
+ * Userspace owned hwavail packets before the reset,
+ * so the NIC that last hwavail descriptors of the ring
+ * are still owned by the driver (and keep one empty).
+ */
+ max_avail = n - 1 - na->rx_rings[0].nr_hwavail;
for (i = 0; i < n; i++) {
void *addr;
uint64_t paddr;
- struct netmap_kring *kring = &na->rx_rings[0];
- int l = i + kring->nkr_hwofs;
-
- if (l >= n)
- l -= n;
+ int l = netmap_idx_n2k(&na->rx_rings[0], i);
addr = PNMB(slot + l, &paddr);
@@ -413,16 +391,31 @@ re_netmap_rx_init(struct rl_softc *sc)
sc->rl_ldata.rl_rx_desc[i].rx_dmamap, BUS_DMASYNC_PREREAD);
desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
desc[i].rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
- cmdstat = na->buff_size;
- if (i == n - 1)
+ cmdstat = NETMAP_BUF_SIZE;
+ if (i == n - 1) /* mark the end of ring */
cmdstat |= RL_RDESC_CMD_EOR;
- /*
- * userspace knows that hwavail packets were ready before the
- * reset, so we need to tell the NIC that last hwavail
- * descriptors of the ring are still owned by the driver.
- */
- if (i < n - 1 - kring->nr_hwavail) // XXX + 1 ?
+ if (i < max_avail)
cmdstat |= RL_RDESC_CMD_OWN;
desc[i].rl_cmdstat = htole32(cmdstat);
}
}
+
+
+static void
+re_netmap_attach(struct rl_softc *sc)
+{
+ struct netmap_adapter na;
+
+ bzero(&na, sizeof(na));
+
+ na.ifp = sc->rl_ifp;
+ na.separate_locks = 0;
+ na.num_tx_desc = sc->rl_ldata.rl_tx_desc_cnt;
+ na.num_rx_desc = sc->rl_ldata.rl_rx_desc_cnt;
+ na.nm_txsync = re_netmap_txsync;
+ na.nm_rxsync = re_netmap_rxsync;
+ na.nm_lock = re_netmap_lock_wrapper;
+ na.nm_register = re_netmap_reg;
+ netmap_attach(&na, 1);
+}
+/* end of file */
diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h
index bdcaf3875e44..fb539636d46f 100644
--- a/sys/dev/netmap/ixgbe_netmap.h
+++ b/sys/dev/netmap/ixgbe_netmap.h
@@ -25,7 +25,7 @@
/*
* $FreeBSD$
- * $Id: ixgbe_netmap.h 9802 2011-12-02 18:42:37Z luigi $
+ * $Id: ixgbe_netmap.h 10627 2012-02-23 19:37:15Z luigi $
*
* netmap modifications for ixgbe
*
@@ -47,44 +47,34 @@
#include <vm/pmap.h>
*/
-
#include <dev/netmap/netmap_kern.h>
/*
- * prototypes for the new API calls that are used by the
- * *_netmap_attach() routine.
- */
-static int ixgbe_netmap_reg(struct ifnet *, int onoff);
-static int ixgbe_netmap_txsync(struct ifnet *, u_int, int);
-static int ixgbe_netmap_rxsync(struct ifnet *, u_int, int);
-static void ixgbe_netmap_lock_wrapper(struct ifnet *, int, u_int);
-
-
-/*
- * The attach routine, called near the end of ixgbe_attach(),
- * fills the parameters for netmap_attach() and calls it.
- * It cannot fail, in the worst case (such as no memory)
- * netmap mode will be disabled and the driver will only
- * operate in standard mode.
+ * ix_crcstrip: 0: keep CRC in rx frames (default), 1: strip it.
+ * During regular operations the CRC is stripped, but on some
+ * hardware reception of frames not multiple of 64 is slower,
+ * so using crcstrip=0 helps in benchmarks.
+ *
+ * ix_rx_miss, ix_rx_miss_bufs:
+ * count packets that might be missed due to lost interrupts.
+ *
+ * ix_use_dd
+ * use the dd bit for completed tx transmissions.
+ * This is tricky, much better to use TDH for now.
*/
-static void
-ixgbe_netmap_attach(struct adapter *adapter)
-{
- struct netmap_adapter na;
-
- bzero(&na, sizeof(na));
-
- na.ifp = adapter->ifp;
- na.separate_locks = 1; /* this card has separate rx/tx locks */
- na.num_tx_desc = adapter->num_tx_desc;
- na.num_rx_desc = adapter->num_rx_desc;
- na.nm_txsync = ixgbe_netmap_txsync;
- na.nm_rxsync = ixgbe_netmap_rxsync;
- na.nm_lock = ixgbe_netmap_lock_wrapper;
- na.nm_register = ixgbe_netmap_reg;
- netmap_attach(&na, adapter->num_queues);
-}
-
+SYSCTL_DECL(_dev_netmap);
+static int ix_write_len;
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_write_len,
+ CTLFLAG_RW, &ix_write_len, 0, "write rx len");
+static int ix_rx_miss, ix_rx_miss_bufs, ix_use_dd, ix_crcstrip;
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
+ CTLFLAG_RW, &ix_crcstrip, 0, "strip CRC on rx frames");
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_use_dd,
+ CTLFLAG_RW, &ix_use_dd, 0, "use dd instead of tdh to detect tx frames");
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss,
+ CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr");
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss_bufs,
+ CTLFLAG_RW, &ix_rx_miss_bufs, 0, "potentially missed rx intr bufs");
/*
* wrapper to export locks to the generic netmap code.
@@ -118,8 +108,45 @@ ixgbe_netmap_lock_wrapper(struct ifnet *_a, int what, u_int queueid)
}
+static void
+set_crcstrip(struct ixgbe_hw *hw, int onoff)
+{
+ /* crc stripping is set in two places:
+ * IXGBE_HLREG0 (modified on init_locked and hw reset)
+ * IXGBE_RDRXCTL (set by the original driver in
+ * ixgbe_setup_hw_rsc() called in init_locked.
+ * We disable the setting when netmap is compiled in).
+ * We update the values here, but also in ixgbe.c because
+ * init_locked sometimes is called outside our control.
+ */
+ uint32_t hl, rxc;
+
+ hl = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+ if (netmap_verbose)
+ D("%s read HLREG 0x%x rxc 0x%x",
+ onoff ? "enter" : "exit", hl, rxc);
+ /* hw requirements ... */
+ rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
+ rxc |= IXGBE_RDRXCTL_RSCACKC;
+ if (onoff && !ix_crcstrip) {
+ /* keep the crc. Fast rx */
+ hl &= ~IXGBE_HLREG0_RXCRCSTRP;
+ rxc &= ~IXGBE_RDRXCTL_CRCSTRIP;
+ } else {
+ /* reset default mode */
+ hl |= IXGBE_HLREG0_RXCRCSTRP;
+ rxc |= IXGBE_RDRXCTL_CRCSTRIP;
+ }
+ if (netmap_verbose)
+ D("%s write HLREG 0x%x rxc 0x%x",
+ onoff ? "enter" : "exit", hl, rxc);
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl);
+ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc);
+}
+
/*
- * Netmap register/unregister. We are already under core lock.
+ * Register/unregister. We are already under core lock.
* Only called on the first register or the last unregister.
*/
static int
@@ -129,14 +156,15 @@ ixgbe_netmap_reg(struct ifnet *ifp, int onoff)
struct netmap_adapter *na = NA(ifp);
int error = 0;
- if (!na) /* probably, netmap_attach() failed */
- return EINVAL;
+ if (na == NULL)
+ return EINVAL; /* no netmap support here */
ixgbe_disable_intr(adapter);
/* Tell the stack that the interface is no longer active */
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ set_crcstrip(&adapter->hw, onoff);
if (onoff) { /* enable netmap mode */
ifp->if_capenable |= IFCAP_NETMAP;
@@ -161,6 +189,7 @@ fail:
/* initialize the card, this time in standard mode */
ixgbe_init_locked(adapter); /* also enables intr */
}
+ set_crcstrip(&adapter->hw, onoff);
return (error);
}
@@ -197,7 +226,7 @@ ixgbe_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
struct netmap_adapter *na = NA(adapter->ifp);
struct netmap_kring *kring = &na->tx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n = 0, lim = kring->nkr_num_slots - 1;
+ u_int j, k = ring->cur, l, n = 0, lim = kring->nkr_num_slots - 1;
/*
* ixgbe can generate an interrupt on every tx packet, but it
@@ -206,19 +235,10 @@ ixgbe_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
*/
int report_frequency = kring->nkr_num_slots >> 1;
+ if (k > lim)
+ return netmap_ring_reinit(kring);
if (do_lock)
IXGBE_TX_LOCK(txr);
- /* take a copy of ring->cur now, and never read it again */
- k = ring->cur;
- l = k - kring->nr_hwcur;
- if (l < 0)
- l += lim + 1;
- /* if cur is invalid reinitialize the ring. */
- if (k > lim || l > kring->nr_hwavail) {
- if (do_lock)
- IXGBE_TX_UNLOCK(txr);
- return netmap_ring_reinit(kring);
- }
bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
BUS_DMASYNC_POSTREAD);
@@ -240,11 +260,10 @@ ixgbe_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
*/
j = kring->nr_hwcur;
if (j != k) { /* we have new packets to send */
- l = j - kring->nkr_hwofs;
- if (l < 0) /* wraparound */
- l += lim + 1;
-
- while (j != k) {
+ prefetch(&ring->slot[j]);
+ l = netmap_idx_k2n(kring, j); /* NIC index */
+ prefetch(&txr->tx_buffers[l]);
+ for (n = 0; j != k; n++) {
/*
* Collect per-slot info.
* Note that txbuf and curr are indexed by l.
@@ -255,17 +274,25 @@ ixgbe_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
* Many other drivers preserve the address, so
* we only need to access it if NS_BUF_CHANGED
* is set.
+ * XXX note, on this device the dmamap* calls are
+ * not necessary because tag is 0, however just accessing
+ * the per-packet tag kills 1Mpps at 900 MHz.
*/
struct netmap_slot *slot = &ring->slot[j];
- struct ixgbe_tx_buf *txbuf = &txr->tx_buffers[l];
union ixgbe_adv_tx_desc *curr = &txr->tx_base[l];
+ struct ixgbe_tx_buf *txbuf = &txr->tx_buffers[l];
uint64_t paddr;
- void *addr = PNMB(slot, &paddr);
// XXX type for flags and len ?
int flags = ((slot->flags & NS_REPORT) ||
j == 0 || j == report_frequency) ?
IXGBE_TXD_CMD_RS : 0;
- int len = slot->len;
+ u_int len = slot->len;
+ void *addr = PNMB(slot, &paddr);
+
+ j = (j == lim) ? 0 : j + 1;
+ l = (l == lim) ? 0 : l + 1;
+ prefetch(&ring->slot[j]);
+ prefetch(&txr->tx_buffers[l]);
/*
* Quick check for valid addr and len.
@@ -281,41 +308,29 @@ ring_reset:
return netmap_ring_reinit(kring);
}
+ if (slot->flags & NS_BUF_CHANGED) {
+ /* buffer has changed, unload and reload map */
+ netmap_reload_map(txr->txtag, txbuf->map, addr);
+ slot->flags &= ~NS_BUF_CHANGED;
+ }
slot->flags &= ~NS_REPORT;
/*
* Fill the slot in the NIC ring.
* In this driver we need to rewrite the buffer
* address in the NIC ring. Other drivers do not
* need this.
+ * Use legacy descriptor, it is faster.
*/
curr->read.buffer_addr = htole64(paddr);
- curr->read.olinfo_status = htole32(len << IXGBE_ADVTXD_PAYLEN_SHIFT);
- curr->read.cmd_type_len =
- htole32(txr->txd_cmd | len |
- (IXGBE_ADVTXD_DTYP_DATA |
- IXGBE_ADVTXD_DCMD_DEXT |
- IXGBE_ADVTXD_DCMD_IFCS |
- IXGBE_TXD_CMD_EOP | flags) );
- /* If the buffer has changed, unload and reload map
- * (and possibly the physical address in the NIC
- * slot, but we did it already).
- */
- if (slot->flags & NS_BUF_CHANGED) {
- /* buffer has changed, unload and reload map */
- netmap_reload_map(txr->txtag, txbuf->map, addr);
- slot->flags &= ~NS_BUF_CHANGED;
- }
+ curr->read.olinfo_status = 0;
+ curr->read.cmd_type_len = htole32(len | flags |
+ IXGBE_ADVTXD_DCMD_IFCS | IXGBE_TXD_CMD_EOP);
/* make sure changes to the buffer are synced */
- bus_dmamap_sync(txr->txtag, txbuf->map,
- BUS_DMASYNC_PREWRITE);
- j = (j == lim) ? 0 : j + 1;
- l = (l == lim) ? 0 : l + 1;
- n++;
+ bus_dmamap_sync(txr->txtag, txbuf->map, BUS_DMASYNC_PREWRITE);
}
kring->nr_hwcur = k; /* the saved ring->cur */
-
- /* decrease avail by number of sent packets */
+ /* decrease avail by number of packets sent */
kring->nr_hwavail -= n;
/* synchronize the NIC ring */
@@ -357,7 +372,7 @@ ring_reset:
j= (j < kring->nkr_num_slots / 4 || j >= kring->nkr_num_slots*3/4) ?
0 : report_frequency;
kring->nr_kflags = j; /* the slot to check */
- j = txd[j].upper.fields.status & IXGBE_TXD_STAT_DD;
+ j = txd[j].upper.fields.status & IXGBE_TXD_STAT_DD; // XXX cpu_to_le32 ?
}
if (j) {
int delta;
@@ -375,12 +390,26 @@ ring_reset:
* For the time being we use TDH, as we do it infrequently
* enough not to pose performance problems.
*/
+ if (ix_use_dd) {
+ struct ixgbe_legacy_tx_desc *txd =
+ (struct ixgbe_legacy_tx_desc *)txr->tx_base;
+
+ l = txr->next_to_clean;
+ k = netmap_idx_k2n(kring, kring->nr_hwcur);
+ delta = 0;
+ while (l != k &&
+ txd[l].upper.fields.status & IXGBE_TXD_STAT_DD) {
+ delta++;
+ l = (l == lim) ? 0 : l + 1;
+ }
+ } else {
l = IXGBE_READ_REG(&adapter->hw, IXGBE_TDH(ring_nr));
if (l >= kring->nkr_num_slots) { /* XXX can happen */
D("TDH wrap %d", l);
l -= kring->nkr_num_slots;
}
delta = l - txr->next_to_clean;
+ }
if (delta) {
/* some tx completed, increment avail */
if (delta < 0)
@@ -397,7 +426,6 @@ ring_reset:
if (do_lock)
IXGBE_TX_UNLOCK(txr);
return 0;
-
}
@@ -425,20 +453,15 @@ ixgbe_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
struct netmap_adapter *na = NA(adapter->ifp);
struct netmap_kring *kring = &na->rx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
- int j, k, l, n, lim = kring->nkr_num_slots - 1;
+ u_int j, l, n, lim = kring->nkr_num_slots - 1;
int force_update = do_lock || kring->nr_kflags & NKR_PENDINTR;
+ u_int k = ring->cur, resvd = ring->reserved;
- k = ring->cur; /* cache and check value, same as in txsync */
- n = k - kring->nr_hwcur;
- if (n < 0)
- n += lim + 1;
- if (k > lim || n > kring->nr_hwavail) /* userspace is cheating */
+ if (k > lim)
return netmap_ring_reinit(kring);
if (do_lock)
IXGBE_RX_LOCK(rxr);
- if (n < 0)
- n += lim + 1;
/* XXX check sync modes */
bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
@@ -458,45 +481,60 @@ ixgbe_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
*
* rxr->next_to_check is set to 0 on a ring reinit
*/
- l = rxr->next_to_check;
- j = rxr->next_to_check + kring->nkr_hwofs;
- if (j > lim)
- j -= lim + 1;
+ if (netmap_no_pendintr || force_update) {
+ /* XXX apparently the length field in advanced descriptors
+ * does not include the CRC irrespective of the setting
+ * of CRCSTRIP. The data sheets say differently.
+ * Very strange.
+ */
+ int crclen = ix_crcstrip ? 0 : 4;
+ l = rxr->next_to_check;
+ j = netmap_idx_n2k(kring, l);
- if (netmap_no_pendintr || force_update) {
- for (n = 0; ; n++) {
- union ixgbe_adv_rx_desc *curr = &rxr->rx_base[l];
- uint32_t staterr = le32toh(curr->wb.upper.status_error);
+ for (n = 0; ; n++) {
+ union ixgbe_adv_rx_desc *curr = &rxr->rx_base[l];
+ uint32_t staterr = le32toh(curr->wb.upper.status_error);
- if ((staterr & IXGBE_RXD_STAT_DD) == 0)
- break;
- ring->slot[j].len = le16toh(curr->wb.upper.length);
- bus_dmamap_sync(rxr->ptag,
- rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD);
- j = (j == lim) ? 0 : j + 1;
- l = (l == lim) ? 0 : l + 1;
- }
- if (n) { /* update the state variables */
- rxr->next_to_check = l;
- kring->nr_hwavail += n;
+ if ((staterr & IXGBE_RXD_STAT_DD) == 0)
+ break;
+ ring->slot[j].len = le16toh(curr->wb.upper.length) - crclen;
+ if (ix_write_len)
+ D("rx[%d] len %d", j, ring->slot[j].len);
+ bus_dmamap_sync(rxr->ptag,
+ rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD);
+ j = (j == lim) ? 0 : j + 1;
+ l = (l == lim) ? 0 : l + 1;
+ }
+ if (n) { /* update the state variables */
+ if (netmap_no_pendintr && !force_update) {
+ /* diagnostics */
+ ix_rx_miss ++;
+ ix_rx_miss_bufs += n;
+ }
+ rxr->next_to_check = l;
+ kring->nr_hwavail += n;
+ }
+ kring->nr_kflags &= ~NKR_PENDINTR;
}
- kring->nr_kflags &= ~NKR_PENDINTR;
- }
/*
- * Skip past packets that userspace has already processed
- * (from kring->nr_hwcur to ring->cur excluded), and make
- * the buffers available for reception.
+ * Skip past packets that userspace has released
+ * (from kring->nr_hwcur to ring->cur - ring->reserved excluded),
+ * and make the buffers available for reception.
* As usual j is the index in the netmap ring, l is the index
* in the NIC ring, and j == (l + kring->nkr_hwofs) % ring_size
*/
j = kring->nr_hwcur;
- if (j != k) { /* userspace has read some packets. */
- n = 0;
- l = kring->nr_hwcur - kring->nkr_hwofs;
- if (l < 0)
- l += lim + 1;
- while (j != k) {
+ if (resvd > 0) {
+ if (resvd + ring->avail >= lim + 1) {
+ D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
+ ring->reserved = resvd = 0; // XXX panic...
+ }
+ k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;
+ }
+ if (j != k) { /* userspace has released some packets. */
+ l = netmap_idx_k2n(kring, j);
+ for (n = 0; j != k; n++) {
/* collect per-slot info, with similar validations
* and flag handling as in the txsync code.
*
@@ -514,19 +552,16 @@ ixgbe_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
- curr->wb.upper.status_error = 0;
- curr->read.pkt_addr = htole64(paddr);
if (slot->flags & NS_BUF_CHANGED) {
netmap_reload_map(rxr->ptag, rxbuf->pmap, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
-
+ curr->wb.upper.status_error = 0;
+ curr->read.pkt_addr = htole64(paddr);
bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
BUS_DMASYNC_PREREAD);
-
j = (j == lim) ? 0 : j + 1;
l = (l == lim) ? 0 : l + 1;
- n++;
}
kring->nr_hwavail -= n;
kring->nr_hwcur = k;
@@ -539,7 +574,7 @@ ixgbe_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(rxr->me), l);
}
/* tell userspace that there are new packets */
- ring->avail = kring->nr_hwavail ;
+ ring->avail = kring->nr_hwavail - resvd;
if (do_lock)
IXGBE_RX_UNLOCK(rxr);
@@ -550,4 +585,31 @@ ring_reset:
IXGBE_RX_UNLOCK(rxr);
return netmap_ring_reinit(kring);
}
+
+
+/*
+ * The attach routine, called near the end of ixgbe_attach(),
+ * fills the parameters for netmap_attach() and calls it.
+ * It cannot fail, in the worst case (such as no memory)
+ * netmap mode will be disabled and the driver will only
+ * operate in standard mode.
+ */
+static void
+ixgbe_netmap_attach(struct adapter *adapter)
+{
+ struct netmap_adapter na;
+
+ bzero(&na, sizeof(na));
+
+ na.ifp = adapter->ifp;
+ na.separate_locks = 1; /* this card has separate rx/tx locks */
+ na.num_tx_desc = adapter->num_tx_desc;
+ na.num_rx_desc = adapter->num_rx_desc;
+ na.nm_txsync = ixgbe_netmap_txsync;
+ na.nm_rxsync = ixgbe_netmap_rxsync;
+ na.nm_lock = ixgbe_netmap_lock_wrapper;
+ na.nm_register = ixgbe_netmap_reg;
+ netmap_attach(&na, adapter->num_queues);
+}
+
/* end of file */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 198a845311c4..1cd0a92d0a38 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Matteo Landi, Luigi Rizzo. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -9,7 +9,7 @@
* 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
@@ -24,9 +24,6 @@
*/
/*
- * $FreeBSD$
- * $Id: netmap.c 9795 2011-12-02 11:39:08Z luigi $
- *
* This module supports memory mapped access to network devices,
* see netmap(4).
*
@@ -90,10 +87,10 @@ MALLOC_DEFINE(M_NETMAP, "netmap", "Network memory map");
/*
* lock and unlock for the netmap memory allocator
*/
-#define NMA_LOCK() mtx_lock(&netmap_mem_d->nm_mtx);
-#define NMA_UNLOCK() mtx_unlock(&netmap_mem_d->nm_mtx);
+#define NMA_LOCK() mtx_lock(&nm_mem->nm_mtx);
+#define NMA_UNLOCK() mtx_unlock(&nm_mem->nm_mtx);
struct netmap_mem_d;
-static struct netmap_mem_d *netmap_mem_d; /* Our memory allocator. */
+static struct netmap_mem_d *nm_mem; /* Our memory allocator. */
u_int netmap_total_buffers;
char *netmap_buffer_base; /* address of an invalid buffer */
@@ -114,514 +111,18 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, buf_size,
CTLFLAG_RD, &netmap_buf_size, 0, "Size of packet buffers");
int netmap_mitigate = 1;
SYSCTL_INT(_dev_netmap, OID_AUTO, mitigate, CTLFLAG_RW, &netmap_mitigate, 0, "");
-int netmap_no_pendintr;
+int netmap_no_pendintr = 1;
SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr,
CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets.");
-
-/*----- memory allocator -----------------*/
-/*
- * Here we have the low level routines for memory allocator
- * and its primary users.
- */
-
-/*
- * Default amount of memory pre-allocated by the module.
- * We start with a large size and then shrink our demand
- * according to what is avalable when the module is loaded.
- * At the moment the block is contiguous, but we can easily
- * restrict our demand to smaller units (16..64k)
- */
-#define NETMAP_MEMORY_SIZE (64 * 1024 * PAGE_SIZE)
-static void * netmap_malloc(size_t size, const char *msg);
-static void netmap_free(void *addr, const char *msg);
-
-#define netmap_if_malloc(len) netmap_malloc(len, "nifp")
-#define netmap_if_free(v) netmap_free((v), "nifp")
-
-#define netmap_ring_malloc(len) netmap_malloc(len, "ring")
-#define netmap_free_rings(na) \
- netmap_free((na)->tx_rings[0].ring, "shadow rings");
-
-/*
- * Allocator for a pool of packet buffers. For each buffer we have
- * one entry in the bitmap to signal the state. Allocation scans
- * the bitmap, but since this is done only on attach, we are not
- * too worried about performance
- * XXX if we need to allocate small blocks, a translation
- * table is used both for kernel virtual address and physical
- * addresses.
- */
-struct netmap_buf_pool {
- u_int total_buffers; /* total buffers. */
- u_int free;
- u_int bufsize;
- char *base; /* buffer base address */
- uint32_t *bitmap; /* one bit per buffer, 1 means free */
-};
-struct netmap_buf_pool nm_buf_pool;
-SYSCTL_INT(_dev_netmap, OID_AUTO, total_buffers,
- CTLFLAG_RD, &nm_buf_pool.total_buffers, 0, "total_buffers");
-SYSCTL_INT(_dev_netmap, OID_AUTO, free_buffers,
- CTLFLAG_RD, &nm_buf_pool.free, 0, "free_buffers");
-
-
-
-
-/*
- * Allocate n buffers from the ring, and fill the slot.
- * Buffer 0 is the 'junk' buffer.
- */
-static void
-netmap_new_bufs(struct netmap_if *nifp __unused,
- struct netmap_slot *slot, u_int n)
-{
- struct netmap_buf_pool *p = &nm_buf_pool;
- uint32_t bi = 0; /* index in the bitmap */
- uint32_t mask, j, i = 0; /* slot counter */
-
- if (n > p->free) {
- D("only %d out of %d buffers available", i, n);
- return;
- }
- /* termination is guaranteed by p->free */
- while (i < n && p->free > 0) {
- uint32_t cur = p->bitmap[bi];
- if (cur == 0) { /* bitmask is fully used */
- bi++;
- continue;
- }
- /* locate a slot */
- for (j = 0, mask = 1; (cur & mask) == 0; j++, mask <<= 1) ;
- p->bitmap[bi] &= ~mask; /* slot in use */
- p->free--;
- slot[i].buf_idx = bi*32+j;
- slot[i].len = p->bufsize;
- slot[i].flags = NS_BUF_CHANGED;
- i++;
- }
- ND("allocated %d buffers, %d available", n, p->free);
-}
-
-
-static void
-netmap_free_buf(struct netmap_if *nifp __unused, uint32_t i)
-{
- struct netmap_buf_pool *p = &nm_buf_pool;
-
- uint32_t pos, mask;
- if (i >= p->total_buffers) {
- D("invalid free index %d", i);
- return;
- }
- pos = i / 32;
- mask = 1 << (i % 32);
- if (p->bitmap[pos] & mask) {
- D("slot %d already free", i);
- return;
- }
- p->bitmap[pos] |= mask;
- p->free++;
-}
-
-
-/* Descriptor of the memory objects handled by our memory allocator. */
-struct netmap_mem_obj {
- TAILQ_ENTRY(netmap_mem_obj) nmo_next; /* next object in the
- chain. */
- int nmo_used; /* flag set on used memory objects. */
- size_t nmo_size; /* size of the memory area reserved for the
- object. */
- void *nmo_data; /* pointer to the memory area. */
-};
-
-/* Wrap our memory objects to make them ``chainable``. */
-TAILQ_HEAD(netmap_mem_obj_h, netmap_mem_obj);
-
-
-/* Descriptor of our custom memory allocator. */
-struct netmap_mem_d {
- struct mtx nm_mtx; /* lock used to handle the chain of memory
- objects. */
- struct netmap_mem_obj_h nm_molist; /* list of memory objects */
- size_t nm_size; /* total amount of memory used for rings etc. */
- size_t nm_totalsize; /* total amount of allocated memory
- (the difference is used for buffers) */
- size_t nm_buf_start; /* offset of packet buffers.
- This is page-aligned. */
- size_t nm_buf_len; /* total memory for buffers */
- void *nm_buffer; /* pointer to the whole pre-allocated memory
- area. */
-};
-
-/* Shorthand to compute a netmap interface offset. */
-#define netmap_if_offset(v) \
- ((char *) (v) - (char *) netmap_mem_d->nm_buffer)
-/* .. and get a physical address given a memory offset */
-#define netmap_ofstophys(o) \
- (vtophys(netmap_mem_d->nm_buffer) + (o))
-
-
-/*------ netmap memory allocator -------*/
-/*
- * Request for a chunk of memory.
- *
- * Memory objects are arranged into a list, hence we need to walk this
- * list until we find an object with the needed amount of data free.
- * This sounds like a completely inefficient implementation, but given
- * the fact that data allocation is done once, we can handle it
- * flawlessly.
- *
- * Return NULL on failure.
- */
-static void *
-netmap_malloc(size_t size, __unused const char *msg)
-{
- struct netmap_mem_obj *mem_obj, *new_mem_obj;
- void *ret = NULL;
-
- NMA_LOCK();
- TAILQ_FOREACH(mem_obj, &netmap_mem_d->nm_molist, nmo_next) {
- if (mem_obj->nmo_used != 0 || mem_obj->nmo_size < size)
- continue;
-
- new_mem_obj = malloc(sizeof(struct netmap_mem_obj), M_NETMAP,
- M_WAITOK | M_ZERO);
- TAILQ_INSERT_BEFORE(mem_obj, new_mem_obj, nmo_next);
-
- new_mem_obj->nmo_used = 1;
- new_mem_obj->nmo_size = size;
- new_mem_obj->nmo_data = mem_obj->nmo_data;
- memset(new_mem_obj->nmo_data, 0, new_mem_obj->nmo_size);
-
- mem_obj->nmo_size -= size;
- mem_obj->nmo_data = (char *) mem_obj->nmo_data + size;
- if (mem_obj->nmo_size == 0) {
- TAILQ_REMOVE(&netmap_mem_d->nm_molist, mem_obj,
- nmo_next);
- free(mem_obj, M_NETMAP);
- }
-
- ret = new_mem_obj->nmo_data;
-
- break;
- }
- NMA_UNLOCK();
- ND("%s: %d bytes at %p", msg, size, ret);
-
- return (ret);
-}
-
-/*
- * Return the memory to the allocator.
- *
- * While freeing a memory object, we try to merge adjacent chunks in
- * order to reduce memory fragmentation.
- */
-static void
-netmap_free(void *addr, const char *msg)
-{
- size_t size;
- struct netmap_mem_obj *cur, *prev, *next;
-
- if (addr == NULL) {
- D("NULL addr for %s", msg);
- return;
- }
-
- NMA_LOCK();
- TAILQ_FOREACH(cur, &netmap_mem_d->nm_molist, nmo_next) {
- if (cur->nmo_data == addr && cur->nmo_used)
- break;
- }
- if (cur == NULL) {
- NMA_UNLOCK();
- D("invalid addr %s %p", msg, addr);
- return;
- }
-
- size = cur->nmo_size;
- cur->nmo_used = 0;
-
- /* merge current chunk of memory with the previous one,
- if present. */
- prev = TAILQ_PREV(cur, netmap_mem_obj_h, nmo_next);
- if (prev && prev->nmo_used == 0) {
- TAILQ_REMOVE(&netmap_mem_d->nm_molist, cur, nmo_next);
- prev->nmo_size += cur->nmo_size;
- free(cur, M_NETMAP);
- cur = prev;
- }
-
- /* merge with the next one */
- next = TAILQ_NEXT(cur, nmo_next);
- if (next && next->nmo_used == 0) {
- TAILQ_REMOVE(&netmap_mem_d->nm_molist, next, nmo_next);
- cur->nmo_size += next->nmo_size;
- free(next, M_NETMAP);
- }
- NMA_UNLOCK();
- ND("freed %s %d bytes at %p", msg, size, addr);
-}
-
-
-/*
- * Create and return a new ``netmap_if`` object, and possibly also
- * rings and packet buffors.
- *
- * Return NULL on failure.
- */
-static void *
-netmap_if_new(const char *ifname, struct netmap_adapter *na)
-{
- struct netmap_if *nifp;
- struct netmap_ring *ring;
- char *buff;
- u_int i, len, ofs;
- u_int n = na->num_queues + 1; /* shorthand, include stack queue */
-
- /*
- * the descriptor is followed inline by an array of offsets
- * to the tx and rx rings in the shared memory region.
- */
- len = sizeof(struct netmap_if) + 2 * n * sizeof(ssize_t);
- nifp = netmap_if_malloc(len);
- if (nifp == NULL)
- return (NULL);
-
- /* initialize base fields */
- *(int *)(uintptr_t)&nifp->ni_num_queues = na->num_queues;
- strncpy(nifp->ni_name, ifname, IFNAMSIZ);
-
- (na->refcount)++; /* XXX atomic ? we are under lock */
- if (na->refcount > 1)
- goto final;
-
- /*
- * If this is the first instance, allocate the shadow rings and
- * buffers for this card (one for each hw queue, one for the host).
- * The rings are contiguous, but have variable size.
- * The entire block is reachable at
- * na->tx_rings[0].ring
- */
-
- len = n * (2 * sizeof(struct netmap_ring) +
- (na->num_tx_desc + na->num_rx_desc) *
- sizeof(struct netmap_slot) );
- buff = netmap_ring_malloc(len);
- if (buff == NULL) {
- D("failed to allocate %d bytes for %s shadow ring",
- len, ifname);
-error:
- (na->refcount)--;
- netmap_if_free(nifp);
- return (NULL);
- }
- /* do we have the bufers ? we are in need of num_tx_desc buffers for
- * each tx ring and num_tx_desc buffers for each rx ring. */
- len = n * (na->num_tx_desc + na->num_rx_desc);
- NMA_LOCK();
- if (nm_buf_pool.free < len) {
- NMA_UNLOCK();
- netmap_free(buff, "not enough bufs");
- goto error;
- }
- /*
- * in the kring, store the pointers to the shared rings
- * and initialize the rings. We are under NMA_LOCK().
- */
- ofs = 0;
- for (i = 0; i < n; i++) {
- struct netmap_kring *kring;
- int numdesc;
-
- /* Transmit rings */
- kring = &na->tx_rings[i];
- numdesc = na->num_tx_desc;
- bzero(kring, sizeof(*kring));
- kring->na = na;
-
- ring = kring->ring = (struct netmap_ring *)(buff + ofs);
- *(ssize_t *)(uintptr_t)&ring->buf_ofs =
- nm_buf_pool.base - (char *)ring;
- ND("txring[%d] at %p ofs %d", i, ring, ring->buf_ofs);
- *(uint32_t *)(uintptr_t)&ring->num_slots =
- kring->nkr_num_slots = numdesc;
-
- /*
- * IMPORTANT:
- * Always keep one slot empty, so we can detect new
- * transmissions comparing cur and nr_hwcur (they are
- * the same only if there are no new transmissions).
- */
- ring->avail = kring->nr_hwavail = numdesc - 1;
- ring->cur = kring->nr_hwcur = 0;
- *(uint16_t *)(uintptr_t)&ring->nr_buf_size = NETMAP_BUF_SIZE;
- netmap_new_bufs(nifp, ring->slot, numdesc);
-
- ofs += sizeof(struct netmap_ring) +
- numdesc * sizeof(struct netmap_slot);
-
- /* Receive rings */
- kring = &na->rx_rings[i];
- numdesc = na->num_rx_desc;
- bzero(kring, sizeof(*kring));
- kring->na = na;
-
- ring = kring->ring = (struct netmap_ring *)(buff + ofs);
- *(ssize_t *)(uintptr_t)&ring->buf_ofs =
- nm_buf_pool.base - (char *)ring;
- ND("rxring[%d] at %p offset %d", i, ring, ring->buf_ofs);
- *(uint32_t *)(uintptr_t)&ring->num_slots =
- kring->nkr_num_slots = numdesc;
- ring->cur = kring->nr_hwcur = 0;
- ring->avail = kring->nr_hwavail = 0; /* empty */
- *(uint16_t *)(uintptr_t)&ring->nr_buf_size = NETMAP_BUF_SIZE;
- netmap_new_bufs(nifp, ring->slot, numdesc);
- ofs += sizeof(struct netmap_ring) +
- numdesc * sizeof(struct netmap_slot);
- }
- NMA_UNLOCK();
- for (i = 0; i < n+1; i++) {
- // XXX initialize the selrecord structs.
- }
-final:
- /*
- * fill the slots for the rx and tx queues. They contain the offset
- * between the ring and nifp, so the information is usable in
- * userspace to reach the ring from the nifp.
- */
- for (i = 0; i < n; i++) {
- char *base = (char *)nifp;
- *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] =
- (char *)na->tx_rings[i].ring - base;
- *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n] =
- (char *)na->rx_rings[i].ring - base;
- }
- return (nifp);
-}
-
-/*
- * Initialize the memory allocator.
- *
- * Create the descriptor for the memory , allocate the pool of memory
- * and initialize the list of memory objects with a single chunk
- * containing the whole pre-allocated memory marked as free.
- *
- * Start with a large size, then halve as needed if we fail to
- * allocate the block. While halving, always add one extra page
- * because buffers 0 and 1 are used for special purposes.
- * Return 0 on success, errno otherwise.
- */
-static int
-netmap_memory_init(void)
-{
- struct netmap_mem_obj *mem_obj;
- void *buf = NULL;
- int i, n, sz = NETMAP_MEMORY_SIZE;
- int extra_sz = 0; // space for rings and two spare buffers
-
- for (; sz >= 1<<20; sz >>=1) {
- extra_sz = sz/200;
- extra_sz = (extra_sz + 2*PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
- buf = contigmalloc(sz + extra_sz,
- M_NETMAP,
- M_WAITOK | M_ZERO,
- 0, /* low address */
- -1UL, /* high address */
- PAGE_SIZE, /* alignment */
- 0 /* boundary */
- );
- if (buf)
- break;
- }
- if (buf == NULL)
- return (ENOMEM);
- sz += extra_sz;
- netmap_mem_d = malloc(sizeof(struct netmap_mem_d), M_NETMAP,
- M_WAITOK | M_ZERO);
- mtx_init(&netmap_mem_d->nm_mtx, "netmap memory allocator lock", NULL,
- MTX_DEF);
- TAILQ_INIT(&netmap_mem_d->nm_molist);
- netmap_mem_d->nm_buffer = buf;
- netmap_mem_d->nm_totalsize = sz;
-
- /*
- * A buffer takes 2k, a slot takes 8 bytes + ring overhead,
- * so the ratio is 200:1. In other words, we can use 1/200 of
- * the memory for the rings, and the rest for the buffers,
- * and be sure we never run out.
- */
- netmap_mem_d->nm_size = sz/200;
- netmap_mem_d->nm_buf_start =
- (netmap_mem_d->nm_size + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
- netmap_mem_d->nm_buf_len = sz - netmap_mem_d->nm_buf_start;
-
- nm_buf_pool.base = netmap_mem_d->nm_buffer;
- nm_buf_pool.base += netmap_mem_d->nm_buf_start;
- netmap_buffer_base = nm_buf_pool.base;
- D("netmap_buffer_base %p (offset %d)",
- netmap_buffer_base, (int)netmap_mem_d->nm_buf_start);
- /* number of buffers, they all start as free */
-
- netmap_total_buffers = nm_buf_pool.total_buffers =
- netmap_mem_d->nm_buf_len / NETMAP_BUF_SIZE;
- nm_buf_pool.bufsize = NETMAP_BUF_SIZE;
-
- D("Have %d MB, use %dKB for rings, %d buffers at %p",
- (sz >> 20), (int)(netmap_mem_d->nm_size >> 10),
- nm_buf_pool.total_buffers, nm_buf_pool.base);
-
- /* allocate and initialize the bitmap. Entry 0 is considered
- * always busy (used as default when there are no buffers left).
- */
- n = (nm_buf_pool.total_buffers + 31) / 32;
- nm_buf_pool.bitmap = malloc(sizeof(uint32_t) * n, M_NETMAP,
- M_WAITOK | M_ZERO);
- nm_buf_pool.bitmap[0] = ~3; /* slot 0 and 1 always busy */
- for (i = 1; i < n; i++)
- nm_buf_pool.bitmap[i] = ~0;
- nm_buf_pool.free = nm_buf_pool.total_buffers - 2;
-
- mem_obj = malloc(sizeof(struct netmap_mem_obj), M_NETMAP,
- M_WAITOK | M_ZERO);
- TAILQ_INSERT_HEAD(&netmap_mem_d->nm_molist, mem_obj, nmo_next);
- mem_obj->nmo_used = 0;
- mem_obj->nmo_size = netmap_mem_d->nm_size;
- mem_obj->nmo_data = netmap_mem_d->nm_buffer;
-
- return (0);
-}
-
-
-/*
- * Finalize the memory allocator.
- *
- * Free all the memory objects contained inside the list, and deallocate
- * the pool of memory; finally free the memory allocator descriptor.
- */
-static void
-netmap_memory_fini(void)
-{
- struct netmap_mem_obj *mem_obj;
-
- while (!TAILQ_EMPTY(&netmap_mem_d->nm_molist)) {
- mem_obj = TAILQ_FIRST(&netmap_mem_d->nm_molist);
- TAILQ_REMOVE(&netmap_mem_d->nm_molist, mem_obj, nmo_next);
- if (mem_obj->nmo_used == 1) {
- printf("netmap: leaked %d bytes at %p\n",
- (int)mem_obj->nmo_size,
- mem_obj->nmo_data);
- }
- free(mem_obj, M_NETMAP);
- }
- contigfree(netmap_mem_d->nm_buffer, netmap_mem_d->nm_totalsize, M_NETMAP);
- // XXX mutex_destroy(nm_mtx);
- free(netmap_mem_d, M_NETMAP);
-}
-/*------------- end of memory allocator -----------------*/
-
+/*------------- memory allocator -----------------*/
+#ifdef NETMAP_MEM2
+#include "netmap_mem2.c"
+#else /* !NETMAP_MEM2 */
+#include "netmap_mem1.c"
+#endif /* !NETMAP_MEM2 */
+/*------------ end of memory allocator ----------*/
/* Structure associated to each thread which registered an interface. */
struct netmap_priv_d {
@@ -634,100 +135,6 @@ struct netmap_priv_d {
};
-static struct cdev *netmap_dev; /* /dev/netmap character device. */
-
-
-static d_mmap_t netmap_mmap;
-static d_ioctl_t netmap_ioctl;
-static d_poll_t netmap_poll;
-
-#ifdef NETMAP_KEVENT
-static d_kqfilter_t netmap_kqfilter;
-#endif
-
-static struct cdevsw netmap_cdevsw = {
- .d_version = D_VERSION,
- .d_name = "netmap",
- .d_mmap = netmap_mmap,
- .d_ioctl = netmap_ioctl,
- .d_poll = netmap_poll,
-#ifdef NETMAP_KEVENT
- .d_kqfilter = netmap_kqfilter,
-#endif
-};
-
-#ifdef NETMAP_KEVENT
-static int netmap_kqread(struct knote *, long);
-static int netmap_kqwrite(struct knote *, long);
-static void netmap_kqdetach(struct knote *);
-
-static struct filterops netmap_read_filterops = {
- .f_isfd = 1,
- .f_attach = NULL,
- .f_detach = netmap_kqdetach,
- .f_event = netmap_kqread,
-};
-
-static struct filterops netmap_write_filterops = {
- .f_isfd = 1,
- .f_attach = NULL,
- .f_detach = netmap_kqdetach,
- .f_event = netmap_kqwrite,
-};
-
-/*
- * support for the kevent() system call.
- *
- * This is the kevent filter, and is executed each time a new event
- * is triggered on the device. This function execute some operation
- * depending on the received filter.
- *
- * The implementation should test the filters and should implement
- * filter operations we are interested on (a full list in /sys/event.h).
- *
- * On a match we should:
- * - set kn->kn_fop
- * - set kn->kn_hook
- * - call knlist_add() to deliver the event to the application.
- *
- * Return 0 if the event should be delivered to the application.
- */
-static int
-netmap_kqfilter(struct cdev *dev, struct knote *kn)
-{
- /* declare variables needed to read/write */
-
- switch(kn->kn_filter) {
- case EVFILT_READ:
- if (netmap_verbose)
- D("%s kqfilter: EVFILT_READ" ifp->if_xname);
-
- /* read operations */
- kn->kn_fop = &netmap_read_filterops;
- break;
-
- case EVFILT_WRITE:
- if (netmap_verbose)
- D("%s kqfilter: EVFILT_WRITE" ifp->if_xname);
-
- /* write operations */
- kn->kn_fop = &netmap_write_filterops;
- break;
-
- default:
- if (netmap_verbose)
- D("%s kqfilter: invalid filter" ifp->if_xname);
- return(EINVAL);
- }
-
- kn->kn_hook = 0;//
- knlist_add(&netmap_sc->tun_rsel.si_note, kn, 0);
-
- return (0);
-}
-#endif /* NETMAP_KEVENT */
-
-
/*
* File descriptor's private data destructor.
*
@@ -744,7 +151,7 @@ netmap_dtor_locked(void *data)
na->refcount--;
if (na->refcount <= 0) { /* last instance */
- u_int i;
+ u_int i, j, lim;
D("deleting last netmap instance for %s", ifp->if_xname);
/*
@@ -766,24 +173,22 @@ netmap_dtor_locked(void *data)
/* Wake up any sleeping threads. netmap_poll will
* then return POLLERR
*/
- for (i = 0; i < na->num_queues + 2; i++) {
+ for (i = 0; i < na->num_tx_rings + 1; i++)
selwakeuppri(&na->tx_rings[i].si, PI_NET);
+ for (i = 0; i < na->num_rx_rings + 1; i++)
selwakeuppri(&na->rx_rings[i].si, PI_NET);
- }
+ selwakeuppri(&na->tx_si, PI_NET);
+ selwakeuppri(&na->rx_si, PI_NET);
/* release all buffers */
NMA_LOCK();
- for (i = 0; i < na->num_queues + 1; i++) {
- int j, lim;
- struct netmap_ring *ring;
-
- ND("tx queue %d", i);
- ring = na->tx_rings[i].ring;
+ for (i = 0; i < na->num_tx_rings + 1; i++) {
+ struct netmap_ring *ring = na->tx_rings[i].ring;
lim = na->tx_rings[i].nkr_num_slots;
for (j = 0; j < lim; j++)
netmap_free_buf(nifp, ring->slot[j].buf_idx);
-
- ND("rx queue %d", i);
- ring = na->rx_rings[i].ring;
+ }
+ for (i = 0; i < na->num_rx_rings + 1; i++) {
+ struct netmap_ring *ring = na->rx_rings[i].ring;
lim = na->rx_rings[i].nkr_num_slots;
for (j = 0; j < lim; j++)
netmap_free_buf(nifp, ring->slot[j].buf_idx);
@@ -805,7 +210,7 @@ netmap_dtor(void *data)
na->nm_lock(ifp, NETMAP_REG_LOCK, 0);
netmap_dtor_locked(data);
- na->nm_lock(ifp, NETMAP_REG_UNLOCK, 0);
+ na->nm_lock(ifp, NETMAP_REG_UNLOCK, 0);
if_rele(ifp);
bzero(priv, sizeof(*priv)); /* XXX for safety */
@@ -822,14 +227,16 @@ netmap_dtor(void *data)
*
* Return 0 on success, -1 otherwise.
*/
+
static int
+netmap_mmap(__unused struct cdev *dev,
#if __FreeBSD_version < 900000
-netmap_mmap(__unused struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr,
- int nprot)
+ vm_offset_t offset, vm_paddr_t *paddr, int nprot
#else
-netmap_mmap(__unused struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
- int nprot, __unused vm_memattr_t *memattr)
+ vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
+ __unused vm_memattr_t *memattr
#endif
+ )
{
if (nprot & PROT_EXEC)
return (-1); // XXX -1 or EINVAL ?
@@ -853,7 +260,7 @@ netmap_mmap(__unused struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
static void
netmap_sync_to_host(struct netmap_adapter *na)
{
- struct netmap_kring *kring = &na->tx_rings[na->num_queues];
+ struct netmap_kring *kring = &na->tx_rings[na->num_tx_rings];
struct netmap_ring *ring = kring->ring;
struct mbuf *head = NULL, *tail = NULL, *m;
u_int k, n, lim = kring->nkr_num_slots - 1;
@@ -913,31 +320,37 @@ netmap_sync_to_host(struct netmap_adapter *na)
static void
netmap_sync_from_host(struct netmap_adapter *na, struct thread *td)
{
- struct netmap_kring *kring = &na->rx_rings[na->num_queues];
+ struct netmap_kring *kring = &na->rx_rings[na->num_rx_rings];
struct netmap_ring *ring = kring->ring;
- int error = 1, delta;
- u_int k = ring->cur, lim = kring->nkr_num_slots;
+ u_int j, n, lim = kring->nkr_num_slots;
+ u_int k = ring->cur, resvd = ring->reserved;
na->nm_lock(na->ifp, NETMAP_CORE_LOCK, 0);
- if (k >= lim) /* bad value */
- goto done;
- delta = k - kring->nr_hwcur;
- if (delta < 0)
- delta += lim;
- kring->nr_hwavail -= delta;
- if (kring->nr_hwavail < 0) /* error */
- goto done;
- kring->nr_hwcur = k;
- error = 0;
- k = ring->avail = kring->nr_hwavail;
+ if (k >= lim) {
+ netmap_ring_reinit(kring);
+ return;
+ }
+ /* new packets are already set in nr_hwavail */
+ /* skip past packets that userspace has released */
+ j = kring->nr_hwcur;
+ if (resvd > 0) {
+ if (resvd + ring->avail >= lim + 1) {
+ D("XXX invalid reserve/avail %d %d", resvd, ring->avail);
+ ring->reserved = resvd = 0; // XXX panic...
+ }
+ k = (k >= resvd) ? k - resvd : k + lim - resvd;
+ }
+ if (j != k) {
+ n = k >= j ? k - j : k + lim - j;
+ kring->nr_hwavail -= n;
+ kring->nr_hwcur = k;
+ }
+ k = ring->avail = kring->nr_hwavail - resvd;
if (k == 0 && td)
selrecord(td, &kring->si);
if (k && (netmap_verbose & NM_VERB_HOST))
D("%d pkts from stack", k);
-done:
na->nm_lock(na->ifp, NETMAP_CORE_UNLOCK, 0);
- if (error)
- netmap_ring_reinit(kring);
}
@@ -1002,13 +415,13 @@ netmap_ring_reinit(struct netmap_kring *kring)
}
if (errors) {
int pos = kring - kring->na->tx_rings;
- int n = kring->na->num_queues + 2;
+ int n = kring->na->num_tx_rings + 1;
D("total %d errors", errors);
errors++;
D("%s %s[%d] reinit, cur %d -> %d avail %d -> %d",
kring->na->ifp->if_xname,
- pos < n ? "TX" : "RX", pos < n ? pos : pos - n,
+ pos < n ? "TX" : "RX", pos < n ? pos : pos - n,
ring->cur, kring->nr_hwcur,
ring->avail, kring->nr_hwavail);
ring->cur = kring->nr_hwcur;
@@ -1028,10 +441,13 @@ netmap_set_ringid(struct netmap_priv_d *priv, u_int ringid)
struct ifnet *ifp = priv->np_ifp;
struct netmap_adapter *na = NA(ifp);
u_int i = ringid & NETMAP_RING_MASK;
- /* first time we don't lock */
+ /* initially (np_qfirst == np_qlast) we don't want to lock */
int need_lock = (priv->np_qfirst != priv->np_qlast);
+ int lim = na->num_rx_rings;
- if ( (ringid & NETMAP_HW_RING) && i >= na->num_queues) {
+ if (na->num_tx_rings > lim)
+ lim = na->num_tx_rings;
+ if ( (ringid & NETMAP_HW_RING) && i >= lim) {
D("invalid ring id %d", i);
return (EINVAL);
}
@@ -1039,14 +455,14 @@ netmap_set_ringid(struct netmap_priv_d *priv, u_int ringid)
na->nm_lock(ifp, NETMAP_CORE_LOCK, 0);
priv->np_ringid = ringid;
if (ringid & NETMAP_SW_RING) {
- priv->np_qfirst = na->num_queues;
- priv->np_qlast = na->num_queues + 1;
+ priv->np_qfirst = NETMAP_SW_RING;
+ priv->np_qlast = 0;
} else if (ringid & NETMAP_HW_RING) {
priv->np_qfirst = i;
priv->np_qlast = i + 1;
} else {
priv->np_qfirst = 0;
- priv->np_qlast = na->num_queues;
+ priv->np_qlast = NETMAP_HW_RING ;
}
priv->np_txpoll = (ringid & NETMAP_NO_TX_POLL) ? 0 : 1;
if (need_lock)
@@ -1057,8 +473,7 @@ netmap_set_ringid(struct netmap_priv_d *priv, u_int ringid)
D("ringid %s set to HW RING %d", ifp->if_xname,
priv->np_qfirst);
else
- D("ringid %s set to all %d HW RINGS", ifp->if_xname,
- priv->np_qlast);
+ D("ringid %s set to all %d HW RINGS", ifp->if_xname, lim);
return 0;
}
@@ -1084,7 +499,7 @@ netmap_ioctl(__unused struct cdev *dev, u_long cmd, caddr_t data,
struct nmreq *nmr = (struct nmreq *) data;
struct netmap_adapter *na;
int error;
- u_int i;
+ u_int i, lim;
struct netmap_if *nifp;
CURVNET_SET(TD_TO_VNET(td));
@@ -1099,22 +514,36 @@ netmap_ioctl(__unused struct cdev *dev, u_long cmd, caddr_t data,
switch (cmd) {
case NIOCGINFO: /* return capabilities etc */
/* memsize is always valid */
- nmr->nr_memsize = netmap_mem_d->nm_totalsize;
+ nmr->nr_memsize = nm_mem->nm_totalsize;
nmr->nr_offset = 0;
- nmr->nr_numrings = 0;
- nmr->nr_numslots = 0;
+ nmr->nr_rx_rings = nmr->nr_tx_rings = 0;
+ nmr->nr_rx_slots = nmr->nr_tx_slots = 0;
+ if (nmr->nr_version != NETMAP_API) {
+ D("API mismatch got %d have %d",
+ nmr->nr_version, NETMAP_API);
+ nmr->nr_version = NETMAP_API;
+ error = EINVAL;
+ break;
+ }
if (nmr->nr_name[0] == '\0') /* just get memory info */
break;
error = get_ifp(nmr->nr_name, &ifp); /* get a refcount */
if (error)
break;
na = NA(ifp); /* retrieve netmap_adapter */
- nmr->nr_numrings = na->num_queues;
- nmr->nr_numslots = na->num_tx_desc;
+ nmr->nr_rx_rings = na->num_rx_rings;
+ nmr->nr_tx_rings = na->num_tx_rings;
+ nmr->nr_rx_slots = na->num_rx_desc;
+ nmr->nr_tx_slots = na->num_tx_desc;
if_rele(ifp); /* return the refcount */
break;
case NIOCREGIF:
+ if (nmr->nr_version != NETMAP_API) {
+ nmr->nr_version = NETMAP_API;
+ error = EINVAL;
+ break;
+ }
if (priv != NULL) { /* thread already registered */
error = netmap_set_ringid(priv, nmr->nr_ringid);
break;
@@ -1190,9 +619,11 @@ error:
}
/* return the offset of the netmap_if object */
- nmr->nr_numrings = na->num_queues;
- nmr->nr_numslots = na->num_tx_desc;
- nmr->nr_memsize = netmap_mem_d->nm_totalsize;
+ nmr->nr_rx_rings = na->num_rx_rings;
+ nmr->nr_tx_rings = na->num_tx_rings;
+ nmr->nr_rx_slots = na->num_rx_desc;
+ nmr->nr_tx_slots = na->num_tx_desc;
+ nmr->nr_memsize = nm_mem->nm_totalsize;
nmr->nr_offset = netmap_if_offset(nifp);
break;
@@ -1215,35 +646,38 @@ error:
}
ifp = priv->np_ifp; /* we have a reference */
na = NA(ifp); /* retrieve netmap adapter */
-
- if (priv->np_qfirst == na->num_queues) {
- /* queues to/from host */
+ if (priv->np_qfirst == NETMAP_SW_RING) { /* host rings */
if (cmd == NIOCTXSYNC)
netmap_sync_to_host(na);
else
netmap_sync_from_host(na, NULL);
break;
}
+ /* find the last ring to scan */
+ lim = priv->np_qlast;
+ if (lim == NETMAP_HW_RING)
+ lim = (cmd == NIOCTXSYNC) ?
+ na->num_tx_rings : na->num_rx_rings;
- for (i = priv->np_qfirst; i < priv->np_qlast; i++) {
- if (cmd == NIOCTXSYNC) {
- struct netmap_kring *kring = &na->tx_rings[i];
- if (netmap_verbose & NM_VERB_TXSYNC)
- D("sync tx ring %d cur %d hwcur %d",
- i, kring->ring->cur,
- kring->nr_hwcur);
- na->nm_txsync(ifp, i, 1 /* do lock */);
- if (netmap_verbose & NM_VERB_TXSYNC)
- D("after sync tx ring %d cur %d hwcur %d",
- i, kring->ring->cur,
- kring->nr_hwcur);
- } else {
- na->nm_rxsync(ifp, i, 1 /* do lock */);
- microtime(&na->rx_rings[i].ring->ts);
- }
+ for (i = priv->np_qfirst; i < lim; i++) {
+ if (cmd == NIOCTXSYNC) {
+ struct netmap_kring *kring = &na->tx_rings[i];
+ if (netmap_verbose & NM_VERB_TXSYNC)
+ D("pre txsync ring %d cur %d hwcur %d",
+ i, kring->ring->cur,
+ kring->nr_hwcur);
+ na->nm_txsync(ifp, i, 1 /* do lock */);
+ if (netmap_verbose & NM_VERB_TXSYNC)
+ D("post txsync ring %d cur %d hwcur %d",
+ i, kring->ring->cur,
+ kring->nr_hwcur);
+ } else {
+ na->nm_rxsync(ifp, i, 1 /* do lock */);
+ microtime(&na->rx_rings[i].ring->ts);
+ }
}
- break;
+ break;
case BIOCIMMEDIATE:
case BIOCGHDRCMPLT:
@@ -1252,11 +686,8 @@ error:
D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
break;
- default:
+ default: /* allow device-specific ioctls */
{
- /*
- * allow device calls
- */
struct socket so;
bzero(&so, sizeof(so));
error = get_ifp(nmr->nr_name, &ifp); /* keep reference */
@@ -1266,6 +697,7 @@ error:
// so->so_proto not null.
error = ifioctl(&so, cmd, data, td);
if_rele(ifp);
+ break;
}
}
@@ -1292,6 +724,7 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
struct ifnet *ifp;
struct netmap_kring *kring;
u_int core_lock, i, check_all, want_tx, want_rx, revents = 0;
+ u_int lim_tx, lim_rx;
enum {NO_CL, NEED_CL, LOCKED_CL }; /* see below */
if (devfs_get_cdevpriv((void **)&priv) != 0 || priv == NULL)
@@ -1309,17 +742,18 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
na = NA(ifp); /* retrieve netmap adapter */
+ lim_tx = na->num_tx_rings;
+ lim_rx = na->num_rx_rings;
/* how many queues we are scanning */
- i = priv->np_qfirst;
- if (i == na->num_queues) { /* from/to host */
+ if (priv->np_qfirst == NETMAP_SW_RING) {
if (priv->np_txpoll || want_tx) {
/* push any packets up, then we are always ready */
- kring = &na->tx_rings[i];
+ kring = &na->tx_rings[lim_tx];
netmap_sync_to_host(na);
revents |= want_tx;
}
if (want_rx) {
- kring = &na->rx_rings[i];
+ kring = &na->rx_rings[lim_rx];
if (kring->ring->avail == 0)
netmap_sync_from_host(na, td);
if (kring->ring->avail > 0) {
@@ -1350,7 +784,7 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
* there are pending packets to send. The latter can be disabled
* passing NETMAP_NO_TX_POLL in the NIOCREG call.
*/
- check_all = (i + 1 != priv->np_qlast);
+ check_all = (priv->np_qlast == NETMAP_HW_RING) && (lim_tx > 1 || lim_rx > 1);
/*
* core_lock indicates what to do with the core lock.
@@ -1367,25 +801,29 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
* LOCKED_CL core lock is set, so we need to release it.
*/
core_lock = (check_all || !na->separate_locks) ? NEED_CL : NO_CL;
+ if (priv->np_qlast != NETMAP_HW_RING) {
+ lim_tx = lim_rx = priv->np_qlast;
+ }
+
/*
* We start with a lock free round which is good if we have
* data available. If this fails, then lock and call the sync
* routines.
*/
- for (i = priv->np_qfirst; want_rx && i < priv->np_qlast; i++) {
- kring = &na->rx_rings[i];
- if (kring->ring->avail > 0) {
- revents |= want_rx;
- want_rx = 0; /* also breaks the loop */
- }
+ for (i = priv->np_qfirst; want_rx && i < lim_rx; i++) {
+ kring = &na->rx_rings[i];
+ if (kring->ring->avail > 0) {
+ revents |= want_rx;
+ want_rx = 0; /* also breaks the loop */
}
- for (i = priv->np_qfirst; want_tx && i < priv->np_qlast; i++) {
- kring = &na->tx_rings[i];
- if (kring->ring->avail > 0) {
- revents |= want_tx;
- want_tx = 0; /* also breaks the loop */
- }
+ }
+ for (i = priv->np_qfirst; want_tx && i < lim_tx; i++) {
+ kring = &na->tx_rings[i];
+ if (kring->ring->avail > 0) {
+ revents |= want_tx;
+ want_tx = 0; /* also breaks the loop */
}
+ }
/*
* If we to push packets out (priv->np_txpoll) or want_tx is
@@ -1393,7 +831,7 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
* to avoid that the tx rings stall).
*/
if (priv->np_txpoll || want_tx) {
- for (i = priv->np_qfirst; i < priv->np_qlast; i++) {
+ for (i = priv->np_qfirst; i < lim_tx; i++) {
kring = &na->tx_rings[i];
/*
* Skip the current ring if want_tx == 0
@@ -1437,7 +875,7 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
* Do it on all rings because otherwise we starve.
*/
if (want_rx) {
- for (i = priv->np_qfirst; i < priv->np_qlast; i++) {
+ for (i = priv->np_qfirst; i < lim_rx; i++) {
kring = &na->rx_rings[i];
if (core_lock == NEED_CL) {
na->nm_lock(ifp, NETMAP_CORE_LOCK, 0);
@@ -1461,12 +899,11 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
na->nm_lock(ifp, NETMAP_RX_UNLOCK, i);
}
}
- if (check_all && revents == 0) {
- i = na->num_queues + 1; /* the global queue */
+ if (check_all && revents == 0) { /* signal on the global queue */
if (want_tx)
- selrecord(td, &na->tx_rings[i].si);
+ selrecord(td, &na->tx_si);
if (want_rx)
- selrecord(td, &na->rx_rings[i].si);
+ selrecord(td, &na->rx_si);
}
if (core_lock == LOCKED_CL)
na->nm_lock(ifp, NETMAP_CORE_UNLOCK, 0);
@@ -1477,19 +914,19 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td)
/*------- driver support routines ------*/
/*
- * default lock wrapper. On linux we use mostly netmap-specific locks.
+ * default lock wrapper.
*/
static void
-netmap_lock_wrapper(struct ifnet *_a, int what, u_int queueid)
+netmap_lock_wrapper(struct ifnet *dev, int what, u_int queueid)
{
- struct netmap_adapter *na = NA(_a);
+ struct netmap_adapter *na = NA(dev);
switch (what) {
-#ifndef __FreeBSD__ /* some system do not need lock on register */
+#ifdef linux /* some system do not need lock on register */
case NETMAP_REG_LOCK:
case NETMAP_REG_UNLOCK:
break;
-#endif
+#endif /* linux */
case NETMAP_CORE_LOCK:
mtx_lock(&na->core_lock);
@@ -1527,29 +964,37 @@ netmap_lock_wrapper(struct ifnet *_a, int what, u_int queueid)
* kring N is for the host stack queue
* kring N+1 is only used for the selinfo for all queues.
* Return 0 on success, ENOMEM otherwise.
+ *
+ * na->num_tx_rings can be set for cards with different tx/rx setups
*/
int
netmap_attach(struct netmap_adapter *na, int num_queues)
{
- int n = num_queues + 2;
- int size = sizeof(*na) + 2 * n * sizeof(struct netmap_kring);
+ int i, n, size;
void *buf;
struct ifnet *ifp = na->ifp;
- int i;
if (ifp == NULL) {
D("ifp not set, giving up");
return EINVAL;
}
+ /* clear other fields ? */
na->refcount = 0;
- na->num_queues = num_queues;
+ if (na->num_tx_rings == 0)
+ na->num_tx_rings = num_queues;
+ na->num_rx_rings = num_queues;
+ /* on each direction we have N+1 resources
+ * 0..n-1 are the hardware rings
+ * n is the ring attached to the stack.
+ */
+ n = na->num_rx_rings + na->num_tx_rings + 2;
+ size = sizeof(*na) + n * sizeof(struct netmap_kring);
buf = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
if (buf) {
WNA(ifp) = buf;
na->tx_rings = (void *)((char *)buf + sizeof(*na));
- na->rx_rings = na->tx_rings + n;
- na->buff_size = NETMAP_BUF_SIZE;
+ na->rx_rings = na->tx_rings + na->num_tx_rings + 1;
bcopy(na, buf, sizeof(*na));
ifp->if_capabilities |= IFCAP_NETMAP;
@@ -1557,11 +1002,17 @@ netmap_attach(struct netmap_adapter *na, int num_queues)
if (na->nm_lock == NULL)
na->nm_lock = netmap_lock_wrapper;
mtx_init(&na->core_lock, "netmap core lock", NULL, MTX_DEF);
- for (i = 0 ; i < num_queues; i++)
+ for (i = 0 ; i < na->num_tx_rings + 1; i++)
mtx_init(&na->tx_rings[i].q_lock, "netmap txq lock", NULL, MTX_DEF);
- for (i = 0 ; i < num_queues; i++)
+ for (i = 0 ; i < na->num_rx_rings + 1; i++)
mtx_init(&na->rx_rings[i].q_lock, "netmap rxq lock", NULL, MTX_DEF);
}
+#ifdef linux
+ D("netdev_ops %p", ifp->netdev_ops);
+ /* prepare a clone of the netdev ops */
+ na->nm_ndo = *ifp->netdev_ops;
+ na->nm_ndo.ndo_start_xmit = netmap_start_linux;
+#endif
D("%s for %s", buf ? "ok" : "failed", ifp->if_xname);
return (buf ? 0 : ENOMEM);
@@ -1581,10 +1032,16 @@ netmap_detach(struct ifnet *ifp)
if (!na)
return;
- for (i = 0; i < na->num_queues + 2; i++) {
+ for (i = 0; i < na->num_tx_rings + 1; i++) {
knlist_destroy(&na->tx_rings[i].si.si_note);
+ mtx_destroy(&na->tx_rings[i].q_lock);
+ }
+ for (i = 0; i < na->num_rx_rings + 1; i++) {
knlist_destroy(&na->rx_rings[i].si.si_note);
+ mtx_destroy(&na->rx_rings[i].q_lock);
}
+ knlist_destroy(&na->tx_si.si_note);
+ knlist_destroy(&na->rx_si.si_note);
bzero(na, sizeof(*na));
WNA(ifp) = NULL;
free(na, M_DEVBUF);
@@ -1600,7 +1057,7 @@ int
netmap_start(struct ifnet *ifp, struct mbuf *m)
{
struct netmap_adapter *na = NA(ifp);
- struct netmap_kring *kring = &na->rx_rings[na->num_queues];
+ struct netmap_kring *kring = &na->rx_rings[na->num_rx_rings];
u_int i, len = MBUF_LEN(m);
int error = EBUSY, lim = kring->nkr_num_slots - 1;
struct netmap_slot *slot;
@@ -1610,11 +1067,12 @@ netmap_start(struct ifnet *ifp, struct mbuf *m)
kring->nr_hwcur + kring->nr_hwavail, len);
na->nm_lock(ifp, NETMAP_CORE_LOCK, 0);
if (kring->nr_hwavail >= lim) {
- D("stack ring %s full\n", ifp->if_xname);
+ if (netmap_verbose)
+ D("stack ring %s full\n", ifp->if_xname);
goto done; /* no space */
}
- if (len > na->buff_size) {
- D("drop packet size %d > %d", len, na->buff_size);
+ if (len > NETMAP_BUF_SIZE) {
+ D("drop packet size %d > %d", len, NETMAP_BUF_SIZE);
goto done; /* too long for us */
}
@@ -1627,7 +1085,7 @@ netmap_start(struct ifnet *ifp, struct mbuf *m)
slot->len = len;
kring->nr_hwavail++;
if (netmap_verbose & NM_VERB_HOST)
- D("wake up host ring %s %d", na->ifp->if_xname, na->num_queues);
+ D("wake up host ring %s %d", na->ifp->if_xname, na->num_rx_rings);
selwakeuppri(&kring->si, PI_NET);
error = 0;
done:
@@ -1653,21 +1111,21 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, int n,
u_int new_cur)
{
struct netmap_kring *kring;
- struct netmap_ring *ring;
int new_hwofs, lim;
if (na == NULL)
return NULL; /* no netmap support here */
if (!(na->ifp->if_capenable & IFCAP_NETMAP))
return NULL; /* nothing to reinitialize */
- kring = tx == NR_TX ? na->tx_rings + n : na->rx_rings + n;
- ring = kring->ring;
- lim = kring->nkr_num_slots - 1;
- if (tx == NR_TX)
+ if (tx == NR_TX) {
+ kring = na->tx_rings + n;
new_hwofs = kring->nr_hwcur - new_cur;
- else
+ } else {
+ kring = na->rx_rings + n;
new_hwofs = kring->nr_hwcur + kring->nr_hwavail - new_cur;
+ }
+ lim = kring->nkr_num_slots - 1;
if (new_hwofs > lim)
new_hwofs -= lim + 1;
@@ -1680,11 +1138,12 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, int n,
tx == NR_TX ? "TX" : "RX", n);
/*
+ * Wakeup on the individual and global lock
* We do the wakeup here, but the ring is not yet reconfigured.
* However, we are under lock so there are no races.
*/
selwakeuppri(&kring->si, PI_NET);
- selwakeuppri(&kring[na->num_queues + 1 - n].si, PI_NET);
+ selwakeuppri(tx == NR_TX ? &na->tx_si : &na->rx_si, PI_NET);
return kring->ring->slot;
}
@@ -1693,44 +1152,67 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, int n,
* Default functions to handle rx/tx interrupts
* we have 4 cases:
* 1 ring, single lock:
- * lock(core); wake(i=0); unlock(core)
+ * lock(core); wake(i=0); unlock(core)
* N rings, single lock:
- * lock(core); wake(i); wake(N+1) unlock(core)
+ * lock(core); wake(i); wake(N+1) unlock(core)
* 1 ring, separate locks: (i=0)
- * lock(i); wake(i); unlock(i)
+ * lock(i); wake(i); unlock(i)
* N rings, separate locks:
- * lock(i); wake(i); unlock(i); lock(core) wake(N+1) unlock(core)
+ * lock(i); wake(i); unlock(i); lock(core) wake(N+1) unlock(core)
+ * work_done is non-null on the RX path.
*/
-int netmap_rx_irq(struct ifnet *ifp, int q, int *work_done)
+int
+netmap_rx_irq(struct ifnet *ifp, int q, int *work_done)
{
struct netmap_adapter *na;
struct netmap_kring *r;
+ NM_SELINFO_T *main_wq;
if (!(ifp->if_capenable & IFCAP_NETMAP))
return 0;
na = NA(ifp);
- r = work_done ? na->rx_rings : na->tx_rings;
+ if (work_done) { /* RX path */
+ r = na->rx_rings + q;
+ r->nr_kflags |= NKR_PENDINTR;
+ main_wq = (na->num_rx_rings > 1) ? &na->rx_si : NULL;
+ } else { /* tx path */
+ r = na->tx_rings + q;
+ main_wq = (na->num_tx_rings > 1) ? &na->tx_si : NULL;
+ work_done = &q; /* dummy */
+ }
if (na->separate_locks) {
- mtx_lock(&r[q].q_lock);
- selwakeuppri(&r[q].si, PI_NET);
- mtx_unlock(&r[q].q_lock);
- if (na->num_queues > 1) {
+ mtx_lock(&r->q_lock);
+ selwakeuppri(&r->si, PI_NET);
+ mtx_unlock(&r->q_lock);
+ if (main_wq) {
mtx_lock(&na->core_lock);
- selwakeuppri(&r[na->num_queues + 1].si, PI_NET);
+ selwakeuppri(main_wq, PI_NET);
mtx_unlock(&na->core_lock);
}
} else {
mtx_lock(&na->core_lock);
- selwakeuppri(&r[q].si, PI_NET);
- if (na->num_queues > 1)
- selwakeuppri(&r[na->num_queues + 1].si, PI_NET);
+ selwakeuppri(&r->si, PI_NET);
+ if (main_wq)
+ selwakeuppri(main_wq, PI_NET);
mtx_unlock(&na->core_lock);
}
- if (work_done)
- *work_done = 1; /* do not fire napi again */
+ *work_done = 1; /* do not fire napi again */
return 1;
}
+
+static struct cdevsw netmap_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "netmap",
+ .d_mmap = netmap_mmap,
+ .d_ioctl = netmap_ioctl,
+ .d_poll = netmap_poll,
+};
+
+
+static struct cdev *netmap_dev; /* /dev/netmap character device. */
+
+
/*
* Module loader.
*
@@ -1744,19 +1226,16 @@ netmap_init(void)
{
int error;
-
error = netmap_memory_init();
if (error != 0) {
printf("netmap: unable to initialize the memory allocator.");
return (error);
}
printf("netmap: loaded module with %d Mbytes\n",
- (int)(netmap_mem_d->nm_totalsize >> 20));
-
+ (int)(nm_mem->nm_totalsize >> 20));
netmap_dev = make_dev(&netmap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660,
"netmap");
-
- return (0);
+ return (error);
}
@@ -1769,9 +1248,7 @@ static void
netmap_fini(void)
{
destroy_dev(netmap_dev);
-
netmap_memory_fini();
-
printf("netmap: unloaded module.\n");
}
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4fb59980444f..a1ac925b1c57 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -25,7 +25,7 @@
/*
* $FreeBSD$
- * $Id: netmap_kern.h 9795 2011-12-02 11:39:08Z luigi $
+ * $Id: netmap_kern.h 10602 2012-02-21 16:47:55Z luigi $
*
* The header contains the definitions of constants and function
* prototypes used only in kernelspace.
@@ -34,12 +34,14 @@
#ifndef _NET_NETMAP_KERN_H_
#define _NET_NETMAP_KERN_H_
+#define NETMAP_MEM2 // use the new memory allocator
+
#if defined(__FreeBSD__)
#define NM_LOCK_T struct mtx
#define NM_SELINFO_T struct selinfo
#define MBUF_LEN(m) ((m)->m_pkthdr.len)
#define NM_SEND_UP(ifp, m) ((ifp)->if_input)(ifp, m)
-#elif defined (__linux__)
+#elif defined (linux)
#define NM_LOCK_T spinlock_t
#define NM_SELINFO_T wait_queue_head_t
#define MBUF_LEN(m) ((m)->len)
@@ -65,7 +67,14 @@ MALLOC_DECLARE(M_NETMAP);
struct netmap_adapter;
/*
- * private, kernel view of a ring.
+ * private, kernel view of a ring. Keeps track of the status of
+ * a ring across system calls.
+ *
+ * nr_hwcur index of the next buffer to refill.
+ * It corresponds to ring->cur - ring->reserved
+ *
+ * nr_hwavail the number of slots "owned" by userspace.
+ * nr_hwavail =:= ring->avail + ring->reserved
*
* 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
@@ -79,7 +88,7 @@ struct netmap_kring {
u_int nr_hwcur;
int nr_hwavail;
u_int nr_kflags; /* private driver flags */
-#define NKR_PENDINTR 0x1 // Pending interrupt.
+#define NKR_PENDINTR 0x1 // Pending interrupt.
u_int nkr_num_slots;
int nkr_hwofs; /* offset between NIC and netmap ring */
@@ -97,19 +106,25 @@ struct netmap_adapter {
int refcount; /* number of user-space descriptors using this
interface, which is equal to the number of
struct netmap_if objs in the mapped region. */
+ /*
+ * The selwakeup in the interrupt thread can use per-ring
+ * and/or global wait queues. We track how many clients
+ * of each type we have so we can optimize the drivers,
+ * and especially avoid huge contention on the locks.
+ */
+ int na_single; /* threads attached to a single hw queue */
+ int na_multi; /* threads attached to multiple hw queues */
int separate_locks; /* set if the interface suports different
locks for rx, tx and core. */
- u_int num_queues; /* number of tx/rx queue pairs: this is
- a duplicate field needed to simplify the
- signature of ``netmap_detach``. */
+ u_int num_rx_rings; /* number of tx/rx ring pairs */
+ u_int num_tx_rings; // if nonzero, overrides num_rx_rings
u_int num_tx_desc; /* number of descriptor in each queue */
u_int num_rx_desc;
- u_int buff_size;
+ //u_int buff_size; // XXX deprecate, use NETMAP_BUF_SIZE
- //u_int flags; // XXX unused
/* tx_rings and rx_rings are private but allocated
* as a contiguous chunk of memory. Each array has
* N+1 entries, for the adapter queues and for the host queue.
@@ -117,11 +132,11 @@ struct netmap_adapter {
struct netmap_kring *tx_rings; /* array of TX rings. */
struct netmap_kring *rx_rings; /* array of RX rings. */
+ NM_SELINFO_T tx_si, rx_si; /* global wait queues */
+
/* copy of if_qflush and if_transmit pointers, to intercept
* packets from the network stack when netmap is active.
- * XXX probably if_qflush is not necessary.
*/
- //void (*if_qflush)(struct ifnet *); // XXX unused
int (*if_transmit)(struct ifnet *, struct mbuf *);
/* references to the ifnet and device routines, used by
@@ -135,6 +150,9 @@ struct netmap_adapter {
void (*nm_lock)(struct ifnet *, int what, u_int ringid);
int (*nm_txsync)(struct ifnet *, u_int ring, int lock);
int (*nm_rxsync)(struct ifnet *, u_int ring, int lock);
+#ifdef linux
+ struct net_device_ops nm_ndo;
+#endif /* linux */
};
/*
@@ -195,7 +213,7 @@ struct netmap_slot *netmap_reset(struct netmap_adapter *na,
int netmap_ring_reinit(struct netmap_kring *);
extern int netmap_buf_size;
-#define NETMAP_BUF_SIZE netmap_buf_size
+#define NETMAP_BUF_SIZE netmap_buf_size
extern int netmap_mitigate;
extern int netmap_no_pendintr;
extern u_int netmap_total_buffers;
@@ -250,6 +268,51 @@ netmap_reload_map(bus_dma_tag_t tag, bus_dmamap_t map, void *buf)
}
}
+/*
+ * functions to map NIC to KRING indexes (n2k) and vice versa (k2n)
+ */
+static inline int
+netmap_idx_n2k(struct netmap_kring *kr, int idx)
+{
+ int n = kr->nkr_num_slots;
+ idx += kr->nkr_hwofs;
+ if (idx < 0)
+ return idx + n;
+ else if (idx < n)
+ return idx;
+ else
+ return idx - n;
+}
+
+
+static inline int
+netmap_idx_k2n(struct netmap_kring *kr, int idx)
+{
+ int n = kr->nkr_num_slots;
+ idx -= kr->nkr_hwofs;
+ if (idx < 0)
+ return idx + n;
+ else if (idx < n)
+ return idx;
+ else
+ return idx - n;
+}
+
+
+#ifdef NETMAP_MEM2
+/* Entries of the look-up table. */
+struct lut_entry {
+ void *vaddr; /* virtual address. */
+ vm_paddr_t paddr; /* phisical address. */
+};
+
+struct netmap_obj_pool;
+extern struct lut_entry *netmap_buffer_lut;
+#define NMB_VA(i) (netmap_buffer_lut[i].vaddr)
+#define NMB_PA(i) (netmap_buffer_lut[i].paddr)
+#else /* NETMAP_MEM1 */
+#define NMB_VA(i) (netmap_buffer_base + (i * NETMAP_BUF_SIZE) )
+#endif /* NETMAP_MEM2 */
/*
* NMB return the virtual address of a buffer (buffer 0 on bad index)
@@ -259,25 +322,23 @@ static inline void *
NMB(struct netmap_slot *slot)
{
uint32_t i = slot->buf_idx;
- return (i >= netmap_total_buffers) ? netmap_buffer_base :
- netmap_buffer_base + (i *NETMAP_BUF_SIZE);
+ return (i >= netmap_total_buffers) ? NMB_VA(0) : NMB_VA(i);
}
static inline void *
PNMB(struct netmap_slot *slot, uint64_t *pp)
{
uint32_t i = slot->buf_idx;
- void *ret = (i >= netmap_total_buffers) ? netmap_buffer_base :
- netmap_buffer_base + (i *NETMAP_BUF_SIZE);
+ void *ret = (i >= netmap_total_buffers) ? NMB_VA(0) : NMB_VA(i);
+#ifdef NETMAP_MEM2
+ *pp = (i >= netmap_total_buffers) ? NMB_PA(0) : NMB_PA(i);
+#else
*pp = vtophys(ret);
+#endif
return ret;
}
/* default functions to handle rx/tx interrupts */
int netmap_rx_irq(struct ifnet *, int, int *);
#define netmap_tx_irq(_n, _q) netmap_rx_irq(_n, _q, NULL)
-#ifdef __linux__
-#define bus_dmamap_sync(_a, _b, _c) // wmb() or rmb() ?
-netdev_tx_t netmap_start_linux(struct sk_buff *skb, struct net_device *dev);
-#endif
#endif /* _NET_NETMAP_KERN_H_ */