13c0086b8SZbigniew Bodek /* 23c0086b8SZbigniew Bodek * Copyright (C) 2015 Cavium Inc. 33c0086b8SZbigniew Bodek * All rights reserved. 43c0086b8SZbigniew Bodek * 53c0086b8SZbigniew Bodek * Redistribution and use in source and binary forms, with or without 63c0086b8SZbigniew Bodek * modification, are permitted provided that the following conditions 73c0086b8SZbigniew Bodek * are met: 83c0086b8SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright 93c0086b8SZbigniew Bodek * notice, this list of conditions and the following disclaimer. 103c0086b8SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright 113c0086b8SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the 123c0086b8SZbigniew Bodek * documentation and/or other materials provided with the distribution. 133c0086b8SZbigniew Bodek * 143c0086b8SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 153c0086b8SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 163c0086b8SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 173c0086b8SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 183c0086b8SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 193c0086b8SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 203c0086b8SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 213c0086b8SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 223c0086b8SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 233c0086b8SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 243c0086b8SZbigniew Bodek * SUCH DAMAGE. 253c0086b8SZbigniew Bodek * 263c0086b8SZbigniew Bodek * $FreeBSD$ 273c0086b8SZbigniew Bodek * 283c0086b8SZbigniew Bodek */ 292306b72aSZbigniew Bodek #include <sys/cdefs.h> 302306b72aSZbigniew Bodek __FBSDID("$FreeBSD$"); 313c0086b8SZbigniew Bodek 32856dce91SZbigniew Bodek #include "opt_inet.h" 33856dce91SZbigniew Bodek #include "opt_inet6.h" 34856dce91SZbigniew Bodek 352306b72aSZbigniew Bodek #include <sys/param.h> 362306b72aSZbigniew Bodek #include <sys/systm.h> 372306b72aSZbigniew Bodek #include <sys/bitset.h> 382306b72aSZbigniew Bodek #include <sys/bitstring.h> 392306b72aSZbigniew Bodek #include <sys/buf_ring.h> 402306b72aSZbigniew Bodek #include <sys/bus.h> 412306b72aSZbigniew Bodek #include <sys/endian.h> 422306b72aSZbigniew Bodek #include <sys/kernel.h> 432306b72aSZbigniew Bodek #include <sys/malloc.h> 442306b72aSZbigniew Bodek #include <sys/module.h> 452306b72aSZbigniew Bodek #include <sys/rman.h> 462306b72aSZbigniew Bodek #include <sys/pciio.h> 472306b72aSZbigniew Bodek #include <sys/pcpu.h> 482306b72aSZbigniew Bodek #include <sys/proc.h> 492306b72aSZbigniew Bodek #include <sys/sockio.h> 502306b72aSZbigniew Bodek #include <sys/socket.h> 51f6cdb4ceSZbigniew Bodek #include <sys/stdatomic.h> 522306b72aSZbigniew Bodek #include <sys/cpuset.h> 532306b72aSZbigniew Bodek #include <sys/lock.h> 542306b72aSZbigniew Bodek #include <sys/mutex.h> 552306b72aSZbigniew Bodek #include <sys/smp.h> 562306b72aSZbigniew Bodek #include <sys/taskqueue.h> 573c0086b8SZbigniew Bodek 582306b72aSZbigniew Bodek #include <vm/vm.h> 592306b72aSZbigniew Bodek #include <vm/pmap.h> 602306b72aSZbigniew Bodek 612306b72aSZbigniew Bodek #include <machine/bus.h> 622306b72aSZbigniew Bodek #include <machine/vmparam.h> 632306b72aSZbigniew Bodek 642306b72aSZbigniew Bodek #include <net/if.h> 652306b72aSZbigniew Bodek #include <net/if_var.h> 662306b72aSZbigniew Bodek #include <net/if_media.h> 672306b72aSZbigniew Bodek #include <net/ifq.h> 687c617aceSZbigniew Bodek #include <net/bpf.h> 697c617aceSZbigniew Bodek #include <net/ethernet.h> 702306b72aSZbigniew Bodek 71856dce91SZbigniew Bodek #include <netinet/in_systm.h> 72856dce91SZbigniew Bodek #include <netinet/in.h> 73856dce91SZbigniew Bodek #include <netinet/if_ether.h> 74856dce91SZbigniew Bodek #include <netinet/ip.h> 75856dce91SZbigniew Bodek #include <netinet/ip6.h> 76856dce91SZbigniew Bodek #include <netinet/sctp.h> 77856dce91SZbigniew Bodek #include <netinet/tcp.h> 78856dce91SZbigniew Bodek #include <netinet/tcp_lro.h> 79856dce91SZbigniew Bodek #include <netinet/udp.h> 80856dce91SZbigniew Bodek 81c04716b1SBjoern A. Zeeb #include <netinet6/ip6_var.h> 82c04716b1SBjoern A. Zeeb 832306b72aSZbigniew Bodek #include <dev/pci/pcireg.h> 842306b72aSZbigniew Bodek #include <dev/pci/pcivar.h> 852306b72aSZbigniew Bodek 862306b72aSZbigniew Bodek #include "thunder_bgx.h" 873c0086b8SZbigniew Bodek #include "nic_reg.h" 883c0086b8SZbigniew Bodek #include "nic.h" 893c0086b8SZbigniew Bodek #include "q_struct.h" 903c0086b8SZbigniew Bodek #include "nicvf_queues.h" 913c0086b8SZbigniew Bodek 922306b72aSZbigniew Bodek #define DEBUG 932306b72aSZbigniew Bodek #undef DEBUG 942306b72aSZbigniew Bodek 952306b72aSZbigniew Bodek #ifdef DEBUG 962306b72aSZbigniew Bodek #define dprintf(dev, fmt, ...) device_printf(dev, fmt, ##__VA_ARGS__) 972306b72aSZbigniew Bodek #else 982306b72aSZbigniew Bodek #define dprintf(dev, fmt, ...) 992306b72aSZbigniew Bodek #endif 1002306b72aSZbigniew Bodek 1012306b72aSZbigniew Bodek MALLOC_DECLARE(M_NICVF); 1022306b72aSZbigniew Bodek 1032306b72aSZbigniew Bodek static void nicvf_free_snd_queue(struct nicvf *, struct snd_queue *); 1042306b72aSZbigniew Bodek static struct mbuf * nicvf_get_rcv_mbuf(struct nicvf *, struct cqe_rx_t *); 1052306b72aSZbigniew Bodek static void nicvf_sq_disable(struct nicvf *, int); 1062306b72aSZbigniew Bodek static void nicvf_sq_enable(struct nicvf *, struct snd_queue *, int); 1072306b72aSZbigniew Bodek static void nicvf_put_sq_desc(struct snd_queue *, int); 1082306b72aSZbigniew Bodek static void nicvf_cmp_queue_config(struct nicvf *, struct queue_set *, int, 1092306b72aSZbigniew Bodek boolean_t); 1102306b72aSZbigniew Bodek static void nicvf_sq_free_used_descs(struct nicvf *, struct snd_queue *, int); 1112306b72aSZbigniew Bodek 1127c617aceSZbigniew Bodek static int nicvf_tx_mbuf_locked(struct snd_queue *, struct mbuf **); 1137c617aceSZbigniew Bodek 1142306b72aSZbigniew Bodek static void nicvf_rbdr_task(void *, int); 1152306b72aSZbigniew Bodek static void nicvf_rbdr_task_nowait(void *, int); 1162306b72aSZbigniew Bodek 1173c0086b8SZbigniew Bodek struct rbuf_info { 1182306b72aSZbigniew Bodek bus_dma_tag_t dmat; 1192306b72aSZbigniew Bodek bus_dmamap_t dmap; 1202306b72aSZbigniew Bodek struct mbuf * mbuf; 1213c0086b8SZbigniew Bodek }; 1223c0086b8SZbigniew Bodek 1232306b72aSZbigniew Bodek #define GET_RBUF_INFO(x) ((struct rbuf_info *)((x) - NICVF_RCV_BUF_ALIGN_BYTES)) 1243c0086b8SZbigniew Bodek 1253c0086b8SZbigniew Bodek /* Poll a register for a specific value */ 1263c0086b8SZbigniew Bodek static int nicvf_poll_reg(struct nicvf *nic, int qidx, 1272306b72aSZbigniew Bodek uint64_t reg, int bit_pos, int bits, int val) 1283c0086b8SZbigniew Bodek { 1292306b72aSZbigniew Bodek uint64_t bit_mask; 1302306b72aSZbigniew Bodek uint64_t reg_val; 1313c0086b8SZbigniew Bodek int timeout = 10; 1323c0086b8SZbigniew Bodek 1332306b72aSZbigniew Bodek bit_mask = (1UL << bits) - 1; 1343c0086b8SZbigniew Bodek bit_mask = (bit_mask << bit_pos); 1353c0086b8SZbigniew Bodek 1363c0086b8SZbigniew Bodek while (timeout) { 1373c0086b8SZbigniew Bodek reg_val = nicvf_queue_reg_read(nic, reg, qidx); 1383c0086b8SZbigniew Bodek if (((reg_val & bit_mask) >> bit_pos) == val) 1392306b72aSZbigniew Bodek return (0); 1402306b72aSZbigniew Bodek 1412306b72aSZbigniew Bodek DELAY(1000); 1423c0086b8SZbigniew Bodek timeout--; 1433c0086b8SZbigniew Bodek } 1442306b72aSZbigniew Bodek device_printf(nic->dev, "Poll on reg 0x%lx failed\n", reg); 1452306b72aSZbigniew Bodek return (ETIMEDOUT); 1462306b72aSZbigniew Bodek } 1472306b72aSZbigniew Bodek 1482306b72aSZbigniew Bodek /* Callback for bus_dmamap_load() */ 1492306b72aSZbigniew Bodek static void 1502306b72aSZbigniew Bodek nicvf_dmamap_q_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1512306b72aSZbigniew Bodek { 1522306b72aSZbigniew Bodek bus_addr_t *paddr; 1532306b72aSZbigniew Bodek 1542306b72aSZbigniew Bodek KASSERT(nseg == 1, ("wrong number of segments, should be 1")); 1552306b72aSZbigniew Bodek paddr = arg; 1562306b72aSZbigniew Bodek *paddr = segs->ds_addr; 1573c0086b8SZbigniew Bodek } 1583c0086b8SZbigniew Bodek 1593c0086b8SZbigniew Bodek /* Allocate memory for a queue's descriptors */ 1602306b72aSZbigniew Bodek static int 1612306b72aSZbigniew Bodek nicvf_alloc_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem, 1623c0086b8SZbigniew Bodek int q_len, int desc_size, int align_bytes) 1633c0086b8SZbigniew Bodek { 164*21653635SJohn Baldwin int err, err_dmat __diagused; 1653c0086b8SZbigniew Bodek 1662306b72aSZbigniew Bodek /* Create DMA tag first */ 1672306b72aSZbigniew Bodek err = bus_dma_tag_create( 1682306b72aSZbigniew Bodek bus_get_dma_tag(nic->dev), /* parent tag */ 1692306b72aSZbigniew Bodek align_bytes, /* alignment */ 1702306b72aSZbigniew Bodek 0, /* boundary */ 1712306b72aSZbigniew Bodek BUS_SPACE_MAXADDR, /* lowaddr */ 1722306b72aSZbigniew Bodek BUS_SPACE_MAXADDR, /* highaddr */ 1732306b72aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 1742306b72aSZbigniew Bodek (q_len * desc_size), /* maxsize */ 1752306b72aSZbigniew Bodek 1, /* nsegments */ 1762306b72aSZbigniew Bodek (q_len * desc_size), /* maxsegsize */ 1772306b72aSZbigniew Bodek 0, /* flags */ 1782306b72aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 1792306b72aSZbigniew Bodek &dmem->dmat); /* dmat */ 1802306b72aSZbigniew Bodek 1812306b72aSZbigniew Bodek if (err != 0) { 1822306b72aSZbigniew Bodek device_printf(nic->dev, 1832306b72aSZbigniew Bodek "Failed to create busdma tag for descriptors ring\n"); 1842306b72aSZbigniew Bodek return (err); 1852306b72aSZbigniew Bodek } 1862306b72aSZbigniew Bodek 1872306b72aSZbigniew Bodek /* Allocate segment of continuous DMA safe memory */ 1882306b72aSZbigniew Bodek err = bus_dmamem_alloc( 1892306b72aSZbigniew Bodek dmem->dmat, /* DMA tag */ 1902306b72aSZbigniew Bodek &dmem->base, /* virtual address */ 1912306b72aSZbigniew Bodek (BUS_DMA_NOWAIT | BUS_DMA_ZERO), /* flags */ 1922306b72aSZbigniew Bodek &dmem->dmap); /* DMA map */ 1932306b72aSZbigniew Bodek if (err != 0) { 1942306b72aSZbigniew Bodek device_printf(nic->dev, "Failed to allocate DMA safe memory for" 1952306b72aSZbigniew Bodek "descriptors ring\n"); 1962306b72aSZbigniew Bodek goto dmamem_fail; 1972306b72aSZbigniew Bodek } 1982306b72aSZbigniew Bodek 1992306b72aSZbigniew Bodek err = bus_dmamap_load( 2002306b72aSZbigniew Bodek dmem->dmat, 2012306b72aSZbigniew Bodek dmem->dmap, 2022306b72aSZbigniew Bodek dmem->base, 2032306b72aSZbigniew Bodek (q_len * desc_size), /* allocation size */ 2042306b72aSZbigniew Bodek nicvf_dmamap_q_cb, /* map to DMA address cb. */ 2052306b72aSZbigniew Bodek &dmem->phys_base, /* physical address */ 2062306b72aSZbigniew Bodek BUS_DMA_NOWAIT); 2072306b72aSZbigniew Bodek if (err != 0) { 2082306b72aSZbigniew Bodek device_printf(nic->dev, 2092306b72aSZbigniew Bodek "Cannot load DMA map of descriptors ring\n"); 2102306b72aSZbigniew Bodek goto dmamap_fail; 2112306b72aSZbigniew Bodek } 2122306b72aSZbigniew Bodek 2132306b72aSZbigniew Bodek dmem->q_len = q_len; 2142306b72aSZbigniew Bodek dmem->size = (desc_size * q_len); 2152306b72aSZbigniew Bodek 2162306b72aSZbigniew Bodek return (0); 2172306b72aSZbigniew Bodek 2182306b72aSZbigniew Bodek dmamap_fail: 2192306b72aSZbigniew Bodek bus_dmamem_free(dmem->dmat, dmem->base, dmem->dmap); 2202306b72aSZbigniew Bodek dmem->phys_base = 0; 2212306b72aSZbigniew Bodek dmamem_fail: 2222306b72aSZbigniew Bodek err_dmat = bus_dma_tag_destroy(dmem->dmat); 2232306b72aSZbigniew Bodek dmem->base = NULL; 2242306b72aSZbigniew Bodek KASSERT(err_dmat == 0, 2252306b72aSZbigniew Bodek ("%s: Trying to destroy BUSY DMA tag", __func__)); 2262306b72aSZbigniew Bodek 2272306b72aSZbigniew Bodek return (err); 2283c0086b8SZbigniew Bodek } 2293c0086b8SZbigniew Bodek 2303c0086b8SZbigniew Bodek /* Free queue's descriptor memory */ 2312306b72aSZbigniew Bodek static void 2322306b72aSZbigniew Bodek nicvf_free_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem) 2333c0086b8SZbigniew Bodek { 234*21653635SJohn Baldwin int err __diagused; 2352306b72aSZbigniew Bodek 2362306b72aSZbigniew Bodek if ((dmem == NULL) || (dmem->base == NULL)) 2373c0086b8SZbigniew Bodek return; 2383c0086b8SZbigniew Bodek 2392306b72aSZbigniew Bodek /* Unload a map */ 2402306b72aSZbigniew Bodek bus_dmamap_sync(dmem->dmat, dmem->dmap, BUS_DMASYNC_POSTREAD); 2412306b72aSZbigniew Bodek bus_dmamap_unload(dmem->dmat, dmem->dmap); 2422306b72aSZbigniew Bodek /* Free DMA memory */ 2432306b72aSZbigniew Bodek bus_dmamem_free(dmem->dmat, dmem->base, dmem->dmap); 2442306b72aSZbigniew Bodek /* Destroy DMA tag */ 2452306b72aSZbigniew Bodek err = bus_dma_tag_destroy(dmem->dmat); 2462306b72aSZbigniew Bodek 2472306b72aSZbigniew Bodek KASSERT(err == 0, 2482306b72aSZbigniew Bodek ("%s: Trying to destroy BUSY DMA tag", __func__)); 2492306b72aSZbigniew Bodek 2502306b72aSZbigniew Bodek dmem->phys_base = 0; 2513c0086b8SZbigniew Bodek dmem->base = NULL; 2523c0086b8SZbigniew Bodek } 2533c0086b8SZbigniew Bodek 2542306b72aSZbigniew Bodek /* 2552306b72aSZbigniew Bodek * Allocate buffer for packet reception 2563c0086b8SZbigniew Bodek * HW returns memory address where packet is DMA'ed but not a pointer 2573c0086b8SZbigniew Bodek * into RBDR ring, so save buffer address at the start of fragment and 2583c0086b8SZbigniew Bodek * align the start address to a cache aligned address 2593c0086b8SZbigniew Bodek */ 2602306b72aSZbigniew Bodek static __inline int 2612306b72aSZbigniew Bodek nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr, 2622306b72aSZbigniew Bodek bus_dmamap_t dmap, int mflags, uint32_t buf_len, bus_addr_t *rbuf) 2633c0086b8SZbigniew Bodek { 2642306b72aSZbigniew Bodek struct mbuf *mbuf; 2653c0086b8SZbigniew Bodek struct rbuf_info *rinfo; 2662306b72aSZbigniew Bodek bus_dma_segment_t segs[1]; 2672306b72aSZbigniew Bodek int nsegs; 2682306b72aSZbigniew Bodek int err; 2693c0086b8SZbigniew Bodek 2702306b72aSZbigniew Bodek mbuf = m_getjcl(mflags, MT_DATA, M_PKTHDR, MCLBYTES); 2712306b72aSZbigniew Bodek if (mbuf == NULL) 2722306b72aSZbigniew Bodek return (ENOMEM); 2732306b72aSZbigniew Bodek 2742306b72aSZbigniew Bodek /* 2752306b72aSZbigniew Bodek * The length is equal to the actual length + one 128b line 2762306b72aSZbigniew Bodek * used as a room for rbuf_info structure. 2772306b72aSZbigniew Bodek */ 2782306b72aSZbigniew Bodek mbuf->m_len = mbuf->m_pkthdr.len = buf_len; 2792306b72aSZbigniew Bodek 2802306b72aSZbigniew Bodek err = bus_dmamap_load_mbuf_sg(rbdr->rbdr_buff_dmat, dmap, mbuf, segs, 2812306b72aSZbigniew Bodek &nsegs, BUS_DMA_NOWAIT); 2822306b72aSZbigniew Bodek if (err != 0) { 2832306b72aSZbigniew Bodek device_printf(nic->dev, 2842306b72aSZbigniew Bodek "Failed to map mbuf into DMA visible memory, err: %d\n", 2852306b72aSZbigniew Bodek err); 2862306b72aSZbigniew Bodek m_freem(mbuf); 2872306b72aSZbigniew Bodek bus_dmamap_destroy(rbdr->rbdr_buff_dmat, dmap); 2882306b72aSZbigniew Bodek return (err); 2893c0086b8SZbigniew Bodek } 2902306b72aSZbigniew Bodek if (nsegs != 1) 2912306b72aSZbigniew Bodek panic("Unexpected number of DMA segments for RB: %d", nsegs); 2922306b72aSZbigniew Bodek /* 2932306b72aSZbigniew Bodek * Now use the room for rbuf_info structure 2942306b72aSZbigniew Bodek * and adjust mbuf data and length. 2952306b72aSZbigniew Bodek */ 2962306b72aSZbigniew Bodek rinfo = (struct rbuf_info *)mbuf->m_data; 2972306b72aSZbigniew Bodek m_adj(mbuf, NICVF_RCV_BUF_ALIGN_BYTES); 2982306b72aSZbigniew Bodek 2992306b72aSZbigniew Bodek rinfo->dmat = rbdr->rbdr_buff_dmat; 3002306b72aSZbigniew Bodek rinfo->dmap = dmap; 3012306b72aSZbigniew Bodek rinfo->mbuf = mbuf; 3022306b72aSZbigniew Bodek 3032306b72aSZbigniew Bodek *rbuf = segs[0].ds_addr + NICVF_RCV_BUF_ALIGN_BYTES; 3042306b72aSZbigniew Bodek 3052306b72aSZbigniew Bodek return (0); 3063c0086b8SZbigniew Bodek } 3073c0086b8SZbigniew Bodek 3082306b72aSZbigniew Bodek /* Retrieve mbuf for received packet */ 3092306b72aSZbigniew Bodek static struct mbuf * 3102306b72aSZbigniew Bodek nicvf_rb_ptr_to_mbuf(struct nicvf *nic, bus_addr_t rb_ptr) 3113c0086b8SZbigniew Bodek { 3122306b72aSZbigniew Bodek struct mbuf *mbuf; 3133c0086b8SZbigniew Bodek struct rbuf_info *rinfo; 3143c0086b8SZbigniew Bodek 3153c0086b8SZbigniew Bodek /* Get buffer start address and alignment offset */ 3162306b72aSZbigniew Bodek rinfo = GET_RBUF_INFO(PHYS_TO_DMAP(rb_ptr)); 3173c0086b8SZbigniew Bodek 3182306b72aSZbigniew Bodek /* Now retrieve mbuf to give to stack */ 3192306b72aSZbigniew Bodek mbuf = rinfo->mbuf; 3202306b72aSZbigniew Bodek if (__predict_false(mbuf == NULL)) { 3212306b72aSZbigniew Bodek panic("%s: Received packet fragment with NULL mbuf", 3222306b72aSZbigniew Bodek device_get_nameunit(nic->dev)); 3233c0086b8SZbigniew Bodek } 3242306b72aSZbigniew Bodek /* 3252306b72aSZbigniew Bodek * Clear the mbuf in the descriptor to indicate 3262306b72aSZbigniew Bodek * that this slot is processed and free to use. 3272306b72aSZbigniew Bodek */ 3282306b72aSZbigniew Bodek rinfo->mbuf = NULL; 3293c0086b8SZbigniew Bodek 3302306b72aSZbigniew Bodek bus_dmamap_sync(rinfo->dmat, rinfo->dmap, BUS_DMASYNC_POSTREAD); 3312306b72aSZbigniew Bodek bus_dmamap_unload(rinfo->dmat, rinfo->dmap); 3323c0086b8SZbigniew Bodek 3332306b72aSZbigniew Bodek return (mbuf); 3343c0086b8SZbigniew Bodek } 3353c0086b8SZbigniew Bodek 3363c0086b8SZbigniew Bodek /* Allocate RBDR ring and populate receive buffers */ 3372306b72aSZbigniew Bodek static int 3382306b72aSZbigniew Bodek nicvf_init_rbdr(struct nicvf *nic, struct rbdr *rbdr, int ring_len, 3392306b72aSZbigniew Bodek int buf_size, int qidx) 3403c0086b8SZbigniew Bodek { 3412306b72aSZbigniew Bodek bus_dmamap_t dmap; 3422306b72aSZbigniew Bodek bus_addr_t rbuf; 3433c0086b8SZbigniew Bodek struct rbdr_entry_t *desc; 3442306b72aSZbigniew Bodek int idx; 3453c0086b8SZbigniew Bodek int err; 3463c0086b8SZbigniew Bodek 3472306b72aSZbigniew Bodek /* Allocate rbdr descriptors ring */ 3483c0086b8SZbigniew Bodek err = nicvf_alloc_q_desc_mem(nic, &rbdr->dmem, ring_len, 3492306b72aSZbigniew Bodek sizeof(struct rbdr_entry_t), NICVF_RCV_BUF_ALIGN_BYTES); 3502306b72aSZbigniew Bodek if (err != 0) { 3512306b72aSZbigniew Bodek device_printf(nic->dev, 3522306b72aSZbigniew Bodek "Failed to create RBDR descriptors ring\n"); 3532306b72aSZbigniew Bodek return (err); 3542306b72aSZbigniew Bodek } 3553c0086b8SZbigniew Bodek 3563c0086b8SZbigniew Bodek rbdr->desc = rbdr->dmem.base; 3572306b72aSZbigniew Bodek /* 3582306b72aSZbigniew Bodek * Buffer size has to be in multiples of 128 bytes. 3592306b72aSZbigniew Bodek * Make room for metadata of size of one line (128 bytes). 3602306b72aSZbigniew Bodek */ 3612306b72aSZbigniew Bodek rbdr->dma_size = buf_size - NICVF_RCV_BUF_ALIGN_BYTES; 3622306b72aSZbigniew Bodek rbdr->enable = TRUE; 3633c0086b8SZbigniew Bodek rbdr->thresh = RBDR_THRESH; 3642306b72aSZbigniew Bodek rbdr->nic = nic; 3652306b72aSZbigniew Bodek rbdr->idx = qidx; 3663c0086b8SZbigniew Bodek 3672306b72aSZbigniew Bodek /* 3682306b72aSZbigniew Bodek * Create DMA tag for Rx buffers. 3692306b72aSZbigniew Bodek * Each map created using this tag is intended to store Rx payload for 3702306b72aSZbigniew Bodek * one fragment and one header structure containing rbuf_info (thus 3712306b72aSZbigniew Bodek * additional 128 byte line since RB must be a multiple of 128 byte 3722306b72aSZbigniew Bodek * cache line). 3732306b72aSZbigniew Bodek */ 3742306b72aSZbigniew Bodek if (buf_size > MCLBYTES) { 3752306b72aSZbigniew Bodek device_printf(nic->dev, 3762306b72aSZbigniew Bodek "Buffer size to large for mbuf cluster\n"); 3772306b72aSZbigniew Bodek return (EINVAL); 3782306b72aSZbigniew Bodek } 3792306b72aSZbigniew Bodek err = bus_dma_tag_create( 3802306b72aSZbigniew Bodek bus_get_dma_tag(nic->dev), /* parent tag */ 3812306b72aSZbigniew Bodek NICVF_RCV_BUF_ALIGN_BYTES, /* alignment */ 3822306b72aSZbigniew Bodek 0, /* boundary */ 3832306b72aSZbigniew Bodek DMAP_MAX_PHYSADDR, /* lowaddr */ 3842306b72aSZbigniew Bodek DMAP_MIN_PHYSADDR, /* highaddr */ 3852306b72aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 3862306b72aSZbigniew Bodek roundup2(buf_size, MCLBYTES), /* maxsize */ 3872306b72aSZbigniew Bodek 1, /* nsegments */ 3882306b72aSZbigniew Bodek roundup2(buf_size, MCLBYTES), /* maxsegsize */ 3892306b72aSZbigniew Bodek 0, /* flags */ 3902306b72aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 3912306b72aSZbigniew Bodek &rbdr->rbdr_buff_dmat); /* dmat */ 3922306b72aSZbigniew Bodek 3932306b72aSZbigniew Bodek if (err != 0) { 3942306b72aSZbigniew Bodek device_printf(nic->dev, 3952306b72aSZbigniew Bodek "Failed to create busdma tag for RBDR buffers\n"); 3962306b72aSZbigniew Bodek return (err); 3972306b72aSZbigniew Bodek } 3982306b72aSZbigniew Bodek 3992306b72aSZbigniew Bodek rbdr->rbdr_buff_dmaps = malloc(sizeof(*rbdr->rbdr_buff_dmaps) * 4002306b72aSZbigniew Bodek ring_len, M_NICVF, (M_WAITOK | M_ZERO)); 4012306b72aSZbigniew Bodek 4023c0086b8SZbigniew Bodek for (idx = 0; idx < ring_len; idx++) { 4032306b72aSZbigniew Bodek err = bus_dmamap_create(rbdr->rbdr_buff_dmat, 0, &dmap); 4042306b72aSZbigniew Bodek if (err != 0) { 4052306b72aSZbigniew Bodek device_printf(nic->dev, 4062306b72aSZbigniew Bodek "Failed to create DMA map for RB\n"); 4072306b72aSZbigniew Bodek return (err); 4082306b72aSZbigniew Bodek } 4092306b72aSZbigniew Bodek rbdr->rbdr_buff_dmaps[idx] = dmap; 4102306b72aSZbigniew Bodek 4112306b72aSZbigniew Bodek err = nicvf_alloc_rcv_buffer(nic, rbdr, dmap, M_WAITOK, 4122306b72aSZbigniew Bodek DMA_BUFFER_LEN, &rbuf); 4132306b72aSZbigniew Bodek if (err != 0) 4142306b72aSZbigniew Bodek return (err); 4153c0086b8SZbigniew Bodek 4163c0086b8SZbigniew Bodek desc = GET_RBDR_DESC(rbdr, idx); 4172306b72aSZbigniew Bodek desc->buf_addr = (rbuf >> NICVF_RCV_BUF_ALIGN); 4183c0086b8SZbigniew Bodek } 4192306b72aSZbigniew Bodek 4202306b72aSZbigniew Bodek /* Allocate taskqueue */ 4212306b72aSZbigniew Bodek TASK_INIT(&rbdr->rbdr_task, 0, nicvf_rbdr_task, rbdr); 4222306b72aSZbigniew Bodek TASK_INIT(&rbdr->rbdr_task_nowait, 0, nicvf_rbdr_task_nowait, rbdr); 4232306b72aSZbigniew Bodek rbdr->rbdr_taskq = taskqueue_create_fast("nicvf_rbdr_taskq", M_WAITOK, 4242306b72aSZbigniew Bodek taskqueue_thread_enqueue, &rbdr->rbdr_taskq); 4252306b72aSZbigniew Bodek taskqueue_start_threads(&rbdr->rbdr_taskq, 1, PI_NET, "%s: rbdr_taskq", 4262306b72aSZbigniew Bodek device_get_nameunit(nic->dev)); 4272306b72aSZbigniew Bodek 4282306b72aSZbigniew Bodek return (0); 4293c0086b8SZbigniew Bodek } 4303c0086b8SZbigniew Bodek 4313c0086b8SZbigniew Bodek /* Free RBDR ring and its receive buffers */ 4322306b72aSZbigniew Bodek static void 4332306b72aSZbigniew Bodek nicvf_free_rbdr(struct nicvf *nic, struct rbdr *rbdr) 4343c0086b8SZbigniew Bodek { 4352306b72aSZbigniew Bodek struct mbuf *mbuf; 4362306b72aSZbigniew Bodek struct queue_set *qs; 4373c0086b8SZbigniew Bodek struct rbdr_entry_t *desc; 4383c0086b8SZbigniew Bodek struct rbuf_info *rinfo; 4392306b72aSZbigniew Bodek bus_addr_t buf_addr; 4402306b72aSZbigniew Bodek int head, tail, idx; 441*21653635SJohn Baldwin int err __diagused; 4423c0086b8SZbigniew Bodek 4432306b72aSZbigniew Bodek qs = nic->qs; 4442306b72aSZbigniew Bodek 4452306b72aSZbigniew Bodek if ((qs == NULL) || (rbdr == NULL)) 4463c0086b8SZbigniew Bodek return; 4473c0086b8SZbigniew Bodek 4482306b72aSZbigniew Bodek rbdr->enable = FALSE; 4492306b72aSZbigniew Bodek if (rbdr->rbdr_taskq != NULL) { 4502306b72aSZbigniew Bodek /* Remove tasks */ 4512306b72aSZbigniew Bodek while (taskqueue_cancel(rbdr->rbdr_taskq, 4522306b72aSZbigniew Bodek &rbdr->rbdr_task_nowait, NULL) != 0) { 4532306b72aSZbigniew Bodek /* Finish the nowait task first */ 4542306b72aSZbigniew Bodek taskqueue_drain(rbdr->rbdr_taskq, 4552306b72aSZbigniew Bodek &rbdr->rbdr_task_nowait); 4562306b72aSZbigniew Bodek } 4572306b72aSZbigniew Bodek taskqueue_free(rbdr->rbdr_taskq); 4582306b72aSZbigniew Bodek rbdr->rbdr_taskq = NULL; 4593c0086b8SZbigniew Bodek 4602306b72aSZbigniew Bodek while (taskqueue_cancel(taskqueue_thread, 4612306b72aSZbigniew Bodek &rbdr->rbdr_task, NULL) != 0) { 4622306b72aSZbigniew Bodek /* Now finish the sleepable task */ 4632306b72aSZbigniew Bodek taskqueue_drain(taskqueue_thread, &rbdr->rbdr_task); 4642306b72aSZbigniew Bodek } 4652306b72aSZbigniew Bodek } 4662306b72aSZbigniew Bodek 4672306b72aSZbigniew Bodek /* 4682306b72aSZbigniew Bodek * Free all of the memory under the RB descriptors. 4692306b72aSZbigniew Bodek * There are assumptions here: 4702306b72aSZbigniew Bodek * 1. Corresponding RBDR is disabled 4712306b72aSZbigniew Bodek * - it is safe to operate using head and tail indexes 4722306b72aSZbigniew Bodek * 2. All bffers that were received are properly freed by 4732306b72aSZbigniew Bodek * the receive handler 4742306b72aSZbigniew Bodek * - there is no need to unload DMA map and free MBUF for other 4752306b72aSZbigniew Bodek * descriptors than unused ones 4762306b72aSZbigniew Bodek */ 4772306b72aSZbigniew Bodek if (rbdr->rbdr_buff_dmat != NULL) { 4783c0086b8SZbigniew Bodek head = rbdr->head; 4793c0086b8SZbigniew Bodek tail = rbdr->tail; 4803c0086b8SZbigniew Bodek while (head != tail) { 4813c0086b8SZbigniew Bodek desc = GET_RBDR_DESC(rbdr, head); 4823c0086b8SZbigniew Bodek buf_addr = desc->buf_addr << NICVF_RCV_BUF_ALIGN; 4832306b72aSZbigniew Bodek rinfo = GET_RBUF_INFO(PHYS_TO_DMAP(buf_addr)); 4842306b72aSZbigniew Bodek bus_dmamap_unload(rbdr->rbdr_buff_dmat, rinfo->dmap); 4852306b72aSZbigniew Bodek mbuf = rinfo->mbuf; 4862306b72aSZbigniew Bodek /* This will destroy everything including rinfo! */ 4872306b72aSZbigniew Bodek m_freem(mbuf); 4883c0086b8SZbigniew Bodek head++; 4893c0086b8SZbigniew Bodek head &= (rbdr->dmem.q_len - 1); 4903c0086b8SZbigniew Bodek } 4912306b72aSZbigniew Bodek /* Free tail descriptor */ 4923c0086b8SZbigniew Bodek desc = GET_RBDR_DESC(rbdr, tail); 4933c0086b8SZbigniew Bodek buf_addr = desc->buf_addr << NICVF_RCV_BUF_ALIGN; 4942306b72aSZbigniew Bodek rinfo = GET_RBUF_INFO(PHYS_TO_DMAP(buf_addr)); 4952306b72aSZbigniew Bodek bus_dmamap_unload(rbdr->rbdr_buff_dmat, rinfo->dmap); 4962306b72aSZbigniew Bodek mbuf = rinfo->mbuf; 4972306b72aSZbigniew Bodek /* This will destroy everything including rinfo! */ 4982306b72aSZbigniew Bodek m_freem(mbuf); 4992306b72aSZbigniew Bodek 5002306b72aSZbigniew Bodek /* Destroy DMA maps */ 5012306b72aSZbigniew Bodek for (idx = 0; idx < qs->rbdr_len; idx++) { 5022306b72aSZbigniew Bodek if (rbdr->rbdr_buff_dmaps[idx] == NULL) 5032306b72aSZbigniew Bodek continue; 5042306b72aSZbigniew Bodek err = bus_dmamap_destroy(rbdr->rbdr_buff_dmat, 5052306b72aSZbigniew Bodek rbdr->rbdr_buff_dmaps[idx]); 5062306b72aSZbigniew Bodek KASSERT(err == 0, 5072306b72aSZbigniew Bodek ("%s: Could not destroy DMA map for RB, desc: %d", 5082306b72aSZbigniew Bodek __func__, idx)); 5092306b72aSZbigniew Bodek rbdr->rbdr_buff_dmaps[idx] = NULL; 5102306b72aSZbigniew Bodek } 5112306b72aSZbigniew Bodek 5122306b72aSZbigniew Bodek /* Now destroy the tag */ 5132306b72aSZbigniew Bodek err = bus_dma_tag_destroy(rbdr->rbdr_buff_dmat); 5142306b72aSZbigniew Bodek KASSERT(err == 0, 5152306b72aSZbigniew Bodek ("%s: Trying to destroy BUSY DMA tag", __func__)); 5162306b72aSZbigniew Bodek 5172306b72aSZbigniew Bodek rbdr->head = 0; 5182306b72aSZbigniew Bodek rbdr->tail = 0; 5192306b72aSZbigniew Bodek } 5203c0086b8SZbigniew Bodek 5213c0086b8SZbigniew Bodek /* Free RBDR ring */ 5223c0086b8SZbigniew Bodek nicvf_free_q_desc_mem(nic, &rbdr->dmem); 5233c0086b8SZbigniew Bodek } 5243c0086b8SZbigniew Bodek 5252306b72aSZbigniew Bodek /* 5262306b72aSZbigniew Bodek * Refill receive buffer descriptors with new buffers. 5273c0086b8SZbigniew Bodek */ 5282306b72aSZbigniew Bodek static int 5292306b72aSZbigniew Bodek nicvf_refill_rbdr(struct rbdr *rbdr, int mflags) 5303c0086b8SZbigniew Bodek { 5312306b72aSZbigniew Bodek struct nicvf *nic; 5322306b72aSZbigniew Bodek struct queue_set *qs; 5332306b72aSZbigniew Bodek int rbdr_idx; 5343c0086b8SZbigniew Bodek int tail, qcount; 5353c0086b8SZbigniew Bodek int refill_rb_cnt; 5363c0086b8SZbigniew Bodek struct rbdr_entry_t *desc; 5372306b72aSZbigniew Bodek bus_dmamap_t dmap; 5382306b72aSZbigniew Bodek bus_addr_t rbuf; 5392306b72aSZbigniew Bodek boolean_t rb_alloc_fail; 5402306b72aSZbigniew Bodek int new_rb; 5413c0086b8SZbigniew Bodek 5422306b72aSZbigniew Bodek rb_alloc_fail = TRUE; 5432306b72aSZbigniew Bodek new_rb = 0; 5442306b72aSZbigniew Bodek nic = rbdr->nic; 5452306b72aSZbigniew Bodek qs = nic->qs; 5462306b72aSZbigniew Bodek rbdr_idx = rbdr->idx; 5472306b72aSZbigniew Bodek 5483c0086b8SZbigniew Bodek /* Check if it's enabled */ 5493c0086b8SZbigniew Bodek if (!rbdr->enable) 5502306b72aSZbigniew Bodek return (0); 5513c0086b8SZbigniew Bodek 5523c0086b8SZbigniew Bodek /* Get no of desc's to be refilled */ 5533c0086b8SZbigniew Bodek qcount = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, rbdr_idx); 5543c0086b8SZbigniew Bodek qcount &= 0x7FFFF; 5553c0086b8SZbigniew Bodek /* Doorbell can be ringed with a max of ring size minus 1 */ 5562306b72aSZbigniew Bodek if (qcount >= (qs->rbdr_len - 1)) { 5572306b72aSZbigniew Bodek rb_alloc_fail = FALSE; 5582306b72aSZbigniew Bodek goto out; 5592306b72aSZbigniew Bodek } else 5603c0086b8SZbigniew Bodek refill_rb_cnt = qs->rbdr_len - qcount - 1; 5613c0086b8SZbigniew Bodek 5623c0086b8SZbigniew Bodek /* Start filling descs from tail */ 5633c0086b8SZbigniew Bodek tail = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, rbdr_idx) >> 3; 5643c0086b8SZbigniew Bodek while (refill_rb_cnt) { 5653c0086b8SZbigniew Bodek tail++; 5663c0086b8SZbigniew Bodek tail &= (rbdr->dmem.q_len - 1); 5673c0086b8SZbigniew Bodek 5682306b72aSZbigniew Bodek dmap = rbdr->rbdr_buff_dmaps[tail]; 5692306b72aSZbigniew Bodek if (nicvf_alloc_rcv_buffer(nic, rbdr, dmap, mflags, 5702306b72aSZbigniew Bodek DMA_BUFFER_LEN, &rbuf)) { 5712306b72aSZbigniew Bodek /* Something went wrong. Resign */ 5723c0086b8SZbigniew Bodek break; 5732306b72aSZbigniew Bodek } 5743c0086b8SZbigniew Bodek desc = GET_RBDR_DESC(rbdr, tail); 5752306b72aSZbigniew Bodek desc->buf_addr = (rbuf >> NICVF_RCV_BUF_ALIGN); 5763c0086b8SZbigniew Bodek refill_rb_cnt--; 5773c0086b8SZbigniew Bodek new_rb++; 5783c0086b8SZbigniew Bodek } 5793c0086b8SZbigniew Bodek 5803c0086b8SZbigniew Bodek /* make sure all memory stores are done before ringing doorbell */ 5812306b72aSZbigniew Bodek wmb(); 5823c0086b8SZbigniew Bodek 5833c0086b8SZbigniew Bodek /* Check if buffer allocation failed */ 5842306b72aSZbigniew Bodek if (refill_rb_cnt == 0) 5852306b72aSZbigniew Bodek rb_alloc_fail = FALSE; 5863c0086b8SZbigniew Bodek 5873c0086b8SZbigniew Bodek /* Notify HW */ 5883c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR, 5893c0086b8SZbigniew Bodek rbdr_idx, new_rb); 5902306b72aSZbigniew Bodek out: 5912306b72aSZbigniew Bodek if (!rb_alloc_fail) { 5922306b72aSZbigniew Bodek /* 5932306b72aSZbigniew Bodek * Re-enable RBDR interrupts only 5942306b72aSZbigniew Bodek * if buffer allocation is success. 5952306b72aSZbigniew Bodek */ 5963c0086b8SZbigniew Bodek nicvf_enable_intr(nic, NICVF_INTR_RBDR, rbdr_idx); 5973c0086b8SZbigniew Bodek 5982306b72aSZbigniew Bodek return (0); 5993c0086b8SZbigniew Bodek } 6003c0086b8SZbigniew Bodek 6012306b72aSZbigniew Bodek return (ENOMEM); 6022306b72aSZbigniew Bodek } 6032306b72aSZbigniew Bodek 6042306b72aSZbigniew Bodek /* Refill RBs even if sleep is needed to reclaim memory */ 6052306b72aSZbigniew Bodek static void 6062306b72aSZbigniew Bodek nicvf_rbdr_task(void *arg, int pending) 6073c0086b8SZbigniew Bodek { 6082306b72aSZbigniew Bodek struct rbdr *rbdr; 6092306b72aSZbigniew Bodek int err; 6103c0086b8SZbigniew Bodek 6112306b72aSZbigniew Bodek rbdr = (struct rbdr *)arg; 6122306b72aSZbigniew Bodek 6132306b72aSZbigniew Bodek err = nicvf_refill_rbdr(rbdr, M_WAITOK); 6142306b72aSZbigniew Bodek if (__predict_false(err != 0)) { 6152306b72aSZbigniew Bodek panic("%s: Failed to refill RBs even when sleep enabled", 6162306b72aSZbigniew Bodek __func__); 6172306b72aSZbigniew Bodek } 6183c0086b8SZbigniew Bodek } 6193c0086b8SZbigniew Bodek 6202306b72aSZbigniew Bodek /* Refill RBs as soon as possible without waiting */ 6212306b72aSZbigniew Bodek static void 6222306b72aSZbigniew Bodek nicvf_rbdr_task_nowait(void *arg, int pending) 6233c0086b8SZbigniew Bodek { 6242306b72aSZbigniew Bodek struct rbdr *rbdr; 6252306b72aSZbigniew Bodek int err; 6263c0086b8SZbigniew Bodek 6272306b72aSZbigniew Bodek rbdr = (struct rbdr *)arg; 6282306b72aSZbigniew Bodek 6292306b72aSZbigniew Bodek err = nicvf_refill_rbdr(rbdr, M_NOWAIT); 6302306b72aSZbigniew Bodek if (err != 0) { 6312306b72aSZbigniew Bodek /* 6322306b72aSZbigniew Bodek * Schedule another, sleepable kernel thread 6332306b72aSZbigniew Bodek * that will for sure refill the buffers. 6342306b72aSZbigniew Bodek */ 6352306b72aSZbigniew Bodek taskqueue_enqueue(taskqueue_thread, &rbdr->rbdr_task); 6363c0086b8SZbigniew Bodek } 6373c0086b8SZbigniew Bodek } 6383c0086b8SZbigniew Bodek 6392306b72aSZbigniew Bodek static int 6402306b72aSZbigniew Bodek nicvf_rcv_pkt_handler(struct nicvf *nic, struct cmp_queue *cq, 6412306b72aSZbigniew Bodek struct cqe_rx_t *cqe_rx, int cqe_type) 6422306b72aSZbigniew Bodek { 6432306b72aSZbigniew Bodek struct mbuf *mbuf; 644053f3d0eSZbigniew Bodek struct rcv_queue *rq; 6452306b72aSZbigniew Bodek int rq_idx; 6462306b72aSZbigniew Bodek int err = 0; 6472306b72aSZbigniew Bodek 6482306b72aSZbigniew Bodek rq_idx = cqe_rx->rq_idx; 649053f3d0eSZbigniew Bodek rq = &nic->qs->rq[rq_idx]; 6502306b72aSZbigniew Bodek 6512306b72aSZbigniew Bodek /* Check for errors */ 6522306b72aSZbigniew Bodek err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx); 6532306b72aSZbigniew Bodek if (err && !cqe_rx->rb_cnt) 6542306b72aSZbigniew Bodek return (0); 6552306b72aSZbigniew Bodek 6562306b72aSZbigniew Bodek mbuf = nicvf_get_rcv_mbuf(nic, cqe_rx); 6572306b72aSZbigniew Bodek if (mbuf == NULL) { 6582306b72aSZbigniew Bodek dprintf(nic->dev, "Packet not received\n"); 6592306b72aSZbigniew Bodek return (0); 6602306b72aSZbigniew Bodek } 6612306b72aSZbigniew Bodek 6622306b72aSZbigniew Bodek /* If error packet */ 6632306b72aSZbigniew Bodek if (err != 0) { 6642306b72aSZbigniew Bodek m_freem(mbuf); 6652306b72aSZbigniew Bodek return (0); 6662306b72aSZbigniew Bodek } 6672306b72aSZbigniew Bodek 668053f3d0eSZbigniew Bodek if (rq->lro_enabled && 669053f3d0eSZbigniew Bodek ((cqe_rx->l3_type == L3TYPE_IPV4) && (cqe_rx->l4_type == L4TYPE_TCP)) && 670053f3d0eSZbigniew Bodek (mbuf->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == 671053f3d0eSZbigniew Bodek (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { 672053f3d0eSZbigniew Bodek /* 673053f3d0eSZbigniew Bodek * At this point it is known that there are no errors in the 674053f3d0eSZbigniew Bodek * packet. Attempt to LRO enqueue. Send to stack if no resources 675053f3d0eSZbigniew Bodek * or enqueue error. 676053f3d0eSZbigniew Bodek */ 677053f3d0eSZbigniew Bodek if ((rq->lro.lro_cnt != 0) && 678053f3d0eSZbigniew Bodek (tcp_lro_rx(&rq->lro, mbuf, 0) == 0)) 679053f3d0eSZbigniew Bodek return (0); 680053f3d0eSZbigniew Bodek } 6812306b72aSZbigniew Bodek /* 6822306b72aSZbigniew Bodek * Push this packet to the stack later to avoid 6832306b72aSZbigniew Bodek * unlocking completion task in the middle of work. 6842306b72aSZbigniew Bodek */ 6852306b72aSZbigniew Bodek err = buf_ring_enqueue(cq->rx_br, mbuf); 6862306b72aSZbigniew Bodek if (err != 0) { 6872306b72aSZbigniew Bodek /* 6882306b72aSZbigniew Bodek * Failed to enqueue this mbuf. 6892306b72aSZbigniew Bodek * We don't drop it, just schedule another task. 6902306b72aSZbigniew Bodek */ 6912306b72aSZbigniew Bodek return (err); 6922306b72aSZbigniew Bodek } 6932306b72aSZbigniew Bodek 6942306b72aSZbigniew Bodek return (0); 6952306b72aSZbigniew Bodek } 6962306b72aSZbigniew Bodek 697f6cdb4ceSZbigniew Bodek static void 6982306b72aSZbigniew Bodek nicvf_snd_pkt_handler(struct nicvf *nic, struct cmp_queue *cq, 6992306b72aSZbigniew Bodek struct cqe_send_t *cqe_tx, int cqe_type) 7002306b72aSZbigniew Bodek { 7012306b72aSZbigniew Bodek bus_dmamap_t dmap; 7022306b72aSZbigniew Bodek struct mbuf *mbuf; 7032306b72aSZbigniew Bodek struct snd_queue *sq; 7042306b72aSZbigniew Bodek struct sq_hdr_subdesc *hdr; 7052306b72aSZbigniew Bodek 7062306b72aSZbigniew Bodek mbuf = NULL; 7072306b72aSZbigniew Bodek sq = &nic->qs->sq[cqe_tx->sq_idx]; 7082306b72aSZbigniew Bodek 7092306b72aSZbigniew Bodek hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr); 710f6cdb4ceSZbigniew Bodek if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) 711f6cdb4ceSZbigniew Bodek return; 7122306b72aSZbigniew Bodek 7132306b72aSZbigniew Bodek dprintf(nic->dev, 7142306b72aSZbigniew Bodek "%s Qset #%d SQ #%d SQ ptr #%d subdesc count %d\n", 7152306b72aSZbigniew Bodek __func__, cqe_tx->sq_qs, cqe_tx->sq_idx, 7162306b72aSZbigniew Bodek cqe_tx->sqe_ptr, hdr->subdesc_cnt); 7172306b72aSZbigniew Bodek 7182306b72aSZbigniew Bodek dmap = (bus_dmamap_t)sq->snd_buff[cqe_tx->sqe_ptr].dmap; 7192306b72aSZbigniew Bodek bus_dmamap_unload(sq->snd_buff_dmat, dmap); 7202306b72aSZbigniew Bodek 7212306b72aSZbigniew Bodek mbuf = (struct mbuf *)sq->snd_buff[cqe_tx->sqe_ptr].mbuf; 7222306b72aSZbigniew Bodek if (mbuf != NULL) { 7232306b72aSZbigniew Bodek m_freem(mbuf); 7242306b72aSZbigniew Bodek sq->snd_buff[cqe_tx->sqe_ptr].mbuf = NULL; 7256cac5eb7SZbigniew Bodek nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1); 7262306b72aSZbigniew Bodek } 7272306b72aSZbigniew Bodek 7282306b72aSZbigniew Bodek nicvf_check_cqe_tx_errs(nic, cq, cqe_tx); 7292306b72aSZbigniew Bodek } 7302306b72aSZbigniew Bodek 7312306b72aSZbigniew Bodek static int 7322306b72aSZbigniew Bodek nicvf_cq_intr_handler(struct nicvf *nic, uint8_t cq_idx) 7332306b72aSZbigniew Bodek { 7342306b72aSZbigniew Bodek struct mbuf *mbuf; 7352306b72aSZbigniew Bodek struct ifnet *ifp; 7362306b72aSZbigniew Bodek int processed_cqe, work_done = 0, tx_done = 0; 7372306b72aSZbigniew Bodek int cqe_count, cqe_head; 7382306b72aSZbigniew Bodek struct queue_set *qs = nic->qs; 7392306b72aSZbigniew Bodek struct cmp_queue *cq = &qs->cq[cq_idx]; 7407c617aceSZbigniew Bodek struct snd_queue *sq = &qs->sq[cq_idx]; 741053f3d0eSZbigniew Bodek struct rcv_queue *rq; 7422306b72aSZbigniew Bodek struct cqe_rx_t *cq_desc; 743053f3d0eSZbigniew Bodek struct lro_ctrl *lro; 744053f3d0eSZbigniew Bodek int rq_idx; 7452306b72aSZbigniew Bodek int cmp_err; 7462306b72aSZbigniew Bodek 7472306b72aSZbigniew Bodek NICVF_CMP_LOCK(cq); 7482306b72aSZbigniew Bodek cmp_err = 0; 7492306b72aSZbigniew Bodek processed_cqe = 0; 7502306b72aSZbigniew Bodek /* Get no of valid CQ entries to process */ 7512306b72aSZbigniew Bodek cqe_count = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, cq_idx); 7522306b72aSZbigniew Bodek cqe_count &= CQ_CQE_COUNT; 7532306b72aSZbigniew Bodek if (cqe_count == 0) 7542306b72aSZbigniew Bodek goto out; 7552306b72aSZbigniew Bodek 7562306b72aSZbigniew Bodek /* Get head of the valid CQ entries */ 7572306b72aSZbigniew Bodek cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_idx) >> 9; 7582306b72aSZbigniew Bodek cqe_head &= 0xFFFF; 7592306b72aSZbigniew Bodek 7602306b72aSZbigniew Bodek dprintf(nic->dev, "%s CQ%d cqe_count %d cqe_head %d\n", 7612306b72aSZbigniew Bodek __func__, cq_idx, cqe_count, cqe_head); 7622306b72aSZbigniew Bodek while (processed_cqe < cqe_count) { 7632306b72aSZbigniew Bodek /* Get the CQ descriptor */ 7642306b72aSZbigniew Bodek cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head); 7652306b72aSZbigniew Bodek cqe_head++; 7662306b72aSZbigniew Bodek cqe_head &= (cq->dmem.q_len - 1); 76744dd2693SZbigniew Bodek /* Prefetch next CQ descriptor */ 76844dd2693SZbigniew Bodek __builtin_prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head)); 7692306b72aSZbigniew Bodek 7702306b72aSZbigniew Bodek dprintf(nic->dev, "CQ%d cq_desc->cqe_type %d\n", cq_idx, 7712306b72aSZbigniew Bodek cq_desc->cqe_type); 7722306b72aSZbigniew Bodek switch (cq_desc->cqe_type) { 7732306b72aSZbigniew Bodek case CQE_TYPE_RX: 7742306b72aSZbigniew Bodek cmp_err = nicvf_rcv_pkt_handler(nic, cq, cq_desc, 7752306b72aSZbigniew Bodek CQE_TYPE_RX); 7762306b72aSZbigniew Bodek if (__predict_false(cmp_err != 0)) { 7772306b72aSZbigniew Bodek /* 7782306b72aSZbigniew Bodek * Ups. Cannot finish now. 7792306b72aSZbigniew Bodek * Let's try again later. 7802306b72aSZbigniew Bodek */ 7812306b72aSZbigniew Bodek goto done; 7822306b72aSZbigniew Bodek } 7832306b72aSZbigniew Bodek work_done++; 7842306b72aSZbigniew Bodek break; 7852306b72aSZbigniew Bodek case CQE_TYPE_SEND: 786f6cdb4ceSZbigniew Bodek nicvf_snd_pkt_handler(nic, cq, (void *)cq_desc, 787f6cdb4ceSZbigniew Bodek CQE_TYPE_SEND); 7882306b72aSZbigniew Bodek tx_done++; 7892306b72aSZbigniew Bodek break; 7902306b72aSZbigniew Bodek case CQE_TYPE_INVALID: 7912306b72aSZbigniew Bodek case CQE_TYPE_RX_SPLIT: 7922306b72aSZbigniew Bodek case CQE_TYPE_RX_TCP: 7932306b72aSZbigniew Bodek case CQE_TYPE_SEND_PTP: 7942306b72aSZbigniew Bodek /* Ignore for now */ 7952306b72aSZbigniew Bodek break; 7962306b72aSZbigniew Bodek } 7972306b72aSZbigniew Bodek processed_cqe++; 7982306b72aSZbigniew Bodek } 7992306b72aSZbigniew Bodek done: 8002306b72aSZbigniew Bodek dprintf(nic->dev, 8012306b72aSZbigniew Bodek "%s CQ%d processed_cqe %d work_done %d\n", 8022306b72aSZbigniew Bodek __func__, cq_idx, processed_cqe, work_done); 8032306b72aSZbigniew Bodek 8042306b72aSZbigniew Bodek /* Ring doorbell to inform H/W to reuse processed CQEs */ 8052306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR, cq_idx, processed_cqe); 8062306b72aSZbigniew Bodek 8072306b72aSZbigniew Bodek if ((tx_done > 0) && 8082306b72aSZbigniew Bodek ((if_getdrvflags(nic->ifp) & IFF_DRV_RUNNING) != 0)) { 8092306b72aSZbigniew Bodek /* Reenable TXQ if its stopped earlier due to SQ full */ 8102306b72aSZbigniew Bodek if_setdrvflagbits(nic->ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 8117c617aceSZbigniew Bodek taskqueue_enqueue(sq->snd_taskq, &sq->snd_task); 8122306b72aSZbigniew Bodek } 8132306b72aSZbigniew Bodek out: 814053f3d0eSZbigniew Bodek /* 815053f3d0eSZbigniew Bodek * Flush any outstanding LRO work 816053f3d0eSZbigniew Bodek */ 817053f3d0eSZbigniew Bodek rq_idx = cq_idx; 818053f3d0eSZbigniew Bodek rq = &nic->qs->rq[rq_idx]; 819053f3d0eSZbigniew Bodek lro = &rq->lro; 8206dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 821053f3d0eSZbigniew Bodek 8222306b72aSZbigniew Bodek NICVF_CMP_UNLOCK(cq); 8232306b72aSZbigniew Bodek 8242306b72aSZbigniew Bodek ifp = nic->ifp; 8252306b72aSZbigniew Bodek /* Push received MBUFs to the stack */ 8262306b72aSZbigniew Bodek while (!buf_ring_empty(cq->rx_br)) { 8272306b72aSZbigniew Bodek mbuf = buf_ring_dequeue_mc(cq->rx_br); 8282306b72aSZbigniew Bodek if (__predict_true(mbuf != NULL)) 8292306b72aSZbigniew Bodek (*ifp->if_input)(ifp, mbuf); 8302306b72aSZbigniew Bodek } 8312306b72aSZbigniew Bodek 8322306b72aSZbigniew Bodek return (cmp_err); 8332306b72aSZbigniew Bodek } 8342306b72aSZbigniew Bodek 8352306b72aSZbigniew Bodek /* 8362306b72aSZbigniew Bodek * Qset error interrupt handler 8372306b72aSZbigniew Bodek * 8382306b72aSZbigniew Bodek * As of now only CQ errors are handled 8392306b72aSZbigniew Bodek */ 8402306b72aSZbigniew Bodek static void 8412306b72aSZbigniew Bodek nicvf_qs_err_task(void *arg, int pending) 8422306b72aSZbigniew Bodek { 8432306b72aSZbigniew Bodek struct nicvf *nic; 8442306b72aSZbigniew Bodek struct queue_set *qs; 8452306b72aSZbigniew Bodek int qidx; 8462306b72aSZbigniew Bodek uint64_t status; 8472306b72aSZbigniew Bodek boolean_t enable = TRUE; 8482306b72aSZbigniew Bodek 8492306b72aSZbigniew Bodek nic = (struct nicvf *)arg; 8502306b72aSZbigniew Bodek qs = nic->qs; 8512306b72aSZbigniew Bodek 8522306b72aSZbigniew Bodek /* Deactivate network interface */ 8532306b72aSZbigniew Bodek if_setdrvflagbits(nic->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 8542306b72aSZbigniew Bodek 8552306b72aSZbigniew Bodek /* Check if it is CQ err */ 8562306b72aSZbigniew Bodek for (qidx = 0; qidx < qs->cq_cnt; qidx++) { 8572306b72aSZbigniew Bodek status = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, 8582306b72aSZbigniew Bodek qidx); 8592306b72aSZbigniew Bodek if ((status & CQ_ERR_MASK) == 0) 8602306b72aSZbigniew Bodek continue; 8612306b72aSZbigniew Bodek /* Process already queued CQEs and reconfig CQ */ 8622306b72aSZbigniew Bodek nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx); 8632306b72aSZbigniew Bodek nicvf_sq_disable(nic, qidx); 8642306b72aSZbigniew Bodek (void)nicvf_cq_intr_handler(nic, qidx); 8652306b72aSZbigniew Bodek nicvf_cmp_queue_config(nic, qs, qidx, enable); 8662306b72aSZbigniew Bodek nicvf_sq_free_used_descs(nic, &qs->sq[qidx], qidx); 8672306b72aSZbigniew Bodek nicvf_sq_enable(nic, &qs->sq[qidx], qidx); 8682306b72aSZbigniew Bodek nicvf_enable_intr(nic, NICVF_INTR_CQ, qidx); 8692306b72aSZbigniew Bodek } 8702306b72aSZbigniew Bodek 8712306b72aSZbigniew Bodek if_setdrvflagbits(nic->ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 8722306b72aSZbigniew Bodek /* Re-enable Qset error interrupt */ 8732306b72aSZbigniew Bodek nicvf_enable_intr(nic, NICVF_INTR_QS_ERR, 0); 8742306b72aSZbigniew Bodek } 8752306b72aSZbigniew Bodek 8762306b72aSZbigniew Bodek static void 8772306b72aSZbigniew Bodek nicvf_cmp_task(void *arg, int pending) 8782306b72aSZbigniew Bodek { 8792306b72aSZbigniew Bodek struct cmp_queue *cq; 8802306b72aSZbigniew Bodek struct nicvf *nic; 8812306b72aSZbigniew Bodek int cmp_err; 8822306b72aSZbigniew Bodek 8832306b72aSZbigniew Bodek cq = (struct cmp_queue *)arg; 8842306b72aSZbigniew Bodek nic = cq->nic; 8852306b72aSZbigniew Bodek 8862306b72aSZbigniew Bodek /* Handle CQ descriptors */ 8872306b72aSZbigniew Bodek cmp_err = nicvf_cq_intr_handler(nic, cq->idx); 8882306b72aSZbigniew Bodek if (__predict_false(cmp_err != 0)) { 8892306b72aSZbigniew Bodek /* 8902306b72aSZbigniew Bodek * Schedule another thread here since we did not 8912306b72aSZbigniew Bodek * process the entire CQ due to Tx or Rx CQ parse error. 8922306b72aSZbigniew Bodek */ 8932306b72aSZbigniew Bodek taskqueue_enqueue(cq->cmp_taskq, &cq->cmp_task); 8942306b72aSZbigniew Bodek } 8952306b72aSZbigniew Bodek 8960196c2e8SZbigniew Bodek nicvf_clear_intr(nic, NICVF_INTR_CQ, cq->idx); 8972306b72aSZbigniew Bodek /* Reenable interrupt (previously disabled in nicvf_intr_handler() */ 8982306b72aSZbigniew Bodek nicvf_enable_intr(nic, NICVF_INTR_CQ, cq->idx); 8992306b72aSZbigniew Bodek 9002306b72aSZbigniew Bodek } 9012306b72aSZbigniew Bodek 9023c0086b8SZbigniew Bodek /* Initialize completion queue */ 9032306b72aSZbigniew Bodek static int 9042306b72aSZbigniew Bodek nicvf_init_cmp_queue(struct nicvf *nic, struct cmp_queue *cq, int q_len, 9052306b72aSZbigniew Bodek int qidx) 9063c0086b8SZbigniew Bodek { 9073c0086b8SZbigniew Bodek int err; 9083c0086b8SZbigniew Bodek 9092306b72aSZbigniew Bodek /* Initizalize lock */ 9102306b72aSZbigniew Bodek snprintf(cq->mtx_name, sizeof(cq->mtx_name), "%s: CQ(%d) lock", 9112306b72aSZbigniew Bodek device_get_nameunit(nic->dev), qidx); 9122306b72aSZbigniew Bodek mtx_init(&cq->mtx, cq->mtx_name, NULL, MTX_DEF); 9132306b72aSZbigniew Bodek 9143c0086b8SZbigniew Bodek err = nicvf_alloc_q_desc_mem(nic, &cq->dmem, q_len, CMP_QUEUE_DESC_SIZE, 9153c0086b8SZbigniew Bodek NICVF_CQ_BASE_ALIGN_BYTES); 9162306b72aSZbigniew Bodek 9172306b72aSZbigniew Bodek if (err != 0) { 9182306b72aSZbigniew Bodek device_printf(nic->dev, 9192306b72aSZbigniew Bodek "Could not allocate DMA memory for CQ\n"); 9202306b72aSZbigniew Bodek return (err); 9212306b72aSZbigniew Bodek } 9223c0086b8SZbigniew Bodek 9233c0086b8SZbigniew Bodek cq->desc = cq->dmem.base; 9243bdcfeadSZbigniew Bodek cq->thresh = pass1_silicon(nic->dev) ? 0 : CMP_QUEUE_CQE_THRESH; 9252306b72aSZbigniew Bodek cq->nic = nic; 9262306b72aSZbigniew Bodek cq->idx = qidx; 9273c0086b8SZbigniew Bodek nic->cq_coalesce_usecs = (CMP_QUEUE_TIMER_THRESH * 0.05) - 1; 9283c0086b8SZbigniew Bodek 9292306b72aSZbigniew Bodek cq->rx_br = buf_ring_alloc(CMP_QUEUE_LEN * 8, M_DEVBUF, M_WAITOK, 9302306b72aSZbigniew Bodek &cq->mtx); 9312306b72aSZbigniew Bodek 9322306b72aSZbigniew Bodek /* Allocate taskqueue */ 9336c3e93cbSGleb Smirnoff NET_TASK_INIT(&cq->cmp_task, 0, nicvf_cmp_task, cq); 9342306b72aSZbigniew Bodek cq->cmp_taskq = taskqueue_create_fast("nicvf_cmp_taskq", M_WAITOK, 9352306b72aSZbigniew Bodek taskqueue_thread_enqueue, &cq->cmp_taskq); 9362306b72aSZbigniew Bodek taskqueue_start_threads(&cq->cmp_taskq, 1, PI_NET, "%s: cmp_taskq(%d)", 9372306b72aSZbigniew Bodek device_get_nameunit(nic->dev), qidx); 9382306b72aSZbigniew Bodek 9392306b72aSZbigniew Bodek return (0); 9403c0086b8SZbigniew Bodek } 9413c0086b8SZbigniew Bodek 9422306b72aSZbigniew Bodek static void 9432306b72aSZbigniew Bodek nicvf_free_cmp_queue(struct nicvf *nic, struct cmp_queue *cq) 9443c0086b8SZbigniew Bodek { 9453c0086b8SZbigniew Bodek 9462306b72aSZbigniew Bodek if (cq == NULL) 9472306b72aSZbigniew Bodek return; 9482306b72aSZbigniew Bodek /* 9492306b72aSZbigniew Bodek * The completion queue itself should be disabled by now 9502306b72aSZbigniew Bodek * (ref. nicvf_snd_queue_config()). 9512306b72aSZbigniew Bodek * Ensure that it is safe to disable it or panic. 9522306b72aSZbigniew Bodek */ 9532306b72aSZbigniew Bodek if (cq->enable) 9542306b72aSZbigniew Bodek panic("%s: Trying to free working CQ(%d)", __func__, cq->idx); 9552306b72aSZbigniew Bodek 9562306b72aSZbigniew Bodek if (cq->cmp_taskq != NULL) { 9572306b72aSZbigniew Bodek /* Remove task */ 9582306b72aSZbigniew Bodek while (taskqueue_cancel(cq->cmp_taskq, &cq->cmp_task, NULL) != 0) 9592306b72aSZbigniew Bodek taskqueue_drain(cq->cmp_taskq, &cq->cmp_task); 9602306b72aSZbigniew Bodek 9612306b72aSZbigniew Bodek taskqueue_free(cq->cmp_taskq); 9622306b72aSZbigniew Bodek cq->cmp_taskq = NULL; 9632306b72aSZbigniew Bodek } 9642306b72aSZbigniew Bodek /* 9652306b72aSZbigniew Bodek * Completion interrupt will possibly enable interrupts again 9662306b72aSZbigniew Bodek * so disable interrupting now after we finished processing 9672306b72aSZbigniew Bodek * completion task. It is safe to do so since the corresponding CQ 9682306b72aSZbigniew Bodek * was already disabled. 9692306b72aSZbigniew Bodek */ 9702306b72aSZbigniew Bodek nicvf_disable_intr(nic, NICVF_INTR_CQ, cq->idx); 9712306b72aSZbigniew Bodek nicvf_clear_intr(nic, NICVF_INTR_CQ, cq->idx); 9722306b72aSZbigniew Bodek 9732306b72aSZbigniew Bodek NICVF_CMP_LOCK(cq); 9743c0086b8SZbigniew Bodek nicvf_free_q_desc_mem(nic, &cq->dmem); 9752306b72aSZbigniew Bodek drbr_free(cq->rx_br, M_DEVBUF); 9762306b72aSZbigniew Bodek NICVF_CMP_UNLOCK(cq); 9772306b72aSZbigniew Bodek mtx_destroy(&cq->mtx); 9782306b72aSZbigniew Bodek memset(cq->mtx_name, 0, sizeof(cq->mtx_name)); 9792306b72aSZbigniew Bodek } 9802306b72aSZbigniew Bodek 9817c617aceSZbigniew Bodek int 9827c617aceSZbigniew Bodek nicvf_xmit_locked(struct snd_queue *sq) 9837c617aceSZbigniew Bodek { 9847c617aceSZbigniew Bodek struct nicvf *nic; 9857c617aceSZbigniew Bodek struct ifnet *ifp; 9867c617aceSZbigniew Bodek struct mbuf *next; 9877c617aceSZbigniew Bodek int err; 9887c617aceSZbigniew Bodek 9897c617aceSZbigniew Bodek NICVF_TX_LOCK_ASSERT(sq); 9907c617aceSZbigniew Bodek 9917c617aceSZbigniew Bodek nic = sq->nic; 9927c617aceSZbigniew Bodek ifp = nic->ifp; 9937c617aceSZbigniew Bodek err = 0; 9947c617aceSZbigniew Bodek 9957c617aceSZbigniew Bodek while ((next = drbr_peek(ifp, sq->br)) != NULL) { 9962dc620acSEd Maste /* Send a copy of the frame to the BPF listener */ 9972dc620acSEd Maste ETHER_BPF_MTAP(ifp, next); 9982dc620acSEd Maste 9997c617aceSZbigniew Bodek err = nicvf_tx_mbuf_locked(sq, &next); 10007c617aceSZbigniew Bodek if (err != 0) { 10017c617aceSZbigniew Bodek if (next == NULL) 10027c617aceSZbigniew Bodek drbr_advance(ifp, sq->br); 10037c617aceSZbigniew Bodek else 10047c617aceSZbigniew Bodek drbr_putback(ifp, sq->br, next); 10057c617aceSZbigniew Bodek 10067c617aceSZbigniew Bodek break; 10077c617aceSZbigniew Bodek } 10087c617aceSZbigniew Bodek drbr_advance(ifp, sq->br); 10097c617aceSZbigniew Bodek } 10107c617aceSZbigniew Bodek return (err); 10117c617aceSZbigniew Bodek } 10127c617aceSZbigniew Bodek 10132306b72aSZbigniew Bodek static void 10142306b72aSZbigniew Bodek nicvf_snd_task(void *arg, int pending) 10152306b72aSZbigniew Bodek { 10162306b72aSZbigniew Bodek struct snd_queue *sq = (struct snd_queue *)arg; 10177c617aceSZbigniew Bodek struct nicvf *nic; 10187c617aceSZbigniew Bodek struct ifnet *ifp; 10197c617aceSZbigniew Bodek int err; 10207c617aceSZbigniew Bodek 10217c617aceSZbigniew Bodek nic = sq->nic; 10227c617aceSZbigniew Bodek ifp = nic->ifp; 10237c617aceSZbigniew Bodek 10247c617aceSZbigniew Bodek /* 10257c617aceSZbigniew Bodek * Skip sending anything if the driver is not running, 10267c617aceSZbigniew Bodek * SQ full or link is down. 10277c617aceSZbigniew Bodek */ 10287c617aceSZbigniew Bodek if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 10297c617aceSZbigniew Bodek IFF_DRV_RUNNING) || !nic->link_up) 10307c617aceSZbigniew Bodek return; 10312306b72aSZbigniew Bodek 10322306b72aSZbigniew Bodek NICVF_TX_LOCK(sq); 10337c617aceSZbigniew Bodek err = nicvf_xmit_locked(sq); 10342306b72aSZbigniew Bodek NICVF_TX_UNLOCK(sq); 10357c617aceSZbigniew Bodek /* Try again */ 10367c617aceSZbigniew Bodek if (err != 0) 10377c617aceSZbigniew Bodek taskqueue_enqueue(sq->snd_taskq, &sq->snd_task); 10383c0086b8SZbigniew Bodek } 10393c0086b8SZbigniew Bodek 10403c0086b8SZbigniew Bodek /* Initialize transmit queue */ 10412306b72aSZbigniew Bodek static int 10422306b72aSZbigniew Bodek nicvf_init_snd_queue(struct nicvf *nic, struct snd_queue *sq, int q_len, 10432306b72aSZbigniew Bodek int qidx) 10443c0086b8SZbigniew Bodek { 10452306b72aSZbigniew Bodek size_t i; 10463c0086b8SZbigniew Bodek int err; 10473c0086b8SZbigniew Bodek 10482306b72aSZbigniew Bodek /* Initizalize TX lock for this queue */ 10492306b72aSZbigniew Bodek snprintf(sq->mtx_name, sizeof(sq->mtx_name), "%s: SQ(%d) lock", 10502306b72aSZbigniew Bodek device_get_nameunit(nic->dev), qidx); 10512306b72aSZbigniew Bodek mtx_init(&sq->mtx, sq->mtx_name, NULL, MTX_DEF); 10522306b72aSZbigniew Bodek 10532306b72aSZbigniew Bodek NICVF_TX_LOCK(sq); 10542306b72aSZbigniew Bodek /* Allocate buffer ring */ 10552306b72aSZbigniew Bodek sq->br = buf_ring_alloc(q_len / MIN_SQ_DESC_PER_PKT_XMIT, M_DEVBUF, 10562306b72aSZbigniew Bodek M_NOWAIT, &sq->mtx); 10572306b72aSZbigniew Bodek if (sq->br == NULL) { 10582306b72aSZbigniew Bodek device_printf(nic->dev, 10592306b72aSZbigniew Bodek "ERROR: Could not set up buf ring for SQ(%d)\n", qidx); 10602306b72aSZbigniew Bodek err = ENOMEM; 10612306b72aSZbigniew Bodek goto error; 10622306b72aSZbigniew Bodek } 10632306b72aSZbigniew Bodek 10642306b72aSZbigniew Bodek /* Allocate DMA memory for Tx descriptors */ 10653c0086b8SZbigniew Bodek err = nicvf_alloc_q_desc_mem(nic, &sq->dmem, q_len, SND_QUEUE_DESC_SIZE, 10663c0086b8SZbigniew Bodek NICVF_SQ_BASE_ALIGN_BYTES); 10672306b72aSZbigniew Bodek if (err != 0) { 10682306b72aSZbigniew Bodek device_printf(nic->dev, 10692306b72aSZbigniew Bodek "Could not allocate DMA memory for SQ\n"); 10702306b72aSZbigniew Bodek goto error; 10712306b72aSZbigniew Bodek } 10723c0086b8SZbigniew Bodek 10733c0086b8SZbigniew Bodek sq->desc = sq->dmem.base; 10742306b72aSZbigniew Bodek sq->head = sq->tail = 0; 1075f6cdb4ceSZbigniew Bodek atomic_store_rel_int(&sq->free_cnt, q_len - 1); 10763c0086b8SZbigniew Bodek sq->thresh = SND_QUEUE_THRESH; 10772306b72aSZbigniew Bodek sq->idx = qidx; 10782306b72aSZbigniew Bodek sq->nic = nic; 10793c0086b8SZbigniew Bodek 10802306b72aSZbigniew Bodek /* 10812306b72aSZbigniew Bodek * Allocate DMA maps for Tx buffers 10822306b72aSZbigniew Bodek */ 10833c0086b8SZbigniew Bodek 10842306b72aSZbigniew Bodek /* Create DMA tag first */ 10852306b72aSZbigniew Bodek err = bus_dma_tag_create( 10862306b72aSZbigniew Bodek bus_get_dma_tag(nic->dev), /* parent tag */ 10872306b72aSZbigniew Bodek 1, /* alignment */ 10882306b72aSZbigniew Bodek 0, /* boundary */ 10892306b72aSZbigniew Bodek BUS_SPACE_MAXADDR, /* lowaddr */ 10902306b72aSZbigniew Bodek BUS_SPACE_MAXADDR, /* highaddr */ 10912306b72aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 1092af8fe8f1SZbigniew Bodek NICVF_TSO_MAXSIZE, /* maxsize */ 1093af8fe8f1SZbigniew Bodek NICVF_TSO_NSEGS, /* nsegments */ 10942306b72aSZbigniew Bodek MCLBYTES, /* maxsegsize */ 10952306b72aSZbigniew Bodek 0, /* flags */ 10962306b72aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 10972306b72aSZbigniew Bodek &sq->snd_buff_dmat); /* dmat */ 10982306b72aSZbigniew Bodek 10992306b72aSZbigniew Bodek if (err != 0) { 11002306b72aSZbigniew Bodek device_printf(nic->dev, 11012306b72aSZbigniew Bodek "Failed to create busdma tag for Tx buffers\n"); 11022306b72aSZbigniew Bodek goto error; 11033c0086b8SZbigniew Bodek } 11043c0086b8SZbigniew Bodek 11052306b72aSZbigniew Bodek /* Allocate send buffers array */ 1106ac2fffa4SPedro F. Giffuni sq->snd_buff = malloc(sizeof(*sq->snd_buff) * q_len, M_NICVF, 11072306b72aSZbigniew Bodek (M_NOWAIT | M_ZERO)); 11082306b72aSZbigniew Bodek if (sq->snd_buff == NULL) { 11092306b72aSZbigniew Bodek device_printf(nic->dev, 11102306b72aSZbigniew Bodek "Could not allocate memory for Tx buffers array\n"); 11112306b72aSZbigniew Bodek err = ENOMEM; 11122306b72aSZbigniew Bodek goto error; 11132306b72aSZbigniew Bodek } 11142306b72aSZbigniew Bodek 11152306b72aSZbigniew Bodek /* Now populate maps */ 11162306b72aSZbigniew Bodek for (i = 0; i < q_len; i++) { 11172306b72aSZbigniew Bodek err = bus_dmamap_create(sq->snd_buff_dmat, 0, 11182306b72aSZbigniew Bodek &sq->snd_buff[i].dmap); 11192306b72aSZbigniew Bodek if (err != 0) { 11202306b72aSZbigniew Bodek device_printf(nic->dev, 11212306b72aSZbigniew Bodek "Failed to create DMA maps for Tx buffers\n"); 11222306b72aSZbigniew Bodek goto error; 11232306b72aSZbigniew Bodek } 11242306b72aSZbigniew Bodek } 11252306b72aSZbigniew Bodek NICVF_TX_UNLOCK(sq); 11262306b72aSZbigniew Bodek 11272306b72aSZbigniew Bodek /* Allocate taskqueue */ 11282306b72aSZbigniew Bodek TASK_INIT(&sq->snd_task, 0, nicvf_snd_task, sq); 11292306b72aSZbigniew Bodek sq->snd_taskq = taskqueue_create_fast("nicvf_snd_taskq", M_WAITOK, 11302306b72aSZbigniew Bodek taskqueue_thread_enqueue, &sq->snd_taskq); 11312306b72aSZbigniew Bodek taskqueue_start_threads(&sq->snd_taskq, 1, PI_NET, "%s: snd_taskq(%d)", 11322306b72aSZbigniew Bodek device_get_nameunit(nic->dev), qidx); 11332306b72aSZbigniew Bodek 11342306b72aSZbigniew Bodek return (0); 11352306b72aSZbigniew Bodek error: 11362306b72aSZbigniew Bodek NICVF_TX_UNLOCK(sq); 11372306b72aSZbigniew Bodek return (err); 11382306b72aSZbigniew Bodek } 11392306b72aSZbigniew Bodek 11402306b72aSZbigniew Bodek static void 11412306b72aSZbigniew Bodek nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq) 11423c0086b8SZbigniew Bodek { 11432306b72aSZbigniew Bodek struct queue_set *qs = nic->qs; 11442306b72aSZbigniew Bodek size_t i; 1145*21653635SJohn Baldwin int err __diagused; 11462306b72aSZbigniew Bodek 11472306b72aSZbigniew Bodek if (sq == NULL) 11483c0086b8SZbigniew Bodek return; 11493c0086b8SZbigniew Bodek 11502306b72aSZbigniew Bodek if (sq->snd_taskq != NULL) { 11512306b72aSZbigniew Bodek /* Remove task */ 11522306b72aSZbigniew Bodek while (taskqueue_cancel(sq->snd_taskq, &sq->snd_task, NULL) != 0) 11532306b72aSZbigniew Bodek taskqueue_drain(sq->snd_taskq, &sq->snd_task); 11543c0086b8SZbigniew Bodek 11552306b72aSZbigniew Bodek taskqueue_free(sq->snd_taskq); 11562306b72aSZbigniew Bodek sq->snd_taskq = NULL; 11572306b72aSZbigniew Bodek } 11582306b72aSZbigniew Bodek 11592306b72aSZbigniew Bodek NICVF_TX_LOCK(sq); 11602306b72aSZbigniew Bodek if (sq->snd_buff_dmat != NULL) { 11612306b72aSZbigniew Bodek if (sq->snd_buff != NULL) { 11622306b72aSZbigniew Bodek for (i = 0; i < qs->sq_len; i++) { 11632306b72aSZbigniew Bodek m_freem(sq->snd_buff[i].mbuf); 11642306b72aSZbigniew Bodek sq->snd_buff[i].mbuf = NULL; 11652306b72aSZbigniew Bodek 11662306b72aSZbigniew Bodek bus_dmamap_unload(sq->snd_buff_dmat, 11672306b72aSZbigniew Bodek sq->snd_buff[i].dmap); 11682306b72aSZbigniew Bodek err = bus_dmamap_destroy(sq->snd_buff_dmat, 11692306b72aSZbigniew Bodek sq->snd_buff[i].dmap); 11702306b72aSZbigniew Bodek /* 11712306b72aSZbigniew Bodek * If bus_dmamap_destroy fails it can cause 11722306b72aSZbigniew Bodek * random panic later if the tag is also 11732306b72aSZbigniew Bodek * destroyed in the process. 11742306b72aSZbigniew Bodek */ 11752306b72aSZbigniew Bodek KASSERT(err == 0, 11762306b72aSZbigniew Bodek ("%s: Could not destroy DMA map for SQ", 11772306b72aSZbigniew Bodek __func__)); 11782306b72aSZbigniew Bodek } 11792306b72aSZbigniew Bodek } 11802306b72aSZbigniew Bodek 11812306b72aSZbigniew Bodek free(sq->snd_buff, M_NICVF); 11822306b72aSZbigniew Bodek 11832306b72aSZbigniew Bodek err = bus_dma_tag_destroy(sq->snd_buff_dmat); 11842306b72aSZbigniew Bodek KASSERT(err == 0, 11852306b72aSZbigniew Bodek ("%s: Trying to destroy BUSY DMA tag", __func__)); 11862306b72aSZbigniew Bodek } 11872306b72aSZbigniew Bodek 11882306b72aSZbigniew Bodek /* Free private driver ring for this send queue */ 11892306b72aSZbigniew Bodek if (sq->br != NULL) 11902306b72aSZbigniew Bodek drbr_free(sq->br, M_DEVBUF); 11912306b72aSZbigniew Bodek 11922306b72aSZbigniew Bodek if (sq->dmem.base != NULL) 11933c0086b8SZbigniew Bodek nicvf_free_q_desc_mem(nic, &sq->dmem); 11942306b72aSZbigniew Bodek 11952306b72aSZbigniew Bodek NICVF_TX_UNLOCK(sq); 11962306b72aSZbigniew Bodek /* Destroy Tx lock */ 11972306b72aSZbigniew Bodek mtx_destroy(&sq->mtx); 11982306b72aSZbigniew Bodek memset(sq->mtx_name, 0, sizeof(sq->mtx_name)); 11993c0086b8SZbigniew Bodek } 12003c0086b8SZbigniew Bodek 12012306b72aSZbigniew Bodek static void 12022306b72aSZbigniew Bodek nicvf_reclaim_snd_queue(struct nicvf *nic, struct queue_set *qs, int qidx) 12033c0086b8SZbigniew Bodek { 12042306b72aSZbigniew Bodek 12053c0086b8SZbigniew Bodek /* Disable send queue */ 12063c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, 0); 12073c0086b8SZbigniew Bodek /* Check if SQ is stopped */ 12083c0086b8SZbigniew Bodek if (nicvf_poll_reg(nic, qidx, NIC_QSET_SQ_0_7_STATUS, 21, 1, 0x01)) 12093c0086b8SZbigniew Bodek return; 12103c0086b8SZbigniew Bodek /* Reset send queue */ 12113c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET); 12123c0086b8SZbigniew Bodek } 12133c0086b8SZbigniew Bodek 12142306b72aSZbigniew Bodek static void 12152306b72aSZbigniew Bodek nicvf_reclaim_rcv_queue(struct nicvf *nic, struct queue_set *qs, int qidx) 12163c0086b8SZbigniew Bodek { 12173c0086b8SZbigniew Bodek union nic_mbx mbx = {}; 12183c0086b8SZbigniew Bodek 12193c0086b8SZbigniew Bodek /* Make sure all packets in the pipeline are written back into mem */ 12203c0086b8SZbigniew Bodek mbx.msg.msg = NIC_MBOX_MSG_RQ_SW_SYNC; 12213c0086b8SZbigniew Bodek nicvf_send_msg_to_pf(nic, &mbx); 12223c0086b8SZbigniew Bodek } 12233c0086b8SZbigniew Bodek 12242306b72aSZbigniew Bodek static void 12252306b72aSZbigniew Bodek nicvf_reclaim_cmp_queue(struct nicvf *nic, struct queue_set *qs, int qidx) 12263c0086b8SZbigniew Bodek { 12272306b72aSZbigniew Bodek 12283c0086b8SZbigniew Bodek /* Disable timer threshold (doesn't get reset upon CQ reset */ 12293c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx, 0); 12303c0086b8SZbigniew Bodek /* Disable completion queue */ 12313c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, 0); 12323c0086b8SZbigniew Bodek /* Reset completion queue */ 12333c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET); 12343c0086b8SZbigniew Bodek } 12353c0086b8SZbigniew Bodek 12362306b72aSZbigniew Bodek static void 12372306b72aSZbigniew Bodek nicvf_reclaim_rbdr(struct nicvf *nic, struct rbdr *rbdr, int qidx) 12383c0086b8SZbigniew Bodek { 12392306b72aSZbigniew Bodek uint64_t tmp, fifo_state; 12403c0086b8SZbigniew Bodek int timeout = 10; 12413c0086b8SZbigniew Bodek 12423c0086b8SZbigniew Bodek /* Save head and tail pointers for feeing up buffers */ 12432306b72aSZbigniew Bodek rbdr->head = 12442306b72aSZbigniew Bodek nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_HEAD, qidx) >> 3; 12452306b72aSZbigniew Bodek rbdr->tail = 12462306b72aSZbigniew Bodek nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_TAIL, qidx) >> 3; 12473c0086b8SZbigniew Bodek 12482306b72aSZbigniew Bodek /* 12492306b72aSZbigniew Bodek * If RBDR FIFO is in 'FAIL' state then do a reset first 12503c0086b8SZbigniew Bodek * before relaiming. 12513c0086b8SZbigniew Bodek */ 12523c0086b8SZbigniew Bodek fifo_state = nicvf_queue_reg_read(nic, NIC_QSET_RBDR_0_1_STATUS0, qidx); 12532306b72aSZbigniew Bodek if (((fifo_state >> 62) & 0x03) == 0x3) { 12543c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, 12553c0086b8SZbigniew Bodek qidx, NICVF_RBDR_RESET); 12562306b72aSZbigniew Bodek } 12573c0086b8SZbigniew Bodek 12583c0086b8SZbigniew Bodek /* Disable RBDR */ 12593c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0); 12603c0086b8SZbigniew Bodek if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00)) 12613c0086b8SZbigniew Bodek return; 12623c0086b8SZbigniew Bodek while (1) { 12633c0086b8SZbigniew Bodek tmp = nicvf_queue_reg_read(nic, 12642306b72aSZbigniew Bodek NIC_QSET_RBDR_0_1_PREFETCH_STATUS, qidx); 12653c0086b8SZbigniew Bodek if ((tmp & 0xFFFFFFFF) == ((tmp >> 32) & 0xFFFFFFFF)) 12663c0086b8SZbigniew Bodek break; 12672306b72aSZbigniew Bodek 12682306b72aSZbigniew Bodek DELAY(1000); 12693c0086b8SZbigniew Bodek timeout--; 12703c0086b8SZbigniew Bodek if (!timeout) { 12712306b72aSZbigniew Bodek device_printf(nic->dev, 12723c0086b8SZbigniew Bodek "Failed polling on prefetch status\n"); 12733c0086b8SZbigniew Bodek return; 12743c0086b8SZbigniew Bodek } 12753c0086b8SZbigniew Bodek } 12762306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 12772306b72aSZbigniew Bodek NICVF_RBDR_RESET); 12783c0086b8SZbigniew Bodek 12793c0086b8SZbigniew Bodek if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x02)) 12803c0086b8SZbigniew Bodek return; 12813c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 0x00); 12823c0086b8SZbigniew Bodek if (nicvf_poll_reg(nic, qidx, NIC_QSET_RBDR_0_1_STATUS0, 62, 2, 0x00)) 12833c0086b8SZbigniew Bodek return; 12843c0086b8SZbigniew Bodek } 12853c0086b8SZbigniew Bodek 12863c0086b8SZbigniew Bodek /* Configures receive queue */ 12872306b72aSZbigniew Bodek static void 12882306b72aSZbigniew Bodek nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs, 12893c0086b8SZbigniew Bodek int qidx, bool enable) 12903c0086b8SZbigniew Bodek { 12913c0086b8SZbigniew Bodek union nic_mbx mbx = {}; 12923c0086b8SZbigniew Bodek struct rcv_queue *rq; 12933c0086b8SZbigniew Bodek struct rq_cfg rq_cfg; 1294053f3d0eSZbigniew Bodek struct ifnet *ifp; 1295053f3d0eSZbigniew Bodek struct lro_ctrl *lro; 1296053f3d0eSZbigniew Bodek 1297053f3d0eSZbigniew Bodek ifp = nic->ifp; 12983c0086b8SZbigniew Bodek 12993c0086b8SZbigniew Bodek rq = &qs->rq[qidx]; 13003c0086b8SZbigniew Bodek rq->enable = enable; 13013c0086b8SZbigniew Bodek 1302053f3d0eSZbigniew Bodek lro = &rq->lro; 1303053f3d0eSZbigniew Bodek 13043c0086b8SZbigniew Bodek /* Disable receive queue */ 13053c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, 0); 13063c0086b8SZbigniew Bodek 13073c0086b8SZbigniew Bodek if (!rq->enable) { 13083c0086b8SZbigniew Bodek nicvf_reclaim_rcv_queue(nic, qs, qidx); 1309053f3d0eSZbigniew Bodek /* Free LRO memory */ 1310053f3d0eSZbigniew Bodek tcp_lro_free(lro); 1311053f3d0eSZbigniew Bodek rq->lro_enabled = FALSE; 13123c0086b8SZbigniew Bodek return; 13133c0086b8SZbigniew Bodek } 13143c0086b8SZbigniew Bodek 1315053f3d0eSZbigniew Bodek /* Configure LRO if enabled */ 1316053f3d0eSZbigniew Bodek rq->lro_enabled = FALSE; 1317053f3d0eSZbigniew Bodek if ((if_getcapenable(ifp) & IFCAP_LRO) != 0) { 1318053f3d0eSZbigniew Bodek if (tcp_lro_init(lro) != 0) { 1319053f3d0eSZbigniew Bodek device_printf(nic->dev, 1320053f3d0eSZbigniew Bodek "Failed to initialize LRO for RXQ%d\n", qidx); 1321053f3d0eSZbigniew Bodek } else { 1322053f3d0eSZbigniew Bodek rq->lro_enabled = TRUE; 1323053f3d0eSZbigniew Bodek lro->ifp = nic->ifp; 1324053f3d0eSZbigniew Bodek } 1325053f3d0eSZbigniew Bodek } 1326053f3d0eSZbigniew Bodek 13273c0086b8SZbigniew Bodek rq->cq_qs = qs->vnic_id; 13283c0086b8SZbigniew Bodek rq->cq_idx = qidx; 13293c0086b8SZbigniew Bodek rq->start_rbdr_qs = qs->vnic_id; 13303c0086b8SZbigniew Bodek rq->start_qs_rbdr_idx = qs->rbdr_cnt - 1; 13313c0086b8SZbigniew Bodek rq->cont_rbdr_qs = qs->vnic_id; 13323c0086b8SZbigniew Bodek rq->cont_qs_rbdr_idx = qs->rbdr_cnt - 1; 13333c0086b8SZbigniew Bodek /* all writes of RBDR data to be loaded into L2 Cache as well*/ 13343c0086b8SZbigniew Bodek rq->caching = 1; 13353c0086b8SZbigniew Bodek 13363c0086b8SZbigniew Bodek /* Send a mailbox msg to PF to config RQ */ 13373c0086b8SZbigniew Bodek mbx.rq.msg = NIC_MBOX_MSG_RQ_CFG; 13383c0086b8SZbigniew Bodek mbx.rq.qs_num = qs->vnic_id; 13393c0086b8SZbigniew Bodek mbx.rq.rq_num = qidx; 13403c0086b8SZbigniew Bodek mbx.rq.cfg = (rq->caching << 26) | (rq->cq_qs << 19) | 13413c0086b8SZbigniew Bodek (rq->cq_idx << 16) | (rq->cont_rbdr_qs << 9) | 13422306b72aSZbigniew Bodek (rq->cont_qs_rbdr_idx << 8) | (rq->start_rbdr_qs << 1) | 13432306b72aSZbigniew Bodek (rq->start_qs_rbdr_idx); 13443c0086b8SZbigniew Bodek nicvf_send_msg_to_pf(nic, &mbx); 13453c0086b8SZbigniew Bodek 13463c0086b8SZbigniew Bodek mbx.rq.msg = NIC_MBOX_MSG_RQ_BP_CFG; 13472306b72aSZbigniew Bodek mbx.rq.cfg = (1UL << 63) | (1UL << 62) | (qs->vnic_id << 0); 13483c0086b8SZbigniew Bodek nicvf_send_msg_to_pf(nic, &mbx); 13493c0086b8SZbigniew Bodek 13502306b72aSZbigniew Bodek /* 13512306b72aSZbigniew Bodek * RQ drop config 13523c0086b8SZbigniew Bodek * Enable CQ drop to reserve sufficient CQEs for all tx packets 13533c0086b8SZbigniew Bodek */ 13543c0086b8SZbigniew Bodek mbx.rq.msg = NIC_MBOX_MSG_RQ_DROP_CFG; 13552306b72aSZbigniew Bodek mbx.rq.cfg = (1UL << 62) | (RQ_CQ_DROP << 8); 13563c0086b8SZbigniew Bodek nicvf_send_msg_to_pf(nic, &mbx); 13573c0086b8SZbigniew Bodek 13583c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, 0x00); 13593c0086b8SZbigniew Bodek 13603c0086b8SZbigniew Bodek /* Enable Receive queue */ 13613c0086b8SZbigniew Bodek rq_cfg.ena = 1; 13623c0086b8SZbigniew Bodek rq_cfg.tcp_ena = 0; 13632306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RQ_0_7_CFG, qidx, 13642306b72aSZbigniew Bodek *(uint64_t *)&rq_cfg); 13653c0086b8SZbigniew Bodek } 13663c0086b8SZbigniew Bodek 13673c0086b8SZbigniew Bodek /* Configures completion queue */ 13682306b72aSZbigniew Bodek static void 13692306b72aSZbigniew Bodek nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs, 13702306b72aSZbigniew Bodek int qidx, boolean_t enable) 13713c0086b8SZbigniew Bodek { 13723c0086b8SZbigniew Bodek struct cmp_queue *cq; 13733c0086b8SZbigniew Bodek struct cq_cfg cq_cfg; 13743c0086b8SZbigniew Bodek 13753c0086b8SZbigniew Bodek cq = &qs->cq[qidx]; 13763c0086b8SZbigniew Bodek cq->enable = enable; 13773c0086b8SZbigniew Bodek 13783c0086b8SZbigniew Bodek if (!cq->enable) { 13793c0086b8SZbigniew Bodek nicvf_reclaim_cmp_queue(nic, qs, qidx); 13803c0086b8SZbigniew Bodek return; 13813c0086b8SZbigniew Bodek } 13823c0086b8SZbigniew Bodek 13833c0086b8SZbigniew Bodek /* Reset completion queue */ 13843c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, NICVF_CQ_RESET); 13853c0086b8SZbigniew Bodek 13863c0086b8SZbigniew Bodek /* Set completion queue base address */ 13872306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_BASE, qidx, 13882306b72aSZbigniew Bodek (uint64_t)(cq->dmem.phys_base)); 13893c0086b8SZbigniew Bodek 13903c0086b8SZbigniew Bodek /* Enable Completion queue */ 13913c0086b8SZbigniew Bodek cq_cfg.ena = 1; 13923c0086b8SZbigniew Bodek cq_cfg.reset = 0; 13933c0086b8SZbigniew Bodek cq_cfg.caching = 0; 13943c0086b8SZbigniew Bodek cq_cfg.qsize = CMP_QSIZE; 13953c0086b8SZbigniew Bodek cq_cfg.avg_con = 0; 13962306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, *(uint64_t *)&cq_cfg); 13973c0086b8SZbigniew Bodek 13983c0086b8SZbigniew Bodek /* Set threshold value for interrupt generation */ 13993c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh); 14002306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, qidx, 14012306b72aSZbigniew Bodek nic->cq_coalesce_usecs); 14023c0086b8SZbigniew Bodek } 14033c0086b8SZbigniew Bodek 14043c0086b8SZbigniew Bodek /* Configures transmit queue */ 14052306b72aSZbigniew Bodek static void 14062306b72aSZbigniew Bodek nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs, int qidx, 14072306b72aSZbigniew Bodek boolean_t enable) 14083c0086b8SZbigniew Bodek { 14093c0086b8SZbigniew Bodek union nic_mbx mbx = {}; 14103c0086b8SZbigniew Bodek struct snd_queue *sq; 14113c0086b8SZbigniew Bodek struct sq_cfg sq_cfg; 14123c0086b8SZbigniew Bodek 14133c0086b8SZbigniew Bodek sq = &qs->sq[qidx]; 14143c0086b8SZbigniew Bodek sq->enable = enable; 14153c0086b8SZbigniew Bodek 14163c0086b8SZbigniew Bodek if (!sq->enable) { 14173c0086b8SZbigniew Bodek nicvf_reclaim_snd_queue(nic, qs, qidx); 14183c0086b8SZbigniew Bodek return; 14193c0086b8SZbigniew Bodek } 14203c0086b8SZbigniew Bodek 14213c0086b8SZbigniew Bodek /* Reset send queue */ 14223c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, NICVF_SQ_RESET); 14233c0086b8SZbigniew Bodek 14243c0086b8SZbigniew Bodek sq->cq_qs = qs->vnic_id; 14253c0086b8SZbigniew Bodek sq->cq_idx = qidx; 14263c0086b8SZbigniew Bodek 14273c0086b8SZbigniew Bodek /* Send a mailbox msg to PF to config SQ */ 14283c0086b8SZbigniew Bodek mbx.sq.msg = NIC_MBOX_MSG_SQ_CFG; 14293c0086b8SZbigniew Bodek mbx.sq.qs_num = qs->vnic_id; 14303c0086b8SZbigniew Bodek mbx.sq.sq_num = qidx; 14313c0086b8SZbigniew Bodek mbx.sq.sqs_mode = nic->sqs_mode; 14323c0086b8SZbigniew Bodek mbx.sq.cfg = (sq->cq_qs << 3) | sq->cq_idx; 14333c0086b8SZbigniew Bodek nicvf_send_msg_to_pf(nic, &mbx); 14343c0086b8SZbigniew Bodek 14353c0086b8SZbigniew Bodek /* Set queue base address */ 14362306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_BASE, qidx, 14372306b72aSZbigniew Bodek (uint64_t)(sq->dmem.phys_base)); 14383c0086b8SZbigniew Bodek 14393c0086b8SZbigniew Bodek /* Enable send queue & set queue size */ 14403c0086b8SZbigniew Bodek sq_cfg.ena = 1; 14413c0086b8SZbigniew Bodek sq_cfg.reset = 0; 14423c0086b8SZbigniew Bodek sq_cfg.ldwb = 0; 14433c0086b8SZbigniew Bodek sq_cfg.qsize = SND_QSIZE; 14443c0086b8SZbigniew Bodek sq_cfg.tstmp_bgx_intf = 0; 14452306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, *(uint64_t *)&sq_cfg); 14463c0086b8SZbigniew Bodek 14473c0086b8SZbigniew Bodek /* Set threshold value for interrupt generation */ 14483c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_THRESH, qidx, sq->thresh); 14493c0086b8SZbigniew Bodek } 14503c0086b8SZbigniew Bodek 14513c0086b8SZbigniew Bodek /* Configures receive buffer descriptor ring */ 14522306b72aSZbigniew Bodek static void 14532306b72aSZbigniew Bodek nicvf_rbdr_config(struct nicvf *nic, struct queue_set *qs, int qidx, 14542306b72aSZbigniew Bodek boolean_t enable) 14553c0086b8SZbigniew Bodek { 14563c0086b8SZbigniew Bodek struct rbdr *rbdr; 14573c0086b8SZbigniew Bodek struct rbdr_cfg rbdr_cfg; 14583c0086b8SZbigniew Bodek 14593c0086b8SZbigniew Bodek rbdr = &qs->rbdr[qidx]; 14603c0086b8SZbigniew Bodek nicvf_reclaim_rbdr(nic, rbdr, qidx); 14613c0086b8SZbigniew Bodek if (!enable) 14623c0086b8SZbigniew Bodek return; 14633c0086b8SZbigniew Bodek 14643c0086b8SZbigniew Bodek /* Set descriptor base address */ 14652306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_BASE, qidx, 14662306b72aSZbigniew Bodek (uint64_t)(rbdr->dmem.phys_base)); 14673c0086b8SZbigniew Bodek 14683c0086b8SZbigniew Bodek /* Enable RBDR & set queue size */ 14693c0086b8SZbigniew Bodek /* Buffer size should be in multiples of 128 bytes */ 14703c0086b8SZbigniew Bodek rbdr_cfg.ena = 1; 14713c0086b8SZbigniew Bodek rbdr_cfg.reset = 0; 14723c0086b8SZbigniew Bodek rbdr_cfg.ldwb = 0; 14733c0086b8SZbigniew Bodek rbdr_cfg.qsize = RBDR_SIZE; 14743c0086b8SZbigniew Bodek rbdr_cfg.avg_con = 0; 14753c0086b8SZbigniew Bodek rbdr_cfg.lines = rbdr->dma_size / 128; 14762306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_CFG, qidx, 14772306b72aSZbigniew Bodek *(uint64_t *)&rbdr_cfg); 14783c0086b8SZbigniew Bodek 14793c0086b8SZbigniew Bodek /* Notify HW */ 14802306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_DOOR, qidx, 14812306b72aSZbigniew Bodek qs->rbdr_len - 1); 14823c0086b8SZbigniew Bodek 14833c0086b8SZbigniew Bodek /* Set threshold value for interrupt generation */ 14842306b72aSZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_RBDR_0_1_THRESH, qidx, 14852306b72aSZbigniew Bodek rbdr->thresh - 1); 14863c0086b8SZbigniew Bodek } 14873c0086b8SZbigniew Bodek 14883c0086b8SZbigniew Bodek /* Requests PF to assign and enable Qset */ 14892306b72aSZbigniew Bodek void 14902306b72aSZbigniew Bodek nicvf_qset_config(struct nicvf *nic, boolean_t enable) 14913c0086b8SZbigniew Bodek { 14923c0086b8SZbigniew Bodek union nic_mbx mbx = {}; 14932306b72aSZbigniew Bodek struct queue_set *qs; 14943c0086b8SZbigniew Bodek struct qs_cfg *qs_cfg; 14953c0086b8SZbigniew Bodek 14962306b72aSZbigniew Bodek qs = nic->qs; 14972306b72aSZbigniew Bodek if (qs == NULL) { 14982306b72aSZbigniew Bodek device_printf(nic->dev, 14993c0086b8SZbigniew Bodek "Qset is still not allocated, don't init queues\n"); 15003c0086b8SZbigniew Bodek return; 15013c0086b8SZbigniew Bodek } 15023c0086b8SZbigniew Bodek 15033c0086b8SZbigniew Bodek qs->enable = enable; 15043c0086b8SZbigniew Bodek qs->vnic_id = nic->vf_id; 15053c0086b8SZbigniew Bodek 15063c0086b8SZbigniew Bodek /* Send a mailbox msg to PF to config Qset */ 15073c0086b8SZbigniew Bodek mbx.qs.msg = NIC_MBOX_MSG_QS_CFG; 15083c0086b8SZbigniew Bodek mbx.qs.num = qs->vnic_id; 15093c0086b8SZbigniew Bodek 15103c0086b8SZbigniew Bodek mbx.qs.cfg = 0; 15113c0086b8SZbigniew Bodek qs_cfg = (struct qs_cfg *)&mbx.qs.cfg; 15123c0086b8SZbigniew Bodek if (qs->enable) { 15133c0086b8SZbigniew Bodek qs_cfg->ena = 1; 15143c0086b8SZbigniew Bodek qs_cfg->vnic = qs->vnic_id; 15153c0086b8SZbigniew Bodek } 15163c0086b8SZbigniew Bodek nicvf_send_msg_to_pf(nic, &mbx); 15173c0086b8SZbigniew Bodek } 15183c0086b8SZbigniew Bodek 15192306b72aSZbigniew Bodek static void 15202306b72aSZbigniew Bodek nicvf_free_resources(struct nicvf *nic) 15213c0086b8SZbigniew Bodek { 15223c0086b8SZbigniew Bodek int qidx; 15232306b72aSZbigniew Bodek struct queue_set *qs; 15243c0086b8SZbigniew Bodek 15252306b72aSZbigniew Bodek qs = nic->qs; 15262306b72aSZbigniew Bodek /* 15272306b72aSZbigniew Bodek * Remove QS error task first since it has to be dead 15282306b72aSZbigniew Bodek * to safely free completion queue tasks. 15292306b72aSZbigniew Bodek */ 15302306b72aSZbigniew Bodek if (qs->qs_err_taskq != NULL) { 15312306b72aSZbigniew Bodek /* Shut down QS error tasks */ 15322306b72aSZbigniew Bodek while (taskqueue_cancel(qs->qs_err_taskq, 15332306b72aSZbigniew Bodek &qs->qs_err_task, NULL) != 0) { 15342306b72aSZbigniew Bodek taskqueue_drain(qs->qs_err_taskq, &qs->qs_err_task); 15352306b72aSZbigniew Bodek } 15362306b72aSZbigniew Bodek taskqueue_free(qs->qs_err_taskq); 15372306b72aSZbigniew Bodek qs->qs_err_taskq = NULL; 15382306b72aSZbigniew Bodek } 15393c0086b8SZbigniew Bodek /* Free receive buffer descriptor ring */ 15403c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) 15413c0086b8SZbigniew Bodek nicvf_free_rbdr(nic, &qs->rbdr[qidx]); 15423c0086b8SZbigniew Bodek 15433c0086b8SZbigniew Bodek /* Free completion queue */ 15443c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->cq_cnt; qidx++) 15453c0086b8SZbigniew Bodek nicvf_free_cmp_queue(nic, &qs->cq[qidx]); 15463c0086b8SZbigniew Bodek 15473c0086b8SZbigniew Bodek /* Free send queue */ 15483c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->sq_cnt; qidx++) 15493c0086b8SZbigniew Bodek nicvf_free_snd_queue(nic, &qs->sq[qidx]); 15503c0086b8SZbigniew Bodek } 15513c0086b8SZbigniew Bodek 15522306b72aSZbigniew Bodek static int 15532306b72aSZbigniew Bodek nicvf_alloc_resources(struct nicvf *nic) 15543c0086b8SZbigniew Bodek { 15553c0086b8SZbigniew Bodek struct queue_set *qs = nic->qs; 15562306b72aSZbigniew Bodek int qidx; 15573c0086b8SZbigniew Bodek 15583c0086b8SZbigniew Bodek /* Alloc receive buffer descriptor ring */ 15593c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) { 15603c0086b8SZbigniew Bodek if (nicvf_init_rbdr(nic, &qs->rbdr[qidx], qs->rbdr_len, 15612306b72aSZbigniew Bodek DMA_BUFFER_LEN, qidx)) 15623c0086b8SZbigniew Bodek goto alloc_fail; 15633c0086b8SZbigniew Bodek } 15643c0086b8SZbigniew Bodek 15653c0086b8SZbigniew Bodek /* Alloc send queue */ 15663c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->sq_cnt; qidx++) { 15672306b72aSZbigniew Bodek if (nicvf_init_snd_queue(nic, &qs->sq[qidx], qs->sq_len, qidx)) 15683c0086b8SZbigniew Bodek goto alloc_fail; 15693c0086b8SZbigniew Bodek } 15703c0086b8SZbigniew Bodek 15713c0086b8SZbigniew Bodek /* Alloc completion queue */ 15723c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->cq_cnt; qidx++) { 15732306b72aSZbigniew Bodek if (nicvf_init_cmp_queue(nic, &qs->cq[qidx], qs->cq_len, qidx)) 15743c0086b8SZbigniew Bodek goto alloc_fail; 15753c0086b8SZbigniew Bodek } 15763c0086b8SZbigniew Bodek 15772306b72aSZbigniew Bodek /* Allocate QS error taskqueue */ 15786c3e93cbSGleb Smirnoff NET_TASK_INIT(&qs->qs_err_task, 0, nicvf_qs_err_task, nic); 15792306b72aSZbigniew Bodek qs->qs_err_taskq = taskqueue_create_fast("nicvf_qs_err_taskq", M_WAITOK, 15802306b72aSZbigniew Bodek taskqueue_thread_enqueue, &qs->qs_err_taskq); 15812306b72aSZbigniew Bodek taskqueue_start_threads(&qs->qs_err_taskq, 1, PI_NET, "%s: qs_taskq", 15822306b72aSZbigniew Bodek device_get_nameunit(nic->dev)); 15832306b72aSZbigniew Bodek 15842306b72aSZbigniew Bodek return (0); 15853c0086b8SZbigniew Bodek alloc_fail: 15863c0086b8SZbigniew Bodek nicvf_free_resources(nic); 15872306b72aSZbigniew Bodek return (ENOMEM); 15883c0086b8SZbigniew Bodek } 15893c0086b8SZbigniew Bodek 15902306b72aSZbigniew Bodek int 15912306b72aSZbigniew Bodek nicvf_set_qset_resources(struct nicvf *nic) 15923c0086b8SZbigniew Bodek { 15933c0086b8SZbigniew Bodek struct queue_set *qs; 15943c0086b8SZbigniew Bodek 15952306b72aSZbigniew Bodek qs = malloc(sizeof(*qs), M_NICVF, (M_ZERO | M_WAITOK)); 15963c0086b8SZbigniew Bodek nic->qs = qs; 15973c0086b8SZbigniew Bodek 15983c0086b8SZbigniew Bodek /* Set count of each queue */ 15993c0086b8SZbigniew Bodek qs->rbdr_cnt = RBDR_CNT; 16008191a879SZbigniew Bodek qs->rq_cnt = RCV_QUEUE_CNT; 16012306b72aSZbigniew Bodek 16023c0086b8SZbigniew Bodek qs->sq_cnt = SND_QUEUE_CNT; 16033c0086b8SZbigniew Bodek qs->cq_cnt = CMP_QUEUE_CNT; 16043c0086b8SZbigniew Bodek 16053c0086b8SZbigniew Bodek /* Set queue lengths */ 16063c0086b8SZbigniew Bodek qs->rbdr_len = RCV_BUF_COUNT; 16073c0086b8SZbigniew Bodek qs->sq_len = SND_QUEUE_LEN; 16083c0086b8SZbigniew Bodek qs->cq_len = CMP_QUEUE_LEN; 16093c0086b8SZbigniew Bodek 16103c0086b8SZbigniew Bodek nic->rx_queues = qs->rq_cnt; 16113c0086b8SZbigniew Bodek nic->tx_queues = qs->sq_cnt; 16123c0086b8SZbigniew Bodek 16132306b72aSZbigniew Bodek return (0); 16143c0086b8SZbigniew Bodek } 16153c0086b8SZbigniew Bodek 16162306b72aSZbigniew Bodek int 16172306b72aSZbigniew Bodek nicvf_config_data_transfer(struct nicvf *nic, boolean_t enable) 16183c0086b8SZbigniew Bodek { 16192306b72aSZbigniew Bodek boolean_t disable = FALSE; 16202306b72aSZbigniew Bodek struct queue_set *qs; 16213c0086b8SZbigniew Bodek int qidx; 16223c0086b8SZbigniew Bodek 16232306b72aSZbigniew Bodek qs = nic->qs; 16242306b72aSZbigniew Bodek if (qs == NULL) 16252306b72aSZbigniew Bodek return (0); 16263c0086b8SZbigniew Bodek 16273c0086b8SZbigniew Bodek if (enable) { 16282306b72aSZbigniew Bodek if (nicvf_alloc_resources(nic) != 0) 16292306b72aSZbigniew Bodek return (ENOMEM); 16303c0086b8SZbigniew Bodek 16313c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->sq_cnt; qidx++) 16323c0086b8SZbigniew Bodek nicvf_snd_queue_config(nic, qs, qidx, enable); 16333c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->cq_cnt; qidx++) 16343c0086b8SZbigniew Bodek nicvf_cmp_queue_config(nic, qs, qidx, enable); 16353c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) 16363c0086b8SZbigniew Bodek nicvf_rbdr_config(nic, qs, qidx, enable); 16373c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->rq_cnt; qidx++) 16383c0086b8SZbigniew Bodek nicvf_rcv_queue_config(nic, qs, qidx, enable); 16393c0086b8SZbigniew Bodek } else { 16403c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->rq_cnt; qidx++) 16413c0086b8SZbigniew Bodek nicvf_rcv_queue_config(nic, qs, qidx, disable); 16423c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) 16433c0086b8SZbigniew Bodek nicvf_rbdr_config(nic, qs, qidx, disable); 16443c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->sq_cnt; qidx++) 16453c0086b8SZbigniew Bodek nicvf_snd_queue_config(nic, qs, qidx, disable); 16463c0086b8SZbigniew Bodek for (qidx = 0; qidx < qs->cq_cnt; qidx++) 16473c0086b8SZbigniew Bodek nicvf_cmp_queue_config(nic, qs, qidx, disable); 16483c0086b8SZbigniew Bodek 16493c0086b8SZbigniew Bodek nicvf_free_resources(nic); 16503c0086b8SZbigniew Bodek } 16513c0086b8SZbigniew Bodek 16522306b72aSZbigniew Bodek return (0); 16533c0086b8SZbigniew Bodek } 16543c0086b8SZbigniew Bodek 16552306b72aSZbigniew Bodek /* 16562306b72aSZbigniew Bodek * Get a free desc from SQ 16573c0086b8SZbigniew Bodek * returns descriptor ponter & descriptor number 16583c0086b8SZbigniew Bodek */ 16592306b72aSZbigniew Bodek static __inline int 16602306b72aSZbigniew Bodek nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt) 16613c0086b8SZbigniew Bodek { 16623c0086b8SZbigniew Bodek int qentry; 16633c0086b8SZbigniew Bodek 16643c0086b8SZbigniew Bodek qentry = sq->tail; 1665f6cdb4ceSZbigniew Bodek atomic_subtract_int(&sq->free_cnt, desc_cnt); 16663c0086b8SZbigniew Bodek sq->tail += desc_cnt; 16673c0086b8SZbigniew Bodek sq->tail &= (sq->dmem.q_len - 1); 16683c0086b8SZbigniew Bodek 16692306b72aSZbigniew Bodek return (qentry); 16703c0086b8SZbigniew Bodek } 16713c0086b8SZbigniew Bodek 16723c0086b8SZbigniew Bodek /* Free descriptor back to SQ for future use */ 16732306b72aSZbigniew Bodek static void 16742306b72aSZbigniew Bodek nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt) 16753c0086b8SZbigniew Bodek { 16762306b72aSZbigniew Bodek 1677f6cdb4ceSZbigniew Bodek atomic_add_int(&sq->free_cnt, desc_cnt); 16783c0086b8SZbigniew Bodek sq->head += desc_cnt; 16793c0086b8SZbigniew Bodek sq->head &= (sq->dmem.q_len - 1); 16803c0086b8SZbigniew Bodek } 16813c0086b8SZbigniew Bodek 16822306b72aSZbigniew Bodek static __inline int 16832306b72aSZbigniew Bodek nicvf_get_nxt_sqentry(struct snd_queue *sq, int qentry) 16843c0086b8SZbigniew Bodek { 16853c0086b8SZbigniew Bodek qentry++; 16863c0086b8SZbigniew Bodek qentry &= (sq->dmem.q_len - 1); 16872306b72aSZbigniew Bodek return (qentry); 16883c0086b8SZbigniew Bodek } 16893c0086b8SZbigniew Bodek 16902306b72aSZbigniew Bodek static void 16912306b72aSZbigniew Bodek nicvf_sq_enable(struct nicvf *nic, struct snd_queue *sq, int qidx) 16923c0086b8SZbigniew Bodek { 16932306b72aSZbigniew Bodek uint64_t sq_cfg; 16943c0086b8SZbigniew Bodek 16953c0086b8SZbigniew Bodek sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx); 16963c0086b8SZbigniew Bodek sq_cfg |= NICVF_SQ_EN; 16973c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg); 16983c0086b8SZbigniew Bodek /* Ring doorbell so that H/W restarts processing SQEs */ 16993c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR, qidx, 0); 17003c0086b8SZbigniew Bodek } 17013c0086b8SZbigniew Bodek 17022306b72aSZbigniew Bodek static void 17032306b72aSZbigniew Bodek nicvf_sq_disable(struct nicvf *nic, int qidx) 17043c0086b8SZbigniew Bodek { 17052306b72aSZbigniew Bodek uint64_t sq_cfg; 17063c0086b8SZbigniew Bodek 17073c0086b8SZbigniew Bodek sq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CFG, qidx); 17083c0086b8SZbigniew Bodek sq_cfg &= ~NICVF_SQ_EN; 17093c0086b8SZbigniew Bodek nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, sq_cfg); 17103c0086b8SZbigniew Bodek } 17113c0086b8SZbigniew Bodek 17122306b72aSZbigniew Bodek static void 17132306b72aSZbigniew Bodek nicvf_sq_free_used_descs(struct nicvf *nic, struct snd_queue *sq, int qidx) 17143c0086b8SZbigniew Bodek { 1715151ba793SAlexander Kabaev uint64_t head; 17162306b72aSZbigniew Bodek struct snd_buff *snd_buff; 17173c0086b8SZbigniew Bodek struct sq_hdr_subdesc *hdr; 17183c0086b8SZbigniew Bodek 17192306b72aSZbigniew Bodek NICVF_TX_LOCK(sq); 17203c0086b8SZbigniew Bodek head = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_HEAD, qidx) >> 4; 17213c0086b8SZbigniew Bodek while (sq->head != head) { 17223c0086b8SZbigniew Bodek hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, sq->head); 17233c0086b8SZbigniew Bodek if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) { 17243c0086b8SZbigniew Bodek nicvf_put_sq_desc(sq, 1); 17253c0086b8SZbigniew Bodek continue; 17263c0086b8SZbigniew Bodek } 17272306b72aSZbigniew Bodek snd_buff = &sq->snd_buff[sq->head]; 17282306b72aSZbigniew Bodek if (snd_buff->mbuf != NULL) { 17292306b72aSZbigniew Bodek bus_dmamap_unload(sq->snd_buff_dmat, snd_buff->dmap); 17302306b72aSZbigniew Bodek m_freem(snd_buff->mbuf); 17312306b72aSZbigniew Bodek sq->snd_buff[sq->head].mbuf = NULL; 17322306b72aSZbigniew Bodek } 17333c0086b8SZbigniew Bodek nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1); 17343c0086b8SZbigniew Bodek } 17352306b72aSZbigniew Bodek NICVF_TX_UNLOCK(sq); 17363c0086b8SZbigniew Bodek } 17373c0086b8SZbigniew Bodek 17382306b72aSZbigniew Bodek /* 17392306b72aSZbigniew Bodek * Add SQ HEADER subdescriptor. 17403c0086b8SZbigniew Bodek * First subdescriptor for every send descriptor. 17413c0086b8SZbigniew Bodek */ 1742856dce91SZbigniew Bodek static __inline int 17433c0086b8SZbigniew Bodek nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry, 17442306b72aSZbigniew Bodek int subdesc_cnt, struct mbuf *mbuf, int len) 17453c0086b8SZbigniew Bodek { 1746af8fe8f1SZbigniew Bodek struct nicvf *nic; 17473c0086b8SZbigniew Bodek struct sq_hdr_subdesc *hdr; 1748856dce91SZbigniew Bodek struct ether_vlan_header *eh; 1749856dce91SZbigniew Bodek #ifdef INET 1750856dce91SZbigniew Bodek struct ip *ip; 1751af8fe8f1SZbigniew Bodek struct tcphdr *th; 1752856dce91SZbigniew Bodek #endif 1753856dce91SZbigniew Bodek uint16_t etype; 1754c04716b1SBjoern A. Zeeb int ehdrlen, iphlen, poff, proto; 17553c0086b8SZbigniew Bodek 1756af8fe8f1SZbigniew Bodek nic = sq->nic; 1757af8fe8f1SZbigniew Bodek 17583c0086b8SZbigniew Bodek hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, qentry); 17592306b72aSZbigniew Bodek sq->snd_buff[qentry].mbuf = mbuf; 17603c0086b8SZbigniew Bodek 17613c0086b8SZbigniew Bodek memset(hdr, 0, SND_QUEUE_DESC_SIZE); 17623c0086b8SZbigniew Bodek hdr->subdesc_type = SQ_DESC_TYPE_HEADER; 17633c0086b8SZbigniew Bodek /* Enable notification via CQE after processing SQE */ 17643c0086b8SZbigniew Bodek hdr->post_cqe = 1; 17653c0086b8SZbigniew Bodek /* No of subdescriptors following this */ 17663c0086b8SZbigniew Bodek hdr->subdesc_cnt = subdesc_cnt; 17673c0086b8SZbigniew Bodek hdr->tot_len = len; 17683c0086b8SZbigniew Bodek 1769856dce91SZbigniew Bodek eh = mtod(mbuf, struct ether_vlan_header *); 1770856dce91SZbigniew Bodek if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1771856dce91SZbigniew Bodek ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1772856dce91SZbigniew Bodek etype = ntohs(eh->evl_proto); 1773856dce91SZbigniew Bodek } else { 1774856dce91SZbigniew Bodek ehdrlen = ETHER_HDR_LEN; 1775856dce91SZbigniew Bodek etype = ntohs(eh->evl_encap_proto); 1776856dce91SZbigniew Bodek } 1777856dce91SZbigniew Bodek 1778c04716b1SBjoern A. Zeeb poff = proto = -1; 1779856dce91SZbigniew Bodek switch (etype) { 1780856dce91SZbigniew Bodek #ifdef INET6 1781856dce91SZbigniew Bodek case ETHERTYPE_IPV6: 1782c04716b1SBjoern A. Zeeb if (mbuf->m_len < ehdrlen + sizeof(struct ip6_hdr)) { 1783c04716b1SBjoern A. Zeeb mbuf = m_pullup(mbuf, ehdrlen +sizeof(struct ip6_hdr)); 1784856dce91SZbigniew Bodek sq->snd_buff[qentry].mbuf = NULL; 1785c04716b1SBjoern A. Zeeb if (mbuf == NULL) 1786c04716b1SBjoern A. Zeeb return (ENOBUFS); 1787c04716b1SBjoern A. Zeeb } 1788c04716b1SBjoern A. Zeeb poff = ip6_lasthdr(mbuf, ehdrlen, IPPROTO_IPV6, &proto); 1789c04716b1SBjoern A. Zeeb if (poff < 0) 1790c04716b1SBjoern A. Zeeb return (ENOBUFS); 1791c04716b1SBjoern A. Zeeb poff += ehdrlen; 1792c04716b1SBjoern A. Zeeb break; 1793856dce91SZbigniew Bodek #endif 1794856dce91SZbigniew Bodek #ifdef INET 1795856dce91SZbigniew Bodek case ETHERTYPE_IP: 1796af8fe8f1SZbigniew Bodek if (mbuf->m_len < ehdrlen + sizeof(struct ip)) { 1797af8fe8f1SZbigniew Bodek mbuf = m_pullup(mbuf, ehdrlen + sizeof(struct ip)); 1798af8fe8f1SZbigniew Bodek sq->snd_buff[qentry].mbuf = mbuf; 1799af8fe8f1SZbigniew Bodek if (mbuf == NULL) 1800af8fe8f1SZbigniew Bodek return (ENOBUFS); 1801af8fe8f1SZbigniew Bodek } 18027fe94db2SEd Maste if (mbuf->m_pkthdr.csum_flags & CSUM_IP) 18037fe94db2SEd Maste hdr->csum_l3 = 1; /* Enable IP csum calculation */ 1804af8fe8f1SZbigniew Bodek 1805856dce91SZbigniew Bodek ip = (struct ip *)(mbuf->m_data + ehdrlen); 1806856dce91SZbigniew Bodek iphlen = ip->ip_hl << 2; 1807856dce91SZbigniew Bodek poff = ehdrlen + iphlen; 1808c04716b1SBjoern A. Zeeb proto = ip->ip_p; 1809c04716b1SBjoern A. Zeeb break; 1810c04716b1SBjoern A. Zeeb #endif 1811c04716b1SBjoern A. Zeeb } 1812856dce91SZbigniew Bodek 1813c04716b1SBjoern A. Zeeb #if defined(INET6) || defined(INET) 1814c04716b1SBjoern A. Zeeb if (poff > 0 && mbuf->m_pkthdr.csum_flags != 0) { 1815c04716b1SBjoern A. Zeeb switch (proto) { 1816856dce91SZbigniew Bodek case IPPROTO_TCP: 1817856dce91SZbigniew Bodek if ((mbuf->m_pkthdr.csum_flags & CSUM_TCP) == 0) 1818856dce91SZbigniew Bodek break; 1819856dce91SZbigniew Bodek 1820856dce91SZbigniew Bodek if (mbuf->m_len < (poff + sizeof(struct tcphdr))) { 1821856dce91SZbigniew Bodek mbuf = m_pullup(mbuf, poff + sizeof(struct tcphdr)); 1822856dce91SZbigniew Bodek sq->snd_buff[qentry].mbuf = mbuf; 1823856dce91SZbigniew Bodek if (mbuf == NULL) 1824856dce91SZbigniew Bodek return (ENOBUFS); 1825856dce91SZbigniew Bodek } 1826856dce91SZbigniew Bodek hdr->csum_l4 = SEND_L4_CSUM_TCP; 1827856dce91SZbigniew Bodek break; 1828856dce91SZbigniew Bodek case IPPROTO_UDP: 1829856dce91SZbigniew Bodek if ((mbuf->m_pkthdr.csum_flags & CSUM_UDP) == 0) 1830856dce91SZbigniew Bodek break; 1831856dce91SZbigniew Bodek 1832856dce91SZbigniew Bodek if (mbuf->m_len < (poff + sizeof(struct udphdr))) { 1833856dce91SZbigniew Bodek mbuf = m_pullup(mbuf, poff + sizeof(struct udphdr)); 1834856dce91SZbigniew Bodek sq->snd_buff[qentry].mbuf = mbuf; 1835856dce91SZbigniew Bodek if (mbuf == NULL) 1836856dce91SZbigniew Bodek return (ENOBUFS); 1837856dce91SZbigniew Bodek } 1838856dce91SZbigniew Bodek hdr->csum_l4 = SEND_L4_CSUM_UDP; 1839856dce91SZbigniew Bodek break; 1840856dce91SZbigniew Bodek case IPPROTO_SCTP: 1841856dce91SZbigniew Bodek if ((mbuf->m_pkthdr.csum_flags & CSUM_SCTP) == 0) 1842856dce91SZbigniew Bodek break; 1843856dce91SZbigniew Bodek 1844856dce91SZbigniew Bodek if (mbuf->m_len < (poff + sizeof(struct sctphdr))) { 1845856dce91SZbigniew Bodek mbuf = m_pullup(mbuf, poff + sizeof(struct sctphdr)); 1846856dce91SZbigniew Bodek sq->snd_buff[qentry].mbuf = mbuf; 1847856dce91SZbigniew Bodek if (mbuf == NULL) 1848856dce91SZbigniew Bodek return (ENOBUFS); 1849856dce91SZbigniew Bodek } 1850856dce91SZbigniew Bodek hdr->csum_l4 = SEND_L4_CSUM_SCTP; 1851856dce91SZbigniew Bodek break; 1852856dce91SZbigniew Bodek default: 1853856dce91SZbigniew Bodek break; 1854856dce91SZbigniew Bodek } 1855af8fe8f1SZbigniew Bodek hdr->l3_offset = ehdrlen; 1856c04716b1SBjoern A. Zeeb hdr->l4_offset = poff; 1857af8fe8f1SZbigniew Bodek } 1858af8fe8f1SZbigniew Bodek 1859af8fe8f1SZbigniew Bodek if ((mbuf->m_pkthdr.tso_segsz != 0) && nic->hw_tso) { 1860c04716b1SBjoern A. Zeeb th = (struct tcphdr *)((caddr_t)(mbuf->m_data + poff)); 1861af8fe8f1SZbigniew Bodek 1862af8fe8f1SZbigniew Bodek hdr->tso = 1; 1863c04716b1SBjoern A. Zeeb hdr->tso_start = poff + (th->th_off * 4); 1864af8fe8f1SZbigniew Bodek hdr->tso_max_paysize = mbuf->m_pkthdr.tso_segsz; 1865af8fe8f1SZbigniew Bodek hdr->inner_l3_offset = ehdrlen - 2; 1866af8fe8f1SZbigniew Bodek nic->drv_stats.tx_tso++; 1867af8fe8f1SZbigniew Bodek } 1868856dce91SZbigniew Bodek #endif 1869856dce91SZbigniew Bodek 1870856dce91SZbigniew Bodek return (0); 18713c0086b8SZbigniew Bodek } 18723c0086b8SZbigniew Bodek 18732306b72aSZbigniew Bodek /* 18742306b72aSZbigniew Bodek * SQ GATHER subdescriptor 18753c0086b8SZbigniew Bodek * Must follow HDR descriptor 18763c0086b8SZbigniew Bodek */ 18773c0086b8SZbigniew Bodek static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry, 18782306b72aSZbigniew Bodek int size, uint64_t data) 18793c0086b8SZbigniew Bodek { 18803c0086b8SZbigniew Bodek struct sq_gather_subdesc *gather; 18813c0086b8SZbigniew Bodek 18823c0086b8SZbigniew Bodek qentry &= (sq->dmem.q_len - 1); 18833c0086b8SZbigniew Bodek gather = (struct sq_gather_subdesc *)GET_SQ_DESC(sq, qentry); 18843c0086b8SZbigniew Bodek 18853c0086b8SZbigniew Bodek memset(gather, 0, SND_QUEUE_DESC_SIZE); 18863c0086b8SZbigniew Bodek gather->subdesc_type = SQ_DESC_TYPE_GATHER; 18873c0086b8SZbigniew Bodek gather->ld_type = NIC_SEND_LD_TYPE_E_LDD; 18883c0086b8SZbigniew Bodek gather->size = size; 18893c0086b8SZbigniew Bodek gather->addr = data; 18903c0086b8SZbigniew Bodek } 18913c0086b8SZbigniew Bodek 18922306b72aSZbigniew Bodek /* Put an mbuf to a SQ for packet transfer. */ 18937c617aceSZbigniew Bodek static int 18947c617aceSZbigniew Bodek nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf **mbufp) 18953c0086b8SZbigniew Bodek { 18962306b72aSZbigniew Bodek bus_dma_segment_t segs[256]; 18972306b72aSZbigniew Bodek struct snd_buff *snd_buff; 18982306b72aSZbigniew Bodek size_t seg; 18992306b72aSZbigniew Bodek int nsegs, qentry; 1900af8fe8f1SZbigniew Bodek int subdesc_cnt; 19012306b72aSZbigniew Bodek int err; 19023c0086b8SZbigniew Bodek 19032306b72aSZbigniew Bodek NICVF_TX_LOCK_ASSERT(sq); 19042306b72aSZbigniew Bodek 19052306b72aSZbigniew Bodek if (sq->free_cnt == 0) 19062306b72aSZbigniew Bodek return (ENOBUFS); 19072306b72aSZbigniew Bodek 19082306b72aSZbigniew Bodek snd_buff = &sq->snd_buff[sq->tail]; 19092306b72aSZbigniew Bodek 19102306b72aSZbigniew Bodek err = bus_dmamap_load_mbuf_sg(sq->snd_buff_dmat, snd_buff->dmap, 19117c617aceSZbigniew Bodek *mbufp, segs, &nsegs, BUS_DMA_NOWAIT); 19127c617aceSZbigniew Bodek if (__predict_false(err != 0)) { 19132306b72aSZbigniew Bodek /* ARM64TODO: Add mbuf defragmenting if we lack maps */ 19147c617aceSZbigniew Bodek m_freem(*mbufp); 19157c617aceSZbigniew Bodek *mbufp = NULL; 19162306b72aSZbigniew Bodek return (err); 19173c0086b8SZbigniew Bodek } 19182306b72aSZbigniew Bodek 19192306b72aSZbigniew Bodek /* Set how many subdescriptors is required */ 1920af8fe8f1SZbigniew Bodek subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT + nsegs - 1; 19212306b72aSZbigniew Bodek if (subdesc_cnt > sq->free_cnt) { 19222306b72aSZbigniew Bodek /* ARM64TODO: Add mbuf defragmentation if we lack descriptors */ 19232306b72aSZbigniew Bodek bus_dmamap_unload(sq->snd_buff_dmat, snd_buff->dmap); 19242306b72aSZbigniew Bodek return (ENOBUFS); 19253c0086b8SZbigniew Bodek } 19263c0086b8SZbigniew Bodek 19273c0086b8SZbigniew Bodek qentry = nicvf_get_sq_desc(sq, subdesc_cnt); 19283c0086b8SZbigniew Bodek 19293c0086b8SZbigniew Bodek /* Add SQ header subdesc */ 19307c617aceSZbigniew Bodek err = nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, *mbufp, 19317c617aceSZbigniew Bodek (*mbufp)->m_pkthdr.len); 1932856dce91SZbigniew Bodek if (err != 0) { 19337c617aceSZbigniew Bodek nicvf_put_sq_desc(sq, subdesc_cnt); 1934856dce91SZbigniew Bodek bus_dmamap_unload(sq->snd_buff_dmat, snd_buff->dmap); 19357c617aceSZbigniew Bodek if (err == ENOBUFS) { 19367c617aceSZbigniew Bodek m_freem(*mbufp); 19377c617aceSZbigniew Bodek *mbufp = NULL; 19387c617aceSZbigniew Bodek } 1939856dce91SZbigniew Bodek return (err); 1940856dce91SZbigniew Bodek } 19413c0086b8SZbigniew Bodek 19423c0086b8SZbigniew Bodek /* Add SQ gather subdescs */ 19432306b72aSZbigniew Bodek for (seg = 0; seg < nsegs; seg++) { 19443c0086b8SZbigniew Bodek qentry = nicvf_get_nxt_sqentry(sq, qentry); 19452306b72aSZbigniew Bodek nicvf_sq_add_gather_subdesc(sq, qentry, segs[seg].ds_len, 19462306b72aSZbigniew Bodek segs[seg].ds_addr); 19473c0086b8SZbigniew Bodek } 19483c0086b8SZbigniew Bodek 19493c0086b8SZbigniew Bodek /* make sure all memory stores are done before ringing doorbell */ 19502306b72aSZbigniew Bodek bus_dmamap_sync(sq->dmem.dmat, sq->dmem.dmap, BUS_DMASYNC_PREWRITE); 19513c0086b8SZbigniew Bodek 19522306b72aSZbigniew Bodek dprintf(sq->nic->dev, "%s: sq->idx: %d, subdesc_cnt: %d\n", 19532306b72aSZbigniew Bodek __func__, sq->idx, subdesc_cnt); 19543c0086b8SZbigniew Bodek /* Inform HW to xmit new packet */ 19552306b72aSZbigniew Bodek nicvf_queue_reg_write(sq->nic, NIC_QSET_SQ_0_7_DOOR, 19562306b72aSZbigniew Bodek sq->idx, subdesc_cnt); 19572306b72aSZbigniew Bodek return (0); 19583c0086b8SZbigniew Bodek } 19593c0086b8SZbigniew Bodek 19602306b72aSZbigniew Bodek static __inline u_int 19612306b72aSZbigniew Bodek frag_num(u_int i) 19623c0086b8SZbigniew Bodek { 19632306b72aSZbigniew Bodek #if BYTE_ORDER == BIG_ENDIAN 19642306b72aSZbigniew Bodek return ((i & ~3) + 3 - (i & 3)); 19653c0086b8SZbigniew Bodek #else 19662306b72aSZbigniew Bodek return (i); 19673c0086b8SZbigniew Bodek #endif 19683c0086b8SZbigniew Bodek } 19693c0086b8SZbigniew Bodek 19702306b72aSZbigniew Bodek /* Returns MBUF for a received packet */ 19712306b72aSZbigniew Bodek struct mbuf * 19722306b72aSZbigniew Bodek nicvf_get_rcv_mbuf(struct nicvf *nic, struct cqe_rx_t *cqe_rx) 19733c0086b8SZbigniew Bodek { 19743c0086b8SZbigniew Bodek int frag; 19753c0086b8SZbigniew Bodek int payload_len = 0; 19762306b72aSZbigniew Bodek struct mbuf *mbuf; 19772306b72aSZbigniew Bodek struct mbuf *mbuf_frag; 19782306b72aSZbigniew Bodek uint16_t *rb_lens = NULL; 19792306b72aSZbigniew Bodek uint64_t *rb_ptrs = NULL; 19803c0086b8SZbigniew Bodek 19812306b72aSZbigniew Bodek mbuf = NULL; 19822306b72aSZbigniew Bodek rb_lens = (uint16_t *)((uint8_t *)cqe_rx + (3 * sizeof(uint64_t))); 19832306b72aSZbigniew Bodek rb_ptrs = (uint64_t *)((uint8_t *)cqe_rx + (6 * sizeof(uint64_t))); 19843c0086b8SZbigniew Bodek 19852306b72aSZbigniew Bodek dprintf(nic->dev, "%s rb_cnt %d rb0_ptr %lx rb0_sz %d\n", 19863c0086b8SZbigniew Bodek __func__, cqe_rx->rb_cnt, cqe_rx->rb0_ptr, cqe_rx->rb0_sz); 19873c0086b8SZbigniew Bodek 19883c0086b8SZbigniew Bodek for (frag = 0; frag < cqe_rx->rb_cnt; frag++) { 19893c0086b8SZbigniew Bodek payload_len = rb_lens[frag_num(frag)]; 19902306b72aSZbigniew Bodek if (frag == 0) { 19913c0086b8SZbigniew Bodek /* First fragment */ 19922306b72aSZbigniew Bodek mbuf = nicvf_rb_ptr_to_mbuf(nic, 19932306b72aSZbigniew Bodek (*rb_ptrs - cqe_rx->align_pad)); 19942306b72aSZbigniew Bodek mbuf->m_len = payload_len; 19952306b72aSZbigniew Bodek mbuf->m_data += cqe_rx->align_pad; 19962306b72aSZbigniew Bodek if_setrcvif(mbuf, nic->ifp); 19973c0086b8SZbigniew Bodek } else { 19983c0086b8SZbigniew Bodek /* Add fragments */ 19992306b72aSZbigniew Bodek mbuf_frag = nicvf_rb_ptr_to_mbuf(nic, *rb_ptrs); 20002306b72aSZbigniew Bodek m_append(mbuf, payload_len, mbuf_frag->m_data); 20012306b72aSZbigniew Bodek m_freem(mbuf_frag); 20023c0086b8SZbigniew Bodek } 20033c0086b8SZbigniew Bodek /* Next buffer pointer */ 20043c0086b8SZbigniew Bodek rb_ptrs++; 20053c0086b8SZbigniew Bodek } 20062306b72aSZbigniew Bodek 20072306b72aSZbigniew Bodek if (__predict_true(mbuf != NULL)) { 20082306b72aSZbigniew Bodek m_fixhdr(mbuf); 20092306b72aSZbigniew Bodek mbuf->m_pkthdr.flowid = cqe_rx->rq_idx; 20102306b72aSZbigniew Bodek M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE); 2011856dce91SZbigniew Bodek if (__predict_true((if_getcapenable(nic->ifp) & IFCAP_RXCSUM) != 0)) { 2012856dce91SZbigniew Bodek /* 2013856dce91SZbigniew Bodek * HW by default verifies IP & TCP/UDP/SCTP checksums 2014856dce91SZbigniew Bodek */ 2015c8907923SZbigniew Bodek if (__predict_true(cqe_rx->l3_type == L3TYPE_IPV4)) { 2016856dce91SZbigniew Bodek mbuf->m_pkthdr.csum_flags = 2017856dce91SZbigniew Bodek (CSUM_IP_CHECKED | CSUM_IP_VALID); 2018856dce91SZbigniew Bodek } 2019c8907923SZbigniew Bodek 2020c8907923SZbigniew Bodek switch (cqe_rx->l4_type) { 2021c8907923SZbigniew Bodek case L4TYPE_UDP: 2022c8907923SZbigniew Bodek case L4TYPE_TCP: /* fall through */ 2023856dce91SZbigniew Bodek mbuf->m_pkthdr.csum_flags |= 2024856dce91SZbigniew Bodek (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 2025c8907923SZbigniew Bodek mbuf->m_pkthdr.csum_data = 0xffff; 2026c8907923SZbigniew Bodek break; 2027c8907923SZbigniew Bodek case L4TYPE_SCTP: 2028c8907923SZbigniew Bodek mbuf->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; 2029c8907923SZbigniew Bodek break; 2030c8907923SZbigniew Bodek default: 2031c8907923SZbigniew Bodek break; 2032856dce91SZbigniew Bodek } 2033856dce91SZbigniew Bodek } 20342306b72aSZbigniew Bodek } 20352306b72aSZbigniew Bodek 20362306b72aSZbigniew Bodek return (mbuf); 20373c0086b8SZbigniew Bodek } 20383c0086b8SZbigniew Bodek 20393c0086b8SZbigniew Bodek /* Enable interrupt */ 20402306b72aSZbigniew Bodek void 20412306b72aSZbigniew Bodek nicvf_enable_intr(struct nicvf *nic, int int_type, int q_idx) 20423c0086b8SZbigniew Bodek { 20432306b72aSZbigniew Bodek uint64_t reg_val; 20443c0086b8SZbigniew Bodek 20453c0086b8SZbigniew Bodek reg_val = nicvf_reg_read(nic, NIC_VF_ENA_W1S); 20463c0086b8SZbigniew Bodek 20473c0086b8SZbigniew Bodek switch (int_type) { 20483c0086b8SZbigniew Bodek case NICVF_INTR_CQ: 20492306b72aSZbigniew Bodek reg_val |= ((1UL << q_idx) << NICVF_INTR_CQ_SHIFT); 20503c0086b8SZbigniew Bodek break; 20513c0086b8SZbigniew Bodek case NICVF_INTR_SQ: 20522306b72aSZbigniew Bodek reg_val |= ((1UL << q_idx) << NICVF_INTR_SQ_SHIFT); 20533c0086b8SZbigniew Bodek break; 20543c0086b8SZbigniew Bodek case NICVF_INTR_RBDR: 20552306b72aSZbigniew Bodek reg_val |= ((1UL << q_idx) << NICVF_INTR_RBDR_SHIFT); 20563c0086b8SZbigniew Bodek break; 20573c0086b8SZbigniew Bodek case NICVF_INTR_PKT_DROP: 20582306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_PKT_DROP_SHIFT); 20593c0086b8SZbigniew Bodek break; 20603c0086b8SZbigniew Bodek case NICVF_INTR_TCP_TIMER: 20612306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_TCP_TIMER_SHIFT); 20623c0086b8SZbigniew Bodek break; 20633c0086b8SZbigniew Bodek case NICVF_INTR_MBOX: 20642306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_MBOX_SHIFT); 20653c0086b8SZbigniew Bodek break; 20663c0086b8SZbigniew Bodek case NICVF_INTR_QS_ERR: 20672306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_QS_ERR_SHIFT); 20683c0086b8SZbigniew Bodek break; 20693c0086b8SZbigniew Bodek default: 20702306b72aSZbigniew Bodek device_printf(nic->dev, 20713c0086b8SZbigniew Bodek "Failed to enable interrupt: unknown type\n"); 20723c0086b8SZbigniew Bodek break; 20733c0086b8SZbigniew Bodek } 20743c0086b8SZbigniew Bodek 20753c0086b8SZbigniew Bodek nicvf_reg_write(nic, NIC_VF_ENA_W1S, reg_val); 20763c0086b8SZbigniew Bodek } 20773c0086b8SZbigniew Bodek 20783c0086b8SZbigniew Bodek /* Disable interrupt */ 20792306b72aSZbigniew Bodek void 20802306b72aSZbigniew Bodek nicvf_disable_intr(struct nicvf *nic, int int_type, int q_idx) 20813c0086b8SZbigniew Bodek { 20822306b72aSZbigniew Bodek uint64_t reg_val = 0; 20833c0086b8SZbigniew Bodek 20843c0086b8SZbigniew Bodek switch (int_type) { 20853c0086b8SZbigniew Bodek case NICVF_INTR_CQ: 20862306b72aSZbigniew Bodek reg_val |= ((1UL << q_idx) << NICVF_INTR_CQ_SHIFT); 20873c0086b8SZbigniew Bodek break; 20883c0086b8SZbigniew Bodek case NICVF_INTR_SQ: 20892306b72aSZbigniew Bodek reg_val |= ((1UL << q_idx) << NICVF_INTR_SQ_SHIFT); 20903c0086b8SZbigniew Bodek break; 20913c0086b8SZbigniew Bodek case NICVF_INTR_RBDR: 20922306b72aSZbigniew Bodek reg_val |= ((1UL << q_idx) << NICVF_INTR_RBDR_SHIFT); 20933c0086b8SZbigniew Bodek break; 20943c0086b8SZbigniew Bodek case NICVF_INTR_PKT_DROP: 20952306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_PKT_DROP_SHIFT); 20963c0086b8SZbigniew Bodek break; 20973c0086b8SZbigniew Bodek case NICVF_INTR_TCP_TIMER: 20982306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_TCP_TIMER_SHIFT); 20993c0086b8SZbigniew Bodek break; 21003c0086b8SZbigniew Bodek case NICVF_INTR_MBOX: 21012306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_MBOX_SHIFT); 21023c0086b8SZbigniew Bodek break; 21033c0086b8SZbigniew Bodek case NICVF_INTR_QS_ERR: 21042306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_QS_ERR_SHIFT); 21053c0086b8SZbigniew Bodek break; 21063c0086b8SZbigniew Bodek default: 21072306b72aSZbigniew Bodek device_printf(nic->dev, 21083c0086b8SZbigniew Bodek "Failed to disable interrupt: unknown type\n"); 21093c0086b8SZbigniew Bodek break; 21103c0086b8SZbigniew Bodek } 21113c0086b8SZbigniew Bodek 21123c0086b8SZbigniew Bodek nicvf_reg_write(nic, NIC_VF_ENA_W1C, reg_val); 21133c0086b8SZbigniew Bodek } 21143c0086b8SZbigniew Bodek 21153c0086b8SZbigniew Bodek /* Clear interrupt */ 21162306b72aSZbigniew Bodek void 21172306b72aSZbigniew Bodek nicvf_clear_intr(struct nicvf *nic, int int_type, int q_idx) 21183c0086b8SZbigniew Bodek { 21192306b72aSZbigniew Bodek uint64_t reg_val = 0; 21203c0086b8SZbigniew Bodek 21213c0086b8SZbigniew Bodek switch (int_type) { 21223c0086b8SZbigniew Bodek case NICVF_INTR_CQ: 21232306b72aSZbigniew Bodek reg_val = ((1UL << q_idx) << NICVF_INTR_CQ_SHIFT); 21243c0086b8SZbigniew Bodek break; 21253c0086b8SZbigniew Bodek case NICVF_INTR_SQ: 21262306b72aSZbigniew Bodek reg_val = ((1UL << q_idx) << NICVF_INTR_SQ_SHIFT); 21273c0086b8SZbigniew Bodek break; 21283c0086b8SZbigniew Bodek case NICVF_INTR_RBDR: 21292306b72aSZbigniew Bodek reg_val = ((1UL << q_idx) << NICVF_INTR_RBDR_SHIFT); 21303c0086b8SZbigniew Bodek break; 21313c0086b8SZbigniew Bodek case NICVF_INTR_PKT_DROP: 21322306b72aSZbigniew Bodek reg_val = (1UL << NICVF_INTR_PKT_DROP_SHIFT); 21333c0086b8SZbigniew Bodek break; 21343c0086b8SZbigniew Bodek case NICVF_INTR_TCP_TIMER: 21352306b72aSZbigniew Bodek reg_val = (1UL << NICVF_INTR_TCP_TIMER_SHIFT); 21363c0086b8SZbigniew Bodek break; 21373c0086b8SZbigniew Bodek case NICVF_INTR_MBOX: 21382306b72aSZbigniew Bodek reg_val = (1UL << NICVF_INTR_MBOX_SHIFT); 21393c0086b8SZbigniew Bodek break; 21403c0086b8SZbigniew Bodek case NICVF_INTR_QS_ERR: 21412306b72aSZbigniew Bodek reg_val |= (1UL << NICVF_INTR_QS_ERR_SHIFT); 21423c0086b8SZbigniew Bodek break; 21433c0086b8SZbigniew Bodek default: 21442306b72aSZbigniew Bodek device_printf(nic->dev, 21453c0086b8SZbigniew Bodek "Failed to clear interrupt: unknown type\n"); 21463c0086b8SZbigniew Bodek break; 21473c0086b8SZbigniew Bodek } 21483c0086b8SZbigniew Bodek 21493c0086b8SZbigniew Bodek nicvf_reg_write(nic, NIC_VF_INT, reg_val); 21503c0086b8SZbigniew Bodek } 21513c0086b8SZbigniew Bodek 21523c0086b8SZbigniew Bodek /* Check if interrupt is enabled */ 21532306b72aSZbigniew Bodek int 21542306b72aSZbigniew Bodek nicvf_is_intr_enabled(struct nicvf *nic, int int_type, int q_idx) 21553c0086b8SZbigniew Bodek { 21562306b72aSZbigniew Bodek uint64_t reg_val; 21572306b72aSZbigniew Bodek uint64_t mask = 0xff; 21583c0086b8SZbigniew Bodek 21593c0086b8SZbigniew Bodek reg_val = nicvf_reg_read(nic, NIC_VF_ENA_W1S); 21603c0086b8SZbigniew Bodek 21613c0086b8SZbigniew Bodek switch (int_type) { 21623c0086b8SZbigniew Bodek case NICVF_INTR_CQ: 21632306b72aSZbigniew Bodek mask = ((1UL << q_idx) << NICVF_INTR_CQ_SHIFT); 21643c0086b8SZbigniew Bodek break; 21653c0086b8SZbigniew Bodek case NICVF_INTR_SQ: 21662306b72aSZbigniew Bodek mask = ((1UL << q_idx) << NICVF_INTR_SQ_SHIFT); 21673c0086b8SZbigniew Bodek break; 21683c0086b8SZbigniew Bodek case NICVF_INTR_RBDR: 21692306b72aSZbigniew Bodek mask = ((1UL << q_idx) << NICVF_INTR_RBDR_SHIFT); 21703c0086b8SZbigniew Bodek break; 21713c0086b8SZbigniew Bodek case NICVF_INTR_PKT_DROP: 21723c0086b8SZbigniew Bodek mask = NICVF_INTR_PKT_DROP_MASK; 21733c0086b8SZbigniew Bodek break; 21743c0086b8SZbigniew Bodek case NICVF_INTR_TCP_TIMER: 21753c0086b8SZbigniew Bodek mask = NICVF_INTR_TCP_TIMER_MASK; 21763c0086b8SZbigniew Bodek break; 21773c0086b8SZbigniew Bodek case NICVF_INTR_MBOX: 21783c0086b8SZbigniew Bodek mask = NICVF_INTR_MBOX_MASK; 21793c0086b8SZbigniew Bodek break; 21803c0086b8SZbigniew Bodek case NICVF_INTR_QS_ERR: 21813c0086b8SZbigniew Bodek mask = NICVF_INTR_QS_ERR_MASK; 21823c0086b8SZbigniew Bodek break; 21833c0086b8SZbigniew Bodek default: 21842306b72aSZbigniew Bodek device_printf(nic->dev, 21853c0086b8SZbigniew Bodek "Failed to check interrupt enable: unknown type\n"); 21863c0086b8SZbigniew Bodek break; 21873c0086b8SZbigniew Bodek } 21883c0086b8SZbigniew Bodek 21893c0086b8SZbigniew Bodek return (reg_val & mask); 21903c0086b8SZbigniew Bodek } 21913c0086b8SZbigniew Bodek 21922306b72aSZbigniew Bodek void 21932306b72aSZbigniew Bodek nicvf_update_rq_stats(struct nicvf *nic, int rq_idx) 21943c0086b8SZbigniew Bodek { 21953c0086b8SZbigniew Bodek struct rcv_queue *rq; 21963c0086b8SZbigniew Bodek 21973c0086b8SZbigniew Bodek #define GET_RQ_STATS(reg) \ 21983c0086b8SZbigniew Bodek nicvf_reg_read(nic, NIC_QSET_RQ_0_7_STAT_0_1 |\ 21993c0086b8SZbigniew Bodek (rq_idx << NIC_Q_NUM_SHIFT) | (reg << 3)) 22003c0086b8SZbigniew Bodek 22013c0086b8SZbigniew Bodek rq = &nic->qs->rq[rq_idx]; 22023c0086b8SZbigniew Bodek rq->stats.bytes = GET_RQ_STATS(RQ_SQ_STATS_OCTS); 22033c0086b8SZbigniew Bodek rq->stats.pkts = GET_RQ_STATS(RQ_SQ_STATS_PKTS); 22043c0086b8SZbigniew Bodek } 22053c0086b8SZbigniew Bodek 22062306b72aSZbigniew Bodek void 22072306b72aSZbigniew Bodek nicvf_update_sq_stats(struct nicvf *nic, int sq_idx) 22083c0086b8SZbigniew Bodek { 22093c0086b8SZbigniew Bodek struct snd_queue *sq; 22103c0086b8SZbigniew Bodek 22113c0086b8SZbigniew Bodek #define GET_SQ_STATS(reg) \ 22123c0086b8SZbigniew Bodek nicvf_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1 |\ 22133c0086b8SZbigniew Bodek (sq_idx << NIC_Q_NUM_SHIFT) | (reg << 3)) 22143c0086b8SZbigniew Bodek 22153c0086b8SZbigniew Bodek sq = &nic->qs->sq[sq_idx]; 22163c0086b8SZbigniew Bodek sq->stats.bytes = GET_SQ_STATS(RQ_SQ_STATS_OCTS); 22173c0086b8SZbigniew Bodek sq->stats.pkts = GET_SQ_STATS(RQ_SQ_STATS_PKTS); 22183c0086b8SZbigniew Bodek } 22193c0086b8SZbigniew Bodek 22203c0086b8SZbigniew Bodek /* Check for errors in the receive cmp.queue entry */ 22212306b72aSZbigniew Bodek int 22222306b72aSZbigniew Bodek nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cmp_queue *cq, 22232306b72aSZbigniew Bodek struct cqe_rx_t *cqe_rx) 22243c0086b8SZbigniew Bodek { 22253c0086b8SZbigniew Bodek struct nicvf_hw_stats *stats = &nic->hw_stats; 22263c0086b8SZbigniew Bodek struct nicvf_drv_stats *drv_stats = &nic->drv_stats; 22273c0086b8SZbigniew Bodek 22283c0086b8SZbigniew Bodek if (!cqe_rx->err_level && !cqe_rx->err_opcode) { 22293c0086b8SZbigniew Bodek drv_stats->rx_frames_ok++; 22302306b72aSZbigniew Bodek return (0); 22313c0086b8SZbigniew Bodek } 22323c0086b8SZbigniew Bodek 22333c0086b8SZbigniew Bodek switch (cqe_rx->err_opcode) { 22343c0086b8SZbigniew Bodek case CQ_RX_ERROP_RE_PARTIAL: 22353c0086b8SZbigniew Bodek stats->rx_bgx_truncated_pkts++; 22363c0086b8SZbigniew Bodek break; 22373c0086b8SZbigniew Bodek case CQ_RX_ERROP_RE_JABBER: 22383c0086b8SZbigniew Bodek stats->rx_jabber_errs++; 22393c0086b8SZbigniew Bodek break; 22403c0086b8SZbigniew Bodek case CQ_RX_ERROP_RE_FCS: 22413c0086b8SZbigniew Bodek stats->rx_fcs_errs++; 22423c0086b8SZbigniew Bodek break; 22433c0086b8SZbigniew Bodek case CQ_RX_ERROP_RE_RX_CTL: 22443c0086b8SZbigniew Bodek stats->rx_bgx_errs++; 22453c0086b8SZbigniew Bodek break; 22463c0086b8SZbigniew Bodek case CQ_RX_ERROP_PREL2_ERR: 22473c0086b8SZbigniew Bodek stats->rx_prel2_errs++; 22483c0086b8SZbigniew Bodek break; 22493c0086b8SZbigniew Bodek case CQ_RX_ERROP_L2_MAL: 22503c0086b8SZbigniew Bodek stats->rx_l2_hdr_malformed++; 22513c0086b8SZbigniew Bodek break; 22523c0086b8SZbigniew Bodek case CQ_RX_ERROP_L2_OVERSIZE: 22533c0086b8SZbigniew Bodek stats->rx_oversize++; 22543c0086b8SZbigniew Bodek break; 22553c0086b8SZbigniew Bodek case CQ_RX_ERROP_L2_UNDERSIZE: 22563c0086b8SZbigniew Bodek stats->rx_undersize++; 22573c0086b8SZbigniew Bodek break; 22583c0086b8SZbigniew Bodek case CQ_RX_ERROP_L2_LENMISM: 22593c0086b8SZbigniew Bodek stats->rx_l2_len_mismatch++; 22603c0086b8SZbigniew Bodek break; 22613c0086b8SZbigniew Bodek case CQ_RX_ERROP_L2_PCLP: 22623c0086b8SZbigniew Bodek stats->rx_l2_pclp++; 22633c0086b8SZbigniew Bodek break; 22643c0086b8SZbigniew Bodek case CQ_RX_ERROP_IP_NOT: 22653c0086b8SZbigniew Bodek stats->rx_ip_ver_errs++; 22663c0086b8SZbigniew Bodek break; 22673c0086b8SZbigniew Bodek case CQ_RX_ERROP_IP_CSUM_ERR: 22683c0086b8SZbigniew Bodek stats->rx_ip_csum_errs++; 22693c0086b8SZbigniew Bodek break; 22703c0086b8SZbigniew Bodek case CQ_RX_ERROP_IP_MAL: 22713c0086b8SZbigniew Bodek stats->rx_ip_hdr_malformed++; 22723c0086b8SZbigniew Bodek break; 22733c0086b8SZbigniew Bodek case CQ_RX_ERROP_IP_MALD: 22743c0086b8SZbigniew Bodek stats->rx_ip_payload_malformed++; 22753c0086b8SZbigniew Bodek break; 22763c0086b8SZbigniew Bodek case CQ_RX_ERROP_IP_HOP: 22773c0086b8SZbigniew Bodek stats->rx_ip_ttl_errs++; 22783c0086b8SZbigniew Bodek break; 22793c0086b8SZbigniew Bodek case CQ_RX_ERROP_L3_PCLP: 22803c0086b8SZbigniew Bodek stats->rx_l3_pclp++; 22813c0086b8SZbigniew Bodek break; 22823c0086b8SZbigniew Bodek case CQ_RX_ERROP_L4_MAL: 22833c0086b8SZbigniew Bodek stats->rx_l4_malformed++; 22843c0086b8SZbigniew Bodek break; 22853c0086b8SZbigniew Bodek case CQ_RX_ERROP_L4_CHK: 22863c0086b8SZbigniew Bodek stats->rx_l4_csum_errs++; 22873c0086b8SZbigniew Bodek break; 22883c0086b8SZbigniew Bodek case CQ_RX_ERROP_UDP_LEN: 22893c0086b8SZbigniew Bodek stats->rx_udp_len_errs++; 22903c0086b8SZbigniew Bodek break; 22913c0086b8SZbigniew Bodek case CQ_RX_ERROP_L4_PORT: 22923c0086b8SZbigniew Bodek stats->rx_l4_port_errs++; 22933c0086b8SZbigniew Bodek break; 22943c0086b8SZbigniew Bodek case CQ_RX_ERROP_TCP_FLAG: 22953c0086b8SZbigniew Bodek stats->rx_tcp_flag_errs++; 22963c0086b8SZbigniew Bodek break; 22973c0086b8SZbigniew Bodek case CQ_RX_ERROP_TCP_OFFSET: 22983c0086b8SZbigniew Bodek stats->rx_tcp_offset_errs++; 22993c0086b8SZbigniew Bodek break; 23003c0086b8SZbigniew Bodek case CQ_RX_ERROP_L4_PCLP: 23013c0086b8SZbigniew Bodek stats->rx_l4_pclp++; 23023c0086b8SZbigniew Bodek break; 23033c0086b8SZbigniew Bodek case CQ_RX_ERROP_RBDR_TRUNC: 23043c0086b8SZbigniew Bodek stats->rx_truncated_pkts++; 23053c0086b8SZbigniew Bodek break; 23063c0086b8SZbigniew Bodek } 23073c0086b8SZbigniew Bodek 23082306b72aSZbigniew Bodek return (1); 23093c0086b8SZbigniew Bodek } 23103c0086b8SZbigniew Bodek 23113c0086b8SZbigniew Bodek /* Check for errors in the send cmp.queue entry */ 23122306b72aSZbigniew Bodek int 23132306b72aSZbigniew Bodek nicvf_check_cqe_tx_errs(struct nicvf *nic, struct cmp_queue *cq, 23142306b72aSZbigniew Bodek struct cqe_send_t *cqe_tx) 23153c0086b8SZbigniew Bodek { 23163c0086b8SZbigniew Bodek struct cmp_queue_stats *stats = &cq->stats; 23173c0086b8SZbigniew Bodek 23183c0086b8SZbigniew Bodek switch (cqe_tx->send_status) { 23193c0086b8SZbigniew Bodek case CQ_TX_ERROP_GOOD: 23203c0086b8SZbigniew Bodek stats->tx.good++; 23212306b72aSZbigniew Bodek return (0); 23223c0086b8SZbigniew Bodek case CQ_TX_ERROP_DESC_FAULT: 23233c0086b8SZbigniew Bodek stats->tx.desc_fault++; 23243c0086b8SZbigniew Bodek break; 23253c0086b8SZbigniew Bodek case CQ_TX_ERROP_HDR_CONS_ERR: 23263c0086b8SZbigniew Bodek stats->tx.hdr_cons_err++; 23273c0086b8SZbigniew Bodek break; 23283c0086b8SZbigniew Bodek case CQ_TX_ERROP_SUBDC_ERR: 23293c0086b8SZbigniew Bodek stats->tx.subdesc_err++; 23303c0086b8SZbigniew Bodek break; 23313c0086b8SZbigniew Bodek case CQ_TX_ERROP_IMM_SIZE_OFLOW: 23323c0086b8SZbigniew Bodek stats->tx.imm_size_oflow++; 23333c0086b8SZbigniew Bodek break; 23343c0086b8SZbigniew Bodek case CQ_TX_ERROP_DATA_SEQUENCE_ERR: 23353c0086b8SZbigniew Bodek stats->tx.data_seq_err++; 23363c0086b8SZbigniew Bodek break; 23373c0086b8SZbigniew Bodek case CQ_TX_ERROP_MEM_SEQUENCE_ERR: 23383c0086b8SZbigniew Bodek stats->tx.mem_seq_err++; 23393c0086b8SZbigniew Bodek break; 23403c0086b8SZbigniew Bodek case CQ_TX_ERROP_LOCK_VIOL: 23413c0086b8SZbigniew Bodek stats->tx.lock_viol++; 23423c0086b8SZbigniew Bodek break; 23433c0086b8SZbigniew Bodek case CQ_TX_ERROP_DATA_FAULT: 23443c0086b8SZbigniew Bodek stats->tx.data_fault++; 23453c0086b8SZbigniew Bodek break; 23463c0086b8SZbigniew Bodek case CQ_TX_ERROP_TSTMP_CONFLICT: 23473c0086b8SZbigniew Bodek stats->tx.tstmp_conflict++; 23483c0086b8SZbigniew Bodek break; 23493c0086b8SZbigniew Bodek case CQ_TX_ERROP_TSTMP_TIMEOUT: 23503c0086b8SZbigniew Bodek stats->tx.tstmp_timeout++; 23513c0086b8SZbigniew Bodek break; 23523c0086b8SZbigniew Bodek case CQ_TX_ERROP_MEM_FAULT: 23533c0086b8SZbigniew Bodek stats->tx.mem_fault++; 23543c0086b8SZbigniew Bodek break; 23553c0086b8SZbigniew Bodek case CQ_TX_ERROP_CK_OVERLAP: 23563c0086b8SZbigniew Bodek stats->tx.csum_overlap++; 23573c0086b8SZbigniew Bodek break; 23583c0086b8SZbigniew Bodek case CQ_TX_ERROP_CK_OFLOW: 23593c0086b8SZbigniew Bodek stats->tx.csum_overflow++; 23603c0086b8SZbigniew Bodek break; 23613c0086b8SZbigniew Bodek } 23623c0086b8SZbigniew Bodek 23632306b72aSZbigniew Bodek return (1); 23643c0086b8SZbigniew Bodek } 2365