xref: /freebsd/sys/dev/ixl/ixl_txrx.c (revision cb6b8299fdda0ccd5c9c9b0d29cd9c005f6d780b)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3b6c8f260SJack F Vogel   Copyright (c) 2013-2015, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel /*$FreeBSD$*/
3461ae650dSJack F Vogel 
3561ae650dSJack F Vogel /*
3661ae650dSJack F Vogel **	IXL driver TX/RX Routines:
3761ae650dSJack F Vogel **	    This was seperated to allow usage by
384294f337SSean Bruno ** 	    both the PF and VF drivers.
3961ae650dSJack F Vogel */
4061ae650dSJack F Vogel 
41b6c8f260SJack F Vogel #ifndef IXL_STANDALONE_BUILD
4261ae650dSJack F Vogel #include "opt_inet.h"
4361ae650dSJack F Vogel #include "opt_inet6.h"
44df1d7a71SJack F Vogel #include "opt_rss.h"
45b6c8f260SJack F Vogel #endif
46b6c8f260SJack F Vogel 
4761ae650dSJack F Vogel #include "ixl.h"
4861ae650dSJack F Vogel 
49dcd7b3b2SJack F Vogel #ifdef RSS
50dcd7b3b2SJack F Vogel #include <net/rss_config.h>
51dcd7b3b2SJack F Vogel #endif
52dcd7b3b2SJack F Vogel 
5361ae650dSJack F Vogel /* Local Prototypes */
5461ae650dSJack F Vogel static void	ixl_rx_checksum(struct mbuf *, u32, u32, u8);
5561ae650dSJack F Vogel static void	ixl_refresh_mbufs(struct ixl_queue *, int);
5661ae650dSJack F Vogel static int      ixl_xmit(struct ixl_queue *, struct mbuf **);
5761ae650dSJack F Vogel static int	ixl_tx_setup_offload(struct ixl_queue *,
5861ae650dSJack F Vogel 		    struct mbuf *, u32 *, u32 *);
5961ae650dSJack F Vogel static bool	ixl_tso_setup(struct ixl_queue *, struct mbuf *);
6061ae650dSJack F Vogel 
614294f337SSean Bruno static inline void ixl_rx_discard(struct rx_ring *, int);
624294f337SSean Bruno static inline void ixl_rx_input(struct rx_ring *, struct ifnet *,
6361ae650dSJack F Vogel 		    struct mbuf *, u8);
6461ae650dSJack F Vogel 
654294f337SSean Bruno static inline bool ixl_tso_detect_sparse(struct mbuf *mp);
664294f337SSean Bruno static int	ixl_tx_setup_offload(struct ixl_queue *que,
674294f337SSean Bruno     struct mbuf *mp, u32 *cmd, u32 *off);
684294f337SSean Bruno static inline u32 ixl_get_tx_head(struct ixl_queue *que);
694294f337SSean Bruno 
7031830672SJack F Vogel #ifdef DEV_NETMAP
7131830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
72ff9b61caSEric Joyner int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip = 1;
7331830672SJack F Vogel #endif /* DEV_NETMAP */
74bc8b78d3SLuigi Rizzo 
7561ae650dSJack F Vogel /*
764294f337SSean Bruno  * @key key is saved into this parameter
774294f337SSean Bruno  */
784294f337SSean Bruno void
794294f337SSean Bruno ixl_get_default_rss_key(u32 *key)
804294f337SSean Bruno {
814294f337SSean Bruno 	MPASS(key != NULL);
824294f337SSean Bruno 
834294f337SSean Bruno 	u32 rss_seed[IXL_RSS_KEY_SIZE_REG] = {0x41b01687,
844294f337SSean Bruno 	    0x183cfd8c, 0xce880440, 0x580cbc3c,
854294f337SSean Bruno 	    0x35897377, 0x328b25e1, 0x4fa98922,
864294f337SSean Bruno 	    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1,
874294f337SSean Bruno 	    0x0, 0x0, 0x0};
884294f337SSean Bruno 
894294f337SSean Bruno 	bcopy(rss_seed, key, IXL_RSS_KEY_SIZE);
904294f337SSean Bruno }
914294f337SSean Bruno 
924294f337SSean Bruno /*
9361ae650dSJack F Vogel ** Multiqueue Transmit driver
9461ae650dSJack F Vogel */
9561ae650dSJack F Vogel int
9661ae650dSJack F Vogel ixl_mq_start(struct ifnet *ifp, struct mbuf *m)
9761ae650dSJack F Vogel {
9861ae650dSJack F Vogel 	struct ixl_vsi		*vsi = ifp->if_softc;
9961ae650dSJack F Vogel 	struct ixl_queue	*que;
10061ae650dSJack F Vogel 	struct tx_ring		*txr;
10161ae650dSJack F Vogel 	int 			err, i;
102845a028fSJack F Vogel #ifdef RSS
103845a028fSJack F Vogel 	u32			bucket_id;
104845a028fSJack F Vogel #endif
10561ae650dSJack F Vogel 
106845a028fSJack F Vogel 	/*
107845a028fSJack F Vogel 	** Which queue to use:
108845a028fSJack F Vogel 	**
109845a028fSJack F Vogel 	** When doing RSS, map it to the same outbound
110845a028fSJack F Vogel 	** queue as the incoming flow would be mapped to.
111845a028fSJack F Vogel 	** If everything is setup correctly, it should be
112845a028fSJack F Vogel 	** the same bucket that the current CPU we're on is.
113845a028fSJack F Vogel 	*/
114845a028fSJack F Vogel 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
115845a028fSJack F Vogel #ifdef  RSS
116845a028fSJack F Vogel 		if (rss_hash2bucket(m->m_pkthdr.flowid,
117845a028fSJack F Vogel 		    M_HASHTYPE_GET(m), &bucket_id) == 0) {
118845a028fSJack F Vogel 			i = bucket_id % vsi->num_queues;
119845a028fSJack F Vogel                 } else
120845a028fSJack F Vogel #endif
12161ae650dSJack F Vogel                         i = m->m_pkthdr.flowid % vsi->num_queues;
122845a028fSJack F Vogel         } else
12361ae650dSJack F Vogel 		i = curcpu % vsi->num_queues;
12461ae650dSJack F Vogel 
12561ae650dSJack F Vogel 	que = &vsi->queues[i];
12661ae650dSJack F Vogel 	txr = &que->txr;
12761ae650dSJack F Vogel 
12861ae650dSJack F Vogel 	err = drbr_enqueue(ifp, txr->br, m);
12961ae650dSJack F Vogel 	if (err)
13061ae650dSJack F Vogel 		return (err);
13161ae650dSJack F Vogel 	if (IXL_TX_TRYLOCK(txr)) {
13261ae650dSJack F Vogel 		ixl_mq_start_locked(ifp, txr);
13361ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
13461ae650dSJack F Vogel 	} else
13561ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->tx_task);
13661ae650dSJack F Vogel 
13761ae650dSJack F Vogel 	return (0);
13861ae650dSJack F Vogel }
13961ae650dSJack F Vogel 
14061ae650dSJack F Vogel int
14161ae650dSJack F Vogel ixl_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr)
14261ae650dSJack F Vogel {
14361ae650dSJack F Vogel 	struct ixl_queue	*que = txr->que;
14461ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
14561ae650dSJack F Vogel         struct mbuf		*next;
14661ae650dSJack F Vogel         int			err = 0;
14761ae650dSJack F Vogel 
14861ae650dSJack F Vogel 
14961ae650dSJack F Vogel 	if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) ||
15061ae650dSJack F Vogel 	    vsi->link_active == 0)
15161ae650dSJack F Vogel 		return (ENETDOWN);
15261ae650dSJack F Vogel 
15361ae650dSJack F Vogel 	/* Process the transmit queue */
15461ae650dSJack F Vogel 	while ((next = drbr_peek(ifp, txr->br)) != NULL) {
15561ae650dSJack F Vogel 		if ((err = ixl_xmit(que, &next)) != 0) {
15661ae650dSJack F Vogel 			if (next == NULL)
15761ae650dSJack F Vogel 				drbr_advance(ifp, txr->br);
15861ae650dSJack F Vogel 			else
15961ae650dSJack F Vogel 				drbr_putback(ifp, txr->br, next);
16061ae650dSJack F Vogel 			break;
16161ae650dSJack F Vogel 		}
16261ae650dSJack F Vogel 		drbr_advance(ifp, txr->br);
16361ae650dSJack F Vogel 		/* Send a copy of the frame to the BPF listener */
16461ae650dSJack F Vogel 		ETHER_BPF_MTAP(ifp, next);
16561ae650dSJack F Vogel 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
16661ae650dSJack F Vogel 			break;
16761ae650dSJack F Vogel 	}
16861ae650dSJack F Vogel 
16961ae650dSJack F Vogel 	if (txr->avail < IXL_TX_CLEANUP_THRESHOLD)
17061ae650dSJack F Vogel 		ixl_txeof(que);
17161ae650dSJack F Vogel 
17261ae650dSJack F Vogel 	return (err);
17361ae650dSJack F Vogel }
17461ae650dSJack F Vogel 
17561ae650dSJack F Vogel /*
17661ae650dSJack F Vogel  * Called from a taskqueue to drain queued transmit packets.
17761ae650dSJack F Vogel  */
17861ae650dSJack F Vogel void
17961ae650dSJack F Vogel ixl_deferred_mq_start(void *arg, int pending)
18061ae650dSJack F Vogel {
18161ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
18261ae650dSJack F Vogel         struct tx_ring		*txr = &que->txr;
18361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
18461ae650dSJack F Vogel         struct ifnet		*ifp = vsi->ifp;
18561ae650dSJack F Vogel 
18661ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
18761ae650dSJack F Vogel 	if (!drbr_empty(ifp, txr->br))
18861ae650dSJack F Vogel 		ixl_mq_start_locked(ifp, txr);
18961ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
19061ae650dSJack F Vogel }
19161ae650dSJack F Vogel 
19261ae650dSJack F Vogel /*
19361ae650dSJack F Vogel ** Flush all queue ring buffers
19461ae650dSJack F Vogel */
19561ae650dSJack F Vogel void
19661ae650dSJack F Vogel ixl_qflush(struct ifnet *ifp)
19761ae650dSJack F Vogel {
19861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
19961ae650dSJack F Vogel 
20061ae650dSJack F Vogel         for (int i = 0; i < vsi->num_queues; i++) {
20161ae650dSJack F Vogel 		struct ixl_queue *que = &vsi->queues[i];
20261ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
20361ae650dSJack F Vogel 		struct mbuf	*m;
20461ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
20561ae650dSJack F Vogel 		while ((m = buf_ring_dequeue_sc(txr->br)) != NULL)
20661ae650dSJack F Vogel 			m_freem(m);
20761ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
20861ae650dSJack F Vogel 	}
20961ae650dSJack F Vogel 	if_qflush(ifp);
21061ae650dSJack F Vogel }
21161ae650dSJack F Vogel 
21261ae650dSJack F Vogel /*
21361ae650dSJack F Vogel ** Find mbuf chains passed to the driver
21461ae650dSJack F Vogel ** that are 'sparse', using more than 8
21561ae650dSJack F Vogel ** mbufs to deliver an mss-size chunk of data
21661ae650dSJack F Vogel */
21761ae650dSJack F Vogel static inline bool
21861ae650dSJack F Vogel ixl_tso_detect_sparse(struct mbuf *mp)
21961ae650dSJack F Vogel {
22061ae650dSJack F Vogel 	struct mbuf	*m;
221*cb6b8299SEric Joyner 	int		num, mss;
22261ae650dSJack F Vogel 
223*cb6b8299SEric Joyner 	num = 0;
22461ae650dSJack F Vogel 	mss = mp->m_pkthdr.tso_segsz;
22561ae650dSJack F Vogel 
226*cb6b8299SEric Joyner 	/* Exclude first mbuf; assume it contains all headers */
227*cb6b8299SEric Joyner 	for (m = mp->m_next; m != NULL; m = m->m_next) {
228*cb6b8299SEric Joyner 		if (m == NULL)
229*cb6b8299SEric Joyner 			break;
230*cb6b8299SEric Joyner 		num++;
231*cb6b8299SEric Joyner 		mss -= m->m_len % mp->m_pkthdr.tso_segsz;
232*cb6b8299SEric Joyner 
233*cb6b8299SEric Joyner 		if (mss < 1) {
234*cb6b8299SEric Joyner 			if (num > IXL_SPARSE_CHAIN)
235*cb6b8299SEric Joyner 				return (true);
236*cb6b8299SEric Joyner 			num = (mss == 0) ? 0 : 1;
237*cb6b8299SEric Joyner 			mss += mp->m_pkthdr.tso_segsz;
238*cb6b8299SEric Joyner 		}
239*cb6b8299SEric Joyner 	}
240*cb6b8299SEric Joyner 
241*cb6b8299SEric Joyner 	return (false);
24261ae650dSJack F Vogel }
24361ae650dSJack F Vogel 
24461ae650dSJack F Vogel 
24561ae650dSJack F Vogel /*********************************************************************
24661ae650dSJack F Vogel  *
24761ae650dSJack F Vogel  *  This routine maps the mbufs to tx descriptors, allowing the
24861ae650dSJack F Vogel  *  TX engine to transmit the packets.
24961ae650dSJack F Vogel  *  	- return 0 on success, positive on failure
25061ae650dSJack F Vogel  *
25161ae650dSJack F Vogel  **********************************************************************/
25261ae650dSJack F Vogel #define IXL_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
25361ae650dSJack F Vogel 
25461ae650dSJack F Vogel static int
25561ae650dSJack F Vogel ixl_xmit(struct ixl_queue *que, struct mbuf **m_headp)
25661ae650dSJack F Vogel {
25761ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
25861ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
25961ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
26061ae650dSJack F Vogel 	struct ixl_tx_buf	*buf;
26161ae650dSJack F Vogel 	struct i40e_tx_desc	*txd = NULL;
26261ae650dSJack F Vogel 	struct mbuf		*m_head, *m;
2634294f337SSean Bruno 	int             	i, j, error, nsegs;
26461ae650dSJack F Vogel 	int			first, last = 0;
26561ae650dSJack F Vogel 	u16			vtag = 0;
26661ae650dSJack F Vogel 	u32			cmd, off;
26761ae650dSJack F Vogel 	bus_dmamap_t		map;
26861ae650dSJack F Vogel 	bus_dma_tag_t		tag;
26961ae650dSJack F Vogel 	bus_dma_segment_t	segs[IXL_MAX_TSO_SEGS];
27061ae650dSJack F Vogel 
27161ae650dSJack F Vogel 	cmd = off = 0;
27261ae650dSJack F Vogel 	m_head = *m_headp;
27361ae650dSJack F Vogel 
27461ae650dSJack F Vogel         /*
27561ae650dSJack F Vogel          * Important to capture the first descriptor
27661ae650dSJack F Vogel          * used because it will contain the index of
27761ae650dSJack F Vogel          * the one we tell the hardware to report back
27861ae650dSJack F Vogel          */
27961ae650dSJack F Vogel         first = txr->next_avail;
28061ae650dSJack F Vogel 	buf = &txr->buffers[first];
28161ae650dSJack F Vogel 	map = buf->map;
28261ae650dSJack F Vogel 	tag = txr->tx_tag;
28361ae650dSJack F Vogel 
28461ae650dSJack F Vogel 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
28561ae650dSJack F Vogel 		/* Use larger mapping for TSO */
28661ae650dSJack F Vogel 		tag = txr->tso_tag;
28761ae650dSJack F Vogel 		if (ixl_tso_detect_sparse(m_head)) {
28861ae650dSJack F Vogel 			m = m_defrag(m_head, M_NOWAIT);
289e5100ee2SJack F Vogel 			if (m == NULL) {
290e5100ee2SJack F Vogel 				m_freem(*m_headp);
291e5100ee2SJack F Vogel 				*m_headp = NULL;
292e5100ee2SJack F Vogel 				return (ENOBUFS);
293e5100ee2SJack F Vogel 			}
29461ae650dSJack F Vogel 			*m_headp = m;
29561ae650dSJack F Vogel 		}
29661ae650dSJack F Vogel 	}
29761ae650dSJack F Vogel 
29861ae650dSJack F Vogel 	/*
29961ae650dSJack F Vogel 	 * Map the packet for DMA.
30061ae650dSJack F Vogel 	 */
30161ae650dSJack F Vogel 	error = bus_dmamap_load_mbuf_sg(tag, map,
30261ae650dSJack F Vogel 	    *m_headp, segs, &nsegs, BUS_DMA_NOWAIT);
30361ae650dSJack F Vogel 
30461ae650dSJack F Vogel 	if (error == EFBIG) {
30561ae650dSJack F Vogel 		struct mbuf *m;
30661ae650dSJack F Vogel 
3076d011ad5SEric Joyner 		m = m_defrag(*m_headp, M_NOWAIT);
30861ae650dSJack F Vogel 		if (m == NULL) {
30961ae650dSJack F Vogel 			que->mbuf_defrag_failed++;
31061ae650dSJack F Vogel 			m_freem(*m_headp);
31161ae650dSJack F Vogel 			*m_headp = NULL;
31261ae650dSJack F Vogel 			return (ENOBUFS);
31361ae650dSJack F Vogel 		}
31461ae650dSJack F Vogel 		*m_headp = m;
31561ae650dSJack F Vogel 
31661ae650dSJack F Vogel 		/* Try it again */
31761ae650dSJack F Vogel 		error = bus_dmamap_load_mbuf_sg(tag, map,
31861ae650dSJack F Vogel 		    *m_headp, segs, &nsegs, BUS_DMA_NOWAIT);
31961ae650dSJack F Vogel 
320*cb6b8299SEric Joyner 		if (error != 0) {
3214294f337SSean Bruno 			que->tx_dmamap_failed++;
32261ae650dSJack F Vogel 			m_freem(*m_headp);
32361ae650dSJack F Vogel 			*m_headp = NULL;
32461ae650dSJack F Vogel 			return (error);
32561ae650dSJack F Vogel 		}
32661ae650dSJack F Vogel 	} else if (error != 0) {
3274294f337SSean Bruno 		que->tx_dmamap_failed++;
32861ae650dSJack F Vogel 		m_freem(*m_headp);
32961ae650dSJack F Vogel 		*m_headp = NULL;
33061ae650dSJack F Vogel 		return (error);
33161ae650dSJack F Vogel 	}
33261ae650dSJack F Vogel 
33361ae650dSJack F Vogel 	/* Make certain there are enough descriptors */
33461ae650dSJack F Vogel 	if (nsegs > txr->avail - 2) {
33561ae650dSJack F Vogel 		txr->no_desc++;
33661ae650dSJack F Vogel 		error = ENOBUFS;
33761ae650dSJack F Vogel 		goto xmit_fail;
33861ae650dSJack F Vogel 	}
33961ae650dSJack F Vogel 	m_head = *m_headp;
34061ae650dSJack F Vogel 
34161ae650dSJack F Vogel 	/* Set up the TSO/CSUM offload */
34261ae650dSJack F Vogel 	if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) {
34361ae650dSJack F Vogel 		error = ixl_tx_setup_offload(que, m_head, &cmd, &off);
34461ae650dSJack F Vogel 		if (error)
34561ae650dSJack F Vogel 			goto xmit_fail;
34661ae650dSJack F Vogel 	}
34761ae650dSJack F Vogel 
34861ae650dSJack F Vogel 	cmd |= I40E_TX_DESC_CMD_ICRC;
34961ae650dSJack F Vogel 	/* Grab the VLAN tag */
35061ae650dSJack F Vogel 	if (m_head->m_flags & M_VLANTAG) {
35161ae650dSJack F Vogel 		cmd |= I40E_TX_DESC_CMD_IL2TAG1;
35261ae650dSJack F Vogel 		vtag = htole16(m_head->m_pkthdr.ether_vtag);
35361ae650dSJack F Vogel 	}
35461ae650dSJack F Vogel 
35561ae650dSJack F Vogel 	i = txr->next_avail;
35661ae650dSJack F Vogel 	for (j = 0; j < nsegs; j++) {
35761ae650dSJack F Vogel 		bus_size_t seglen;
35861ae650dSJack F Vogel 
35961ae650dSJack F Vogel 		buf = &txr->buffers[i];
36061ae650dSJack F Vogel 		buf->tag = tag; /* Keep track of the type tag */
36161ae650dSJack F Vogel 		txd = &txr->base[i];
36261ae650dSJack F Vogel 		seglen = segs[j].ds_len;
36361ae650dSJack F Vogel 
36461ae650dSJack F Vogel 		txd->buffer_addr = htole64(segs[j].ds_addr);
36561ae650dSJack F Vogel 		txd->cmd_type_offset_bsz =
36661ae650dSJack F Vogel 		    htole64(I40E_TX_DESC_DTYPE_DATA
36761ae650dSJack F Vogel 		    | ((u64)cmd  << I40E_TXD_QW1_CMD_SHIFT)
36861ae650dSJack F Vogel 		    | ((u64)off << I40E_TXD_QW1_OFFSET_SHIFT)
36961ae650dSJack F Vogel 		    | ((u64)seglen  << I40E_TXD_QW1_TX_BUF_SZ_SHIFT)
37061ae650dSJack F Vogel 		    | ((u64)vtag  << I40E_TXD_QW1_L2TAG1_SHIFT));
37161ae650dSJack F Vogel 
37261ae650dSJack F Vogel 		last = i; /* descriptor that will get completion IRQ */
37361ae650dSJack F Vogel 
37461ae650dSJack F Vogel 		if (++i == que->num_desc)
37561ae650dSJack F Vogel 			i = 0;
37661ae650dSJack F Vogel 
37761ae650dSJack F Vogel 		buf->m_head = NULL;
37861ae650dSJack F Vogel 		buf->eop_index = -1;
37961ae650dSJack F Vogel 	}
38061ae650dSJack F Vogel 	/* Set the last descriptor for report */
38161ae650dSJack F Vogel 	txd->cmd_type_offset_bsz |=
38261ae650dSJack F Vogel 	    htole64(((u64)IXL_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT));
38361ae650dSJack F Vogel 	txr->avail -= nsegs;
38461ae650dSJack F Vogel 	txr->next_avail = i;
38561ae650dSJack F Vogel 
38661ae650dSJack F Vogel 	buf->m_head = m_head;
38761ae650dSJack F Vogel 	/* Swap the dma map between the first and last descriptor */
38861ae650dSJack F Vogel 	txr->buffers[first].map = buf->map;
38961ae650dSJack F Vogel 	buf->map = map;
39061ae650dSJack F Vogel 	bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE);
39161ae650dSJack F Vogel 
39261ae650dSJack F Vogel         /* Set the index of the descriptor that will be marked done */
39361ae650dSJack F Vogel         buf = &txr->buffers[first];
39461ae650dSJack F Vogel 	buf->eop_index = last;
39561ae650dSJack F Vogel 
39661ae650dSJack F Vogel         bus_dmamap_sync(txr->dma.tag, txr->dma.map,
39761ae650dSJack F Vogel             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
39861ae650dSJack F Vogel 	/*
39961ae650dSJack F Vogel 	 * Advance the Transmit Descriptor Tail (Tdt), this tells the
40061ae650dSJack F Vogel 	 * hardware that this frame is available to transmit.
40161ae650dSJack F Vogel 	 */
40261ae650dSJack F Vogel 	++txr->total_packets;
40361ae650dSJack F Vogel 	wr32(hw, txr->tail, i);
40461ae650dSJack F Vogel 
40561ae650dSJack F Vogel 	/* Mark outstanding work */
406*cb6b8299SEric Joyner 	atomic_store_rel_32(&txr->watchdog_timer, IXL_WATCHDOG);
40761ae650dSJack F Vogel 	return (0);
40861ae650dSJack F Vogel 
40961ae650dSJack F Vogel xmit_fail:
41061ae650dSJack F Vogel 	bus_dmamap_unload(tag, buf->map);
41161ae650dSJack F Vogel 	return (error);
41261ae650dSJack F Vogel }
41361ae650dSJack F Vogel 
41461ae650dSJack F Vogel 
41561ae650dSJack F Vogel /*********************************************************************
41661ae650dSJack F Vogel  *
41761ae650dSJack F Vogel  *  Allocate memory for tx_buffer structures. The tx_buffer stores all
41861ae650dSJack F Vogel  *  the information needed to transmit a packet on the wire. This is
41961ae650dSJack F Vogel  *  called only once at attach, setup is done every reset.
42061ae650dSJack F Vogel  *
42161ae650dSJack F Vogel  **********************************************************************/
42261ae650dSJack F Vogel int
42361ae650dSJack F Vogel ixl_allocate_tx_data(struct ixl_queue *que)
42461ae650dSJack F Vogel {
42561ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
42661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
42761ae650dSJack F Vogel 	device_t		dev = vsi->dev;
42861ae650dSJack F Vogel 	struct ixl_tx_buf	*buf;
42961ae650dSJack F Vogel 	int			error = 0;
43061ae650dSJack F Vogel 
43161ae650dSJack F Vogel 	/*
43261ae650dSJack F Vogel 	 * Setup DMA descriptor areas.
43361ae650dSJack F Vogel 	 */
43461ae650dSJack F Vogel 	if ((error = bus_dma_tag_create(NULL,		/* parent */
43561ae650dSJack F Vogel 			       1, 0,			/* alignment, bounds */
43661ae650dSJack F Vogel 			       BUS_SPACE_MAXADDR,	/* lowaddr */
43761ae650dSJack F Vogel 			       BUS_SPACE_MAXADDR,	/* highaddr */
43861ae650dSJack F Vogel 			       NULL, NULL,		/* filter, filterarg */
43961ae650dSJack F Vogel 			       IXL_TSO_SIZE,		/* maxsize */
44061ae650dSJack F Vogel 			       IXL_MAX_TX_SEGS,		/* nsegments */
44161ae650dSJack F Vogel 			       PAGE_SIZE,		/* maxsegsize */
44261ae650dSJack F Vogel 			       0,			/* flags */
44361ae650dSJack F Vogel 			       NULL,			/* lockfunc */
44461ae650dSJack F Vogel 			       NULL,			/* lockfuncarg */
44561ae650dSJack F Vogel 			       &txr->tx_tag))) {
44661ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate TX DMA tag\n");
44761ae650dSJack F Vogel 		goto fail;
44861ae650dSJack F Vogel 	}
44961ae650dSJack F Vogel 
45061ae650dSJack F Vogel 	/* Make a special tag for TSO */
45161ae650dSJack F Vogel 	if ((error = bus_dma_tag_create(NULL,		/* parent */
45261ae650dSJack F Vogel 			       1, 0,			/* alignment, bounds */
45361ae650dSJack F Vogel 			       BUS_SPACE_MAXADDR,	/* lowaddr */
45461ae650dSJack F Vogel 			       BUS_SPACE_MAXADDR,	/* highaddr */
45561ae650dSJack F Vogel 			       NULL, NULL,		/* filter, filterarg */
45661ae650dSJack F Vogel 			       IXL_TSO_SIZE,		/* maxsize */
45761ae650dSJack F Vogel 			       IXL_MAX_TSO_SEGS,	/* nsegments */
45861ae650dSJack F Vogel 			       PAGE_SIZE,		/* maxsegsize */
45961ae650dSJack F Vogel 			       0,			/* flags */
46061ae650dSJack F Vogel 			       NULL,			/* lockfunc */
46161ae650dSJack F Vogel 			       NULL,			/* lockfuncarg */
46261ae650dSJack F Vogel 			       &txr->tso_tag))) {
46361ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate TX TSO DMA tag\n");
46461ae650dSJack F Vogel 		goto fail;
46561ae650dSJack F Vogel 	}
46661ae650dSJack F Vogel 
46761ae650dSJack F Vogel 	if (!(txr->buffers =
46861ae650dSJack F Vogel 	    (struct ixl_tx_buf *) malloc(sizeof(struct ixl_tx_buf) *
46961ae650dSJack F Vogel 	    que->num_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) {
47061ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate tx_buffer memory\n");
47161ae650dSJack F Vogel 		error = ENOMEM;
47261ae650dSJack F Vogel 		goto fail;
47361ae650dSJack F Vogel 	}
47461ae650dSJack F Vogel 
47561ae650dSJack F Vogel         /* Create the descriptor buffer default dma maps */
47661ae650dSJack F Vogel 	buf = txr->buffers;
47761ae650dSJack F Vogel 	for (int i = 0; i < que->num_desc; i++, buf++) {
47861ae650dSJack F Vogel 		buf->tag = txr->tx_tag;
47961ae650dSJack F Vogel 		error = bus_dmamap_create(buf->tag, 0, &buf->map);
48061ae650dSJack F Vogel 		if (error != 0) {
48161ae650dSJack F Vogel 			device_printf(dev, "Unable to create TX DMA map\n");
48261ae650dSJack F Vogel 			goto fail;
48361ae650dSJack F Vogel 		}
48461ae650dSJack F Vogel 	}
48561ae650dSJack F Vogel fail:
48661ae650dSJack F Vogel 	return (error);
48761ae650dSJack F Vogel }
48861ae650dSJack F Vogel 
48961ae650dSJack F Vogel 
49061ae650dSJack F Vogel /*********************************************************************
49161ae650dSJack F Vogel  *
49261ae650dSJack F Vogel  *  (Re)Initialize a queue transmit ring.
49361ae650dSJack F Vogel  *	- called by init, it clears the descriptor ring,
49461ae650dSJack F Vogel  *	  and frees any stale mbufs
49561ae650dSJack F Vogel  *
49661ae650dSJack F Vogel  **********************************************************************/
49761ae650dSJack F Vogel void
49861ae650dSJack F Vogel ixl_init_tx_ring(struct ixl_queue *que)
49961ae650dSJack F Vogel {
50031830672SJack F Vogel #ifdef DEV_NETMAP
50131830672SJack F Vogel 	struct netmap_adapter *na = NA(que->vsi->ifp);
50231830672SJack F Vogel 	struct netmap_slot *slot;
50331830672SJack F Vogel #endif /* DEV_NETMAP */
50461ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
50561ae650dSJack F Vogel 	struct ixl_tx_buf	*buf;
50661ae650dSJack F Vogel 
50761ae650dSJack F Vogel 	/* Clear the old ring contents */
50861ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
50956c2c47bSJack F Vogel 
51031830672SJack F Vogel #ifdef DEV_NETMAP
51131830672SJack F Vogel 	/*
51231830672SJack F Vogel 	 * (under lock): if in netmap mode, do some consistency
51331830672SJack F Vogel 	 * checks and set slot to entry 0 of the netmap ring.
51431830672SJack F Vogel 	 */
51531830672SJack F Vogel 	slot = netmap_reset(na, NR_TX, que->me, 0);
51631830672SJack F Vogel #endif /* DEV_NETMAP */
517bc8b78d3SLuigi Rizzo 
51861ae650dSJack F Vogel 	bzero((void *)txr->base,
51961ae650dSJack F Vogel 	      (sizeof(struct i40e_tx_desc)) * que->num_desc);
52061ae650dSJack F Vogel 
52161ae650dSJack F Vogel 	/* Reset indices */
52261ae650dSJack F Vogel 	txr->next_avail = 0;
52361ae650dSJack F Vogel 	txr->next_to_clean = 0;
52461ae650dSJack F Vogel 
525*cb6b8299SEric Joyner 	/* Reset watchdog status */
526*cb6b8299SEric Joyner 	txr->watchdog_timer = 0;
527*cb6b8299SEric Joyner 
52861ae650dSJack F Vogel #ifdef IXL_FDIR
52961ae650dSJack F Vogel 	/* Initialize flow director */
53061ae650dSJack F Vogel 	txr->atr_rate = ixl_atr_rate;
53161ae650dSJack F Vogel 	txr->atr_count = 0;
53261ae650dSJack F Vogel #endif
53361ae650dSJack F Vogel 	/* Free any existing tx mbufs. */
53461ae650dSJack F Vogel         buf = txr->buffers;
53561ae650dSJack F Vogel 	for (int i = 0; i < que->num_desc; i++, buf++) {
53661ae650dSJack F Vogel 		if (buf->m_head != NULL) {
53761ae650dSJack F Vogel 			bus_dmamap_sync(buf->tag, buf->map,
53861ae650dSJack F Vogel 			    BUS_DMASYNC_POSTWRITE);
53961ae650dSJack F Vogel 			bus_dmamap_unload(buf->tag, buf->map);
54061ae650dSJack F Vogel 			m_freem(buf->m_head);
54161ae650dSJack F Vogel 			buf->m_head = NULL;
54261ae650dSJack F Vogel 		}
54331830672SJack F Vogel #ifdef DEV_NETMAP
54431830672SJack F Vogel 		/*
54531830672SJack F Vogel 		 * In netmap mode, set the map for the packet buffer.
54631830672SJack F Vogel 		 * NOTE: Some drivers (not this one) also need to set
54731830672SJack F Vogel 		 * the physical buffer address in the NIC ring.
54831830672SJack F Vogel 		 * netmap_idx_n2k() maps a nic index, i, into the corresponding
54931830672SJack F Vogel 		 * netmap slot index, si
55031830672SJack F Vogel 		 */
55131830672SJack F Vogel 		if (slot) {
55231830672SJack F Vogel 			int si = netmap_idx_n2k(&na->tx_rings[que->me], i);
55331830672SJack F Vogel 			netmap_load_map(na, buf->tag, buf->map, NMB(na, slot + si));
55431830672SJack F Vogel 		}
55531830672SJack F Vogel #endif /* DEV_NETMAP */
55661ae650dSJack F Vogel 		/* Clear the EOP index */
55761ae650dSJack F Vogel 		buf->eop_index = -1;
55861ae650dSJack F Vogel         }
55961ae650dSJack F Vogel 
56061ae650dSJack F Vogel 	/* Set number of descriptors available */
56161ae650dSJack F Vogel 	txr->avail = que->num_desc;
56261ae650dSJack F Vogel 
56361ae650dSJack F Vogel 	bus_dmamap_sync(txr->dma.tag, txr->dma.map,
56461ae650dSJack F Vogel 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
56561ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
56661ae650dSJack F Vogel }
56761ae650dSJack F Vogel 
56861ae650dSJack F Vogel 
56961ae650dSJack F Vogel /*********************************************************************
57061ae650dSJack F Vogel  *
57161ae650dSJack F Vogel  *  Free transmit ring related data structures.
57261ae650dSJack F Vogel  *
57361ae650dSJack F Vogel  **********************************************************************/
57461ae650dSJack F Vogel void
57561ae650dSJack F Vogel ixl_free_que_tx(struct ixl_queue *que)
57661ae650dSJack F Vogel {
57761ae650dSJack F Vogel 	struct tx_ring *txr = &que->txr;
57861ae650dSJack F Vogel 	struct ixl_tx_buf *buf;
57961ae650dSJack F Vogel 
58061ae650dSJack F Vogel 	INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me);
58161ae650dSJack F Vogel 
58261ae650dSJack F Vogel 	for (int i = 0; i < que->num_desc; i++) {
58361ae650dSJack F Vogel 		buf = &txr->buffers[i];
58461ae650dSJack F Vogel 		if (buf->m_head != NULL) {
58561ae650dSJack F Vogel 			bus_dmamap_sync(buf->tag, buf->map,
58661ae650dSJack F Vogel 			    BUS_DMASYNC_POSTWRITE);
58761ae650dSJack F Vogel 			bus_dmamap_unload(buf->tag,
58861ae650dSJack F Vogel 			    buf->map);
58961ae650dSJack F Vogel 			m_freem(buf->m_head);
59061ae650dSJack F Vogel 			buf->m_head = NULL;
59161ae650dSJack F Vogel 			if (buf->map != NULL) {
59261ae650dSJack F Vogel 				bus_dmamap_destroy(buf->tag,
59361ae650dSJack F Vogel 				    buf->map);
59461ae650dSJack F Vogel 				buf->map = NULL;
59561ae650dSJack F Vogel 			}
59661ae650dSJack F Vogel 		} else if (buf->map != NULL) {
59761ae650dSJack F Vogel 			bus_dmamap_unload(buf->tag,
59861ae650dSJack F Vogel 			    buf->map);
59961ae650dSJack F Vogel 			bus_dmamap_destroy(buf->tag,
60061ae650dSJack F Vogel 			    buf->map);
60161ae650dSJack F Vogel 			buf->map = NULL;
60261ae650dSJack F Vogel 		}
60361ae650dSJack F Vogel 	}
60461ae650dSJack F Vogel 	if (txr->br != NULL)
60561ae650dSJack F Vogel 		buf_ring_free(txr->br, M_DEVBUF);
60661ae650dSJack F Vogel 	if (txr->buffers != NULL) {
60761ae650dSJack F Vogel 		free(txr->buffers, M_DEVBUF);
60861ae650dSJack F Vogel 		txr->buffers = NULL;
60961ae650dSJack F Vogel 	}
61061ae650dSJack F Vogel 	if (txr->tx_tag != NULL) {
61161ae650dSJack F Vogel 		bus_dma_tag_destroy(txr->tx_tag);
61261ae650dSJack F Vogel 		txr->tx_tag = NULL;
61361ae650dSJack F Vogel 	}
61461ae650dSJack F Vogel 	if (txr->tso_tag != NULL) {
61561ae650dSJack F Vogel 		bus_dma_tag_destroy(txr->tso_tag);
61661ae650dSJack F Vogel 		txr->tso_tag = NULL;
61761ae650dSJack F Vogel 	}
61861ae650dSJack F Vogel 
61961ae650dSJack F Vogel 	INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me);
62061ae650dSJack F Vogel 	return;
62161ae650dSJack F Vogel }
62261ae650dSJack F Vogel 
62361ae650dSJack F Vogel /*********************************************************************
62461ae650dSJack F Vogel  *
62561ae650dSJack F Vogel  *  Setup descriptor for hw offloads
62661ae650dSJack F Vogel  *
62761ae650dSJack F Vogel  **********************************************************************/
62861ae650dSJack F Vogel 
62961ae650dSJack F Vogel static int
63061ae650dSJack F Vogel ixl_tx_setup_offload(struct ixl_queue *que,
63161ae650dSJack F Vogel     struct mbuf *mp, u32 *cmd, u32 *off)
63261ae650dSJack F Vogel {
63361ae650dSJack F Vogel 	struct ether_vlan_header	*eh;
6341f873f18SJack F Vogel #ifdef INET
63561ae650dSJack F Vogel 	struct ip			*ip = NULL;
6361f873f18SJack F Vogel #endif
63761ae650dSJack F Vogel 	struct tcphdr			*th = NULL;
6381f873f18SJack F Vogel #ifdef INET6
63961ae650dSJack F Vogel 	struct ip6_hdr			*ip6;
6401f873f18SJack F Vogel #endif
64161ae650dSJack F Vogel 	int				elen, ip_hlen = 0, tcp_hlen;
64261ae650dSJack F Vogel 	u16				etype;
64361ae650dSJack F Vogel 	u8				ipproto = 0;
64461ae650dSJack F Vogel 	bool				tso = FALSE;
64561ae650dSJack F Vogel 
64661ae650dSJack F Vogel 	/* Set up the TSO context descriptor if required */
64761ae650dSJack F Vogel 	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
64861ae650dSJack F Vogel 		tso = ixl_tso_setup(que, mp);
64961ae650dSJack F Vogel 		if (tso)
65061ae650dSJack F Vogel 			++que->tso;
65161ae650dSJack F Vogel 		else
65261ae650dSJack F Vogel 			return (ENXIO);
65361ae650dSJack F Vogel 	}
65461ae650dSJack F Vogel 
65561ae650dSJack F Vogel 	/*
65661ae650dSJack F Vogel 	 * Determine where frame payload starts.
65761ae650dSJack F Vogel 	 * Jump over vlan headers if already present,
65861ae650dSJack F Vogel 	 * helpful for QinQ too.
65961ae650dSJack F Vogel 	 */
66061ae650dSJack F Vogel 	eh = mtod(mp, struct ether_vlan_header *);
66161ae650dSJack F Vogel 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
66261ae650dSJack F Vogel 		etype = ntohs(eh->evl_proto);
66361ae650dSJack F Vogel 		elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
66461ae650dSJack F Vogel 	} else {
66561ae650dSJack F Vogel 		etype = ntohs(eh->evl_encap_proto);
66661ae650dSJack F Vogel 		elen = ETHER_HDR_LEN;
66761ae650dSJack F Vogel 	}
66861ae650dSJack F Vogel 
66961ae650dSJack F Vogel 	switch (etype) {
6702f4959abSJack F Vogel #ifdef INET
671b555c614SBjoern A. Zeeb 		case ETHERTYPE_IP:
67261ae650dSJack F Vogel 			ip = (struct ip *)(mp->m_data + elen);
67361ae650dSJack F Vogel 			ip_hlen = ip->ip_hl << 2;
67461ae650dSJack F Vogel 			ipproto = ip->ip_p;
67561ae650dSJack F Vogel 			th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
67661ae650dSJack F Vogel 			/* The IP checksum must be recalculated with TSO */
67761ae650dSJack F Vogel 			if (tso)
67861ae650dSJack F Vogel 				*cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
67961ae650dSJack F Vogel 			else
68061ae650dSJack F Vogel 				*cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
68161ae650dSJack F Vogel 			break;
682b555c614SBjoern A. Zeeb #endif
6832f4959abSJack F Vogel #ifdef INET6
684b555c614SBjoern A. Zeeb 		case ETHERTYPE_IPV6:
68561ae650dSJack F Vogel 			ip6 = (struct ip6_hdr *)(mp->m_data + elen);
68661ae650dSJack F Vogel 			ip_hlen = sizeof(struct ip6_hdr);
68761ae650dSJack F Vogel 			ipproto = ip6->ip6_nxt;
68861ae650dSJack F Vogel 			th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
68961ae650dSJack F Vogel 			*cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
690b555c614SBjoern A. Zeeb 			break;
6912f4959abSJack F Vogel #endif
69261ae650dSJack F Vogel 		default:
69361ae650dSJack F Vogel 			break;
69461ae650dSJack F Vogel 	}
69561ae650dSJack F Vogel 
69661ae650dSJack F Vogel 	*off |= (elen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
69761ae650dSJack F Vogel 	*off |= (ip_hlen >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
69861ae650dSJack F Vogel 
69961ae650dSJack F Vogel 	switch (ipproto) {
70061ae650dSJack F Vogel 		case IPPROTO_TCP:
70161ae650dSJack F Vogel 			tcp_hlen = th->th_off << 2;
70261ae650dSJack F Vogel 			if (mp->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_TCP_IPV6)) {
70361ae650dSJack F Vogel 				*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
70461ae650dSJack F Vogel 				*off |= (tcp_hlen >> 2) <<
70561ae650dSJack F Vogel 				    I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
70661ae650dSJack F Vogel 			}
70761ae650dSJack F Vogel #ifdef IXL_FDIR
70861ae650dSJack F Vogel 			ixl_atr(que, th, etype);
70961ae650dSJack F Vogel #endif
71061ae650dSJack F Vogel 			break;
71161ae650dSJack F Vogel 		case IPPROTO_UDP:
71261ae650dSJack F Vogel 			if (mp->m_pkthdr.csum_flags & (CSUM_UDP|CSUM_UDP_IPV6)) {
71361ae650dSJack F Vogel 				*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
71461ae650dSJack F Vogel 				*off |= (sizeof(struct udphdr) >> 2) <<
71561ae650dSJack F Vogel 				    I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
71661ae650dSJack F Vogel 			}
71761ae650dSJack F Vogel 			break;
71861ae650dSJack F Vogel 
71961ae650dSJack F Vogel 		case IPPROTO_SCTP:
72061ae650dSJack F Vogel 			if (mp->m_pkthdr.csum_flags & (CSUM_SCTP|CSUM_SCTP_IPV6)) {
72161ae650dSJack F Vogel 				*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
72261ae650dSJack F Vogel 				*off |= (sizeof(struct sctphdr) >> 2) <<
72361ae650dSJack F Vogel 				    I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
72461ae650dSJack F Vogel 			}
72561ae650dSJack F Vogel 			/* Fall Thru */
72661ae650dSJack F Vogel 		default:
72761ae650dSJack F Vogel 			break;
72861ae650dSJack F Vogel 	}
72961ae650dSJack F Vogel 
73061ae650dSJack F Vogel         return (0);
73161ae650dSJack F Vogel }
73261ae650dSJack F Vogel 
73361ae650dSJack F Vogel 
73461ae650dSJack F Vogel /**********************************************************************
73561ae650dSJack F Vogel  *
73661ae650dSJack F Vogel  *  Setup context for hardware segmentation offload (TSO)
73761ae650dSJack F Vogel  *
73861ae650dSJack F Vogel  **********************************************************************/
73961ae650dSJack F Vogel static bool
74061ae650dSJack F Vogel ixl_tso_setup(struct ixl_queue *que, struct mbuf *mp)
74161ae650dSJack F Vogel {
74261ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
74361ae650dSJack F Vogel 	struct i40e_tx_context_desc	*TXD;
74461ae650dSJack F Vogel 	struct ixl_tx_buf		*buf;
74561ae650dSJack F Vogel 	u32				cmd, mss, type, tsolen;
74661ae650dSJack F Vogel 	u16				etype;
74761ae650dSJack F Vogel 	int				idx, elen, ip_hlen, tcp_hlen;
74861ae650dSJack F Vogel 	struct ether_vlan_header	*eh;
7491f873f18SJack F Vogel #ifdef INET
75061ae650dSJack F Vogel 	struct ip			*ip;
7511f873f18SJack F Vogel #endif
7521f873f18SJack F Vogel #ifdef INET6
75361ae650dSJack F Vogel 	struct ip6_hdr			*ip6;
7541f873f18SJack F Vogel #endif
755b555c614SBjoern A. Zeeb #if defined(INET6) || defined(INET)
75661ae650dSJack F Vogel 	struct tcphdr			*th;
757b555c614SBjoern A. Zeeb #endif
75861ae650dSJack F Vogel 	u64				type_cmd_tso_mss;
75961ae650dSJack F Vogel 
76061ae650dSJack F Vogel 	/*
76161ae650dSJack F Vogel 	 * Determine where frame payload starts.
76261ae650dSJack F Vogel 	 * Jump over vlan headers if already present
76361ae650dSJack F Vogel 	 */
76461ae650dSJack F Vogel 	eh = mtod(mp, struct ether_vlan_header *);
76561ae650dSJack F Vogel 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
76661ae650dSJack F Vogel 		elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
76761ae650dSJack F Vogel 		etype = eh->evl_proto;
76861ae650dSJack F Vogel 	} else {
76961ae650dSJack F Vogel 		elen = ETHER_HDR_LEN;
77061ae650dSJack F Vogel 		etype = eh->evl_encap_proto;
77161ae650dSJack F Vogel 	}
77261ae650dSJack F Vogel 
77361ae650dSJack F Vogel         switch (ntohs(etype)) {
77461ae650dSJack F Vogel #ifdef INET6
77561ae650dSJack F Vogel 	case ETHERTYPE_IPV6:
77661ae650dSJack F Vogel 		ip6 = (struct ip6_hdr *)(mp->m_data + elen);
77761ae650dSJack F Vogel 		if (ip6->ip6_nxt != IPPROTO_TCP)
77861ae650dSJack F Vogel 			return (ENXIO);
77961ae650dSJack F Vogel 		ip_hlen = sizeof(struct ip6_hdr);
78061ae650dSJack F Vogel 		th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
78161ae650dSJack F Vogel 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
78261ae650dSJack F Vogel 		tcp_hlen = th->th_off << 2;
7836d011ad5SEric Joyner 		/*
7846d011ad5SEric Joyner 		 * The corresponding flag is set by the stack in the IPv4
7856d011ad5SEric Joyner 		 * TSO case, but not in IPv6 (at least in FreeBSD 10.2).
7866d011ad5SEric Joyner 		 * So, set it here because the rest of the flow requires it.
7876d011ad5SEric Joyner 		 */
7886d011ad5SEric Joyner 		mp->m_pkthdr.csum_flags |= CSUM_TCP_IPV6;
78961ae650dSJack F Vogel 		break;
79061ae650dSJack F Vogel #endif
79161ae650dSJack F Vogel #ifdef INET
79261ae650dSJack F Vogel 	case ETHERTYPE_IP:
79361ae650dSJack F Vogel 		ip = (struct ip *)(mp->m_data + elen);
79461ae650dSJack F Vogel 		if (ip->ip_p != IPPROTO_TCP)
79561ae650dSJack F Vogel 			return (ENXIO);
79661ae650dSJack F Vogel 		ip->ip_sum = 0;
79761ae650dSJack F Vogel 		ip_hlen = ip->ip_hl << 2;
79861ae650dSJack F Vogel 		th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
79961ae650dSJack F Vogel 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
80061ae650dSJack F Vogel 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
80161ae650dSJack F Vogel 		tcp_hlen = th->th_off << 2;
80261ae650dSJack F Vogel 		break;
80361ae650dSJack F Vogel #endif
80461ae650dSJack F Vogel 	default:
805b555c614SBjoern A. Zeeb 		printf("%s: CSUM_TSO but no supported IP version (0x%04x)",
80661ae650dSJack F Vogel 		    __func__, ntohs(etype));
807b555c614SBjoern A. Zeeb 		return FALSE;
80861ae650dSJack F Vogel         }
80961ae650dSJack F Vogel 
81061ae650dSJack F Vogel         /* Ensure we have at least the IP+TCP header in the first mbuf. */
81161ae650dSJack F Vogel         if (mp->m_len < elen + ip_hlen + sizeof(struct tcphdr))
81261ae650dSJack F Vogel 		return FALSE;
81361ae650dSJack F Vogel 
81461ae650dSJack F Vogel 	idx = txr->next_avail;
81561ae650dSJack F Vogel 	buf = &txr->buffers[idx];
81661ae650dSJack F Vogel 	TXD = (struct i40e_tx_context_desc *) &txr->base[idx];
81761ae650dSJack F Vogel 	tsolen = mp->m_pkthdr.len - (elen + ip_hlen + tcp_hlen);
81861ae650dSJack F Vogel 
81961ae650dSJack F Vogel 	type = I40E_TX_DESC_DTYPE_CONTEXT;
82061ae650dSJack F Vogel 	cmd = I40E_TX_CTX_DESC_TSO;
821*cb6b8299SEric Joyner 	/* TSO MSS must not be less than 64 */
822*cb6b8299SEric Joyner 	if (mp->m_pkthdr.tso_segsz < IXL_MIN_TSO_MSS) {
823*cb6b8299SEric Joyner 		que->mss_too_small++;
824*cb6b8299SEric Joyner 		mp->m_pkthdr.tso_segsz = IXL_MIN_TSO_MSS;
825*cb6b8299SEric Joyner 	}
82661ae650dSJack F Vogel 	mss = mp->m_pkthdr.tso_segsz;
82761ae650dSJack F Vogel 
82861ae650dSJack F Vogel 	type_cmd_tso_mss = ((u64)type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) |
82961ae650dSJack F Vogel 	    ((u64)cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
83061ae650dSJack F Vogel 	    ((u64)tsolen << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
83161ae650dSJack F Vogel 	    ((u64)mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
83261ae650dSJack F Vogel 	TXD->type_cmd_tso_mss = htole64(type_cmd_tso_mss);
83361ae650dSJack F Vogel 
83461ae650dSJack F Vogel 	TXD->tunneling_params = htole32(0);
83561ae650dSJack F Vogel 	buf->m_head = NULL;
83661ae650dSJack F Vogel 	buf->eop_index = -1;
83761ae650dSJack F Vogel 
83861ae650dSJack F Vogel 	if (++idx == que->num_desc)
83961ae650dSJack F Vogel 		idx = 0;
84061ae650dSJack F Vogel 
84161ae650dSJack F Vogel 	txr->avail--;
84261ae650dSJack F Vogel 	txr->next_avail = idx;
84361ae650dSJack F Vogel 
84461ae650dSJack F Vogel 	return TRUE;
84561ae650dSJack F Vogel }
84661ae650dSJack F Vogel 
84761ae650dSJack F Vogel /*
84861ae650dSJack F Vogel ** ixl_get_tx_head - Retrieve the value from the
84961ae650dSJack F Vogel **    location the HW records its HEAD index
85061ae650dSJack F Vogel */
85161ae650dSJack F Vogel static inline u32
85261ae650dSJack F Vogel ixl_get_tx_head(struct ixl_queue *que)
85361ae650dSJack F Vogel {
85461ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
85561ae650dSJack F Vogel 	void *head = &txr->base[que->num_desc];
85661ae650dSJack F Vogel 	return LE32_TO_CPU(*(volatile __le32 *)head);
85761ae650dSJack F Vogel }
85861ae650dSJack F Vogel 
85961ae650dSJack F Vogel /**********************************************************************
86061ae650dSJack F Vogel  *
86161ae650dSJack F Vogel  *  Examine each tx_buffer in the used queue. If the hardware is done
86261ae650dSJack F Vogel  *  processing the packet then free associated resources. The
86361ae650dSJack F Vogel  *  tx_buffer is put back on the free queue.
86461ae650dSJack F Vogel  *
86561ae650dSJack F Vogel  **********************************************************************/
86661ae650dSJack F Vogel bool
86761ae650dSJack F Vogel ixl_txeof(struct ixl_queue *que)
86861ae650dSJack F Vogel {
86961ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
87061ae650dSJack F Vogel 	u32			first, last, head, done, processed;
87161ae650dSJack F Vogel 	struct ixl_tx_buf	*buf;
87261ae650dSJack F Vogel 	struct i40e_tx_desc	*tx_desc, *eop_desc;
87361ae650dSJack F Vogel 
87461ae650dSJack F Vogel 
87561ae650dSJack F Vogel 	mtx_assert(&txr->mtx, MA_OWNED);
87661ae650dSJack F Vogel 
87731830672SJack F Vogel #ifdef DEV_NETMAP
87831830672SJack F Vogel 	// XXX todo: implement moderation
87931830672SJack F Vogel 	if (netmap_tx_irq(que->vsi->ifp, que->me))
88031830672SJack F Vogel 		return FALSE;
88131830672SJack F Vogel #endif /* DEF_NETMAP */
882e5100ee2SJack F Vogel 
88361ae650dSJack F Vogel 	/* These are not the descriptors you seek, move along :) */
88461ae650dSJack F Vogel 	if (txr->avail == que->num_desc) {
885*cb6b8299SEric Joyner 		atomic_store_rel_32(&txr->watchdog_timer, 0);
88661ae650dSJack F Vogel 		return FALSE;
88761ae650dSJack F Vogel 	}
88861ae650dSJack F Vogel 
88961ae650dSJack F Vogel 	processed = 0;
89061ae650dSJack F Vogel 	first = txr->next_to_clean;
89161ae650dSJack F Vogel 	buf = &txr->buffers[first];
89261ae650dSJack F Vogel 	tx_desc = (struct i40e_tx_desc *)&txr->base[first];
89361ae650dSJack F Vogel 	last = buf->eop_index;
89461ae650dSJack F Vogel 	if (last == -1)
89561ae650dSJack F Vogel 		return FALSE;
89661ae650dSJack F Vogel 	eop_desc = (struct i40e_tx_desc *)&txr->base[last];
89761ae650dSJack F Vogel 
89861ae650dSJack F Vogel 	/* Get the Head WB value */
89961ae650dSJack F Vogel 	head = ixl_get_tx_head(que);
90061ae650dSJack F Vogel 
90161ae650dSJack F Vogel 	/*
90261ae650dSJack F Vogel 	** Get the index of the first descriptor
90361ae650dSJack F Vogel 	** BEYOND the EOP and call that 'done'.
90461ae650dSJack F Vogel 	** I do this so the comparison in the
90561ae650dSJack F Vogel 	** inner while loop below can be simple
90661ae650dSJack F Vogel 	*/
90761ae650dSJack F Vogel 	if (++last == que->num_desc) last = 0;
90861ae650dSJack F Vogel 	done = last;
90961ae650dSJack F Vogel 
91061ae650dSJack F Vogel         bus_dmamap_sync(txr->dma.tag, txr->dma.map,
91161ae650dSJack F Vogel             BUS_DMASYNC_POSTREAD);
91261ae650dSJack F Vogel 	/*
91361ae650dSJack F Vogel 	** The HEAD index of the ring is written in a
91461ae650dSJack F Vogel 	** defined location, this rather than a done bit
91561ae650dSJack F Vogel 	** is what is used to keep track of what must be
91661ae650dSJack F Vogel 	** 'cleaned'.
91761ae650dSJack F Vogel 	*/
91861ae650dSJack F Vogel 	while (first != head) {
91961ae650dSJack F Vogel 		/* We clean the range of the packet */
92061ae650dSJack F Vogel 		while (first != done) {
92161ae650dSJack F Vogel 			++txr->avail;
92261ae650dSJack F Vogel 			++processed;
92361ae650dSJack F Vogel 
92461ae650dSJack F Vogel 			if (buf->m_head) {
92561ae650dSJack F Vogel 				txr->bytes += /* for ITR adjustment */
92661ae650dSJack F Vogel 				    buf->m_head->m_pkthdr.len;
92761ae650dSJack F Vogel 				txr->tx_bytes += /* for TX stats */
92861ae650dSJack F Vogel 				    buf->m_head->m_pkthdr.len;
92961ae650dSJack F Vogel 				bus_dmamap_sync(buf->tag,
93061ae650dSJack F Vogel 				    buf->map,
93161ae650dSJack F Vogel 				    BUS_DMASYNC_POSTWRITE);
93261ae650dSJack F Vogel 				bus_dmamap_unload(buf->tag,
93361ae650dSJack F Vogel 				    buf->map);
93461ae650dSJack F Vogel 				m_freem(buf->m_head);
93561ae650dSJack F Vogel 				buf->m_head = NULL;
93661ae650dSJack F Vogel 				buf->map = NULL;
93761ae650dSJack F Vogel 			}
93861ae650dSJack F Vogel 			buf->eop_index = -1;
93961ae650dSJack F Vogel 
94061ae650dSJack F Vogel 			if (++first == que->num_desc)
94161ae650dSJack F Vogel 				first = 0;
94261ae650dSJack F Vogel 
94361ae650dSJack F Vogel 			buf = &txr->buffers[first];
94461ae650dSJack F Vogel 			tx_desc = &txr->base[first];
94561ae650dSJack F Vogel 		}
94661ae650dSJack F Vogel 		++txr->packets;
94761ae650dSJack F Vogel 		/* See if there is more work now */
94861ae650dSJack F Vogel 		last = buf->eop_index;
94961ae650dSJack F Vogel 		if (last != -1) {
95061ae650dSJack F Vogel 			eop_desc = &txr->base[last];
95161ae650dSJack F Vogel 			/* Get next done point */
95261ae650dSJack F Vogel 			if (++last == que->num_desc) last = 0;
95361ae650dSJack F Vogel 			done = last;
95461ae650dSJack F Vogel 		} else
95561ae650dSJack F Vogel 			break;
95661ae650dSJack F Vogel 	}
95761ae650dSJack F Vogel 	bus_dmamap_sync(txr->dma.tag, txr->dma.map,
95861ae650dSJack F Vogel 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
95961ae650dSJack F Vogel 
96061ae650dSJack F Vogel 	txr->next_to_clean = first;
96161ae650dSJack F Vogel 
96261ae650dSJack F Vogel 
96361ae650dSJack F Vogel 	/*
96461ae650dSJack F Vogel 	 * If there are no pending descriptors, clear the timeout.
96561ae650dSJack F Vogel 	 */
96661ae650dSJack F Vogel 	if (txr->avail == que->num_desc) {
967*cb6b8299SEric Joyner 		atomic_store_rel_32(&txr->watchdog_timer, 0);
96861ae650dSJack F Vogel 		return FALSE;
96961ae650dSJack F Vogel 	}
97061ae650dSJack F Vogel 
97161ae650dSJack F Vogel 	return TRUE;
97261ae650dSJack F Vogel }
97361ae650dSJack F Vogel 
97461ae650dSJack F Vogel /*********************************************************************
97561ae650dSJack F Vogel  *
97661ae650dSJack F Vogel  *  Refresh mbuf buffers for RX descriptor rings
97761ae650dSJack F Vogel  *   - now keeps its own state so discards due to resource
97861ae650dSJack F Vogel  *     exhaustion are unnecessary, if an mbuf cannot be obtained
97961ae650dSJack F Vogel  *     it just returns, keeping its placeholder, thus it can simply
98061ae650dSJack F Vogel  *     be recalled to try again.
98161ae650dSJack F Vogel  *
98261ae650dSJack F Vogel  **********************************************************************/
98361ae650dSJack F Vogel static void
98461ae650dSJack F Vogel ixl_refresh_mbufs(struct ixl_queue *que, int limit)
98561ae650dSJack F Vogel {
98661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
98761ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
98861ae650dSJack F Vogel 	bus_dma_segment_t	hseg[1];
98961ae650dSJack F Vogel 	bus_dma_segment_t	pseg[1];
99061ae650dSJack F Vogel 	struct ixl_rx_buf	*buf;
99161ae650dSJack F Vogel 	struct mbuf		*mh, *mp;
99261ae650dSJack F Vogel 	int			i, j, nsegs, error;
99361ae650dSJack F Vogel 	bool			refreshed = FALSE;
99461ae650dSJack F Vogel 
99561ae650dSJack F Vogel 	i = j = rxr->next_refresh;
99661ae650dSJack F Vogel 	/* Control the loop with one beyond */
99761ae650dSJack F Vogel 	if (++j == que->num_desc)
99861ae650dSJack F Vogel 		j = 0;
99961ae650dSJack F Vogel 
100061ae650dSJack F Vogel 	while (j != limit) {
100161ae650dSJack F Vogel 		buf = &rxr->buffers[i];
100261ae650dSJack F Vogel 		if (rxr->hdr_split == FALSE)
100361ae650dSJack F Vogel 			goto no_split;
100461ae650dSJack F Vogel 
100561ae650dSJack F Vogel 		if (buf->m_head == NULL) {
100661ae650dSJack F Vogel 			mh = m_gethdr(M_NOWAIT, MT_DATA);
100761ae650dSJack F Vogel 			if (mh == NULL)
100861ae650dSJack F Vogel 				goto update;
100961ae650dSJack F Vogel 		} else
101061ae650dSJack F Vogel 			mh = buf->m_head;
101161ae650dSJack F Vogel 
101261ae650dSJack F Vogel 		mh->m_pkthdr.len = mh->m_len = MHLEN;
101361ae650dSJack F Vogel 		mh->m_len = MHLEN;
101461ae650dSJack F Vogel 		mh->m_flags |= M_PKTHDR;
101561ae650dSJack F Vogel 		/* Get the memory mapping */
101661ae650dSJack F Vogel 		error = bus_dmamap_load_mbuf_sg(rxr->htag,
101761ae650dSJack F Vogel 		    buf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT);
101861ae650dSJack F Vogel 		if (error != 0) {
101961ae650dSJack F Vogel 			printf("Refresh mbufs: hdr dmamap load"
102061ae650dSJack F Vogel 			    " failure - %d\n", error);
102161ae650dSJack F Vogel 			m_free(mh);
102261ae650dSJack F Vogel 			buf->m_head = NULL;
102361ae650dSJack F Vogel 			goto update;
102461ae650dSJack F Vogel 		}
102561ae650dSJack F Vogel 		buf->m_head = mh;
102661ae650dSJack F Vogel 		bus_dmamap_sync(rxr->htag, buf->hmap,
102761ae650dSJack F Vogel 		    BUS_DMASYNC_PREREAD);
102861ae650dSJack F Vogel 		rxr->base[i].read.hdr_addr =
102961ae650dSJack F Vogel 		   htole64(hseg[0].ds_addr);
103061ae650dSJack F Vogel 
103161ae650dSJack F Vogel no_split:
103261ae650dSJack F Vogel 		if (buf->m_pack == NULL) {
103361ae650dSJack F Vogel 			mp = m_getjcl(M_NOWAIT, MT_DATA,
103461ae650dSJack F Vogel 			    M_PKTHDR, rxr->mbuf_sz);
103561ae650dSJack F Vogel 			if (mp == NULL)
103661ae650dSJack F Vogel 				goto update;
103761ae650dSJack F Vogel 		} else
103861ae650dSJack F Vogel 			mp = buf->m_pack;
103961ae650dSJack F Vogel 
104061ae650dSJack F Vogel 		mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz;
104161ae650dSJack F Vogel 		/* Get the memory mapping */
104261ae650dSJack F Vogel 		error = bus_dmamap_load_mbuf_sg(rxr->ptag,
104361ae650dSJack F Vogel 		    buf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT);
104461ae650dSJack F Vogel 		if (error != 0) {
104561ae650dSJack F Vogel 			printf("Refresh mbufs: payload dmamap load"
104661ae650dSJack F Vogel 			    " failure - %d\n", error);
104761ae650dSJack F Vogel 			m_free(mp);
104861ae650dSJack F Vogel 			buf->m_pack = NULL;
104961ae650dSJack F Vogel 			goto update;
105061ae650dSJack F Vogel 		}
105161ae650dSJack F Vogel 		buf->m_pack = mp;
105261ae650dSJack F Vogel 		bus_dmamap_sync(rxr->ptag, buf->pmap,
105361ae650dSJack F Vogel 		    BUS_DMASYNC_PREREAD);
105461ae650dSJack F Vogel 		rxr->base[i].read.pkt_addr =
105561ae650dSJack F Vogel 		   htole64(pseg[0].ds_addr);
105661ae650dSJack F Vogel 		/* Used only when doing header split */
105761ae650dSJack F Vogel 		rxr->base[i].read.hdr_addr = 0;
105861ae650dSJack F Vogel 
105961ae650dSJack F Vogel 		refreshed = TRUE;
106061ae650dSJack F Vogel 		/* Next is precalculated */
106161ae650dSJack F Vogel 		i = j;
106261ae650dSJack F Vogel 		rxr->next_refresh = i;
106361ae650dSJack F Vogel 		if (++j == que->num_desc)
106461ae650dSJack F Vogel 			j = 0;
106561ae650dSJack F Vogel 	}
106661ae650dSJack F Vogel update:
106761ae650dSJack F Vogel 	if (refreshed) /* Update hardware tail index */
106861ae650dSJack F Vogel 		wr32(vsi->hw, rxr->tail, rxr->next_refresh);
106961ae650dSJack F Vogel 	return;
107061ae650dSJack F Vogel }
107161ae650dSJack F Vogel 
107261ae650dSJack F Vogel 
107361ae650dSJack F Vogel /*********************************************************************
107461ae650dSJack F Vogel  *
107561ae650dSJack F Vogel  *  Allocate memory for rx_buffer structures. Since we use one
107661ae650dSJack F Vogel  *  rx_buffer per descriptor, the maximum number of rx_buffer's
107761ae650dSJack F Vogel  *  that we'll need is equal to the number of receive descriptors
107861ae650dSJack F Vogel  *  that we've defined.
107961ae650dSJack F Vogel  *
108061ae650dSJack F Vogel  **********************************************************************/
108161ae650dSJack F Vogel int
108261ae650dSJack F Vogel ixl_allocate_rx_data(struct ixl_queue *que)
108361ae650dSJack F Vogel {
108461ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
108561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
108661ae650dSJack F Vogel 	device_t 		dev = vsi->dev;
108761ae650dSJack F Vogel 	struct ixl_rx_buf 	*buf;
108861ae650dSJack F Vogel 	int             	i, bsize, error;
108961ae650dSJack F Vogel 
109061ae650dSJack F Vogel 	bsize = sizeof(struct ixl_rx_buf) * que->num_desc;
109161ae650dSJack F Vogel 	if (!(rxr->buffers =
109261ae650dSJack F Vogel 	    (struct ixl_rx_buf *) malloc(bsize,
109361ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO))) {
109461ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate rx_buffer memory\n");
109561ae650dSJack F Vogel 		error = ENOMEM;
109661ae650dSJack F Vogel 		return (error);
109761ae650dSJack F Vogel 	}
109861ae650dSJack F Vogel 
109961ae650dSJack F Vogel 	if ((error = bus_dma_tag_create(NULL,	/* parent */
110061ae650dSJack F Vogel 				   1, 0,	/* alignment, bounds */
110161ae650dSJack F Vogel 				   BUS_SPACE_MAXADDR,	/* lowaddr */
110261ae650dSJack F Vogel 				   BUS_SPACE_MAXADDR,	/* highaddr */
110361ae650dSJack F Vogel 				   NULL, NULL,		/* filter, filterarg */
110461ae650dSJack F Vogel 				   MSIZE,		/* maxsize */
110561ae650dSJack F Vogel 				   1,			/* nsegments */
110661ae650dSJack F Vogel 				   MSIZE,		/* maxsegsize */
110761ae650dSJack F Vogel 				   0,			/* flags */
110861ae650dSJack F Vogel 				   NULL,		/* lockfunc */
110961ae650dSJack F Vogel 				   NULL,		/* lockfuncarg */
111061ae650dSJack F Vogel 				   &rxr->htag))) {
111161ae650dSJack F Vogel 		device_printf(dev, "Unable to create RX DMA htag\n");
111261ae650dSJack F Vogel 		return (error);
111361ae650dSJack F Vogel 	}
111461ae650dSJack F Vogel 
111561ae650dSJack F Vogel 	if ((error = bus_dma_tag_create(NULL,	/* parent */
111661ae650dSJack F Vogel 				   1, 0,	/* alignment, bounds */
111761ae650dSJack F Vogel 				   BUS_SPACE_MAXADDR,	/* lowaddr */
111861ae650dSJack F Vogel 				   BUS_SPACE_MAXADDR,	/* highaddr */
111961ae650dSJack F Vogel 				   NULL, NULL,		/* filter, filterarg */
112061ae650dSJack F Vogel 				   MJUM16BYTES,		/* maxsize */
112161ae650dSJack F Vogel 				   1,			/* nsegments */
112261ae650dSJack F Vogel 				   MJUM16BYTES,		/* maxsegsize */
112361ae650dSJack F Vogel 				   0,			/* flags */
112461ae650dSJack F Vogel 				   NULL,		/* lockfunc */
112561ae650dSJack F Vogel 				   NULL,		/* lockfuncarg */
112661ae650dSJack F Vogel 				   &rxr->ptag))) {
112761ae650dSJack F Vogel 		device_printf(dev, "Unable to create RX DMA ptag\n");
112861ae650dSJack F Vogel 		return (error);
112961ae650dSJack F Vogel 	}
113061ae650dSJack F Vogel 
113161ae650dSJack F Vogel 	for (i = 0; i < que->num_desc; i++) {
113261ae650dSJack F Vogel 		buf = &rxr->buffers[i];
113361ae650dSJack F Vogel 		error = bus_dmamap_create(rxr->htag,
113461ae650dSJack F Vogel 		    BUS_DMA_NOWAIT, &buf->hmap);
113561ae650dSJack F Vogel 		if (error) {
113661ae650dSJack F Vogel 			device_printf(dev, "Unable to create RX head map\n");
113761ae650dSJack F Vogel 			break;
113861ae650dSJack F Vogel 		}
113961ae650dSJack F Vogel 		error = bus_dmamap_create(rxr->ptag,
114061ae650dSJack F Vogel 		    BUS_DMA_NOWAIT, &buf->pmap);
114161ae650dSJack F Vogel 		if (error) {
114261ae650dSJack F Vogel 			device_printf(dev, "Unable to create RX pkt map\n");
114361ae650dSJack F Vogel 			break;
114461ae650dSJack F Vogel 		}
114561ae650dSJack F Vogel 	}
114661ae650dSJack F Vogel 
114761ae650dSJack F Vogel 	return (error);
114861ae650dSJack F Vogel }
114961ae650dSJack F Vogel 
115061ae650dSJack F Vogel 
115161ae650dSJack F Vogel /*********************************************************************
115261ae650dSJack F Vogel  *
115361ae650dSJack F Vogel  *  (Re)Initialize the queue receive ring and its buffers.
115461ae650dSJack F Vogel  *
115561ae650dSJack F Vogel  **********************************************************************/
115661ae650dSJack F Vogel int
115761ae650dSJack F Vogel ixl_init_rx_ring(struct ixl_queue *que)
115861ae650dSJack F Vogel {
1159b3f7259bSBjoern A. Zeeb 	struct	rx_ring 	*rxr = &que->rxr;
1160393c4bb1SJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
1161a2cf30b9SBjoern A. Zeeb #if defined(INET6) || defined(INET)
116261ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
116361ae650dSJack F Vogel 	struct lro_ctrl		*lro = &rxr->lro;
1164b3f7259bSBjoern A. Zeeb #endif
116561ae650dSJack F Vogel 	struct ixl_rx_buf	*buf;
116661ae650dSJack F Vogel 	bus_dma_segment_t	pseg[1], hseg[1];
116761ae650dSJack F Vogel 	int			rsize, nsegs, error = 0;
116831830672SJack F Vogel #ifdef DEV_NETMAP
116931830672SJack F Vogel 	struct netmap_adapter *na = NA(que->vsi->ifp);
117031830672SJack F Vogel 	struct netmap_slot *slot;
117131830672SJack F Vogel #endif /* DEV_NETMAP */
117261ae650dSJack F Vogel 
117361ae650dSJack F Vogel 	IXL_RX_LOCK(rxr);
117431830672SJack F Vogel #ifdef DEV_NETMAP
117531830672SJack F Vogel 	/* same as in ixl_init_tx_ring() */
117631830672SJack F Vogel 	slot = netmap_reset(na, NR_RX, que->me, 0);
117731830672SJack F Vogel #endif /* DEV_NETMAP */
117861ae650dSJack F Vogel 	/* Clear the ring contents */
117961ae650dSJack F Vogel 	rsize = roundup2(que->num_desc *
118061ae650dSJack F Vogel 	    sizeof(union i40e_rx_desc), DBA_ALIGN);
118161ae650dSJack F Vogel 	bzero((void *)rxr->base, rsize);
118261ae650dSJack F Vogel 	/* Cleanup any existing buffers */
118361ae650dSJack F Vogel 	for (int i = 0; i < que->num_desc; i++) {
118461ae650dSJack F Vogel 		buf = &rxr->buffers[i];
118561ae650dSJack F Vogel 		if (buf->m_head != NULL) {
118661ae650dSJack F Vogel 			bus_dmamap_sync(rxr->htag, buf->hmap,
118761ae650dSJack F Vogel 			    BUS_DMASYNC_POSTREAD);
118861ae650dSJack F Vogel 			bus_dmamap_unload(rxr->htag, buf->hmap);
118961ae650dSJack F Vogel 			buf->m_head->m_flags |= M_PKTHDR;
119061ae650dSJack F Vogel 			m_freem(buf->m_head);
119161ae650dSJack F Vogel 		}
119261ae650dSJack F Vogel 		if (buf->m_pack != NULL) {
119361ae650dSJack F Vogel 			bus_dmamap_sync(rxr->ptag, buf->pmap,
119461ae650dSJack F Vogel 			    BUS_DMASYNC_POSTREAD);
119561ae650dSJack F Vogel 			bus_dmamap_unload(rxr->ptag, buf->pmap);
119661ae650dSJack F Vogel 			buf->m_pack->m_flags |= M_PKTHDR;
119761ae650dSJack F Vogel 			m_freem(buf->m_pack);
119861ae650dSJack F Vogel 		}
119961ae650dSJack F Vogel 		buf->m_head = NULL;
120061ae650dSJack F Vogel 		buf->m_pack = NULL;
120161ae650dSJack F Vogel 	}
120261ae650dSJack F Vogel 
120361ae650dSJack F Vogel 	/* header split is off */
120461ae650dSJack F Vogel 	rxr->hdr_split = FALSE;
120561ae650dSJack F Vogel 
120661ae650dSJack F Vogel 	/* Now replenish the mbufs */
120761ae650dSJack F Vogel 	for (int j = 0; j != que->num_desc; ++j) {
120861ae650dSJack F Vogel 		struct mbuf	*mh, *mp;
120961ae650dSJack F Vogel 
121061ae650dSJack F Vogel 		buf = &rxr->buffers[j];
121131830672SJack F Vogel #ifdef DEV_NETMAP
121231830672SJack F Vogel 		/*
121331830672SJack F Vogel 		 * In netmap mode, fill the map and set the buffer
121431830672SJack F Vogel 		 * address in the NIC ring, considering the offset
121531830672SJack F Vogel 		 * between the netmap and NIC rings (see comment in
121631830672SJack F Vogel 		 * ixgbe_setup_transmit_ring() ). No need to allocate
121731830672SJack F Vogel 		 * an mbuf, so end the block with a continue;
121831830672SJack F Vogel 		 */
121931830672SJack F Vogel 		if (slot) {
122031830672SJack F Vogel 			int sj = netmap_idx_n2k(&na->rx_rings[que->me], j);
122131830672SJack F Vogel 			uint64_t paddr;
122231830672SJack F Vogel 			void *addr;
1223bc8b78d3SLuigi Rizzo 
122431830672SJack F Vogel 			addr = PNMB(na, slot + sj, &paddr);
122531830672SJack F Vogel 			netmap_load_map(na, rxr->dma.tag, buf->pmap, addr);
122631830672SJack F Vogel 			/* Update descriptor and the cached value */
122731830672SJack F Vogel 			rxr->base[j].read.pkt_addr = htole64(paddr);
122831830672SJack F Vogel 			rxr->base[j].read.hdr_addr = 0;
122931830672SJack F Vogel 			continue;
123031830672SJack F Vogel 		}
123131830672SJack F Vogel #endif /* DEV_NETMAP */
123261ae650dSJack F Vogel 		/*
123361ae650dSJack F Vogel 		** Don't allocate mbufs if not
123461ae650dSJack F Vogel 		** doing header split, its wasteful
123561ae650dSJack F Vogel 		*/
123661ae650dSJack F Vogel 		if (rxr->hdr_split == FALSE)
123761ae650dSJack F Vogel 			goto skip_head;
123861ae650dSJack F Vogel 
123961ae650dSJack F Vogel 		/* First the header */
124061ae650dSJack F Vogel 		buf->m_head = m_gethdr(M_NOWAIT, MT_DATA);
124161ae650dSJack F Vogel 		if (buf->m_head == NULL) {
124261ae650dSJack F Vogel 			error = ENOBUFS;
124361ae650dSJack F Vogel 			goto fail;
124461ae650dSJack F Vogel 		}
124561ae650dSJack F Vogel 		m_adj(buf->m_head, ETHER_ALIGN);
124661ae650dSJack F Vogel 		mh = buf->m_head;
124761ae650dSJack F Vogel 		mh->m_len = mh->m_pkthdr.len = MHLEN;
124861ae650dSJack F Vogel 		mh->m_flags |= M_PKTHDR;
124961ae650dSJack F Vogel 		/* Get the memory mapping */
125061ae650dSJack F Vogel 		error = bus_dmamap_load_mbuf_sg(rxr->htag,
125161ae650dSJack F Vogel 		    buf->hmap, buf->m_head, hseg,
125261ae650dSJack F Vogel 		    &nsegs, BUS_DMA_NOWAIT);
125361ae650dSJack F Vogel 		if (error != 0) /* Nothing elegant to do here */
125461ae650dSJack F Vogel 			goto fail;
125561ae650dSJack F Vogel 		bus_dmamap_sync(rxr->htag,
125661ae650dSJack F Vogel 		    buf->hmap, BUS_DMASYNC_PREREAD);
125761ae650dSJack F Vogel 		/* Update descriptor */
125861ae650dSJack F Vogel 		rxr->base[j].read.hdr_addr = htole64(hseg[0].ds_addr);
125961ae650dSJack F Vogel 
126061ae650dSJack F Vogel skip_head:
126161ae650dSJack F Vogel 		/* Now the payload cluster */
126261ae650dSJack F Vogel 		buf->m_pack = m_getjcl(M_NOWAIT, MT_DATA,
126361ae650dSJack F Vogel 		    M_PKTHDR, rxr->mbuf_sz);
126461ae650dSJack F Vogel 		if (buf->m_pack == NULL) {
126561ae650dSJack F Vogel 			error = ENOBUFS;
126661ae650dSJack F Vogel                         goto fail;
126761ae650dSJack F Vogel 		}
126861ae650dSJack F Vogel 		mp = buf->m_pack;
126961ae650dSJack F Vogel 		mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz;
127061ae650dSJack F Vogel 		/* Get the memory mapping */
127161ae650dSJack F Vogel 		error = bus_dmamap_load_mbuf_sg(rxr->ptag,
127261ae650dSJack F Vogel 		    buf->pmap, mp, pseg,
127361ae650dSJack F Vogel 		    &nsegs, BUS_DMA_NOWAIT);
127461ae650dSJack F Vogel 		if (error != 0)
127561ae650dSJack F Vogel                         goto fail;
127661ae650dSJack F Vogel 		bus_dmamap_sync(rxr->ptag,
127761ae650dSJack F Vogel 		    buf->pmap, BUS_DMASYNC_PREREAD);
127861ae650dSJack F Vogel 		/* Update descriptor */
127961ae650dSJack F Vogel 		rxr->base[j].read.pkt_addr = htole64(pseg[0].ds_addr);
128061ae650dSJack F Vogel 		rxr->base[j].read.hdr_addr = 0;
128161ae650dSJack F Vogel 	}
128261ae650dSJack F Vogel 
128361ae650dSJack F Vogel 
128461ae650dSJack F Vogel 	/* Setup our descriptor indices */
128561ae650dSJack F Vogel 	rxr->next_check = 0;
128661ae650dSJack F Vogel 	rxr->next_refresh = 0;
128761ae650dSJack F Vogel 	rxr->lro_enabled = FALSE;
128861ae650dSJack F Vogel 	rxr->split = 0;
128961ae650dSJack F Vogel 	rxr->bytes = 0;
129061ae650dSJack F Vogel 	rxr->discard = FALSE;
129161ae650dSJack F Vogel 
1292e5100ee2SJack F Vogel 	wr32(vsi->hw, rxr->tail, que->num_desc - 1);
1293e5100ee2SJack F Vogel 	ixl_flush(vsi->hw);
1294e5100ee2SJack F Vogel 
1295b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET)
129661ae650dSJack F Vogel 	/*
129761ae650dSJack F Vogel 	** Now set up the LRO interface:
129861ae650dSJack F Vogel 	*/
129961ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_LRO) {
130061ae650dSJack F Vogel 		int err = tcp_lro_init(lro);
130161ae650dSJack F Vogel 		if (err) {
130261ae650dSJack F Vogel 			if_printf(ifp, "queue %d: LRO Initialization failed!\n", que->me);
130361ae650dSJack F Vogel 			goto fail;
130461ae650dSJack F Vogel 		}
130561ae650dSJack F Vogel 		INIT_DBG_IF(ifp, "queue %d: RX Soft LRO Initialized", que->me);
130661ae650dSJack F Vogel 		rxr->lro_enabled = TRUE;
130761ae650dSJack F Vogel 		lro->ifp = vsi->ifp;
130861ae650dSJack F Vogel 	}
1309b3f7259bSBjoern A. Zeeb #endif
131061ae650dSJack F Vogel 
131161ae650dSJack F Vogel 	bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
131261ae650dSJack F Vogel 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
131361ae650dSJack F Vogel 
131461ae650dSJack F Vogel fail:
131561ae650dSJack F Vogel 	IXL_RX_UNLOCK(rxr);
131661ae650dSJack F Vogel 	return (error);
131761ae650dSJack F Vogel }
131861ae650dSJack F Vogel 
131961ae650dSJack F Vogel 
132061ae650dSJack F Vogel /*********************************************************************
132161ae650dSJack F Vogel  *
132261ae650dSJack F Vogel  *  Free station receive ring data structures
132361ae650dSJack F Vogel  *
132461ae650dSJack F Vogel  **********************************************************************/
132561ae650dSJack F Vogel void
132661ae650dSJack F Vogel ixl_free_que_rx(struct ixl_queue *que)
132761ae650dSJack F Vogel {
132861ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
132961ae650dSJack F Vogel 	struct ixl_rx_buf	*buf;
133061ae650dSJack F Vogel 
133161ae650dSJack F Vogel 	INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me);
133261ae650dSJack F Vogel 
133361ae650dSJack F Vogel 	/* Cleanup any existing buffers */
133461ae650dSJack F Vogel 	if (rxr->buffers != NULL) {
133561ae650dSJack F Vogel 		for (int i = 0; i < que->num_desc; i++) {
133661ae650dSJack F Vogel 			buf = &rxr->buffers[i];
133761ae650dSJack F Vogel 			if (buf->m_head != NULL) {
133861ae650dSJack F Vogel 				bus_dmamap_sync(rxr->htag, buf->hmap,
133961ae650dSJack F Vogel 				    BUS_DMASYNC_POSTREAD);
134061ae650dSJack F Vogel 				bus_dmamap_unload(rxr->htag, buf->hmap);
134161ae650dSJack F Vogel 				buf->m_head->m_flags |= M_PKTHDR;
134261ae650dSJack F Vogel 				m_freem(buf->m_head);
134361ae650dSJack F Vogel 			}
134461ae650dSJack F Vogel 			if (buf->m_pack != NULL) {
134561ae650dSJack F Vogel 				bus_dmamap_sync(rxr->ptag, buf->pmap,
134661ae650dSJack F Vogel 				    BUS_DMASYNC_POSTREAD);
134761ae650dSJack F Vogel 				bus_dmamap_unload(rxr->ptag, buf->pmap);
134861ae650dSJack F Vogel 				buf->m_pack->m_flags |= M_PKTHDR;
134961ae650dSJack F Vogel 				m_freem(buf->m_pack);
135061ae650dSJack F Vogel 			}
135161ae650dSJack F Vogel 			buf->m_head = NULL;
135261ae650dSJack F Vogel 			buf->m_pack = NULL;
135361ae650dSJack F Vogel 			if (buf->hmap != NULL) {
135461ae650dSJack F Vogel 				bus_dmamap_destroy(rxr->htag, buf->hmap);
135561ae650dSJack F Vogel 				buf->hmap = NULL;
135661ae650dSJack F Vogel 			}
135761ae650dSJack F Vogel 			if (buf->pmap != NULL) {
135861ae650dSJack F Vogel 				bus_dmamap_destroy(rxr->ptag, buf->pmap);
135961ae650dSJack F Vogel 				buf->pmap = NULL;
136061ae650dSJack F Vogel 			}
136161ae650dSJack F Vogel 		}
136261ae650dSJack F Vogel 		if (rxr->buffers != NULL) {
136361ae650dSJack F Vogel 			free(rxr->buffers, M_DEVBUF);
136461ae650dSJack F Vogel 			rxr->buffers = NULL;
136561ae650dSJack F Vogel 		}
136661ae650dSJack F Vogel 	}
136761ae650dSJack F Vogel 
136861ae650dSJack F Vogel 	if (rxr->htag != NULL) {
136961ae650dSJack F Vogel 		bus_dma_tag_destroy(rxr->htag);
137061ae650dSJack F Vogel 		rxr->htag = NULL;
137161ae650dSJack F Vogel 	}
137261ae650dSJack F Vogel 	if (rxr->ptag != NULL) {
137361ae650dSJack F Vogel 		bus_dma_tag_destroy(rxr->ptag);
137461ae650dSJack F Vogel 		rxr->ptag = NULL;
137561ae650dSJack F Vogel 	}
137661ae650dSJack F Vogel 
137761ae650dSJack F Vogel 	INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me);
137861ae650dSJack F Vogel 	return;
137961ae650dSJack F Vogel }
138061ae650dSJack F Vogel 
13814294f337SSean Bruno static inline void
138261ae650dSJack F Vogel ixl_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u8 ptype)
138361ae650dSJack F Vogel {
1384b3f7259bSBjoern A. Zeeb 
1385b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET)
138661ae650dSJack F Vogel         /*
138761ae650dSJack F Vogel          * ATM LRO is only for IPv4/TCP packets and TCP checksum of the packet
138861ae650dSJack F Vogel          * should be computed by hardware. Also it should not have VLAN tag in
138961ae650dSJack F Vogel          * ethernet header.
139061ae650dSJack F Vogel          */
139161ae650dSJack F Vogel         if (rxr->lro_enabled &&
139261ae650dSJack F Vogel             (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 &&
139361ae650dSJack F Vogel             (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) ==
139461ae650dSJack F Vogel             (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) {
139561ae650dSJack F Vogel                 /*
139661ae650dSJack F Vogel                  * Send to the stack if:
139761ae650dSJack F Vogel                  **  - LRO not enabled, or
139861ae650dSJack F Vogel                  **  - no LRO resources, or
139961ae650dSJack F Vogel                  **  - lro enqueue fails
140061ae650dSJack F Vogel                  */
140161ae650dSJack F Vogel                 if (rxr->lro.lro_cnt != 0)
140261ae650dSJack F Vogel                         if (tcp_lro_rx(&rxr->lro, m, 0) == 0)
140361ae650dSJack F Vogel                                 return;
140461ae650dSJack F Vogel         }
1405b3f7259bSBjoern A. Zeeb #endif
140661ae650dSJack F Vogel 	IXL_RX_UNLOCK(rxr);
140761ae650dSJack F Vogel         (*ifp->if_input)(ifp, m);
140861ae650dSJack F Vogel 	IXL_RX_LOCK(rxr);
140961ae650dSJack F Vogel }
141061ae650dSJack F Vogel 
141161ae650dSJack F Vogel 
14124294f337SSean Bruno static inline void
141361ae650dSJack F Vogel ixl_rx_discard(struct rx_ring *rxr, int i)
141461ae650dSJack F Vogel {
141561ae650dSJack F Vogel 	struct ixl_rx_buf	*rbuf;
141661ae650dSJack F Vogel 
141761ae650dSJack F Vogel 	rbuf = &rxr->buffers[i];
141861ae650dSJack F Vogel 
141961ae650dSJack F Vogel         if (rbuf->fmp != NULL) {/* Partial chain ? */
142061ae650dSJack F Vogel 		rbuf->fmp->m_flags |= M_PKTHDR;
142161ae650dSJack F Vogel                 m_freem(rbuf->fmp);
142261ae650dSJack F Vogel                 rbuf->fmp = NULL;
142361ae650dSJack F Vogel 	}
142461ae650dSJack F Vogel 
142561ae650dSJack F Vogel 	/*
142661ae650dSJack F Vogel 	** With advanced descriptors the writeback
142761ae650dSJack F Vogel 	** clobbers the buffer addrs, so its easier
142861ae650dSJack F Vogel 	** to just free the existing mbufs and take
142961ae650dSJack F Vogel 	** the normal refresh path to get new buffers
143061ae650dSJack F Vogel 	** and mapping.
143161ae650dSJack F Vogel 	*/
143261ae650dSJack F Vogel 	if (rbuf->m_head) {
143361ae650dSJack F Vogel 		m_free(rbuf->m_head);
143461ae650dSJack F Vogel 		rbuf->m_head = NULL;
143561ae650dSJack F Vogel 	}
143661ae650dSJack F Vogel 
143761ae650dSJack F Vogel 	if (rbuf->m_pack) {
143861ae650dSJack F Vogel 		m_free(rbuf->m_pack);
143961ae650dSJack F Vogel 		rbuf->m_pack = NULL;
144061ae650dSJack F Vogel 	}
144161ae650dSJack F Vogel 
144261ae650dSJack F Vogel 	return;
144361ae650dSJack F Vogel }
144461ae650dSJack F Vogel 
14456b30e6aeSJack F Vogel #ifdef RSS
14466b30e6aeSJack F Vogel /*
1447b6c8f260SJack F Vogel ** i40e_ptype_to_hash: parse the packet type
14486b30e6aeSJack F Vogel ** to determine the appropriate hash.
14496b30e6aeSJack F Vogel */
14506b30e6aeSJack F Vogel static inline int
14516b30e6aeSJack F Vogel ixl_ptype_to_hash(u8 ptype)
14526b30e6aeSJack F Vogel {
14536b30e6aeSJack F Vogel         struct i40e_rx_ptype_decoded	decoded;
1454b2bdc62aSAdrian Chadd 	u8				ex = 0;
14556b30e6aeSJack F Vogel 
1456dcd7b3b2SJack F Vogel 	decoded = decode_rx_desc_ptype(ptype);
14576b30e6aeSJack F Vogel 	ex = decoded.outer_frag;
14586b30e6aeSJack F Vogel 
14596b30e6aeSJack F Vogel 	if (!decoded.known)
146036ad8372SSepherosa Ziehau 		return M_HASHTYPE_OPAQUE_HASH;
14616b30e6aeSJack F Vogel 
14626b30e6aeSJack F Vogel 	if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_L2)
146336ad8372SSepherosa Ziehau 		return M_HASHTYPE_OPAQUE_HASH;
14646b30e6aeSJack F Vogel 
14656b30e6aeSJack F Vogel 	/* Note: anything that gets to this point is IP */
14666b30e6aeSJack F Vogel         if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) {
14676b30e6aeSJack F Vogel 		switch (decoded.inner_prot) {
14686b30e6aeSJack F Vogel 			case I40E_RX_PTYPE_INNER_PROT_TCP:
14696b30e6aeSJack F Vogel 				if (ex)
14706b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_TCP_IPV6_EX;
14716b30e6aeSJack F Vogel 				else
14726b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_TCP_IPV6;
14736b30e6aeSJack F Vogel 			case I40E_RX_PTYPE_INNER_PROT_UDP:
14746b30e6aeSJack F Vogel 				if (ex)
14756b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_UDP_IPV6_EX;
14766b30e6aeSJack F Vogel 				else
14776b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_UDP_IPV6;
14786b30e6aeSJack F Vogel 			default:
14796b30e6aeSJack F Vogel 				if (ex)
14806b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_IPV6_EX;
14816b30e6aeSJack F Vogel 				else
14826b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_IPV6;
14836b30e6aeSJack F Vogel 		}
14846b30e6aeSJack F Vogel 	}
14856b30e6aeSJack F Vogel         if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) {
14866b30e6aeSJack F Vogel 		switch (decoded.inner_prot) {
14876b30e6aeSJack F Vogel 			case I40E_RX_PTYPE_INNER_PROT_TCP:
14886b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_TCP_IPV4;
14896b30e6aeSJack F Vogel 			case I40E_RX_PTYPE_INNER_PROT_UDP:
14906b30e6aeSJack F Vogel 				if (ex)
14916b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_UDP_IPV4_EX;
14926b30e6aeSJack F Vogel 				else
14936b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_UDP_IPV4;
14946b30e6aeSJack F Vogel 			default:
14956b30e6aeSJack F Vogel 					return M_HASHTYPE_RSS_IPV4;
14966b30e6aeSJack F Vogel 		}
14976b30e6aeSJack F Vogel 	}
14986b30e6aeSJack F Vogel 	/* We should never get here!! */
149936ad8372SSepherosa Ziehau 	return M_HASHTYPE_OPAQUE_HASH;
15006b30e6aeSJack F Vogel }
15016b30e6aeSJack F Vogel #endif /* RSS */
150261ae650dSJack F Vogel 
150361ae650dSJack F Vogel /*********************************************************************
150461ae650dSJack F Vogel  *
150561ae650dSJack F Vogel  *  This routine executes in interrupt context. It replenishes
150661ae650dSJack F Vogel  *  the mbufs in the descriptor and sends data which has been
150761ae650dSJack F Vogel  *  dma'ed into host memory to upper layer.
150861ae650dSJack F Vogel  *
150961ae650dSJack F Vogel  *  We loop at most count times if count is > 0, or until done if
151061ae650dSJack F Vogel  *  count < 0.
151161ae650dSJack F Vogel  *
151261ae650dSJack F Vogel  *  Return TRUE for more work, FALSE for all clean.
151361ae650dSJack F Vogel  *********************************************************************/
151461ae650dSJack F Vogel bool
151561ae650dSJack F Vogel ixl_rxeof(struct ixl_queue *que, int count)
151661ae650dSJack F Vogel {
151761ae650dSJack F Vogel 	struct ixl_vsi		*vsi = que->vsi;
151861ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
151961ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
1520b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET)
152161ae650dSJack F Vogel 	struct lro_ctrl		*lro = &rxr->lro;
1522b3f7259bSBjoern A. Zeeb #endif
152361ae650dSJack F Vogel 	int			i, nextp, processed = 0;
152461ae650dSJack F Vogel 	union i40e_rx_desc	*cur;
152561ae650dSJack F Vogel 	struct ixl_rx_buf	*rbuf, *nbuf;
152661ae650dSJack F Vogel 
152761ae650dSJack F Vogel 
152861ae650dSJack F Vogel 	IXL_RX_LOCK(rxr);
152961ae650dSJack F Vogel 
153031830672SJack F Vogel #ifdef DEV_NETMAP
153131830672SJack F Vogel 	if (netmap_rx_irq(ifp, que->me, &count)) {
153231830672SJack F Vogel 		IXL_RX_UNLOCK(rxr);
153331830672SJack F Vogel 		return (FALSE);
153431830672SJack F Vogel 	}
153531830672SJack F Vogel #endif /* DEV_NETMAP */
1536e5100ee2SJack F Vogel 
153761ae650dSJack F Vogel 	for (i = rxr->next_check; count != 0;) {
153861ae650dSJack F Vogel 		struct mbuf	*sendmp, *mh, *mp;
15394294f337SSean Bruno 		u32		status, error;
154061ae650dSJack F Vogel 		u16		hlen, plen, vtag;
154161ae650dSJack F Vogel 		u64		qword;
154261ae650dSJack F Vogel 		u8		ptype;
154361ae650dSJack F Vogel 		bool		eop;
154461ae650dSJack F Vogel 
154561ae650dSJack F Vogel 		/* Sync the ring. */
154661ae650dSJack F Vogel 		bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
154761ae650dSJack F Vogel 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
154861ae650dSJack F Vogel 
154961ae650dSJack F Vogel 		cur = &rxr->base[i];
155061ae650dSJack F Vogel 		qword = le64toh(cur->wb.qword1.status_error_len);
155161ae650dSJack F Vogel 		status = (qword & I40E_RXD_QW1_STATUS_MASK)
155261ae650dSJack F Vogel 		    >> I40E_RXD_QW1_STATUS_SHIFT;
155361ae650dSJack F Vogel 		error = (qword & I40E_RXD_QW1_ERROR_MASK)
155461ae650dSJack F Vogel 		    >> I40E_RXD_QW1_ERROR_SHIFT;
155561ae650dSJack F Vogel 		plen = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
155661ae650dSJack F Vogel 		    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
155761ae650dSJack F Vogel 		hlen = (qword & I40E_RXD_QW1_LENGTH_HBUF_MASK)
155861ae650dSJack F Vogel 		    >> I40E_RXD_QW1_LENGTH_HBUF_SHIFT;
155961ae650dSJack F Vogel 		ptype = (qword & I40E_RXD_QW1_PTYPE_MASK)
156061ae650dSJack F Vogel 		    >> I40E_RXD_QW1_PTYPE_SHIFT;
156161ae650dSJack F Vogel 
156261ae650dSJack F Vogel 		if ((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) == 0) {
156361ae650dSJack F Vogel 			++rxr->not_done;
156461ae650dSJack F Vogel 			break;
156561ae650dSJack F Vogel 		}
156661ae650dSJack F Vogel 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
156761ae650dSJack F Vogel 			break;
156861ae650dSJack F Vogel 
156961ae650dSJack F Vogel 		count--;
157061ae650dSJack F Vogel 		sendmp = NULL;
157161ae650dSJack F Vogel 		nbuf = NULL;
157261ae650dSJack F Vogel 		cur->wb.qword1.status_error_len = 0;
157361ae650dSJack F Vogel 		rbuf = &rxr->buffers[i];
157461ae650dSJack F Vogel 		mh = rbuf->m_head;
157561ae650dSJack F Vogel 		mp = rbuf->m_pack;
157661ae650dSJack F Vogel 		eop = (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT));
157761ae650dSJack F Vogel 		if (status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT))
157861ae650dSJack F Vogel 			vtag = le16toh(cur->wb.qword0.lo_dword.l2tag1);
157961ae650dSJack F Vogel 		else
158061ae650dSJack F Vogel 			vtag = 0;
158161ae650dSJack F Vogel 
158261ae650dSJack F Vogel 		/*
158361ae650dSJack F Vogel 		** Make sure bad packets are discarded,
158461ae650dSJack F Vogel 		** note that only EOP descriptor has valid
158561ae650dSJack F Vogel 		** error results.
158661ae650dSJack F Vogel 		*/
158761ae650dSJack F Vogel                 if (eop && (error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
15886d011ad5SEric Joyner 			rxr->desc_errs++;
158961ae650dSJack F Vogel 			ixl_rx_discard(rxr, i);
159061ae650dSJack F Vogel 			goto next_desc;
159161ae650dSJack F Vogel 		}
159261ae650dSJack F Vogel 
159361ae650dSJack F Vogel 		/* Prefetch the next buffer */
159461ae650dSJack F Vogel 		if (!eop) {
159561ae650dSJack F Vogel 			nextp = i + 1;
159661ae650dSJack F Vogel 			if (nextp == que->num_desc)
159761ae650dSJack F Vogel 				nextp = 0;
159861ae650dSJack F Vogel 			nbuf = &rxr->buffers[nextp];
159961ae650dSJack F Vogel 			prefetch(nbuf);
160061ae650dSJack F Vogel 		}
160161ae650dSJack F Vogel 
160261ae650dSJack F Vogel 		/*
160361ae650dSJack F Vogel 		** The header mbuf is ONLY used when header
160461ae650dSJack F Vogel 		** split is enabled, otherwise we get normal
160561ae650dSJack F Vogel 		** behavior, ie, both header and payload
160661ae650dSJack F Vogel 		** are DMA'd into the payload buffer.
160761ae650dSJack F Vogel 		**
160861ae650dSJack F Vogel 		** Rather than using the fmp/lmp global pointers
160961ae650dSJack F Vogel 		** we now keep the head of a packet chain in the
161061ae650dSJack F Vogel 		** buffer struct and pass this along from one
161161ae650dSJack F Vogel 		** descriptor to the next, until we get EOP.
161261ae650dSJack F Vogel 		*/
161361ae650dSJack F Vogel 		if (rxr->hdr_split && (rbuf->fmp == NULL)) {
161461ae650dSJack F Vogel 			if (hlen > IXL_RX_HDR)
161561ae650dSJack F Vogel 				hlen = IXL_RX_HDR;
161661ae650dSJack F Vogel 			mh->m_len = hlen;
161761ae650dSJack F Vogel 			mh->m_flags |= M_PKTHDR;
161861ae650dSJack F Vogel 			mh->m_next = NULL;
161961ae650dSJack F Vogel 			mh->m_pkthdr.len = mh->m_len;
162061ae650dSJack F Vogel 			/* Null buf pointer so it is refreshed */
162161ae650dSJack F Vogel 			rbuf->m_head = NULL;
162261ae650dSJack F Vogel 			/*
162361ae650dSJack F Vogel 			** Check the payload length, this
162461ae650dSJack F Vogel 			** could be zero if its a small
162561ae650dSJack F Vogel 			** packet.
162661ae650dSJack F Vogel 			*/
162761ae650dSJack F Vogel 			if (plen > 0) {
162861ae650dSJack F Vogel 				mp->m_len = plen;
162961ae650dSJack F Vogel 				mp->m_next = NULL;
163061ae650dSJack F Vogel 				mp->m_flags &= ~M_PKTHDR;
163161ae650dSJack F Vogel 				mh->m_next = mp;
163261ae650dSJack F Vogel 				mh->m_pkthdr.len += mp->m_len;
163361ae650dSJack F Vogel 				/* Null buf pointer so it is refreshed */
163461ae650dSJack F Vogel 				rbuf->m_pack = NULL;
163561ae650dSJack F Vogel 				rxr->split++;
163661ae650dSJack F Vogel 			}
163761ae650dSJack F Vogel 			/*
163861ae650dSJack F Vogel 			** Now create the forward
163961ae650dSJack F Vogel 			** chain so when complete
164061ae650dSJack F Vogel 			** we wont have to.
164161ae650dSJack F Vogel 			*/
164261ae650dSJack F Vogel                         if (eop == 0) {
164361ae650dSJack F Vogel 				/* stash the chain head */
164461ae650dSJack F Vogel                                 nbuf->fmp = mh;
164561ae650dSJack F Vogel 				/* Make forward chain */
164661ae650dSJack F Vogel                                 if (plen)
164761ae650dSJack F Vogel                                         mp->m_next = nbuf->m_pack;
164861ae650dSJack F Vogel                                 else
164961ae650dSJack F Vogel                                         mh->m_next = nbuf->m_pack;
165061ae650dSJack F Vogel                         } else {
165161ae650dSJack F Vogel 				/* Singlet, prepare to send */
165261ae650dSJack F Vogel                                 sendmp = mh;
165361ae650dSJack F Vogel                                 if (vtag) {
165461ae650dSJack F Vogel                                         sendmp->m_pkthdr.ether_vtag = vtag;
165561ae650dSJack F Vogel                                         sendmp->m_flags |= M_VLANTAG;
165661ae650dSJack F Vogel                                 }
165761ae650dSJack F Vogel                         }
165861ae650dSJack F Vogel 		} else {
165961ae650dSJack F Vogel 			/*
166061ae650dSJack F Vogel 			** Either no header split, or a
166161ae650dSJack F Vogel 			** secondary piece of a fragmented
166261ae650dSJack F Vogel 			** split packet.
166361ae650dSJack F Vogel 			*/
166461ae650dSJack F Vogel 			mp->m_len = plen;
166561ae650dSJack F Vogel 			/*
166661ae650dSJack F Vogel 			** See if there is a stored head
166761ae650dSJack F Vogel 			** that determines what we are
166861ae650dSJack F Vogel 			*/
166961ae650dSJack F Vogel 			sendmp = rbuf->fmp;
167061ae650dSJack F Vogel 			rbuf->m_pack = rbuf->fmp = NULL;
167161ae650dSJack F Vogel 
167261ae650dSJack F Vogel 			if (sendmp != NULL) /* secondary frag */
167361ae650dSJack F Vogel 				sendmp->m_pkthdr.len += mp->m_len;
167461ae650dSJack F Vogel 			else {
167561ae650dSJack F Vogel 				/* first desc of a non-ps chain */
167661ae650dSJack F Vogel 				sendmp = mp;
167761ae650dSJack F Vogel 				sendmp->m_flags |= M_PKTHDR;
167861ae650dSJack F Vogel 				sendmp->m_pkthdr.len = mp->m_len;
167961ae650dSJack F Vogel                         }
168061ae650dSJack F Vogel 			/* Pass the head pointer on */
168161ae650dSJack F Vogel 			if (eop == 0) {
168261ae650dSJack F Vogel 				nbuf->fmp = sendmp;
168361ae650dSJack F Vogel 				sendmp = NULL;
168461ae650dSJack F Vogel 				mp->m_next = nbuf->m_pack;
168561ae650dSJack F Vogel 			}
168661ae650dSJack F Vogel 		}
168761ae650dSJack F Vogel 		++processed;
168861ae650dSJack F Vogel 		/* Sending this frame? */
168961ae650dSJack F Vogel 		if (eop) {
169061ae650dSJack F Vogel 			sendmp->m_pkthdr.rcvif = ifp;
169161ae650dSJack F Vogel 			/* gather stats */
169261ae650dSJack F Vogel 			rxr->rx_packets++;
169361ae650dSJack F Vogel 			rxr->rx_bytes += sendmp->m_pkthdr.len;
169461ae650dSJack F Vogel 			/* capture data for dynamic ITR adjustment */
169561ae650dSJack F Vogel 			rxr->packets++;
169661ae650dSJack F Vogel 			rxr->bytes += sendmp->m_pkthdr.len;
16974294f337SSean Bruno 			/* Set VLAN tag (field only valid in eop desc) */
16984294f337SSean Bruno 			if (vtag) {
16994294f337SSean Bruno 				sendmp->m_pkthdr.ether_vtag = vtag;
17004294f337SSean Bruno 				sendmp->m_flags |= M_VLANTAG;
17014294f337SSean Bruno 			}
170261ae650dSJack F Vogel 			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
170361ae650dSJack F Vogel 				ixl_rx_checksum(sendmp, status, error, ptype);
1704845a028fSJack F Vogel #ifdef RSS
17056b30e6aeSJack F Vogel 			sendmp->m_pkthdr.flowid =
17066b30e6aeSJack F Vogel 			    le32toh(cur->wb.qword0.hi_dword.rss);
17076b30e6aeSJack F Vogel 			M_HASHTYPE_SET(sendmp, ixl_ptype_to_hash(ptype));
17086b30e6aeSJack F Vogel #else
170961ae650dSJack F Vogel 			sendmp->m_pkthdr.flowid = que->msix;
1710845a028fSJack F Vogel 			M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE);
17116b30e6aeSJack F Vogel #endif
171261ae650dSJack F Vogel 		}
171361ae650dSJack F Vogel next_desc:
171461ae650dSJack F Vogel 		bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
171561ae650dSJack F Vogel 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
171661ae650dSJack F Vogel 
171761ae650dSJack F Vogel 		/* Advance our pointers to the next descriptor. */
171861ae650dSJack F Vogel 		if (++i == que->num_desc)
171961ae650dSJack F Vogel 			i = 0;
172061ae650dSJack F Vogel 
172161ae650dSJack F Vogel 		/* Now send to the stack or do LRO */
172261ae650dSJack F Vogel 		if (sendmp != NULL) {
172361ae650dSJack F Vogel 			rxr->next_check = i;
172461ae650dSJack F Vogel 			ixl_rx_input(rxr, ifp, sendmp, ptype);
172561ae650dSJack F Vogel 			i = rxr->next_check;
172661ae650dSJack F Vogel 		}
172761ae650dSJack F Vogel 
172861ae650dSJack F Vogel                /* Every 8 descriptors we go to refresh mbufs */
172961ae650dSJack F Vogel 		if (processed == 8) {
173061ae650dSJack F Vogel 			ixl_refresh_mbufs(que, i);
173161ae650dSJack F Vogel 			processed = 0;
173261ae650dSJack F Vogel 		}
173361ae650dSJack F Vogel 	}
173461ae650dSJack F Vogel 
173561ae650dSJack F Vogel 	/* Refresh any remaining buf structs */
173661ae650dSJack F Vogel 	if (ixl_rx_unrefreshed(que))
173761ae650dSJack F Vogel 		ixl_refresh_mbufs(que, i);
173861ae650dSJack F Vogel 
173961ae650dSJack F Vogel 	rxr->next_check = i;
174061ae650dSJack F Vogel 
1741b3f7259bSBjoern A. Zeeb #if defined(INET6) || defined(INET)
174261ae650dSJack F Vogel 	/*
174361ae650dSJack F Vogel 	 * Flush any outstanding LRO work
174461ae650dSJack F Vogel 	 */
1745*cb6b8299SEric Joyner #if __FreeBSD_version >= 1100105
17466dd38b87SSepherosa Ziehau 	tcp_lro_flush_all(lro);
1747*cb6b8299SEric Joyner #else
1748*cb6b8299SEric Joyner 	struct lro_entry *queued;
1749*cb6b8299SEric Joyner 	while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
1750*cb6b8299SEric Joyner 		SLIST_REMOVE_HEAD(&lro->lro_active, next);
1751*cb6b8299SEric Joyner 		tcp_lro_flush(lro, queued);
1752*cb6b8299SEric Joyner 	}
1753b3f7259bSBjoern A. Zeeb #endif
1754*cb6b8299SEric Joyner #endif /* defined(INET6) || defined(INET) */
175561ae650dSJack F Vogel 
175661ae650dSJack F Vogel 	IXL_RX_UNLOCK(rxr);
175761ae650dSJack F Vogel 	return (FALSE);
175861ae650dSJack F Vogel }
175961ae650dSJack F Vogel 
176061ae650dSJack F Vogel 
176161ae650dSJack F Vogel /*********************************************************************
176261ae650dSJack F Vogel  *
176361ae650dSJack F Vogel  *  Verify that the hardware indicated that the checksum is valid.
176461ae650dSJack F Vogel  *  Inform the stack about the status of checksum so that stack
176561ae650dSJack F Vogel  *  doesn't spend time verifying the checksum.
176661ae650dSJack F Vogel  *
176761ae650dSJack F Vogel  *********************************************************************/
176861ae650dSJack F Vogel static void
176961ae650dSJack F Vogel ixl_rx_checksum(struct mbuf * mp, u32 status, u32 error, u8 ptype)
177061ae650dSJack F Vogel {
177161ae650dSJack F Vogel 	struct i40e_rx_ptype_decoded decoded;
177261ae650dSJack F Vogel 
177361ae650dSJack F Vogel 	decoded = decode_rx_desc_ptype(ptype);
177461ae650dSJack F Vogel 
177561ae650dSJack F Vogel 	/* Errors? */
177661ae650dSJack F Vogel  	if (error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
177761ae650dSJack F Vogel 	    (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))) {
177861ae650dSJack F Vogel 		mp->m_pkthdr.csum_flags = 0;
177961ae650dSJack F Vogel 		return;
178061ae650dSJack F Vogel 	}
178161ae650dSJack F Vogel 
178261ae650dSJack F Vogel 	/* IPv6 with extension headers likely have bad csum */
178361ae650dSJack F Vogel 	if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
178461ae650dSJack F Vogel 	    decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
178561ae650dSJack F Vogel 		if (status &
178661ae650dSJack F Vogel 		    (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) {
178761ae650dSJack F Vogel 			mp->m_pkthdr.csum_flags = 0;
178861ae650dSJack F Vogel 			return;
178961ae650dSJack F Vogel 		}
179061ae650dSJack F Vogel 
179161ae650dSJack F Vogel 
179261ae650dSJack F Vogel 	/* IP Checksum Good */
179361ae650dSJack F Vogel 	mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
179461ae650dSJack F Vogel 	mp->m_pkthdr.csum_flags |= CSUM_IP_VALID;
179561ae650dSJack F Vogel 
179661ae650dSJack F Vogel 	if (status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)) {
179761ae650dSJack F Vogel 		mp->m_pkthdr.csum_flags |=
179861ae650dSJack F Vogel 		    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
179961ae650dSJack F Vogel 		mp->m_pkthdr.csum_data |= htons(0xffff);
180061ae650dSJack F Vogel 	}
180161ae650dSJack F Vogel 	return;
180261ae650dSJack F Vogel }
18034b443922SGleb Smirnoff 
18044b443922SGleb Smirnoff #if __FreeBSD_version >= 1100000
18054b443922SGleb Smirnoff uint64_t
18064b443922SGleb Smirnoff ixl_get_counter(if_t ifp, ift_counter cnt)
18074b443922SGleb Smirnoff {
18084b443922SGleb Smirnoff 	struct ixl_vsi *vsi;
18094b443922SGleb Smirnoff 
18104b443922SGleb Smirnoff 	vsi = if_getsoftc(ifp);
18114b443922SGleb Smirnoff 
18124b443922SGleb Smirnoff 	switch (cnt) {
18134b443922SGleb Smirnoff 	case IFCOUNTER_IPACKETS:
18144b443922SGleb Smirnoff 		return (vsi->ipackets);
18154b443922SGleb Smirnoff 	case IFCOUNTER_IERRORS:
18164b443922SGleb Smirnoff 		return (vsi->ierrors);
18174b443922SGleb Smirnoff 	case IFCOUNTER_OPACKETS:
18184b443922SGleb Smirnoff 		return (vsi->opackets);
18194b443922SGleb Smirnoff 	case IFCOUNTER_OERRORS:
18204b443922SGleb Smirnoff 		return (vsi->oerrors);
18214b443922SGleb Smirnoff 	case IFCOUNTER_COLLISIONS:
18224b443922SGleb Smirnoff 		/* Collisions are by standard impossible in 40G/10G Ethernet */
18234b443922SGleb Smirnoff 		return (0);
18244b443922SGleb Smirnoff 	case IFCOUNTER_IBYTES:
18254b443922SGleb Smirnoff 		return (vsi->ibytes);
18264b443922SGleb Smirnoff 	case IFCOUNTER_OBYTES:
18274b443922SGleb Smirnoff 		return (vsi->obytes);
18284b443922SGleb Smirnoff 	case IFCOUNTER_IMCASTS:
18294b443922SGleb Smirnoff 		return (vsi->imcasts);
18304b443922SGleb Smirnoff 	case IFCOUNTER_OMCASTS:
18314b443922SGleb Smirnoff 		return (vsi->omcasts);
18324b443922SGleb Smirnoff 	case IFCOUNTER_IQDROPS:
18334b443922SGleb Smirnoff 		return (vsi->iqdrops);
18344b443922SGleb Smirnoff 	case IFCOUNTER_OQDROPS:
18354b443922SGleb Smirnoff 		return (vsi->oqdrops);
18364b443922SGleb Smirnoff 	case IFCOUNTER_NOPROTO:
18374b443922SGleb Smirnoff 		return (vsi->noproto);
18384b443922SGleb Smirnoff 	default:
18394b443922SGleb Smirnoff 		return (if_get_counter_default(ifp, cnt));
18404b443922SGleb Smirnoff 	}
18414b443922SGleb Smirnoff }
18424b443922SGleb Smirnoff #endif
1843e5100ee2SJack F Vogel 
1844