if_lem_netmap.h revision 260368
1227614Sluigi/* 2260368Sluigi * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. 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 26232238Sluigi 27227614Sluigi/* 28227614Sluigi * $FreeBSD: head/sys/dev/netmap/if_lem_netmap.h 260368 2014-01-06 12:53:15Z luigi $ 29227614Sluigi * 30259412Sluigi * netmap support for: lem 31228276Sluigi * 32232238Sluigi * For details on netmap support please see ixgbe_netmap.h 33227614Sluigi */ 34227614Sluigi 35259412Sluigi 36227614Sluigi#include <net/netmap.h> 37227614Sluigi#include <sys/selinfo.h> 38227614Sluigi#include <vm/vm.h> 39227614Sluigi#include <vm/pmap.h> /* vtophys ? */ 40227614Sluigi#include <dev/netmap/netmap_kern.h> 41227614Sluigi 42227614Sluigi 43227614Sluigi/* 44259412Sluigi * Register/unregister. We are already under netmap lock. 45227614Sluigi */ 46227614Sluigistatic int 47259412Sluigilem_netmap_reg(struct netmap_adapter *na, int onoff) 48228276Sluigi{ 49259412Sluigi struct ifnet *ifp = na->ifp; 50228276Sluigi struct adapter *adapter = ifp->if_softc; 51228276Sluigi 52257529Sluigi EM_CORE_LOCK(adapter); 53257529Sluigi 54228276Sluigi lem_disable_intr(adapter); 55228276Sluigi 56228276Sluigi /* Tell the stack that the interface is no longer active */ 57228276Sluigi ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 58228276Sluigi 59228276Sluigi#ifndef EM_LEGACY_IRQ // XXX do we need this ? 60228276Sluigi taskqueue_block(adapter->tq); 61228276Sluigi taskqueue_drain(adapter->tq, &adapter->rxtx_task); 62228276Sluigi taskqueue_drain(adapter->tq, &adapter->link_task); 63228276Sluigi#endif /* !EM_LEGCY_IRQ */ 64259412Sluigi 65259412Sluigi /* enable or disable flags and callbacks in na and ifp */ 66228276Sluigi if (onoff) { 67259412Sluigi nm_set_native_flags(na); 68228276Sluigi } else { 69259412Sluigi nm_clear_native_flags(na); 70228276Sluigi } 71259412Sluigi lem_init_locked(adapter); /* also enable intr */ 72228276Sluigi 73228276Sluigi#ifndef EM_LEGACY_IRQ 74228276Sluigi taskqueue_unblock(adapter->tq); // XXX do we need this ? 75228276Sluigi#endif /* !EM_LEGCY_IRQ */ 76228276Sluigi 77257529Sluigi EM_CORE_UNLOCK(adapter); 78257529Sluigi 79259412Sluigi return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); 80228276Sluigi} 81228276Sluigi 82228276Sluigi 83228276Sluigi/* 84232238Sluigi * Reconcile kernel and user view of the transmit ring. 85228276Sluigi */ 86228276Sluigistatic int 87259412Sluigilem_netmap_txsync(struct netmap_adapter *na, u_int ring_nr, int flags) 88227614Sluigi{ 89259412Sluigi struct ifnet *ifp = na->ifp; 90231796Sluigi struct netmap_kring *kring = &na->tx_rings[ring_nr]; 91227614Sluigi struct netmap_ring *ring = kring->ring; 92259412Sluigi u_int nm_i; /* index into the netmap ring */ 93259412Sluigi u_int nic_i; /* index into the NIC ring */ 94259412Sluigi u_int const lim = kring->nkr_num_slots - 1; 95260368Sluigi u_int const head = kring->rhead; 96227614Sluigi /* generate an interrupt approximately every half ring */ 97259412Sluigi u_int report_frequency = kring->nkr_num_slots >> 1; 98227614Sluigi 99259412Sluigi /* device-specific */ 100259412Sluigi struct adapter *adapter = ifp->if_softc; 101259412Sluigi 102227614Sluigi bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, 103227614Sluigi BUS_DMASYNC_POSTREAD); 104259412Sluigi 105232238Sluigi /* 106259412Sluigi * First part: process new packets to send. 107231778Sluigi */ 108259412Sluigi 109259412Sluigi nm_i = kring->nr_hwcur; 110260368Sluigi if (nm_i != head) { /* we have new packets to send */ 111259412Sluigi nic_i = netmap_idx_k2n(kring, nm_i); 112260368Sluigi while (nm_i != head) { 113259412Sluigi struct netmap_slot *slot = &ring->slot[nm_i]; 114259412Sluigi u_int len = slot->len; 115231778Sluigi uint64_t paddr; 116231778Sluigi void *addr = PNMB(slot, &paddr); 117227614Sluigi 118259412Sluigi /* device-specific */ 119259412Sluigi struct e1000_tx_desc *curr = &adapter->tx_desc_base[nic_i]; 120259412Sluigi struct em_buffer *txbuf = &adapter->tx_buffer_area[nic_i]; 121259412Sluigi int flags = (slot->flags & NS_REPORT || 122259412Sluigi nic_i == 0 || nic_i == report_frequency) ? 123259412Sluigi E1000_TXD_CMD_RS : 0; 124227614Sluigi 125259412Sluigi NM_CHECK_ADDR_LEN(addr, len); 126259412Sluigi 127259412Sluigi if (slot->flags & NS_BUF_CHANGED) { 128228276Sluigi /* buffer has changed, reload map */ 129259412Sluigi curr->buffer_addr = htole64(paddr); 130229939Sluigi netmap_reload_map(adapter->txtag, txbuf->map, addr); 131227614Sluigi } 132259412Sluigi slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); 133259412Sluigi 134259412Sluigi /* Fill the slot in the NIC ring. */ 135232238Sluigi curr->upper.data = 0; 136259412Sluigi curr->lower.data = htole32(adapter->txd_cmd | len | 137232238Sluigi (E1000_TXD_CMD_EOP | flags) ); 138259412Sluigi bus_dmamap_sync(adapter->txtag, txbuf->map, 139259412Sluigi BUS_DMASYNC_PREWRITE); 140227614Sluigi 141259412Sluigi nm_i = nm_next(nm_i, lim); 142259412Sluigi nic_i = nm_next(nic_i, lim); 143227614Sluigi } 144260368Sluigi kring->nr_hwcur = head; 145227614Sluigi 146259412Sluigi /* synchronize the NIC ring */ 147227614Sluigi bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, 148259412Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 149227614Sluigi 150259412Sluigi /* (re)start the tx unit up to slot nic_i (excluded) */ 151259412Sluigi E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), nic_i); 152227614Sluigi } 153228276Sluigi 154259412Sluigi /* 155259412Sluigi * Second part: reclaim buffers for completed transmissions. 156259412Sluigi */ 157260368Sluigi if (ticks != kring->last_reclaim || flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) { 158260368Sluigi kring->last_reclaim = ticks; 159228276Sluigi /* record completed transmissions using TDH */ 160259412Sluigi nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(0)); 161259412Sluigi if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */ 162259412Sluigi D("TDH wrap %d", nic_i); 163259412Sluigi nic_i -= kring->nkr_num_slots; 164228276Sluigi } 165260368Sluigi adapter->next_tx_to_clean = nic_i; 166260368Sluigi kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); 167228276Sluigi } 168231198Sluigi 169260368Sluigi nm_txsync_finalize(kring); 170259412Sluigi 171227614Sluigi return 0; 172227614Sluigi} 173227614Sluigi 174227614Sluigi 175227614Sluigi/* 176228276Sluigi * Reconcile kernel and user view of the receive ring. 177227614Sluigi */ 178227614Sluigistatic int 179259412Sluigilem_netmap_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags) 180227614Sluigi{ 181259412Sluigi struct ifnet *ifp = na->ifp; 182231796Sluigi struct netmap_kring *kring = &na->rx_rings[ring_nr]; 183227614Sluigi struct netmap_ring *ring = kring->ring; 184259412Sluigi u_int nm_i; /* index into the netmap ring */ 185259412Sluigi u_int nic_i; /* index into the NIC ring */ 186260368Sluigi u_int n; 187259412Sluigi u_int const lim = kring->nkr_num_slots - 1; 188260368Sluigi u_int const head = nm_rxsync_prologue(kring); 189257529Sluigi int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; 190227614Sluigi 191259412Sluigi /* device-specific */ 192259412Sluigi struct adapter *adapter = ifp->if_softc; 193259412Sluigi 194260368Sluigi if (head > lim) 195227614Sluigi return netmap_ring_reinit(kring); 196227614Sluigi 197227614Sluigi /* XXX check sync modes */ 198227614Sluigi bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, 199227614Sluigi BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 200227614Sluigi 201232238Sluigi /* 202259412Sluigi * First part: import newly received packets. 203231778Sluigi */ 204232238Sluigi if (netmap_no_pendintr || force_update) { 205245579Sluigi uint16_t slot_flags = kring->nkr_slot_flags; 206245579Sluigi 207259412Sluigi nic_i = adapter->next_rx_desc_to_check; 208259412Sluigi nm_i = netmap_idx_n2k(kring, nic_i); 209259412Sluigi 210232238Sluigi for (n = 0; ; n++) { 211259412Sluigi struct e1000_rx_desc *curr = &adapter->rx_desc_base[nic_i]; 212232238Sluigi uint32_t staterr = le32toh(curr->status); 213232238Sluigi int len; 214227614Sluigi 215232238Sluigi if ((staterr & E1000_RXD_STAT_DD) == 0) 216232238Sluigi break; 217232238Sluigi len = le16toh(curr->length) - 4; // CRC 218232238Sluigi if (len < 0) { 219259412Sluigi D("bogus pkt size %d nic idx %d", len, nic_i); 220232238Sluigi len = 0; 221232238Sluigi } 222259412Sluigi ring->slot[nm_i].len = len; 223259412Sluigi ring->slot[nm_i].flags = slot_flags; 224232238Sluigi bus_dmamap_sync(adapter->rxtag, 225259412Sluigi adapter->rx_buffer_area[nic_i].map, 226259412Sluigi BUS_DMASYNC_POSTREAD); 227259412Sluigi nm_i = nm_next(nm_i, lim); 228259412Sluigi nic_i = nm_next(nic_i, lim); 229227614Sluigi } 230232238Sluigi if (n) { /* update the state variables */ 231260368Sluigi ND("%d new packets at nic %d nm %d tail %d", 232260368Sluigi n, 233260368Sluigi adapter->next_rx_desc_to_check, 234260368Sluigi netmap_idx_n2k(kring, adapter->next_rx_desc_to_check), 235260368Sluigi kring->nr_hwtail); 236259412Sluigi adapter->next_rx_desc_to_check = nic_i; 237259412Sluigi // ifp->if_ipackets += n; 238260368Sluigi kring->nr_hwtail = nm_i; 239232238Sluigi } 240232238Sluigi kring->nr_kflags &= ~NKR_PENDINTR; 241227614Sluigi } 242227614Sluigi 243259412Sluigi /* 244259412Sluigi * Second part: skip past packets that userspace has released. 245259412Sluigi */ 246259412Sluigi nm_i = kring->nr_hwcur; 247260368Sluigi if (nm_i != head) { 248259412Sluigi nic_i = netmap_idx_k2n(kring, nm_i); 249260368Sluigi for (n = 0; nm_i != head; n++) { 250259412Sluigi struct netmap_slot *slot = &ring->slot[nm_i]; 251229939Sluigi uint64_t paddr; 252229939Sluigi void *addr = PNMB(slot, &paddr); 253227614Sluigi 254259412Sluigi struct e1000_rx_desc *curr = &adapter->rx_desc_base[nic_i]; 255259412Sluigi struct em_buffer *rxbuf = &adapter->rx_buffer_area[nic_i]; 256231778Sluigi 257259412Sluigi if (addr == netmap_buffer_base) /* bad buf */ 258259412Sluigi goto ring_reset; 259259412Sluigi 260227614Sluigi if (slot->flags & NS_BUF_CHANGED) { 261231796Sluigi /* buffer has changed, reload map */ 262259412Sluigi curr->buffer_addr = htole64(paddr); 263229939Sluigi netmap_reload_map(adapter->rxtag, rxbuf->map, addr); 264227614Sluigi slot->flags &= ~NS_BUF_CHANGED; 265227614Sluigi } 266232238Sluigi curr->status = 0; 267227614Sluigi bus_dmamap_sync(adapter->rxtag, rxbuf->map, 268228276Sluigi BUS_DMASYNC_PREREAD); 269259412Sluigi nm_i = nm_next(nm_i, lim); 270259412Sluigi nic_i = nm_next(nic_i, lim); 271227614Sluigi } 272260368Sluigi kring->nr_hwcur = head; 273227614Sluigi bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, 274228276Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 275227614Sluigi /* 276227614Sluigi * IMPORTANT: we must leave one free slot in the ring, 277259412Sluigi * so move nic_i back by one unit 278227614Sluigi */ 279260368Sluigi nic_i = nm_prev(nic_i, lim); 280259412Sluigi E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), nic_i); 281227614Sluigi } 282259412Sluigi 283259412Sluigi /* tell userspace that there might be new packets */ 284260368Sluigi nm_rxsync_finalize(kring); 285259412Sluigi 286227614Sluigi return 0; 287259412Sluigi 288259412Sluigiring_reset: 289259412Sluigi return netmap_ring_reinit(kring); 290227614Sluigi} 291232238Sluigi 292232238Sluigi 293232238Sluigistatic void 294232238Sluigilem_netmap_attach(struct adapter *adapter) 295232238Sluigi{ 296232238Sluigi struct netmap_adapter na; 297232238Sluigi 298232238Sluigi bzero(&na, sizeof(na)); 299232238Sluigi 300232238Sluigi na.ifp = adapter->ifp; 301257529Sluigi na.na_flags = NAF_BDG_MAYSLEEP; 302232238Sluigi na.num_tx_desc = adapter->num_tx_desc; 303232238Sluigi na.num_rx_desc = adapter->num_rx_desc; 304232238Sluigi na.nm_txsync = lem_netmap_txsync; 305232238Sluigi na.nm_rxsync = lem_netmap_rxsync; 306232238Sluigi na.nm_register = lem_netmap_reg; 307259412Sluigi na.num_tx_rings = na.num_rx_rings = 1; 308259412Sluigi netmap_attach(&na); 309232238Sluigi} 310232238Sluigi 311231198Sluigi/* end of file */ 312