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>
303eb6d4b4SKonstantin Belousov #include <netinet/ip_var.h>
31dc7e38acSHans Petter Selasky #include <machine/in_cksum.h>
32e23731dbSKonstantin Belousov #include <dev/mlx5/mlx5_accel/ipsec.h>
33dc7e38acSHans Petter Selasky
34dc7e38acSHans Petter Selasky static inline int
mlx5e_alloc_rx_wqe(struct mlx5e_rq * rq,struct mlx5e_rx_wqe * wqe,u16 ix)35dc7e38acSHans Petter Selasky mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq,
36dc7e38acSHans Petter Selasky struct mlx5e_rx_wqe *wqe, u16 ix)
37dc7e38acSHans Petter Selasky {
388b825a18SHans Petter Selasky bus_dma_segment_t segs[MLX5E_MAX_BUSDMA_RX_SEGS];
39dc7e38acSHans Petter Selasky struct mbuf *mb;
40dc7e38acSHans Petter Selasky int nsegs;
41dc7e38acSHans Petter Selasky int err;
422f17f76aSHans Petter Selasky struct mbuf *mb_head;
432f17f76aSHans Petter Selasky int i;
444d0e6d84SHans Petter Selasky
45dc7e38acSHans Petter Selasky if (rq->mbuf[ix].mbuf != NULL)
46dc7e38acSHans Petter Selasky return (0);
47dc7e38acSHans Petter Selasky
48016f4046SKonstantin Belousov mb_head = mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, rq->wqe_sz);
492f17f76aSHans Petter Selasky if (unlikely(mb == NULL))
502f17f76aSHans Petter Selasky return (-ENOMEM);
51dc7e38acSHans Petter Selasky
52016f4046SKonstantin Belousov mb->m_len = rq->wqe_sz;
53016f4046SKonstantin Belousov mb->m_pkthdr.len = rq->wqe_sz;
542f17f76aSHans Petter Selasky
552f17f76aSHans Petter Selasky for (i = 1; i < rq->nsegs; i++) {
56016f4046SKonstantin Belousov mb = mb->m_next = m_getjcl(M_NOWAIT, MT_DATA, 0, rq->wqe_sz);
572f17f76aSHans Petter Selasky if (unlikely(mb == NULL)) {
582f17f76aSHans Petter Selasky m_freem(mb_head);
592f17f76aSHans Petter Selasky return (-ENOMEM);
602f17f76aSHans Petter Selasky }
61016f4046SKonstantin Belousov mb->m_len = rq->wqe_sz;
62016f4046SKonstantin Belousov mb_head->m_pkthdr.len += rq->wqe_sz;
632f17f76aSHans Petter Selasky }
642f17f76aSHans Petter Selasky /* rewind to first mbuf in chain */
652f17f76aSHans Petter Selasky mb = mb_head;
664d0e6d84SHans Petter Selasky
67dc7e38acSHans Petter Selasky /* get IP header aligned */
68dc7e38acSHans Petter Selasky m_adj(mb, MLX5E_NET_IP_ALIGN);
69dc7e38acSHans Petter Selasky
70d00f3505SKonstantin Belousov err = mlx5_accel_ipsec_rx_tag_add(rq->ifp, &rq->mbuf[ix]);
71e23731dbSKonstantin Belousov if (err)
72e23731dbSKonstantin Belousov goto err_free_mbuf;
73dc7e38acSHans Petter Selasky err = -bus_dmamap_load_mbuf_sg(rq->dma_tag, rq->mbuf[ix].dma_map,
74dc7e38acSHans Petter Selasky mb, segs, &nsegs, BUS_DMA_NOWAIT);
75dc7e38acSHans Petter Selasky if (err != 0)
76dc7e38acSHans Petter Selasky goto err_free_mbuf;
772f17f76aSHans Petter Selasky if (unlikely(nsegs == 0)) {
78dc7e38acSHans Petter Selasky bus_dmamap_unload(rq->dma_tag, rq->mbuf[ix].dma_map);
79dc7e38acSHans Petter Selasky err = -ENOMEM;
80dc7e38acSHans Petter Selasky goto err_free_mbuf;
81dc7e38acSHans Petter Selasky }
822f17f76aSHans Petter Selasky wqe->data[0].addr = cpu_to_be64(segs[0].ds_addr);
832f17f76aSHans Petter Selasky wqe->data[0].byte_count = cpu_to_be32(segs[0].ds_len |
842f17f76aSHans Petter Selasky MLX5_HW_START_PADDING);
852f17f76aSHans Petter Selasky for (i = 1; i != nsegs; i++) {
862f17f76aSHans Petter Selasky wqe->data[i].addr = cpu_to_be64(segs[i].ds_addr);
872f17f76aSHans Petter Selasky wqe->data[i].byte_count = cpu_to_be32(segs[i].ds_len);
882f17f76aSHans Petter Selasky }
892f17f76aSHans Petter Selasky for (; i < rq->nsegs; i++) {
902f17f76aSHans Petter Selasky wqe->data[i].addr = 0;
912f17f76aSHans Petter Selasky wqe->data[i].byte_count = 0;
922f17f76aSHans Petter Selasky }
93dc7e38acSHans Petter Selasky
94dc7e38acSHans Petter Selasky rq->mbuf[ix].mbuf = mb;
95dc7e38acSHans Petter Selasky rq->mbuf[ix].data = mb->m_data;
96dc7e38acSHans Petter Selasky
97dc7e38acSHans Petter Selasky bus_dmamap_sync(rq->dma_tag, rq->mbuf[ix].dma_map,
98dc7e38acSHans Petter Selasky BUS_DMASYNC_PREREAD);
99dc7e38acSHans Petter Selasky return (0);
100dc7e38acSHans Petter Selasky
101dc7e38acSHans Petter Selasky err_free_mbuf:
102dc7e38acSHans Petter Selasky m_freem(mb);
103dc7e38acSHans Petter Selasky return (err);
104dc7e38acSHans Petter Selasky }
105dc7e38acSHans Petter Selasky
106dc7e38acSHans Petter Selasky static void
mlx5e_post_rx_wqes(struct mlx5e_rq * rq)107dc7e38acSHans Petter Selasky mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
108dc7e38acSHans Petter Selasky {
109dc7e38acSHans Petter Selasky if (unlikely(rq->enabled == 0))
110dc7e38acSHans Petter Selasky return;
111dc7e38acSHans Petter Selasky
112dc7e38acSHans Petter Selasky while (!mlx5_wq_ll_is_full(&rq->wq)) {
113dc7e38acSHans Petter Selasky struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(&rq->wq, rq->wq.head);
114dc7e38acSHans Petter Selasky
1156f4cab6cSHans Petter Selasky if (unlikely(mlx5e_alloc_rx_wqe(rq, wqe, rq->wq.head))) {
1166f4cab6cSHans Petter Selasky callout_reset_curcpu(&rq->watchdog, 1, (void *)&mlx5e_post_rx_wqes, rq);
117dc7e38acSHans Petter Selasky break;
1186f4cab6cSHans Petter Selasky }
119dc7e38acSHans Petter Selasky mlx5_wq_ll_push(&rq->wq, be16_to_cpu(wqe->next.next_wqe_index));
120dc7e38acSHans Petter Selasky }
121dc7e38acSHans Petter Selasky
122dc7e38acSHans Petter Selasky /* ensure wqes are visible to device before updating doorbell record */
123e44f4f35SKonstantin Belousov atomic_thread_fence_rel();
124dc7e38acSHans Petter Selasky
125dc7e38acSHans Petter Selasky mlx5_wq_ll_update_db_record(&rq->wq);
126dc7e38acSHans Petter Selasky }
127dc7e38acSHans Petter Selasky
1283eb6d4b4SKonstantin Belousov static uint32_t
csum_reduce(uint32_t val)1293eb6d4b4SKonstantin Belousov csum_reduce(uint32_t val)
1303eb6d4b4SKonstantin Belousov {
1313eb6d4b4SKonstantin Belousov while (val > 0xffff)
1323eb6d4b4SKonstantin Belousov val = (val >> 16) + (val & 0xffff);
1333eb6d4b4SKonstantin Belousov return (val);
1343eb6d4b4SKonstantin Belousov }
1353eb6d4b4SKonstantin Belousov
1363eb6d4b4SKonstantin Belousov static u_short
csum_buf(uint32_t val,void * buf,int len)1373eb6d4b4SKonstantin Belousov csum_buf(uint32_t val, void *buf, int len)
1383eb6d4b4SKonstantin Belousov {
1393eb6d4b4SKonstantin Belousov u_short x;
1403eb6d4b4SKonstantin Belousov
1413eb6d4b4SKonstantin Belousov MPASS(len % 2 == 0);
1423eb6d4b4SKonstantin Belousov for (int i = 0; i < len; i += 2) {
1433eb6d4b4SKonstantin Belousov bcopy((char *)buf + i, &x, 2);
1443eb6d4b4SKonstantin Belousov val = csum_reduce(val + x);
1453eb6d4b4SKonstantin Belousov }
1463eb6d4b4SKonstantin Belousov return (val);
1473eb6d4b4SKonstantin Belousov }
1483eb6d4b4SKonstantin Belousov
149dc7e38acSHans Petter Selasky static void
mlx5e_lro_update_hdr(struct mbuf * mb,struct mlx5_cqe64 * cqe)150dc7e38acSHans Petter Selasky mlx5e_lro_update_hdr(struct mbuf *mb, struct mlx5_cqe64 *cqe)
151dc7e38acSHans Petter Selasky {
152dc7e38acSHans Petter Selasky /* TODO: consider vlans, ip options, ... */
153dc7e38acSHans Petter Selasky struct ether_header *eh;
154dc7e38acSHans Petter Selasky uint16_t eh_type;
1551558d49bSHans Petter Selasky uint16_t tot_len;
156dc7e38acSHans Petter Selasky struct ip6_hdr *ip6 = NULL;
157dc7e38acSHans Petter Selasky struct ip *ip4 = NULL;
158dc7e38acSHans Petter Selasky struct tcphdr *th;
159dc7e38acSHans Petter Selasky uint32_t *ts_ptr;
1603eb6d4b4SKonstantin Belousov uint32_t tcp_csum;
1611558d49bSHans Petter Selasky uint8_t l4_hdr_type;
1621558d49bSHans Petter Selasky int tcp_ack;
163dc7e38acSHans Petter Selasky
164dc7e38acSHans Petter Selasky eh = mtod(mb, struct ether_header *);
165dc7e38acSHans Petter Selasky eh_type = ntohs(eh->ether_type);
166dc7e38acSHans Petter Selasky
1671558d49bSHans Petter Selasky l4_hdr_type = get_cqe_l4_hdr_type(cqe);
1681558d49bSHans Petter Selasky tcp_ack = ((CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA == l4_hdr_type) ||
169dc7e38acSHans Petter Selasky (CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA == l4_hdr_type));
170dc7e38acSHans Petter Selasky
171dc7e38acSHans Petter Selasky /* TODO: consider vlan */
1721558d49bSHans Petter Selasky tot_len = be32_to_cpu(cqe->byte_cnt) - ETHER_HDR_LEN;
173dc7e38acSHans Petter Selasky
174dc7e38acSHans Petter Selasky switch (eh_type) {
175dc7e38acSHans Petter Selasky case ETHERTYPE_IP:
176dc7e38acSHans Petter Selasky ip4 = (struct ip *)(eh + 1);
177dc7e38acSHans Petter Selasky th = (struct tcphdr *)(ip4 + 1);
178dc7e38acSHans Petter Selasky break;
179dc7e38acSHans Petter Selasky case ETHERTYPE_IPV6:
180dc7e38acSHans Petter Selasky ip6 = (struct ip6_hdr *)(eh + 1);
181dc7e38acSHans Petter Selasky th = (struct tcphdr *)(ip6 + 1);
182dc7e38acSHans Petter Selasky break;
183dc7e38acSHans Petter Selasky default:
184dc7e38acSHans Petter Selasky return;
185dc7e38acSHans Petter Selasky }
186dc7e38acSHans Petter Selasky
187dc7e38acSHans Petter Selasky ts_ptr = (uint32_t *)(th + 1);
188dc7e38acSHans Petter Selasky
189dc7e38acSHans Petter Selasky if (get_cqe_lro_tcppsh(cqe))
1900fc7bdc9SRichard Scheffenegger tcp_set_flags(th, tcp_get_flags(th) | TH_PUSH);
191dc7e38acSHans Petter Selasky
192dc7e38acSHans Petter Selasky if (tcp_ack) {
1930fc7bdc9SRichard Scheffenegger tcp_set_flags(th, tcp_get_flags(th) | TH_ACK);
194dc7e38acSHans Petter Selasky th->th_ack = cqe->lro_ack_seq_num;
195dc7e38acSHans Petter Selasky th->th_win = cqe->lro_tcp_win;
196dc7e38acSHans Petter Selasky
197bb3853c6SHans Petter Selasky /*
198bb3853c6SHans Petter Selasky * FreeBSD handles only 32bit aligned timestamp right after
199bb3853c6SHans Petter Selasky * the TCP hdr
200dc7e38acSHans Petter Selasky * +--------+--------+--------+--------+
201dc7e38acSHans Petter Selasky * | NOP | NOP | TSopt | 10 |
202dc7e38acSHans Petter Selasky * +--------+--------+--------+--------+
203dc7e38acSHans Petter Selasky * | TSval timestamp |
204dc7e38acSHans Petter Selasky * +--------+--------+--------+--------+
205dc7e38acSHans Petter Selasky * | TSecr timestamp |
206dc7e38acSHans Petter Selasky * +--------+--------+--------+--------+
207dc7e38acSHans Petter Selasky */
208dc7e38acSHans Petter Selasky if (get_cqe_lro_timestamp_valid(cqe) &&
20990399676SKonstantin Belousov (__predict_true(*ts_ptr == ntohl(TCPOPT_NOP << 24 |
210dc7e38acSHans Petter Selasky TCPOPT_NOP << 16 | TCPOPT_TIMESTAMP << 8 |
21190399676SKonstantin Belousov TCPOLEN_TIMESTAMP)))) {
212bb3853c6SHans Petter Selasky /*
213bb3853c6SHans Petter Selasky * cqe->timestamp is 64bit long.
214dc7e38acSHans Petter Selasky * [0-31] - timestamp.
215dc7e38acSHans Petter Selasky * [32-64] - timestamp echo replay.
216dc7e38acSHans Petter Selasky */
217dc7e38acSHans Petter Selasky ts_ptr[2] = *((uint32_t *)&cqe->timestamp + 1);
218dc7e38acSHans Petter Selasky }
219dc7e38acSHans Petter Selasky }
220dc7e38acSHans Petter Selasky if (ip4) {
2213eb6d4b4SKonstantin Belousov struct ipovly io;
2223eb6d4b4SKonstantin Belousov
223dc7e38acSHans Petter Selasky ip4->ip_ttl = cqe->lro_min_ttl;
224dc7e38acSHans Petter Selasky ip4->ip_len = cpu_to_be16(tot_len);
225dc7e38acSHans Petter Selasky ip4->ip_sum = 0;
226dd1bd0ecSKonstantin Belousov ip4->ip_sum = in_cksum_skip(mb, (ip4->ip_hl << 2) +
227dd1bd0ecSKonstantin Belousov ETHER_HDR_LEN, ETHER_HDR_LEN);
2283eb6d4b4SKonstantin Belousov
2293eb6d4b4SKonstantin Belousov /* TCP checksum: data */
2303eb6d4b4SKonstantin Belousov tcp_csum = cqe->check_sum;
2313eb6d4b4SKonstantin Belousov
2323eb6d4b4SKonstantin Belousov /* TCP checksum: IP pseudoheader */
2333eb6d4b4SKonstantin Belousov bzero(io.ih_x1, sizeof(io.ih_x1));
2343eb6d4b4SKonstantin Belousov io.ih_pr = IPPROTO_TCP;
2353eb6d4b4SKonstantin Belousov io.ih_len = htons(ntohs(ip4->ip_len) - sizeof(*ip4));
2363eb6d4b4SKonstantin Belousov io.ih_src = ip4->ip_src;
2373eb6d4b4SKonstantin Belousov io.ih_dst = ip4->ip_dst;
2383eb6d4b4SKonstantin Belousov tcp_csum = csum_buf(tcp_csum, &io, sizeof(io));
2393eb6d4b4SKonstantin Belousov
2403eb6d4b4SKonstantin Belousov /* TCP checksum: TCP header */
2413eb6d4b4SKonstantin Belousov th->th_sum = 0;
2423eb6d4b4SKonstantin Belousov tcp_csum = csum_buf(tcp_csum, th, th->th_off * 4);
2433eb6d4b4SKonstantin Belousov th->th_sum = ~tcp_csum & 0xffff;
244dc7e38acSHans Petter Selasky } else {
245dc7e38acSHans Petter Selasky ip6->ip6_hlim = cqe->lro_min_ttl;
246dc7e38acSHans Petter Selasky ip6->ip6_plen = cpu_to_be16(tot_len -
247dc7e38acSHans Petter Selasky sizeof(struct ip6_hdr));
248efe9a399SKonstantin Belousov
249efe9a399SKonstantin Belousov /* TCP checksum */
250efe9a399SKonstantin Belousov th->th_sum = 0;
251efe9a399SKonstantin Belousov tcp_csum = ~in6_cksum_partial_l2(mb, IPPROTO_TCP,
252efe9a399SKonstantin Belousov sizeof(struct ether_header),
253efe9a399SKonstantin Belousov sizeof(struct ether_header) + sizeof(struct ip6_hdr),
254efe9a399SKonstantin Belousov tot_len - sizeof(struct ip6_hdr), th->th_off * 4) & 0xffff;
255efe9a399SKonstantin Belousov tcp_csum = csum_reduce(tcp_csum + cqe->check_sum);
256efe9a399SKonstantin Belousov th->th_sum = ~tcp_csum & 0xffff;
257dc7e38acSHans Petter Selasky }
258dc7e38acSHans Petter Selasky }
259dc7e38acSHans Petter Selasky
260ef23f141SKonstantin Belousov static uint64_t
mlx5e_mbuf_tstmp(struct mlx5e_priv * priv,uint64_t hw_tstmp)261ef23f141SKonstantin Belousov mlx5e_mbuf_tstmp(struct mlx5e_priv *priv, uint64_t hw_tstmp)
262ef23f141SKonstantin Belousov {
263945f3984SHans Petter Selasky struct mlx5e_clbr_point *cp, dcp;
2647cc3ea9cSRandall Stewart uint64_t tstmp_sec, tstmp_nsec;
2657cc3ea9cSRandall Stewart uint64_t hw_clocks;
2667cc3ea9cSRandall Stewart uint64_t rt_cur_to_prev, res_s, res_n, res_s_modulo, res;
2677cc3ea9cSRandall Stewart uint64_t hw_clk_div;
268ef23f141SKonstantin Belousov u_int gen;
269ef23f141SKonstantin Belousov
270ef23f141SKonstantin Belousov do {
271ef23f141SKonstantin Belousov cp = &priv->clbr_points[priv->clbr_curr];
272ef23f141SKonstantin Belousov gen = atomic_load_acq_int(&cp->clbr_gen);
273945f3984SHans Petter Selasky if (gen == 0)
274945f3984SHans Petter Selasky return (0);
275945f3984SHans Petter Selasky dcp = *cp;
276945f3984SHans Petter Selasky atomic_thread_fence_acq();
2777cc3ea9cSRandall Stewart } while (gen != dcp.clbr_gen);
278ef23f141SKonstantin Belousov /*
2797cc3ea9cSRandall Stewart * Our goal here is to have a result that is:
2807cc3ea9cSRandall Stewart *
2817cc3ea9cSRandall Stewart * ( (cur_time - prev_time) )
2827cc3ea9cSRandall Stewart * ((hw_tstmp - hw_prev) * ----------------------------- ) + prev_time
2837cc3ea9cSRandall Stewart * ( (hw_cur - hw_prev) )
2847cc3ea9cSRandall Stewart *
2857cc3ea9cSRandall Stewart * With the constraints that we cannot use float and we
2867cc3ea9cSRandall Stewart * don't want to overflow the uint64_t numbers we are using.
2877cc3ea9cSRandall Stewart *
2887cc3ea9cSRandall Stewart * The plan is to take the clocking value of the hw timestamps
2897cc3ea9cSRandall Stewart * and split them into seconds and nanosecond equivalent portions.
2907cc3ea9cSRandall Stewart * Then we operate on the two portions seperately making sure to
2917cc3ea9cSRandall Stewart * bring back the carry over from the seconds when we divide.
2927cc3ea9cSRandall Stewart *
2937cc3ea9cSRandall Stewart * First up lets get the two divided into separate entities
2947cc3ea9cSRandall Stewart * i.e. the seconds. We use the clock frequency for this.
2957cc3ea9cSRandall Stewart * Note that priv->cclk was setup with the clock frequency
2967cc3ea9cSRandall Stewart * in hz so we are all set to go.
297ef23f141SKonstantin Belousov */
2987cc3ea9cSRandall Stewart hw_clocks = hw_tstmp - dcp.clbr_hw_prev;
2997cc3ea9cSRandall Stewart tstmp_sec = hw_clocks / priv->cclk;
3007cc3ea9cSRandall Stewart tstmp_nsec = hw_clocks % priv->cclk;
3017cc3ea9cSRandall Stewart /* Now work with them separately */
3027cc3ea9cSRandall Stewart rt_cur_to_prev = (dcp.base_curr - dcp.base_prev);
3037cc3ea9cSRandall Stewart res_s = tstmp_sec * rt_cur_to_prev;
3047cc3ea9cSRandall Stewart res_n = tstmp_nsec * rt_cur_to_prev;
3057cc3ea9cSRandall Stewart /* Now lets get our divider */
3067cc3ea9cSRandall Stewart hw_clk_div = dcp.clbr_hw_curr - dcp.clbr_hw_prev;
3077cc3ea9cSRandall Stewart /* Make sure to save the remainder from the seconds divide */
3087cc3ea9cSRandall Stewart res_s_modulo = res_s % hw_clk_div;
3097cc3ea9cSRandall Stewart res_s /= hw_clk_div;
3107cc3ea9cSRandall Stewart /* scale the remainder to where it should be */
3117cc3ea9cSRandall Stewart res_s_modulo *= priv->cclk;
3127cc3ea9cSRandall Stewart /* Now add in the remainder */
3137cc3ea9cSRandall Stewart res_n += res_s_modulo;
3147cc3ea9cSRandall Stewart /* Now do the divide */
3157cc3ea9cSRandall Stewart res_n /= hw_clk_div;
3167cc3ea9cSRandall Stewart res_s *= priv->cclk;
3177cc3ea9cSRandall Stewart /* Recombine the two */
3187cc3ea9cSRandall Stewart res = res_s + res_n;
3197cc3ea9cSRandall Stewart /* And now add in the base time to get to the real timestamp */
320945f3984SHans Petter Selasky res += dcp.base_prev;
321ef23f141SKonstantin Belousov return (res);
322ef23f141SKonstantin Belousov }
323ef23f141SKonstantin Belousov
324dc7e38acSHans Petter Selasky static inline void
mlx5e_build_rx_mbuf(struct mlx5_cqe64 * cqe,struct mlx5e_rq * rq,struct mbuf * mb,struct mlx5e_rq_mbuf * mr,u32 cqe_bcnt)325d00f3505SKonstantin Belousov mlx5e_build_rx_mbuf(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
326d00f3505SKonstantin Belousov struct mbuf *mb, struct mlx5e_rq_mbuf *mr, u32 cqe_bcnt)
327dc7e38acSHans Petter Selasky {
3285dc00f00SJustin Hibbits if_t ifp = rq->ifp;
329ef23f141SKonstantin Belousov struct mlx5e_channel *c;
3302f17f76aSHans Petter Selasky struct mbuf *mb_head;
331dc7e38acSHans Petter Selasky int lro_num_seg; /* HW LRO session aggregated packets counter */
332ef23f141SKonstantin Belousov uint64_t tstmp;
333dc7e38acSHans Petter Selasky
334dc7e38acSHans Petter Selasky lro_num_seg = be32_to_cpu(cqe->srqn) >> 24;
335dc7e38acSHans Petter Selasky if (lro_num_seg > 1) {
336dc7e38acSHans Petter Selasky mlx5e_lro_update_hdr(mb, cqe);
337dc7e38acSHans Petter Selasky rq->stats.lro_packets++;
338dc7e38acSHans Petter Selasky rq->stats.lro_bytes += cqe_bcnt;
339dc7e38acSHans Petter Selasky }
340dc7e38acSHans Petter Selasky
3412f17f76aSHans Petter Selasky mb->m_pkthdr.len = cqe_bcnt;
3422f17f76aSHans Petter Selasky for (mb_head = mb; mb != NULL; mb = mb->m_next) {
3432f17f76aSHans Petter Selasky if (mb->m_len > cqe_bcnt)
3442f17f76aSHans Petter Selasky mb->m_len = cqe_bcnt;
3452f17f76aSHans Petter Selasky cqe_bcnt -= mb->m_len;
3462f17f76aSHans Petter Selasky if (likely(cqe_bcnt == 0)) {
3472f17f76aSHans Petter Selasky if (likely(mb->m_next != NULL)) {
3482f17f76aSHans Petter Selasky /* trim off empty mbufs */
3492f17f76aSHans Petter Selasky m_freem(mb->m_next);
3502f17f76aSHans Petter Selasky mb->m_next = NULL;
3512f17f76aSHans Petter Selasky }
3522f17f76aSHans Petter Selasky break;
3532f17f76aSHans Petter Selasky }
3542f17f76aSHans Petter Selasky }
3552f17f76aSHans Petter Selasky /* rewind to first mbuf in chain */
3562f17f76aSHans Petter Selasky mb = mb_head;
3574d0e6d84SHans Petter Selasky
358dc7e38acSHans Petter Selasky /* check if a Toeplitz hash was computed */
359278ce1c9SHans Petter Selasky if (cqe->rss_hash_type != 0) {
360dc7e38acSHans Petter Selasky mb->m_pkthdr.flowid = be32_to_cpu(cqe->rss_hash_result);
361278ce1c9SHans Petter Selasky #ifdef RSS
362278ce1c9SHans Petter Selasky /* decode the RSS hash type */
363278ce1c9SHans Petter Selasky switch (cqe->rss_hash_type &
364278ce1c9SHans Petter Selasky (CQE_RSS_DST_HTYPE_L4 | CQE_RSS_DST_HTYPE_IP)) {
365278ce1c9SHans Petter Selasky /* IPv4 */
366278ce1c9SHans Petter Selasky case (CQE_RSS_DST_HTYPE_TCP | CQE_RSS_DST_HTYPE_IPV4):
367278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_TCP_IPV4);
368278ce1c9SHans Petter Selasky break;
369278ce1c9SHans Petter Selasky case (CQE_RSS_DST_HTYPE_UDP | CQE_RSS_DST_HTYPE_IPV4):
370278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_UDP_IPV4);
371278ce1c9SHans Petter Selasky break;
372278ce1c9SHans Petter Selasky case CQE_RSS_DST_HTYPE_IPV4:
373278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_IPV4);
374278ce1c9SHans Petter Selasky break;
375278ce1c9SHans Petter Selasky /* IPv6 */
376278ce1c9SHans Petter Selasky case (CQE_RSS_DST_HTYPE_TCP | CQE_RSS_DST_HTYPE_IPV6):
377278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_TCP_IPV6);
378278ce1c9SHans Petter Selasky break;
379278ce1c9SHans Petter Selasky case (CQE_RSS_DST_HTYPE_UDP | CQE_RSS_DST_HTYPE_IPV6):
380278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_UDP_IPV6);
381278ce1c9SHans Petter Selasky break;
382278ce1c9SHans Petter Selasky case CQE_RSS_DST_HTYPE_IPV6:
383278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_RSS_IPV6);
384278ce1c9SHans Petter Selasky break;
385278ce1c9SHans Petter Selasky default: /* Other */
38636ad8372SSepherosa Ziehau M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE_HASH);
387278ce1c9SHans Petter Selasky break;
388278ce1c9SHans Petter Selasky }
389278ce1c9SHans Petter Selasky #else
39036ad8372SSepherosa Ziehau M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE_HASH);
391278ce1c9SHans Petter Selasky #endif
392149349e0SKonstantin Belousov #ifdef M_HASHTYPE_SETINNER
393149349e0SKonstantin Belousov if (cqe_is_tunneled(cqe))
394149349e0SKonstantin Belousov M_HASHTYPE_SETINNER(mb);
395149349e0SKonstantin Belousov #endif
396278ce1c9SHans Petter Selasky } else {
397278ce1c9SHans Petter Selasky mb->m_pkthdr.flowid = rq->ix;
398278ce1c9SHans Petter Selasky M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE);
399278ce1c9SHans Petter Selasky }
400dc7e38acSHans Petter Selasky mb->m_pkthdr.rcvif = ifp;
401cb276279SHans Petter Selasky mb->m_pkthdr.leaf_rcvif = ifp;
402dc7e38acSHans Petter Selasky
403149349e0SKonstantin Belousov if (cqe_is_tunneled(cqe)) {
404149349e0SKonstantin Belousov /*
405149349e0SKonstantin Belousov * CQE can be tunneled only if TIR is configured to
406149349e0SKonstantin Belousov * enable parsing of tunneled payload, so no need to
407149349e0SKonstantin Belousov * check for capabilities.
408149349e0SKonstantin Belousov */
409149349e0SKonstantin Belousov if (((cqe->hds_ip_ext & (CQE_L2_OK | CQE_L3_OK)) ==
410149349e0SKonstantin Belousov (CQE_L2_OK | CQE_L3_OK))) {
411149349e0SKonstantin Belousov mb->m_pkthdr.csum_flags |=
412149349e0SKonstantin Belousov CSUM_INNER_L3_CALC | CSUM_INNER_L3_VALID |
413149349e0SKonstantin Belousov CSUM_IP_CHECKED | CSUM_IP_VALID |
414149349e0SKonstantin Belousov CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
415149349e0SKonstantin Belousov mb->m_pkthdr.csum_data = htons(0xffff);
416aabca103SHans Petter Selasky
417aabca103SHans Petter Selasky if (likely((cqe->hds_ip_ext & CQE_L4_OK) == CQE_L4_OK)) {
418149349e0SKonstantin Belousov mb->m_pkthdr.csum_flags |=
419149349e0SKonstantin Belousov CSUM_INNER_L4_CALC | CSUM_INNER_L4_VALID;
420149349e0SKonstantin Belousov }
421aabca103SHans Petter Selasky } else {
422aabca103SHans Petter Selasky rq->stats.csum_none++;
423aabca103SHans Petter Selasky }
4245dc00f00SJustin Hibbits } else if (likely((if_getcapenable(ifp) & (IFCAP_RXCSUM |
425149349e0SKonstantin Belousov IFCAP_RXCSUM_IPV6)) != 0) &&
426dc7e38acSHans Petter Selasky ((cqe->hds_ip_ext & (CQE_L2_OK | CQE_L3_OK | CQE_L4_OK)) ==
427dc7e38acSHans Petter Selasky (CQE_L2_OK | CQE_L3_OK | CQE_L4_OK))) {
428dc7e38acSHans Petter Selasky mb->m_pkthdr.csum_flags =
429dc7e38acSHans Petter Selasky CSUM_IP_CHECKED | CSUM_IP_VALID |
430dc7e38acSHans Petter Selasky CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
431dc7e38acSHans Petter Selasky mb->m_pkthdr.csum_data = htons(0xffff);
432dc7e38acSHans Petter Selasky } else {
433dc7e38acSHans Petter Selasky rq->stats.csum_none++;
434dc7e38acSHans Petter Selasky }
435dc7e38acSHans Petter Selasky
436dc7e38acSHans Petter Selasky if (cqe_has_vlan(cqe)) {
437dc7e38acSHans Petter Selasky mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->vlan_info);
438dc7e38acSHans Petter Selasky mb->m_flags |= M_VLANTAG;
439dc7e38acSHans Petter Selasky }
440ef23f141SKonstantin Belousov
441ef23f141SKonstantin Belousov c = container_of(rq, struct mlx5e_channel, rq);
442ef23f141SKonstantin Belousov if (c->priv->clbr_done >= 2) {
443ef23f141SKonstantin Belousov tstmp = mlx5e_mbuf_tstmp(c->priv, be64_to_cpu(cqe->timestamp));
444ef23f141SKonstantin Belousov if ((tstmp & MLX5_CQE_TSTMP_PTP) != 0) {
445ef23f141SKonstantin Belousov /*
446ef23f141SKonstantin Belousov * Timestamp was taken on the packet entrance,
447ef23f141SKonstantin Belousov * instead of the cqe generation.
448ef23f141SKonstantin Belousov */
449ef23f141SKonstantin Belousov tstmp &= ~MLX5_CQE_TSTMP_PTP;
450ef23f141SKonstantin Belousov mb->m_flags |= M_TSTMP_HPREC;
451ef23f141SKonstantin Belousov }
4527cc3ea9cSRandall Stewart if (tstmp != 0) {
453ef23f141SKonstantin Belousov mb->m_pkthdr.rcv_tstmp = tstmp;
454ef23f141SKonstantin Belousov mb->m_flags |= M_TSTMP;
455ef23f141SKonstantin Belousov }
4567cc3ea9cSRandall Stewart }
45784d7b8e7SHans Petter Selasky switch (get_cqe_tls_offload(cqe)) {
45884d7b8e7SHans Petter Selasky case CQE_TLS_OFFLOAD_DECRYPTED:
45984d7b8e7SHans Petter Selasky /* set proper checksum flag for decrypted packets */
46084d7b8e7SHans Petter Selasky mb->m_pkthdr.csum_flags |= CSUM_TLS_DECRYPTED;
46184d7b8e7SHans Petter Selasky rq->stats.decrypted_ok_packets++;
46284d7b8e7SHans Petter Selasky break;
46384d7b8e7SHans Petter Selasky case CQE_TLS_OFFLOAD_ERROR:
46484d7b8e7SHans Petter Selasky rq->stats.decrypted_error_packets++;
46584d7b8e7SHans Petter Selasky break;
46684d7b8e7SHans Petter Selasky default:
46784d7b8e7SHans Petter Selasky break;
46884d7b8e7SHans Petter Selasky }
469e23731dbSKonstantin Belousov
470d00f3505SKonstantin Belousov mlx5e_accel_ipsec_handle_rx(mb, cqe, mr);
471dc7e38acSHans Petter Selasky }
472dc7e38acSHans Petter Selasky
47390cc1c77SHans Petter Selasky static inline void
mlx5e_read_cqe_slot(struct mlx5e_cq * cq,u32 cc,void * data)47490cc1c77SHans Petter Selasky mlx5e_read_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
47590cc1c77SHans Petter Selasky {
47690cc1c77SHans Petter Selasky memcpy(data, mlx5_cqwq_get_wqe(&cq->wq, (cc & cq->wq.sz_m1)),
47790cc1c77SHans Petter Selasky sizeof(struct mlx5_cqe64));
47890cc1c77SHans Petter Selasky }
47990cc1c77SHans Petter Selasky
48090cc1c77SHans Petter Selasky static inline void
mlx5e_write_cqe_slot(struct mlx5e_cq * cq,u32 cc,void * data)48190cc1c77SHans Petter Selasky mlx5e_write_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
48290cc1c77SHans Petter Selasky {
48390cc1c77SHans Petter Selasky memcpy(mlx5_cqwq_get_wqe(&cq->wq, cc & cq->wq.sz_m1),
48490cc1c77SHans Petter Selasky data, sizeof(struct mlx5_cqe64));
48590cc1c77SHans Petter Selasky }
48690cc1c77SHans Petter Selasky
48790cc1c77SHans Petter Selasky static inline void
mlx5e_decompress_cqe(struct mlx5e_cq * cq,struct mlx5_cqe64 * title,struct mlx5_mini_cqe8 * mini,u16 wqe_counter,int i)48890cc1c77SHans Petter Selasky mlx5e_decompress_cqe(struct mlx5e_cq *cq, struct mlx5_cqe64 *title,
48990cc1c77SHans Petter Selasky struct mlx5_mini_cqe8 *mini,
49090cc1c77SHans Petter Selasky u16 wqe_counter, int i)
49190cc1c77SHans Petter Selasky {
492636d1fecSHans Petter Selasky /*
493636d1fecSHans Petter Selasky * NOTE: The fields which are not set here are copied from the
494636d1fecSHans Petter Selasky * initial and common title. See memcpy() in
495636d1fecSHans Petter Selasky * mlx5e_write_cqe_slot().
496636d1fecSHans Petter Selasky */
49790cc1c77SHans Petter Selasky title->byte_cnt = mini->byte_cnt;
49890cc1c77SHans Petter Selasky title->wqe_counter = cpu_to_be16((wqe_counter + i) & cq->wq.sz_m1);
499a005c157SHans Petter Selasky title->rss_hash_result = mini->rx_hash_result;
500a005c157SHans Petter Selasky /*
501a005c157SHans Petter Selasky * Since we use MLX5_CQE_FORMAT_HASH when creating the RX CQ,
502a005c157SHans Petter Selasky * the value of the checksum should be ignored.
503a005c157SHans Petter Selasky */
504a005c157SHans Petter Selasky title->check_sum = 0;
50590cc1c77SHans Petter Selasky title->op_own = (title->op_own & 0xf0) |
50690cc1c77SHans Petter Selasky (((cq->wq.cc + i) >> cq->wq.log_sz) & 1);
50790cc1c77SHans Petter Selasky }
50890cc1c77SHans Petter Selasky
50990cc1c77SHans Petter Selasky #define MLX5E_MINI_ARRAY_SZ 8
51090cc1c77SHans Petter Selasky /* Make sure structs are not packet differently */
51190cc1c77SHans Petter Selasky CTASSERT(sizeof(struct mlx5_cqe64) ==
51290cc1c77SHans Petter Selasky sizeof(struct mlx5_mini_cqe8) * MLX5E_MINI_ARRAY_SZ);
51390cc1c77SHans Petter Selasky static void
mlx5e_decompress_cqes(struct mlx5e_cq * cq)51490cc1c77SHans Petter Selasky mlx5e_decompress_cqes(struct mlx5e_cq *cq)
51590cc1c77SHans Petter Selasky {
51690cc1c77SHans Petter Selasky struct mlx5_mini_cqe8 mini_array[MLX5E_MINI_ARRAY_SZ];
51790cc1c77SHans Petter Selasky struct mlx5_cqe64 title;
51890cc1c77SHans Petter Selasky u32 cqe_count;
51990cc1c77SHans Petter Selasky u32 i = 0;
52090cc1c77SHans Petter Selasky u16 title_wqe_counter;
52190cc1c77SHans Petter Selasky
52290cc1c77SHans Petter Selasky mlx5e_read_cqe_slot(cq, cq->wq.cc, &title);
52390cc1c77SHans Petter Selasky title_wqe_counter = be16_to_cpu(title.wqe_counter);
52490cc1c77SHans Petter Selasky cqe_count = be32_to_cpu(title.byte_cnt);
52590cc1c77SHans Petter Selasky
52690cc1c77SHans Petter Selasky /* Make sure we won't overflow */
52790cc1c77SHans Petter Selasky KASSERT(cqe_count <= cq->wq.sz_m1,
52890cc1c77SHans Petter Selasky ("%s: cqe_count %u > cq->wq.sz_m1 %u", __func__,
52990cc1c77SHans Petter Selasky cqe_count, cq->wq.sz_m1));
53090cc1c77SHans Petter Selasky
53190cc1c77SHans Petter Selasky mlx5e_read_cqe_slot(cq, cq->wq.cc + 1, mini_array);
53290cc1c77SHans Petter Selasky while (true) {
53390cc1c77SHans Petter Selasky mlx5e_decompress_cqe(cq, &title,
53490cc1c77SHans Petter Selasky &mini_array[i % MLX5E_MINI_ARRAY_SZ],
53590cc1c77SHans Petter Selasky title_wqe_counter, i);
53690cc1c77SHans Petter Selasky mlx5e_write_cqe_slot(cq, cq->wq.cc + i, &title);
53790cc1c77SHans Petter Selasky i++;
53890cc1c77SHans Petter Selasky
53990cc1c77SHans Petter Selasky if (i == cqe_count)
54090cc1c77SHans Petter Selasky break;
54190cc1c77SHans Petter Selasky if (i % MLX5E_MINI_ARRAY_SZ == 0)
54290cc1c77SHans Petter Selasky mlx5e_read_cqe_slot(cq, cq->wq.cc + i, mini_array);
54390cc1c77SHans Petter Selasky }
54490cc1c77SHans Petter Selasky }
54590cc1c77SHans Petter Selasky
546dc7e38acSHans Petter Selasky static int
mlx5e_poll_rx_cq(struct mlx5e_rq * rq,int budget)547dc7e38acSHans Petter Selasky mlx5e_poll_rx_cq(struct mlx5e_rq *rq, int budget)
548dc7e38acSHans Petter Selasky {
549538ff57bSAndrew Gallatin struct pfil_head *pfil;
550538ff57bSAndrew Gallatin int i, rv;
551dc7e38acSHans Petter Selasky
5525dc00f00SJustin Hibbits CURVNET_SET_QUIET(if_getvnet(rq->ifp));
553538ff57bSAndrew Gallatin pfil = rq->channel->priv->pfil;
554dc7e38acSHans Petter Selasky for (i = 0; i < budget; i++) {
555dc7e38acSHans Petter Selasky struct mlx5e_rx_wqe *wqe;
556dc7e38acSHans Petter Selasky struct mlx5_cqe64 *cqe;
557dc7e38acSHans Petter Selasky struct mbuf *mb;
558dc7e38acSHans Petter Selasky __be16 wqe_counter_be;
559dc7e38acSHans Petter Selasky u16 wqe_counter;
560538ff57bSAndrew Gallatin u32 byte_cnt, seglen;
561dc7e38acSHans Petter Selasky
562dc7e38acSHans Petter Selasky cqe = mlx5e_get_cqe(&rq->cq);
563dc7e38acSHans Petter Selasky if (!cqe)
564dc7e38acSHans Petter Selasky break;
565dc7e38acSHans Petter Selasky
56690cc1c77SHans Petter Selasky if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED)
56790cc1c77SHans Petter Selasky mlx5e_decompress_cqes(&rq->cq);
56890cc1c77SHans Petter Selasky
56990cc1c77SHans Petter Selasky mlx5_cqwq_pop(&rq->cq.wq);
57090cc1c77SHans Petter Selasky
571dc7e38acSHans Petter Selasky wqe_counter_be = cqe->wqe_counter;
572dc7e38acSHans Petter Selasky wqe_counter = be16_to_cpu(wqe_counter_be);
573dc7e38acSHans Petter Selasky wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
574dc7e38acSHans Petter Selasky byte_cnt = be32_to_cpu(cqe->byte_cnt);
575dc7e38acSHans Petter Selasky
576dc7e38acSHans Petter Selasky bus_dmamap_sync(rq->dma_tag,
577dc7e38acSHans Petter Selasky rq->mbuf[wqe_counter].dma_map,
578dc7e38acSHans Petter Selasky BUS_DMASYNC_POSTREAD);
579dc7e38acSHans Petter Selasky
580dc7e38acSHans Petter Selasky if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) {
581bc531a1fSHans Petter Selasky mlx5e_dump_err_cqe(&rq->cq, rq->rqn, (const void *)cqe);
582dc7e38acSHans Petter Selasky rq->stats.wqe_err++;
583dc7e38acSHans Petter Selasky goto wq_ll_pop;
584dc7e38acSHans Petter Selasky }
585538ff57bSAndrew Gallatin if (pfil != NULL && PFIL_HOOKED_IN(pfil)) {
586538ff57bSAndrew Gallatin seglen = MIN(byte_cnt, MLX5E_MAX_RX_BYTES);
587caf32b26SGleb Smirnoff rv = pfil_mem_in(rq->channel->priv->pfil,
588caf32b26SGleb Smirnoff rq->mbuf[wqe_counter].data, seglen, rq->ifp, &mb);
589538ff57bSAndrew Gallatin
590538ff57bSAndrew Gallatin switch (rv) {
591538ff57bSAndrew Gallatin case PFIL_DROPPED:
592538ff57bSAndrew Gallatin case PFIL_CONSUMED:
593538ff57bSAndrew Gallatin /*
594538ff57bSAndrew Gallatin * Filter dropped or consumed it. In
595538ff57bSAndrew Gallatin * either case, we can just recycle
596538ff57bSAndrew Gallatin * buffer; there is no more work to do.
597538ff57bSAndrew Gallatin */
598538ff57bSAndrew Gallatin rq->stats.packets++;
599538ff57bSAndrew Gallatin goto wq_ll_pop;
600538ff57bSAndrew Gallatin case PFIL_REALLOCED:
601538ff57bSAndrew Gallatin /*
602538ff57bSAndrew Gallatin * Filter copied it; recycle buffer
603538ff57bSAndrew Gallatin * and receive the new mbuf allocated
604538ff57bSAndrew Gallatin * by the Filter
605538ff57bSAndrew Gallatin */
606538ff57bSAndrew Gallatin goto rx_common;
607538ff57bSAndrew Gallatin default:
608538ff57bSAndrew Gallatin /*
609538ff57bSAndrew Gallatin * The Filter said it was OK, so
610538ff57bSAndrew Gallatin * receive like normal.
611538ff57bSAndrew Gallatin */
612538ff57bSAndrew Gallatin KASSERT(rv == PFIL_PASS,
613538ff57bSAndrew Gallatin ("Filter returned %d!\n", rv));
614538ff57bSAndrew Gallatin }
615538ff57bSAndrew Gallatin }
616e23731dbSKonstantin Belousov if (!mlx5e_accel_ipsec_flow(cqe) /* tag is already assigned
617e23731dbSKonstantin Belousov to rq->mbuf */ &&
618e23731dbSKonstantin Belousov MHLEN - MLX5E_NET_IP_ALIGN >= byte_cnt &&
619dc7e38acSHans Petter Selasky (mb = m_gethdr(M_NOWAIT, MT_DATA)) != NULL) {
6202f17f76aSHans Petter Selasky /* set maximum mbuf length */
6212f17f76aSHans Petter Selasky mb->m_len = MHLEN - MLX5E_NET_IP_ALIGN;
6228508e4d7SHans Petter Selasky /* get IP header aligned */
6238508e4d7SHans Petter Selasky mb->m_data += MLX5E_NET_IP_ALIGN;
6248508e4d7SHans Petter Selasky
625dc7e38acSHans Petter Selasky bcopy(rq->mbuf[wqe_counter].data, mtod(mb, caddr_t),
626dc7e38acSHans Petter Selasky byte_cnt);
627dc7e38acSHans Petter Selasky } else {
628dc7e38acSHans Petter Selasky mb = rq->mbuf[wqe_counter].mbuf;
629dc7e38acSHans Petter Selasky rq->mbuf[wqe_counter].mbuf = NULL; /* safety clear */
630dc7e38acSHans Petter Selasky
631dc7e38acSHans Petter Selasky bus_dmamap_unload(rq->dma_tag,
632dc7e38acSHans Petter Selasky rq->mbuf[wqe_counter].dma_map);
633dc7e38acSHans Petter Selasky }
634538ff57bSAndrew Gallatin rx_common:
635d00f3505SKonstantin Belousov mlx5e_build_rx_mbuf(cqe, rq, mb, &rq->mbuf[wqe_counter],
636d00f3505SKonstantin Belousov byte_cnt);
63701f02abfSSlava Shwartsman rq->stats.bytes += byte_cnt;
638dc7e38acSHans Petter Selasky rq->stats.packets++;
63950575ce1SAndrew Gallatin #ifdef NUMA
6405dc00f00SJustin Hibbits mb->m_pkthdr.numa_domain = if_getnumadomain(rq->ifp);
64150575ce1SAndrew Gallatin #endif
64257d5dd79SHans Petter Selasky
64357d5dd79SHans Petter Selasky #if !defined(HAVE_TCP_LRO_RX)
64457d5dd79SHans Petter Selasky tcp_lro_queue_mbuf(&rq->lro, mb);
645dc7e38acSHans Petter Selasky #else
646dc7e38acSHans Petter Selasky if (mb->m_pkthdr.csum_flags == 0 ||
6475dc00f00SJustin Hibbits (if_getcapenable(rq->ifp) & IFCAP_LRO) == 0 ||
648dc7e38acSHans Petter Selasky rq->lro.lro_cnt == 0 ||
649dc7e38acSHans Petter Selasky tcp_lro_rx(&rq->lro, mb, 0) != 0) {
6505dc00f00SJustin Hibbits if_input(rq->ifp, mb);
651dc7e38acSHans Petter Selasky }
652dc7e38acSHans Petter Selasky #endif
653dc7e38acSHans Petter Selasky wq_ll_pop:
654dc7e38acSHans Petter Selasky mlx5_wq_ll_pop(&rq->wq, wqe_counter_be,
655dc7e38acSHans Petter Selasky &wqe->next.next_wqe_index);
656dc7e38acSHans Petter Selasky }
657538ff57bSAndrew Gallatin CURVNET_RESTORE();
658dc7e38acSHans Petter Selasky
659dc7e38acSHans Petter Selasky mlx5_cqwq_update_db_record(&rq->cq.wq);
660dc7e38acSHans Petter Selasky
661dc7e38acSHans Petter Selasky /* ensure cq space is freed before enabling more cqes */
662e44f4f35SKonstantin Belousov atomic_thread_fence_rel();
663dc7e38acSHans Petter Selasky return (i);
664dc7e38acSHans Petter Selasky }
665dc7e38acSHans Petter Selasky
666dc7e38acSHans Petter Selasky void
mlx5e_rx_cq_comp(struct mlx5_core_cq * mcq,struct mlx5_eqe * eqe __unused)667f34f0a65SHans Petter Selasky mlx5e_rx_cq_comp(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe __unused)
668dc7e38acSHans Petter Selasky {
6692d5e5a0dSHans Petter Selasky struct mlx5e_channel *c = container_of(mcq, struct mlx5e_channel, rq.cq.mcq);
670dc7e38acSHans Petter Selasky struct mlx5e_rq *rq = container_of(mcq, struct mlx5e_rq, cq.mcq);
671dc7e38acSHans Petter Selasky int i = 0;
672dc7e38acSHans Petter Selasky
673dc7e38acSHans Petter Selasky #ifdef HAVE_PER_CQ_EVENT_PACKET
67490c8e441SHans Petter Selasky #if (MHLEN < 15)
67590c8e441SHans Petter Selasky #error "MHLEN is too small"
67690c8e441SHans Petter Selasky #endif
67790c8e441SHans Petter Selasky struct mbuf *mb = m_gethdr(M_NOWAIT, MT_DATA);
678bb3853c6SHans Petter Selasky
679dc7e38acSHans Petter Selasky if (mb != NULL) {
680dc7e38acSHans Petter Selasky /* this code is used for debugging purpose only */
681dc7e38acSHans Petter Selasky mb->m_pkthdr.len = mb->m_len = 15;
682dc7e38acSHans Petter Selasky memset(mb->m_data, 255, 14);
683dc7e38acSHans Petter Selasky mb->m_data[14] = rq->ix;
684dc7e38acSHans Petter Selasky mb->m_pkthdr.rcvif = rq->ifp;
685cb276279SHans Petter Selasky mb->m_pkthdr.leaf_rcvif = rq->ifp;
6865dc00f00SJustin Hibbits if_input(rq->ifp, mb);
687dc7e38acSHans Petter Selasky }
688dc7e38acSHans Petter Selasky #endif
6892d5e5a0dSHans Petter Selasky for (int j = 0; j != MLX5E_MAX_TX_NUM_TC; j++) {
6902d5e5a0dSHans Petter Selasky mtx_lock(&c->sq[j].lock);
6912d5e5a0dSHans Petter Selasky c->sq[j].db_inhibit++;
6922d5e5a0dSHans Petter Selasky mtx_unlock(&c->sq[j].lock);
6932d5e5a0dSHans Petter Selasky }
694dc7e38acSHans Petter Selasky
69569426357SHans Petter Selasky mtx_lock(&c->iq.lock);
69669426357SHans Petter Selasky c->iq.db_inhibit++;
69769426357SHans Petter Selasky mtx_unlock(&c->iq.lock);
69869426357SHans Petter Selasky
699dc7e38acSHans Petter Selasky mtx_lock(&rq->mtx);
700*f0adc907SKonstantin Belousov if (rq->enabled == 0)
701*f0adc907SKonstantin Belousov goto out;
702*f0adc907SKonstantin Belousov rq->processing++;
703dc7e38acSHans Petter Selasky
704dc7e38acSHans Petter Selasky /*
705dc7e38acSHans Petter Selasky * Polling the entire CQ without posting new WQEs results in
706dc7e38acSHans Petter Selasky * lack of receive WQEs during heavy traffic scenarios.
707dc7e38acSHans Petter Selasky */
708dc7e38acSHans Petter Selasky while (1) {
709dc7e38acSHans Petter Selasky if (mlx5e_poll_rx_cq(rq, MLX5E_RX_BUDGET_MAX) !=
710dc7e38acSHans Petter Selasky MLX5E_RX_BUDGET_MAX)
711dc7e38acSHans Petter Selasky break;
712dc7e38acSHans Petter Selasky i += MLX5E_RX_BUDGET_MAX;
713dc7e38acSHans Petter Selasky if (i >= MLX5E_BUDGET_MAX)
714dc7e38acSHans Petter Selasky break;
715dc7e38acSHans Petter Selasky mlx5e_post_rx_wqes(rq);
716dc7e38acSHans Petter Selasky }
717dc7e38acSHans Petter Selasky mlx5e_post_rx_wqes(rq);
718423530beSHans Petter Selasky /* check for dynamic interrupt moderation callback */
719423530beSHans Petter Selasky if (rq->dim.mode != NET_DIM_CQ_PERIOD_MODE_DISABLED)
720423530beSHans Petter Selasky net_dim(&rq->dim, rq->stats.packets, rq->stats.bytes);
721e5d6b589SHans Petter Selasky mlx5e_cq_arm(&rq->cq, MLX5_GET_DOORBELL_LOCK(&rq->channel->priv->doorbell_lock));
72257d5dd79SHans Petter Selasky tcp_lro_flush_all(&rq->lro);
723*f0adc907SKonstantin Belousov rq->processing--;
724*f0adc907SKonstantin Belousov out:
725dc7e38acSHans Petter Selasky mtx_unlock(&rq->mtx);
7262d5e5a0dSHans Petter Selasky
7272d5e5a0dSHans Petter Selasky for (int j = 0; j != MLX5E_MAX_TX_NUM_TC; j++) {
7282d5e5a0dSHans Petter Selasky mtx_lock(&c->sq[j].lock);
7292d5e5a0dSHans Petter Selasky c->sq[j].db_inhibit--;
7302d5e5a0dSHans Petter Selasky /* Update the doorbell record, if any. */
7312d5e5a0dSHans Petter Selasky mlx5e_tx_notify_hw(c->sq + j, true);
7322d5e5a0dSHans Petter Selasky mtx_unlock(&c->sq[j].lock);
7332d5e5a0dSHans Petter Selasky }
73469426357SHans Petter Selasky
73569426357SHans Petter Selasky mtx_lock(&c->iq.lock);
73669426357SHans Petter Selasky c->iq.db_inhibit--;
73769426357SHans Petter Selasky mlx5e_iq_notify_hw(&c->iq);
73869426357SHans Petter Selasky mtx_unlock(&c->iq.lock);
739dc7e38acSHans Petter Selasky }
740