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