xref: /freebsd-src/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c (revision 0fc7bdc978366abb4351b0b76b50a5848cc5d982)
1dc7e38acSHans Petter Selasky /*-
22d5e5a0dSHans Petter Selasky  * Copyright (c) 2015-2021 Mellanox Technologies. All rights reserved.
3dc7e38acSHans Petter Selasky  *
4dc7e38acSHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
5dc7e38acSHans Petter Selasky  * modification, are permitted provided that the following conditions
6dc7e38acSHans Petter Selasky  * are met:
7dc7e38acSHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
8dc7e38acSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
9dc7e38acSHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
10dc7e38acSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
11dc7e38acSHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
12dc7e38acSHans Petter Selasky  *
13dc7e38acSHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14dc7e38acSHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15dc7e38acSHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16dc7e38acSHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17dc7e38acSHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18dc7e38acSHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19dc7e38acSHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20dc7e38acSHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21dc7e38acSHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22dc7e38acSHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23dc7e38acSHans Petter Selasky  * SUCH DAMAGE.
24dc7e38acSHans Petter Selasky  */
25dc7e38acSHans Petter Selasky 
26b984b956SKonstantin Belousov #include "opt_rss.h"
27b984b956SKonstantin Belousov #include "opt_ratelimit.h"
28b984b956SKonstantin Belousov 
2989918a23SKonstantin Belousov #include <dev/mlx5/mlx5_en/en.h>
30dc7e38acSHans Petter Selasky #include <machine/in_cksum.h>
31e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_accel/ipsec.h>
32dc7e38acSHans Petter Selasky 
33dc7e38acSHans Petter Selasky static inline int
34dc7e38acSHans Petter Selasky mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq,
35dc7e38acSHans Petter Selasky     struct mlx5e_rx_wqe *wqe, u16 ix)
36dc7e38acSHans Petter Selasky {
378b825a18SHans Petter Selasky 	bus_dma_segment_t segs[MLX5E_MAX_BUSDMA_RX_SEGS];
38dc7e38acSHans Petter Selasky 	struct mbuf *mb;
39dc7e38acSHans Petter Selasky 	int nsegs;
40dc7e38acSHans Petter Selasky 	int err;
412f17f76aSHans Petter Selasky 	struct mbuf *mb_head;
422f17f76aSHans Petter Selasky 	int i;
434d0e6d84SHans Petter Selasky 
44dc7e38acSHans Petter Selasky 	if (rq->mbuf[ix].mbuf != NULL)
45dc7e38acSHans Petter Selasky 		return (0);
46dc7e38acSHans Petter Selasky 
472f17f76aSHans Petter Selasky 	mb_head = mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
482f17f76aSHans Petter Selasky 	    MLX5E_MAX_RX_BYTES);
492f17f76aSHans Petter Selasky 	if (unlikely(mb == NULL))
502f17f76aSHans Petter Selasky 		return (-ENOMEM);
51dc7e38acSHans Petter Selasky 
522f17f76aSHans Petter Selasky 	mb->m_len = MLX5E_MAX_RX_BYTES;
532f17f76aSHans Petter Selasky 	mb->m_pkthdr.len = MLX5E_MAX_RX_BYTES;
542f17f76aSHans Petter Selasky 
552f17f76aSHans Petter Selasky 	for (i = 1; i < rq->nsegs; i++) {
562f17f76aSHans Petter Selasky 		if (mb_head->m_pkthdr.len >= rq->wqe_sz)
572f17f76aSHans Petter Selasky 			break;
582f17f76aSHans Petter Selasky 		mb = mb->m_next = m_getjcl(M_NOWAIT, MT_DATA, 0,
592f17f76aSHans Petter Selasky 		    MLX5E_MAX_RX_BYTES);
602f17f76aSHans Petter Selasky 		if (unlikely(mb == NULL)) {
612f17f76aSHans Petter Selasky 			m_freem(mb_head);
622f17f76aSHans Petter Selasky 			return (-ENOMEM);
632f17f76aSHans Petter Selasky 		}
642f17f76aSHans Petter Selasky 		mb->m_len = MLX5E_MAX_RX_BYTES;
652f17f76aSHans Petter Selasky 		mb_head->m_pkthdr.len += MLX5E_MAX_RX_BYTES;
662f17f76aSHans Petter Selasky 	}
672f17f76aSHans Petter Selasky 	/* rewind to first mbuf in chain */
682f17f76aSHans Petter Selasky 	mb = mb_head;
694d0e6d84SHans Petter Selasky 
70dc7e38acSHans Petter Selasky 	/* get IP header aligned */
71dc7e38acSHans Petter Selasky 	m_adj(mb, MLX5E_NET_IP_ALIGN);
72dc7e38acSHans Petter Selasky 
73d00f3505SKonstantin Belousov 	err = mlx5_accel_ipsec_rx_tag_add(rq->ifp, &rq->mbuf[ix]);
74e23731dbSKonstantin Belousov 	if (err)
75e23731dbSKonstantin Belousov 		goto err_free_mbuf;
76dc7e38acSHans Petter Selasky 	err = -bus_dmamap_load_mbuf_sg(rq->dma_tag, rq->mbuf[ix].dma_map,
77dc7e38acSHans Petter Selasky 	    mb, segs, &nsegs, BUS_DMA_NOWAIT);
78dc7e38acSHans Petter Selasky 	if (err != 0)
79dc7e38acSHans Petter Selasky 		goto err_free_mbuf;
802f17f76aSHans Petter Selasky 	if (unlikely(nsegs == 0)) {
81dc7e38acSHans Petter Selasky 		bus_dmamap_unload(rq->dma_tag, rq->mbuf[ix].dma_map);
82dc7e38acSHans Petter Selasky 		err = -ENOMEM;
83dc7e38acSHans Petter Selasky 		goto err_free_mbuf;
84dc7e38acSHans Petter Selasky 	}
852f17f76aSHans Petter Selasky 	wqe->data[0].addr = cpu_to_be64(segs[0].ds_addr);
862f17f76aSHans Petter Selasky 	wqe->data[0].byte_count = cpu_to_be32(segs[0].ds_len |
872f17f76aSHans Petter Selasky 	    MLX5_HW_START_PADDING);
882f17f76aSHans Petter Selasky 	for (i = 1; i != nsegs; i++) {
892f17f76aSHans Petter Selasky 		wqe->data[i].addr = cpu_to_be64(segs[i].ds_addr);
902f17f76aSHans Petter Selasky 		wqe->data[i].byte_count = cpu_to_be32(segs[i].ds_len);
912f17f76aSHans Petter Selasky 	}
922f17f76aSHans Petter Selasky 	for (; i < rq->nsegs; i++) {
932f17f76aSHans Petter Selasky 		wqe->data[i].addr = 0;
942f17f76aSHans Petter Selasky 		wqe->data[i].byte_count = 0;
952f17f76aSHans Petter Selasky 	}
96dc7e38acSHans Petter Selasky 
97dc7e38acSHans Petter Selasky 	rq->mbuf[ix].mbuf = mb;
98dc7e38acSHans Petter Selasky 	rq->mbuf[ix].data = mb->m_data;
99dc7e38acSHans Petter Selasky 
100dc7e38acSHans Petter Selasky 	bus_dmamap_sync(rq->dma_tag, rq->mbuf[ix].dma_map,
101dc7e38acSHans Petter Selasky 	    BUS_DMASYNC_PREREAD);
102dc7e38acSHans Petter Selasky 	return (0);
103dc7e38acSHans Petter Selasky 
104dc7e38acSHans Petter Selasky err_free_mbuf:
105dc7e38acSHans Petter Selasky 	m_freem(mb);
106dc7e38acSHans Petter Selasky 	return (err);
107dc7e38acSHans Petter Selasky }
108dc7e38acSHans Petter Selasky 
109dc7e38acSHans Petter Selasky static void
110dc7e38acSHans Petter Selasky mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
111dc7e38acSHans Petter Selasky {
112dc7e38acSHans Petter Selasky 	if (unlikely(rq->enabled == 0))
113dc7e38acSHans Petter Selasky 		return;
114dc7e38acSHans Petter Selasky 
115dc7e38acSHans Petter Selasky 	while (!mlx5_wq_ll_is_full(&rq->wq)) {
116dc7e38acSHans Petter Selasky 		struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(&rq->wq, rq->wq.head);
117dc7e38acSHans Petter Selasky 
1186f4cab6cSHans Petter Selasky 		if (unlikely(mlx5e_alloc_rx_wqe(rq, wqe, rq->wq.head))) {
1196f4cab6cSHans Petter Selasky 			callout_reset_curcpu(&rq->watchdog, 1, (void *)&mlx5e_post_rx_wqes, rq);
120dc7e38acSHans Petter Selasky 			break;
1216f4cab6cSHans Petter Selasky 		}
122dc7e38acSHans Petter Selasky 		mlx5_wq_ll_push(&rq->wq, be16_to_cpu(wqe->next.next_wqe_index));
123dc7e38acSHans Petter Selasky 	}
124dc7e38acSHans Petter Selasky 
125dc7e38acSHans Petter Selasky 	/* ensure wqes are visible to device before updating doorbell record */
126e44f4f35SKonstantin Belousov 	atomic_thread_fence_rel();
127dc7e38acSHans Petter Selasky 
128dc7e38acSHans Petter Selasky 	mlx5_wq_ll_update_db_record(&rq->wq);
129dc7e38acSHans Petter Selasky }
130dc7e38acSHans Petter Selasky 
131dc7e38acSHans Petter Selasky static void
132dc7e38acSHans Petter Selasky mlx5e_lro_update_hdr(struct mbuf *mb, struct mlx5_cqe64 *cqe)
133dc7e38acSHans Petter Selasky {
134dc7e38acSHans Petter Selasky 	/* TODO: consider vlans, ip options, ... */
135dc7e38acSHans Petter Selasky 	struct ether_header *eh;
136dc7e38acSHans Petter Selasky 	uint16_t eh_type;
1371558d49bSHans Petter Selasky 	uint16_t tot_len;
138dc7e38acSHans Petter Selasky 	struct ip6_hdr *ip6 = NULL;
139dc7e38acSHans Petter Selasky 	struct ip *ip4 = NULL;
140dc7e38acSHans Petter Selasky 	struct tcphdr *th;
141dc7e38acSHans Petter Selasky 	uint32_t *ts_ptr;
1421558d49bSHans Petter Selasky 	uint8_t l4_hdr_type;
1431558d49bSHans Petter Selasky 	int tcp_ack;
144dc7e38acSHans Petter Selasky 
145dc7e38acSHans Petter Selasky 	eh = mtod(mb, struct ether_header *);
146dc7e38acSHans Petter Selasky 	eh_type = ntohs(eh->ether_type);
147dc7e38acSHans Petter Selasky 
1481558d49bSHans Petter Selasky 	l4_hdr_type = get_cqe_l4_hdr_type(cqe);
1491558d49bSHans Petter Selasky 	tcp_ack = ((CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA == l4_hdr_type) ||
150dc7e38acSHans Petter Selasky 	    (CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA == l4_hdr_type));
151dc7e38acSHans Petter Selasky 
152dc7e38acSHans Petter Selasky 	/* TODO: consider vlan */
1531558d49bSHans Petter Selasky 	tot_len = be32_to_cpu(cqe->byte_cnt) - ETHER_HDR_LEN;
154dc7e38acSHans Petter Selasky 
155dc7e38acSHans Petter Selasky 	switch (eh_type) {
156dc7e38acSHans Petter Selasky 	case ETHERTYPE_IP:
157dc7e38acSHans Petter Selasky 		ip4 = (struct ip *)(eh + 1);
158dc7e38acSHans Petter Selasky 		th = (struct tcphdr *)(ip4 + 1);
159dc7e38acSHans Petter Selasky 		break;
160dc7e38acSHans Petter Selasky 	case ETHERTYPE_IPV6:
161dc7e38acSHans Petter Selasky 		ip6 = (struct ip6_hdr *)(eh + 1);
162dc7e38acSHans Petter Selasky 		th = (struct tcphdr *)(ip6 + 1);
163dc7e38acSHans Petter Selasky 		break;
164dc7e38acSHans Petter Selasky 	default:
165dc7e38acSHans Petter Selasky 		return;
166dc7e38acSHans Petter Selasky 	}
167dc7e38acSHans Petter Selasky 
168dc7e38acSHans Petter Selasky 	ts_ptr = (uint32_t *)(th + 1);
169dc7e38acSHans Petter Selasky 
170dc7e38acSHans Petter Selasky 	if (get_cqe_lro_tcppsh(cqe))
171*0fc7bdc9SRichard Scheffenegger 		tcp_set_flags(th, tcp_get_flags(th) | TH_PUSH);
172dc7e38acSHans Petter Selasky 
173dc7e38acSHans Petter Selasky 	if (tcp_ack) {
174*0fc7bdc9SRichard Scheffenegger 		tcp_set_flags(th, tcp_get_flags(th) | TH_ACK);
175dc7e38acSHans Petter Selasky 		th->th_ack = cqe->lro_ack_seq_num;
176dc7e38acSHans Petter Selasky 		th->th_win = cqe->lro_tcp_win;
177dc7e38acSHans Petter Selasky 
178bb3853c6SHans Petter Selasky 		/*
179bb3853c6SHans Petter Selasky 		 * FreeBSD handles only 32bit aligned timestamp right after
180bb3853c6SHans Petter Selasky 		 * the TCP hdr
181dc7e38acSHans Petter Selasky 		 * +--------+--------+--------+--------+
182dc7e38acSHans Petter Selasky 		 * |   NOP  |  NOP   |  TSopt |   10   |
183dc7e38acSHans Petter Selasky 		 * +--------+--------+--------+--------+
184dc7e38acSHans Petter Selasky 		 * |          TSval   timestamp        |
185dc7e38acSHans Petter Selasky 		 * +--------+--------+--------+--------+
186dc7e38acSHans Petter Selasky 		 * |          TSecr   timestamp        |
187dc7e38acSHans Petter Selasky 		 * +--------+--------+--------+--------+
188dc7e38acSHans Petter Selasky 		 */
189dc7e38acSHans Petter Selasky 		if (get_cqe_lro_timestamp_valid(cqe) &&
190dc7e38acSHans Petter Selasky 		    (__predict_true(*ts_ptr) == ntohl(TCPOPT_NOP << 24 |
191dc7e38acSHans Petter Selasky 		    TCPOPT_NOP << 16 | TCPOPT_TIMESTAMP << 8 |
192dc7e38acSHans Petter Selasky 		    TCPOLEN_TIMESTAMP))) {
193bb3853c6SHans Petter Selasky 			/*
194bb3853c6SHans Petter Selasky 			 * cqe->timestamp is 64bit long.
195dc7e38acSHans Petter Selasky 			 * [0-31] - timestamp.
196dc7e38acSHans Petter Selasky 			 * [32-64] - timestamp echo replay.
197dc7e38acSHans Petter Selasky 			 */
198dc7e38acSHans Petter Selasky 			ts_ptr[1] = *(uint32_t *)&cqe->timestamp;
199dc7e38acSHans Petter Selasky 			ts_ptr[2] = *((uint32_t *)&cqe->timestamp + 1);
200dc7e38acSHans Petter Selasky 		}
201dc7e38acSHans Petter Selasky 	}
202dc7e38acSHans Petter Selasky 	if (ip4) {
203dc7e38acSHans Petter Selasky 		ip4->ip_ttl = cqe->lro_min_ttl;
204dc7e38acSHans Petter Selasky 		ip4->ip_len = cpu_to_be16(tot_len);
205dc7e38acSHans Petter Selasky 		ip4->ip_sum = 0;
206dc7e38acSHans Petter Selasky 		ip4->ip_sum = in_cksum(mb, ip4->ip_hl << 2);
207dc7e38acSHans Petter Selasky 	} else {
208dc7e38acSHans Petter Selasky 		ip6->ip6_hlim = cqe->lro_min_ttl;
209dc7e38acSHans Petter Selasky 		ip6->ip6_plen = cpu_to_be16(tot_len -
210dc7e38acSHans Petter Selasky 		    sizeof(struct ip6_hdr));
211dc7e38acSHans Petter Selasky 	}
212dc7e38acSHans Petter Selasky 	/* TODO: handle tcp checksum */
213dc7e38acSHans Petter Selasky }
214dc7e38acSHans Petter Selasky 
215ef23f141SKonstantin Belousov static uint64_t
216ef23f141SKonstantin Belousov mlx5e_mbuf_tstmp(struct mlx5e_priv *priv, uint64_t hw_tstmp)
217ef23f141SKonstantin Belousov {
218945f3984SHans Petter Selasky 	struct mlx5e_clbr_point *cp, dcp;
2197cc3ea9cSRandall Stewart 	uint64_t tstmp_sec, tstmp_nsec;
2207cc3ea9cSRandall Stewart 	uint64_t hw_clocks;
2217cc3ea9cSRandall Stewart 	uint64_t rt_cur_to_prev, res_s, res_n, res_s_modulo, res;
2227cc3ea9cSRandall Stewart 	uint64_t hw_clk_div;
223ef23f141SKonstantin Belousov 	u_int gen;
224ef23f141SKonstantin Belousov 
225ef23f141SKonstantin Belousov 	do {
226ef23f141SKonstantin Belousov 		cp = &priv->clbr_points[priv->clbr_curr];
227ef23f141SKonstantin Belousov 		gen = atomic_load_acq_int(&cp->clbr_gen);
228945f3984SHans Petter Selasky 		if (gen == 0)
229945f3984SHans Petter Selasky 			return (0);
230945f3984SHans Petter Selasky 		dcp = *cp;
231945f3984SHans Petter Selasky 		atomic_thread_fence_acq();
2327cc3ea9cSRandall Stewart 	} while (gen != dcp.clbr_gen);
233ef23f141SKonstantin Belousov 	/*
2347cc3ea9cSRandall Stewart 	 * Our goal here is to have a result that is:
2357cc3ea9cSRandall Stewart 	 *
2367cc3ea9cSRandall Stewart 	 * (                             (cur_time - prev_time)   )
2377cc3ea9cSRandall Stewart 	 * ((hw_tstmp - hw_prev) *  ----------------------------- ) + prev_time
2387cc3ea9cSRandall Stewart 	 * (                             (hw_cur - hw_prev)       )
2397cc3ea9cSRandall Stewart 	 *
2407cc3ea9cSRandall Stewart 	 * With the constraints that we cannot use float and we
2417cc3ea9cSRandall Stewart 	 * don't want to overflow the uint64_t numbers we are using.
2427cc3ea9cSRandall Stewart 	 *
2437cc3ea9cSRandall Stewart 	 * The plan is to take the clocking value of the hw timestamps
2447cc3ea9cSRandall Stewart 	 * and split them into seconds and nanosecond equivalent portions.
2457cc3ea9cSRandall Stewart 	 * Then we operate on the two portions seperately making sure to
2467cc3ea9cSRandall Stewart 	 * bring back the carry over from the seconds when we divide.
2477cc3ea9cSRandall Stewart 	 *
2487cc3ea9cSRandall Stewart 	 * First up lets get the two divided into separate entities
2497cc3ea9cSRandall Stewart 	 * i.e. the seconds. We use the clock frequency for this.
2507cc3ea9cSRandall Stewart 	 * Note that priv->cclk was setup with the clock frequency
2517cc3ea9cSRandall Stewart 	 * in hz so we are all set to go.
252ef23f141SKonstantin Belousov 	 */
2537cc3ea9cSRandall Stewart 	hw_clocks = hw_tstmp - dcp.clbr_hw_prev;
2547cc3ea9cSRandall Stewart 	tstmp_sec = hw_clocks / priv->cclk;
2557cc3ea9cSRandall Stewart 	tstmp_nsec = hw_clocks % priv->cclk;
2567cc3ea9cSRandall Stewart 	/* Now work with them separately */
2577cc3ea9cSRandall Stewart 	rt_cur_to_prev = (dcp.base_curr - dcp.base_prev);
2587cc3ea9cSRandall Stewart 	res_s = tstmp_sec * rt_cur_to_prev;
2597cc3ea9cSRandall Stewart 	res_n = tstmp_nsec * rt_cur_to_prev;
2607cc3ea9cSRandall Stewart 	/* Now lets get our divider */
2617cc3ea9cSRandall Stewart 	hw_clk_div = dcp.clbr_hw_curr - dcp.clbr_hw_prev;
2627cc3ea9cSRandall Stewart 	/* Make sure to save the remainder from the seconds divide */
2637cc3ea9cSRandall Stewart 	res_s_modulo = res_s % hw_clk_div;
2647cc3ea9cSRandall Stewart 	res_s /= hw_clk_div;
2657cc3ea9cSRandall Stewart 	/* scale the remainder to where it should be */
2667cc3ea9cSRandall Stewart 	res_s_modulo *= priv->cclk;
2677cc3ea9cSRandall Stewart 	/* Now add in the remainder */
2687cc3ea9cSRandall Stewart 	res_n += res_s_modulo;
2697cc3ea9cSRandall Stewart 	/* Now do the divide */
2707cc3ea9cSRandall Stewart 	res_n /= hw_clk_div;
2717cc3ea9cSRandall Stewart 	res_s *= priv->cclk;
2727cc3ea9cSRandall Stewart 	/* Recombine the two */
2737cc3ea9cSRandall Stewart 	res = res_s + res_n;
2747cc3ea9cSRandall Stewart 	/* And now add in the base time to get to the real timestamp */
275945f3984SHans Petter Selasky 	res += dcp.base_prev;
276ef23f141SKonstantin Belousov 	return (res);
277ef23f141SKonstantin Belousov }
278ef23f141SKonstantin Belousov 
279dc7e38acSHans Petter Selasky static inline void
280d00f3505SKonstantin Belousov mlx5e_build_rx_mbuf(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
281d00f3505SKonstantin Belousov     struct mbuf *mb, struct mlx5e_rq_mbuf *mr, u32 cqe_bcnt)
282dc7e38acSHans Petter Selasky {
2835dc00f00SJustin Hibbits 	if_t ifp = rq->ifp;
284ef23f141SKonstantin Belousov 	struct mlx5e_channel *c;
2852f17f76aSHans Petter Selasky 	struct mbuf *mb_head;
286dc7e38acSHans Petter Selasky 	int lro_num_seg;	/* HW LRO session aggregated packets counter */
287ef23f141SKonstantin Belousov 	uint64_t tstmp;
288dc7e38acSHans Petter Selasky 
289dc7e38acSHans Petter Selasky 	lro_num_seg = be32_to_cpu(cqe->srqn) >> 24;
290dc7e38acSHans Petter Selasky 	if (lro_num_seg > 1) {
291dc7e38acSHans Petter Selasky 		mlx5e_lro_update_hdr(mb, cqe);
292dc7e38acSHans Petter Selasky 		rq->stats.lro_packets++;
293dc7e38acSHans Petter Selasky 		rq->stats.lro_bytes += cqe_bcnt;
294dc7e38acSHans Petter Selasky 	}
295dc7e38acSHans Petter Selasky 
2962f17f76aSHans Petter Selasky 	mb->m_pkthdr.len = cqe_bcnt;
2972f17f76aSHans Petter Selasky 	for (mb_head = mb; mb != NULL; mb = mb->m_next) {
2982f17f76aSHans Petter Selasky 		if (mb->m_len > cqe_bcnt)
2992f17f76aSHans Petter Selasky 			mb->m_len = cqe_bcnt;
3002f17f76aSHans Petter Selasky 		cqe_bcnt -= mb->m_len;
3012f17f76aSHans Petter Selasky 		if (likely(cqe_bcnt == 0)) {
3022f17f76aSHans Petter Selasky 			if (likely(mb->m_next != NULL)) {
3032f17f76aSHans Petter Selasky 				/* trim off empty mbufs */
3042f17f76aSHans Petter Selasky 				m_freem(mb->m_next);
3052f17f76aSHans Petter Selasky 				mb->m_next = NULL;
3062f17f76aSHans Petter Selasky 			}
3072f17f76aSHans Petter Selasky 			break;
3082f17f76aSHans Petter Selasky 		}
3092f17f76aSHans Petter Selasky 	}
3102f17f76aSHans Petter Selasky 	/* rewind to first mbuf in chain */
3112f17f76aSHans Petter Selasky 	mb = mb_head;
3124d0e6d84SHans Petter Selasky 
313dc7e38acSHans Petter Selasky 	/* check if a Toeplitz hash was computed */
314278ce1c9SHans Petter Selasky 	if (cqe->rss_hash_type != 0) {
315dc7e38acSHans Petter Selasky 		mb->m_pkthdr.flowid = be32_to_cpu(cqe->rss_hash_result);
316278ce1c9SHans Petter Selasky #ifdef RSS
317278ce1c9SHans Petter Selasky 		/* decode the RSS hash type */
318278ce1c9SHans Petter Selasky 		switch (cqe->rss_hash_type &
319278ce1c9SHans Petter Selasky 		    (CQE_RSS_DST_HTYPE_L4 | CQE_RSS_DST_HTYPE_IP)) {
320278ce1c9SHans Petter Selasky 		/* IPv4 */
321278ce1c9SHans Petter Selasky 		case (CQE_RSS_DST_HTYPE_TCP | CQE_RSS_DST_HTYPE_IPV4):
322278ce1c9SHans Petter Selasky 			M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_TCP_IPV4);
323278ce1c9SHans Petter Selasky 			break;
324278ce1c9SHans Petter Selasky 		case (CQE_RSS_DST_HTYPE_UDP | CQE_RSS_DST_HTYPE_IPV4):
325278ce1c9SHans Petter Selasky 			M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_UDP_IPV4);
326278ce1c9SHans Petter Selasky 			break;
327278ce1c9SHans Petter Selasky 		case CQE_RSS_DST_HTYPE_IPV4:
328278ce1c9SHans Petter Selasky 			M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_IPV4);
329278ce1c9SHans Petter Selasky 			break;
330278ce1c9SHans Petter Selasky 		/* IPv6 */
331278ce1c9SHans Petter Selasky 		case (CQE_RSS_DST_HTYPE_TCP | CQE_RSS_DST_HTYPE_IPV6):
332278ce1c9SHans Petter Selasky 			M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_TCP_IPV6);
333278ce1c9SHans Petter Selasky 			break;
334278ce1c9SHans Petter Selasky 		case (CQE_RSS_DST_HTYPE_UDP | CQE_RSS_DST_HTYPE_IPV6):
335278ce1c9SHans Petter Selasky 			M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_UDP_IPV6);
336278ce1c9SHans Petter Selasky 			break;
337278ce1c9SHans Petter Selasky 		case CQE_RSS_DST_HTYPE_IPV6:
338278ce1c9SHans Petter Selasky 			M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_IPV6);
339278ce1c9SHans Petter Selasky 			break;
340278ce1c9SHans Petter Selasky 		default:	/* Other */
34136ad8372SSepherosa Ziehau 			M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE_HASH);
342278ce1c9SHans Petter Selasky 			break;
343278ce1c9SHans Petter Selasky 		}
344278ce1c9SHans Petter Selasky #else
34536ad8372SSepherosa Ziehau 		M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE_HASH);
346278ce1c9SHans Petter Selasky #endif
347149349e0SKonstantin Belousov #ifdef M_HASHTYPE_SETINNER
348149349e0SKonstantin Belousov 		if (cqe_is_tunneled(cqe))
349149349e0SKonstantin Belousov 			M_HASHTYPE_SETINNER(mb);
350149349e0SKonstantin Belousov #endif
351278ce1c9SHans Petter Selasky 	} else {
352278ce1c9SHans Petter Selasky 		mb->m_pkthdr.flowid = rq->ix;
353278ce1c9SHans Petter Selasky 		M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE);
354278ce1c9SHans Petter Selasky 	}
355dc7e38acSHans Petter Selasky 	mb->m_pkthdr.rcvif = ifp;
356cb276279SHans Petter Selasky 	mb->m_pkthdr.leaf_rcvif = ifp;
357dc7e38acSHans Petter Selasky 
358149349e0SKonstantin Belousov 	if (cqe_is_tunneled(cqe)) {
359149349e0SKonstantin Belousov 		/*
360149349e0SKonstantin Belousov 		 * CQE can be tunneled only if TIR is configured to
361149349e0SKonstantin Belousov 		 * enable parsing of tunneled payload, so no need to
362149349e0SKonstantin Belousov 		 * check for capabilities.
363149349e0SKonstantin Belousov 		 */
364149349e0SKonstantin Belousov 		if (((cqe->hds_ip_ext & (CQE_L2_OK | CQE_L3_OK)) ==
365149349e0SKonstantin Belousov 		    (CQE_L2_OK | CQE_L3_OK))) {
366149349e0SKonstantin Belousov 			mb->m_pkthdr.csum_flags |=
367149349e0SKonstantin Belousov 			    CSUM_INNER_L3_CALC | CSUM_INNER_L3_VALID |
368149349e0SKonstantin Belousov 			    CSUM_IP_CHECKED | CSUM_IP_VALID |
369149349e0SKonstantin Belousov 			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
370149349e0SKonstantin Belousov 			mb->m_pkthdr.csum_data = htons(0xffff);
371aabca103SHans Petter Selasky 
372aabca103SHans Petter Selasky 			if (likely((cqe->hds_ip_ext & CQE_L4_OK) == CQE_L4_OK)) {
373149349e0SKonstantin Belousov 				mb->m_pkthdr.csum_flags |=
374149349e0SKonstantin Belousov 				    CSUM_INNER_L4_CALC | CSUM_INNER_L4_VALID;
375149349e0SKonstantin Belousov 			}
376aabca103SHans Petter Selasky 		} else {
377aabca103SHans Petter Selasky 			rq->stats.csum_none++;
378aabca103SHans Petter Selasky 		}
3795dc00f00SJustin Hibbits 	} else if (likely((if_getcapenable(ifp) & (IFCAP_RXCSUM |
380149349e0SKonstantin Belousov 	    IFCAP_RXCSUM_IPV6)) != 0) &&
381dc7e38acSHans Petter Selasky 	    ((cqe->hds_ip_ext & (CQE_L2_OK | CQE_L3_OK | CQE_L4_OK)) ==
382dc7e38acSHans Petter Selasky 	    (CQE_L2_OK | CQE_L3_OK | CQE_L4_OK))) {
383dc7e38acSHans Petter Selasky 		mb->m_pkthdr.csum_flags =
384dc7e38acSHans Petter Selasky 		    CSUM_IP_CHECKED | CSUM_IP_VALID |
385dc7e38acSHans Petter Selasky 		    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
386dc7e38acSHans Petter Selasky 		mb->m_pkthdr.csum_data = htons(0xffff);
387dc7e38acSHans Petter Selasky 	} else {
388dc7e38acSHans Petter Selasky 		rq->stats.csum_none++;
389dc7e38acSHans Petter Selasky 	}
390dc7e38acSHans Petter Selasky 
391dc7e38acSHans Petter Selasky 	if (cqe_has_vlan(cqe)) {
392dc7e38acSHans Petter Selasky 		mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->vlan_info);
393dc7e38acSHans Petter Selasky 		mb->m_flags |= M_VLANTAG;
394dc7e38acSHans Petter Selasky 	}
395ef23f141SKonstantin Belousov 
396ef23f141SKonstantin Belousov 	c = container_of(rq, struct mlx5e_channel, rq);
397ef23f141SKonstantin Belousov 	if (c->priv->clbr_done >= 2) {
398ef23f141SKonstantin Belousov 		tstmp = mlx5e_mbuf_tstmp(c->priv, be64_to_cpu(cqe->timestamp));
399ef23f141SKonstantin Belousov 		if ((tstmp & MLX5_CQE_TSTMP_PTP) != 0) {
400ef23f141SKonstantin Belousov 			/*
401ef23f141SKonstantin Belousov 			 * Timestamp was taken on the packet entrance,
402ef23f141SKonstantin Belousov 			 * instead of the cqe generation.
403ef23f141SKonstantin Belousov 			 */
404ef23f141SKonstantin Belousov 			tstmp &= ~MLX5_CQE_TSTMP_PTP;
405ef23f141SKonstantin Belousov 			mb->m_flags |= M_TSTMP_HPREC;
406ef23f141SKonstantin Belousov 		}
4077cc3ea9cSRandall Stewart 		if (tstmp != 0) {
408ef23f141SKonstantin Belousov 			mb->m_pkthdr.rcv_tstmp = tstmp;
409ef23f141SKonstantin Belousov 			mb->m_flags |= M_TSTMP;
410ef23f141SKonstantin Belousov 		}
4117cc3ea9cSRandall Stewart 	}
41284d7b8e7SHans Petter Selasky 	switch (get_cqe_tls_offload(cqe)) {
41384d7b8e7SHans Petter Selasky 	case CQE_TLS_OFFLOAD_DECRYPTED:
41484d7b8e7SHans Petter Selasky 		/* set proper checksum flag for decrypted packets */
41584d7b8e7SHans Petter Selasky 		mb->m_pkthdr.csum_flags |= CSUM_TLS_DECRYPTED;
41684d7b8e7SHans Petter Selasky 		rq->stats.decrypted_ok_packets++;
41784d7b8e7SHans Petter Selasky 		break;
41884d7b8e7SHans Petter Selasky 	case CQE_TLS_OFFLOAD_ERROR:
41984d7b8e7SHans Petter Selasky 		rq->stats.decrypted_error_packets++;
42084d7b8e7SHans Petter Selasky 		break;
42184d7b8e7SHans Petter Selasky 	default:
42284d7b8e7SHans Petter Selasky 		break;
42384d7b8e7SHans Petter Selasky 	}
424e23731dbSKonstantin Belousov 
425d00f3505SKonstantin Belousov 	mlx5e_accel_ipsec_handle_rx(mb, cqe, mr);
426dc7e38acSHans Petter Selasky }
427dc7e38acSHans Petter Selasky 
42890cc1c77SHans Petter Selasky static inline void
42990cc1c77SHans Petter Selasky mlx5e_read_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
43090cc1c77SHans Petter Selasky {
43190cc1c77SHans Petter Selasky 	memcpy(data, mlx5_cqwq_get_wqe(&cq->wq, (cc & cq->wq.sz_m1)),
43290cc1c77SHans Petter Selasky 	    sizeof(struct mlx5_cqe64));
43390cc1c77SHans Petter Selasky }
43490cc1c77SHans Petter Selasky 
43590cc1c77SHans Petter Selasky static inline void
43690cc1c77SHans Petter Selasky mlx5e_write_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
43790cc1c77SHans Petter Selasky {
43890cc1c77SHans Petter Selasky 	memcpy(mlx5_cqwq_get_wqe(&cq->wq, cc & cq->wq.sz_m1),
43990cc1c77SHans Petter Selasky 	    data, sizeof(struct mlx5_cqe64));
44090cc1c77SHans Petter Selasky }
44190cc1c77SHans Petter Selasky 
44290cc1c77SHans Petter Selasky static inline void
44390cc1c77SHans Petter Selasky mlx5e_decompress_cqe(struct mlx5e_cq *cq, struct mlx5_cqe64 *title,
44490cc1c77SHans Petter Selasky     struct mlx5_mini_cqe8 *mini,
44590cc1c77SHans Petter Selasky     u16 wqe_counter, int i)
44690cc1c77SHans Petter Selasky {
447636d1fecSHans Petter Selasky 	/*
448636d1fecSHans Petter Selasky 	 * NOTE: The fields which are not set here are copied from the
449636d1fecSHans Petter Selasky 	 * initial and common title. See memcpy() in
450636d1fecSHans Petter Selasky 	 * mlx5e_write_cqe_slot().
451636d1fecSHans Petter Selasky 	 */
45290cc1c77SHans Petter Selasky 	title->byte_cnt = mini->byte_cnt;
45390cc1c77SHans Petter Selasky 	title->wqe_counter = cpu_to_be16((wqe_counter + i) & cq->wq.sz_m1);
454a005c157SHans Petter Selasky 	title->rss_hash_result = mini->rx_hash_result;
455a005c157SHans Petter Selasky 	/*
456a005c157SHans Petter Selasky 	 * Since we use MLX5_CQE_FORMAT_HASH when creating the RX CQ,
457a005c157SHans Petter Selasky 	 * the value of the checksum should be ignored.
458a005c157SHans Petter Selasky 	 */
459a005c157SHans Petter Selasky 	title->check_sum = 0;
46090cc1c77SHans Petter Selasky 	title->op_own = (title->op_own & 0xf0) |
46190cc1c77SHans Petter Selasky 	    (((cq->wq.cc + i) >> cq->wq.log_sz) & 1);
46290cc1c77SHans Petter Selasky }
46390cc1c77SHans Petter Selasky 
46490cc1c77SHans Petter Selasky #define MLX5E_MINI_ARRAY_SZ 8
46590cc1c77SHans Petter Selasky /* Make sure structs are not packet differently */
46690cc1c77SHans Petter Selasky CTASSERT(sizeof(struct mlx5_cqe64) ==
46790cc1c77SHans Petter Selasky     sizeof(struct mlx5_mini_cqe8) * MLX5E_MINI_ARRAY_SZ);
46890cc1c77SHans Petter Selasky static void
46990cc1c77SHans Petter Selasky mlx5e_decompress_cqes(struct mlx5e_cq *cq)
47090cc1c77SHans Petter Selasky {
47190cc1c77SHans Petter Selasky 	struct mlx5_mini_cqe8 mini_array[MLX5E_MINI_ARRAY_SZ];
47290cc1c77SHans Petter Selasky 	struct mlx5_cqe64 title;
47390cc1c77SHans Petter Selasky 	u32 cqe_count;
47490cc1c77SHans Petter Selasky 	u32 i = 0;
47590cc1c77SHans Petter Selasky 	u16 title_wqe_counter;
47690cc1c77SHans Petter Selasky 
47790cc1c77SHans Petter Selasky 	mlx5e_read_cqe_slot(cq, cq->wq.cc, &title);
47890cc1c77SHans Petter Selasky 	title_wqe_counter = be16_to_cpu(title.wqe_counter);
47990cc1c77SHans Petter Selasky 	cqe_count = be32_to_cpu(title.byte_cnt);
48090cc1c77SHans Petter Selasky 
48190cc1c77SHans Petter Selasky 	/* Make sure we won't overflow */
48290cc1c77SHans Petter Selasky 	KASSERT(cqe_count <= cq->wq.sz_m1,
48390cc1c77SHans Petter Selasky 	    ("%s: cqe_count %u > cq->wq.sz_m1 %u", __func__,
48490cc1c77SHans Petter Selasky 	    cqe_count, cq->wq.sz_m1));
48590cc1c77SHans Petter Selasky 
48690cc1c77SHans Petter Selasky 	mlx5e_read_cqe_slot(cq, cq->wq.cc + 1, mini_array);
48790cc1c77SHans Petter Selasky 	while (true) {
48890cc1c77SHans Petter Selasky 		mlx5e_decompress_cqe(cq, &title,
48990cc1c77SHans Petter Selasky 		    &mini_array[i % MLX5E_MINI_ARRAY_SZ],
49090cc1c77SHans Petter Selasky 		    title_wqe_counter, i);
49190cc1c77SHans Petter Selasky 		mlx5e_write_cqe_slot(cq, cq->wq.cc + i, &title);
49290cc1c77SHans Petter Selasky 		i++;
49390cc1c77SHans Petter Selasky 
49490cc1c77SHans Petter Selasky 		if (i == cqe_count)
49590cc1c77SHans Petter Selasky 			break;
49690cc1c77SHans Petter Selasky 		if (i % MLX5E_MINI_ARRAY_SZ == 0)
49790cc1c77SHans Petter Selasky 			mlx5e_read_cqe_slot(cq, cq->wq.cc + i, mini_array);
49890cc1c77SHans Petter Selasky 	}
49990cc1c77SHans Petter Selasky }
50090cc1c77SHans Petter Selasky 
501dc7e38acSHans Petter Selasky static int
502dc7e38acSHans Petter Selasky mlx5e_poll_rx_cq(struct mlx5e_rq *rq, int budget)
503dc7e38acSHans Petter Selasky {
504538ff57bSAndrew Gallatin 	struct pfil_head *pfil;
505538ff57bSAndrew Gallatin 	int i, rv;
506dc7e38acSHans Petter Selasky 
5075dc00f00SJustin Hibbits 	CURVNET_SET_QUIET(if_getvnet(rq->ifp));
508538ff57bSAndrew Gallatin 	pfil = rq->channel->priv->pfil;
509dc7e38acSHans Petter Selasky 	for (i = 0; i < budget; i++) {
510dc7e38acSHans Petter Selasky 		struct mlx5e_rx_wqe *wqe;
511dc7e38acSHans Petter Selasky 		struct mlx5_cqe64 *cqe;
512dc7e38acSHans Petter Selasky 		struct mbuf *mb;
513dc7e38acSHans Petter Selasky 		__be16 wqe_counter_be;
514dc7e38acSHans Petter Selasky 		u16 wqe_counter;
515538ff57bSAndrew Gallatin 		u32 byte_cnt, seglen;
516dc7e38acSHans Petter Selasky 
517dc7e38acSHans Petter Selasky 		cqe = mlx5e_get_cqe(&rq->cq);
518dc7e38acSHans Petter Selasky 		if (!cqe)
519dc7e38acSHans Petter Selasky 			break;
520dc7e38acSHans Petter Selasky 
52190cc1c77SHans Petter Selasky 		if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED)
52290cc1c77SHans Petter Selasky 			mlx5e_decompress_cqes(&rq->cq);
52390cc1c77SHans Petter Selasky 
52490cc1c77SHans Petter Selasky 		mlx5_cqwq_pop(&rq->cq.wq);
52590cc1c77SHans Petter Selasky 
526dc7e38acSHans Petter Selasky 		wqe_counter_be = cqe->wqe_counter;
527dc7e38acSHans Petter Selasky 		wqe_counter = be16_to_cpu(wqe_counter_be);
528dc7e38acSHans Petter Selasky 		wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
529dc7e38acSHans Petter Selasky 		byte_cnt = be32_to_cpu(cqe->byte_cnt);
530dc7e38acSHans Petter Selasky 
531dc7e38acSHans Petter Selasky 		bus_dmamap_sync(rq->dma_tag,
532dc7e38acSHans Petter Selasky 		    rq->mbuf[wqe_counter].dma_map,
533dc7e38acSHans Petter Selasky 		    BUS_DMASYNC_POSTREAD);
534dc7e38acSHans Petter Selasky 
535dc7e38acSHans Petter Selasky 		if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) {
536bc531a1fSHans Petter Selasky 			mlx5e_dump_err_cqe(&rq->cq, rq->rqn, (const void *)cqe);
537dc7e38acSHans Petter Selasky 			rq->stats.wqe_err++;
538dc7e38acSHans Petter Selasky 			goto wq_ll_pop;
539dc7e38acSHans Petter Selasky 		}
540538ff57bSAndrew Gallatin 		if (pfil != NULL && PFIL_HOOKED_IN(pfil)) {
541538ff57bSAndrew Gallatin 			seglen = MIN(byte_cnt, MLX5E_MAX_RX_BYTES);
542caf32b26SGleb Smirnoff 			rv = pfil_mem_in(rq->channel->priv->pfil,
543caf32b26SGleb Smirnoff 			    rq->mbuf[wqe_counter].data, seglen, rq->ifp, &mb);
544538ff57bSAndrew Gallatin 
545538ff57bSAndrew Gallatin 			switch (rv) {
546538ff57bSAndrew Gallatin 			case PFIL_DROPPED:
547538ff57bSAndrew Gallatin 			case PFIL_CONSUMED:
548538ff57bSAndrew Gallatin 				/*
549538ff57bSAndrew Gallatin 				 * Filter dropped or consumed it. In
550538ff57bSAndrew Gallatin 				 * either case, we can just recycle
551538ff57bSAndrew Gallatin 				 * buffer; there is no more work to do.
552538ff57bSAndrew Gallatin 				 */
553538ff57bSAndrew Gallatin 				rq->stats.packets++;
554538ff57bSAndrew Gallatin 				goto wq_ll_pop;
555538ff57bSAndrew Gallatin 			case PFIL_REALLOCED:
556538ff57bSAndrew Gallatin 				/*
557538ff57bSAndrew Gallatin 				 * Filter copied it; recycle buffer
558538ff57bSAndrew Gallatin 				 * and receive the new mbuf allocated
559538ff57bSAndrew Gallatin 				 * by the Filter
560538ff57bSAndrew Gallatin 				 */
561538ff57bSAndrew Gallatin 				goto rx_common;
562538ff57bSAndrew Gallatin 			default:
563538ff57bSAndrew Gallatin 				/*
564538ff57bSAndrew Gallatin 				 * The Filter said it was OK, so
565538ff57bSAndrew Gallatin 				 * receive like normal.
566538ff57bSAndrew Gallatin 				 */
567538ff57bSAndrew Gallatin 				KASSERT(rv == PFIL_PASS,
568538ff57bSAndrew Gallatin 					("Filter returned %d!\n", rv));
569538ff57bSAndrew Gallatin 			}
570538ff57bSAndrew Gallatin 		}
571e23731dbSKonstantin Belousov 		if (!mlx5e_accel_ipsec_flow(cqe) /* tag is already assigned
572e23731dbSKonstantin Belousov 						    to rq->mbuf */ &&
573e23731dbSKonstantin Belousov 		    MHLEN - MLX5E_NET_IP_ALIGN >= byte_cnt &&
574dc7e38acSHans Petter Selasky 		    (mb = m_gethdr(M_NOWAIT, MT_DATA)) != NULL) {
5752f17f76aSHans Petter Selasky 			/* set maximum mbuf length */
5762f17f76aSHans Petter Selasky 			mb->m_len = MHLEN - MLX5E_NET_IP_ALIGN;
5778508e4d7SHans Petter Selasky 			/* get IP header aligned */
5788508e4d7SHans Petter Selasky 			mb->m_data += MLX5E_NET_IP_ALIGN;
5798508e4d7SHans Petter Selasky 
580dc7e38acSHans Petter Selasky 			bcopy(rq->mbuf[wqe_counter].data, mtod(mb, caddr_t),
581dc7e38acSHans Petter Selasky 			    byte_cnt);
582dc7e38acSHans Petter Selasky 		} else {
583dc7e38acSHans Petter Selasky 			mb = rq->mbuf[wqe_counter].mbuf;
584dc7e38acSHans Petter Selasky 			rq->mbuf[wqe_counter].mbuf = NULL;	/* safety clear */
585dc7e38acSHans Petter Selasky 
586dc7e38acSHans Petter Selasky 			bus_dmamap_unload(rq->dma_tag,
587dc7e38acSHans Petter Selasky 			    rq->mbuf[wqe_counter].dma_map);
588dc7e38acSHans Petter Selasky 		}
589538ff57bSAndrew Gallatin rx_common:
590d00f3505SKonstantin Belousov 		mlx5e_build_rx_mbuf(cqe, rq, mb, &rq->mbuf[wqe_counter],
591d00f3505SKonstantin Belousov 		    byte_cnt);
59201f02abfSSlava Shwartsman 		rq->stats.bytes += byte_cnt;
593dc7e38acSHans Petter Selasky 		rq->stats.packets++;
59450575ce1SAndrew Gallatin #ifdef NUMA
5955dc00f00SJustin Hibbits 		mb->m_pkthdr.numa_domain = if_getnumadomain(rq->ifp);
59650575ce1SAndrew Gallatin #endif
59757d5dd79SHans Petter Selasky 
59857d5dd79SHans Petter Selasky #if !defined(HAVE_TCP_LRO_RX)
59957d5dd79SHans Petter Selasky 		tcp_lro_queue_mbuf(&rq->lro, mb);
600dc7e38acSHans Petter Selasky #else
601dc7e38acSHans Petter Selasky 		if (mb->m_pkthdr.csum_flags == 0 ||
6025dc00f00SJustin Hibbits 		    (if_getcapenable(rq->ifp) & IFCAP_LRO) == 0 ||
603dc7e38acSHans Petter Selasky 		    rq->lro.lro_cnt == 0 ||
604dc7e38acSHans Petter Selasky 		    tcp_lro_rx(&rq->lro, mb, 0) != 0) {
6055dc00f00SJustin Hibbits 			if_input(rq->ifp, mb);
606dc7e38acSHans Petter Selasky 		}
607dc7e38acSHans Petter Selasky #endif
608dc7e38acSHans Petter Selasky wq_ll_pop:
609dc7e38acSHans Petter Selasky 		mlx5_wq_ll_pop(&rq->wq, wqe_counter_be,
610dc7e38acSHans Petter Selasky 		    &wqe->next.next_wqe_index);
611dc7e38acSHans Petter Selasky 	}
612538ff57bSAndrew Gallatin 	CURVNET_RESTORE();
613dc7e38acSHans Petter Selasky 
614dc7e38acSHans Petter Selasky 	mlx5_cqwq_update_db_record(&rq->cq.wq);
615dc7e38acSHans Petter Selasky 
616dc7e38acSHans Petter Selasky 	/* ensure cq space is freed before enabling more cqes */
617e44f4f35SKonstantin Belousov 	atomic_thread_fence_rel();
618dc7e38acSHans Petter Selasky 	return (i);
619dc7e38acSHans Petter Selasky }
620dc7e38acSHans Petter Selasky 
621dc7e38acSHans Petter Selasky void
622f34f0a65SHans Petter Selasky mlx5e_rx_cq_comp(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe __unused)
623dc7e38acSHans Petter Selasky {
6242d5e5a0dSHans Petter Selasky 	struct mlx5e_channel *c = container_of(mcq, struct mlx5e_channel, rq.cq.mcq);
625dc7e38acSHans Petter Selasky 	struct mlx5e_rq *rq = container_of(mcq, struct mlx5e_rq, cq.mcq);
626dc7e38acSHans Petter Selasky 	int i = 0;
627dc7e38acSHans Petter Selasky 
628dc7e38acSHans Petter Selasky #ifdef HAVE_PER_CQ_EVENT_PACKET
62990c8e441SHans Petter Selasky #if (MHLEN < 15)
63090c8e441SHans Petter Selasky #error "MHLEN is too small"
63190c8e441SHans Petter Selasky #endif
63290c8e441SHans Petter Selasky 	struct mbuf *mb = m_gethdr(M_NOWAIT, MT_DATA);
633bb3853c6SHans Petter Selasky 
634dc7e38acSHans Petter Selasky 	if (mb != NULL) {
635dc7e38acSHans Petter Selasky 		/* this code is used for debugging purpose only */
636dc7e38acSHans Petter Selasky 		mb->m_pkthdr.len = mb->m_len = 15;
637dc7e38acSHans Petter Selasky 		memset(mb->m_data, 255, 14);
638dc7e38acSHans Petter Selasky 		mb->m_data[14] = rq->ix;
639dc7e38acSHans Petter Selasky 		mb->m_pkthdr.rcvif = rq->ifp;
640cb276279SHans Petter Selasky 		mb->m_pkthdr.leaf_rcvif = rq->ifp;
6415dc00f00SJustin Hibbits 		if_input(rq->ifp, mb);
642dc7e38acSHans Petter Selasky 	}
643dc7e38acSHans Petter Selasky #endif
6442d5e5a0dSHans Petter Selasky 	for (int j = 0; j != MLX5E_MAX_TX_NUM_TC; j++) {
6452d5e5a0dSHans Petter Selasky 		mtx_lock(&c->sq[j].lock);
6462d5e5a0dSHans Petter Selasky 		c->sq[j].db_inhibit++;
6472d5e5a0dSHans Petter Selasky 		mtx_unlock(&c->sq[j].lock);
6482d5e5a0dSHans Petter Selasky 	}
649dc7e38acSHans Petter Selasky 
65069426357SHans Petter Selasky 	mtx_lock(&c->iq.lock);
65169426357SHans Petter Selasky 	c->iq.db_inhibit++;
65269426357SHans Petter Selasky 	mtx_unlock(&c->iq.lock);
65369426357SHans Petter Selasky 
654dc7e38acSHans Petter Selasky 	mtx_lock(&rq->mtx);
655dc7e38acSHans Petter Selasky 
656dc7e38acSHans Petter Selasky 	/*
657dc7e38acSHans Petter Selasky 	 * Polling the entire CQ without posting new WQEs results in
658dc7e38acSHans Petter Selasky 	 * lack of receive WQEs during heavy traffic scenarios.
659dc7e38acSHans Petter Selasky 	 */
660dc7e38acSHans Petter Selasky 	while (1) {
661dc7e38acSHans Petter Selasky 		if (mlx5e_poll_rx_cq(rq, MLX5E_RX_BUDGET_MAX) !=
662dc7e38acSHans Petter Selasky 		    MLX5E_RX_BUDGET_MAX)
663dc7e38acSHans Petter Selasky 			break;
664dc7e38acSHans Petter Selasky 		i += MLX5E_RX_BUDGET_MAX;
665dc7e38acSHans Petter Selasky 		if (i >= MLX5E_BUDGET_MAX)
666dc7e38acSHans Petter Selasky 			break;
667dc7e38acSHans Petter Selasky 		mlx5e_post_rx_wqes(rq);
668dc7e38acSHans Petter Selasky 	}
669dc7e38acSHans Petter Selasky 	mlx5e_post_rx_wqes(rq);
670423530beSHans Petter Selasky 	/* check for dynamic interrupt moderation callback */
671423530beSHans Petter Selasky 	if (rq->dim.mode != NET_DIM_CQ_PERIOD_MODE_DISABLED)
672423530beSHans Petter Selasky 		net_dim(&rq->dim, rq->stats.packets, rq->stats.bytes);
673e5d6b589SHans Petter Selasky 	mlx5e_cq_arm(&rq->cq, MLX5_GET_DOORBELL_LOCK(&rq->channel->priv->doorbell_lock));
67457d5dd79SHans Petter Selasky 	tcp_lro_flush_all(&rq->lro);
675dc7e38acSHans Petter Selasky 	mtx_unlock(&rq->mtx);
6762d5e5a0dSHans Petter Selasky 
6772d5e5a0dSHans Petter Selasky 	for (int j = 0; j != MLX5E_MAX_TX_NUM_TC; j++) {
6782d5e5a0dSHans Petter Selasky 		mtx_lock(&c->sq[j].lock);
6792d5e5a0dSHans Petter Selasky 		c->sq[j].db_inhibit--;
6802d5e5a0dSHans Petter Selasky 		/* Update the doorbell record, if any. */
6812d5e5a0dSHans Petter Selasky 		mlx5e_tx_notify_hw(c->sq + j, true);
6822d5e5a0dSHans Petter Selasky 		mtx_unlock(&c->sq[j].lock);
6832d5e5a0dSHans Petter Selasky 	}
68469426357SHans Petter Selasky 
68569426357SHans Petter Selasky 	mtx_lock(&c->iq.lock);
68669426357SHans Petter Selasky 	c->iq.db_inhibit--;
68769426357SHans Petter Selasky 	mlx5e_iq_notify_hw(&c->iq);
68869426357SHans Petter Selasky 	mtx_unlock(&c->iq.lock);
689dc7e38acSHans Petter Selasky }
690