1*55485da1Smsaitoh /* $NetBSD: ixgbe_netmap.c,v 1.6 2023/10/06 14:37:04 msaitoh Exp $ */
2dc7f84c8Smsaitoh /******************************************************************************
3dc7f84c8Smsaitoh
4dc7f84c8Smsaitoh Copyright (c) 2001-2017, Intel Corporation
5dc7f84c8Smsaitoh All rights reserved.
6dc7f84c8Smsaitoh
7dc7f84c8Smsaitoh Redistribution and use in source and binary forms, with or without
8dc7f84c8Smsaitoh modification, are permitted provided that the following conditions are met:
9dc7f84c8Smsaitoh
10dc7f84c8Smsaitoh 1. Redistributions of source code must retain the above copyright notice,
11dc7f84c8Smsaitoh this list of conditions and the following disclaimer.
12dc7f84c8Smsaitoh
13dc7f84c8Smsaitoh 2. Redistributions in binary form must reproduce the above copyright
14dc7f84c8Smsaitoh notice, this list of conditions and the following disclaimer in the
15dc7f84c8Smsaitoh documentation and/or other materials provided with the distribution.
16dc7f84c8Smsaitoh
17dc7f84c8Smsaitoh 3. Neither the name of the Intel Corporation nor the names of its
18dc7f84c8Smsaitoh contributors may be used to endorse or promote products derived from
19dc7f84c8Smsaitoh this software without specific prior written permission.
20dc7f84c8Smsaitoh
21dc7f84c8Smsaitoh THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22dc7f84c8Smsaitoh AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23dc7f84c8Smsaitoh IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24dc7f84c8Smsaitoh ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25dc7f84c8Smsaitoh LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26dc7f84c8Smsaitoh CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27dc7f84c8Smsaitoh SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28dc7f84c8Smsaitoh INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29dc7f84c8Smsaitoh CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30dc7f84c8Smsaitoh ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31dc7f84c8Smsaitoh POSSIBILITY OF SUCH DAMAGE.
32dc7f84c8Smsaitoh
33dc7f84c8Smsaitoh ******************************************************************************/
34dc7f84c8Smsaitoh /*$FreeBSD: head/sys/dev/ixgbe/ixgbe_netmap.c 320688 2017-07-05 17:27:03Z erj $*/
35dc7f84c8Smsaitoh
36dc7f84c8Smsaitoh /*
37dc7f84c8Smsaitoh * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
38dc7f84c8Smsaitoh *
39dc7f84c8Smsaitoh * Redistribution and use in source and binary forms, with or without
40dc7f84c8Smsaitoh * modification, are permitted provided that the following conditions
41dc7f84c8Smsaitoh * are met:
42dc7f84c8Smsaitoh * 1. Redistributions of source code must retain the above copyright
43dc7f84c8Smsaitoh * notice, this list of conditions and the following disclaimer.
44dc7f84c8Smsaitoh * 2. Redistributions in binary form must reproduce the above copyright
45dc7f84c8Smsaitoh * notice, this list of conditions and the following disclaimer in the
46dc7f84c8Smsaitoh * documentation and/or other materials provided with the distribution.
47dc7f84c8Smsaitoh *
48dc7f84c8Smsaitoh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
49dc7f84c8Smsaitoh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50dc7f84c8Smsaitoh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51dc7f84c8Smsaitoh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
52dc7f84c8Smsaitoh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53dc7f84c8Smsaitoh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54dc7f84c8Smsaitoh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55dc7f84c8Smsaitoh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56dc7f84c8Smsaitoh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57dc7f84c8Smsaitoh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58dc7f84c8Smsaitoh * SUCH DAMAGE.
59dc7f84c8Smsaitoh */
60dc7f84c8Smsaitoh
61dc7f84c8Smsaitoh /*
62dc7f84c8Smsaitoh * $FreeBSD: head/sys/dev/ixgbe/ixgbe_netmap.c 320688 2017-07-05 17:27:03Z erj $
63dc7f84c8Smsaitoh *
64dc7f84c8Smsaitoh * netmap support for: ixgbe
65dc7f84c8Smsaitoh *
66dc7f84c8Smsaitoh * This file is meant to be a reference on how to implement
67dc7f84c8Smsaitoh * netmap support for a network driver.
68dc7f84c8Smsaitoh * This file contains code but only static or inline functions used
69dc7f84c8Smsaitoh * by a single driver. To avoid replication of code we just #include
70dc7f84c8Smsaitoh * it near the beginning of the standard driver.
71dc7f84c8Smsaitoh */
72dc7f84c8Smsaitoh
73ab119b16Smsaitoh #include <sys/cdefs.h>
74*55485da1Smsaitoh __KERNEL_RCSID(0, "$NetBSD: ixgbe_netmap.c,v 1.6 2023/10/06 14:37:04 msaitoh Exp $");
75ab119b16Smsaitoh
76dc7f84c8Smsaitoh #ifdef DEV_NETMAP
77dc7f84c8Smsaitoh /*
78dc7f84c8Smsaitoh * Some drivers may need the following headers. Others
79dc7f84c8Smsaitoh * already include them by default
80dc7f84c8Smsaitoh
81dc7f84c8Smsaitoh #include <vm/vm.h>
82dc7f84c8Smsaitoh #include <vm/pmap.h>
83dc7f84c8Smsaitoh
84dc7f84c8Smsaitoh */
85dc7f84c8Smsaitoh #include "ixgbe.h"
86dc7f84c8Smsaitoh
87dc7f84c8Smsaitoh /*
88dc7f84c8Smsaitoh * device-specific sysctl variables:
89dc7f84c8Smsaitoh *
90dc7f84c8Smsaitoh * ix_crcstrip: 0: keep CRC in rx frames (default), 1: strip it.
91dc7f84c8Smsaitoh * During regular operations the CRC is stripped, but on some
92dc7f84c8Smsaitoh * hardware reception of frames not multiple of 64 is slower,
93dc7f84c8Smsaitoh * so using crcstrip=0 helps in benchmarks.
94dc7f84c8Smsaitoh *
95dc7f84c8Smsaitoh * ix_rx_miss, ix_rx_miss_bufs:
96dc7f84c8Smsaitoh * count packets that might be missed due to lost interrupts.
97dc7f84c8Smsaitoh */
98dc7f84c8Smsaitoh SYSCTL_DECL(_dev_netmap);
99dc7f84c8Smsaitoh static int ix_rx_miss, ix_rx_miss_bufs;
100dc7f84c8Smsaitoh int ix_crcstrip;
101dc7f84c8Smsaitoh SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
102dc7f84c8Smsaitoh CTLFLAG_RW, &ix_crcstrip, 0, "strip CRC on rx frames");
103dc7f84c8Smsaitoh SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss,
104dc7f84c8Smsaitoh CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr");
105dc7f84c8Smsaitoh SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss_bufs,
106dc7f84c8Smsaitoh CTLFLAG_RW, &ix_rx_miss_bufs, 0, "potentially missed rx intr bufs");
107dc7f84c8Smsaitoh
108dc7f84c8Smsaitoh
109dc7f84c8Smsaitoh static void
set_crcstrip(struct ixgbe_hw * hw,int onoff)110dc7f84c8Smsaitoh set_crcstrip(struct ixgbe_hw *hw, int onoff)
111dc7f84c8Smsaitoh {
112dc7f84c8Smsaitoh /* crc stripping is set in two places:
113dc7f84c8Smsaitoh * IXGBE_HLREG0 (modified on init_locked and hw reset)
114dc7f84c8Smsaitoh * IXGBE_RDRXCTL (set by the original driver in
115dc7f84c8Smsaitoh * ixgbe_setup_hw_rsc() called in init_locked.
116dc7f84c8Smsaitoh * We disable the setting when netmap is compiled in).
117dc7f84c8Smsaitoh * We update the values here, but also in ixgbe.c because
118dc7f84c8Smsaitoh * init_locked sometimes is called outside our control.
119dc7f84c8Smsaitoh */
120dc7f84c8Smsaitoh uint32_t hl, rxc;
121dc7f84c8Smsaitoh
122dc7f84c8Smsaitoh hl = IXGBE_READ_REG(hw, IXGBE_HLREG0);
123dc7f84c8Smsaitoh rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
124e4f827b8Smsaitoh #ifdef D
125dc7f84c8Smsaitoh if (netmap_verbose)
126dc7f84c8Smsaitoh D("%s read HLREG 0x%x rxc 0x%x",
127dc7f84c8Smsaitoh onoff ? "enter" : "exit", hl, rxc);
128e4f827b8Smsaitoh #endif
129dc7f84c8Smsaitoh /* hw requirements ... */
130dc7f84c8Smsaitoh rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
131dc7f84c8Smsaitoh rxc |= IXGBE_RDRXCTL_RSCACKC;
132dc7f84c8Smsaitoh if (onoff && !ix_crcstrip) {
133dc7f84c8Smsaitoh /* keep the crc. Fast rx */
134dc7f84c8Smsaitoh hl &= ~IXGBE_HLREG0_RXCRCSTRP;
135dc7f84c8Smsaitoh rxc &= ~IXGBE_RDRXCTL_CRCSTRIP;
136dc7f84c8Smsaitoh } else {
137dc7f84c8Smsaitoh /* reset default mode */
138dc7f84c8Smsaitoh hl |= IXGBE_HLREG0_RXCRCSTRP;
139dc7f84c8Smsaitoh rxc |= IXGBE_RDRXCTL_CRCSTRIP;
140dc7f84c8Smsaitoh }
141e4f827b8Smsaitoh #ifdef D
142dc7f84c8Smsaitoh if (netmap_verbose)
143dc7f84c8Smsaitoh D("%s write HLREG 0x%x rxc 0x%x",
144dc7f84c8Smsaitoh onoff ? "enter" : "exit", hl, rxc);
145e4f827b8Smsaitoh #endif
146dc7f84c8Smsaitoh IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl);
147dc7f84c8Smsaitoh IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc);
148dc7f84c8Smsaitoh }
149dc7f84c8Smsaitoh
150dc7f84c8Smsaitoh
151dc7f84c8Smsaitoh /*
152dc7f84c8Smsaitoh * Register/unregister. We are already under netmap lock.
153dc7f84c8Smsaitoh * Only called on the first register or the last unregister.
154dc7f84c8Smsaitoh */
155dc7f84c8Smsaitoh static int
ixgbe_netmap_reg(struct netmap_adapter * na,int onoff)156dc7f84c8Smsaitoh ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
157dc7f84c8Smsaitoh {
158dc7f84c8Smsaitoh struct ifnet *ifp = na->ifp;
159*55485da1Smsaitoh struct ixgbe_softc *sc = ifp->if_softc;
160dc7f84c8Smsaitoh
161*55485da1Smsaitoh IXGBE_CORE_LOCK(sc);
162*55485da1Smsaitoh sc->stop_locked(sc);
163dc7f84c8Smsaitoh
164*55485da1Smsaitoh set_crcstrip(&sc->hw, onoff);
165dc7f84c8Smsaitoh /* enable or disable flags and callbacks in na and ifp */
166dc7f84c8Smsaitoh if (onoff) {
167dc7f84c8Smsaitoh nm_set_native_flags(na);
168dc7f84c8Smsaitoh } else {
169dc7f84c8Smsaitoh nm_clear_native_flags(na);
170dc7f84c8Smsaitoh }
171*55485da1Smsaitoh sc->init_locked(sc); /* also enables intr */
172*55485da1Smsaitoh set_crcstrip(&sc->hw, onoff); // XXX why twice ?
173*55485da1Smsaitoh IXGBE_CORE_UNLOCK(sc);
174dc7f84c8Smsaitoh return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1);
175dc7f84c8Smsaitoh }
176dc7f84c8Smsaitoh
177dc7f84c8Smsaitoh
178dc7f84c8Smsaitoh /*
179dc7f84c8Smsaitoh * Reconcile kernel and user view of the transmit ring.
180dc7f84c8Smsaitoh *
181dc7f84c8Smsaitoh * All information is in the kring.
182dc7f84c8Smsaitoh * Userspace wants to send packets up to the one before kring->rhead,
183dc7f84c8Smsaitoh * kernel knows kring->nr_hwcur is the first unsent packet.
184dc7f84c8Smsaitoh *
185dc7f84c8Smsaitoh * Here we push packets out (as many as possible), and possibly
186dc7f84c8Smsaitoh * reclaim buffers from previously completed transmission.
187dc7f84c8Smsaitoh *
188dc7f84c8Smsaitoh * The caller (netmap) guarantees that there is only one instance
189dc7f84c8Smsaitoh * running at any time. Any interference with other driver
190dc7f84c8Smsaitoh * methods should be handled by the individual drivers.
191dc7f84c8Smsaitoh */
192dc7f84c8Smsaitoh static int
ixgbe_netmap_txsync(struct netmap_kring * kring,int flags)193dc7f84c8Smsaitoh ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
194dc7f84c8Smsaitoh {
195dc7f84c8Smsaitoh struct netmap_adapter *na = kring->na;
196dc7f84c8Smsaitoh struct ifnet *ifp = na->ifp;
197dc7f84c8Smsaitoh struct netmap_ring *ring = kring->ring;
198dc7f84c8Smsaitoh u_int nm_i; /* index into the netmap ring */
199dc7f84c8Smsaitoh u_int nic_i; /* index into the NIC ring */
200dc7f84c8Smsaitoh u_int n;
201dc7f84c8Smsaitoh u_int const lim = kring->nkr_num_slots - 1;
202dc7f84c8Smsaitoh u_int const head = kring->rhead;
203dc7f84c8Smsaitoh /*
204dc7f84c8Smsaitoh * interrupts on every tx packet are expensive so request
205dc7f84c8Smsaitoh * them every half ring, or where NS_REPORT is set
206dc7f84c8Smsaitoh */
207dc7f84c8Smsaitoh u_int report_frequency = kring->nkr_num_slots >> 1;
208dc7f84c8Smsaitoh
209dc7f84c8Smsaitoh /* device-specific */
210*55485da1Smsaitoh struct ixgbe_softc *sc = ifp->if_softc;
211*55485da1Smsaitoh struct tx_ring *txr = &sc->tx_rings[kring->ring_id];
212dc7f84c8Smsaitoh int reclaim_tx;
213dc7f84c8Smsaitoh
214dc7f84c8Smsaitoh bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
215dc7f84c8Smsaitoh BUS_DMASYNC_POSTREAD);
216dc7f84c8Smsaitoh
217dc7f84c8Smsaitoh /*
218dc7f84c8Smsaitoh * First part: process new packets to send.
219dc7f84c8Smsaitoh * nm_i is the current index in the netmap ring,
220dc7f84c8Smsaitoh * nic_i is the corresponding index in the NIC ring.
221dc7f84c8Smsaitoh * The two numbers differ because upon a *_init() we reset
222dc7f84c8Smsaitoh * the NIC ring but leave the netmap ring unchanged.
223dc7f84c8Smsaitoh * For the transmit ring, we have
224dc7f84c8Smsaitoh *
225dc7f84c8Smsaitoh * nm_i = kring->nr_hwcur
226dc7f84c8Smsaitoh * nic_i = IXGBE_TDT (not tracked in the driver)
227dc7f84c8Smsaitoh * and
228dc7f84c8Smsaitoh * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
229dc7f84c8Smsaitoh *
230dc7f84c8Smsaitoh * In this driver kring->nkr_hwofs >= 0, but for other
231dc7f84c8Smsaitoh * drivers it might be negative as well.
232dc7f84c8Smsaitoh */
233dc7f84c8Smsaitoh
234dc7f84c8Smsaitoh /*
235dc7f84c8Smsaitoh * If we have packets to send (kring->nr_hwcur != kring->rhead)
236dc7f84c8Smsaitoh * iterate over the netmap ring, fetch length and update
237dc7f84c8Smsaitoh * the corresponding slot in the NIC ring. Some drivers also
238dc7f84c8Smsaitoh * need to update the buffer's physical address in the NIC slot
239dc7f84c8Smsaitoh * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
240dc7f84c8Smsaitoh *
241dc7f84c8Smsaitoh * The netmap_reload_map() calls is especially expensive,
242dc7f84c8Smsaitoh * even when (as in this case) the tag is 0, so do only
243dc7f84c8Smsaitoh * when the buffer has actually changed.
244dc7f84c8Smsaitoh *
245dc7f84c8Smsaitoh * If possible do not set the report/intr bit on all slots,
246dc7f84c8Smsaitoh * but only a few times per ring or when NS_REPORT is set.
247dc7f84c8Smsaitoh *
248dc7f84c8Smsaitoh * Finally, on 10G and faster drivers, it might be useful
249dc7f84c8Smsaitoh * to prefetch the next slot and txr entry.
250dc7f84c8Smsaitoh */
251dc7f84c8Smsaitoh
252dc7f84c8Smsaitoh nm_i = kring->nr_hwcur;
253dc7f84c8Smsaitoh if (nm_i != head) { /* we have new packets to send */
254dc7f84c8Smsaitoh nic_i = netmap_idx_k2n(kring, nm_i);
255dc7f84c8Smsaitoh
256dc7f84c8Smsaitoh __builtin_prefetch(&ring->slot[nm_i]);
257dc7f84c8Smsaitoh __builtin_prefetch(&txr->tx_buffers[nic_i]);
258dc7f84c8Smsaitoh
259dc7f84c8Smsaitoh for (n = 0; nm_i != head; n++) {
260dc7f84c8Smsaitoh struct netmap_slot *slot = &ring->slot[nm_i];
261dc7f84c8Smsaitoh u_int len = slot->len;
262dc7f84c8Smsaitoh uint64_t paddr;
263dc7f84c8Smsaitoh void *addr = PNMB(na, slot, &paddr);
264dc7f84c8Smsaitoh
265dc7f84c8Smsaitoh /* device-specific */
266dc7f84c8Smsaitoh union ixgbe_adv_tx_desc *curr = &txr->tx_base[nic_i];
267dc7f84c8Smsaitoh struct ixgbe_tx_buf *txbuf = &txr->tx_buffers[nic_i];
268dc7f84c8Smsaitoh int flags = (slot->flags & NS_REPORT ||
269dc7f84c8Smsaitoh nic_i == 0 || nic_i == report_frequency) ?
270dc7f84c8Smsaitoh IXGBE_TXD_CMD_RS : 0;
271dc7f84c8Smsaitoh
272dc7f84c8Smsaitoh /* prefetch for next round */
273dc7f84c8Smsaitoh __builtin_prefetch(&ring->slot[nm_i + 1]);
274dc7f84c8Smsaitoh __builtin_prefetch(&txr->tx_buffers[nic_i + 1]);
275dc7f84c8Smsaitoh
276dc7f84c8Smsaitoh NM_CHECK_ADDR_LEN(na, addr, len);
277dc7f84c8Smsaitoh
278dc7f84c8Smsaitoh if (slot->flags & NS_BUF_CHANGED) {
279dc7f84c8Smsaitoh /* buffer has changed, reload map */
280dc7f84c8Smsaitoh netmap_reload_map(na, txr->txtag, txbuf->map, addr);
281dc7f84c8Smsaitoh }
282dc7f84c8Smsaitoh slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
283dc7f84c8Smsaitoh
284dc7f84c8Smsaitoh /* Fill the slot in the NIC ring. */
285dc7f84c8Smsaitoh /* Use legacy descriptor, they are faster? */
286dc7f84c8Smsaitoh curr->read.buffer_addr = htole64(paddr);
287dc7f84c8Smsaitoh curr->read.olinfo_status = 0;
288dc7f84c8Smsaitoh curr->read.cmd_type_len = htole32(len | flags |
289dc7f84c8Smsaitoh IXGBE_ADVTXD_DCMD_IFCS | IXGBE_TXD_CMD_EOP);
290dc7f84c8Smsaitoh
291dc7f84c8Smsaitoh /* make sure changes to the buffer are synced */
292dc7f84c8Smsaitoh bus_dmamap_sync(txr->txtag, txbuf->map,
293dc7f84c8Smsaitoh BUS_DMASYNC_PREWRITE);
294dc7f84c8Smsaitoh
295dc7f84c8Smsaitoh nm_i = nm_next(nm_i, lim);
296dc7f84c8Smsaitoh nic_i = nm_next(nic_i, lim);
297dc7f84c8Smsaitoh }
298dc7f84c8Smsaitoh kring->nr_hwcur = head;
299dc7f84c8Smsaitoh
300dc7f84c8Smsaitoh /* synchronize the NIC ring */
301dc7f84c8Smsaitoh bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
302dc7f84c8Smsaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
303dc7f84c8Smsaitoh
304dc7f84c8Smsaitoh /* (re)start the tx unit up to slot nic_i (excluded) */
305*55485da1Smsaitoh IXGBE_WRITE_REG(&sc->hw, txr->tail, nic_i);
306dc7f84c8Smsaitoh }
307dc7f84c8Smsaitoh
308dc7f84c8Smsaitoh /*
309dc7f84c8Smsaitoh * Second part: reclaim buffers for completed transmissions.
310dc7f84c8Smsaitoh * Because this is expensive (we read a NIC register etc.)
311dc7f84c8Smsaitoh * we only do it in specific cases (see below).
312dc7f84c8Smsaitoh */
313dc7f84c8Smsaitoh if (flags & NAF_FORCE_RECLAIM) {
314dc7f84c8Smsaitoh reclaim_tx = 1; /* forced reclaim */
315dc7f84c8Smsaitoh } else if (!nm_kr_txempty(kring)) {
316dc7f84c8Smsaitoh reclaim_tx = 0; /* have buffers, no reclaim */
317dc7f84c8Smsaitoh } else {
318dc7f84c8Smsaitoh /*
319dc7f84c8Smsaitoh * No buffers available. Locate previous slot with
320dc7f84c8Smsaitoh * REPORT_STATUS set.
321dc7f84c8Smsaitoh * If the slot has DD set, we can reclaim space,
322dc7f84c8Smsaitoh * otherwise wait for the next interrupt.
323dc7f84c8Smsaitoh * This enables interrupt moderation on the tx
324dc7f84c8Smsaitoh * side though it might reduce throughput.
325dc7f84c8Smsaitoh */
326dc7f84c8Smsaitoh struct ixgbe_legacy_tx_desc *txd =
327dc7f84c8Smsaitoh (struct ixgbe_legacy_tx_desc *)txr->tx_base;
328dc7f84c8Smsaitoh
329dc7f84c8Smsaitoh nic_i = txr->next_to_clean + report_frequency;
330dc7f84c8Smsaitoh if (nic_i > lim)
331dc7f84c8Smsaitoh nic_i -= lim + 1;
332dc7f84c8Smsaitoh // round to the closest with dd set
333dc7f84c8Smsaitoh nic_i = (nic_i < kring->nkr_num_slots / 4 ||
334dc7f84c8Smsaitoh nic_i >= kring->nkr_num_slots*3/4) ?
335dc7f84c8Smsaitoh 0 : report_frequency;
336dc7f84c8Smsaitoh reclaim_tx = txd[nic_i].upper.fields.status & IXGBE_TXD_STAT_DD; // XXX cpu_to_le32 ?
337dc7f84c8Smsaitoh }
338dc7f84c8Smsaitoh if (reclaim_tx) {
339dc7f84c8Smsaitoh /*
340dc7f84c8Smsaitoh * Record completed transmissions.
341dc7f84c8Smsaitoh * We (re)use the driver's txr->next_to_clean to keep
342dc7f84c8Smsaitoh * track of the most recently completed transmission.
343dc7f84c8Smsaitoh *
344dc7f84c8Smsaitoh * The datasheet discourages the use of TDH to find
345dc7f84c8Smsaitoh * out the number of sent packets, but we only set
346dc7f84c8Smsaitoh * REPORT_STATUS in a few slots so TDH is the only
347dc7f84c8Smsaitoh * good way.
348dc7f84c8Smsaitoh */
349*55485da1Smsaitoh nic_i = IXGBE_READ_REG(&sc->hw, IXGBE_TDH(kring->ring_id));
350dc7f84c8Smsaitoh if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
351e4f827b8Smsaitoh #ifdef D
352dc7f84c8Smsaitoh D("TDH wrap %d", nic_i);
353e4f827b8Smsaitoh #endif
354dc7f84c8Smsaitoh nic_i -= kring->nkr_num_slots;
355dc7f84c8Smsaitoh }
356dc7f84c8Smsaitoh if (nic_i != txr->next_to_clean) {
357dc7f84c8Smsaitoh /* some tx completed, increment avail */
358dc7f84c8Smsaitoh txr->next_to_clean = nic_i;
359dc7f84c8Smsaitoh kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
360dc7f84c8Smsaitoh }
361dc7f84c8Smsaitoh }
362dc7f84c8Smsaitoh
363dc7f84c8Smsaitoh return 0;
364dc7f84c8Smsaitoh }
365dc7f84c8Smsaitoh
366dc7f84c8Smsaitoh
367dc7f84c8Smsaitoh /*
368dc7f84c8Smsaitoh * Reconcile kernel and user view of the receive ring.
369dc7f84c8Smsaitoh * Same as for the txsync, this routine must be efficient.
370dc7f84c8Smsaitoh * The caller guarantees a single invocations, but races against
371dc7f84c8Smsaitoh * the rest of the driver should be handled here.
372dc7f84c8Smsaitoh *
373dc7f84c8Smsaitoh * On call, kring->rhead is the first packet that userspace wants
374dc7f84c8Smsaitoh * to keep, and kring->rcur is the wakeup point.
375dc7f84c8Smsaitoh * The kernel has previously reported packets up to kring->rtail.
376dc7f84c8Smsaitoh *
377dc7f84c8Smsaitoh * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
378dc7f84c8Smsaitoh * of whether or not we received an interrupt.
379dc7f84c8Smsaitoh */
380dc7f84c8Smsaitoh static int
ixgbe_netmap_rxsync(struct netmap_kring * kring,int flags)381dc7f84c8Smsaitoh ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
382dc7f84c8Smsaitoh {
383dc7f84c8Smsaitoh struct netmap_adapter *na = kring->na;
384dc7f84c8Smsaitoh struct ifnet *ifp = na->ifp;
385dc7f84c8Smsaitoh struct netmap_ring *ring = kring->ring;
386dc7f84c8Smsaitoh u_int nm_i; /* index into the netmap ring */
387dc7f84c8Smsaitoh u_int nic_i; /* index into the NIC ring */
388dc7f84c8Smsaitoh u_int n;
389dc7f84c8Smsaitoh u_int const lim = kring->nkr_num_slots - 1;
390dc7f84c8Smsaitoh u_int const head = kring->rhead;
391dc7f84c8Smsaitoh int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
392dc7f84c8Smsaitoh
393dc7f84c8Smsaitoh /* device-specific */
394*55485da1Smsaitoh struct ixgbe_softc *sc = ifp->if_softc;
395*55485da1Smsaitoh struct rx_ring *rxr = &sc->rx_rings[kring->ring_id];
396dc7f84c8Smsaitoh
397dc7f84c8Smsaitoh if (head > lim)
398dc7f84c8Smsaitoh return netmap_ring_reinit(kring);
399dc7f84c8Smsaitoh
400dc7f84c8Smsaitoh /* XXX check sync modes */
401dc7f84c8Smsaitoh bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
402dc7f84c8Smsaitoh BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
403dc7f84c8Smsaitoh
404dc7f84c8Smsaitoh /*
405dc7f84c8Smsaitoh * First part: import newly received packets.
406dc7f84c8Smsaitoh *
407dc7f84c8Smsaitoh * nm_i is the index of the next free slot in the netmap ring,
408dc7f84c8Smsaitoh * nic_i is the index of the next received packet in the NIC ring,
409dc7f84c8Smsaitoh * and they may differ in case if_init() has been called while
410dc7f84c8Smsaitoh * in netmap mode. For the receive ring we have
411dc7f84c8Smsaitoh *
412dc7f84c8Smsaitoh * nic_i = rxr->next_to_check;
413dc7f84c8Smsaitoh * nm_i = kring->nr_hwtail (previous)
414dc7f84c8Smsaitoh * and
415dc7f84c8Smsaitoh * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
416dc7f84c8Smsaitoh *
417dc7f84c8Smsaitoh * rxr->next_to_check is set to 0 on a ring reinit
418dc7f84c8Smsaitoh */
419dc7f84c8Smsaitoh if (netmap_no_pendintr || force_update) {
420dc7f84c8Smsaitoh int crclen = (ix_crcstrip) ? 0 : 4;
421dc7f84c8Smsaitoh
422dc7f84c8Smsaitoh nic_i = rxr->next_to_check; // or also k2n(kring->nr_hwtail)
423dc7f84c8Smsaitoh nm_i = netmap_idx_n2k(kring, nic_i);
424dc7f84c8Smsaitoh
425dc7f84c8Smsaitoh for (n = 0; ; n++) {
426dc7f84c8Smsaitoh union ixgbe_adv_rx_desc *curr = &rxr->rx_base[nic_i];
427dc7f84c8Smsaitoh uint32_t staterr = le32toh(curr->wb.upper.status_error);
428dc7f84c8Smsaitoh
429dc7f84c8Smsaitoh if ((staterr & IXGBE_RXD_STAT_DD) == 0)
430dc7f84c8Smsaitoh break;
431dc7f84c8Smsaitoh ring->slot[nm_i].len = le16toh(curr->wb.upper.length) - crclen;
432bec7d0d6Smsaitoh ring->slot[nm_i].flags = 0;
433dc7f84c8Smsaitoh bus_dmamap_sync(rxr->ptag,
434dc7f84c8Smsaitoh rxr->rx_buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
435dc7f84c8Smsaitoh nm_i = nm_next(nm_i, lim);
436dc7f84c8Smsaitoh nic_i = nm_next(nic_i, lim);
437dc7f84c8Smsaitoh }
438dc7f84c8Smsaitoh if (n) { /* update the state variables */
439dc7f84c8Smsaitoh if (netmap_no_pendintr && !force_update) {
440dc7f84c8Smsaitoh /* diagnostics */
441dc7f84c8Smsaitoh ix_rx_miss ++;
442dc7f84c8Smsaitoh ix_rx_miss_bufs += n;
443dc7f84c8Smsaitoh }
444dc7f84c8Smsaitoh rxr->next_to_check = nic_i;
445dc7f84c8Smsaitoh kring->nr_hwtail = nm_i;
446dc7f84c8Smsaitoh }
447dc7f84c8Smsaitoh kring->nr_kflags &= ~NKR_PENDINTR;
448dc7f84c8Smsaitoh }
449dc7f84c8Smsaitoh
450dc7f84c8Smsaitoh /*
451dc7f84c8Smsaitoh * Second part: skip past packets that userspace has released.
452dc7f84c8Smsaitoh * (kring->nr_hwcur to kring->rhead excluded),
453dc7f84c8Smsaitoh * and make the buffers available for reception.
454dc7f84c8Smsaitoh * As usual nm_i is the index in the netmap ring,
455dc7f84c8Smsaitoh * nic_i is the index in the NIC ring, and
456dc7f84c8Smsaitoh * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
457dc7f84c8Smsaitoh */
458dc7f84c8Smsaitoh nm_i = kring->nr_hwcur;
459dc7f84c8Smsaitoh if (nm_i != head) {
460dc7f84c8Smsaitoh nic_i = netmap_idx_k2n(kring, nm_i);
461dc7f84c8Smsaitoh for (n = 0; nm_i != head; n++) {
462dc7f84c8Smsaitoh struct netmap_slot *slot = &ring->slot[nm_i];
463dc7f84c8Smsaitoh uint64_t paddr;
464dc7f84c8Smsaitoh void *addr = PNMB(na, slot, &paddr);
465dc7f84c8Smsaitoh
466dc7f84c8Smsaitoh union ixgbe_adv_rx_desc *curr = &rxr->rx_base[nic_i];
467dc7f84c8Smsaitoh struct ixgbe_rx_buf *rxbuf = &rxr->rx_buffers[nic_i];
468dc7f84c8Smsaitoh
469dc7f84c8Smsaitoh if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
470dc7f84c8Smsaitoh goto ring_reset;
471dc7f84c8Smsaitoh
472dc7f84c8Smsaitoh if (slot->flags & NS_BUF_CHANGED) {
473dc7f84c8Smsaitoh /* buffer has changed, reload map */
474dc7f84c8Smsaitoh netmap_reload_map(na, rxr->ptag, rxbuf->pmap, addr);
475dc7f84c8Smsaitoh slot->flags &= ~NS_BUF_CHANGED;
476dc7f84c8Smsaitoh }
477dc7f84c8Smsaitoh curr->wb.upper.status_error = 0;
478dc7f84c8Smsaitoh curr->read.pkt_addr = htole64(paddr);
479dc7f84c8Smsaitoh bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
480dc7f84c8Smsaitoh BUS_DMASYNC_PREREAD);
481dc7f84c8Smsaitoh nm_i = nm_next(nm_i, lim);
482dc7f84c8Smsaitoh nic_i = nm_next(nic_i, lim);
483dc7f84c8Smsaitoh }
484dc7f84c8Smsaitoh kring->nr_hwcur = head;
485dc7f84c8Smsaitoh
486dc7f84c8Smsaitoh bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
487dc7f84c8Smsaitoh BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
488dc7f84c8Smsaitoh /*
489dc7f84c8Smsaitoh * IMPORTANT: we must leave one free slot in the ring,
490dc7f84c8Smsaitoh * so move nic_i back by one unit
491dc7f84c8Smsaitoh */
492dc7f84c8Smsaitoh nic_i = nm_prev(nic_i, lim);
493*55485da1Smsaitoh IXGBE_WRITE_REG(&sc->hw, rxr->tail, nic_i);
494dc7f84c8Smsaitoh }
495dc7f84c8Smsaitoh
496dc7f84c8Smsaitoh return 0;
497dc7f84c8Smsaitoh
498dc7f84c8Smsaitoh ring_reset:
499dc7f84c8Smsaitoh return netmap_ring_reinit(kring);
500dc7f84c8Smsaitoh }
501dc7f84c8Smsaitoh
502dc7f84c8Smsaitoh
503dc7f84c8Smsaitoh /*
504dc7f84c8Smsaitoh * The attach routine, called near the end of ixgbe_attach(),
505dc7f84c8Smsaitoh * fills the parameters for netmap_attach() and calls it.
506dc7f84c8Smsaitoh * It cannot fail, in the worst case (such as no memory)
507dc7f84c8Smsaitoh * netmap mode will be disabled and the driver will only
508dc7f84c8Smsaitoh * operate in standard mode.
509dc7f84c8Smsaitoh */
510dc7f84c8Smsaitoh void
ixgbe_netmap_attach(struct ixgbe_softc * sc)511*55485da1Smsaitoh ixgbe_netmap_attach(struct ixgbe_softc *sc)
512dc7f84c8Smsaitoh {
513dc7f84c8Smsaitoh struct netmap_adapter na;
514dc7f84c8Smsaitoh
515dc7f84c8Smsaitoh bzero(&na, sizeof(na));
516dc7f84c8Smsaitoh
517*55485da1Smsaitoh na.ifp = sc->ifp;
518dc7f84c8Smsaitoh na.na_flags = NAF_BDG_MAYSLEEP;
519*55485da1Smsaitoh na.num_tx_desc = sc->num_tx_desc;
520*55485da1Smsaitoh na.num_rx_desc = sc->num_rx_desc;
521dc7f84c8Smsaitoh na.nm_txsync = ixgbe_netmap_txsync;
522dc7f84c8Smsaitoh na.nm_rxsync = ixgbe_netmap_rxsync;
523dc7f84c8Smsaitoh na.nm_register = ixgbe_netmap_reg;
524*55485da1Smsaitoh na.num_tx_rings = na.num_rx_rings = sc->num_queues;
525dc7f84c8Smsaitoh netmap_attach(&na);
526dc7f84c8Smsaitoh }
527dc7f84c8Smsaitoh
528dc7f84c8Smsaitoh #endif /* DEV_NETMAP */
529dc7f84c8Smsaitoh
530dc7f84c8Smsaitoh /* end of file */
531