diff options
author | luigi <luigi@FreeBSD.org> | 2012-02-27 19:05:01 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2012-02-27 19:05:01 +0000 |
commit | 3ac0fcfb9762b2fd4991f32bff09543ba13df0d0 (patch) | |
tree | a547096f4399bc66370c43d717a40e4b79eb8401 /sys/dev | |
parent | 71d18727cc7b50dc4e7c4d02cab4232fd4b10711 (diff) | |
download | FreeBSD-src-3ac0fcfb9762b2fd4991f32bff09543ba13df0d0.zip FreeBSD-src-3ac0fcfb9762b2fd4991f32bff09543ba13df0d0.tar.gz |
A bunch of netmap fixes:
USERSPACE:
1. add support for devices with different number of rx and tx queues;
2. add better support for zero-copy operation, adding an extra field
to the netmap ring to indicate how many buffers we have already processed
but not yet released (with help from Eddie Kohler);
3. The two changes above unfortunately require an API change, so while
at it add a version field and some spares to the ioctl() argument
to help detect mismatches.
4. update the manual page for the two changes above;
5. update sample applications in tools/tools/netmap
KERNEL:
1. simplify the internal structures moving the global wait queues
to the 'struct netmap_adapter';
2. simplify the functions that map kring<->nic ring indexes
3. normalize device-specific code, helps mainteinance;
4. start exploring the impact of micro-optimizations (prefetch etc.)
in the ixgbe driver.
Use 'legacy' descriptors on the tx ring and prefetch slots gives
about 20% speedup at 900 MHz. Another 7-10% would come from removing
the explict calls to bus_dmamap* in the core (they are effectively
NOPs in this case, but it takes expensive load of the per-buffer
dma maps to figure out that they are all NULL.
Rx performance not investigated.
I am postponing the MFC so i can import a few more improvements
before merging.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/e1000/if_em.c | 9 | ||||
-rw-r--r-- | sys/dev/e1000/if_igb.c | 9 | ||||
-rw-r--r-- | sys/dev/e1000/if_lem.c | 8 | ||||
-rw-r--r-- | sys/dev/ixgbe/ixgbe.c | 10 | ||||
-rw-r--r-- | sys/dev/netmap/if_em_netmap.h | 161 | ||||
-rw-r--r-- | sys/dev/netmap/if_igb_netmap.h | 154 | ||||
-rw-r--r-- | sys/dev/netmap/if_lem_netmap.h | 178 | ||||
-rw-r--r-- | sys/dev/netmap/if_re_netmap.h | 141 | ||||
-rw-r--r-- | sys/dev/netmap/ixgbe_netmap.h | 157 | ||||
-rw-r--r-- | sys/dev/netmap/netmap.c | 397 | ||||
-rw-r--r-- | sys/dev/netmap/netmap_kern.h | 77 | ||||
-rw-r--r-- | sys/dev/re/if_re.c | 1 |
12 files changed, 681 insertions, 621 deletions
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 9495c79..8ab511d 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -3296,7 +3296,7 @@ em_setup_transmit_ring(struct tx_ring *txr) } #ifdef DEV_NETMAP if (slot) { - int si = netmap_tidx_n2k(na, txr->me, i); + int si = netmap_idx_n2k(&na->tx_rings[txr->me], i); uint64_t paddr; void *addr; @@ -3759,7 +3759,7 @@ em_txeof(struct tx_ring *txr) selwakeuppri(&na->tx_rings[txr->me].si, PI_NET); EM_TX_UNLOCK(txr); EM_CORE_LOCK(adapter); - selwakeuppri(&na->tx_rings[na->num_queues + 1].si, PI_NET); + selwakeuppri(&na->tx_si, PI_NET); EM_CORE_UNLOCK(adapter); EM_TX_LOCK(txr); return (FALSE); @@ -4051,7 +4051,7 @@ em_setup_receive_ring(struct rx_ring *rxr) rxbuf = &rxr->rx_buffers[j]; #ifdef DEV_NETMAP if (slot) { - int si = netmap_ridx_n2k(na, rxr->me, j); + int si = netmap_idx_n2k(&na->rx_rings[rxr->me], j); uint64_t paddr; void *addr; @@ -4370,10 +4370,11 @@ em_rxeof(struct rx_ring *rxr, int count, int *done) if (ifp->if_capenable & IFCAP_NETMAP) { struct netmap_adapter *na = NA(ifp); + na->rx_rings[rxr->me].nr_kflags |= NKR_PENDINTR; selwakeuppri(&na->rx_rings[rxr->me].si, PI_NET); EM_RX_UNLOCK(rxr); EM_CORE_LOCK(adapter); - selwakeuppri(&na->rx_rings[na->num_queues + 1].si, PI_NET); + selwakeuppri(&na->rx_si, PI_NET); EM_CORE_UNLOCK(adapter); return (0); } diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index a70b4ad..4c84281 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -3315,7 +3315,7 @@ igb_setup_transmit_ring(struct tx_ring *txr) } #ifdef DEV_NETMAP if (slot) { - int si = netmap_tidx_n2k(na, txr->me, i); + int si = netmap_idx_n2k(&na->tx_rings[txr->me], i); /* no need to set the address */ netmap_load_map(txr->txtag, txbuf->map, NMB(slot + si)); } @@ -3693,7 +3693,7 @@ igb_txeof(struct tx_ring *txr) selwakeuppri(&na->tx_rings[txr->me].si, PI_NET); IGB_TX_UNLOCK(txr); IGB_CORE_LOCK(adapter); - selwakeuppri(&na->tx_rings[na->num_queues + 1].si, PI_NET); + selwakeuppri(&na->tx_si, PI_NET); IGB_CORE_UNLOCK(adapter); IGB_TX_LOCK(txr); return FALSE; @@ -4057,7 +4057,7 @@ igb_setup_receive_ring(struct rx_ring *rxr) #ifdef DEV_NETMAP if (slot) { /* slot sj is mapped to the i-th NIC-ring entry */ - int sj = netmap_ridx_n2k(na, rxr->me, j); + int sj = netmap_idx_n2k(&na->rx_rings[rxr->me], j); uint64_t paddr; void *addr; @@ -4554,10 +4554,11 @@ igb_rxeof(struct igb_queue *que, int count, int *done) if (ifp->if_capenable & IFCAP_NETMAP) { struct netmap_adapter *na = NA(ifp); + na->rx_rings[rxr->me].nr_kflags |= NKR_PENDINTR; selwakeuppri(&na->rx_rings[rxr->me].si, PI_NET); IGB_RX_UNLOCK(rxr); IGB_CORE_LOCK(adapter); - selwakeuppri(&na->rx_rings[na->num_queues + 1].si, PI_NET); + selwakeuppri(&na->rx_si, PI_NET); IGB_CORE_UNLOCK(adapter); return (0); } diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c index be46260..b5bca6a 100644 --- a/sys/dev/e1000/if_lem.c +++ b/sys/dev/e1000/if_lem.c @@ -2669,7 +2669,7 @@ lem_setup_transmit_structures(struct adapter *adapter) #ifdef DEV_NETMAP if (slot) { /* the i-th NIC entry goes to slot si */ - int si = netmap_tidx_n2k(na, 0, i); + int si = netmap_idx_n2k(&na->tx_rings[0], i); uint64_t paddr; void *addr; @@ -3243,7 +3243,7 @@ lem_setup_receive_structures(struct adapter *adapter) #ifdef DEV_NETMAP if (slot) { /* the i-th NIC entry goes to slot si */ - int si = netmap_ridx_n2k(na, 0, i); + int si = netmap_idx_n2k(&na->rx_rings[0], i); uint64_t paddr; void *addr; @@ -3475,7 +3475,9 @@ lem_rxeof(struct adapter *adapter, int count, int *done) #ifdef DEV_NETMAP if (ifp->if_capenable & IFCAP_NETMAP) { - selwakeuppri(&NA(ifp)->rx_rings[0].si, PI_NET); + struct netmap_adapter *na = NA(ifp); + na->rx_rings[0].nr_kflags |= NKR_PENDINTR; + selwakeuppri(&na->rx_rings[0].si, PI_NET); EM_RX_UNLOCK(adapter); return (0); } diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c index 48a27b0..befedc9 100644 --- a/sys/dev/ixgbe/ixgbe.c +++ b/sys/dev/ixgbe/ixgbe.c @@ -2970,10 +2970,10 @@ ixgbe_setup_transmit_ring(struct tx_ring *txr) * kring->nkr_hwofs positions "ahead" wrt the * corresponding slot in the NIC ring. In some drivers * (not here) nkr_hwofs can be negative. Function - * netmap_tidx_n2k() handles wraparounds properly. + * netmap_idx_n2k() handles wraparounds properly. */ if (slot) { - int si = netmap_tidx_n2k(na, txr->me, i); + int si = netmap_idx_n2k(&na->tx_rings[txr->me], i); netmap_load_map(txr->txtag, txbuf->map, NMB(slot + si)); } #endif /* DEV_NETMAP */ @@ -3491,7 +3491,7 @@ ixgbe_txeof(struct tx_ring *txr) selwakeuppri(&na->tx_rings[txr->me].si, PI_NET); IXGBE_TX_UNLOCK(txr); IXGBE_CORE_LOCK(adapter); - selwakeuppri(&na->tx_rings[na->num_queues + 1].si, PI_NET); + selwakeuppri(&na->tx_si, PI_NET); IXGBE_CORE_UNLOCK(adapter); IXGBE_TX_LOCK(txr); } @@ -3922,7 +3922,7 @@ ixgbe_setup_receive_ring(struct rx_ring *rxr) * an mbuf, so end the block with a continue; */ if (slot) { - int sj = netmap_ridx_n2k(na, rxr->me, j); + int sj = netmap_idx_n2k(&na->rx_rings[rxr->me], j); uint64_t paddr; void *addr; @@ -4376,7 +4376,7 @@ ixgbe_rxeof(struct ix_queue *que, int count) selwakeuppri(&na->rx_rings[rxr->me].si, PI_NET); IXGBE_RX_UNLOCK(rxr); IXGBE_CORE_LOCK(adapter); - selwakeuppri(&na->rx_rings[na->num_queues + 1].si, PI_NET); + selwakeuppri(&na->rx_si, PI_NET); IXGBE_CORE_UNLOCK(adapter); return (FALSE); } diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h index 70d92cf..8a3893e 100644 --- a/sys/dev/netmap/if_em_netmap.h +++ b/sys/dev/netmap/if_em_netmap.h @@ -25,45 +25,23 @@ /* * $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 support for if_em.c + * 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); -} static void @@ -137,7 +115,7 @@ em_netmap_unblock_tasks(struct adapter *adapter) /* - * register-unregister routine + * Register/unregister routine */ static int em_netmap_reg(struct ifnet *ifp, int onoff) @@ -180,17 +158,17 @@ fail: /* - * 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,16 +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 = netmap_tidx_k2n(na, ring_nr, j); + 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) || @@ -221,7 +200,7 @@ 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) @@ -230,25 +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; } - 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, @@ -275,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) @@ -292,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) @@ -308,37 +285,45 @@ em_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 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 = netmap_ridx_n2k(na, ring_nr, l); - for (n = 0; ; n++) { - struct e1000_rx_desc *curr = &rxr->rx_base[l]; - - 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; + 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 ((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 */ + /* skip past packets that userspace has released */ j = kring->nr_hwcur; /* netmap ring index */ - if (j != k) { /* userspace has read some packets. */ - l = netmap_ridx_k2n(na, ring_nr, j); /* NIC 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]; @@ -352,17 +337,15 @@ 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; } @@ -378,9 +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 3d37b69..8ba13ee 100644 --- a/sys/dev/netmap/if_igb_netmap.h +++ b/sys/dev/netmap/if_igb_netmap.h @@ -25,41 +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 contributed 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 @@ -134,17 +112,17 @@ fail: /* - * Reconcile hardware and user view of the transmit ring. + * Reconcile kernel and user view of the transmit ring. */ static int 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; @@ -164,14 +142,16 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) * j == (l + kring->nkr_hwofs) % ring_size */ j = kring->nr_hwcur; - if (j != k) { /* we have packets to send */ + if (j != k) { /* we have new packets to send */ /* 82575 needs the queue index added */ u32 olinfo_status = (adapter->hw.mac.type == e1000_82575) ? (txr->me << 4) : 0; - l = netmap_tidx_k2n(na, ring_nr, j); + 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 */ union e1000_adv_tx_desc *curr = (union e1000_adv_tx_desc *)&txr->tx_base[l]; struct igb_tx_buffer *txbuf = &txr->tx_buffers[l]; @@ -180,7 +160,7 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) E1000_ADVTXD_DCMD_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) @@ -189,8 +169,13 @@ igb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) } slot->flags &= ~NS_REPORT; - // XXX set the address unconditionally + 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)); @@ -199,20 +184,13 @@ 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; } - kring->nr_hwcur = k; - - /* decrease avail by number of sent packets */ + kring->nr_hwcur = k; /* the saved ring->cur */ kring->nr_hwavail -= n; /* Set the watchdog XXX ? */ @@ -243,7 +221,7 @@ igb_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) @@ -260,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) @@ -276,36 +256,43 @@ igb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 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 = netmap_ridx_n2k(na, ring_nr, l); - 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; + 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) { /* 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. */ - l = netmap_ridx_k2n(na, ring_nr, j); + /* 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]; @@ -319,16 +306,14 @@ 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; } @@ -344,9 +329,28 @@ igb_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) 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 0182318..9f24580 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,30 +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); - - -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) @@ -94,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) @@ -104,7 +80,7 @@ lem_netmap_reg(struct ifnet *ifp, int onoff) int error = 0; if (na == NULL) - return EINVAL; /* no netmap support here */ + return EINVAL; lem_disable_intr(adapter); @@ -144,20 +120,21 @@ fail: /* - * Reconcile hardware and user view of the transmit ring. + * Reconcile kernel and user view of the transmit ring. */ 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_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); @@ -166,17 +143,17 @@ 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); - - /* 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 = netmap_tidx_k2n(na, ring_nr, j); + 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 = &adapter->tx_desc_base[l]; struct em_buffer *txbuf = &adapter->tx_buffer_area[l]; int flags = ((slot->flags & NS_REPORT) || @@ -184,7 +161,7 @@ lem_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) @@ -193,25 +170,23 @@ 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; } - 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(adapter->txdma.dma_tag, adapter->txdma.dma_map, @@ -231,14 +206,14 @@ lem_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) } delta = l - adapter->next_tx_to_clean; if (delta) { - /* some completed, increment hwavail. */ + /* some tx completed, increment hwavail. */ if (delta < 0) delta += kring->nkr_num_slots; adapter->next_tx_to_clean = l; 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) @@ -254,12 +229,13 @@ 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_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); @@ -270,42 +246,50 @@ lem_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 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 - * 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 = adapter->next_rx_desc_to_check; - j = netmap_ridx_n2k(na, ring_nr, l); - 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 - - if (len < 0) { - D("bogus pkt size at %d", j); - len = 0; + 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 ((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 */ + /* skip past packets that userspace has released */ j = kring->nr_hwcur; /* netmap ring index */ - if (j != k) { /* userspace has read some packets. */ - l = netmap_ridx_k2n(na, ring_nr, j); /* NIC 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]; @@ -319,13 +303,13 @@ lem_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(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); @@ -345,9 +329,29 @@ lem_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 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 1ad5307..9984186 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,7 +149,7 @@ 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; @@ -211,10 +190,8 @@ re_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) l = (l == lim) ? 0 : l + 1; } 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, @@ -241,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) @@ -255,45 +234,53 @@ 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 = netmap_ridx_n2k(na, ring_nr, l); /* the kring index */ - 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; + 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; + } + 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. */ - l = netmap_ridx_k2n(na, ring_nr, j); /* the NIC 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); /* 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]; @@ -310,15 +297,15 @@ 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; @@ -333,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; @@ -363,7 +350,7 @@ 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++) { uint64_t paddr; - int l = netmap_tidx_n2k(na, 0, i); + int l = netmap_idx_n2k(&na->tx_rings[0], i); void *addr = PNMB(slot + l, &paddr); desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr)); @@ -394,7 +381,7 @@ re_netmap_rx_init(struct rl_softc *sc) for (i = 0; i < n; i++) { void *addr; uint64_t paddr; - int l = netmap_ridx_n2k(na, 0, i); + int l = netmap_idx_n2k(&na->rx_rings[0], i); addr = PNMB(slot + l, &paddr); @@ -412,3 +399,23 @@ re_netmap_rx_init(struct rl_softc *sc) 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 b0a203a..c711110 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,8 @@ #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. - */ -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); -} - /* * wrapper to export locks to the generic netmap code. @@ -119,7 +83,7 @@ ixgbe_netmap_lock_wrapper(struct ifnet *_a, int what, u_int queueid) /* - * 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,8 +93,8 @@ 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); @@ -197,7 +161,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,20 +170,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; - /* do a sanity check on cur - hwcur XXX verify */ - 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); @@ -241,7 +195,9 @@ 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 = netmap_tidx_k2n(na, ring_nr, j); /* NIC index */ + 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. @@ -253,17 +209,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. @@ -279,35 +243,29 @@ ring_reset: return netmap_ring_reinit(kring); } - slot->flags &= ~NS_REPORT; 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) ); + 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; + 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 */ @@ -416,20 +374,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); @@ -450,7 +403,7 @@ 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 = netmap_ridx_n2k(na, ring_nr, l); + j = netmap_idx_n2k(kring, l); if (netmap_no_pendintr || force_update) { for (n = 0; ; n++) { @@ -473,15 +426,22 @@ ixgbe_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) } /* - * 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. */ - l = netmap_ridx_k2n(na, ring_nr, j); + 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. @@ -522,7 +482,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); @@ -533,4 +493,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 8dc62d8..ae9a599 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 @@ -87,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 */ @@ -254,10 +254,10 @@ struct netmap_mem_d { /* Shorthand to compute a netmap interface offset. */ #define netmap_if_offset(v) \ - ((char *) (v) - (char *) netmap_mem_d->nm_buffer) + ((char *) (v) - (char *) nm_mem->nm_buffer) /* .. and get a physical address given a memory offset */ #define netmap_ofstophys(o) \ - (vtophys(netmap_mem_d->nm_buffer) + (o)) + (vtophys(nm_mem->nm_buffer) + (o)) /*------ netmap memory allocator -------*/ @@ -265,7 +265,7 @@ struct netmap_mem_d { * 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. + * 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. @@ -279,7 +279,7 @@ netmap_malloc(size_t size, __unused const char *msg) void *ret = NULL; NMA_LOCK(); - TAILQ_FOREACH(mem_obj, &netmap_mem_d->nm_molist, nmo_next) { + TAILQ_FOREACH(mem_obj, &nm_mem->nm_molist, nmo_next) { if (mem_obj->nmo_used != 0 || mem_obj->nmo_size < size) continue; @@ -295,7 +295,7 @@ netmap_malloc(size_t size, __unused const char *msg) 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, + TAILQ_REMOVE(&nm_mem->nm_molist, mem_obj, nmo_next); free(mem_obj, M_NETMAP); } @@ -328,7 +328,7 @@ netmap_free(void *addr, const char *msg) } NMA_LOCK(); - TAILQ_FOREACH(cur, &netmap_mem_d->nm_molist, nmo_next) { + TAILQ_FOREACH(cur, &nm_mem->nm_molist, nmo_next) { if (cur->nmo_data == addr && cur->nmo_used) break; } @@ -345,7 +345,7 @@ netmap_free(void *addr, const char *msg) 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); + TAILQ_REMOVE(&nm_mem->nm_molist, cur, nmo_next); prev->nmo_size += cur->nmo_size; free(cur, M_NETMAP); cur = prev; @@ -354,7 +354,7 @@ netmap_free(void *addr, const char *msg) /* 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); + TAILQ_REMOVE(&nm_mem->nm_molist, next, nmo_next); cur->nmo_size += next->nmo_size; free(next, M_NETMAP); } @@ -374,21 +374,24 @@ netmap_if_new(const char *ifname, struct netmap_adapter *na) { struct netmap_if *nifp; struct netmap_ring *ring; + struct netmap_kring *kring; char *buff; - u_int i, len, ofs; - u_int n = na->num_queues + 1; /* shorthand, include stack queue */ + u_int i, len, ofs, numdesc; + u_int nrx = na->num_rx_queues + 1; /* shorthand, include stack queue */ + u_int ntx = na->num_tx_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); + len = sizeof(struct netmap_if) + (nrx + ntx) * 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; + *(int *)(uintptr_t)&nifp->ni_rx_queues = na->num_rx_queues; + *(int *)(uintptr_t)&nifp->ni_tx_queues = na->num_tx_queues; strncpy(nifp->ni_name, ifname, IFNAMSIZ); (na->refcount)++; /* XXX atomic ? we are under lock */ @@ -396,16 +399,15 @@ netmap_if_new(const char *ifname, struct netmap_adapter *na) 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). + * First instance. Allocate the netmap rings + * (one for each hw queue, one pair for the host). * The rings are contiguous, but have variable size. * The entire block is reachable at - * na->tx_rings[0].ring + * na->tx_rings[0] */ - - len = n * (2 * sizeof(struct netmap_ring) + - (na->num_tx_desc + na->num_rx_desc) * - sizeof(struct netmap_slot) ); + len = (ntx + nrx) * sizeof(struct netmap_ring) + + (ntx * na->num_tx_desc + nrx * 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", @@ -415,9 +417,8 @@ error: 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); + /* Check whether we have enough buffers */ + len = ntx * na->num_tx_desc + nrx * na->num_rx_desc; NMA_LOCK(); if (nm_buf_pool.free < len) { NMA_UNLOCK(); @@ -429,11 +430,7 @@ error: * 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 */ + for (i = 0; i < ntx; i++) { /* Transmit rings */ kring = &na->tx_rings[i]; numdesc = na->num_tx_desc; bzero(kring, sizeof(*kring)); @@ -459,8 +456,9 @@ error: ofs += sizeof(struct netmap_ring) + numdesc * sizeof(struct netmap_slot); + } - /* Receive rings */ + for (i = 0; i < nrx; i++) { /* Receive rings */ kring = &na->rx_rings[i]; numdesc = na->num_rx_desc; bzero(kring, sizeof(*kring)); @@ -480,21 +478,21 @@ error: numdesc * sizeof(struct netmap_slot); } NMA_UNLOCK(); - for (i = 0; i < n+1; i++) { - // XXX initialize the selrecord structs. - } + // 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; + for (i = 0; i < ntx; i++) { *(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; + (char *)na->tx_rings[i].ring - (char *)nifp; + } + for (i = 0; i < nrx; i++) { + *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+ntx] = + (char *)na->rx_rings[i].ring - (char *)nifp; } return (nifp); } @@ -532,17 +530,17 @@ netmap_memory_init(void) ); if (buf) break; - } + } if (buf == NULL) return (ENOMEM); sz += extra_sz; - netmap_mem_d = malloc(sizeof(struct netmap_mem_d), M_NETMAP, + nm_mem = 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_init(&nm_mem->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; + TAILQ_INIT(&nm_mem->nm_molist); + nm_mem->nm_buffer = buf; + nm_mem->nm_totalsize = sz; /* * A buffer takes 2k, a slot takes 8 bytes + ring overhead, @@ -550,24 +548,24 @@ netmap_memory_init(void) * 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_mem->nm_size = sz/200; + nm_mem->nm_buf_start = + (nm_mem->nm_size + PAGE_SIZE - 1) & ~(PAGE_SIZE-1); + nm_mem->nm_buf_len = sz - nm_mem->nm_buf_start; - nm_buf_pool.base = netmap_mem_d->nm_buffer; - nm_buf_pool.base += netmap_mem_d->nm_buf_start; + nm_buf_pool.base = nm_mem->nm_buffer; + nm_buf_pool.base += nm_mem->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); + netmap_buffer_base, (int)nm_mem->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_mem->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), + (sz >> 20), (int)(nm_mem->nm_size >> 10), nm_buf_pool.total_buffers, nm_buf_pool.base); /* allocate and initialize the bitmap. Entry 0 is considered @@ -583,10 +581,10 @@ netmap_memory_init(void) 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); + TAILQ_INSERT_HEAD(&nm_mem->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; + mem_obj->nmo_size = nm_mem->nm_size; + mem_obj->nmo_data = nm_mem->nm_buffer; return (0); } @@ -603,9 +601,9 @@ 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); + while (!TAILQ_EMPTY(&nm_mem->nm_molist)) { + mem_obj = TAILQ_FIRST(&nm_mem->nm_molist); + TAILQ_REMOVE(&nm_mem->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, @@ -613,9 +611,9 @@ netmap_memory_fini(void) } free(mem_obj, M_NETMAP); } - contigfree(netmap_mem_d->nm_buffer, netmap_mem_d->nm_totalsize, M_NETMAP); + contigfree(nm_mem->nm_buffer, nm_mem->nm_totalsize, M_NETMAP); // XXX mutex_destroy(nm_mtx); - free(netmap_mem_d, M_NETMAP); + free(nm_mem, M_NETMAP); } /*------------- end of memory allocator -----------------*/ @@ -647,7 +645,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); /* @@ -669,24 +667,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_queues + 1; i++) selwakeuppri(&na->tx_rings[i].si, PI_NET); + for (i = 0; i < na->num_rx_queues + 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_queues + 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_queues + 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); @@ -708,7 +704,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 */ @@ -758,7 +754,7 @@ netmap_mmap(__unused struct cdev *dev, 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_queues]; struct netmap_ring *ring = kring->ring; struct mbuf *head = NULL, *tail = NULL, *m; u_int k, n, lim = kring->nkr_num_slots - 1; @@ -818,31 +814,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_queues]; 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; + 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; - error = 0; - k = ring->avail = kring->nr_hwavail; + } + 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); } @@ -907,13 +909,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_queues + 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; @@ -933,10 +935,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_queues; - if ( (ringid & NETMAP_HW_RING) && i >= na->num_queues) { + if (na->num_tx_queues > lim) + lim = na->num_tx_queues; + if ( (ringid & NETMAP_HW_RING) && i >= lim) { D("invalid ring id %d", i); return (EINVAL); } @@ -944,14 +949,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) @@ -962,8 +967,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; } @@ -989,7 +993,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)); @@ -1004,22 +1008,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_queues; + nmr->nr_tx_rings = na->num_tx_queues; + 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; @@ -1095,9 +1113,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_queues; + nmr->nr_tx_rings = na->num_tx_queues; + 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; @@ -1120,17 +1140,19 @@ 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_queues : na->num_rx_queues; - for (i = priv->np_qfirst; i < priv->np_qlast; i++) { + 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) @@ -1195,6 +1217,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) @@ -1212,17 +1235,18 @@ netmap_poll(__unused struct cdev *dev, int events, struct thread *td) na = NA(ifp); /* retrieve netmap adapter */ + lim_tx = na->num_tx_queues; + lim_rx = na->num_rx_queues; /* 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) { @@ -1253,7 +1277,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. @@ -1270,25 +1294,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 @@ -1296,7 +1324,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 @@ -1340,7 +1368,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); @@ -1364,12 +1392,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); @@ -1430,28 +1457,37 @@ netmap_lock_wrapper(struct ifnet *dev, 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_queues 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_queues == 0) + na->num_tx_queues = num_queues; + na->num_rx_queues = 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_queues + na->num_tx_queues + 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->rx_rings = na->tx_rings + na->num_tx_queues + 1; na->buff_size = NETMAP_BUF_SIZE; bcopy(na, buf, sizeof(*na)); ifp->if_capabilities |= IFCAP_NETMAP; @@ -1460,11 +1496,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_queues + 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_queues + 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); @@ -1484,10 +1526,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_queues + 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_queues + 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); @@ -1503,7 +1551,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_queues]; u_int i, len = MBUF_LEN(m); int error = EBUSY, lim = kring->nkr_num_slots - 1; struct netmap_slot *slot; @@ -1516,8 +1564,8 @@ netmap_start(struct ifnet *ifp, struct mbuf *m) 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 */ } @@ -1530,7 +1578,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_queues); selwakeuppri(&kring->si, PI_NET); error = 0; done: @@ -1556,21 +1604,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; @@ -1583,11 +1631,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; } @@ -1603,38 +1652,48 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, int n, * lock(i); wake(i); unlock(i) * N rings, separate locks: * 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) { 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_queues > 1) ? &na->tx_si : NULL; + } else { /* tx path */ + r = na->tx_rings + q; + main_wq = (na->num_tx_queues > 1) ? &na->rx_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 */ return 1; } + static struct cdevsw netmap_cdevsw = { .d_version = D_VERSION, .d_name = "netmap", @@ -1666,7 +1725,7 @@ netmap_init(void) 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 (error); diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 6e03570..7660d14 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. @@ -39,7 +39,7 @@ #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 +65,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 @@ -101,13 +108,14 @@ struct netmap_adapter { 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 + u_int num_rx_queues; /* number of tx/rx queue pairs: this is a duplicate field needed to simplify the signature of ``netmap_detach``. */ + u_int num_tx_queues; // if nonzero, overrides num_queues XXX 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 @@ -117,6 +125,8 @@ 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. @@ -135,6 +145,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 */ }; /* @@ -254,55 +267,33 @@ 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_ridx_n2k(struct netmap_adapter *na, int ring, int nic_idx) +netmap_idx_n2k(struct netmap_kring *kr, int idx) { - int kring_idx = nic_idx + na->rx_rings[ring].nkr_hwofs; - if (kring_idx < 0) - return kring_idx + na->num_rx_desc; - else if (kring_idx < na->num_rx_desc) - return kring_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 kring_idx - na->num_rx_desc; -} - -static inline int -netmap_tidx_n2k(struct netmap_adapter *na, int ring, int nic_idx) -{ - int kring_idx = nic_idx + na->tx_rings[ring].nkr_hwofs; - if (kring_idx < 0) - return kring_idx + na->num_tx_desc; - else if (kring_idx < na->num_tx_desc) - return kring_idx; - else - return kring_idx - na->num_tx_desc; + return idx - n; } static inline int -netmap_ridx_k2n(struct netmap_adapter *na, int ring, int kring_idx) +netmap_idx_k2n(struct netmap_kring *kr, int idx) { - int nic_idx = kring_idx - na->rx_rings[ring].nkr_hwofs; - if (nic_idx < 0) - return nic_idx + na->num_rx_desc; - else if (nic_idx < na->num_rx_desc) - return nic_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 nic_idx - na->num_rx_desc; + return idx - n; } -static inline int -netmap_tidx_k2n(struct netmap_adapter *na, int ring, int kring_idx) -{ - int nic_idx = kring_idx - na->tx_rings[ring].nkr_hwofs; - if (nic_idx < 0) - return nic_idx + na->num_tx_desc; - else if (nic_idx < na->num_tx_desc) - return nic_idx; - else - return nic_idx - na->num_tx_desc; -} - /* * NMB return the virtual address of a buffer (buffer 0 on bad index) * PNMB also fills the physical address diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index f73389e..d11661c 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -2111,6 +2111,7 @@ re_rxeof(struct rl_softc *sc, int *rx_npktsp) ifp = sc->rl_ifp; #ifdef DEV_NETMAP if (ifp->if_capenable & IFCAP_NETMAP) { + NA(ifp)->rx_rings->nr_kflags |= NKR_PENDINTR; selwakeuppri(&NA(ifp)->rx_rings->si, PI_NET); return 0; } |