1227614Sluigi/* 2262151Sluigi * 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$ 29227614Sluigi * 30262151Sluigi * netmap support for: lem 31228276Sluigi * 32232238Sluigi * For details on netmap support please see ixgbe_netmap.h 33227614Sluigi */ 34227614Sluigi 35262151Sluigi 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 42270252Sluigiextern int netmap_adaptive_io; 43227614Sluigi 44227614Sluigi/* 45262151Sluigi * Register/unregister. We are already under netmap lock. 46227614Sluigi */ 47227614Sluigistatic int 48262151Sluigilem_netmap_reg(struct netmap_adapter *na, int onoff) 49228276Sluigi{ 50262151Sluigi struct ifnet *ifp = na->ifp; 51228276Sluigi struct adapter *adapter = ifp->if_softc; 52228276Sluigi 53262151Sluigi EM_CORE_LOCK(adapter); 54228276Sluigi 55228276Sluigi lem_disable_intr(adapter); 56228276Sluigi 57228276Sluigi /* Tell the stack that the interface is no longer active */ 58228276Sluigi ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 59228276Sluigi 60228276Sluigi#ifndef EM_LEGACY_IRQ // XXX do we need this ? 61228276Sluigi taskqueue_block(adapter->tq); 62228276Sluigi taskqueue_drain(adapter->tq, &adapter->rxtx_task); 63228276Sluigi taskqueue_drain(adapter->tq, &adapter->link_task); 64228276Sluigi#endif /* !EM_LEGCY_IRQ */ 65262151Sluigi 66262151Sluigi /* enable or disable flags and callbacks in na and ifp */ 67228276Sluigi if (onoff) { 68262151Sluigi nm_set_native_flags(na); 69228276Sluigi } else { 70262151Sluigi nm_clear_native_flags(na); 71228276Sluigi } 72262151Sluigi lem_init_locked(adapter); /* also enable intr */ 73228276Sluigi 74228276Sluigi#ifndef EM_LEGACY_IRQ 75228276Sluigi taskqueue_unblock(adapter->tq); // XXX do we need this ? 76228276Sluigi#endif /* !EM_LEGCY_IRQ */ 77228276Sluigi 78262151Sluigi EM_CORE_UNLOCK(adapter); 79262151Sluigi 80262151Sluigi return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); 81228276Sluigi} 82228276Sluigi 83228276Sluigi 84228276Sluigi/* 85232238Sluigi * Reconcile kernel and user view of the transmit ring. 86228276Sluigi */ 87228276Sluigistatic int 88270252Sluigilem_netmap_txsync(struct netmap_kring *kring, int flags) 89227614Sluigi{ 90270252Sluigi struct netmap_adapter *na = kring->na; 91262151Sluigi struct ifnet *ifp = na->ifp; 92227614Sluigi struct netmap_ring *ring = kring->ring; 93262151Sluigi u_int nm_i; /* index into the netmap ring */ 94262151Sluigi u_int nic_i; /* index into the NIC ring */ 95262151Sluigi u_int const lim = kring->nkr_num_slots - 1; 96262151Sluigi u_int const head = kring->rhead; 97227614Sluigi /* generate an interrupt approximately every half ring */ 98262151Sluigi u_int report_frequency = kring->nkr_num_slots >> 1; 99227614Sluigi 100262151Sluigi /* device-specific */ 101262151Sluigi struct adapter *adapter = ifp->if_softc; 102270252Sluigi#ifdef NIC_PARAVIRT 103270252Sluigi struct paravirt_csb *csb = adapter->csb; 104270252Sluigi uint64_t *csbd = (uint64_t *)(csb + 1); 105270252Sluigi#endif /* NIC_PARAVIRT */ 106227614Sluigi 107227614Sluigi bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, 108227614Sluigi BUS_DMASYNC_POSTREAD); 109262151Sluigi 110232238Sluigi /* 111262151Sluigi * First part: process new packets to send. 112231778Sluigi */ 113262151Sluigi 114262151Sluigi nm_i = kring->nr_hwcur; 115262151Sluigi if (nm_i != head) { /* we have new packets to send */ 116270252Sluigi#ifdef NIC_PARAVIRT 117270252Sluigi int do_kick = 0; 118270252Sluigi uint64_t t = 0; // timestamp 119270252Sluigi int n = head - nm_i; 120270252Sluigi if (n < 0) 121270252Sluigi n += lim + 1; 122270252Sluigi if (csb) { 123270252Sluigi t = rdtsc(); /* last timestamp */ 124270252Sluigi csbd[16] += t - csbd[0]; /* total Wg */ 125270252Sluigi csbd[17] += n; /* Wg count */ 126270252Sluigi csbd[0] = t; 127270252Sluigi } 128270252Sluigi#endif /* NIC_PARAVIRT */ 129262151Sluigi nic_i = netmap_idx_k2n(kring, nm_i); 130262151Sluigi while (nm_i != head) { 131262151Sluigi struct netmap_slot *slot = &ring->slot[nm_i]; 132262151Sluigi u_int len = slot->len; 133231778Sluigi uint64_t paddr; 134270252Sluigi void *addr = PNMB(na, slot, &paddr); 135227614Sluigi 136262151Sluigi /* device-specific */ 137262151Sluigi struct e1000_tx_desc *curr = &adapter->tx_desc_base[nic_i]; 138262151Sluigi struct em_buffer *txbuf = &adapter->tx_buffer_area[nic_i]; 139262151Sluigi int flags = (slot->flags & NS_REPORT || 140262151Sluigi nic_i == 0 || nic_i == report_frequency) ? 141262151Sluigi E1000_TXD_CMD_RS : 0; 142227614Sluigi 143270252Sluigi NM_CHECK_ADDR_LEN(na, addr, len); 144262151Sluigi 145227614Sluigi if (slot->flags & NS_BUF_CHANGED) { 146228276Sluigi /* buffer has changed, reload map */ 147262151Sluigi curr->buffer_addr = htole64(paddr); 148270252Sluigi netmap_reload_map(na, adapter->txtag, txbuf->map, addr); 149227614Sluigi } 150262151Sluigi slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); 151262151Sluigi 152262151Sluigi /* Fill the slot in the NIC ring. */ 153232238Sluigi curr->upper.data = 0; 154262151Sluigi curr->lower.data = htole32(adapter->txd_cmd | len | 155232238Sluigi (E1000_TXD_CMD_EOP | flags) ); 156262151Sluigi bus_dmamap_sync(adapter->txtag, txbuf->map, 157262151Sluigi BUS_DMASYNC_PREWRITE); 158227614Sluigi 159262151Sluigi nm_i = nm_next(nm_i, lim); 160262151Sluigi nic_i = nm_next(nic_i, lim); 161270252Sluigi // XXX might try an early kick 162227614Sluigi } 163262151Sluigi kring->nr_hwcur = head; 164227614Sluigi 165262151Sluigi /* synchronize the NIC ring */ 166227614Sluigi bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, 167262151Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 168227614Sluigi 169270252Sluigi#ifdef NIC_PARAVIRT 170270252Sluigi /* set unconditionally, then also kick if needed */ 171270252Sluigi if (csb) { 172270252Sluigi t = rdtsc(); 173270252Sluigi if (csb->host_need_txkick == 2) { 174270252Sluigi /* can compute an update of delta */ 175270252Sluigi int64_t delta = t - csbd[3]; 176270252Sluigi if (delta < 0) 177270252Sluigi delta = -delta; 178270252Sluigi if (csbd[8] == 0 || delta < csbd[8]) { 179270252Sluigi csbd[8] = delta; 180270252Sluigi csbd[9]++; 181270252Sluigi } 182270252Sluigi csbd[10]++; 183270252Sluigi } 184270252Sluigi csb->guest_tdt = nic_i; 185270252Sluigi csbd[18] += t - csbd[0]; // total wp 186270252Sluigi csbd[19] += n; 187270252Sluigi } 188270252Sluigi if (!csb || !csb->guest_csb_on || (csb->host_need_txkick & 1)) 189270252Sluigi do_kick = 1; 190270252Sluigi if (do_kick) 191270252Sluigi#endif /* NIC_PARAVIRT */ 192262151Sluigi /* (re)start the tx unit up to slot nic_i (excluded) */ 193262151Sluigi E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), nic_i); 194270252Sluigi#ifdef NIC_PARAVIRT 195270252Sluigi if (do_kick) { 196270252Sluigi uint64_t t1 = rdtsc(); 197270252Sluigi csbd[20] += t1 - t; // total Np 198270252Sluigi csbd[21]++; 199270252Sluigi } 200270252Sluigi#endif /* NIC_PARAVIRT */ 201227614Sluigi } 202228276Sluigi 203262151Sluigi /* 204262151Sluigi * Second part: reclaim buffers for completed transmissions. 205262151Sluigi */ 206262151Sluigi if (ticks != kring->last_reclaim || flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) { 207262151Sluigi kring->last_reclaim = ticks; 208228276Sluigi /* record completed transmissions using TDH */ 209270252Sluigi#ifdef NIC_PARAVIRT 210270252Sluigi /* host updates tdh unconditionally, and we have 211270252Sluigi * no side effects on reads, so we can read from there 212270252Sluigi * instead of exiting. 213270252Sluigi */ 214270252Sluigi if (csb) { 215270252Sluigi static int drain = 0, nodrain=0, good = 0, bad = 0, fail = 0; 216270252Sluigi u_int x = adapter->next_tx_to_clean; 217270252Sluigi csbd[19]++; // XXX count reclaims 218270252Sluigi nic_i = csb->host_tdh; 219270252Sluigi if (csb->guest_csb_on) { 220270252Sluigi if (nic_i == x) { 221270252Sluigi bad++; 222270252Sluigi csbd[24]++; // failed reclaims 223270252Sluigi /* no progress, request kick and retry */ 224270252Sluigi csb->guest_need_txkick = 1; 225270252Sluigi mb(); // XXX barrier 226270252Sluigi nic_i = csb->host_tdh; 227270252Sluigi } else { 228270252Sluigi good++; 229270252Sluigi } 230270252Sluigi if (nic_i != x) { 231270252Sluigi csb->guest_need_txkick = 2; 232270252Sluigi if (nic_i == csb->guest_tdt) 233270252Sluigi drain++; 234270252Sluigi else 235270252Sluigi nodrain++; 236270252Sluigi#if 1 237270252Sluigi if (netmap_adaptive_io) { 238270252Sluigi /* new mechanism: last half ring (or so) 239270252Sluigi * released one slot at a time. 240270252Sluigi * This effectively makes the system spin. 241270252Sluigi * 242270252Sluigi * Take next_to_clean + 1 as a reference. 243270252Sluigi * tdh must be ahead or equal 244270252Sluigi * On entry, the logical order is 245270252Sluigi * x < tdh = nic_i 246270252Sluigi * We first push tdh up to avoid wraps. 247270252Sluigi * The limit is tdh-ll (half ring). 248270252Sluigi * if tdh-256 < x we report x; 249270252Sluigi * else we report tdh-256 250270252Sluigi */ 251270252Sluigi u_int tdh = nic_i; 252270252Sluigi u_int ll = csbd[15]; 253270252Sluigi u_int delta = lim/8; 254270252Sluigi if (netmap_adaptive_io == 2 || ll > delta) 255270252Sluigi csbd[15] = ll = delta; 256270252Sluigi else if (netmap_adaptive_io == 1 && ll > 1) { 257270252Sluigi csbd[15]--; 258270252Sluigi } 259270252Sluigi 260270252Sluigi if (nic_i >= kring->nkr_num_slots) { 261270252Sluigi RD(5, "bad nic_i %d on input", nic_i); 262270252Sluigi } 263270252Sluigi x = nm_next(x, lim); 264270252Sluigi if (tdh < x) 265270252Sluigi tdh += lim + 1; 266270252Sluigi if (tdh <= x + ll) { 267270252Sluigi nic_i = x; 268270252Sluigi csbd[25]++; //report n + 1; 269270252Sluigi } else { 270270252Sluigi tdh = nic_i; 271270252Sluigi if (tdh < ll) 272270252Sluigi tdh += lim + 1; 273270252Sluigi nic_i = tdh - ll; 274270252Sluigi csbd[26]++; // report tdh - ll 275270252Sluigi } 276270252Sluigi } 277270252Sluigi#endif 278270252Sluigi } else { 279270252Sluigi /* we stop, count whether we are idle or not */ 280270252Sluigi int bh_active = csb->host_need_txkick & 2 ? 4 : 0; 281270252Sluigi csbd[27+ csb->host_need_txkick]++; 282270252Sluigi if (netmap_adaptive_io == 1) { 283270252Sluigi if (bh_active && csbd[15] > 1) 284270252Sluigi csbd[15]--; 285270252Sluigi else if (!bh_active && csbd[15] < lim/2) 286270252Sluigi csbd[15]++; 287270252Sluigi } 288270252Sluigi bad--; 289270252Sluigi fail++; 290270252Sluigi } 291270252Sluigi } 292270252Sluigi RD(1, "drain %d nodrain %d good %d retry %d fail %d", 293270252Sluigi drain, nodrain, good, bad, fail); 294270252Sluigi } else 295270252Sluigi#endif /* !NIC_PARAVIRT */ 296262151Sluigi nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(0)); 297262151Sluigi if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */ 298262151Sluigi D("TDH wrap %d", nic_i); 299262151Sluigi nic_i -= kring->nkr_num_slots; 300228276Sluigi } 301262151Sluigi adapter->next_tx_to_clean = nic_i; 302262151Sluigi kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); 303228276Sluigi } 304231198Sluigi 305262151Sluigi nm_txsync_finalize(kring); 306262151Sluigi 307227614Sluigi return 0; 308227614Sluigi} 309227614Sluigi 310227614Sluigi 311227614Sluigi/* 312228276Sluigi * Reconcile kernel and user view of the receive ring. 313227614Sluigi */ 314227614Sluigistatic int 315270252Sluigilem_netmap_rxsync(struct netmap_kring *kring, int flags) 316227614Sluigi{ 317270252Sluigi struct netmap_adapter *na = kring->na; 318262151Sluigi struct ifnet *ifp = na->ifp; 319227614Sluigi struct netmap_ring *ring = kring->ring; 320262151Sluigi u_int nm_i; /* index into the netmap ring */ 321262151Sluigi u_int nic_i; /* index into the NIC ring */ 322262151Sluigi u_int n; 323262151Sluigi u_int const lim = kring->nkr_num_slots - 1; 324262151Sluigi u_int const head = nm_rxsync_prologue(kring); 325262151Sluigi int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; 326227614Sluigi 327262151Sluigi /* device-specific */ 328262151Sluigi struct adapter *adapter = ifp->if_softc; 329270252Sluigi#ifdef NIC_PARAVIRT 330270252Sluigi struct paravirt_csb *csb = adapter->csb; 331270252Sluigi uint32_t csb_mode = csb && csb->guest_csb_on; 332270252Sluigi uint32_t do_host_rxkick = 0; 333270252Sluigi#endif /* NIC_PARAVIRT */ 334262151Sluigi 335262151Sluigi if (head > lim) 336227614Sluigi return netmap_ring_reinit(kring); 337227614Sluigi 338270252Sluigi#ifdef NIC_PARAVIRT 339270252Sluigi if (csb_mode) { 340270252Sluigi force_update = 1; 341270252Sluigi csb->guest_need_rxkick = 0; 342270252Sluigi } 343270252Sluigi#endif /* NIC_PARAVIRT */ 344227614Sluigi /* XXX check sync modes */ 345227614Sluigi bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, 346227614Sluigi BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 347227614Sluigi 348232238Sluigi /* 349262151Sluigi * First part: import newly received packets. 350231778Sluigi */ 351232238Sluigi if (netmap_no_pendintr || force_update) { 352245579Sluigi uint16_t slot_flags = kring->nkr_slot_flags; 353245579Sluigi 354262151Sluigi nic_i = adapter->next_rx_desc_to_check; 355262151Sluigi nm_i = netmap_idx_n2k(kring, nic_i); 356262151Sluigi 357232238Sluigi for (n = 0; ; n++) { 358262151Sluigi struct e1000_rx_desc *curr = &adapter->rx_desc_base[nic_i]; 359232238Sluigi uint32_t staterr = le32toh(curr->status); 360232238Sluigi int len; 361227614Sluigi 362270252Sluigi#ifdef NIC_PARAVIRT 363270252Sluigi if (csb_mode) { 364270252Sluigi if ((staterr & E1000_RXD_STAT_DD) == 0) { 365270252Sluigi /* don't bother to retry if more than 1 pkt */ 366270252Sluigi if (n > 1) 367270252Sluigi break; 368270252Sluigi csb->guest_need_rxkick = 1; 369270252Sluigi wmb(); 370270252Sluigi staterr = le32toh(curr->status); 371270252Sluigi if ((staterr & E1000_RXD_STAT_DD) == 0) { 372270252Sluigi break; 373270252Sluigi } else { /* we are good */ 374270252Sluigi csb->guest_need_rxkick = 0; 375270252Sluigi } 376270252Sluigi } 377270252Sluigi } else 378270252Sluigi#endif /* NIC_PARAVIRT */ 379232238Sluigi if ((staterr & E1000_RXD_STAT_DD) == 0) 380232238Sluigi break; 381232238Sluigi len = le16toh(curr->length) - 4; // CRC 382232238Sluigi if (len < 0) { 383270252Sluigi RD(5, "bogus pkt (%d) size %d nic idx %d", n, len, nic_i); 384232238Sluigi len = 0; 385232238Sluigi } 386262151Sluigi ring->slot[nm_i].len = len; 387262151Sluigi ring->slot[nm_i].flags = slot_flags; 388232238Sluigi bus_dmamap_sync(adapter->rxtag, 389262151Sluigi adapter->rx_buffer_area[nic_i].map, 390262151Sluigi BUS_DMASYNC_POSTREAD); 391262151Sluigi nm_i = nm_next(nm_i, lim); 392262151Sluigi nic_i = nm_next(nic_i, lim); 393227614Sluigi } 394232238Sluigi if (n) { /* update the state variables */ 395270252Sluigi#ifdef NIC_PARAVIRT 396270252Sluigi if (csb_mode) { 397270252Sluigi if (n > 1) { 398270252Sluigi /* leave one spare buffer so we avoid rxkicks */ 399270252Sluigi nm_i = nm_prev(nm_i, lim); 400270252Sluigi nic_i = nm_prev(nic_i, lim); 401270252Sluigi n--; 402270252Sluigi } else { 403270252Sluigi csb->guest_need_rxkick = 1; 404270252Sluigi } 405270252Sluigi } 406270252Sluigi#endif /* NIC_PARAVIRT */ 407262151Sluigi ND("%d new packets at nic %d nm %d tail %d", 408262151Sluigi n, 409262151Sluigi adapter->next_rx_desc_to_check, 410262151Sluigi netmap_idx_n2k(kring, adapter->next_rx_desc_to_check), 411262151Sluigi kring->nr_hwtail); 412262151Sluigi adapter->next_rx_desc_to_check = nic_i; 413262151Sluigi // ifp->if_ipackets += n; 414262151Sluigi kring->nr_hwtail = nm_i; 415232238Sluigi } 416232238Sluigi kring->nr_kflags &= ~NKR_PENDINTR; 417227614Sluigi } 418227614Sluigi 419262151Sluigi /* 420262151Sluigi * Second part: skip past packets that userspace has released. 421262151Sluigi */ 422262151Sluigi nm_i = kring->nr_hwcur; 423262151Sluigi if (nm_i != head) { 424262151Sluigi nic_i = netmap_idx_k2n(kring, nm_i); 425262151Sluigi for (n = 0; nm_i != head; n++) { 426262151Sluigi struct netmap_slot *slot = &ring->slot[nm_i]; 427229939Sluigi uint64_t paddr; 428270252Sluigi void *addr = PNMB(na, slot, &paddr); 429227614Sluigi 430262151Sluigi struct e1000_rx_desc *curr = &adapter->rx_desc_base[nic_i]; 431262151Sluigi struct em_buffer *rxbuf = &adapter->rx_buffer_area[nic_i]; 432231778Sluigi 433270252Sluigi if (addr == NETMAP_BUF_BASE(na)) /* bad buf */ 434262151Sluigi goto ring_reset; 435262151Sluigi 436227614Sluigi if (slot->flags & NS_BUF_CHANGED) { 437231796Sluigi /* buffer has changed, reload map */ 438262151Sluigi curr->buffer_addr = htole64(paddr); 439270252Sluigi netmap_reload_map(na, adapter->rxtag, rxbuf->map, addr); 440227614Sluigi slot->flags &= ~NS_BUF_CHANGED; 441227614Sluigi } 442232238Sluigi curr->status = 0; 443227614Sluigi bus_dmamap_sync(adapter->rxtag, rxbuf->map, 444228276Sluigi BUS_DMASYNC_PREREAD); 445270252Sluigi#ifdef NIC_PARAVIRT 446270252Sluigi if (csb_mode && csb->host_rxkick_at == nic_i) 447270252Sluigi do_host_rxkick = 1; 448270252Sluigi#endif /* NIC_PARAVIRT */ 449262151Sluigi nm_i = nm_next(nm_i, lim); 450262151Sluigi nic_i = nm_next(nic_i, lim); 451227614Sluigi } 452262151Sluigi kring->nr_hwcur = head; 453227614Sluigi bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, 454228276Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 455227614Sluigi /* 456227614Sluigi * IMPORTANT: we must leave one free slot in the ring, 457262151Sluigi * so move nic_i back by one unit 458227614Sluigi */ 459262151Sluigi nic_i = nm_prev(nic_i, lim); 460270252Sluigi#ifdef NIC_PARAVIRT 461270252Sluigi /* set unconditionally, then also kick if needed */ 462270252Sluigi if (csb) 463270252Sluigi csb->guest_rdt = nic_i; 464270252Sluigi if (!csb_mode || do_host_rxkick) 465270252Sluigi#endif /* NIC_PARAVIRT */ 466262151Sluigi E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), nic_i); 467227614Sluigi } 468262151Sluigi 469262151Sluigi /* tell userspace that there might be new packets */ 470262151Sluigi nm_rxsync_finalize(kring); 471262151Sluigi 472227614Sluigi return 0; 473262151Sluigi 474262151Sluigiring_reset: 475262151Sluigi return netmap_ring_reinit(kring); 476227614Sluigi} 477232238Sluigi 478232238Sluigi 479232238Sluigistatic void 480232238Sluigilem_netmap_attach(struct adapter *adapter) 481232238Sluigi{ 482232238Sluigi struct netmap_adapter na; 483232238Sluigi 484232238Sluigi bzero(&na, sizeof(na)); 485232238Sluigi 486232238Sluigi na.ifp = adapter->ifp; 487262151Sluigi na.na_flags = NAF_BDG_MAYSLEEP; 488232238Sluigi na.num_tx_desc = adapter->num_tx_desc; 489232238Sluigi na.num_rx_desc = adapter->num_rx_desc; 490232238Sluigi na.nm_txsync = lem_netmap_txsync; 491232238Sluigi na.nm_rxsync = lem_netmap_rxsync; 492232238Sluigi na.nm_register = lem_netmap_reg; 493262151Sluigi na.num_tx_rings = na.num_rx_rings = 1; 494262151Sluigi netmap_attach(&na); 495232238Sluigi} 496232238Sluigi 497231198Sluigi/* end of file */ 498