if_igb_netmap.h revision 238985
1227614Sluigi/* 2227614Sluigi * Copyright (C) 2011 Universita` di Pisa. All rights reserved. 3227614Sluigi * 4227614Sluigi * Redistribution and use in source and binary forms, with or without 5227614Sluigi * modification, are permitted provided that the following conditions 6227614Sluigi * are met: 7227614Sluigi * 1. Redistributions of source code must retain the above copyright 8227614Sluigi * notice, this list of conditions and the following disclaimer. 9227614Sluigi * 2. Redistributions in binary form must reproduce the above copyright 10227614Sluigi * notice, this list of conditions and the following disclaimer in the 11227614Sluigi * documentation and/or other materials provided with the distribution. 12227614Sluigi * 13227614Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14227614Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15227614Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16227614Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17227614Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18227614Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19227614Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20227614Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21227614Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22227614Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23227614Sluigi * SUCH DAMAGE. 24227614Sluigi */ 25227614Sluigi 26227614Sluigi/* 27227614Sluigi * $FreeBSD: head/sys/dev/netmap/if_igb_netmap.h 238985 2012-08-02 11:59:43Z luigi $ 28232238Sluigi * $Id: if_igb_netmap.h 10627 2012-02-23 19:37:15Z luigi $ 29227614Sluigi * 30232238Sluigi * Netmap support for igb, partly contributed by Ahmed Kooli 31232238Sluigi * For details on netmap support please see ixgbe_netmap.h 32227614Sluigi */ 33227614Sluigi 34232238Sluigi 35227614Sluigi#include <net/netmap.h> 36227614Sluigi#include <sys/selinfo.h> 37227614Sluigi#include <vm/vm.h> 38227614Sluigi#include <vm/pmap.h> /* vtophys ? */ 39227614Sluigi#include <dev/netmap/netmap_kern.h> 40227614Sluigi 41227614Sluigi 42227614Sluigi/* 43227614Sluigi * wrapper to export locks to the generic code 44227614Sluigi */ 45227614Sluigistatic void 46231594Sluigiigb_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int queueid) 47227614Sluigi{ 48231594Sluigi struct adapter *adapter = ifp->if_softc; 49227614Sluigi 50227614Sluigi ASSERT(queueid < adapter->num_queues); 51227614Sluigi switch (what) { 52227614Sluigi case NETMAP_CORE_LOCK: 53227614Sluigi IGB_CORE_LOCK(adapter); 54227614Sluigi break; 55227614Sluigi case NETMAP_CORE_UNLOCK: 56227614Sluigi IGB_CORE_UNLOCK(adapter); 57227614Sluigi break; 58227614Sluigi case NETMAP_TX_LOCK: 59227614Sluigi IGB_TX_LOCK(&adapter->tx_rings[queueid]); 60227614Sluigi break; 61227614Sluigi case NETMAP_TX_UNLOCK: 62227614Sluigi IGB_TX_UNLOCK(&adapter->tx_rings[queueid]); 63227614Sluigi break; 64227614Sluigi case NETMAP_RX_LOCK: 65227614Sluigi IGB_RX_LOCK(&adapter->rx_rings[queueid]); 66227614Sluigi break; 67227614Sluigi case NETMAP_RX_UNLOCK: 68227614Sluigi IGB_RX_UNLOCK(&adapter->rx_rings[queueid]); 69227614Sluigi break; 70227614Sluigi } 71227614Sluigi} 72227614Sluigi 73227614Sluigi 74227614Sluigi/* 75231778Sluigi * register-unregister routine 76227614Sluigi */ 77227614Sluigistatic int 78227614Sluigiigb_netmap_reg(struct ifnet *ifp, int onoff) 79227614Sluigi{ 80227614Sluigi struct adapter *adapter = ifp->if_softc; 81227614Sluigi struct netmap_adapter *na = NA(ifp); 82227614Sluigi int error = 0; 83227614Sluigi 84228276Sluigi if (na == NULL) 85231778Sluigi return EINVAL; /* no netmap support here */ 86227614Sluigi 87227614Sluigi igb_disable_intr(adapter); 88227614Sluigi 89227614Sluigi /* Tell the stack that the interface is no longer active */ 90227614Sluigi ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 91227614Sluigi 92227614Sluigi if (onoff) { 93227614Sluigi ifp->if_capenable |= IFCAP_NETMAP; 94227614Sluigi 95227614Sluigi na->if_transmit = ifp->if_transmit; 96227614Sluigi ifp->if_transmit = netmap_start; 97227614Sluigi 98227614Sluigi igb_init_locked(adapter); 99227614Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) == 0) { 100227614Sluigi error = ENOMEM; 101227614Sluigi goto fail; 102227614Sluigi } 103227614Sluigi } else { 104227614Sluigifail: 105227614Sluigi /* restore if_transmit */ 106227614Sluigi ifp->if_transmit = na->if_transmit; 107227614Sluigi ifp->if_capenable &= ~IFCAP_NETMAP; 108231778Sluigi igb_init_locked(adapter); /* also enable intr */ 109227614Sluigi } 110227614Sluigi return (error); 111227614Sluigi} 112227614Sluigi 113227614Sluigi 114227614Sluigi/* 115232238Sluigi * Reconcile kernel and user view of the transmit ring. 116227614Sluigi */ 117227614Sluigistatic int 118231594Sluigiigb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 119227614Sluigi{ 120231594Sluigi struct adapter *adapter = ifp->if_softc; 121227614Sluigi struct tx_ring *txr = &adapter->tx_rings[ring_nr]; 122232238Sluigi struct netmap_adapter *na = NA(ifp); 123227614Sluigi struct netmap_kring *kring = &na->tx_rings[ring_nr]; 124227614Sluigi struct netmap_ring *ring = kring->ring; 125232238Sluigi u_int j, k, l, n = 0, lim = kring->nkr_num_slots - 1; 126227614Sluigi 127227614Sluigi /* generate an interrupt approximately every half ring */ 128238985Sluigi u_int report_frequency = kring->nkr_num_slots >> 1; 129227614Sluigi 130228276Sluigi k = ring->cur; 131228276Sluigi if (k > lim) 132227614Sluigi return netmap_ring_reinit(kring); 133227614Sluigi 134227614Sluigi if (do_lock) 135227614Sluigi IGB_TX_LOCK(txr); 136227614Sluigi bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 137228276Sluigi BUS_DMASYNC_POSTREAD); 138227614Sluigi 139231778Sluigi /* check for new packets to send. 140231778Sluigi * j indexes the netmap ring, l indexes the nic ring, and 141231778Sluigi * j = kring->nr_hwcur, l = E1000_TDT (not tracked), 142231778Sluigi * j == (l + kring->nkr_hwofs) % ring_size 143231778Sluigi */ 144231778Sluigi j = kring->nr_hwcur; 145232238Sluigi if (j != k) { /* we have new packets to send */ 146231778Sluigi /* 82575 needs the queue index added */ 147231778Sluigi u32 olinfo_status = 148231778Sluigi (adapter->hw.mac.type == e1000_82575) ? (txr->me << 4) : 0; 149227614Sluigi 150232238Sluigi l = netmap_idx_k2n(kring, j); 151231881Sluigi for (n = 0; j != k; n++) { 152232238Sluigi /* slot is the current slot in the netmap ring */ 153227614Sluigi struct netmap_slot *slot = &ring->slot[j]; 154232238Sluigi /* curr is the current slot in the nic ring */ 155227614Sluigi union e1000_adv_tx_desc *curr = 156228276Sluigi (union e1000_adv_tx_desc *)&txr->tx_base[l]; 157231778Sluigi struct igb_tx_buffer *txbuf = &txr->tx_buffers[l]; 158227614Sluigi int flags = ((slot->flags & NS_REPORT) || 159227614Sluigi j == 0 || j == report_frequency) ? 160227614Sluigi E1000_ADVTXD_DCMD_RS : 0; 161231778Sluigi uint64_t paddr; 162231778Sluigi void *addr = PNMB(slot, &paddr); 163232238Sluigi u_int len = slot->len; 164227614Sluigi 165227614Sluigi if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) { 166227614Sluigi if (do_lock) 167227614Sluigi IGB_TX_UNLOCK(txr); 168227614Sluigi return netmap_ring_reinit(kring); 169227614Sluigi } 170227614Sluigi 171227614Sluigi slot->flags &= ~NS_REPORT; 172232238Sluigi if (slot->flags & NS_BUF_CHANGED) { 173232238Sluigi /* buffer has changed, reload map */ 174232238Sluigi netmap_reload_map(txr->txtag, txbuf->map, addr); 175232238Sluigi slot->flags &= ~NS_BUF_CHANGED; 176232238Sluigi } 177229939Sluigi curr->read.buffer_addr = htole64(paddr); 178232238Sluigi // XXX check olinfo and cmd_type_len 179227614Sluigi curr->read.olinfo_status = 180227614Sluigi htole32(olinfo_status | 181227614Sluigi (len<< E1000_ADVTXD_PAYLEN_SHIFT)); 182227614Sluigi curr->read.cmd_type_len = 183227614Sluigi htole32(len | E1000_ADVTXD_DTYP_DATA | 184227614Sluigi E1000_ADVTXD_DCMD_IFCS | 185227614Sluigi E1000_ADVTXD_DCMD_DEXT | 186227614Sluigi E1000_ADVTXD_DCMD_EOP | flags); 187227614Sluigi 188227614Sluigi bus_dmamap_sync(txr->txtag, txbuf->map, 189227614Sluigi BUS_DMASYNC_PREWRITE); 190227614Sluigi j = (j == lim) ? 0 : j + 1; 191228276Sluigi l = (l == lim) ? 0 : l + 1; 192227614Sluigi } 193232238Sluigi kring->nr_hwcur = k; /* the saved ring->cur */ 194228276Sluigi kring->nr_hwavail -= n; 195227614Sluigi 196228276Sluigi /* Set the watchdog XXX ? */ 197227614Sluigi txr->queue_status = IGB_QUEUE_WORKING; 198227614Sluigi txr->watchdog_time = ticks; 199227614Sluigi 200227614Sluigi bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 201228276Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 202227614Sluigi 203228276Sluigi E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), l); 204227614Sluigi } 205231778Sluigi 206228276Sluigi if (n == 0 || kring->nr_hwavail < 1) { 207228276Sluigi int delta; 208228276Sluigi 209231778Sluigi /* record completed transmissions using TDH */ 210228276Sluigi l = E1000_READ_REG(&adapter->hw, E1000_TDH(ring_nr)); 211231778Sluigi if (l >= kring->nkr_num_slots) { /* XXX can it happen ? */ 212231778Sluigi D("TDH wrap %d", l); 213228276Sluigi l -= kring->nkr_num_slots; 214231778Sluigi } 215228276Sluigi delta = l - txr->next_to_clean; 216228276Sluigi if (delta) { 217231778Sluigi /* some completed, increment hwavail. */ 218228276Sluigi if (delta < 0) 219228276Sluigi delta += kring->nkr_num_slots; 220228276Sluigi txr->next_to_clean = l; 221228276Sluigi kring->nr_hwavail += delta; 222228276Sluigi } 223228276Sluigi } 224232238Sluigi /* update avail to what the kernel knows */ 225231778Sluigi ring->avail = kring->nr_hwavail; 226231778Sluigi 227227614Sluigi if (do_lock) 228227614Sluigi IGB_TX_UNLOCK(txr); 229227614Sluigi return 0; 230227614Sluigi} 231227614Sluigi 232227614Sluigi 233227614Sluigi/* 234227614Sluigi * Reconcile kernel and user view of the receive ring. 235227614Sluigi */ 236227614Sluigistatic int 237231594Sluigiigb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 238227614Sluigi{ 239231594Sluigi struct adapter *adapter = ifp->if_softc; 240227614Sluigi struct rx_ring *rxr = &adapter->rx_rings[ring_nr]; 241232238Sluigi struct netmap_adapter *na = NA(ifp); 242227614Sluigi struct netmap_kring *kring = &na->rx_rings[ring_nr]; 243227614Sluigi struct netmap_ring *ring = kring->ring; 244232238Sluigi u_int j, l, n, lim = kring->nkr_num_slots - 1; 245232238Sluigi int force_update = do_lock || kring->nr_kflags & NKR_PENDINTR; 246232238Sluigi u_int k = ring->cur, resvd = ring->reserved; 247227614Sluigi 248228276Sluigi k = ring->cur; 249228276Sluigi if (k > lim) 250227614Sluigi return netmap_ring_reinit(kring); 251227614Sluigi 252227614Sluigi if (do_lock) 253227614Sluigi IGB_RX_LOCK(rxr); 254227614Sluigi 255231778Sluigi /* XXX check sync modes */ 256227614Sluigi bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 257227614Sluigi BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 258227614Sluigi 259232238Sluigi /* 260232238Sluigi * import newly received packets into the netmap ring. 261232238Sluigi * j is an index in the netmap ring, l in the NIC ring. 262231778Sluigi */ 263228276Sluigi l = rxr->next_to_check; 264232238Sluigi j = netmap_idx_n2k(kring, l); 265232238Sluigi if (netmap_no_pendintr || force_update) { 266232238Sluigi for (n = 0; ; n++) { 267232238Sluigi union e1000_adv_rx_desc *curr = &rxr->rx_base[l]; 268232238Sluigi uint32_t staterr = le32toh(curr->wb.upper.status_error); 269227614Sluigi 270232238Sluigi if ((staterr & E1000_RXD_STAT_DD) == 0) 271232238Sluigi break; 272232238Sluigi ring->slot[j].len = le16toh(curr->wb.upper.length); 273232238Sluigi bus_dmamap_sync(rxr->ptag, 274232238Sluigi rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD); 275232238Sluigi j = (j == lim) ? 0 : j + 1; 276232238Sluigi l = (l == lim) ? 0 : l + 1; 277232238Sluigi } 278232238Sluigi if (n) { /* update the state variables */ 279232238Sluigi rxr->next_to_check = l; 280232238Sluigi kring->nr_hwavail += n; 281232238Sluigi } 282232238Sluigi kring->nr_kflags &= ~NKR_PENDINTR; 283227614Sluigi } 284232238Sluigi 285232238Sluigi /* skip past packets that userspace has released */ 286232238Sluigi j = kring->nr_hwcur; /* netmap ring index */ 287232238Sluigi if (resvd > 0) { 288232238Sluigi if (resvd + ring->avail >= lim + 1) { 289232238Sluigi D("XXX invalid reserve/avail %d %d", resvd, ring->avail); 290232238Sluigi ring->reserved = resvd = 0; // XXX panic... 291232238Sluigi } 292232238Sluigi k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd; 293227614Sluigi } 294232238Sluigi if (j != k) { /* userspace has released some packets. */ 295232238Sluigi l = netmap_idx_k2n(kring, j); 296231881Sluigi for (n = 0; j != k; n++) { 297227614Sluigi struct netmap_slot *slot = ring->slot + j; 298228276Sluigi union e1000_adv_rx_desc *curr = &rxr->rx_base[l]; 299228276Sluigi struct igb_rx_buf *rxbuf = rxr->rx_buffers + l; 300229939Sluigi uint64_t paddr; 301229939Sluigi void *addr = PNMB(slot, &paddr); 302227614Sluigi 303227614Sluigi if (addr == netmap_buffer_base) { /* bad buf */ 304227614Sluigi if (do_lock) 305227614Sluigi IGB_RX_UNLOCK(rxr); 306227614Sluigi return netmap_ring_reinit(kring); 307227614Sluigi } 308227614Sluigi 309227614Sluigi if (slot->flags & NS_BUF_CHANGED) { 310229939Sluigi netmap_reload_map(rxr->ptag, rxbuf->pmap, addr); 311227614Sluigi slot->flags &= ~NS_BUF_CHANGED; 312227614Sluigi } 313232238Sluigi curr->read.pkt_addr = htole64(paddr); 314232238Sluigi curr->wb.upper.status_error = 0; 315227614Sluigi bus_dmamap_sync(rxr->ptag, rxbuf->pmap, 316227614Sluigi BUS_DMASYNC_PREREAD); 317227614Sluigi j = (j == lim) ? 0 : j + 1; 318228276Sluigi l = (l == lim) ? 0 : l + 1; 319227614Sluigi } 320227614Sluigi kring->nr_hwavail -= n; 321231778Sluigi kring->nr_hwcur = k; 322227614Sluigi bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 323227614Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 324231778Sluigi /* 325231778Sluigi * IMPORTANT: we must leave one free slot in the ring, 326228276Sluigi * so move l back by one unit 327227614Sluigi */ 328228276Sluigi l = (l == 0) ? lim : l - 1; 329228276Sluigi E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), l); 330227614Sluigi } 331227614Sluigi /* tell userspace that there are new packets */ 332232238Sluigi ring->avail = kring->nr_hwavail - resvd; 333227614Sluigi if (do_lock) 334227614Sluigi IGB_RX_UNLOCK(rxr); 335227614Sluigi return 0; 336227614Sluigi} 337232238Sluigi 338232238Sluigi 339232238Sluigistatic void 340232238Sluigiigb_netmap_attach(struct adapter *adapter) 341232238Sluigi{ 342232238Sluigi struct netmap_adapter na; 343232238Sluigi 344232238Sluigi bzero(&na, sizeof(na)); 345232238Sluigi 346232238Sluigi na.ifp = adapter->ifp; 347232238Sluigi na.separate_locks = 1; 348232238Sluigi na.num_tx_desc = adapter->num_tx_desc; 349232238Sluigi na.num_rx_desc = adapter->num_rx_desc; 350232238Sluigi na.nm_txsync = igb_netmap_txsync; 351232238Sluigi na.nm_rxsync = igb_netmap_rxsync; 352232238Sluigi na.nm_lock = igb_netmap_lock_wrapper; 353232238Sluigi na.nm_register = igb_netmap_reg; 354232238Sluigi netmap_attach(&na, adapter->num_queues); 355232238Sluigi} 356231778Sluigi/* end of file */ 357