if_igb_netmap.h revision 231881
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 231881 2012-02-17 14:09:04Z luigi $ 28228276Sluigi * $Id: if_igb_netmap.h 9802 2011-12-02 18:42:37Z luigi $ 29227614Sluigi * 30231778Sluigi * netmap modifications for igb contributed by Ahmed Kooli 31227614Sluigi */ 32227614Sluigi 33227614Sluigi#include <net/netmap.h> 34227614Sluigi#include <sys/selinfo.h> 35227614Sluigi#include <vm/vm.h> 36227614Sluigi#include <vm/pmap.h> /* vtophys ? */ 37227614Sluigi#include <dev/netmap/netmap_kern.h> 38227614Sluigi 39227614Sluigistatic int igb_netmap_reg(struct ifnet *, int onoff); 40231594Sluigistatic int igb_netmap_txsync(struct ifnet *, u_int, int); 41231594Sluigistatic int igb_netmap_rxsync(struct ifnet *, u_int, int); 42231594Sluigistatic void igb_netmap_lock_wrapper(struct ifnet *, int, u_int); 43227614Sluigi 44227614Sluigi 45227614Sluigistatic void 46227614Sluigiigb_netmap_attach(struct adapter *adapter) 47227614Sluigi{ 48227614Sluigi struct netmap_adapter na; 49227614Sluigi 50227614Sluigi bzero(&na, sizeof(na)); 51227614Sluigi 52227614Sluigi na.ifp = adapter->ifp; 53227614Sluigi na.separate_locks = 1; 54227614Sluigi na.num_tx_desc = adapter->num_tx_desc; 55227614Sluigi na.num_rx_desc = adapter->num_rx_desc; 56227614Sluigi na.nm_txsync = igb_netmap_txsync; 57227614Sluigi na.nm_rxsync = igb_netmap_rxsync; 58227614Sluigi na.nm_lock = igb_netmap_lock_wrapper; 59227614Sluigi na.nm_register = igb_netmap_reg; 60227614Sluigi netmap_attach(&na, adapter->num_queues); 61227614Sluigi} 62227614Sluigi 63227614Sluigi 64227614Sluigi/* 65227614Sluigi * wrapper to export locks to the generic code 66227614Sluigi */ 67227614Sluigistatic void 68231594Sluigiigb_netmap_lock_wrapper(struct ifnet *ifp, int what, u_int queueid) 69227614Sluigi{ 70231594Sluigi struct adapter *adapter = ifp->if_softc; 71227614Sluigi 72227614Sluigi ASSERT(queueid < adapter->num_queues); 73227614Sluigi switch (what) { 74227614Sluigi case NETMAP_CORE_LOCK: 75227614Sluigi IGB_CORE_LOCK(adapter); 76227614Sluigi break; 77227614Sluigi case NETMAP_CORE_UNLOCK: 78227614Sluigi IGB_CORE_UNLOCK(adapter); 79227614Sluigi break; 80227614Sluigi case NETMAP_TX_LOCK: 81227614Sluigi IGB_TX_LOCK(&adapter->tx_rings[queueid]); 82227614Sluigi break; 83227614Sluigi case NETMAP_TX_UNLOCK: 84227614Sluigi IGB_TX_UNLOCK(&adapter->tx_rings[queueid]); 85227614Sluigi break; 86227614Sluigi case NETMAP_RX_LOCK: 87227614Sluigi IGB_RX_LOCK(&adapter->rx_rings[queueid]); 88227614Sluigi break; 89227614Sluigi case NETMAP_RX_UNLOCK: 90227614Sluigi IGB_RX_UNLOCK(&adapter->rx_rings[queueid]); 91227614Sluigi break; 92227614Sluigi } 93227614Sluigi} 94227614Sluigi 95227614Sluigi 96227614Sluigi/* 97231778Sluigi * register-unregister routine 98227614Sluigi */ 99227614Sluigistatic int 100227614Sluigiigb_netmap_reg(struct ifnet *ifp, int onoff) 101227614Sluigi{ 102227614Sluigi struct adapter *adapter = ifp->if_softc; 103227614Sluigi struct netmap_adapter *na = NA(ifp); 104227614Sluigi int error = 0; 105227614Sluigi 106228276Sluigi if (na == NULL) 107231778Sluigi return EINVAL; /* no netmap support here */ 108227614Sluigi 109227614Sluigi igb_disable_intr(adapter); 110227614Sluigi 111227614Sluigi /* Tell the stack that the interface is no longer active */ 112227614Sluigi ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 113227614Sluigi 114227614Sluigi if (onoff) { 115227614Sluigi ifp->if_capenable |= IFCAP_NETMAP; 116227614Sluigi 117227614Sluigi na->if_transmit = ifp->if_transmit; 118227614Sluigi ifp->if_transmit = netmap_start; 119227614Sluigi 120227614Sluigi igb_init_locked(adapter); 121227614Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) == 0) { 122227614Sluigi error = ENOMEM; 123227614Sluigi goto fail; 124227614Sluigi } 125227614Sluigi } else { 126227614Sluigifail: 127227614Sluigi /* restore if_transmit */ 128227614Sluigi ifp->if_transmit = na->if_transmit; 129227614Sluigi ifp->if_capenable &= ~IFCAP_NETMAP; 130231778Sluigi igb_init_locked(adapter); /* also enable intr */ 131227614Sluigi } 132227614Sluigi return (error); 133227614Sluigi} 134227614Sluigi 135227614Sluigi 136227614Sluigi/* 137231778Sluigi * Reconcile hardware and user view of the transmit ring. 138227614Sluigi */ 139227614Sluigistatic int 140231594Sluigiigb_netmap_txsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 141227614Sluigi{ 142231594Sluigi struct adapter *adapter = ifp->if_softc; 143227614Sluigi struct tx_ring *txr = &adapter->tx_rings[ring_nr]; 144227614Sluigi struct netmap_adapter *na = NA(adapter->ifp); 145227614Sluigi struct netmap_kring *kring = &na->tx_rings[ring_nr]; 146227614Sluigi struct netmap_ring *ring = kring->ring; 147228276Sluigi int j, k, l, n = 0, lim = kring->nkr_num_slots - 1; 148227614Sluigi 149227614Sluigi /* generate an interrupt approximately every half ring */ 150227614Sluigi int report_frequency = kring->nkr_num_slots >> 1; 151227614Sluigi 152228276Sluigi k = ring->cur; 153228276Sluigi if (k > lim) 154227614Sluigi return netmap_ring_reinit(kring); 155227614Sluigi 156227614Sluigi if (do_lock) 157227614Sluigi IGB_TX_LOCK(txr); 158227614Sluigi bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 159228276Sluigi BUS_DMASYNC_POSTREAD); 160227614Sluigi 161231778Sluigi /* check for new packets to send. 162231778Sluigi * j indexes the netmap ring, l indexes the nic ring, and 163231778Sluigi * j = kring->nr_hwcur, l = E1000_TDT (not tracked), 164231778Sluigi * j == (l + kring->nkr_hwofs) % ring_size 165231778Sluigi */ 166231778Sluigi j = kring->nr_hwcur; 167231778Sluigi if (j != k) { /* we have packets to send */ 168231778Sluigi /* 82575 needs the queue index added */ 169231778Sluigi u32 olinfo_status = 170231778Sluigi (adapter->hw.mac.type == e1000_82575) ? (txr->me << 4) : 0; 171227614Sluigi 172231796Sluigi l = netmap_tidx_k2n(na, ring_nr, j); 173231881Sluigi for (n = 0; j != k; n++) { 174227614Sluigi struct netmap_slot *slot = &ring->slot[j]; 175227614Sluigi union e1000_adv_tx_desc *curr = 176228276Sluigi (union e1000_adv_tx_desc *)&txr->tx_base[l]; 177231778Sluigi struct igb_tx_buffer *txbuf = &txr->tx_buffers[l]; 178227614Sluigi int flags = ((slot->flags & NS_REPORT) || 179227614Sluigi j == 0 || j == report_frequency) ? 180227614Sluigi E1000_ADVTXD_DCMD_RS : 0; 181231778Sluigi uint64_t paddr; 182231778Sluigi void *addr = PNMB(slot, &paddr); 183227614Sluigi int len = slot->len; 184227614Sluigi 185227614Sluigi if (addr == netmap_buffer_base || len > NETMAP_BUF_SIZE) { 186227614Sluigi if (do_lock) 187227614Sluigi IGB_TX_UNLOCK(txr); 188227614Sluigi return netmap_ring_reinit(kring); 189227614Sluigi } 190227614Sluigi 191227614Sluigi slot->flags &= ~NS_REPORT; 192231778Sluigi // XXX set the address unconditionally 193229939Sluigi curr->read.buffer_addr = htole64(paddr); 194227614Sluigi curr->read.olinfo_status = 195227614Sluigi htole32(olinfo_status | 196227614Sluigi (len<< E1000_ADVTXD_PAYLEN_SHIFT)); 197227614Sluigi curr->read.cmd_type_len = 198227614Sluigi htole32(len | E1000_ADVTXD_DTYP_DATA | 199227614Sluigi E1000_ADVTXD_DCMD_IFCS | 200227614Sluigi E1000_ADVTXD_DCMD_DEXT | 201227614Sluigi E1000_ADVTXD_DCMD_EOP | flags); 202227614Sluigi if (slot->flags & NS_BUF_CHANGED) { 203228276Sluigi /* buffer has changed, reload map */ 204229939Sluigi netmap_reload_map(txr->txtag, txbuf->map, addr); 205227614Sluigi slot->flags &= ~NS_BUF_CHANGED; 206227614Sluigi } 207227614Sluigi 208227614Sluigi bus_dmamap_sync(txr->txtag, txbuf->map, 209227614Sluigi BUS_DMASYNC_PREWRITE); 210227614Sluigi j = (j == lim) ? 0 : j + 1; 211228276Sluigi l = (l == lim) ? 0 : l + 1; 212227614Sluigi } 213227614Sluigi kring->nr_hwcur = k; 214227614Sluigi 215227614Sluigi /* decrease avail by number of sent packets */ 216228276Sluigi kring->nr_hwavail -= n; 217227614Sluigi 218228276Sluigi /* Set the watchdog XXX ? */ 219227614Sluigi txr->queue_status = IGB_QUEUE_WORKING; 220227614Sluigi txr->watchdog_time = ticks; 221227614Sluigi 222227614Sluigi bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, 223228276Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 224227614Sluigi 225228276Sluigi E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), l); 226227614Sluigi } 227231778Sluigi 228228276Sluigi if (n == 0 || kring->nr_hwavail < 1) { 229228276Sluigi int delta; 230228276Sluigi 231231778Sluigi /* record completed transmissions using TDH */ 232228276Sluigi l = E1000_READ_REG(&adapter->hw, E1000_TDH(ring_nr)); 233231778Sluigi if (l >= kring->nkr_num_slots) { /* XXX can it happen ? */ 234231778Sluigi D("TDH wrap %d", l); 235228276Sluigi l -= kring->nkr_num_slots; 236231778Sluigi } 237228276Sluigi delta = l - txr->next_to_clean; 238228276Sluigi if (delta) { 239231778Sluigi /* some completed, increment hwavail. */ 240228276Sluigi if (delta < 0) 241228276Sluigi delta += kring->nkr_num_slots; 242228276Sluigi txr->next_to_clean = l; 243228276Sluigi kring->nr_hwavail += delta; 244228276Sluigi } 245228276Sluigi } 246231778Sluigi /* update avail to what the hardware knows */ 247231778Sluigi ring->avail = kring->nr_hwavail; 248231778Sluigi 249227614Sluigi if (do_lock) 250227614Sluigi IGB_TX_UNLOCK(txr); 251227614Sluigi return 0; 252227614Sluigi} 253227614Sluigi 254227614Sluigi 255227614Sluigi/* 256227614Sluigi * Reconcile kernel and user view of the receive ring. 257227614Sluigi */ 258227614Sluigistatic int 259231594Sluigiigb_netmap_rxsync(struct ifnet *ifp, u_int ring_nr, int do_lock) 260227614Sluigi{ 261231594Sluigi struct adapter *adapter = ifp->if_softc; 262227614Sluigi struct rx_ring *rxr = &adapter->rx_rings[ring_nr]; 263227614Sluigi struct netmap_adapter *na = NA(adapter->ifp); 264227614Sluigi struct netmap_kring *kring = &na->rx_rings[ring_nr]; 265227614Sluigi struct netmap_ring *ring = kring->ring; 266228276Sluigi int j, k, l, n, lim = kring->nkr_num_slots - 1; 267227614Sluigi 268228276Sluigi k = ring->cur; 269228276Sluigi if (k > lim) 270227614Sluigi return netmap_ring_reinit(kring); 271227614Sluigi 272227614Sluigi if (do_lock) 273227614Sluigi IGB_RX_LOCK(rxr); 274227614Sluigi 275231778Sluigi /* XXX check sync modes */ 276227614Sluigi bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 277227614Sluigi BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 278227614Sluigi 279231778Sluigi /* import newly received packets into the netmap ring. 280231778Sluigi * j is an index in the netmap ring, l in the NIC ring, and 281231778Sluigi * j = (kring->nr_hwcur + kring->nr_hwavail) % ring_size 282231778Sluigi * l = rxr->next_to_check; 283231778Sluigi * and 284231778Sluigi * j == (l + kring->nkr_hwofs) % ring_size 285231778Sluigi */ 286228276Sluigi l = rxr->next_to_check; 287231796Sluigi j = netmap_ridx_n2k(na, ring_nr, l); 288227614Sluigi for (n = 0; ; n++) { 289228276Sluigi union e1000_adv_rx_desc *curr = &rxr->rx_base[l]; 290227614Sluigi uint32_t staterr = le32toh(curr->wb.upper.status_error); 291227614Sluigi 292227614Sluigi if ((staterr & E1000_RXD_STAT_DD) == 0) 293227614Sluigi break; 294227614Sluigi ring->slot[j].len = le16toh(curr->wb.upper.length); 295227614Sluigi bus_dmamap_sync(rxr->ptag, 296228276Sluigi rxr->rx_buffers[l].pmap, BUS_DMASYNC_POSTREAD); 297227614Sluigi j = (j == lim) ? 0 : j + 1; 298228276Sluigi l = (l == lim) ? 0 : l + 1; 299227614Sluigi } 300227614Sluigi if (n) { 301228276Sluigi rxr->next_to_check = l; 302227614Sluigi kring->nr_hwavail += n; 303227614Sluigi } 304227614Sluigi 305231778Sluigi /* skip past packets that userspace has already processed */ 306227614Sluigi j = kring->nr_hwcur; 307231778Sluigi if (j != k) { /* userspace has read some packets. */ 308231796Sluigi l = netmap_ridx_k2n(na, ring_nr, j); 309231881Sluigi for (n = 0; j != k; n++) { 310227614Sluigi struct netmap_slot *slot = ring->slot + j; 311228276Sluigi union e1000_adv_rx_desc *curr = &rxr->rx_base[l]; 312228276Sluigi struct igb_rx_buf *rxbuf = rxr->rx_buffers + l; 313229939Sluigi uint64_t paddr; 314229939Sluigi void *addr = PNMB(slot, &paddr); 315227614Sluigi 316227614Sluigi if (addr == netmap_buffer_base) { /* bad buf */ 317227614Sluigi if (do_lock) 318227614Sluigi IGB_RX_UNLOCK(rxr); 319227614Sluigi return netmap_ring_reinit(kring); 320227614Sluigi } 321227614Sluigi 322227614Sluigi curr->wb.upper.status_error = 0; 323229939Sluigi curr->read.pkt_addr = htole64(paddr); 324227614Sluigi if (slot->flags & NS_BUF_CHANGED) { 325229939Sluigi netmap_reload_map(rxr->ptag, rxbuf->pmap, addr); 326227614Sluigi slot->flags &= ~NS_BUF_CHANGED; 327227614Sluigi } 328227614Sluigi 329227614Sluigi bus_dmamap_sync(rxr->ptag, rxbuf->pmap, 330227614Sluigi BUS_DMASYNC_PREREAD); 331227614Sluigi 332227614Sluigi j = (j == lim) ? 0 : j + 1; 333228276Sluigi l = (l == lim) ? 0 : l + 1; 334227614Sluigi } 335227614Sluigi kring->nr_hwavail -= n; 336231778Sluigi kring->nr_hwcur = k; 337227614Sluigi bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, 338227614Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 339231778Sluigi /* 340231778Sluigi * IMPORTANT: we must leave one free slot in the ring, 341228276Sluigi * so move l back by one unit 342227614Sluigi */ 343228276Sluigi l = (l == 0) ? lim : l - 1; 344228276Sluigi E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), l); 345227614Sluigi } 346227614Sluigi /* tell userspace that there are new packets */ 347227614Sluigi ring->avail = kring->nr_hwavail ; 348227614Sluigi if (do_lock) 349227614Sluigi IGB_RX_UNLOCK(rxr); 350227614Sluigi return 0; 351227614Sluigi} 352231778Sluigi/* end of file */ 353