1331722Seadler/*
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.
12228276Sluigi *
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: stable/11/sys/dev/netmap/if_em_netmap.h 343771 2019-02-05 10:33:22Z vmaffione $
28227614Sluigi *
29259412Sluigi * netmap support for: em.
30228276Sluigi *
31232238Sluigi * For more 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
41232238Sluigi
42228276Sluigi// XXX do we need to block/unblock the tasks ?
43227614Sluigistatic void
44227614Sluigiem_netmap_block_tasks(struct adapter *adapter)
45227614Sluigi{
46227614Sluigi	if (adapter->msix > 1) { /* MSIX */
47227614Sluigi		int i;
48227614Sluigi		struct tx_ring *txr = adapter->tx_rings;
49227614Sluigi		struct rx_ring *rxr = adapter->rx_rings;
50227614Sluigi
51227614Sluigi		for (i = 0; i < adapter->num_queues; i++, txr++, rxr++) {
52227614Sluigi			taskqueue_block(txr->tq);
53227614Sluigi			taskqueue_drain(txr->tq, &txr->tx_task);
54227614Sluigi			taskqueue_block(rxr->tq);
55227614Sluigi			taskqueue_drain(rxr->tq, &rxr->rx_task);
56227614Sluigi		}
57227614Sluigi	} else {	/* legacy */
58227614Sluigi		taskqueue_block(adapter->tq);
59227614Sluigi		taskqueue_drain(adapter->tq, &adapter->link_task);
60227614Sluigi		taskqueue_drain(adapter->tq, &adapter->que_task);
61227614Sluigi	}
62227614Sluigi}
63227614Sluigi
64227614Sluigi
65227614Sluigistatic void
66227614Sluigiem_netmap_unblock_tasks(struct adapter *adapter)
67227614Sluigi{
68227614Sluigi	if (adapter->msix > 1) {
69227614Sluigi		struct tx_ring *txr = adapter->tx_rings;
70227614Sluigi		struct rx_ring *rxr = adapter->rx_rings;
71227614Sluigi		int i;
72227614Sluigi
73283959Ssbruno		for (i = 0; i < adapter->num_queues; i++, txr++, rxr++) {
74227614Sluigi			taskqueue_unblock(txr->tq);
75227614Sluigi			taskqueue_unblock(rxr->tq);
76227614Sluigi		}
77227614Sluigi	} else { /* legacy */
78227614Sluigi		taskqueue_unblock(adapter->tq);
79227614Sluigi	}
80227614Sluigi}
81227614Sluigi
82231778Sluigi
83227614Sluigi/*
84259412Sluigi * Register/unregister. We are already under netmap lock.
85227614Sluigi */
86227614Sluigistatic int
87259412Sluigiem_netmap_reg(struct netmap_adapter *na, int onoff)
88227614Sluigi{
89259412Sluigi	struct ifnet *ifp = na->ifp;
90227614Sluigi	struct adapter *adapter = ifp->if_softc;
91227614Sluigi
92259412Sluigi	EM_CORE_LOCK(adapter);
93227614Sluigi	em_disable_intr(adapter);
94227614Sluigi
95227614Sluigi	/* Tell the stack that the interface is no longer active */
96227614Sluigi	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
97227614Sluigi
98227614Sluigi	em_netmap_block_tasks(adapter);
99259412Sluigi	/* enable or disable flags and callbacks in na and ifp */
100227614Sluigi	if (onoff) {
101259412Sluigi		nm_set_native_flags(na);
102227614Sluigi	} else {
103259412Sluigi		nm_clear_native_flags(na);
104227614Sluigi	}
105259412Sluigi	em_init_locked(adapter);	/* also enable intr */
106227614Sluigi	em_netmap_unblock_tasks(adapter);
107259412Sluigi	EM_CORE_UNLOCK(adapter);
108259412Sluigi	return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1);
109227614Sluigi}
110227614Sluigi
111231778Sluigi
112227614Sluigi/*
113232238Sluigi * Reconcile kernel and user view of the transmit ring.
114227614Sluigi */
115227614Sluigistatic int
116270063Sluigiem_netmap_txsync(struct netmap_kring *kring, int flags)
117227614Sluigi{
118270063Sluigi	struct netmap_adapter *na = kring->na;
119259412Sluigi	struct ifnet *ifp = na->ifp;
120227614Sluigi	struct netmap_ring *ring = kring->ring;
121259412Sluigi	u_int nm_i;	/* index into the netmap ring */
122259412Sluigi	u_int nic_i;	/* index into the NIC ring */
123260368Sluigi	u_int n;
124259412Sluigi	u_int const lim = kring->nkr_num_slots - 1;
125260368Sluigi	u_int const head = kring->rhead;
126227614Sluigi	/* generate an interrupt approximately every half ring */
127238985Sluigi	u_int report_frequency = kring->nkr_num_slots >> 1;
128227614Sluigi
129259412Sluigi	/* device-specific */
130259412Sluigi	struct adapter *adapter = ifp->if_softc;
131270063Sluigi	struct tx_ring *txr = &adapter->tx_rings[kring->ring_id];
132259412Sluigi
133227614Sluigi	bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
134227614Sluigi			BUS_DMASYNC_POSTREAD);
135227614Sluigi
136232238Sluigi	/*
137259412Sluigi	 * First part: process new packets to send.
138227614Sluigi	 */
139259412Sluigi
140259412Sluigi	nm_i = kring->nr_hwcur;
141260368Sluigi	if (nm_i != head) {	/* we have new packets to send */
142259412Sluigi		nic_i = netmap_idx_k2n(kring, nm_i);
143260368Sluigi		for (n = 0; nm_i != head; n++) {
144259412Sluigi			struct netmap_slot *slot = &ring->slot[nm_i];
145259412Sluigi			u_int len = slot->len;
146229939Sluigi			uint64_t paddr;
147270063Sluigi			void *addr = PNMB(na, slot, &paddr);
148231778Sluigi
149259412Sluigi			/* device-specific */
150259412Sluigi			struct e1000_tx_desc *curr = &txr->tx_base[nic_i];
151293331Ssbruno			struct em_txbuffer *txbuf = &txr->tx_buffers[nic_i];
152259412Sluigi			int flags = (slot->flags & NS_REPORT ||
153259412Sluigi				nic_i == 0 || nic_i == report_frequency) ?
154259412Sluigi				E1000_TXD_CMD_RS : 0;
155227614Sluigi
156270063Sluigi			NM_CHECK_ADDR_LEN(na, addr, len);
157259412Sluigi
158227614Sluigi			if (slot->flags & NS_BUF_CHANGED) {
159229939Sluigi				curr->buffer_addr = htole64(paddr);
160228276Sluigi				/* buffer has changed, reload map */
161270063Sluigi				netmap_reload_map(na, txr->txtag, txbuf->map, addr);
162227614Sluigi			}
163259412Sluigi			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
164259412Sluigi
165259412Sluigi			/* Fill the slot in the NIC ring. */
166232238Sluigi			curr->upper.data = 0;
167232238Sluigi			curr->lower.data = htole32(adapter->txd_cmd | len |
168232238Sluigi				(E1000_TXD_CMD_EOP | flags) );
169227614Sluigi			bus_dmamap_sync(txr->txtag, txbuf->map,
170227614Sluigi				BUS_DMASYNC_PREWRITE);
171259412Sluigi
172259412Sluigi			nm_i = nm_next(nm_i, lim);
173259412Sluigi			nic_i = nm_next(nic_i, lim);
174227614Sluigi		}
175260368Sluigi		kring->nr_hwcur = head;
176227614Sluigi
177259412Sluigi		/* synchronize the NIC ring */
178227614Sluigi		bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
179259412Sluigi			BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
180227614Sluigi
181259412Sluigi		/* (re)start the tx unit up to slot nic_i (excluded) */
182259412Sluigi		E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), nic_i);
183227614Sluigi	}
184228276Sluigi
185259412Sluigi	/*
186259412Sluigi	 * Second part: reclaim buffers for completed transmissions.
187259412Sluigi	 */
188260368Sluigi	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
189231778Sluigi		/* record completed transmissions using TDH */
190270063Sluigi		nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(kring->ring_id));
191343771Svmaffione		if (unlikely(nic_i >= kring->nkr_num_slots)) {
192343771Svmaffione			nm_prerr("TDH wrap at idx %d", nic_i);
193259412Sluigi			nic_i -= kring->nkr_num_slots;
194228276Sluigi		}
195260368Sluigi		if (nic_i != txr->next_to_clean) {
196259412Sluigi			txr->next_to_clean = nic_i;
197260368Sluigi			kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
198228276Sluigi		}
199228276Sluigi	}
200228276Sluigi
201227614Sluigi	return 0;
202227614Sluigi}
203227614Sluigi
204231778Sluigi
205227614Sluigi/*
206228276Sluigi * Reconcile kernel and user view of the receive ring.
207227614Sluigi */
208227614Sluigistatic int
209270063Sluigiem_netmap_rxsync(struct netmap_kring *kring, int flags)
210227614Sluigi{
211270063Sluigi	struct netmap_adapter *na = kring->na;
212259412Sluigi	struct ifnet *ifp = na->ifp;
213227614Sluigi	struct netmap_ring *ring = kring->ring;
214259412Sluigi	u_int nm_i;	/* index into the netmap ring */
215259412Sluigi	u_int nic_i;	/* index into the NIC ring */
216260368Sluigi	u_int n;
217259412Sluigi	u_int const lim = kring->nkr_num_slots - 1;
218285349Sluigi	u_int const head = kring->rhead;
219257529Sluigi	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
220227614Sluigi
221259412Sluigi	/* device-specific */
222259412Sluigi	struct adapter *adapter = ifp->if_softc;
223270063Sluigi	struct rx_ring *rxr = &adapter->rx_rings[kring->ring_id];
224259412Sluigi
225260368Sluigi	if (head > lim)
226227614Sluigi		return netmap_ring_reinit(kring);
227250184Sluigi
228227614Sluigi	/* XXX check sync modes */
229227614Sluigi	bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
230227614Sluigi			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
231227614Sluigi
232232238Sluigi	/*
233259412Sluigi	 * First part: import newly received packets.
234228276Sluigi	 */
235232238Sluigi	if (netmap_no_pendintr || force_update) {
236259412Sluigi		nic_i = rxr->next_to_check;
237259412Sluigi		nm_i = netmap_idx_n2k(kring, nic_i);
238259412Sluigi
239260368Sluigi		for (n = 0; ; n++) { // XXX no need to count
240293331Ssbruno			union e1000_rx_desc_extended *curr = &rxr->rx_base[nic_i];
241293331Ssbruno			uint32_t staterr = le32toh(curr->wb.upper.status_error);
242227614Sluigi
243232238Sluigi			if ((staterr & E1000_RXD_STAT_DD) == 0)
244232238Sluigi				break;
245293331Ssbruno			ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
246341477Svmaffione			ring->slot[nm_i].flags = 0;
247259412Sluigi			bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[nic_i].map,
248232238Sluigi				BUS_DMASYNC_POSTREAD);
249259412Sluigi			nm_i = nm_next(nm_i, lim);
250232238Sluigi			/* make sure next_to_refresh follows next_to_check */
251259412Sluigi			rxr->next_to_refresh = nic_i;	// XXX
252259412Sluigi			nic_i = nm_next(nic_i, lim);
253232238Sluigi		}
254232238Sluigi		if (n) { /* update the state variables */
255259412Sluigi			rxr->next_to_check = nic_i;
256260368Sluigi			kring->nr_hwtail = nm_i;
257232238Sluigi		}
258232238Sluigi		kring->nr_kflags &= ~NKR_PENDINTR;
259227614Sluigi	}
260227614Sluigi
261259412Sluigi	/*
262259412Sluigi	 * Second part: skip past packets that userspace has released.
263259412Sluigi	 */
264259412Sluigi	nm_i = kring->nr_hwcur;
265260368Sluigi	if (nm_i != head) {
266259412Sluigi		nic_i = netmap_idx_k2n(kring, nm_i);
267260368Sluigi		for (n = 0; nm_i != head; n++) {
268259412Sluigi			struct netmap_slot *slot = &ring->slot[nm_i];
269229939Sluigi			uint64_t paddr;
270270063Sluigi			void *addr = PNMB(na, slot, &paddr);
271227614Sluigi
272293331Ssbruno			union e1000_rx_desc_extended *curr = &rxr->rx_base[nic_i];
273293331Ssbruno			struct em_rxbuffer *rxbuf = &rxr->rx_buffers[nic_i];
274227614Sluigi
275270063Sluigi			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
276259412Sluigi				goto ring_reset;
277259412Sluigi
278308131Ssbruno			curr->read.buffer_addr = htole64(paddr);
279227614Sluigi			if (slot->flags & NS_BUF_CHANGED) {
280259412Sluigi				/* buffer has changed, reload map */
281270063Sluigi				netmap_reload_map(na, rxr->rxtag, rxbuf->map, addr);
282227614Sluigi				slot->flags &= ~NS_BUF_CHANGED;
283227614Sluigi			}
284293331Ssbruno			curr->wb.upper.status_error = 0;
285227614Sluigi			bus_dmamap_sync(rxr->rxtag, rxbuf->map,
286228276Sluigi			    BUS_DMASYNC_PREREAD);
287259412Sluigi			nm_i = nm_next(nm_i, lim);
288259412Sluigi			nic_i = nm_next(nic_i, lim);
289227614Sluigi		}
290260368Sluigi		kring->nr_hwcur = head;
291259412Sluigi
292227614Sluigi		bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
293228276Sluigi		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
294227614Sluigi		/*
295227614Sluigi		 * IMPORTANT: we must leave one free slot in the ring,
296259412Sluigi		 * so move nic_i back by one unit
297227614Sluigi		 */
298260368Sluigi		nic_i = nm_prev(nic_i, lim);
299259412Sluigi		E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), nic_i);
300227614Sluigi	}
301259412Sluigi
302227614Sluigi	return 0;
303259412Sluigi
304259412Sluigiring_reset:
305259412Sluigi	return netmap_ring_reinit(kring);
306227614Sluigi}
307232238Sluigi
308232238Sluigi
309232238Sluigistatic void
310232238Sluigiem_netmap_attach(struct adapter *adapter)
311232238Sluigi{
312232238Sluigi	struct netmap_adapter na;
313232238Sluigi
314232238Sluigi	bzero(&na, sizeof(na));
315232238Sluigi
316232238Sluigi	na.ifp = adapter->ifp;
317257529Sluigi	na.na_flags = NAF_BDG_MAYSLEEP;
318232238Sluigi	na.num_tx_desc = adapter->num_tx_desc;
319232238Sluigi	na.num_rx_desc = adapter->num_rx_desc;
320232238Sluigi	na.nm_txsync = em_netmap_txsync;
321232238Sluigi	na.nm_rxsync = em_netmap_rxsync;
322232238Sluigi	na.nm_register = em_netmap_reg;
323259412Sluigi	na.num_tx_rings = na.num_rx_rings = adapter->num_queues;
324259412Sluigi	netmap_attach(&na);
325232238Sluigi}
326232238Sluigi
327231778Sluigi/* end of file */
328