From owner-svn-src-head@FreeBSD.ORG Mon Dec 5 15:33:15 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5383D106564A; Mon, 5 Dec 2011 15:33:14 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 42A848FC19; Mon, 5 Dec 2011 15:33:14 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id pB5FXEBV043068; Mon, 5 Dec 2011 15:33:14 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pB5FXEuh043063; Mon, 5 Dec 2011 15:33:14 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201112051533.pB5FXEuh043063@svn.freebsd.org> From: Luigi Rizzo Date: Mon, 5 Dec 2011 15:33:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r228281 - in head/sys/dev: e1000 re X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Dec 2011 15:33:15 -0000 Author: luigi Date: Mon Dec 5 15:33:13 2011 New Revision: 228281 URL: http://svn.freebsd.org/changeset/base/228281 Log: add netmap support for "em", "lem", "igb" and "re". On my hardware, "em" in netmap mode does about 1.388 Mpps on one card (on an Asus motherboard), and 1.1 Mpps on another card (PCIe bus). Both seem to be NIC-limited, because i have the same rate even with the CPU running at 150 MHz. On the "re" driver the tx throughput is around 420-450 Kpps on various (8111C and the like) chipsets. On the Rx side performance seems much better, and i can receive the full load generated by the "em" cards. "igb" is untested as i don't have the hardware. Modified: head/sys/dev/e1000/if_em.c head/sys/dev/e1000/if_igb.c head/sys/dev/e1000/if_lem.c head/sys/dev/re/if_re.c Modified: head/sys/dev/e1000/if_em.c ============================================================================== --- head/sys/dev/e1000/if_em.c Mon Dec 5 15:21:21 2011 (r228280) +++ head/sys/dev/e1000/if_em.c Mon Dec 5 15:33:13 2011 (r228281) @@ -399,6 +399,10 @@ SYSCTL_INT(_hw_em, OID_AUTO, eee_setting /* Global used in WOL setup with multiport cards */ static int global_quad_port_a = 0; +#ifdef DEV_NETMAP /* see ixgbe.c for details */ +#include +#endif /* DEV_NETMAP */ + /********************************************************************* * Device identification routine * @@ -714,6 +718,9 @@ em_attach(device_t dev) adapter->led_dev = led_create(em_led_func, adapter, device_get_nameunit(dev)); +#ifdef DEV_NETMAP + em_netmap_attach(adapter); +#endif /* DEV_NETMAP */ INIT_DEBUGOUT("em_attach: end"); @@ -785,6 +792,10 @@ em_detach(device_t dev) ether_ifdetach(adapter->ifp); callout_drain(&adapter->timer); +#ifdef DEV_NETMAP + netmap_detach(ifp); +#endif /* DEV_NETMAP */ + em_free_pci_resources(adapter); bus_generic_detach(dev); if_free(ifp); @@ -3213,9 +3224,17 @@ em_setup_transmit_ring(struct tx_ring *t struct adapter *adapter = txr->adapter; struct em_buffer *txbuf; int i; +#ifdef DEV_NETMAP + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_slot *slot; +#endif /* DEV_NETMAP */ /* Clear the old descriptor contents */ EM_TX_LOCK(txr); +#ifdef DEV_NETMAP + slot = netmap_reset(na, NR_TX, txr->me, 0); +#endif /* DEV_NETMAP */ + bzero((void *)txr->tx_base, (sizeof(struct e1000_tx_desc)) * adapter->num_tx_desc); /* Reset indices */ @@ -3232,6 +3251,22 @@ em_setup_transmit_ring(struct tx_ring *t m_freem(txbuf->m_head); txbuf->m_head = NULL; } +#ifdef DEV_NETMAP + if (slot) { + int si = i + na->tx_rings[txr->me].nkr_hwofs; + void *addr; + + if (si >= na->num_tx_desc) + si -= na->num_tx_desc; + addr = NMB(slot + si); + txr->tx_base[i].buffer_addr = + htole64(vtophys(addr)); + /* reload the map for netmap mode */ + netmap_load_map(txr->txtag, + txbuf->map, addr, na->buff_size); + } +#endif /* DEV_NETMAP */ + /* clear the watch index */ txbuf->next_eop = -1; } @@ -3682,6 +3717,19 @@ em_txeof(struct tx_ring *txr) struct ifnet *ifp = adapter->ifp; EM_TX_LOCK_ASSERT(txr); +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(ifp); + + 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); + EM_CORE_UNLOCK(adapter); + EM_TX_LOCK(txr); + return (FALSE); + } +#endif /* DEV_NETMAP */ /* No work, make sure watchdog is off */ if (txr->tx_avail == adapter->num_tx_desc) { @@ -3978,6 +4026,57 @@ em_setup_receive_ring(struct rx_ring *rx if (++j == adapter->num_rx_desc) j = 0; } +#ifdef DEV_NETMAP + { + /* + * This driver is slightly different from the standard: + * it refills the rings in blocks of 8, so the while() + * above completes any leftover work. Also, after if_init() + * the ring starts at rxr->next_to_check instead of 0. + * + * Currently: we leave the mbufs allocated even in netmap + * mode, and simply make the NIC ring point to the + * correct buffer (netmap_buf or mbuf) depending on + * the mode. To avoid mbuf leaks, when in netmap mode we + * must make sure that next_to_refresh == next_to_check - 1 + * so that the above while() loop is never run on init. + * + * A better way would be to free the mbufs when entering + * netmap mode, and set next_to_refresh/check in + * a way that the mbufs are completely reallocated + * when going back to standard mode. + */ + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_slot *slot = netmap_reset(na, + NR_RX, rxr->me, rxr->next_to_check); + int sj = slot ? na->rx_rings[rxr->me].nkr_hwofs : 0; + + /* slot sj corresponds to entry j in the NIC ring */ + if (sj < 0) + sj += adapter->num_rx_desc; + + for (j = 0; j != adapter->num_rx_desc; j++, sj++) { + void *addr; + int sz; + + rxbuf = &rxr->rx_buffers[j]; + /* no mbuf and regular mode -> skip this entry */ + if (rxbuf->m_head == NULL && !slot) + continue; + /* Handle wrap. Cannot use "na" here, could be NULL */ + if (sj >= adapter->num_rx_desc) + sj -= adapter->num_rx_desc; + /* see comment, set slot addr and map */ + addr = slot ? NMB(slot + sj) : rxbuf->m_head->m_data; + sz = slot ? na->buff_size : adapter->rx_mbuf_sz; + // XXX load or reload ? + netmap_load_map(rxr->rxtag, rxbuf->map, addr, sz); + /* Update descriptor */ + rxr->rx_base[j].buffer_addr = htole64(vtophys(addr)); + bus_dmamap_sync(rxr->rxtag, rxbuf->map, BUS_DMASYNC_PREREAD); + } + } +#endif /* DEV_NETMAP */ fail: rxr->next_to_refresh = i; @@ -4170,6 +4269,23 @@ em_initialize_receive_unit(struct adapte E1000_WRITE_REG(hw, E1000_RDBAL(i), (u32)bus_addr); /* Setup the Head and Tail Descriptor Pointers */ E1000_WRITE_REG(hw, E1000_RDH(i), rxr->next_to_check); +#ifdef DEV_NETMAP + /* + * an init() while a netmap client is active must + * preserve the rx buffers passed to userspace. + * In this driver it means we adjust RDT to + * something different from next_to_refresh. + */ + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_kring *kring = &na->rx_rings[i]; + int t = rxr->next_to_refresh - kring->nr_hwavail; + + if (t < 0) + t += na->num_rx_desc; + E1000_WRITE_REG(hw, E1000_RDT(i), t); + } else +#endif /* DEV_NETMAP */ E1000_WRITE_REG(hw, E1000_RDT(i), rxr->next_to_refresh); } @@ -4247,6 +4363,19 @@ em_rxeof(struct rx_ring *rxr, int count, EM_RX_LOCK(rxr); +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(ifp); + + 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); + EM_CORE_UNLOCK(adapter); + return (0); + } +#endif /* DEV_NETMAP */ + for (i = rxr->next_to_check, processed = 0; count != 0;) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) Modified: head/sys/dev/e1000/if_igb.c ============================================================================== --- head/sys/dev/e1000/if_igb.c Mon Dec 5 15:21:21 2011 (r228280) +++ head/sys/dev/e1000/if_igb.c Mon Dec 5 15:33:13 2011 (r228281) @@ -369,6 +369,9 @@ SYSCTL_INT(_hw_igb, OID_AUTO, rx_process &igb_rx_process_limit, 0, "Maximum number of received packets to process at a time, -1 means unlimited"); +#ifdef DEV_NETMAP /* see ixgbe.c for details */ +#include +#endif /* DEV_NETMAP */ /********************************************************************* * Device identification routine * @@ -664,6 +667,9 @@ igb_attach(device_t dev) adapter->led_dev = led_create(igb_led_func, adapter, device_get_nameunit(dev)); +#ifdef DEV_NETMAP + igb_netmap_attach(adapter); +#endif /* DEV_NETMAP */ INIT_DEBUGOUT("igb_attach: end"); return (0); @@ -742,6 +748,9 @@ igb_detach(device_t dev) callout_drain(&adapter->timer); +#ifdef DEV_NETMAP + netmap_detach(adapter->ifp); +#endif /* DEV_NETMAP */ igb_free_pci_resources(adapter); bus_generic_detach(dev); if_free(ifp); @@ -3212,9 +3221,16 @@ igb_setup_transmit_ring(struct tx_ring * struct adapter *adapter = txr->adapter; struct igb_tx_buffer *txbuf; int i; +#ifdef DEV_NETMAP + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_slot *slot; +#endif /* DEV_NETMAP */ /* Clear the old descriptor contents */ IGB_TX_LOCK(txr); +#ifdef DEV_NETMAP + slot = netmap_reset(na, NR_TX, txr->me, 0); +#endif /* DEV_NETMAP */ bzero((void *)txr->tx_base, (sizeof(union e1000_adv_tx_desc)) * adapter->num_tx_desc); /* Reset indices */ @@ -3231,6 +3247,17 @@ igb_setup_transmit_ring(struct tx_ring * m_freem(txbuf->m_head); txbuf->m_head = NULL; } +#ifdef DEV_NETMAP + if (slot) { + /* slot si is mapped to the i-th NIC-ring entry */ + int si = i + na->tx_rings[txr->me].nkr_hwofs; + + if (si < 0) + si += na->num_tx_desc; + netmap_load_map(txr->txtag, txbuf->map, + NMB(slot + si), na->buff_size); + } +#endif /* DEV_NETMAP */ /* clear the watch index */ txbuf->next_eop = -1; } @@ -3626,6 +3653,19 @@ igb_txeof(struct tx_ring *txr) IGB_TX_LOCK_ASSERT(txr); +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(ifp); + + 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); + IGB_CORE_UNLOCK(adapter); + IGB_TX_LOCK(txr); + return FALSE; + } +#endif /* DEV_NETMAP */ if (txr->tx_avail == adapter->num_tx_desc) { txr->queue_status = IGB_QUEUE_IDLE; return FALSE; @@ -3949,6 +3989,10 @@ igb_setup_receive_ring(struct rx_ring *r bus_dma_segment_t pseg[1], hseg[1]; struct lro_ctrl *lro = &rxr->lro; int rsize, nsegs, error = 0; +#ifdef DEV_NETMAP + struct netmap_adapter *na = NA(rxr->adapter->ifp); + struct netmap_slot *slot; +#endif /* DEV_NETMAP */ adapter = rxr->adapter; dev = adapter->dev; @@ -3956,6 +4000,9 @@ igb_setup_receive_ring(struct rx_ring *r /* Clear the ring contents */ IGB_RX_LOCK(rxr); +#ifdef DEV_NETMAP + slot = netmap_reset(na, NR_RX, rxr->me, 0); +#endif /* DEV_NETMAP */ rsize = roundup2(adapter->num_rx_desc * sizeof(union e1000_adv_rx_desc), IGB_DBA_ALIGN); bzero((void *)rxr->rx_base, rsize); @@ -3974,6 +4021,22 @@ igb_setup_receive_ring(struct rx_ring *r struct mbuf *mh, *mp; rxbuf = &rxr->rx_buffers[j]; +#ifdef DEV_NETMAP + if (slot) { + /* slot sj is mapped to the i-th NIC-ring entry */ + int sj = j + na->rx_rings[rxr->me].nkr_hwofs; + void *addr; + + if (sj < 0) + sj += na->num_rx_desc; + addr = NMB(slot + sj); + netmap_load_map(rxr->ptag, + rxbuf->pmap, addr, na->buff_size); + /* Update descriptor */ + rxr->rx_base[j].read.pkt_addr = htole64(vtophys(addr)); + continue; + } +#endif /* DEV_NETMAP */ if (rxr->hdr_split == FALSE) goto skip_head; @@ -4258,6 +4321,26 @@ igb_initialize_receive_units(struct adap for (int i = 0; i < adapter->num_queues; i++) { rxr = &adapter->rx_rings[i]; E1000_WRITE_REG(hw, E1000_RDH(i), rxr->next_to_check); +#ifdef DEV_NETMAP + /* + * an init() while a netmap client is active must + * preserve the rx buffers passed to userspace. + * In this driver it means we adjust RDT to + * somthing different from next_to_refresh + * (which is not used in netmap mode). + */ + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_kring *kring = &na->rx_rings[i]; + int t = rxr->next_to_refresh - kring->nr_hwavail; + + if (t >= adapter->num_rx_desc) + t -= adapter->num_rx_desc; + else if (t < 0) + t += adapter->num_rx_desc; + E1000_WRITE_REG(hw, E1000_RDT(i), t); + } else +#endif /* DEV_NETMAP */ E1000_WRITE_REG(hw, E1000_RDT(i), rxr->next_to_refresh); } return; @@ -4436,6 +4519,19 @@ igb_rxeof(struct igb_queue *que, int cou bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(ifp); + + 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); + IGB_CORE_UNLOCK(adapter); + return (0); + } +#endif /* DEV_NETMAP */ + /* Main clean loop */ for (i = rxr->next_to_check; count != 0;) { struct mbuf *sendmp, *mh, *mp; Modified: head/sys/dev/e1000/if_lem.c ============================================================================== --- head/sys/dev/e1000/if_lem.c Mon Dec 5 15:21:21 2011 (r228280) +++ head/sys/dev/e1000/if_lem.c Mon Dec 5 15:33:13 2011 (r228281) @@ -316,6 +316,10 @@ TUNABLE_INT("hw.em.fc_setting", &lem_fc_ /* Global used in WOL setup with multiport cards */ static int global_quad_port_a = 0; +#ifdef DEV_NETMAP /* see ixgbe.c for details */ +#include +#endif /* DEV_NETMAP */ + /********************************************************************* * Device identification routine * @@ -646,6 +650,9 @@ lem_attach(device_t dev) adapter->led_dev = led_create(lem_led_func, adapter, device_get_nameunit(dev)); +#ifdef DEV_NETMAP + lem_netmap_attach(adapter); +#endif /* DEV_NETMAP */ INIT_DEBUGOUT("lem_attach: end"); return (0); @@ -724,6 +731,9 @@ lem_detach(device_t dev) callout_drain(&adapter->timer); callout_drain(&adapter->tx_fifo_timer); +#ifdef DEV_NETMAP + netmap_detach(ifp); +#endif /* DEV_NETMAP */ lem_free_pci_resources(adapter); bus_generic_detach(dev); if_free(ifp); @@ -2637,6 +2647,11 @@ static void lem_setup_transmit_structures(struct adapter *adapter) { struct em_buffer *tx_buffer; +#ifdef DEV_NETMAP + /* we are already locked */ + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_slot *slot = netmap_reset(na, NR_TX, 0, 0); +#endif /* DEV_NETMAP */ /* Clear the old ring contents */ bzero(adapter->tx_desc_base, @@ -2650,6 +2665,22 @@ lem_setup_transmit_structures(struct ada bus_dmamap_unload(adapter->txtag, tx_buffer->map); m_freem(tx_buffer->m_head); tx_buffer->m_head = NULL; +#ifdef DEV_NETMAP + if (slot) { + /* slot si is mapped to the i-th NIC-ring entry */ + int si = i + na->tx_rings[0].nkr_hwofs; + void *addr; + + if (si > na->num_tx_desc) + si -= na->num_tx_desc; + addr = NMB(slot + si); + adapter->tx_desc_base[si].buffer_addr = + htole64(vtophys(addr)); + /* reload the map for netmap mode */ + netmap_load_map(adapter->txtag, + tx_buffer->map, addr, na->buff_size); + } +#endif /* DEV_NETMAP */ tx_buffer->next_eop = -1; } @@ -2951,6 +2982,12 @@ lem_txeof(struct adapter *adapter) EM_TX_LOCK_ASSERT(adapter); +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + selwakeuppri(&NA(ifp)->tx_rings[0].si, PI_NET); + return; + } +#endif /* DEV_NETMAP */ if (adapter->num_tx_desc_avail == adapter->num_tx_desc) return; @@ -3181,6 +3218,11 @@ lem_setup_receive_structures(struct adap { struct em_buffer *rx_buffer; int i, error; +#ifdef DEV_NETMAP + /* we are already under lock */ + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_slot *slot = netmap_reset(na, NR_RX, 0, 0); +#endif /* Reset descriptor ring */ bzero(adapter->rx_desc_base, @@ -3200,6 +3242,23 @@ lem_setup_receive_structures(struct adap /* Allocate new ones. */ for (i = 0; i < adapter->num_rx_desc; i++) { +#ifdef DEV_NETMAP + if (slot) { + /* slot si is mapped to the i-th NIC-ring entry */ + int si = i + na->rx_rings[0].nkr_hwofs; + void *addr; + + if (si > na->num_rx_desc) + si -= na->num_rx_desc; + addr = NMB(slot + si); + netmap_load_map(adapter->rxtag, + rx_buffer->map, addr, na->buff_size); + /* Update descriptor */ + adapter->rx_desc_base[i].buffer_addr = + htole64(vtophys(addr)); + continue; + } +#endif /* DEV_NETMAP */ error = lem_get_buf(adapter, i); if (error) return (error); @@ -3324,6 +3383,18 @@ lem_initialize_receive_unit(struct adapt * Tail Descriptor Pointers */ E1000_WRITE_REG(&adapter->hw, E1000_RDH(0), 0); +#ifdef DEV_NETMAP + /* preserve buffers already made available to clients */ + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_adapter *na = NA(adapter->ifp); + struct netmap_kring *kring = &na->rx_rings[0]; + int t = na->num_rx_desc - 1 - kring->nr_hwavail; + + if (t >= na->num_rx_desc) + t -= na->num_rx_desc; + E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), t); + } else +#endif /* DEV_NETMAP */ E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1); return; @@ -3407,6 +3478,14 @@ lem_rxeof(struct adapter *adapter, int c bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, BUS_DMASYNC_POSTREAD); +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + selwakeuppri(&NA(ifp)->rx_rings[0].si, PI_NET); + EM_RX_UNLOCK(adapter); + return (0); + } +#endif /* DEV_NETMAP */ + if (!((current_desc->status) & E1000_RXD_STAT_DD)) { if (done != NULL) *done = rx_sent; Modified: head/sys/dev/re/if_re.c ============================================================================== --- head/sys/dev/re/if_re.c Mon Dec 5 15:21:21 2011 (r228280) +++ head/sys/dev/re/if_re.c Mon Dec 5 15:33:13 2011 (r228281) @@ -296,6 +296,10 @@ static void re_setwol (struct rl_softc static void re_clrwol (struct rl_softc *); static void re_set_linkspeed (struct rl_softc *); +#ifdef DEV_NETMAP /* see ixgbe.c for details */ +#include +#endif /* !DEV_NETMAP */ + #ifdef RE_DIAG static int re_diag (struct rl_softc *); #endif @@ -1620,6 +1624,9 @@ re_attach(device_t dev) */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); +#ifdef DEV_NETMAP + re_netmap_attach(sc); +#endif /* DEV_NETMAP */ #ifdef RE_DIAG /* * Perform hardware diagnostic on the original RTL8169. @@ -1815,6 +1822,9 @@ re_detach(device_t dev) bus_dma_tag_destroy(sc->rl_ldata.rl_stag); } +#ifdef DEV_NETMAP + netmap_detach(ifp); +#endif /* DEV_NETMAP */ if (sc->rl_parent_tag) bus_dma_tag_destroy(sc->rl_parent_tag); @@ -1989,6 +1999,9 @@ re_tx_list_init(struct rl_softc *sc) sc->rl_ldata.rl_tx_desc_cnt * sizeof(struct rl_desc)); for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++) sc->rl_ldata.rl_tx_desc[i].tx_m = NULL; +#ifdef DEV_NETMAP + re_netmap_tx_init(sc); +#endif /* DEV_NETMAP */ /* Set EOR. */ desc = &sc->rl_ldata.rl_tx_list[sc->rl_ldata.rl_tx_desc_cnt - 1]; desc->rl_cmdstat |= htole32(RL_TDESC_CMD_EOR); @@ -2016,6 +2029,9 @@ re_rx_list_init(struct rl_softc *sc) if ((error = re_newbuf(sc, i)) != 0) return (error); } +#ifdef DEV_NETMAP + re_netmap_rx_init(sc); +#endif /* DEV_NETMAP */ /* Flush the RX descriptors */ @@ -2072,6 +2088,12 @@ re_rxeof(struct rl_softc *sc, int *rx_np RL_LOCK_ASSERT(sc); ifp = sc->rl_ifp; +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + selwakeuppri(&NA(ifp)->rx_rings->si, PI_NET); + return 0; + } +#endif /* DEV_NETMAP */ if (ifp->if_mtu > RL_MTU && (sc->rl_flags & RL_FLAG_JUMBOV2) != 0) jumbo = 1; else @@ -2313,6 +2335,12 @@ re_txeof(struct rl_softc *sc) return; ifp = sc->rl_ifp; +#ifdef DEV_NETMAP + if (ifp->if_capenable & IFCAP_NETMAP) { + selwakeuppri(&NA(ifp)->tx_rings[0].si, PI_NET); + return; + } +#endif /* DEV_NETMAP */ /* Invalidate the TX descriptor list */ bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag, sc->rl_ldata.rl_tx_list_map, @@ -2831,6 +2859,21 @@ re_start_locked(struct ifnet *ifp) sc = ifp->if_softc; +#ifdef DEV_NETMAP + /* XXX is this necessary ? */ + if (ifp->if_capenable & IFCAP_NETMAP) { + struct netmap_kring *kring = &NA(ifp)->tx_rings[0]; + if (sc->rl_ldata.rl_tx_prodidx != kring->nr_hwcur) { + /* kick the tx unit */ + CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START); +#ifdef RE_TX_MODERATION + CSR_WRITE_4(sc, RL_TIMERCNT, 1); +#endif + sc->rl_watchdog_timer = 5; + } + return; + } +#endif /* DEV_NETMAP */ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING || (sc->rl_flags & RL_FLAG_LINK) == 0) return;