1b6d90eb7SKip Macy /**************************************************************************
24d846d26SWarner Losh SPDX-License-Identifier: BSD-2-Clause
3b6d90eb7SKip Macy
4f2d8ff04SGeorge V. Neville-Neil Copyright (c) 2007-2009, Chelsio Inc.
5b6d90eb7SKip Macy All rights reserved.
6b6d90eb7SKip Macy
7b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without
8b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met:
9b6d90eb7SKip Macy
10b6d90eb7SKip Macy 1. Redistributions of source code must retain the above copyright notice,
11b6d90eb7SKip Macy this list of conditions and the following disclaimer.
12b6d90eb7SKip Macy
13d722cab4SKip Macy 2. Neither the name of the Chelsio Corporation nor the names of its
14b6d90eb7SKip Macy contributors may be used to endorse or promote products derived from
15b6d90eb7SKip Macy this software without specific prior written permission.
16b6d90eb7SKip Macy
17b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE.
28b6d90eb7SKip Macy
29b6d90eb7SKip Macy ***************************************************************************/
30b6d90eb7SKip Macy
31b6d90eb7SKip Macy #include <sys/cdefs.h>
3247cfa99aSBjoern A. Zeeb #include "opt_inet6.h"
3363122c7eSNavdeep Parhar #include "opt_inet.h"
3463122c7eSNavdeep Parhar
35b6d90eb7SKip Macy #include <sys/param.h>
36b6d90eb7SKip Macy #include <sys/systm.h>
37b6d90eb7SKip Macy #include <sys/kernel.h>
38b6d90eb7SKip Macy #include <sys/module.h>
39b6d90eb7SKip Macy #include <sys/bus.h>
40b6d90eb7SKip Macy #include <sys/conf.h>
41b6d90eb7SKip Macy #include <machine/bus.h>
42b6d90eb7SKip Macy #include <machine/resource.h>
43b6d90eb7SKip Macy #include <sys/rman.h>
44b6d90eb7SKip Macy #include <sys/queue.h>
45b6d90eb7SKip Macy #include <sys/sysctl.h>
46b6d90eb7SKip Macy #include <sys/taskqueue.h>
47b6d90eb7SKip Macy
48b6d90eb7SKip Macy #include <sys/proc.h>
49f001b63dSKip Macy #include <sys/sbuf.h>
50b6d90eb7SKip Macy #include <sys/sched.h>
51b6d90eb7SKip Macy #include <sys/smp.h>
52693d746cSKip Macy #include <sys/systm.h>
538090c9f5SKip Macy #include <sys/syslog.h>
54f9c6e164SNavdeep Parhar #include <sys/socket.h>
5509fe6320SNavdeep Parhar #include <sys/sglist.h>
56b6d90eb7SKip Macy
57c3322cb9SGleb Smirnoff #include <net/if.h>
58c3322cb9SGleb Smirnoff #include <net/if_var.h>
593f345a5dSKip Macy #include <net/bpf.h>
60f9c6e164SNavdeep Parhar #include <net/ethernet.h>
61f9c6e164SNavdeep Parhar #include <net/if_vlan_var.h>
623f345a5dSKip Macy
63b6d90eb7SKip Macy #include <netinet/in_systm.h>
64b6d90eb7SKip Macy #include <netinet/in.h>
65b6d90eb7SKip Macy #include <netinet/ip.h>
663e7cc3caSNavdeep Parhar #include <netinet/ip6.h>
67b6d90eb7SKip Macy #include <netinet/tcp.h>
68b6d90eb7SKip Macy
69b6d90eb7SKip Macy #include <dev/pci/pcireg.h>
70b6d90eb7SKip Macy #include <dev/pci/pcivar.h>
71b6d90eb7SKip Macy
7201cf8d43SKip Macy #include <vm/vm.h>
738090c9f5SKip Macy #include <vm/pmap.h>
74fc5a2e51SKip Macy
7510faa568SKip Macy #include <cxgb_include.h>
7601cf8d43SKip Macy #include <sys/mvec.h>
77c0a24dd4SKip Macy
78b8fe6051SKip Macy int txq_fills = 0;
793f345a5dSKip Macy int multiq_tx_enable = 1;
803f345a5dSKip Macy
8109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
8209fe6320SNavdeep Parhar CTASSERT(NUM_CPL_HANDLERS >= NUM_CPL_CMDS);
8309fe6320SNavdeep Parhar #endif
8409fe6320SNavdeep Parhar
853f345a5dSKip Macy extern struct sysctl_oid_list sysctl__hw_cxgb_children;
863f345a5dSKip Macy int cxgb_txq_buf_ring_size = TX_ETH_Q_SIZE;
87deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, txq_mr_size, CTLFLAG_RDTUN, &cxgb_txq_buf_ring_size, 0,
883f345a5dSKip Macy "size of per-queue mbuf ring");
893f345a5dSKip Macy
903f345a5dSKip Macy static int cxgb_tx_coalesce_force = 0;
91af3b2549SHans Petter Selasky SYSCTL_INT(_hw_cxgb, OID_AUTO, tx_coalesce_force, CTLFLAG_RWTUN,
923f345a5dSKip Macy &cxgb_tx_coalesce_force, 0,
933f345a5dSKip Macy "coalesce small packets into a single work request regardless of ring state");
943f345a5dSKip Macy
953f345a5dSKip Macy #define COALESCE_START_DEFAULT TX_ETH_Q_SIZE>>1
963f345a5dSKip Macy #define COALESCE_START_MAX (TX_ETH_Q_SIZE-(TX_ETH_Q_SIZE>>3))
973f345a5dSKip Macy #define COALESCE_STOP_DEFAULT TX_ETH_Q_SIZE>>2
983f345a5dSKip Macy #define COALESCE_STOP_MIN TX_ETH_Q_SIZE>>5
993f345a5dSKip Macy #define TX_RECLAIM_DEFAULT TX_ETH_Q_SIZE>>5
1003f345a5dSKip Macy #define TX_RECLAIM_MAX TX_ETH_Q_SIZE>>2
1013f345a5dSKip Macy #define TX_RECLAIM_MIN TX_ETH_Q_SIZE>>6
1023f345a5dSKip Macy
1033f345a5dSKip Macy
1043f345a5dSKip Macy static int cxgb_tx_coalesce_enable_start = COALESCE_START_DEFAULT;
105af3b2549SHans Petter Selasky SYSCTL_INT(_hw_cxgb, OID_AUTO, tx_coalesce_enable_start, CTLFLAG_RWTUN,
1063f345a5dSKip Macy &cxgb_tx_coalesce_enable_start, 0,
1073f345a5dSKip Macy "coalesce enable threshold");
1083f345a5dSKip Macy static int cxgb_tx_coalesce_enable_stop = COALESCE_STOP_DEFAULT;
109af3b2549SHans Petter Selasky SYSCTL_INT(_hw_cxgb, OID_AUTO, tx_coalesce_enable_stop, CTLFLAG_RWTUN,
1103f345a5dSKip Macy &cxgb_tx_coalesce_enable_stop, 0,
1113f345a5dSKip Macy "coalesce disable threshold");
1123f345a5dSKip Macy static int cxgb_tx_reclaim_threshold = TX_RECLAIM_DEFAULT;
113af3b2549SHans Petter Selasky SYSCTL_INT(_hw_cxgb, OID_AUTO, tx_reclaim_threshold, CTLFLAG_RWTUN,
1143f345a5dSKip Macy &cxgb_tx_reclaim_threshold, 0,
1153f345a5dSKip Macy "tx cleaning minimum threshold");
1163f345a5dSKip Macy
1178e10660fSKip Macy /*
1188e10660fSKip Macy * XXX don't re-enable this until TOE stops assuming
1198e10660fSKip Macy * we have an m_ext
1208e10660fSKip Macy */
1218e10660fSKip Macy static int recycle_enable = 0;
122f705d735SKip Macy
123f001b63dSKip Macy extern int cxgb_use_16k_clusters;
12497ae3bc3SNavdeep Parhar extern int nmbjumbop;
125f705d735SKip Macy extern int nmbjumbo9;
126f705d735SKip Macy extern int nmbjumbo16;
12751580731SKip Macy
128b6d90eb7SKip Macy #define USE_GTS 0
129b6d90eb7SKip Macy
130b6d90eb7SKip Macy #define SGE_RX_SM_BUF_SIZE 1536
131b6d90eb7SKip Macy #define SGE_RX_DROP_THRES 16
132d722cab4SKip Macy #define SGE_RX_COPY_THRES 128
133b6d90eb7SKip Macy
134b6d90eb7SKip Macy /*
135b6d90eb7SKip Macy * Period of the Tx buffer reclaim timer. This timer does not need to run
136b6d90eb7SKip Macy * frequently as Tx buffers are usually reclaimed by new Tx packets.
137b6d90eb7SKip Macy */
13804ad3390SKip Macy #define TX_RECLAIM_PERIOD (hz >> 1)
139b6d90eb7SKip Macy
140b6d90eb7SKip Macy /*
141b6d90eb7SKip Macy * Values for sge_txq.flags
142b6d90eb7SKip Macy */
143b6d90eb7SKip Macy enum {
144b6d90eb7SKip Macy TXQ_RUNNING = 1 << 0, /* fetch engine is running */
145b6d90eb7SKip Macy TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */
146b6d90eb7SKip Macy };
147b6d90eb7SKip Macy
148b6d90eb7SKip Macy struct tx_desc {
149b6d90eb7SKip Macy uint64_t flit[TX_DESC_FLITS];
150b6d90eb7SKip Macy } __packed;
151b6d90eb7SKip Macy
152b6d90eb7SKip Macy struct rx_desc {
153b6d90eb7SKip Macy uint32_t addr_lo;
154b6d90eb7SKip Macy uint32_t len_gen;
155b6d90eb7SKip Macy uint32_t gen2;
156b6d90eb7SKip Macy uint32_t addr_hi;
157c2ede4b3SMartin Blapp } __packed;
158b6d90eb7SKip Macy
159b6d90eb7SKip Macy struct rsp_desc { /* response queue descriptor */
160b6d90eb7SKip Macy struct rss_header rss_hdr;
161b6d90eb7SKip Macy uint32_t flags;
162b6d90eb7SKip Macy uint32_t len_cq;
163b6d90eb7SKip Macy uint8_t imm_data[47];
164b6d90eb7SKip Macy uint8_t intr_gen;
165b6d90eb7SKip Macy } __packed;
166b6d90eb7SKip Macy
167b6d90eb7SKip Macy #define RX_SW_DESC_MAP_CREATED (1 << 0)
16851580731SKip Macy #define TX_SW_DESC_MAP_CREATED (1 << 1)
169b6d90eb7SKip Macy #define RX_SW_DESC_INUSE (1 << 3)
170b6d90eb7SKip Macy #define TX_SW_DESC_MAPPED (1 << 4)
171b6d90eb7SKip Macy
172b6d90eb7SKip Macy #define RSPQ_NSOP_NEOP G_RSPD_SOP_EOP(0)
173b6d90eb7SKip Macy #define RSPQ_EOP G_RSPD_SOP_EOP(F_RSPD_EOP)
174b6d90eb7SKip Macy #define RSPQ_SOP G_RSPD_SOP_EOP(F_RSPD_SOP)
175b6d90eb7SKip Macy #define RSPQ_SOP_EOP G_RSPD_SOP_EOP(F_RSPD_SOP|F_RSPD_EOP)
176b6d90eb7SKip Macy
177b6d90eb7SKip Macy struct tx_sw_desc { /* SW state per Tx descriptor */
1783f345a5dSKip Macy struct mbuf *m;
179b6d90eb7SKip Macy bus_dmamap_t map;
180b6d90eb7SKip Macy int flags;
181b6d90eb7SKip Macy };
182b6d90eb7SKip Macy
183b6d90eb7SKip Macy struct rx_sw_desc { /* SW state per Rx descriptor */
1848090c9f5SKip Macy caddr_t rxsd_cl;
1853f345a5dSKip Macy struct mbuf *m;
186b6d90eb7SKip Macy bus_dmamap_t map;
187b6d90eb7SKip Macy int flags;
188b6d90eb7SKip Macy };
189b6d90eb7SKip Macy
190b6d90eb7SKip Macy struct txq_state {
191b6d90eb7SKip Macy unsigned int compl;
192b6d90eb7SKip Macy unsigned int gen;
193b6d90eb7SKip Macy unsigned int pidx;
194b6d90eb7SKip Macy };
195b6d90eb7SKip Macy
196fa0521c0SKip Macy struct refill_fl_cb_arg {
197fa0521c0SKip Macy int error;
198fa0521c0SKip Macy bus_dma_segment_t seg;
199fa0521c0SKip Macy int nseg;
200fa0521c0SKip Macy };
201fa0521c0SKip Macy
2023f345a5dSKip Macy
203b6d90eb7SKip Macy /*
204b6d90eb7SKip Macy * Maps a number of flits to the number of Tx descriptors that can hold them.
205b6d90eb7SKip Macy * The formula is
206b6d90eb7SKip Macy *
207b6d90eb7SKip Macy * desc = 1 + (flits - 2) / (WR_FLITS - 1).
208b6d90eb7SKip Macy *
209b6d90eb7SKip Macy * HW allows up to 4 descriptors to be combined into a WR.
210b6d90eb7SKip Macy */
211b6d90eb7SKip Macy static uint8_t flit_desc_map[] = {
212b6d90eb7SKip Macy 0,
213b6d90eb7SKip Macy #if SGE_NUM_GENBITS == 1
214b6d90eb7SKip Macy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
215b6d90eb7SKip Macy 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
216b6d90eb7SKip Macy 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
217b6d90eb7SKip Macy 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
218b6d90eb7SKip Macy #elif SGE_NUM_GENBITS == 2
219b6d90eb7SKip Macy 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
220b6d90eb7SKip Macy 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
221b6d90eb7SKip Macy 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
222b6d90eb7SKip Macy 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
223b6d90eb7SKip Macy #else
224b6d90eb7SKip Macy # error "SGE_NUM_GENBITS must be 1 or 2"
225b6d90eb7SKip Macy #endif
226b6d90eb7SKip Macy };
227b6d90eb7SKip Macy
2283f345a5dSKip Macy #define TXQ_LOCK_ASSERT(qs) mtx_assert(&(qs)->lock, MA_OWNED)
2293f345a5dSKip Macy #define TXQ_TRYLOCK(qs) mtx_trylock(&(qs)->lock)
2303f345a5dSKip Macy #define TXQ_LOCK(qs) mtx_lock(&(qs)->lock)
2313f345a5dSKip Macy #define TXQ_UNLOCK(qs) mtx_unlock(&(qs)->lock)
2323f345a5dSKip Macy #define TXQ_RING_EMPTY(qs) drbr_empty((qs)->port->ifp, (qs)->txq[TXQ_ETH].txq_mr)
233193cbc4dSMax Laier #define TXQ_RING_NEEDS_ENQUEUE(qs) \
234193cbc4dSMax Laier drbr_needs_enqueue((qs)->port->ifp, (qs)->txq[TXQ_ETH].txq_mr)
2353f345a5dSKip Macy #define TXQ_RING_FLUSH(qs) drbr_flush((qs)->port->ifp, (qs)->txq[TXQ_ETH].txq_mr)
2363f345a5dSKip Macy #define TXQ_RING_DEQUEUE_COND(qs, func, arg) \
2373f345a5dSKip Macy drbr_dequeue_cond((qs)->port->ifp, (qs)->txq[TXQ_ETH].txq_mr, func, arg)
2383f345a5dSKip Macy #define TXQ_RING_DEQUEUE(qs) \
2393f345a5dSKip Macy drbr_dequeue((qs)->port->ifp, (qs)->txq[TXQ_ETH].txq_mr)
240b6d90eb7SKip Macy
241b6d90eb7SKip Macy int cxgb_debug = 0;
242b6d90eb7SKip Macy
243b6d90eb7SKip Macy static void sge_timer_cb(void *arg);
244b6d90eb7SKip Macy static void sge_timer_reclaim(void *arg, int ncount);
245b8fe6051SKip Macy static void sge_txq_reclaim_handler(void *arg, int ncount);
2463f345a5dSKip Macy static void cxgb_start_locked(struct sge_qset *qs);
2473f345a5dSKip Macy
2483f345a5dSKip Macy /*
2493f345a5dSKip Macy * XXX need to cope with bursty scheduling by looking at a wider
2503f345a5dSKip Macy * window than we are now for determining the need for coalescing
2513f345a5dSKip Macy *
2523f345a5dSKip Macy */
2533f345a5dSKip Macy static __inline uint64_t
check_pkt_coalesce(struct sge_qset * qs)2543f345a5dSKip Macy check_pkt_coalesce(struct sge_qset *qs)
2553f345a5dSKip Macy {
2563f345a5dSKip Macy struct adapter *sc;
2573f345a5dSKip Macy struct sge_txq *txq;
2583f345a5dSKip Macy uint8_t *fill;
2593f345a5dSKip Macy
2603f345a5dSKip Macy if (__predict_false(cxgb_tx_coalesce_force))
2613f345a5dSKip Macy return (1);
2623f345a5dSKip Macy txq = &qs->txq[TXQ_ETH];
2633f345a5dSKip Macy sc = qs->port->adapter;
2643f345a5dSKip Macy fill = &sc->tunq_fill[qs->idx];
2653f345a5dSKip Macy
2663f345a5dSKip Macy if (cxgb_tx_coalesce_enable_start > COALESCE_START_MAX)
2673f345a5dSKip Macy cxgb_tx_coalesce_enable_start = COALESCE_START_MAX;
2683f345a5dSKip Macy if (cxgb_tx_coalesce_enable_stop < COALESCE_STOP_MIN)
26953734ccdSTed Spence cxgb_tx_coalesce_enable_stop = COALESCE_STOP_MIN;
2703f345a5dSKip Macy /*
2713f345a5dSKip Macy * if the hardware transmit queue is more than 1/8 full
2723f345a5dSKip Macy * we mark it as coalescing - we drop back from coalescing
2733f345a5dSKip Macy * when we go below 1/32 full and there are no packets enqueued,
2743f345a5dSKip Macy * this provides us with some degree of hysteresis
2753f345a5dSKip Macy */
2763f345a5dSKip Macy if (*fill != 0 && (txq->in_use <= cxgb_tx_coalesce_enable_stop) &&
2773f345a5dSKip Macy TXQ_RING_EMPTY(qs) && (qs->coalescing == 0))
2783f345a5dSKip Macy *fill = 0;
2793f345a5dSKip Macy else if (*fill == 0 && (txq->in_use >= cxgb_tx_coalesce_enable_start))
2803f345a5dSKip Macy *fill = 1;
2813f345a5dSKip Macy
2823f345a5dSKip Macy return (sc->tunq_coalesce);
2833f345a5dSKip Macy }
2843f345a5dSKip Macy
2853f345a5dSKip Macy #ifdef __LP64__
2863f345a5dSKip Macy static void
set_wr_hdr(struct work_request_hdr * wrp,uint32_t wr_hi,uint32_t wr_lo)2873f345a5dSKip Macy set_wr_hdr(struct work_request_hdr *wrp, uint32_t wr_hi, uint32_t wr_lo)
2883f345a5dSKip Macy {
2893f345a5dSKip Macy uint64_t wr_hilo;
2903f345a5dSKip Macy #if _BYTE_ORDER == _LITTLE_ENDIAN
2913f345a5dSKip Macy wr_hilo = wr_hi;
2923f345a5dSKip Macy wr_hilo |= (((uint64_t)wr_lo)<<32);
2933f345a5dSKip Macy #else
2943f345a5dSKip Macy wr_hilo = wr_lo;
2953f345a5dSKip Macy wr_hilo |= (((uint64_t)wr_hi)<<32);
2963f345a5dSKip Macy #endif
2973f345a5dSKip Macy wrp->wrh_hilo = wr_hilo;
2983f345a5dSKip Macy }
2993f345a5dSKip Macy #else
3003f345a5dSKip Macy static void
set_wr_hdr(struct work_request_hdr * wrp,uint32_t wr_hi,uint32_t wr_lo)3013f345a5dSKip Macy set_wr_hdr(struct work_request_hdr *wrp, uint32_t wr_hi, uint32_t wr_lo)
3023f345a5dSKip Macy {
3033f345a5dSKip Macy
3043f345a5dSKip Macy wrp->wrh_hi = wr_hi;
3053f345a5dSKip Macy wmb();
3063f345a5dSKip Macy wrp->wrh_lo = wr_lo;
3073f345a5dSKip Macy }
3083f345a5dSKip Macy #endif
3093f345a5dSKip Macy
3103f345a5dSKip Macy struct coalesce_info {
3113f345a5dSKip Macy int count;
3123f345a5dSKip Macy int nbytes;
313d510bf13SAlexander Motin int noncoal;
3143f345a5dSKip Macy };
3153f345a5dSKip Macy
3163f345a5dSKip Macy static int
coalesce_check(struct mbuf * m,void * arg)3173f345a5dSKip Macy coalesce_check(struct mbuf *m, void *arg)
3183f345a5dSKip Macy {
3193f345a5dSKip Macy struct coalesce_info *ci = arg;
3203f345a5dSKip Macy
321d510bf13SAlexander Motin if ((m->m_next != NULL) ||
322d510bf13SAlexander Motin ((mtod(m, vm_offset_t) & PAGE_MASK) + m->m_len > PAGE_SIZE))
323d510bf13SAlexander Motin ci->noncoal = 1;
324d510bf13SAlexander Motin
325d510bf13SAlexander Motin if ((ci->count == 0) || (ci->noncoal == 0 && (ci->count < 7) &&
326d510bf13SAlexander Motin (ci->nbytes + m->m_len <= 10500))) {
327d510bf13SAlexander Motin ci->count++;
328d510bf13SAlexander Motin ci->nbytes += m->m_len;
3293f345a5dSKip Macy return (1);
3303f345a5dSKip Macy }
3313f345a5dSKip Macy return (0);
3323f345a5dSKip Macy }
3333f345a5dSKip Macy
3343f345a5dSKip Macy static struct mbuf *
cxgb_dequeue(struct sge_qset * qs)3353f345a5dSKip Macy cxgb_dequeue(struct sge_qset *qs)
3363f345a5dSKip Macy {
3373f345a5dSKip Macy struct mbuf *m, *m_head, *m_tail;
3383f345a5dSKip Macy struct coalesce_info ci;
3393f345a5dSKip Macy
3403f345a5dSKip Macy
3413f345a5dSKip Macy if (check_pkt_coalesce(qs) == 0)
3423f345a5dSKip Macy return TXQ_RING_DEQUEUE(qs);
3433f345a5dSKip Macy
3443f345a5dSKip Macy m_head = m_tail = NULL;
345d510bf13SAlexander Motin ci.count = ci.nbytes = ci.noncoal = 0;
3463f345a5dSKip Macy do {
3473f345a5dSKip Macy m = TXQ_RING_DEQUEUE_COND(qs, coalesce_check, &ci);
3483f345a5dSKip Macy if (m_head == NULL) {
3493f345a5dSKip Macy m_tail = m_head = m;
3503f345a5dSKip Macy } else if (m != NULL) {
3513f345a5dSKip Macy m_tail->m_nextpkt = m;
3523f345a5dSKip Macy m_tail = m;
3533f345a5dSKip Macy }
3543f345a5dSKip Macy } while (m != NULL);
3553f345a5dSKip Macy if (ci.count > 7)
3563f345a5dSKip Macy panic("trying to coalesce %d packets in to one WR", ci.count);
3573f345a5dSKip Macy return (m_head);
3583f345a5dSKip Macy }
359b6d90eb7SKip Macy
360b6d90eb7SKip Macy /**
361b6d90eb7SKip Macy * reclaim_completed_tx - reclaims completed Tx descriptors
362b6d90eb7SKip Macy * @adapter: the adapter
363b6d90eb7SKip Macy * @q: the Tx queue to reclaim completed descriptors from
364b6d90eb7SKip Macy *
365b6d90eb7SKip Macy * Reclaims Tx descriptors that the SGE has indicated it has processed,
366b6d90eb7SKip Macy * and frees the associated buffers if possible. Called with the Tx
367b6d90eb7SKip Macy * queue's lock held.
368b6d90eb7SKip Macy */
369b6d90eb7SKip Macy static __inline int
reclaim_completed_tx(struct sge_qset * qs,int reclaim_min,int queue)3703f345a5dSKip Macy reclaim_completed_tx(struct sge_qset *qs, int reclaim_min, int queue)
371b6d90eb7SKip Macy {
3723f345a5dSKip Macy struct sge_txq *q = &qs->txq[queue];
3738090c9f5SKip Macy int reclaim = desc_reclaimable(q);
374b6d90eb7SKip Macy
3753f345a5dSKip Macy if ((cxgb_tx_reclaim_threshold > TX_RECLAIM_MAX) ||
3763f345a5dSKip Macy (cxgb_tx_reclaim_threshold < TX_RECLAIM_MIN))
3773f345a5dSKip Macy cxgb_tx_reclaim_threshold = TX_RECLAIM_DEFAULT;
3783f345a5dSKip Macy
3799330dbc3SKip Macy if (reclaim < reclaim_min)
3809330dbc3SKip Macy return (0);
3819330dbc3SKip Macy
3823f345a5dSKip Macy mtx_assert(&qs->lock, MA_OWNED);
383b6d90eb7SKip Macy if (reclaim > 0) {
3843f345a5dSKip Macy t3_free_tx_desc(qs, reclaim, queue);
3858090c9f5SKip Macy q->cleaned += reclaim;
3868090c9f5SKip Macy q->in_use -= reclaim;
387b6d90eb7SKip Macy }
3883f345a5dSKip Macy if (isset(&qs->txq_stopped, TXQ_ETH))
3893f345a5dSKip Macy clrbit(&qs->txq_stopped, TXQ_ETH);
3903f345a5dSKip Macy
3918090c9f5SKip Macy return (reclaim);
392b6d90eb7SKip Macy }
393b6d90eb7SKip Macy
3947790c8c1SConrad Meyer #ifdef DEBUGNET
395eb07d67eSMark Johnston int
cxgb_debugnet_poll_tx(struct sge_qset * qs)3967790c8c1SConrad Meyer cxgb_debugnet_poll_tx(struct sge_qset *qs)
397eb07d67eSMark Johnston {
398eb07d67eSMark Johnston
399eb07d67eSMark Johnston return (reclaim_completed_tx(qs, TX_RECLAIM_MAX, TXQ_ETH));
400eb07d67eSMark Johnston }
401eb07d67eSMark Johnston #endif
402eb07d67eSMark Johnston
403b6d90eb7SKip Macy /**
404d722cab4SKip Macy * should_restart_tx - are there enough resources to restart a Tx queue?
405d722cab4SKip Macy * @q: the Tx queue
406d722cab4SKip Macy *
407d722cab4SKip Macy * Checks if there are enough descriptors to restart a suspended Tx queue.
408d722cab4SKip Macy */
409d722cab4SKip Macy static __inline int
should_restart_tx(const struct sge_txq * q)410d722cab4SKip Macy should_restart_tx(const struct sge_txq *q)
411d722cab4SKip Macy {
412d722cab4SKip Macy unsigned int r = q->processed - q->cleaned;
413d722cab4SKip Macy
414d722cab4SKip Macy return q->in_use - r < (q->size >> 1);
415d722cab4SKip Macy }
416d722cab4SKip Macy
417d722cab4SKip Macy /**
418b6d90eb7SKip Macy * t3_sge_init - initialize SGE
419b6d90eb7SKip Macy * @adap: the adapter
420b6d90eb7SKip Macy * @p: the SGE parameters
421b6d90eb7SKip Macy *
422b6d90eb7SKip Macy * Performs SGE initialization needed every time after a chip reset.
423b6d90eb7SKip Macy * We do not initialize any of the queue sets here, instead the driver
424b6d90eb7SKip Macy * top-level must request those individually. We also do not enable DMA
425b6d90eb7SKip Macy * here, that should be done after the queues have been set up.
426b6d90eb7SKip Macy */
427b6d90eb7SKip Macy void
t3_sge_init(adapter_t * adap,struct sge_params * p)428b6d90eb7SKip Macy t3_sge_init(adapter_t *adap, struct sge_params *p)
429b6d90eb7SKip Macy {
430b6d90eb7SKip Macy u_int ctrl, ups;
431b6d90eb7SKip Macy
432b6d90eb7SKip Macy ups = 0; /* = ffs(pci_resource_len(adap->pdev, 2) >> 12); */
433b6d90eb7SKip Macy
434b6d90eb7SKip Macy ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
4358e10660fSKip Macy F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN |
436b6d90eb7SKip Macy V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
437b6d90eb7SKip Macy V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
438b6d90eb7SKip Macy #if SGE_NUM_GENBITS == 1
439b6d90eb7SKip Macy ctrl |= F_EGRGENCTRL;
440b6d90eb7SKip Macy #endif
441b6d90eb7SKip Macy if (adap->params.rev > 0) {
442b6d90eb7SKip Macy if (!(adap->flags & (USING_MSIX | USING_MSI)))
443b6d90eb7SKip Macy ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
444b6d90eb7SKip Macy }
445b6d90eb7SKip Macy t3_write_reg(adap, A_SG_CONTROL, ctrl);
446b6d90eb7SKip Macy t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
447b6d90eb7SKip Macy V_LORCQDRBTHRSH(512));
448b6d90eb7SKip Macy t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
449b6d90eb7SKip Macy t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
450b6d90eb7SKip Macy V_TIMEOUT(200 * core_ticks_per_usec(adap)));
4518e10660fSKip Macy t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH,
4528e10660fSKip Macy adap->params.rev < T3_REV_C ? 1000 : 500);
453b6d90eb7SKip Macy t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
454b6d90eb7SKip Macy t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
455b6d90eb7SKip Macy t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
456b6d90eb7SKip Macy t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff));
457b6d90eb7SKip Macy t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024);
458b6d90eb7SKip Macy }
459b6d90eb7SKip Macy
460b6d90eb7SKip Macy
461b6d90eb7SKip Macy /**
462b6d90eb7SKip Macy * sgl_len - calculates the size of an SGL of the given capacity
463b6d90eb7SKip Macy * @n: the number of SGL entries
464b6d90eb7SKip Macy *
465b6d90eb7SKip Macy * Calculates the number of flits needed for a scatter/gather list that
466b6d90eb7SKip Macy * can hold the given number of entries.
467b6d90eb7SKip Macy */
468b6d90eb7SKip Macy static __inline unsigned int
sgl_len(unsigned int n)469b6d90eb7SKip Macy sgl_len(unsigned int n)
470b6d90eb7SKip Macy {
471b6d90eb7SKip Macy return ((3 * n) / 2 + (n & 1));
472b6d90eb7SKip Macy }
473b6d90eb7SKip Macy
474b6d90eb7SKip Macy /**
475b6d90eb7SKip Macy * get_imm_packet - return the next ingress packet buffer from a response
476b6d90eb7SKip Macy * @resp: the response descriptor containing the packet data
477b6d90eb7SKip Macy *
478b6d90eb7SKip Macy * Return a packet containing the immediate data of the given response.
479b6d90eb7SKip Macy */
480ac3a6d9cSKip Macy static int
get_imm_packet(adapter_t * sc,const struct rsp_desc * resp,struct mbuf * m)4818e10660fSKip Macy get_imm_packet(adapter_t *sc, const struct rsp_desc *resp, struct mbuf *m)
482b6d90eb7SKip Macy {
483b6d90eb7SKip Macy
48409fe6320SNavdeep Parhar if (resp->rss_hdr.opcode == CPL_RX_DATA) {
48509fe6320SNavdeep Parhar const struct cpl_rx_data *cpl = (const void *)&resp->imm_data[0];
48609fe6320SNavdeep Parhar m->m_len = sizeof(*cpl) + ntohs(cpl->len);
48709fe6320SNavdeep Parhar } else if (resp->rss_hdr.opcode == CPL_RX_PKT) {
48809fe6320SNavdeep Parhar const struct cpl_rx_pkt *cpl = (const void *)&resp->imm_data[0];
48909fe6320SNavdeep Parhar m->m_len = sizeof(*cpl) + ntohs(cpl->len);
49009fe6320SNavdeep Parhar } else
49109fe6320SNavdeep Parhar m->m_len = IMMED_PKT_SIZE;
4928e10660fSKip Macy m->m_ext.ext_buf = NULL;
4938e10660fSKip Macy m->m_ext.ext_type = 0;
49409fe6320SNavdeep Parhar memcpy(mtod(m, uint8_t *), resp->imm_data, m->m_len);
4958090c9f5SKip Macy return (0);
496b6d90eb7SKip Macy }
497b6d90eb7SKip Macy
498b6d90eb7SKip Macy static __inline u_int
flits_to_desc(u_int n)499b6d90eb7SKip Macy flits_to_desc(u_int n)
500b6d90eb7SKip Macy {
501b6d90eb7SKip Macy return (flit_desc_map[n]);
502b6d90eb7SKip Macy }
503b6d90eb7SKip Macy
5048e10660fSKip Macy #define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
5058e10660fSKip Macy F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
5068e10660fSKip Macy V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
5078e10660fSKip Macy F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
5088e10660fSKip Macy F_HIRCQPARITYERROR)
5098e10660fSKip Macy #define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR)
5108e10660fSKip Macy #define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \
5118e10660fSKip Macy F_RSPQDISABLED)
5128e10660fSKip Macy
5138e10660fSKip Macy /**
5148e10660fSKip Macy * t3_sge_err_intr_handler - SGE async event interrupt handler
5158e10660fSKip Macy * @adapter: the adapter
5168e10660fSKip Macy *
5178e10660fSKip Macy * Interrupt handler for SGE asynchronous (non-data) events.
5188e10660fSKip Macy */
519b6d90eb7SKip Macy void
t3_sge_err_intr_handler(adapter_t * adapter)520b6d90eb7SKip Macy t3_sge_err_intr_handler(adapter_t *adapter)
521b6d90eb7SKip Macy {
522b6d90eb7SKip Macy unsigned int v, status;
523b6d90eb7SKip Macy
524b6d90eb7SKip Macy status = t3_read_reg(adapter, A_SG_INT_CAUSE);
5258e10660fSKip Macy if (status & SGE_PARERR)
5268e10660fSKip Macy CH_ALERT(adapter, "SGE parity error (0x%x)\n",
5278e10660fSKip Macy status & SGE_PARERR);
5288e10660fSKip Macy if (status & SGE_FRAMINGERR)
5298e10660fSKip Macy CH_ALERT(adapter, "SGE framing error (0x%x)\n",
5308e10660fSKip Macy status & SGE_FRAMINGERR);
531b6d90eb7SKip Macy if (status & F_RSPQCREDITOVERFOW)
532b6d90eb7SKip Macy CH_ALERT(adapter, "SGE response queue credit overflow\n");
533b6d90eb7SKip Macy
534b6d90eb7SKip Macy if (status & F_RSPQDISABLED) {
535b6d90eb7SKip Macy v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS);
536b6d90eb7SKip Macy
537b6d90eb7SKip Macy CH_ALERT(adapter,
538b6d90eb7SKip Macy "packet delivered to disabled response queue (0x%x)\n",
539b6d90eb7SKip Macy (v >> S_RSPQ0DISABLED) & 0xff);
540b6d90eb7SKip Macy }
541b6d90eb7SKip Macy
542b6d90eb7SKip Macy t3_write_reg(adapter, A_SG_INT_CAUSE, status);
5438e10660fSKip Macy if (status & SGE_FATALERR)
544b6d90eb7SKip Macy t3_fatal_err(adapter);
545b6d90eb7SKip Macy }
546b6d90eb7SKip Macy
547b6d90eb7SKip Macy void
t3_sge_prep(adapter_t * adap,struct sge_params * p)548b6d90eb7SKip Macy t3_sge_prep(adapter_t *adap, struct sge_params *p)
549b6d90eb7SKip Macy {
55097ae3bc3SNavdeep Parhar int i, nqsets, fl_q_size, jumbo_q_size, use_16k, jumbo_buf_size;
551f705d735SKip Macy
55297ae3bc3SNavdeep Parhar nqsets = min(SGE_QSETS / adap->params.nports, mp_ncpus);
55397ae3bc3SNavdeep Parhar nqsets *= adap->params.nports;
554f705d735SKip Macy
555f705d735SKip Macy fl_q_size = min(nmbclusters/(3*nqsets), FL_Q_SIZE);
5567bb73f73SDoug Moore fl_q_size = rounddown_pow_of_two(fl_q_size);
55797ae3bc3SNavdeep Parhar
55897ae3bc3SNavdeep Parhar use_16k = cxgb_use_16k_clusters != -1 ? cxgb_use_16k_clusters :
55997ae3bc3SNavdeep Parhar is_offload(adap);
56097ae3bc3SNavdeep Parhar
56197ae3bc3SNavdeep Parhar if (use_16k) {
562f705d735SKip Macy jumbo_q_size = min(nmbjumbo16/(3*nqsets), JUMBO_Q_SIZE);
56397ae3bc3SNavdeep Parhar jumbo_buf_size = MJUM16BYTES;
56497ae3bc3SNavdeep Parhar } else {
565f705d735SKip Macy jumbo_q_size = min(nmbjumbo9/(3*nqsets), JUMBO_Q_SIZE);
56697ae3bc3SNavdeep Parhar jumbo_buf_size = MJUM9BYTES;
56797ae3bc3SNavdeep Parhar }
5687bb73f73SDoug Moore jumbo_q_size = rounddown_pow_of_two(jumbo_q_size);
569b6d90eb7SKip Macy
5701299e071SNavdeep Parhar if (fl_q_size < (FL_Q_SIZE / 4) || jumbo_q_size < (JUMBO_Q_SIZE / 2))
5711299e071SNavdeep Parhar device_printf(adap->dev,
5721299e071SNavdeep Parhar "Insufficient clusters and/or jumbo buffers.\n");
5731299e071SNavdeep Parhar
57497ae3bc3SNavdeep Parhar p->max_pkt_size = jumbo_buf_size - sizeof(struct cpl_rx_data);
575b6d90eb7SKip Macy
576b6d90eb7SKip Macy for (i = 0; i < SGE_QSETS; ++i) {
577b6d90eb7SKip Macy struct qset_params *q = p->qset + i;
578b6d90eb7SKip Macy
5798090c9f5SKip Macy if (adap->params.nports > 2) {
5804af83c8cSKip Macy q->coalesce_usecs = 50;
5818090c9f5SKip Macy } else {
5828090c9f5SKip Macy #ifdef INVARIANTS
5834af83c8cSKip Macy q->coalesce_usecs = 10;
5848090c9f5SKip Macy #else
5854af83c8cSKip Macy q->coalesce_usecs = 5;
5868090c9f5SKip Macy #endif
5878090c9f5SKip Macy }
5881ffd6e58SKip Macy q->polling = 0;
589b6d90eb7SKip Macy q->rspq_size = RSPQ_Q_SIZE;
590f705d735SKip Macy q->fl_size = fl_q_size;
591f705d735SKip Macy q->jumbo_size = jumbo_q_size;
59297ae3bc3SNavdeep Parhar q->jumbo_buf_size = jumbo_buf_size;
593b6d90eb7SKip Macy q->txq_size[TXQ_ETH] = TX_ETH_Q_SIZE;
59497ae3bc3SNavdeep Parhar q->txq_size[TXQ_OFLD] = is_offload(adap) ? TX_OFLD_Q_SIZE : 16;
59597ae3bc3SNavdeep Parhar q->txq_size[TXQ_CTRL] = TX_CTRL_Q_SIZE;
596b6d90eb7SKip Macy q->cong_thres = 0;
597b6d90eb7SKip Macy }
598b6d90eb7SKip Macy }
599b6d90eb7SKip Macy
600b6d90eb7SKip Macy int
t3_sge_alloc(adapter_t * sc)601b6d90eb7SKip Macy t3_sge_alloc(adapter_t *sc)
602b6d90eb7SKip Macy {
603b6d90eb7SKip Macy
604b6d90eb7SKip Macy /* The parent tag. */
605b6f97155SScott Long if (bus_dma_tag_create( bus_get_dma_tag(sc->dev),/* PCI parent */
606b6d90eb7SKip Macy 1, 0, /* algnmnt, boundary */
607b6d90eb7SKip Macy BUS_SPACE_MAXADDR, /* lowaddr */
608b6d90eb7SKip Macy BUS_SPACE_MAXADDR, /* highaddr */
609b6d90eb7SKip Macy NULL, NULL, /* filter, filterarg */
610b6d90eb7SKip Macy BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
611b6d90eb7SKip Macy BUS_SPACE_UNRESTRICTED, /* nsegments */
612b6d90eb7SKip Macy BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
613b6d90eb7SKip Macy 0, /* flags */
614b6d90eb7SKip Macy NULL, NULL, /* lock, lockarg */
615b6d90eb7SKip Macy &sc->parent_dmat)) {
616b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate parent DMA tag\n");
617b6d90eb7SKip Macy return (ENOMEM);
618b6d90eb7SKip Macy }
619b6d90eb7SKip Macy
620b6d90eb7SKip Macy /*
621b6d90eb7SKip Macy * DMA tag for normal sized RX frames
622b6d90eb7SKip Macy */
623b6d90eb7SKip Macy if (bus_dma_tag_create(sc->parent_dmat, MCLBYTES, 0, BUS_SPACE_MAXADDR,
624b6d90eb7SKip Macy BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1,
625b6d90eb7SKip Macy MCLBYTES, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->rx_dmat)) {
626b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate RX DMA tag\n");
627b6d90eb7SKip Macy return (ENOMEM);
628b6d90eb7SKip Macy }
629b6d90eb7SKip Macy
630b6d90eb7SKip Macy /*
631b6d90eb7SKip Macy * DMA tag for jumbo sized RX frames.
632b6d90eb7SKip Macy */
633f001b63dSKip Macy if (bus_dma_tag_create(sc->parent_dmat, MJUM16BYTES, 0, BUS_SPACE_MAXADDR,
634f001b63dSKip Macy BUS_SPACE_MAXADDR, NULL, NULL, MJUM16BYTES, 1, MJUM16BYTES,
635b6d90eb7SKip Macy BUS_DMA_ALLOCNOW, NULL, NULL, &sc->rx_jumbo_dmat)) {
636b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate RX jumbo DMA tag\n");
637b6d90eb7SKip Macy return (ENOMEM);
638b6d90eb7SKip Macy }
639b6d90eb7SKip Macy
640b6d90eb7SKip Macy /*
641b6d90eb7SKip Macy * DMA tag for TX frames.
642b6d90eb7SKip Macy */
643b6d90eb7SKip Macy if (bus_dma_tag_create(sc->parent_dmat, 1, 0, BUS_SPACE_MAXADDR,
644b6d90eb7SKip Macy BUS_SPACE_MAXADDR, NULL, NULL, TX_MAX_SIZE, TX_MAX_SEGS,
645b6d90eb7SKip Macy TX_MAX_SIZE, BUS_DMA_ALLOCNOW,
646b6d90eb7SKip Macy NULL, NULL, &sc->tx_dmat)) {
647b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate TX DMA tag\n");
648b6d90eb7SKip Macy return (ENOMEM);
649b6d90eb7SKip Macy }
650b6d90eb7SKip Macy
651b6d90eb7SKip Macy return (0);
652b6d90eb7SKip Macy }
653b6d90eb7SKip Macy
654b6d90eb7SKip Macy int
t3_sge_free(struct adapter * sc)655b6d90eb7SKip Macy t3_sge_free(struct adapter * sc)
656b6d90eb7SKip Macy {
657b6d90eb7SKip Macy
658b6d90eb7SKip Macy if (sc->tx_dmat != NULL)
659b6d90eb7SKip Macy bus_dma_tag_destroy(sc->tx_dmat);
660b6d90eb7SKip Macy
661b6d90eb7SKip Macy if (sc->rx_jumbo_dmat != NULL)
662b6d90eb7SKip Macy bus_dma_tag_destroy(sc->rx_jumbo_dmat);
663b6d90eb7SKip Macy
664b6d90eb7SKip Macy if (sc->rx_dmat != NULL)
665b6d90eb7SKip Macy bus_dma_tag_destroy(sc->rx_dmat);
666b6d90eb7SKip Macy
667b6d90eb7SKip Macy if (sc->parent_dmat != NULL)
668b6d90eb7SKip Macy bus_dma_tag_destroy(sc->parent_dmat);
669b6d90eb7SKip Macy
670b6d90eb7SKip Macy return (0);
671b6d90eb7SKip Macy }
672b6d90eb7SKip Macy
673b6d90eb7SKip Macy void
t3_update_qset_coalesce(struct sge_qset * qs,const struct qset_params * p)674b6d90eb7SKip Macy t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
675b6d90eb7SKip Macy {
676b6d90eb7SKip Macy
6774af83c8cSKip Macy qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);
678b6d90eb7SKip Macy qs->rspq.polling = 0 /* p->polling */;
679b6d90eb7SKip Macy }
680b6d90eb7SKip Macy
6818090c9f5SKip Macy #if !defined(__i386__) && !defined(__amd64__)
682fa0521c0SKip Macy static void
refill_fl_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)683fa0521c0SKip Macy refill_fl_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
684fa0521c0SKip Macy {
685fa0521c0SKip Macy struct refill_fl_cb_arg *cb_arg = arg;
686fa0521c0SKip Macy
687fa0521c0SKip Macy cb_arg->error = error;
688fa0521c0SKip Macy cb_arg->seg = segs[0];
689fa0521c0SKip Macy cb_arg->nseg = nseg;
690fa0521c0SKip Macy
691fa0521c0SKip Macy }
6928090c9f5SKip Macy #endif
693b6d90eb7SKip Macy /**
694b6d90eb7SKip Macy * refill_fl - refill an SGE free-buffer list
695b6d90eb7SKip Macy * @sc: the controller softc
696b6d90eb7SKip Macy * @q: the free-list to refill
697b6d90eb7SKip Macy * @n: the number of new buffers to allocate
698b6d90eb7SKip Macy *
699b6d90eb7SKip Macy * (Re)populate an SGE free-buffer list with up to @n new packet buffers.
700b6d90eb7SKip Macy * The caller must assure that @n does not exceed the queue's capacity.
701b6d90eb7SKip Macy */
702b6d90eb7SKip Macy static void
refill_fl(adapter_t * sc,struct sge_fl * q,int n)703b6d90eb7SKip Macy refill_fl(adapter_t *sc, struct sge_fl *q, int n)
704b6d90eb7SKip Macy {
705b6d90eb7SKip Macy struct rx_sw_desc *sd = &q->sdesc[q->pidx];
706b6d90eb7SKip Macy struct rx_desc *d = &q->desc[q->pidx];
707fa0521c0SKip Macy struct refill_fl_cb_arg cb_arg;
7083f345a5dSKip Macy struct mbuf *m;
7098090c9f5SKip Macy caddr_t cl;
7101d4942f4SNavdeep Parhar int err;
711b6d90eb7SKip Macy
712fa0521c0SKip Macy cb_arg.error = 0;
713b6d90eb7SKip Macy while (n--) {
714fa0521c0SKip Macy /*
71509fe6320SNavdeep Parhar * We allocate an uninitialized mbuf + cluster, mbuf is
71609fe6320SNavdeep Parhar * initialized after rx.
717fa0521c0SKip Macy */
7183f345a5dSKip Macy if (q->zone == zone_pack) {
7193f345a5dSKip Macy if ((m = m_getcl(M_NOWAIT, MT_NOINIT, M_PKTHDR)) == NULL)
7203f345a5dSKip Macy break;
7213f345a5dSKip Macy cl = m->m_ext.ext_buf;
7223f345a5dSKip Macy } else {
7233f345a5dSKip Macy if ((cl = m_cljget(NULL, M_NOWAIT, q->buf_size)) == NULL)
7243f345a5dSKip Macy break;
725edcf1054SMateusz Guzik if ((m = m_gethdr_raw(M_NOWAIT, 0)) == NULL) {
7263f345a5dSKip Macy uma_zfree(q->zone, cl);
7273f345a5dSKip Macy break;
728b6d90eb7SKip Macy }
7293f345a5dSKip Macy }
730b6d90eb7SKip Macy if ((sd->flags & RX_SW_DESC_MAP_CREATED) == 0) {
731fa0521c0SKip Macy if ((err = bus_dmamap_create(q->entry_tag, 0, &sd->map))) {
73220fe52b8SKip Macy log(LOG_WARNING, "bus_dmamap_create failed %d\n", err);
7335f1e4ae3SKip Macy uma_zfree(q->zone, cl);
73420fe52b8SKip Macy goto done;
73520fe52b8SKip Macy }
736b6d90eb7SKip Macy sd->flags |= RX_SW_DESC_MAP_CREATED;
737b6d90eb7SKip Macy }
7388090c9f5SKip Macy #if !defined(__i386__) && !defined(__amd64__)
7398090c9f5SKip Macy err = bus_dmamap_load(q->entry_tag, sd->map,
7403f345a5dSKip Macy cl, q->buf_size, refill_fl_cb, &cb_arg, 0);
741b6d90eb7SKip Macy
742fa0521c0SKip Macy if (err != 0 || cb_arg.error) {
7438ee1c087SGleb Smirnoff if (q->zone != zone_pack)
7443f345a5dSKip Macy uma_zfree(q->zone, cl);
7453f345a5dSKip Macy m_free(m);
74675417d6dSKip Macy goto done;
747b6d90eb7SKip Macy }
7488090c9f5SKip Macy #else
7493f345a5dSKip Macy cb_arg.seg.ds_addr = pmap_kextract((vm_offset_t)cl);
7508090c9f5SKip Macy #endif
751fa0521c0SKip Macy sd->flags |= RX_SW_DESC_INUSE;
7528090c9f5SKip Macy sd->rxsd_cl = cl;
7533f345a5dSKip Macy sd->m = m;
754fa0521c0SKip Macy d->addr_lo = htobe32(cb_arg.seg.ds_addr & 0xffffffff);
755fa0521c0SKip Macy d->addr_hi = htobe32(((uint64_t)cb_arg.seg.ds_addr >>32) & 0xffffffff);
756b6d90eb7SKip Macy d->len_gen = htobe32(V_FLD_GEN1(q->gen));
757b6d90eb7SKip Macy d->gen2 = htobe32(V_FLD_GEN2(q->gen));
758b6d90eb7SKip Macy
759b6d90eb7SKip Macy d++;
760b6d90eb7SKip Macy sd++;
761b6d90eb7SKip Macy
762b6d90eb7SKip Macy if (++q->pidx == q->size) {
763b6d90eb7SKip Macy q->pidx = 0;
764b6d90eb7SKip Macy q->gen ^= 1;
765b6d90eb7SKip Macy sd = q->sdesc;
766b6d90eb7SKip Macy d = q->desc;
767b6d90eb7SKip Macy }
768b6d90eb7SKip Macy q->credits++;
7691d4942f4SNavdeep Parhar q->db_pending++;
770b6d90eb7SKip Macy }
771b6d90eb7SKip Macy
772b6d90eb7SKip Macy done:
7731d4942f4SNavdeep Parhar if (q->db_pending >= 32) {
7741d4942f4SNavdeep Parhar q->db_pending = 0;
775b6d90eb7SKip Macy t3_write_reg(sc, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
776b6d90eb7SKip Macy }
7771d4942f4SNavdeep Parhar }
778b6d90eb7SKip Macy
779b6d90eb7SKip Macy
780b6d90eb7SKip Macy /**
781b6d90eb7SKip Macy * free_rx_bufs - free the Rx buffers on an SGE free list
782b6d90eb7SKip Macy * @sc: the controle softc
783b6d90eb7SKip Macy * @q: the SGE free list to clean up
784b6d90eb7SKip Macy *
785b6d90eb7SKip Macy * Release the buffers on an SGE free-buffer Rx queue. HW fetching from
786b6d90eb7SKip Macy * this queue should be stopped before calling this function.
787b6d90eb7SKip Macy */
788b6d90eb7SKip Macy static void
free_rx_bufs(adapter_t * sc,struct sge_fl * q)789b6d90eb7SKip Macy free_rx_bufs(adapter_t *sc, struct sge_fl *q)
790b6d90eb7SKip Macy {
791b6d90eb7SKip Macy u_int cidx = q->cidx;
792b6d90eb7SKip Macy
793b6d90eb7SKip Macy while (q->credits--) {
794b6d90eb7SKip Macy struct rx_sw_desc *d = &q->sdesc[cidx];
795b6d90eb7SKip Macy
796b6d90eb7SKip Macy if (d->flags & RX_SW_DESC_INUSE) {
797fa0521c0SKip Macy bus_dmamap_unload(q->entry_tag, d->map);
798fa0521c0SKip Macy bus_dmamap_destroy(q->entry_tag, d->map);
7993f345a5dSKip Macy if (q->zone == zone_pack) {
800b4b12e52SGleb Smirnoff m_init(d->m, M_NOWAIT, MT_DATA, M_EXT);
8013f345a5dSKip Macy uma_zfree(zone_pack, d->m);
8023f345a5dSKip Macy } else {
803b4b12e52SGleb Smirnoff m_init(d->m, M_NOWAIT, MT_DATA, 0);
8042a69eb8cSMateusz Guzik m_free_raw(d->m);
8058090c9f5SKip Macy uma_zfree(q->zone, d->rxsd_cl);
806b6d90eb7SKip Macy }
8073f345a5dSKip Macy }
8083f345a5dSKip Macy
8098090c9f5SKip Macy d->rxsd_cl = NULL;
8103f345a5dSKip Macy d->m = NULL;
811b6d90eb7SKip Macy if (++cidx == q->size)
812b6d90eb7SKip Macy cidx = 0;
813b6d90eb7SKip Macy }
814b6d90eb7SKip Macy }
815b6d90eb7SKip Macy
816b6d90eb7SKip Macy static __inline void
__refill_fl(adapter_t * adap,struct sge_fl * fl)817b6d90eb7SKip Macy __refill_fl(adapter_t *adap, struct sge_fl *fl)
818b6d90eb7SKip Macy {
819b6d90eb7SKip Macy refill_fl(adap, fl, min(16U, fl->size - fl->credits));
820b6d90eb7SKip Macy }
821b6d90eb7SKip Macy
8228090c9f5SKip Macy static __inline void
__refill_fl_lt(adapter_t * adap,struct sge_fl * fl,int max)8238090c9f5SKip Macy __refill_fl_lt(adapter_t *adap, struct sge_fl *fl, int max)
8248090c9f5SKip Macy {
8251d4942f4SNavdeep Parhar uint32_t reclaimable = fl->size - fl->credits;
8261d4942f4SNavdeep Parhar
8271d4942f4SNavdeep Parhar if (reclaimable > 0)
8281d4942f4SNavdeep Parhar refill_fl(adap, fl, min(max, reclaimable));
8298090c9f5SKip Macy }
8308090c9f5SKip Macy
831d722cab4SKip Macy /**
832d722cab4SKip Macy * recycle_rx_buf - recycle a receive buffer
833d722cab4SKip Macy * @adapter: the adapter
834d722cab4SKip Macy * @q: the SGE free list
835d722cab4SKip Macy * @idx: index of buffer to recycle
836d722cab4SKip Macy *
837d722cab4SKip Macy * Recycles the specified buffer on the given free list by adding it at
838d722cab4SKip Macy * the next available slot on the list.
839d722cab4SKip Macy */
840d722cab4SKip Macy static void
recycle_rx_buf(adapter_t * adap,struct sge_fl * q,unsigned int idx)841d722cab4SKip Macy recycle_rx_buf(adapter_t *adap, struct sge_fl *q, unsigned int idx)
842d722cab4SKip Macy {
843d722cab4SKip Macy struct rx_desc *from = &q->desc[idx];
844d722cab4SKip Macy struct rx_desc *to = &q->desc[q->pidx];
845d722cab4SKip Macy
846d722cab4SKip Macy q->sdesc[q->pidx] = q->sdesc[idx];
847d722cab4SKip Macy to->addr_lo = from->addr_lo; // already big endian
848d722cab4SKip Macy to->addr_hi = from->addr_hi; // likewise
8493f345a5dSKip Macy wmb(); /* necessary ? */
850d722cab4SKip Macy to->len_gen = htobe32(V_FLD_GEN1(q->gen));
851d722cab4SKip Macy to->gen2 = htobe32(V_FLD_GEN2(q->gen));
852d722cab4SKip Macy q->credits++;
853d722cab4SKip Macy
854d722cab4SKip Macy if (++q->pidx == q->size) {
855d722cab4SKip Macy q->pidx = 0;
856d722cab4SKip Macy q->gen ^= 1;
857d722cab4SKip Macy }
858d722cab4SKip Macy t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
859d722cab4SKip Macy }
860d722cab4SKip Macy
861b6d90eb7SKip Macy static void
alloc_ring_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)862b6d90eb7SKip Macy alloc_ring_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
863b6d90eb7SKip Macy {
864b6d90eb7SKip Macy uint32_t *addr;
865b6d90eb7SKip Macy
866b6d90eb7SKip Macy addr = arg;
867b6d90eb7SKip Macy *addr = segs[0].ds_addr;
868b6d90eb7SKip Macy }
869b6d90eb7SKip Macy
870b6d90eb7SKip Macy static int
alloc_ring(adapter_t * sc,size_t nelem,size_t elem_size,size_t sw_size,bus_addr_t * phys,void * desc,void * sdesc,bus_dma_tag_t * tag,bus_dmamap_t * map,bus_dma_tag_t parent_entry_tag,bus_dma_tag_t * entry_tag)871b6d90eb7SKip Macy alloc_ring(adapter_t *sc, size_t nelem, size_t elem_size, size_t sw_size,
872b6d90eb7SKip Macy bus_addr_t *phys, void *desc, void *sdesc, bus_dma_tag_t *tag,
873fa0521c0SKip Macy bus_dmamap_t *map, bus_dma_tag_t parent_entry_tag, bus_dma_tag_t *entry_tag)
874b6d90eb7SKip Macy {
875b6d90eb7SKip Macy size_t len = nelem * elem_size;
876b6d90eb7SKip Macy void *s = NULL;
877b6d90eb7SKip Macy void *p = NULL;
878b6d90eb7SKip Macy int err;
879b6d90eb7SKip Macy
880b6d90eb7SKip Macy if ((err = bus_dma_tag_create(sc->parent_dmat, PAGE_SIZE, 0,
881b6d90eb7SKip Macy BUS_SPACE_MAXADDR_32BIT,
882b6d90eb7SKip Macy BUS_SPACE_MAXADDR, NULL, NULL, len, 1,
883b6d90eb7SKip Macy len, 0, NULL, NULL, tag)) != 0) {
884b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate descriptor tag\n");
885b6d90eb7SKip Macy return (ENOMEM);
886b6d90eb7SKip Macy }
887b6d90eb7SKip Macy
888b6d90eb7SKip Macy if ((err = bus_dmamem_alloc(*tag, (void **)&p, BUS_DMA_NOWAIT,
889b6d90eb7SKip Macy map)) != 0) {
890b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate descriptor memory\n");
891b6d90eb7SKip Macy return (ENOMEM);
892b6d90eb7SKip Macy }
893b6d90eb7SKip Macy
894b6d90eb7SKip Macy bus_dmamap_load(*tag, *map, p, len, alloc_ring_cb, phys, 0);
895b6d90eb7SKip Macy bzero(p, len);
896b6d90eb7SKip Macy *(void **)desc = p;
897b6d90eb7SKip Macy
898b6d90eb7SKip Macy if (sw_size) {
899b6d90eb7SKip Macy len = nelem * sw_size;
90060f1e276SKip Macy s = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO);
901b6d90eb7SKip Macy *(void **)sdesc = s;
902b6d90eb7SKip Macy }
903fa0521c0SKip Macy if (parent_entry_tag == NULL)
904fa0521c0SKip Macy return (0);
905fa0521c0SKip Macy
90698d6fba7SKip Macy if ((err = bus_dma_tag_create(parent_entry_tag, 1, 0,
907fa0521c0SKip Macy BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
90898d6fba7SKip Macy NULL, NULL, TX_MAX_SIZE, TX_MAX_SEGS,
90998d6fba7SKip Macy TX_MAX_SIZE, BUS_DMA_ALLOCNOW,
910fa0521c0SKip Macy NULL, NULL, entry_tag)) != 0) {
911fa0521c0SKip Macy device_printf(sc->dev, "Cannot allocate descriptor entry tag\n");
912fa0521c0SKip Macy return (ENOMEM);
913fa0521c0SKip Macy }
914b6d90eb7SKip Macy return (0);
915b6d90eb7SKip Macy }
916b6d90eb7SKip Macy
917b6d90eb7SKip Macy static void
sge_slow_intr_handler(void * arg,int ncount)918b6d90eb7SKip Macy sge_slow_intr_handler(void *arg, int ncount)
919b6d90eb7SKip Macy {
920b6d90eb7SKip Macy adapter_t *sc = arg;
921b6d90eb7SKip Macy
922b6d90eb7SKip Macy t3_slow_intr_handler(sc);
9232c32b502SNavdeep Parhar t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
9242c32b502SNavdeep Parhar (void) t3_read_reg(sc, A_PL_INT_ENABLE0);
925b6d90eb7SKip Macy }
926b6d90eb7SKip Macy
927ac3a6d9cSKip Macy /**
928ac3a6d9cSKip Macy * sge_timer_cb - perform periodic maintenance of an SGE qset
929ac3a6d9cSKip Macy * @data: the SGE queue set to maintain
930ac3a6d9cSKip Macy *
931ac3a6d9cSKip Macy * Runs periodically from a timer to perform maintenance of an SGE queue
932ac3a6d9cSKip Macy * set. It performs two tasks:
933ac3a6d9cSKip Macy *
934ac3a6d9cSKip Macy * a) Cleans up any completed Tx descriptors that may still be pending.
935ac3a6d9cSKip Macy * Normal descriptor cleanup happens when new packets are added to a Tx
936ac3a6d9cSKip Macy * queue so this timer is relatively infrequent and does any cleanup only
937ac3a6d9cSKip Macy * if the Tx queue has not seen any new packets in a while. We make a
938ac3a6d9cSKip Macy * best effort attempt to reclaim descriptors, in that we don't wait
939ac3a6d9cSKip Macy * around if we cannot get a queue's lock (which most likely is because
940ac3a6d9cSKip Macy * someone else is queueing new packets and so will also handle the clean
941ac3a6d9cSKip Macy * up). Since control queues use immediate data exclusively we don't
942ac3a6d9cSKip Macy * bother cleaning them up here.
943ac3a6d9cSKip Macy *
944ac3a6d9cSKip Macy * b) Replenishes Rx queues that have run out due to memory shortage.
945ac3a6d9cSKip Macy * Normally new Rx buffers are added when existing ones are consumed but
946ac3a6d9cSKip Macy * when out of memory a queue can become empty. We try to add only a few
947ac3a6d9cSKip Macy * buffers here, the queue will be replenished fully as these new buffers
948ac3a6d9cSKip Macy * are used up if memory shortage has subsided.
949ac3a6d9cSKip Macy *
950ac3a6d9cSKip Macy * c) Return coalesced response queue credits in case a response queue is
951ac3a6d9cSKip Macy * starved.
952ac3a6d9cSKip Macy *
953ac3a6d9cSKip Macy * d) Ring doorbells for T304 tunnel queues since we have seen doorbell
954ac3a6d9cSKip Macy * fifo overflows and the FW doesn't implement any recovery scheme yet.
955ac3a6d9cSKip Macy */
956b6d90eb7SKip Macy static void
sge_timer_cb(void * arg)957b6d90eb7SKip Macy sge_timer_cb(void *arg)
958b6d90eb7SKip Macy {
959b6d90eb7SKip Macy adapter_t *sc = arg;
9603f345a5dSKip Macy if ((sc->flags & USING_MSIX) == 0) {
9613f345a5dSKip Macy
9628090c9f5SKip Macy struct port_info *pi;
963b6d90eb7SKip Macy struct sge_qset *qs;
964b6d90eb7SKip Macy struct sge_txq *txq;
965b6d90eb7SKip Macy int i, j;
96660f1e276SKip Macy int reclaim_ofl, refill_rx;
967b6d90eb7SKip Macy
9683f345a5dSKip Macy if (sc->open_device_map == 0)
9693f345a5dSKip Macy return;
9703f345a5dSKip Macy
971d5e2c3ddSKip Macy for (i = 0; i < sc->params.nports; i++) {
972d5e2c3ddSKip Macy pi = &sc->port[i];
973d5e2c3ddSKip Macy for (j = 0; j < pi->nqsets; j++) {
974d5e2c3ddSKip Macy qs = &sc->sge.qs[pi->first_qset + j];
975b6d90eb7SKip Macy txq = &qs->txq[0];
976b6d90eb7SKip Macy reclaim_ofl = txq[TXQ_OFLD].processed - txq[TXQ_OFLD].cleaned;
977b6d90eb7SKip Macy refill_rx = ((qs->fl[0].credits < qs->fl[0].size) ||
978b6d90eb7SKip Macy (qs->fl[1].credits < qs->fl[1].size));
97960f1e276SKip Macy if (reclaim_ofl || refill_rx) {
980d5e2c3ddSKip Macy taskqueue_enqueue(sc->tq, &pi->timer_reclaim_task);
981ef72318fSKip Macy break;
982b6d90eb7SKip Macy }
983b6d90eb7SKip Macy }
984d5e2c3ddSKip Macy }
9853f345a5dSKip Macy }
9863f345a5dSKip Macy
987ac3a6d9cSKip Macy if (sc->params.nports > 2) {
988ac3a6d9cSKip Macy int i;
989ac3a6d9cSKip Macy
990ac3a6d9cSKip Macy for_each_port(sc, i) {
991ac3a6d9cSKip Macy struct port_info *pi = &sc->port[i];
992ac3a6d9cSKip Macy
993ac3a6d9cSKip Macy t3_write_reg(sc, A_SG_KDOORBELL,
994ac3a6d9cSKip Macy F_SELEGRCNTX |
995ac3a6d9cSKip Macy (FW_TUNNEL_SGEEC_START + pi->first_qset));
996ac3a6d9cSKip Macy }
997ac3a6d9cSKip Macy }
9983f345a5dSKip Macy if (((sc->flags & USING_MSIX) == 0 || sc->params.nports > 2) &&
9993f345a5dSKip Macy sc->open_device_map != 0)
1000b6d90eb7SKip Macy callout_reset(&sc->sge_timer_ch, TX_RECLAIM_PERIOD, sge_timer_cb, sc);
1001b6d90eb7SKip Macy }
1002b6d90eb7SKip Macy
1003b6d90eb7SKip Macy /*
1004b6d90eb7SKip Macy * This is meant to be a catch-all function to keep sge state private
1005b6d90eb7SKip Macy * to sge.c
1006b6d90eb7SKip Macy *
1007b6d90eb7SKip Macy */
1008b6d90eb7SKip Macy int
t3_sge_init_adapter(adapter_t * sc)1009ef72318fSKip Macy t3_sge_init_adapter(adapter_t *sc)
1010b6d90eb7SKip Macy {
1011fd90e2edSJung-uk Kim callout_init(&sc->sge_timer_ch, 1);
1012b6d90eb7SKip Macy callout_reset(&sc->sge_timer_ch, TX_RECLAIM_PERIOD, sge_timer_cb, sc);
1013b6d90eb7SKip Macy TASK_INIT(&sc->slow_intr_task, 0, sge_slow_intr_handler, sc);
1014b6d90eb7SKip Macy return (0);
1015b6d90eb7SKip Macy }
1016b6d90eb7SKip Macy
1017ef72318fSKip Macy int
t3_sge_reset_adapter(adapter_t * sc)10189330dbc3SKip Macy t3_sge_reset_adapter(adapter_t *sc)
10199330dbc3SKip Macy {
10209330dbc3SKip Macy callout_reset(&sc->sge_timer_ch, TX_RECLAIM_PERIOD, sge_timer_cb, sc);
10219330dbc3SKip Macy return (0);
10229330dbc3SKip Macy }
10239330dbc3SKip Macy
10249330dbc3SKip Macy int
t3_sge_init_port(struct port_info * pi)10258090c9f5SKip Macy t3_sge_init_port(struct port_info *pi)
1026ef72318fSKip Macy {
10278090c9f5SKip Macy TASK_INIT(&pi->timer_reclaim_task, 0, sge_timer_reclaim, pi);
1028c0fdfb95SKip Macy return (0);
1029ef72318fSKip Macy }
1030ef72318fSKip Macy
10318db47741SKip Macy /**
10328db47741SKip Macy * refill_rspq - replenish an SGE response queue
10338db47741SKip Macy * @adapter: the adapter
10348db47741SKip Macy * @q: the response queue to replenish
10358db47741SKip Macy * @credits: how many new responses to make available
10368db47741SKip Macy *
10378db47741SKip Macy * Replenishes a response queue by making the supplied number of responses
10388db47741SKip Macy * available to HW.
10398db47741SKip Macy */
10408db47741SKip Macy static __inline void
refill_rspq(adapter_t * sc,const struct sge_rspq * q,u_int credits)10418db47741SKip Macy refill_rspq(adapter_t *sc, const struct sge_rspq *q, u_int credits)
10428db47741SKip Macy {
10438db47741SKip Macy
10448db47741SKip Macy /* mbufs are allocated on demand when a rspq entry is processed. */
10458db47741SKip Macy t3_write_reg(sc, A_SG_RSPQ_CREDIT_RETURN,
10468db47741SKip Macy V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
10478db47741SKip Macy }
10488db47741SKip Macy
1049b8fe6051SKip Macy static void
sge_txq_reclaim_handler(void * arg,int ncount)1050b8fe6051SKip Macy sge_txq_reclaim_handler(void *arg, int ncount)
1051b8fe6051SKip Macy {
10523f345a5dSKip Macy struct sge_qset *qs = arg;
10533f345a5dSKip Macy int i;
1054b8fe6051SKip Macy
10553f345a5dSKip Macy for (i = 0; i < 3; i++)
10563f345a5dSKip Macy reclaim_completed_tx(qs, 16, i);
1057b8fe6051SKip Macy }
1058b6d90eb7SKip Macy
1059b6d90eb7SKip Macy static void
sge_timer_reclaim(void * arg,int ncount)1060b6d90eb7SKip Macy sge_timer_reclaim(void *arg, int ncount)
1061b6d90eb7SKip Macy {
10628090c9f5SKip Macy struct port_info *pi = arg;
10638090c9f5SKip Macy int i, nqsets = pi->nqsets;
10648090c9f5SKip Macy adapter_t *sc = pi->adapter;
1065b6d90eb7SKip Macy struct sge_qset *qs;
1066b6d90eb7SKip Macy struct mtx *lock;
1067693d746cSKip Macy
10683f345a5dSKip Macy KASSERT((sc->flags & USING_MSIX) == 0,
10693f345a5dSKip Macy ("can't call timer reclaim for msi-x"));
10703f345a5dSKip Macy
1071b6d90eb7SKip Macy for (i = 0; i < nqsets; i++) {
1072d5e2c3ddSKip Macy qs = &sc->sge.qs[pi->first_qset + i];
1073b6d90eb7SKip Macy
10743f345a5dSKip Macy reclaim_completed_tx(qs, 16, TXQ_OFLD);
1075b6d90eb7SKip Macy lock = (sc->flags & USING_MSIX) ? &qs->rspq.lock :
1076b6d90eb7SKip Macy &sc->sge.qs[0].rspq.lock;
1077b6d90eb7SKip Macy
1078b6d90eb7SKip Macy if (mtx_trylock(lock)) {
1079b6d90eb7SKip Macy /* XXX currently assume that we are *NOT* polling */
1080b6d90eb7SKip Macy uint32_t status = t3_read_reg(sc, A_SG_RSPQ_FL_STATUS);
1081b6d90eb7SKip Macy
1082693d746cSKip Macy if (qs->fl[0].credits < qs->fl[0].size - 16)
1083b6d90eb7SKip Macy __refill_fl(sc, &qs->fl[0]);
1084693d746cSKip Macy if (qs->fl[1].credits < qs->fl[1].size - 16)
1085b6d90eb7SKip Macy __refill_fl(sc, &qs->fl[1]);
1086b6d90eb7SKip Macy
1087b6d90eb7SKip Macy if (status & (1 << qs->rspq.cntxt_id)) {
1088b6d90eb7SKip Macy if (qs->rspq.credits) {
1089b6d90eb7SKip Macy refill_rspq(sc, &qs->rspq, 1);
1090b6d90eb7SKip Macy qs->rspq.credits--;
1091b6d90eb7SKip Macy t3_write_reg(sc, A_SG_RSPQ_FL_STATUS,
1092b6d90eb7SKip Macy 1 << qs->rspq.cntxt_id);
1093b6d90eb7SKip Macy }
1094b6d90eb7SKip Macy }
1095b6d90eb7SKip Macy mtx_unlock(lock);
1096b6d90eb7SKip Macy }
1097b6d90eb7SKip Macy }
1098b6d90eb7SKip Macy }
1099b6d90eb7SKip Macy
1100b6d90eb7SKip Macy /**
1101b6d90eb7SKip Macy * init_qset_cntxt - initialize an SGE queue set context info
1102b6d90eb7SKip Macy * @qs: the queue set
1103b6d90eb7SKip Macy * @id: the queue set id
1104b6d90eb7SKip Macy *
1105b6d90eb7SKip Macy * Initializes the TIDs and context ids for the queues of a queue set.
1106b6d90eb7SKip Macy */
1107b6d90eb7SKip Macy static void
init_qset_cntxt(struct sge_qset * qs,u_int id)1108b6d90eb7SKip Macy init_qset_cntxt(struct sge_qset *qs, u_int id)
1109b6d90eb7SKip Macy {
1110b6d90eb7SKip Macy
1111b6d90eb7SKip Macy qs->rspq.cntxt_id = id;
1112b6d90eb7SKip Macy qs->fl[0].cntxt_id = 2 * id;
1113b6d90eb7SKip Macy qs->fl[1].cntxt_id = 2 * id + 1;
1114b6d90eb7SKip Macy qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id;
1115b6d90eb7SKip Macy qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id;
1116b6d90eb7SKip Macy qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id;
1117b6d90eb7SKip Macy qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id;
1118b6d90eb7SKip Macy qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id;
11198090c9f5SKip Macy
1120c578b6acSGleb Smirnoff /* XXX: a sane limit is needed instead of INT_MAX */
1121c578b6acSGleb Smirnoff mbufq_init(&qs->txq[TXQ_ETH].sendq, INT_MAX);
1122c578b6acSGleb Smirnoff mbufq_init(&qs->txq[TXQ_OFLD].sendq, INT_MAX);
1123c578b6acSGleb Smirnoff mbufq_init(&qs->txq[TXQ_CTRL].sendq, INT_MAX);
1124b6d90eb7SKip Macy }
1125b6d90eb7SKip Macy
1126b6d90eb7SKip Macy
1127b6d90eb7SKip Macy static void
txq_prod(struct sge_txq * txq,unsigned int ndesc,struct txq_state * txqs)1128b6d90eb7SKip Macy txq_prod(struct sge_txq *txq, unsigned int ndesc, struct txq_state *txqs)
1129b6d90eb7SKip Macy {
1130b6d90eb7SKip Macy txq->in_use += ndesc;
1131b6d90eb7SKip Macy /*
1132b6d90eb7SKip Macy * XXX we don't handle stopping of queue
1133b6d90eb7SKip Macy * presumably start handles this when we bump against the end
1134b6d90eb7SKip Macy */
1135b6d90eb7SKip Macy txqs->gen = txq->gen;
1136b6d90eb7SKip Macy txq->unacked += ndesc;
11378e10660fSKip Macy txqs->compl = (txq->unacked & 32) << (S_WR_COMPL - 5);
11388e10660fSKip Macy txq->unacked &= 31;
1139b6d90eb7SKip Macy txqs->pidx = txq->pidx;
1140b6d90eb7SKip Macy txq->pidx += ndesc;
1141139edb19SKip Macy #ifdef INVARIANTS
1142139edb19SKip Macy if (((txqs->pidx > txq->cidx) &&
1143139edb19SKip Macy (txq->pidx < txqs->pidx) &&
1144139edb19SKip Macy (txq->pidx >= txq->cidx)) ||
1145139edb19SKip Macy ((txqs->pidx < txq->cidx) &&
1146139edb19SKip Macy (txq->pidx >= txq-> cidx)) ||
1147139edb19SKip Macy ((txqs->pidx < txq->cidx) &&
1148139edb19SKip Macy (txq->cidx < txqs->pidx)))
1149139edb19SKip Macy panic("txqs->pidx=%d txq->pidx=%d txq->cidx=%d",
1150139edb19SKip Macy txqs->pidx, txq->pidx, txq->cidx);
1151139edb19SKip Macy #endif
1152b6d90eb7SKip Macy if (txq->pidx >= txq->size) {
1153b6d90eb7SKip Macy txq->pidx -= txq->size;
1154b6d90eb7SKip Macy txq->gen ^= 1;
1155b6d90eb7SKip Macy }
1156b6d90eb7SKip Macy
1157b6d90eb7SKip Macy }
1158b6d90eb7SKip Macy
1159b6d90eb7SKip Macy /**
1160b6d90eb7SKip Macy * calc_tx_descs - calculate the number of Tx descriptors for a packet
1161b6d90eb7SKip Macy * @m: the packet mbufs
1162b6d90eb7SKip Macy * @nsegs: the number of segments
1163b6d90eb7SKip Macy *
1164b6d90eb7SKip Macy * Returns the number of Tx descriptors needed for the given Ethernet
1165b6d90eb7SKip Macy * packet. Ethernet packets require addition of WR and CPL headers.
1166b6d90eb7SKip Macy */
1167b6d90eb7SKip Macy static __inline unsigned int
calc_tx_descs(const struct mbuf * m,int nsegs)1168b6d90eb7SKip Macy calc_tx_descs(const struct mbuf *m, int nsegs)
1169b6d90eb7SKip Macy {
1170b6d90eb7SKip Macy unsigned int flits;
1171b6d90eb7SKip Macy
11723f345a5dSKip Macy if (m->m_pkthdr.len <= PIO_LEN)
1173b6d90eb7SKip Macy return 1;
1174b6d90eb7SKip Macy
1175b6d90eb7SKip Macy flits = sgl_len(nsegs) + 2;
11768090c9f5SKip Macy if (m->m_pkthdr.csum_flags & CSUM_TSO)
1177b6d90eb7SKip Macy flits++;
1178e83ec3e5SNavdeep Parhar
1179b6d90eb7SKip Macy return flits_to_desc(flits);
1180b6d90eb7SKip Macy }
1181b6d90eb7SKip Macy
1182b6d90eb7SKip Macy /**
1183b6d90eb7SKip Macy * make_sgl - populate a scatter/gather list for a packet
1184b6d90eb7SKip Macy * @sgp: the SGL to populate
1185b6d90eb7SKip Macy * @segs: the packet dma segments
1186b6d90eb7SKip Macy * @nsegs: the number of segments
1187b6d90eb7SKip Macy *
1188b6d90eb7SKip Macy * Generates a scatter/gather list for the buffers that make up a packet
1189b6d90eb7SKip Macy * and returns the SGL size in 8-byte words. The caller must size the SGL
1190b6d90eb7SKip Macy * appropriately.
1191b6d90eb7SKip Macy */
1192b6d90eb7SKip Macy static __inline void
make_sgl(struct sg_ent * sgp,bus_dma_segment_t * segs,int nsegs)1193b6d90eb7SKip Macy make_sgl(struct sg_ent *sgp, bus_dma_segment_t *segs, int nsegs)
1194b6d90eb7SKip Macy {
1195b6d90eb7SKip Macy int i, idx;
1196b6d90eb7SKip Macy
11978090c9f5SKip Macy for (idx = 0, i = 0; i < nsegs; i++) {
11988090c9f5SKip Macy /*
11998090c9f5SKip Macy * firmware doesn't like empty segments
12008090c9f5SKip Macy */
12018090c9f5SKip Macy if (segs[i].ds_len == 0)
12028090c9f5SKip Macy continue;
1203b6d90eb7SKip Macy if (i && idx == 0)
1204b6d90eb7SKip Macy ++sgp;
1205b6d90eb7SKip Macy
1206b6d90eb7SKip Macy sgp->len[idx] = htobe32(segs[i].ds_len);
1207b6d90eb7SKip Macy sgp->addr[idx] = htobe64(segs[i].ds_addr);
12088090c9f5SKip Macy idx ^= 1;
1209b6d90eb7SKip Macy }
1210b6d90eb7SKip Macy
1211f001b63dSKip Macy if (idx) {
1212b6d90eb7SKip Macy sgp->len[idx] = 0;
1213f001b63dSKip Macy sgp->addr[idx] = 0;
1214f001b63dSKip Macy }
1215b6d90eb7SKip Macy }
1216b6d90eb7SKip Macy
1217b6d90eb7SKip Macy /**
1218b6d90eb7SKip Macy * check_ring_tx_db - check and potentially ring a Tx queue's doorbell
1219b6d90eb7SKip Macy * @adap: the adapter
1220b6d90eb7SKip Macy * @q: the Tx queue
1221b6d90eb7SKip Macy *
12223f345a5dSKip Macy * Ring the doorbell if a Tx queue is asleep. There is a natural race,
1223b6d90eb7SKip Macy * where the HW is going to sleep just after we checked, however,
1224b6d90eb7SKip Macy * then the interrupt handler will detect the outstanding TX packet
1225b6d90eb7SKip Macy * and ring the doorbell for us.
1226b6d90eb7SKip Macy *
1227b6d90eb7SKip Macy * When GTS is disabled we unconditionally ring the doorbell.
1228b6d90eb7SKip Macy */
1229b6d90eb7SKip Macy static __inline void
check_ring_tx_db(adapter_t * adap,struct sge_txq * q,int mustring)12301d4942f4SNavdeep Parhar check_ring_tx_db(adapter_t *adap, struct sge_txq *q, int mustring)
1231b6d90eb7SKip Macy {
1232b6d90eb7SKip Macy #if USE_GTS
1233b6d90eb7SKip Macy clear_bit(TXQ_LAST_PKT_DB, &q->flags);
1234b6d90eb7SKip Macy if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) {
1235b6d90eb7SKip Macy set_bit(TXQ_LAST_PKT_DB, &q->flags);
1236b6d90eb7SKip Macy #ifdef T3_TRACE
1237b6d90eb7SKip Macy T3_TRACE1(adap->tb[q->cntxt_id & 7], "doorbell Tx, cntxt %d",
1238b6d90eb7SKip Macy q->cntxt_id);
1239b6d90eb7SKip Macy #endif
1240b6d90eb7SKip Macy t3_write_reg(adap, A_SG_KDOORBELL,
1241b6d90eb7SKip Macy F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
1242b6d90eb7SKip Macy }
1243b6d90eb7SKip Macy #else
12441d4942f4SNavdeep Parhar if (mustring || ++q->db_pending >= 32) {
1245b6d90eb7SKip Macy wmb(); /* write descriptors before telling HW */
1246b6d90eb7SKip Macy t3_write_reg(adap, A_SG_KDOORBELL,
1247b6d90eb7SKip Macy F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
12481d4942f4SNavdeep Parhar q->db_pending = 0;
12491d4942f4SNavdeep Parhar }
1250b6d90eb7SKip Macy #endif
1251b6d90eb7SKip Macy }
1252b6d90eb7SKip Macy
1253b6d90eb7SKip Macy static __inline void
wr_gen2(struct tx_desc * d,unsigned int gen)1254b6d90eb7SKip Macy wr_gen2(struct tx_desc *d, unsigned int gen)
1255b6d90eb7SKip Macy {
1256b6d90eb7SKip Macy #if SGE_NUM_GENBITS == 2
1257b6d90eb7SKip Macy d->flit[TX_DESC_FLITS - 1] = htobe64(gen);
1258b6d90eb7SKip Macy #endif
1259b6d90eb7SKip Macy }
1260b6d90eb7SKip Macy
1261d722cab4SKip Macy /**
1262d722cab4SKip Macy * write_wr_hdr_sgl - write a WR header and, optionally, SGL
1263d722cab4SKip Macy * @ndesc: number of Tx descriptors spanned by the SGL
1264d722cab4SKip Macy * @txd: first Tx descriptor to be written
1265d722cab4SKip Macy * @txqs: txq state (generation and producer index)
1266d722cab4SKip Macy * @txq: the SGE Tx queue
1267d722cab4SKip Macy * @sgl: the SGL
1268d722cab4SKip Macy * @flits: number of flits to the start of the SGL in the first descriptor
1269d722cab4SKip Macy * @sgl_flits: the SGL size in flits
1270d722cab4SKip Macy * @wr_hi: top 32 bits of WR header based on WR type (big endian)
1271d722cab4SKip Macy * @wr_lo: low 32 bits of WR header based on WR type (big endian)
1272d722cab4SKip Macy *
1273d722cab4SKip Macy * Write a work request header and an associated SGL. If the SGL is
1274d722cab4SKip Macy * small enough to fit into one Tx descriptor it has already been written
1275d722cab4SKip Macy * and we just need to write the WR header. Otherwise we distribute the
1276d722cab4SKip Macy * SGL across the number of descriptors it spans.
1277d722cab4SKip Macy */
1278d722cab4SKip Macy static void
write_wr_hdr_sgl(unsigned int ndesc,struct tx_desc * txd,struct txq_state * txqs,const struct sge_txq * txq,const struct sg_ent * sgl,unsigned int flits,unsigned int sgl_flits,unsigned int wr_hi,unsigned int wr_lo)1279d722cab4SKip Macy write_wr_hdr_sgl(unsigned int ndesc, struct tx_desc *txd, struct txq_state *txqs,
1280d722cab4SKip Macy const struct sge_txq *txq, const struct sg_ent *sgl, unsigned int flits,
1281d722cab4SKip Macy unsigned int sgl_flits, unsigned int wr_hi, unsigned int wr_lo)
1282d722cab4SKip Macy {
1283d722cab4SKip Macy
1284d722cab4SKip Macy struct work_request_hdr *wrp = (struct work_request_hdr *)txd;
1285d722cab4SKip Macy
1286d722cab4SKip Macy if (__predict_true(ndesc == 1)) {
12873f345a5dSKip Macy set_wr_hdr(wrp, htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
12883f345a5dSKip Macy V_WR_SGLSFLT(flits)) | wr_hi,
128909fe6320SNavdeep Parhar htonl(V_WR_LEN(flits + sgl_flits) | V_WR_GEN(txqs->gen)) |
129009fe6320SNavdeep Parhar wr_lo);
129109fe6320SNavdeep Parhar
1292d722cab4SKip Macy wr_gen2(txd, txqs->gen);
12938090c9f5SKip Macy
1294d722cab4SKip Macy } else {
1295d722cab4SKip Macy unsigned int ogen = txqs->gen;
1296d722cab4SKip Macy const uint64_t *fp = (const uint64_t *)sgl;
1297d722cab4SKip Macy struct work_request_hdr *wp = wrp;
1298d722cab4SKip Macy
12993f345a5dSKip Macy wrp->wrh_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
1300d722cab4SKip Macy V_WR_SGLSFLT(flits)) | wr_hi;
1301d722cab4SKip Macy
1302d722cab4SKip Macy while (sgl_flits) {
1303d722cab4SKip Macy unsigned int avail = WR_FLITS - flits;
1304d722cab4SKip Macy
1305d722cab4SKip Macy if (avail > sgl_flits)
1306d722cab4SKip Macy avail = sgl_flits;
1307d722cab4SKip Macy memcpy(&txd->flit[flits], fp, avail * sizeof(*fp));
1308d722cab4SKip Macy sgl_flits -= avail;
1309d722cab4SKip Macy ndesc--;
1310d722cab4SKip Macy if (!sgl_flits)
1311d722cab4SKip Macy break;
1312d722cab4SKip Macy
1313d722cab4SKip Macy fp += avail;
1314d722cab4SKip Macy txd++;
1315d722cab4SKip Macy if (++txqs->pidx == txq->size) {
1316d722cab4SKip Macy txqs->pidx = 0;
1317d722cab4SKip Macy txqs->gen ^= 1;
1318d722cab4SKip Macy txd = txq->desc;
1319d722cab4SKip Macy }
1320d722cab4SKip Macy
1321d722cab4SKip Macy /*
1322d722cab4SKip Macy * when the head of the mbuf chain
1323d722cab4SKip Macy * is freed all clusters will be freed
1324d722cab4SKip Macy * with it
1325d722cab4SKip Macy */
1326d722cab4SKip Macy wrp = (struct work_request_hdr *)txd;
13273f345a5dSKip Macy wrp->wrh_hi = htonl(V_WR_DATATYPE(1) |
1328d722cab4SKip Macy V_WR_SGLSFLT(1)) | wr_hi;
13293f345a5dSKip Macy wrp->wrh_lo = htonl(V_WR_LEN(min(WR_FLITS,
1330d722cab4SKip Macy sgl_flits + 1)) |
1331d722cab4SKip Macy V_WR_GEN(txqs->gen)) | wr_lo;
1332d722cab4SKip Macy wr_gen2(txd, txqs->gen);
1333d722cab4SKip Macy flits = 1;
1334d722cab4SKip Macy }
13353f345a5dSKip Macy wrp->wrh_hi |= htonl(F_WR_EOP);
1336d722cab4SKip Macy wmb();
13373f345a5dSKip Macy wp->wrh_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
1338d722cab4SKip Macy wr_gen2((struct tx_desc *)wp, ogen);
1339d722cab4SKip Macy }
1340d722cab4SKip Macy }
1341d722cab4SKip Macy
1342f9c6e164SNavdeep Parhar /* sizeof(*eh) + sizeof(*ip) + sizeof(*tcp) */
1343f9c6e164SNavdeep Parhar #define TCPPKTHDRSIZE (ETHER_HDR_LEN + 20 + 20)
1344b6d90eb7SKip Macy
13458090c9f5SKip Macy #define GET_VTAG(cntrl, m) \
13468090c9f5SKip Macy do { \
13478090c9f5SKip Macy if ((m)->m_flags & M_VLANTAG) \
13488090c9f5SKip Macy cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN((m)->m_pkthdr.ether_vtag); \
13498090c9f5SKip Macy } while (0)
13508090c9f5SKip Macy
13513f345a5dSKip Macy static int
t3_encap(struct sge_qset * qs,struct mbuf ** m)13523f345a5dSKip Macy t3_encap(struct sge_qset *qs, struct mbuf **m)
1353b6d90eb7SKip Macy {
1354b6d90eb7SKip Macy adapter_t *sc;
1355b6d90eb7SKip Macy struct mbuf *m0;
1356b6d90eb7SKip Macy struct sge_txq *txq;
1357b6d90eb7SKip Macy struct txq_state txqs;
13588090c9f5SKip Macy struct port_info *pi;
13597aff6d8eSKip Macy unsigned int ndesc, flits, cntrl, mlen;
13605c5df3daSKip Macy int err, nsegs, tso_info = 0;
1361b6d90eb7SKip Macy
1362b6d90eb7SKip Macy struct work_request_hdr *wrp;
1363b6d90eb7SKip Macy struct tx_sw_desc *txsd;
13648090c9f5SKip Macy struct sg_ent *sgp, *sgl;
1365b6d90eb7SKip Macy uint32_t wr_hi, wr_lo, sgl_flits;
1366139edb19SKip Macy bus_dma_segment_t segs[TX_MAX_SEGS];
1367b6d90eb7SKip Macy
1368b6d90eb7SKip Macy struct tx_desc *txd;
1369b6d90eb7SKip Macy
13708090c9f5SKip Macy pi = qs->port;
13718090c9f5SKip Macy sc = pi->adapter;
1372b6d90eb7SKip Macy txq = &qs->txq[TXQ_ETH];
1373b6d90eb7SKip Macy txd = &txq->desc[txq->pidx];
1374139edb19SKip Macy txsd = &txq->sdesc[txq->pidx];
13758090c9f5SKip Macy sgl = txq->txq_sgl;
13763f345a5dSKip Macy
13773f345a5dSKip Macy prefetch(txd);
13788090c9f5SKip Macy m0 = *m;
137960f1e276SKip Macy
13803f345a5dSKip Macy mtx_assert(&qs->lock, MA_OWNED);
13818090c9f5SKip Macy cntrl = V_TXPKT_INTF(pi->txpkt_intf);
13823f345a5dSKip Macy KASSERT(m0->m_flags & M_PKTHDR, ("not packet header\n"));
13833f345a5dSKip Macy
13843f345a5dSKip Macy if (m0->m_nextpkt == NULL && m0->m_next != NULL &&
13853f345a5dSKip Macy m0->m_pkthdr.csum_flags & (CSUM_TSO))
1386b6d90eb7SKip Macy tso_info = V_LSO_MSS(m0->m_pkthdr.tso_segsz);
1387e83ec3e5SNavdeep Parhar
13883f345a5dSKip Macy if (m0->m_nextpkt != NULL) {
1389fd3e7902SNavdeep Parhar busdma_map_sg_vec(txq->entry_tag, txsd->map, m0, segs, &nsegs);
13903f345a5dSKip Macy ndesc = 1;
13913f345a5dSKip Macy mlen = 0;
13923f345a5dSKip Macy } else {
1393fd3e7902SNavdeep Parhar if ((err = busdma_map_sg_collapse(txq->entry_tag, txsd->map,
1394fd3e7902SNavdeep Parhar &m0, segs, &nsegs))) {
13958090c9f5SKip Macy if (cxgb_debug)
13968090c9f5SKip Macy printf("failed ... err=%d\n", err);
13978090c9f5SKip Macy return (err);
13988090c9f5SKip Macy }
13993f345a5dSKip Macy mlen = m0->m_pkthdr.len;
14003f345a5dSKip Macy ndesc = calc_tx_descs(m0, nsegs);
140160f1e276SKip Macy }
14023f345a5dSKip Macy txq_prod(txq, ndesc, &txqs);
14033f345a5dSKip Macy
14043f345a5dSKip Macy KASSERT(m0->m_pkthdr.len, ("empty packet nsegs=%d", nsegs));
14053f345a5dSKip Macy txsd->m = m0;
14063f345a5dSKip Macy
14073f345a5dSKip Macy if (m0->m_nextpkt != NULL) {
14088090c9f5SKip Macy struct cpl_tx_pkt_batch *cpl_batch = (struct cpl_tx_pkt_batch *)txd;
14098090c9f5SKip Macy int i, fidx;
14108090c9f5SKip Macy
14113f345a5dSKip Macy if (nsegs > 7)
14123f345a5dSKip Macy panic("trying to coalesce %d packets in to one WR", nsegs);
14133f345a5dSKip Macy txq->txq_coalesced += nsegs;
14148090c9f5SKip Macy wrp = (struct work_request_hdr *)txd;
14153f345a5dSKip Macy flits = nsegs*2 + 1;
14168090c9f5SKip Macy
14173f345a5dSKip Macy for (fidx = 1, i = 0; i < nsegs; i++, fidx += 2) {
14183f345a5dSKip Macy struct cpl_tx_pkt_batch_entry *cbe;
14193f345a5dSKip Macy uint64_t flit;
14203f345a5dSKip Macy uint32_t *hflit = (uint32_t *)&flit;
14213f345a5dSKip Macy int cflags = m0->m_pkthdr.csum_flags;
14228090c9f5SKip Macy
14238090c9f5SKip Macy cntrl = V_TXPKT_INTF(pi->txpkt_intf);
14243f345a5dSKip Macy GET_VTAG(cntrl, m0);
14258090c9f5SKip Macy cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
14263f345a5dSKip Macy if (__predict_false(!(cflags & CSUM_IP)))
14274af83c8cSKip Macy cntrl |= F_TXPKT_IPCSUM_DIS;
14280a704909SNavdeep Parhar if (__predict_false(!(cflags & (CSUM_TCP | CSUM_UDP |
14290a704909SNavdeep Parhar CSUM_UDP_IPV6 | CSUM_TCP_IPV6))))
14304af83c8cSKip Macy cntrl |= F_TXPKT_L4CSUM_DIS;
14313f345a5dSKip Macy
14323f345a5dSKip Macy hflit[0] = htonl(cntrl);
14333f345a5dSKip Macy hflit[1] = htonl(segs[i].ds_len | 0x80000000);
14343f345a5dSKip Macy flit |= htobe64(1 << 24);
14353f345a5dSKip Macy cbe = &cpl_batch->pkt_entry[i];
14363f345a5dSKip Macy cbe->cntrl = hflit[0];
14373f345a5dSKip Macy cbe->len = hflit[1];
14388090c9f5SKip Macy cbe->addr = htobe64(segs[i].ds_addr);
14398090c9f5SKip Macy }
14408090c9f5SKip Macy
14413f345a5dSKip Macy wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
14423f345a5dSKip Macy V_WR_SGLSFLT(flits)) |
14433f345a5dSKip Macy htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | txqs.compl);
14443f345a5dSKip Macy wr_lo = htonl(V_WR_LEN(flits) |
14458090c9f5SKip Macy V_WR_GEN(txqs.gen)) | htonl(V_WR_TID(txq->token));
14463f345a5dSKip Macy set_wr_hdr(wrp, wr_hi, wr_lo);
14473f345a5dSKip Macy wmb();
1448be688bdeSNavdeep Parhar ETHER_BPF_MTAP(pi->ifp, m0);
14498090c9f5SKip Macy wr_gen2(txd, txqs.gen);
14501d4942f4SNavdeep Parhar check_ring_tx_db(sc, txq, 0);
14518090c9f5SKip Macy return (0);
14528090c9f5SKip Macy } else if (tso_info) {
14533e7cc3caSNavdeep Parhar uint16_t eth_type;
14548090c9f5SKip Macy struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)txd;
1455f9c6e164SNavdeep Parhar struct ether_header *eh;
14563e7cc3caSNavdeep Parhar void *l3hdr;
1457b6d90eb7SKip Macy struct tcphdr *tcp;
1458b6d90eb7SKip Macy
1459b6d90eb7SKip Macy txd->flit[2] = 0;
14604af83c8cSKip Macy GET_VTAG(cntrl, m0);
1461b6d90eb7SKip Macy cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
1462b6d90eb7SKip Macy hdr->cntrl = htonl(cntrl);
14638090c9f5SKip Macy hdr->len = htonl(mlen | 0x80000000);
1464b6d90eb7SKip Macy
1465f9c6e164SNavdeep Parhar if (__predict_false(mlen < TCPPKTHDRSIZE)) {
14661b4381afSAndre Oppermann printf("mbuf=%p,len=%d,tso_segsz=%d,csum_flags=%b,flags=%#x",
14672bd5f41aSKip Macy m0, mlen, m0->m_pkthdr.tso_segsz,
14681b4381afSAndre Oppermann (int)m0->m_pkthdr.csum_flags, CSUM_BITS, m0->m_flags);
14692bd5f41aSKip Macy panic("tx tso packet too small");
14702bd5f41aSKip Macy }
14712bd5f41aSKip Macy
14722bd5f41aSKip Macy /* Make sure that ether, ip, tcp headers are all in m0 */
1473f9c6e164SNavdeep Parhar if (__predict_false(m0->m_len < TCPPKTHDRSIZE)) {
1474f9c6e164SNavdeep Parhar m0 = m_pullup(m0, TCPPKTHDRSIZE);
14752bd5f41aSKip Macy if (__predict_false(m0 == NULL)) {
14762bd5f41aSKip Macy /* XXX panic probably an overreaction */
14772bd5f41aSKip Macy panic("couldn't fit header into mbuf");
14782bd5f41aSKip Macy }
14792bd5f41aSKip Macy }
1480b6d90eb7SKip Macy
1481f9c6e164SNavdeep Parhar eh = mtod(m0, struct ether_header *);
14823e7cc3caSNavdeep Parhar eth_type = eh->ether_type;
14833e7cc3caSNavdeep Parhar if (eth_type == htons(ETHERTYPE_VLAN)) {
14843e7cc3caSNavdeep Parhar struct ether_vlan_header *evh = (void *)eh;
1485b6d90eb7SKip Macy
14863e7cc3caSNavdeep Parhar tso_info |= V_LSO_ETH_TYPE(CPL_ETH_II_VLAN);
14873e7cc3caSNavdeep Parhar l3hdr = evh + 1;
14883e7cc3caSNavdeep Parhar eth_type = evh->evl_proto;
14893e7cc3caSNavdeep Parhar } else {
14903e7cc3caSNavdeep Parhar tso_info |= V_LSO_ETH_TYPE(CPL_ETH_II);
14913e7cc3caSNavdeep Parhar l3hdr = eh + 1;
14923e7cc3caSNavdeep Parhar }
14933e7cc3caSNavdeep Parhar
14943e7cc3caSNavdeep Parhar if (eth_type == htons(ETHERTYPE_IP)) {
14953e7cc3caSNavdeep Parhar struct ip *ip = l3hdr;
14963e7cc3caSNavdeep Parhar
14973e7cc3caSNavdeep Parhar tso_info |= V_LSO_IPHDR_WORDS(ip->ip_hl);
14983e7cc3caSNavdeep Parhar tcp = (struct tcphdr *)(ip + 1);
14993e7cc3caSNavdeep Parhar } else if (eth_type == htons(ETHERTYPE_IPV6)) {
15003e7cc3caSNavdeep Parhar struct ip6_hdr *ip6 = l3hdr;
15013e7cc3caSNavdeep Parhar
15023e7cc3caSNavdeep Parhar KASSERT(ip6->ip6_nxt == IPPROTO_TCP,
15033e7cc3caSNavdeep Parhar ("%s: CSUM_TSO with ip6_nxt %d",
15043e7cc3caSNavdeep Parhar __func__, ip6->ip6_nxt));
15053e7cc3caSNavdeep Parhar
15063e7cc3caSNavdeep Parhar tso_info |= F_LSO_IPV6;
15073e7cc3caSNavdeep Parhar tso_info |= V_LSO_IPHDR_WORDS(sizeof(*ip6) >> 2);
15083e7cc3caSNavdeep Parhar tcp = (struct tcphdr *)(ip6 + 1);
15093e7cc3caSNavdeep Parhar } else
15103e7cc3caSNavdeep Parhar panic("%s: CSUM_TSO but neither ip nor ip6", __func__);
15113e7cc3caSNavdeep Parhar
15123e7cc3caSNavdeep Parhar tso_info |= V_LSO_TCPHDR_WORDS(tcp->th_off);
1513b6d90eb7SKip Macy hdr->lso_info = htonl(tso_info);
15144af83c8cSKip Macy
15154af83c8cSKip Macy if (__predict_false(mlen <= PIO_LEN)) {
1516f9c6e164SNavdeep Parhar /*
1517f9c6e164SNavdeep Parhar * pkt not undersized but fits in PIO_LEN
1518aa819acfSKip Macy * Indicates a TSO bug at the higher levels.
1519af9b081cSKip Macy */
15203f345a5dSKip Macy txsd->m = NULL;
15214af83c8cSKip Macy m_copydata(m0, 0, mlen, (caddr_t)&txd->flit[3]);
15224af83c8cSKip Macy flits = (mlen + 7) / 8 + 3;
15233f345a5dSKip Macy wr_hi = htonl(V_WR_BCNTLFLT(mlen & 7) |
15244af83c8cSKip Macy V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) |
15254af83c8cSKip Macy F_WR_SOP | F_WR_EOP | txqs.compl);
15263f345a5dSKip Macy wr_lo = htonl(V_WR_LEN(flits) |
15274af83c8cSKip Macy V_WR_GEN(txqs.gen) | V_WR_TID(txq->token));
15283f345a5dSKip Macy set_wr_hdr(&hdr->wr, wr_hi, wr_lo);
15293f345a5dSKip Macy wmb();
1530be688bdeSNavdeep Parhar ETHER_BPF_MTAP(pi->ifp, m0);
15314af83c8cSKip Macy wr_gen2(txd, txqs.gen);
15321d4942f4SNavdeep Parhar check_ring_tx_db(sc, txq, 0);
1533be688bdeSNavdeep Parhar m_freem(m0);
15344af83c8cSKip Macy return (0);
15354af83c8cSKip Macy }
1536b6d90eb7SKip Macy flits = 3;
1537b6d90eb7SKip Macy } else {
15388090c9f5SKip Macy struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)txd;
15398090c9f5SKip Macy
15408090c9f5SKip Macy GET_VTAG(cntrl, m0);
1541b6d90eb7SKip Macy cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
15424af83c8cSKip Macy if (__predict_false(!(m0->m_pkthdr.csum_flags & CSUM_IP)))
15434af83c8cSKip Macy cntrl |= F_TXPKT_IPCSUM_DIS;
15440a704909SNavdeep Parhar if (__predict_false(!(m0->m_pkthdr.csum_flags & (CSUM_TCP |
15450a704909SNavdeep Parhar CSUM_UDP | CSUM_UDP_IPV6 | CSUM_TCP_IPV6))))
15464af83c8cSKip Macy cntrl |= F_TXPKT_L4CSUM_DIS;
1547b6d90eb7SKip Macy cpl->cntrl = htonl(cntrl);
15488090c9f5SKip Macy cpl->len = htonl(mlen | 0x80000000);
1549b6d90eb7SKip Macy
155060f1e276SKip Macy if (mlen <= PIO_LEN) {
15513f345a5dSKip Macy txsd->m = NULL;
1552b6d90eb7SKip Macy m_copydata(m0, 0, mlen, (caddr_t)&txd->flit[2]);
1553b6d90eb7SKip Macy flits = (mlen + 7) / 8 + 2;
15543f345a5dSKip Macy
15553f345a5dSKip Macy wr_hi = htonl(V_WR_BCNTLFLT(mlen & 7) |
1556b6d90eb7SKip Macy V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) |
1557b6d90eb7SKip Macy F_WR_SOP | F_WR_EOP | txqs.compl);
15583f345a5dSKip Macy wr_lo = htonl(V_WR_LEN(flits) |
1559b6d90eb7SKip Macy V_WR_GEN(txqs.gen) | V_WR_TID(txq->token));
15603f345a5dSKip Macy set_wr_hdr(&cpl->wr, wr_hi, wr_lo);
15613f345a5dSKip Macy wmb();
1562be688bdeSNavdeep Parhar ETHER_BPF_MTAP(pi->ifp, m0);
1563b6d90eb7SKip Macy wr_gen2(txd, txqs.gen);
15641d4942f4SNavdeep Parhar check_ring_tx_db(sc, txq, 0);
1565be688bdeSNavdeep Parhar m_freem(m0);
1566b6d90eb7SKip Macy return (0);
1567b6d90eb7SKip Macy }
1568b6d90eb7SKip Macy flits = 2;
1569b6d90eb7SKip Macy }
1570b6d90eb7SKip Macy wrp = (struct work_request_hdr *)txd;
1571d722cab4SKip Macy sgp = (ndesc == 1) ? (struct sg_ent *)&txd->flit[flits] : sgl;
1572b6d90eb7SKip Macy make_sgl(sgp, segs, nsegs);
1573b6d90eb7SKip Macy
1574b6d90eb7SKip Macy sgl_flits = sgl_len(nsegs);
1575b6d90eb7SKip Macy
1576be688bdeSNavdeep Parhar ETHER_BPF_MTAP(pi->ifp, m0);
1577be688bdeSNavdeep Parhar
15783f345a5dSKip Macy KASSERT(ndesc <= 4, ("ndesc too large %d", ndesc));
1579b6d90eb7SKip Macy wr_hi = htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | txqs.compl);
1580b6d90eb7SKip Macy wr_lo = htonl(V_WR_TID(txq->token));
15813f345a5dSKip Macy write_wr_hdr_sgl(ndesc, txd, &txqs, txq, sgl, flits,
15823f345a5dSKip Macy sgl_flits, wr_hi, wr_lo);
15831d4942f4SNavdeep Parhar check_ring_tx_db(sc, txq, 0);
15848090c9f5SKip Macy
1585b6d90eb7SKip Macy return (0);
1586b6d90eb7SKip Macy }
1587b6d90eb7SKip Macy
15887790c8c1SConrad Meyer #ifdef DEBUGNET
1589eb07d67eSMark Johnston int
cxgb_debugnet_encap(struct sge_qset * qs,struct mbuf ** m)15907790c8c1SConrad Meyer cxgb_debugnet_encap(struct sge_qset *qs, struct mbuf **m)
1591eb07d67eSMark Johnston {
1592eb07d67eSMark Johnston int error;
1593eb07d67eSMark Johnston
1594eb07d67eSMark Johnston error = t3_encap(qs, m);
1595eb07d67eSMark Johnston if (error == 0)
1596eb07d67eSMark Johnston check_ring_tx_db(qs->port->adapter, &qs->txq[TXQ_ETH], 1);
1597eb07d67eSMark Johnston else if (*m != NULL) {
1598eb07d67eSMark Johnston m_freem(*m);
1599eb07d67eSMark Johnston *m = NULL;
1600eb07d67eSMark Johnston }
1601eb07d67eSMark Johnston return (error);
1602eb07d67eSMark Johnston }
1603eb07d67eSMark Johnston #endif
1604eb07d67eSMark Johnston
16053f345a5dSKip Macy void
cxgb_tx_watchdog(void * arg)16063f345a5dSKip Macy cxgb_tx_watchdog(void *arg)
16073f345a5dSKip Macy {
16083f345a5dSKip Macy struct sge_qset *qs = arg;
16093f345a5dSKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
16103f345a5dSKip Macy
16113f345a5dSKip Macy if (qs->coalescing != 0 &&
16123f345a5dSKip Macy (txq->in_use <= cxgb_tx_coalesce_enable_stop) &&
16133f345a5dSKip Macy TXQ_RING_EMPTY(qs))
16143f345a5dSKip Macy qs->coalescing = 0;
16153f345a5dSKip Macy else if (qs->coalescing == 0 &&
16163f345a5dSKip Macy (txq->in_use >= cxgb_tx_coalesce_enable_start))
16173f345a5dSKip Macy qs->coalescing = 1;
16183f345a5dSKip Macy if (TXQ_TRYLOCK(qs)) {
16193f345a5dSKip Macy qs->qs_flags |= QS_FLUSHING;
16203f345a5dSKip Macy cxgb_start_locked(qs);
16213f345a5dSKip Macy qs->qs_flags &= ~QS_FLUSHING;
16223f345a5dSKip Macy TXQ_UNLOCK(qs);
16233f345a5dSKip Macy }
1624954712e8SJustin Hibbits if (if_getdrvflags(qs->port->ifp) & IFF_DRV_RUNNING)
16253f345a5dSKip Macy callout_reset_on(&txq->txq_watchdog, hz/4, cxgb_tx_watchdog,
16263f345a5dSKip Macy qs, txq->txq_watchdog.c_cpu);
16273f345a5dSKip Macy }
16283f345a5dSKip Macy
16293f345a5dSKip Macy static void
cxgb_tx_timeout(void * arg)16303f345a5dSKip Macy cxgb_tx_timeout(void *arg)
16313f345a5dSKip Macy {
16323f345a5dSKip Macy struct sge_qset *qs = arg;
16333f345a5dSKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
16343f345a5dSKip Macy
16353f345a5dSKip Macy if (qs->coalescing == 0 && (txq->in_use >= (txq->size>>3)))
16363f345a5dSKip Macy qs->coalescing = 1;
16373f345a5dSKip Macy if (TXQ_TRYLOCK(qs)) {
16383f345a5dSKip Macy qs->qs_flags |= QS_TIMEOUT;
16393f345a5dSKip Macy cxgb_start_locked(qs);
16403f345a5dSKip Macy qs->qs_flags &= ~QS_TIMEOUT;
16413f345a5dSKip Macy TXQ_UNLOCK(qs);
16423f345a5dSKip Macy }
16433f345a5dSKip Macy }
16443f345a5dSKip Macy
16453f345a5dSKip Macy static void
cxgb_start_locked(struct sge_qset * qs)16463f345a5dSKip Macy cxgb_start_locked(struct sge_qset *qs)
16473f345a5dSKip Macy {
16483f345a5dSKip Macy struct mbuf *m_head = NULL;
16493f345a5dSKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
16503f345a5dSKip Macy struct port_info *pi = qs->port;
1651954712e8SJustin Hibbits if_t ifp = pi->ifp;
16523f345a5dSKip Macy
16533f345a5dSKip Macy if (qs->qs_flags & (QS_FLUSHING|QS_TIMEOUT))
16543f345a5dSKip Macy reclaim_completed_tx(qs, 0, TXQ_ETH);
16553f345a5dSKip Macy
16563f345a5dSKip Macy if (!pi->link_config.link_ok) {
16573f345a5dSKip Macy TXQ_RING_FLUSH(qs);
16583f345a5dSKip Macy return;
16593f345a5dSKip Macy }
16603f345a5dSKip Macy TXQ_LOCK_ASSERT(qs);
1661954712e8SJustin Hibbits while (!TXQ_RING_EMPTY(qs) && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) &&
16623f345a5dSKip Macy pi->link_config.link_ok) {
16633f345a5dSKip Macy reclaim_completed_tx(qs, cxgb_tx_reclaim_threshold, TXQ_ETH);
16643f345a5dSKip Macy
1665d2285960SNavdeep Parhar if (txq->size - txq->in_use <= TX_MAX_DESC)
1666d2285960SNavdeep Parhar break;
1667d2285960SNavdeep Parhar
16683f345a5dSKip Macy if ((m_head = cxgb_dequeue(qs)) == NULL)
16693f345a5dSKip Macy break;
16703f345a5dSKip Macy /*
16713f345a5dSKip Macy * Encapsulation can modify our pointer, and or make it
16723f345a5dSKip Macy * NULL on failure. In that event, we can't requeue.
16733f345a5dSKip Macy */
16743f345a5dSKip Macy if (t3_encap(qs, &m_head) || m_head == NULL)
16753f345a5dSKip Macy break;
16763f345a5dSKip Macy
16773f345a5dSKip Macy m_head = NULL;
16783f345a5dSKip Macy }
16791d4942f4SNavdeep Parhar
16801d4942f4SNavdeep Parhar if (txq->db_pending)
16811d4942f4SNavdeep Parhar check_ring_tx_db(pi->adapter, txq, 1);
16821d4942f4SNavdeep Parhar
16833f345a5dSKip Macy if (!TXQ_RING_EMPTY(qs) && callout_pending(&txq->txq_timer) == 0 &&
16843f345a5dSKip Macy pi->link_config.link_ok)
16853f345a5dSKip Macy callout_reset_on(&txq->txq_timer, 1, cxgb_tx_timeout,
16863f345a5dSKip Macy qs, txq->txq_timer.c_cpu);
16873f345a5dSKip Macy if (m_head != NULL)
16883f345a5dSKip Macy m_freem(m_head);
16893f345a5dSKip Macy }
16903f345a5dSKip Macy
16913f345a5dSKip Macy static int
cxgb_transmit_locked(if_t ifp,struct sge_qset * qs,struct mbuf * m)1692954712e8SJustin Hibbits cxgb_transmit_locked(if_t ifp, struct sge_qset *qs, struct mbuf *m)
16933f345a5dSKip Macy {
16943f345a5dSKip Macy struct port_info *pi = qs->port;
16953f345a5dSKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
16963f345a5dSKip Macy struct buf_ring *br = txq->txq_mr;
16973f345a5dSKip Macy int error, avail;
16983f345a5dSKip Macy
16993f345a5dSKip Macy avail = txq->size - txq->in_use;
17003f345a5dSKip Macy TXQ_LOCK_ASSERT(qs);
17013f345a5dSKip Macy
17023f345a5dSKip Macy /*
17033f345a5dSKip Macy * We can only do a direct transmit if the following are true:
17043f345a5dSKip Macy * - we aren't coalescing (ring < 3/4 full)
17053f345a5dSKip Macy * - the link is up -- checked in caller
17063f345a5dSKip Macy * - there are no packets enqueued already
17073f345a5dSKip Macy * - there is space in hardware transmit queue
17083f345a5dSKip Macy */
17093f345a5dSKip Macy if (check_pkt_coalesce(qs) == 0 &&
1710d2285960SNavdeep Parhar !TXQ_RING_NEEDS_ENQUEUE(qs) && avail > TX_MAX_DESC) {
17113f345a5dSKip Macy if (t3_encap(qs, &m)) {
17123f345a5dSKip Macy if (m != NULL &&
17133f345a5dSKip Macy (error = drbr_enqueue(ifp, br, m)) != 0)
17143f345a5dSKip Macy return (error);
17153f345a5dSKip Macy } else {
17161d4942f4SNavdeep Parhar if (txq->db_pending)
17171d4942f4SNavdeep Parhar check_ring_tx_db(pi->adapter, txq, 1);
17181d4942f4SNavdeep Parhar
17193f345a5dSKip Macy /*
17203f345a5dSKip Macy * We've bypassed the buf ring so we need to update
17213f345a5dSKip Macy * the stats directly
17223f345a5dSKip Macy */
17233f345a5dSKip Macy txq->txq_direct_packets++;
17243f345a5dSKip Macy txq->txq_direct_bytes += m->m_pkthdr.len;
17253f345a5dSKip Macy }
17263f345a5dSKip Macy } else if ((error = drbr_enqueue(ifp, br, m)) != 0)
17273f345a5dSKip Macy return (error);
17283f345a5dSKip Macy
17293f345a5dSKip Macy reclaim_completed_tx(qs, cxgb_tx_reclaim_threshold, TXQ_ETH);
17303f345a5dSKip Macy if (!TXQ_RING_EMPTY(qs) && pi->link_config.link_ok &&
17313f345a5dSKip Macy (!check_pkt_coalesce(qs) || (drbr_inuse(ifp, br) >= 7)))
17323f345a5dSKip Macy cxgb_start_locked(qs);
17333f345a5dSKip Macy else if (!TXQ_RING_EMPTY(qs) && !callout_pending(&txq->txq_timer))
17343f345a5dSKip Macy callout_reset_on(&txq->txq_timer, 1, cxgb_tx_timeout,
17353f345a5dSKip Macy qs, txq->txq_timer.c_cpu);
17363f345a5dSKip Macy return (0);
17373f345a5dSKip Macy }
17383f345a5dSKip Macy
17393f345a5dSKip Macy int
cxgb_transmit(if_t ifp,struct mbuf * m)1740954712e8SJustin Hibbits cxgb_transmit(if_t ifp, struct mbuf *m)
17413f345a5dSKip Macy {
17423f345a5dSKip Macy struct sge_qset *qs;
1743954712e8SJustin Hibbits struct port_info *pi = if_getsoftc(ifp);
17443f345a5dSKip Macy int error, qidx = pi->first_qset;
17453f345a5dSKip Macy
1746954712e8SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0
17473f345a5dSKip Macy ||(!pi->link_config.link_ok)) {
17483f345a5dSKip Macy m_freem(m);
17493f345a5dSKip Macy return (0);
17503f345a5dSKip Macy }
17513f345a5dSKip Macy
1752c2529042SHans Petter Selasky /* check if flowid is set */
1753c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
17543f345a5dSKip Macy qidx = (m->m_pkthdr.flowid % pi->nqsets) + pi->first_qset;
17553f345a5dSKip Macy
17563f345a5dSKip Macy qs = &pi->adapter->sge.qs[qidx];
17573f345a5dSKip Macy
17583f345a5dSKip Macy if (TXQ_TRYLOCK(qs)) {
17593f345a5dSKip Macy /* XXX running */
17603f345a5dSKip Macy error = cxgb_transmit_locked(ifp, qs, m);
17613f345a5dSKip Macy TXQ_UNLOCK(qs);
17623f345a5dSKip Macy } else
17633f345a5dSKip Macy error = drbr_enqueue(ifp, qs->txq[TXQ_ETH].txq_mr, m);
17643f345a5dSKip Macy return (error);
17653f345a5dSKip Macy }
17663f345a5dSKip Macy
17673f345a5dSKip Macy void
cxgb_qflush(if_t ifp)1768954712e8SJustin Hibbits cxgb_qflush(if_t ifp)
17693f345a5dSKip Macy {
17703f345a5dSKip Macy /*
17713f345a5dSKip Macy * flush any enqueued mbufs in the buf_rings
17723f345a5dSKip Macy * and in the transmit queues
17733f345a5dSKip Macy * no-op for now
17743f345a5dSKip Macy */
17753f345a5dSKip Macy return;
17763f345a5dSKip Macy }
1777b6d90eb7SKip Macy
1778b6d90eb7SKip Macy /**
1779b6d90eb7SKip Macy * write_imm - write a packet into a Tx descriptor as immediate data
1780b6d90eb7SKip Macy * @d: the Tx descriptor to write
1781b6d90eb7SKip Macy * @m: the packet
1782b6d90eb7SKip Macy * @len: the length of packet data to write as immediate data
1783b6d90eb7SKip Macy * @gen: the generation bit value to write
1784b6d90eb7SKip Macy *
1785b6d90eb7SKip Macy * Writes a packet as immediate data into a Tx descriptor. The packet
1786b6d90eb7SKip Macy * contains a work request at its beginning. We must write the packet
1787b6d90eb7SKip Macy * carefully so the SGE doesn't read accidentally before it's written in
1788b6d90eb7SKip Macy * its entirety.
1789b6d90eb7SKip Macy */
1790d722cab4SKip Macy static __inline void
write_imm(struct tx_desc * d,caddr_t src,unsigned int len,unsigned int gen)179109fe6320SNavdeep Parhar write_imm(struct tx_desc *d, caddr_t src,
1792b6d90eb7SKip Macy unsigned int len, unsigned int gen)
1793b6d90eb7SKip Macy {
179409fe6320SNavdeep Parhar struct work_request_hdr *from = (struct work_request_hdr *)src;
1795b6d90eb7SKip Macy struct work_request_hdr *to = (struct work_request_hdr *)d;
17963f345a5dSKip Macy uint32_t wr_hi, wr_lo;
1797b6d90eb7SKip Macy
179809fe6320SNavdeep Parhar KASSERT(len <= WR_LEN && len >= sizeof(*from),
179909fe6320SNavdeep Parhar ("%s: invalid len %d", __func__, len));
18008090c9f5SKip Macy
1801b6d90eb7SKip Macy memcpy(&to[1], &from[1], len - sizeof(*from));
18023f345a5dSKip Macy wr_hi = from->wrh_hi | htonl(F_WR_SOP | F_WR_EOP |
1803b6d90eb7SKip Macy V_WR_BCNTLFLT(len & 7));
180409fe6320SNavdeep Parhar wr_lo = from->wrh_lo | htonl(V_WR_GEN(gen) | V_WR_LEN((len + 7) / 8));
18053f345a5dSKip Macy set_wr_hdr(to, wr_hi, wr_lo);
18063f345a5dSKip Macy wmb();
1807b6d90eb7SKip Macy wr_gen2(d, gen);
1808b6d90eb7SKip Macy }
1809b6d90eb7SKip Macy
1810b6d90eb7SKip Macy /**
1811b6d90eb7SKip Macy * check_desc_avail - check descriptor availability on a send queue
1812b6d90eb7SKip Macy * @adap: the adapter
1813b6d90eb7SKip Macy * @q: the TX queue
1814b6d90eb7SKip Macy * @m: the packet needing the descriptors
1815b6d90eb7SKip Macy * @ndesc: the number of Tx descriptors needed
1816b6d90eb7SKip Macy * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL)
1817b6d90eb7SKip Macy *
1818b6d90eb7SKip Macy * Checks if the requested number of Tx descriptors is available on an
1819b6d90eb7SKip Macy * SGE send queue. If the queue is already suspended or not enough
1820b6d90eb7SKip Macy * descriptors are available the packet is queued for later transmission.
1821b6d90eb7SKip Macy * Must be called with the Tx queue locked.
1822b6d90eb7SKip Macy *
1823b6d90eb7SKip Macy * Returns 0 if enough descriptors are available, 1 if there aren't
1824b6d90eb7SKip Macy * enough descriptors and the packet has been queued, and 2 if the caller
1825b6d90eb7SKip Macy * needs to retry because there weren't enough descriptors at the
1826b6d90eb7SKip Macy * beginning of the call but some freed up in the mean time.
1827b6d90eb7SKip Macy */
1828b6d90eb7SKip Macy static __inline int
check_desc_avail(adapter_t * adap,struct sge_txq * q,struct mbuf * m,unsigned int ndesc,unsigned int qid)1829b6d90eb7SKip Macy check_desc_avail(adapter_t *adap, struct sge_txq *q,
1830b6d90eb7SKip Macy struct mbuf *m, unsigned int ndesc,
1831b6d90eb7SKip Macy unsigned int qid)
1832b6d90eb7SKip Macy {
1833b6d90eb7SKip Macy /*
1834b6d90eb7SKip Macy * XXX We currently only use this for checking the control queue
1835b6d90eb7SKip Macy * the control queue is only used for binding qsets which happens
1836b6d90eb7SKip Macy * at init time so we are guaranteed enough descriptors
1837b6d90eb7SKip Macy */
18388cb9b68fSJohn Baldwin if (__predict_false(!mbufq_empty(&q->sendq))) {
1839c578b6acSGleb Smirnoff addq_exit: (void )mbufq_enqueue(&q->sendq, m);
1840b6d90eb7SKip Macy return 1;
1841b6d90eb7SKip Macy }
1842b6d90eb7SKip Macy if (__predict_false(q->size - q->in_use < ndesc)) {
1843b6d90eb7SKip Macy
1844b6d90eb7SKip Macy struct sge_qset *qs = txq_to_qset(q, qid);
1845b6d90eb7SKip Macy
1846d722cab4SKip Macy setbit(&qs->txq_stopped, qid);
1847b6d90eb7SKip Macy if (should_restart_tx(q) &&
1848b6d90eb7SKip Macy test_and_clear_bit(qid, &qs->txq_stopped))
1849b6d90eb7SKip Macy return 2;
1850b6d90eb7SKip Macy
1851b6d90eb7SKip Macy q->stops++;
1852b6d90eb7SKip Macy goto addq_exit;
1853b6d90eb7SKip Macy }
1854b6d90eb7SKip Macy return 0;
1855b6d90eb7SKip Macy }
1856b6d90eb7SKip Macy
1857b6d90eb7SKip Macy
1858b6d90eb7SKip Macy /**
1859b6d90eb7SKip Macy * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
1860b6d90eb7SKip Macy * @q: the SGE control Tx queue
1861b6d90eb7SKip Macy *
1862b6d90eb7SKip Macy * This is a variant of reclaim_completed_tx() that is used for Tx queues
1863b6d90eb7SKip Macy * that send only immediate data (presently just the control queues) and
1864d722cab4SKip Macy * thus do not have any mbufs
1865b6d90eb7SKip Macy */
1866b6d90eb7SKip Macy static __inline void
reclaim_completed_tx_imm(struct sge_txq * q)1867b6d90eb7SKip Macy reclaim_completed_tx_imm(struct sge_txq *q)
1868b6d90eb7SKip Macy {
1869b6d90eb7SKip Macy unsigned int reclaim = q->processed - q->cleaned;
1870b6d90eb7SKip Macy
1871b6d90eb7SKip Macy q->in_use -= reclaim;
1872b6d90eb7SKip Macy q->cleaned += reclaim;
1873b6d90eb7SKip Macy }
1874b6d90eb7SKip Macy
1875b6d90eb7SKip Macy /**
1876b6d90eb7SKip Macy * ctrl_xmit - send a packet through an SGE control Tx queue
1877b6d90eb7SKip Macy * @adap: the adapter
1878b6d90eb7SKip Macy * @q: the control queue
1879b6d90eb7SKip Macy * @m: the packet
1880b6d90eb7SKip Macy *
1881b6d90eb7SKip Macy * Send a packet through an SGE control Tx queue. Packets sent through
1882b6d90eb7SKip Macy * a control queue must fit entirely as immediate data in a single Tx
1883b6d90eb7SKip Macy * descriptor and have no page fragments.
1884b6d90eb7SKip Macy */
1885b6d90eb7SKip Macy static int
ctrl_xmit(adapter_t * adap,struct sge_qset * qs,struct mbuf * m)18863f345a5dSKip Macy ctrl_xmit(adapter_t *adap, struct sge_qset *qs, struct mbuf *m)
1887b6d90eb7SKip Macy {
1888b6d90eb7SKip Macy int ret;
1889ef72318fSKip Macy struct work_request_hdr *wrp = mtod(m, struct work_request_hdr *);
18903f345a5dSKip Macy struct sge_txq *q = &qs->txq[TXQ_CTRL];
1891b6d90eb7SKip Macy
189209fe6320SNavdeep Parhar KASSERT(m->m_len <= WR_LEN, ("%s: bad tx data", __func__));
1893b6d90eb7SKip Macy
18943f345a5dSKip Macy wrp->wrh_hi |= htonl(F_WR_SOP | F_WR_EOP);
18953f345a5dSKip Macy wrp->wrh_lo = htonl(V_WR_TID(q->token));
1896b6d90eb7SKip Macy
18973f345a5dSKip Macy TXQ_LOCK(qs);
1898b6d90eb7SKip Macy again: reclaim_completed_tx_imm(q);
1899b6d90eb7SKip Macy
1900b6d90eb7SKip Macy ret = check_desc_avail(adap, q, m, 1, TXQ_CTRL);
1901b6d90eb7SKip Macy if (__predict_false(ret)) {
1902b6d90eb7SKip Macy if (ret == 1) {
19033f345a5dSKip Macy TXQ_UNLOCK(qs);
19048090c9f5SKip Macy return (ENOSPC);
1905b6d90eb7SKip Macy }
1906b6d90eb7SKip Macy goto again;
1907b6d90eb7SKip Macy }
190809fe6320SNavdeep Parhar write_imm(&q->desc[q->pidx], m->m_data, m->m_len, q->gen);
1909b6d90eb7SKip Macy
1910b6d90eb7SKip Macy q->in_use++;
1911b6d90eb7SKip Macy if (++q->pidx >= q->size) {
1912b6d90eb7SKip Macy q->pidx = 0;
1913b6d90eb7SKip Macy q->gen ^= 1;
1914b6d90eb7SKip Macy }
19153f345a5dSKip Macy TXQ_UNLOCK(qs);
191681af4f18SNavdeep Parhar wmb();
1917b6d90eb7SKip Macy t3_write_reg(adap, A_SG_KDOORBELL,
1918b6d90eb7SKip Macy F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
191909fe6320SNavdeep Parhar
192009fe6320SNavdeep Parhar m_free(m);
1921b6d90eb7SKip Macy return (0);
1922b6d90eb7SKip Macy }
1923b6d90eb7SKip Macy
1924d722cab4SKip Macy
1925b6d90eb7SKip Macy /**
1926b6d90eb7SKip Macy * restart_ctrlq - restart a suspended control queue
1927*e86d9dd6SGordon Bergling * @qs: the queue set containing the control queue
1928b6d90eb7SKip Macy *
1929b6d90eb7SKip Macy * Resumes transmission on a suspended Tx control queue.
1930b6d90eb7SKip Macy */
1931b6d90eb7SKip Macy static void
restart_ctrlq(void * data,int npending)1932d722cab4SKip Macy restart_ctrlq(void *data, int npending)
1933b6d90eb7SKip Macy {
1934b6d90eb7SKip Macy struct mbuf *m;
1935b6d90eb7SKip Macy struct sge_qset *qs = (struct sge_qset *)data;
1936b6d90eb7SKip Macy struct sge_txq *q = &qs->txq[TXQ_CTRL];
1937b6d90eb7SKip Macy adapter_t *adap = qs->port->adapter;
1938b6d90eb7SKip Macy
19393f345a5dSKip Macy TXQ_LOCK(qs);
1940b6d90eb7SKip Macy again: reclaim_completed_tx_imm(q);
1941b6d90eb7SKip Macy
1942b6d90eb7SKip Macy while (q->in_use < q->size &&
1943d722cab4SKip Macy (m = mbufq_dequeue(&q->sendq)) != NULL) {
1944b6d90eb7SKip Macy
194509fe6320SNavdeep Parhar write_imm(&q->desc[q->pidx], m->m_data, m->m_len, q->gen);
194609fe6320SNavdeep Parhar m_free(m);
1947b6d90eb7SKip Macy
1948b6d90eb7SKip Macy if (++q->pidx >= q->size) {
1949b6d90eb7SKip Macy q->pidx = 0;
1950b6d90eb7SKip Macy q->gen ^= 1;
1951b6d90eb7SKip Macy }
1952b6d90eb7SKip Macy q->in_use++;
1953b6d90eb7SKip Macy }
19548cb9b68fSJohn Baldwin if (!mbufq_empty(&q->sendq)) {
1955d722cab4SKip Macy setbit(&qs->txq_stopped, TXQ_CTRL);
1956b6d90eb7SKip Macy
1957b6d90eb7SKip Macy if (should_restart_tx(q) &&
1958b6d90eb7SKip Macy test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped))
1959b6d90eb7SKip Macy goto again;
1960b6d90eb7SKip Macy q->stops++;
1961b6d90eb7SKip Macy }
19623f345a5dSKip Macy TXQ_UNLOCK(qs);
1963b6d90eb7SKip Macy t3_write_reg(adap, A_SG_KDOORBELL,
1964b6d90eb7SKip Macy F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
1965b6d90eb7SKip Macy }
1966d722cab4SKip Macy
1967b6d90eb7SKip Macy
1968b6d90eb7SKip Macy /*
1969b6d90eb7SKip Macy * Send a management message through control queue 0
1970b6d90eb7SKip Macy */
1971b6d90eb7SKip Macy int
t3_mgmt_tx(struct adapter * adap,struct mbuf * m)1972b6d90eb7SKip Macy t3_mgmt_tx(struct adapter *adap, struct mbuf *m)
1973b6d90eb7SKip Macy {
19743f345a5dSKip Macy return ctrl_xmit(adap, &adap->sge.qs[0], m);
1975b6d90eb7SKip Macy }
1976b6d90eb7SKip Macy
1977b6d90eb7SKip Macy /**
1978b6d90eb7SKip Macy * free_qset - free the resources of an SGE queue set
1979b6d90eb7SKip Macy * @sc: the controller owning the queue set
1980b6d90eb7SKip Macy * @q: the queue set
1981b6d90eb7SKip Macy *
1982b6d90eb7SKip Macy * Release the HW and SW resources associated with an SGE queue set, such
1983b6d90eb7SKip Macy * as HW contexts, packet buffers, and descriptor rings. Traffic to the
1984b6d90eb7SKip Macy * queue set must be quiesced prior to calling this.
1985b6d90eb7SKip Macy */
19863f345a5dSKip Macy static void
t3_free_qset(adapter_t * sc,struct sge_qset * q)1987b6d90eb7SKip Macy t3_free_qset(adapter_t *sc, struct sge_qset *q)
1988b6d90eb7SKip Macy {
1989b6d90eb7SKip Macy int i;
1990b6d90eb7SKip Macy
19913f345a5dSKip Macy reclaim_completed_tx(q, 0, TXQ_ETH);
199297ae3bc3SNavdeep Parhar if (q->txq[TXQ_ETH].txq_mr != NULL)
199397ae3bc3SNavdeep Parhar buf_ring_free(q->txq[TXQ_ETH].txq_mr, M_DEVBUF);
199497ae3bc3SNavdeep Parhar if (q->txq[TXQ_ETH].txq_ifq != NULL) {
199597ae3bc3SNavdeep Parhar ifq_delete(q->txq[TXQ_ETH].txq_ifq);
199697ae3bc3SNavdeep Parhar free(q->txq[TXQ_ETH].txq_ifq, M_DEVBUF);
1997a02573bcSKip Macy }
1998a02573bcSKip Macy
1999b6d90eb7SKip Macy for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
2000b6d90eb7SKip Macy if (q->fl[i].desc) {
20018e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock);
2002b6d90eb7SKip Macy t3_sge_disable_fl(sc, q->fl[i].cntxt_id);
20038e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock);
2004b6d90eb7SKip Macy bus_dmamap_unload(q->fl[i].desc_tag, q->fl[i].desc_map);
2005b6d90eb7SKip Macy bus_dmamem_free(q->fl[i].desc_tag, q->fl[i].desc,
2006b6d90eb7SKip Macy q->fl[i].desc_map);
2007b6d90eb7SKip Macy bus_dma_tag_destroy(q->fl[i].desc_tag);
2008fa0521c0SKip Macy bus_dma_tag_destroy(q->fl[i].entry_tag);
2009b6d90eb7SKip Macy }
2010b6d90eb7SKip Macy if (q->fl[i].sdesc) {
2011b6d90eb7SKip Macy free_rx_bufs(sc, &q->fl[i]);
2012b6d90eb7SKip Macy free(q->fl[i].sdesc, M_DEVBUF);
2013b6d90eb7SKip Macy }
2014b6d90eb7SKip Macy }
2015b6d90eb7SKip Macy
20163f345a5dSKip Macy mtx_unlock(&q->lock);
20173f345a5dSKip Macy MTX_DESTROY(&q->lock);
2018bb38cd2fSKip Macy for (i = 0; i < SGE_TXQ_PER_SET; i++) {
2019b6d90eb7SKip Macy if (q->txq[i].desc) {
20208e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock);
2021b6d90eb7SKip Macy t3_sge_enable_ecntxt(sc, q->txq[i].cntxt_id, 0);
20228e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock);
2023b6d90eb7SKip Macy bus_dmamap_unload(q->txq[i].desc_tag,
2024b6d90eb7SKip Macy q->txq[i].desc_map);
2025b6d90eb7SKip Macy bus_dmamem_free(q->txq[i].desc_tag, q->txq[i].desc,
2026b6d90eb7SKip Macy q->txq[i].desc_map);
2027b6d90eb7SKip Macy bus_dma_tag_destroy(q->txq[i].desc_tag);
2028fa0521c0SKip Macy bus_dma_tag_destroy(q->txq[i].entry_tag);
2029b6d90eb7SKip Macy }
2030b6d90eb7SKip Macy if (q->txq[i].sdesc) {
2031b6d90eb7SKip Macy free(q->txq[i].sdesc, M_DEVBUF);
2032b6d90eb7SKip Macy }
2033b6d90eb7SKip Macy }
2034b6d90eb7SKip Macy
2035b6d90eb7SKip Macy if (q->rspq.desc) {
20368e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock);
2037b6d90eb7SKip Macy t3_sge_disable_rspcntxt(sc, q->rspq.cntxt_id);
20388e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock);
2039b6d90eb7SKip Macy
2040b6d90eb7SKip Macy bus_dmamap_unload(q->rspq.desc_tag, q->rspq.desc_map);
2041b6d90eb7SKip Macy bus_dmamem_free(q->rspq.desc_tag, q->rspq.desc,
2042b6d90eb7SKip Macy q->rspq.desc_map);
2043b6d90eb7SKip Macy bus_dma_tag_destroy(q->rspq.desc_tag);
2044bb38cd2fSKip Macy MTX_DESTROY(&q->rspq.lock);
2045b6d90eb7SKip Macy }
2046fa0521c0SKip Macy
204747cfa99aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
204825292debSKip Macy tcp_lro_free(&q->lro.ctrl);
204963122c7eSNavdeep Parhar #endif
205025292debSKip Macy
2051b6d90eb7SKip Macy bzero(q, sizeof(*q));
2052b6d90eb7SKip Macy }
2053b6d90eb7SKip Macy
2054b6d90eb7SKip Macy /**
2055b6d90eb7SKip Macy * t3_free_sge_resources - free SGE resources
2056b6d90eb7SKip Macy * @sc: the adapter softc
2057b6d90eb7SKip Macy *
2058b6d90eb7SKip Macy * Frees resources used by the SGE queue sets.
2059b6d90eb7SKip Macy */
2060b6d90eb7SKip Macy void
t3_free_sge_resources(adapter_t * sc,int nqsets)20617eeb16ceSNavdeep Parhar t3_free_sge_resources(adapter_t *sc, int nqsets)
2062b6d90eb7SKip Macy {
20637eeb16ceSNavdeep Parhar int i;
2064bb38cd2fSKip Macy
20653f345a5dSKip Macy for (i = 0; i < nqsets; ++i) {
20663f345a5dSKip Macy TXQ_LOCK(&sc->sge.qs[i]);
2067b6d90eb7SKip Macy t3_free_qset(sc, &sc->sge.qs[i]);
2068b6d90eb7SKip Macy }
20693f345a5dSKip Macy }
20703f345a5dSKip Macy
2071b6d90eb7SKip Macy /**
2072b6d90eb7SKip Macy * t3_sge_start - enable SGE
2073b6d90eb7SKip Macy * @sc: the controller softc
2074b6d90eb7SKip Macy *
2075b6d90eb7SKip Macy * Enables the SGE for DMAs. This is the last step in starting packet
2076b6d90eb7SKip Macy * transfers.
2077b6d90eb7SKip Macy */
2078b6d90eb7SKip Macy void
t3_sge_start(adapter_t * sc)2079b6d90eb7SKip Macy t3_sge_start(adapter_t *sc)
2080b6d90eb7SKip Macy {
2081b6d90eb7SKip Macy t3_set_reg_field(sc, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE);
2082b6d90eb7SKip Macy }
2083b6d90eb7SKip Macy
2084d722cab4SKip Macy /**
2085d722cab4SKip Macy * t3_sge_stop - disable SGE operation
2086d722cab4SKip Macy * @sc: the adapter
2087d722cab4SKip Macy *
2088d722cab4SKip Macy * Disables the DMA engine. This can be called in emeregencies (e.g.,
2089d722cab4SKip Macy * from error interrupts) or from normal process context. In the latter
2090d722cab4SKip Macy * case it also disables any pending queue restart tasklets. Note that
2091d722cab4SKip Macy * if it is called in interrupt context it cannot disable the restart
2092d722cab4SKip Macy * tasklets as it cannot wait, however the tasklets will have no effect
2093d722cab4SKip Macy * since the doorbells are disabled and the driver will call this again
2094d722cab4SKip Macy * later from process context, at which time the tasklets will be stopped
2095d722cab4SKip Macy * if they are still running.
2096d722cab4SKip Macy */
2097d722cab4SKip Macy void
t3_sge_stop(adapter_t * sc)2098d722cab4SKip Macy t3_sge_stop(adapter_t *sc)
2099d722cab4SKip Macy {
2100bb38cd2fSKip Macy
2101d722cab4SKip Macy t3_set_reg_field(sc, A_SG_CONTROL, F_GLOBALENABLE, 0);
2102d722cab4SKip Macy }
2103d722cab4SKip Macy
2104b6d90eb7SKip Macy /**
21058090c9f5SKip Macy * t3_free_tx_desc - reclaims Tx descriptors and their buffers
2106b6d90eb7SKip Macy * @adapter: the adapter
2107b6d90eb7SKip Macy * @q: the Tx queue to reclaim descriptors from
21088090c9f5SKip Macy * @reclaimable: the number of descriptors to reclaim
21098090c9f5SKip Macy * @m_vec_size: maximum number of buffers to reclaim
21108090c9f5SKip Macy * @desc_reclaimed: returns the number of descriptors reclaimed
2111b6d90eb7SKip Macy *
2112b6d90eb7SKip Macy * Reclaims Tx descriptors from an SGE Tx queue and frees the associated
2113b6d90eb7SKip Macy * Tx buffers. Called with the Tx queue lock held.
21148090c9f5SKip Macy *
21158090c9f5SKip Macy * Returns number of buffers of reclaimed
2116b6d90eb7SKip Macy */
21178090c9f5SKip Macy void
t3_free_tx_desc(struct sge_qset * qs,int reclaimable,int queue)21183f345a5dSKip Macy t3_free_tx_desc(struct sge_qset *qs, int reclaimable, int queue)
2119b6d90eb7SKip Macy {
21208090c9f5SKip Macy struct tx_sw_desc *txsd;
21213f345a5dSKip Macy unsigned int cidx, mask;
21223f345a5dSKip Macy struct sge_txq *q = &qs->txq[queue];
2123b6d90eb7SKip Macy
2124b6d90eb7SKip Macy #ifdef T3_TRACE
2125b6d90eb7SKip Macy T3_TRACE2(sc->tb[q->cntxt_id & 7],
21268090c9f5SKip Macy "reclaiming %u Tx descriptors at cidx %u", reclaimable, cidx);
2127b6d90eb7SKip Macy #endif
21288090c9f5SKip Macy cidx = q->cidx;
21293f345a5dSKip Macy mask = q->size - 1;
21308090c9f5SKip Macy txsd = &q->sdesc[cidx];
21313f345a5dSKip Macy
21323f345a5dSKip Macy mtx_assert(&qs->lock, MA_OWNED);
21338090c9f5SKip Macy while (reclaimable--) {
21343f345a5dSKip Macy prefetch(q->sdesc[(cidx + 1) & mask].m);
21353f345a5dSKip Macy prefetch(q->sdesc[(cidx + 2) & mask].m);
21363f345a5dSKip Macy
21373f345a5dSKip Macy if (txsd->m != NULL) {
21388090c9f5SKip Macy if (txsd->flags & TX_SW_DESC_MAPPED) {
21398090c9f5SKip Macy bus_dmamap_unload(q->entry_tag, txsd->map);
21408090c9f5SKip Macy txsd->flags &= ~TX_SW_DESC_MAPPED;
21418090c9f5SKip Macy }
21423f345a5dSKip Macy m_freem_list(txsd->m);
21433f345a5dSKip Macy txsd->m = NULL;
21448090c9f5SKip Macy } else
21458090c9f5SKip Macy q->txq_skipped++;
21468090c9f5SKip Macy
21478090c9f5SKip Macy ++txsd;
2148b6d90eb7SKip Macy if (++cidx == q->size) {
2149b6d90eb7SKip Macy cidx = 0;
21508090c9f5SKip Macy txsd = q->sdesc;
2151b6d90eb7SKip Macy }
2152b6d90eb7SKip Macy }
2153b6d90eb7SKip Macy q->cidx = cidx;
2154b6d90eb7SKip Macy
21558090c9f5SKip Macy }
21568090c9f5SKip Macy
2157b6d90eb7SKip Macy /**
2158b6d90eb7SKip Macy * is_new_response - check if a response is newly written
2159b6d90eb7SKip Macy * @r: the response descriptor
2160b6d90eb7SKip Macy * @q: the response queue
2161b6d90eb7SKip Macy *
2162b6d90eb7SKip Macy * Returns true if a response descriptor contains a yet unprocessed
2163b6d90eb7SKip Macy * response.
2164b6d90eb7SKip Macy */
2165b6d90eb7SKip Macy static __inline int
is_new_response(const struct rsp_desc * r,const struct sge_rspq * q)2166b6d90eb7SKip Macy is_new_response(const struct rsp_desc *r,
2167b6d90eb7SKip Macy const struct sge_rspq *q)
2168b6d90eb7SKip Macy {
2169b6d90eb7SKip Macy return (r->intr_gen & F_RSPD_GEN2) == q->gen;
2170b6d90eb7SKip Macy }
2171b6d90eb7SKip Macy
2172b6d90eb7SKip Macy #define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
2173b6d90eb7SKip Macy #define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
2174b6d90eb7SKip Macy V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
2175b6d90eb7SKip Macy V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \
2176b6d90eb7SKip Macy V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR))
2177b6d90eb7SKip Macy
2178b6d90eb7SKip Macy /* How long to delay the next interrupt in case of memory shortage, in 0.1us. */
2179b6d90eb7SKip Macy #define NOMEM_INTR_DELAY 2500
2180b6d90eb7SKip Macy
218109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
2182d722cab4SKip Macy /**
2183d722cab4SKip Macy * write_ofld_wr - write an offload work request
2184d722cab4SKip Macy * @adap: the adapter
2185d722cab4SKip Macy * @m: the packet to send
2186d722cab4SKip Macy * @q: the Tx queue
2187d722cab4SKip Macy * @pidx: index of the first Tx descriptor to write
2188d722cab4SKip Macy * @gen: the generation value to use
2189d722cab4SKip Macy * @ndesc: number of descriptors the packet will occupy
2190d722cab4SKip Macy *
2191d722cab4SKip Macy * Write an offload work request to send the supplied packet. The packet
2192d722cab4SKip Macy * data already carry the work request with most fields populated.
2193d722cab4SKip Macy */
2194d722cab4SKip Macy static void
write_ofld_wr(adapter_t * adap,struct mbuf * m,struct sge_txq * q,unsigned int pidx,unsigned int gen,unsigned int ndesc)219509fe6320SNavdeep Parhar write_ofld_wr(adapter_t *adap, struct mbuf *m, struct sge_txq *q,
219609fe6320SNavdeep Parhar unsigned int pidx, unsigned int gen, unsigned int ndesc)
2197b6d90eb7SKip Macy {
2198d722cab4SKip Macy unsigned int sgl_flits, flits;
219909fe6320SNavdeep Parhar int i, idx, nsegs, wrlen;
2200d722cab4SKip Macy struct work_request_hdr *from;
220109fe6320SNavdeep Parhar struct sg_ent *sgp, t3sgl[TX_MAX_SEGS / 2 + 1];
2202d722cab4SKip Macy struct tx_desc *d = &q->desc[pidx];
2203d722cab4SKip Macy struct txq_state txqs;
220409fe6320SNavdeep Parhar struct sglist_seg *segs;
220509fe6320SNavdeep Parhar struct ofld_hdr *oh = mtod(m, struct ofld_hdr *);
220609fe6320SNavdeep Parhar struct sglist *sgl;
2207d722cab4SKip Macy
220809fe6320SNavdeep Parhar from = (void *)(oh + 1); /* Start of WR within mbuf */
220909fe6320SNavdeep Parhar wrlen = m->m_len - sizeof(*oh);
221009fe6320SNavdeep Parhar
221109fe6320SNavdeep Parhar if (!(oh->flags & F_HDR_SGL)) {
221209fe6320SNavdeep Parhar write_imm(d, (caddr_t)from, wrlen, gen);
221309fe6320SNavdeep Parhar
221409fe6320SNavdeep Parhar /*
221509fe6320SNavdeep Parhar * mbuf with "real" immediate tx data will be enqueue_wr'd by
221609fe6320SNavdeep Parhar * t3_push_frames and freed in wr_ack. Others, like those sent
221709fe6320SNavdeep Parhar * down by close_conn, t3_send_reset, etc. should be freed here.
221809fe6320SNavdeep Parhar */
221909fe6320SNavdeep Parhar if (!(oh->flags & F_HDR_DF))
222009fe6320SNavdeep Parhar m_free(m);
2221d722cab4SKip Macy return;
2222b6d90eb7SKip Macy }
2223b6d90eb7SKip Macy
222409fe6320SNavdeep Parhar memcpy(&d->flit[1], &from[1], wrlen - sizeof(*from));
2225d722cab4SKip Macy
222609fe6320SNavdeep Parhar sgl = oh->sgl;
222709fe6320SNavdeep Parhar flits = wrlen / 8;
222809fe6320SNavdeep Parhar sgp = (ndesc == 1) ? (struct sg_ent *)&d->flit[flits] : t3sgl;
2229d722cab4SKip Macy
223009fe6320SNavdeep Parhar nsegs = sgl->sg_nseg;
223109fe6320SNavdeep Parhar segs = sgl->sg_segs;
223209fe6320SNavdeep Parhar for (idx = 0, i = 0; i < nsegs; i++) {
223309fe6320SNavdeep Parhar KASSERT(segs[i].ss_len, ("%s: 0 len in sgl", __func__));
223409fe6320SNavdeep Parhar if (i && idx == 0)
223509fe6320SNavdeep Parhar ++sgp;
223609fe6320SNavdeep Parhar sgp->len[idx] = htobe32(segs[i].ss_len);
223709fe6320SNavdeep Parhar sgp->addr[idx] = htobe64(segs[i].ss_paddr);
223809fe6320SNavdeep Parhar idx ^= 1;
223909fe6320SNavdeep Parhar }
224009fe6320SNavdeep Parhar if (idx) {
224109fe6320SNavdeep Parhar sgp->len[idx] = 0;
224209fe6320SNavdeep Parhar sgp->addr[idx] = 0;
224309fe6320SNavdeep Parhar }
224409fe6320SNavdeep Parhar
2245d722cab4SKip Macy sgl_flits = sgl_len(nsegs);
22468090c9f5SKip Macy txqs.gen = gen;
22478090c9f5SKip Macy txqs.pidx = pidx;
22488090c9f5SKip Macy txqs.compl = 0;
22498090c9f5SKip Macy
225009fe6320SNavdeep Parhar write_wr_hdr_sgl(ndesc, d, &txqs, q, t3sgl, flits, sgl_flits,
22513f345a5dSKip Macy from->wrh_hi, from->wrh_lo);
2252d722cab4SKip Macy }
2253d722cab4SKip Macy
2254d722cab4SKip Macy /**
2255d722cab4SKip Macy * ofld_xmit - send a packet through an offload queue
2256d722cab4SKip Macy * @adap: the adapter
2257d722cab4SKip Macy * @q: the Tx offload queue
2258d722cab4SKip Macy * @m: the packet
2259d722cab4SKip Macy *
2260d722cab4SKip Macy * Send an offload packet through an SGE offload queue.
2261d722cab4SKip Macy */
2262d722cab4SKip Macy static int
ofld_xmit(adapter_t * adap,struct sge_qset * qs,struct mbuf * m)22633f345a5dSKip Macy ofld_xmit(adapter_t *adap, struct sge_qset *qs, struct mbuf *m)
2264d722cab4SKip Macy {
226509fe6320SNavdeep Parhar int ret;
22667ac2e6c3SKip Macy unsigned int ndesc;
22677ac2e6c3SKip Macy unsigned int pidx, gen;
22683f345a5dSKip Macy struct sge_txq *q = &qs->txq[TXQ_OFLD];
226909fe6320SNavdeep Parhar struct ofld_hdr *oh = mtod(m, struct ofld_hdr *);
22708090c9f5SKip Macy
227109fe6320SNavdeep Parhar ndesc = G_HDR_NDESC(oh->flags);
2272d722cab4SKip Macy
22733f345a5dSKip Macy TXQ_LOCK(qs);
22743f345a5dSKip Macy again: reclaim_completed_tx(qs, 16, TXQ_OFLD);
2275d722cab4SKip Macy ret = check_desc_avail(adap, q, m, ndesc, TXQ_OFLD);
2276d722cab4SKip Macy if (__predict_false(ret)) {
2277d722cab4SKip Macy if (ret == 1) {
22783f345a5dSKip Macy TXQ_UNLOCK(qs);
22798090c9f5SKip Macy return (EINTR);
2280d722cab4SKip Macy }
2281d722cab4SKip Macy goto again;
2282d722cab4SKip Macy }
2283d722cab4SKip Macy
2284d722cab4SKip Macy gen = q->gen;
2285d722cab4SKip Macy q->in_use += ndesc;
2286d722cab4SKip Macy pidx = q->pidx;
2287d722cab4SKip Macy q->pidx += ndesc;
2288d722cab4SKip Macy if (q->pidx >= q->size) {
2289d722cab4SKip Macy q->pidx -= q->size;
2290d722cab4SKip Macy q->gen ^= 1;
2291d722cab4SKip Macy }
229209fe6320SNavdeep Parhar
229309fe6320SNavdeep Parhar write_ofld_wr(adap, m, q, pidx, gen, ndesc);
229409fe6320SNavdeep Parhar check_ring_tx_db(adap, q, 1);
22953f345a5dSKip Macy TXQ_UNLOCK(qs);
2296d722cab4SKip Macy
22978adc65adSKip Macy return (0);
2298d722cab4SKip Macy }
2299d722cab4SKip Macy
2300d722cab4SKip Macy /**
2301d722cab4SKip Macy * restart_offloadq - restart a suspended offload queue
2302*e86d9dd6SGordon Bergling * @qs: the queue set containing the offload queue
2303d722cab4SKip Macy *
2304d722cab4SKip Macy * Resumes transmission on a suspended Tx offload queue.
2305d722cab4SKip Macy */
2306d722cab4SKip Macy static void
restart_offloadq(void * data,int npending)2307d722cab4SKip Macy restart_offloadq(void *data, int npending)
2308d722cab4SKip Macy {
2309d722cab4SKip Macy struct mbuf *m;
2310d722cab4SKip Macy struct sge_qset *qs = data;
2311d722cab4SKip Macy struct sge_txq *q = &qs->txq[TXQ_OFLD];
2312d722cab4SKip Macy adapter_t *adap = qs->port->adapter;
2313d722cab4SKip Macy
23143f345a5dSKip Macy TXQ_LOCK(qs);
23156792568fSNavdeep Parhar again:
2316c578b6acSGleb Smirnoff while ((m = mbufq_first(&q->sendq)) != NULL) {
2317d722cab4SKip Macy unsigned int gen, pidx;
231809fe6320SNavdeep Parhar struct ofld_hdr *oh = mtod(m, struct ofld_hdr *);
231909fe6320SNavdeep Parhar unsigned int ndesc = G_HDR_NDESC(oh->flags);
2320d722cab4SKip Macy
2321d722cab4SKip Macy if (__predict_false(q->size - q->in_use < ndesc)) {
2322d722cab4SKip Macy setbit(&qs->txq_stopped, TXQ_OFLD);
2323d722cab4SKip Macy if (should_restart_tx(q) &&
2324d722cab4SKip Macy test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped))
2325d722cab4SKip Macy goto again;
2326d722cab4SKip Macy q->stops++;
2327d722cab4SKip Macy break;
2328d722cab4SKip Macy }
2329d722cab4SKip Macy
2330d722cab4SKip Macy gen = q->gen;
2331d722cab4SKip Macy q->in_use += ndesc;
2332d722cab4SKip Macy pidx = q->pidx;
2333d722cab4SKip Macy q->pidx += ndesc;
2334d722cab4SKip Macy if (q->pidx >= q->size) {
2335d722cab4SKip Macy q->pidx -= q->size;
2336d722cab4SKip Macy q->gen ^= 1;
2337d722cab4SKip Macy }
2338d722cab4SKip Macy
2339d722cab4SKip Macy (void)mbufq_dequeue(&q->sendq);
23403f345a5dSKip Macy TXQ_UNLOCK(qs);
234109fe6320SNavdeep Parhar write_ofld_wr(adap, m, q, pidx, gen, ndesc);
23423f345a5dSKip Macy TXQ_LOCK(qs);
2343d722cab4SKip Macy }
2344d722cab4SKip Macy #if USE_GTS
2345d722cab4SKip Macy set_bit(TXQ_RUNNING, &q->flags);
2346d722cab4SKip Macy set_bit(TXQ_LAST_PKT_DB, &q->flags);
2347d722cab4SKip Macy #endif
23483f345a5dSKip Macy TXQ_UNLOCK(qs);
23498e10660fSKip Macy wmb();
2350d722cab4SKip Macy t3_write_reg(adap, A_SG_KDOORBELL,
2351d722cab4SKip Macy F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
2352d722cab4SKip Macy }
2353d722cab4SKip Macy
2354d722cab4SKip Macy /**
2355d722cab4SKip Macy * t3_offload_tx - send an offload packet
2356d722cab4SKip Macy * @m: the packet
2357d722cab4SKip Macy *
2358d722cab4SKip Macy * Sends an offload packet. We use the packet priority to select the
2359d722cab4SKip Macy * appropriate Tx queue as follows: bit 0 indicates whether the packet
2360d722cab4SKip Macy * should be sent as regular or control, bits 1-3 select the queue set.
2361d722cab4SKip Macy */
2362d722cab4SKip Macy int
t3_offload_tx(struct adapter * sc,struct mbuf * m)236309fe6320SNavdeep Parhar t3_offload_tx(struct adapter *sc, struct mbuf *m)
2364d722cab4SKip Macy {
236509fe6320SNavdeep Parhar struct ofld_hdr *oh = mtod(m, struct ofld_hdr *);
236609fe6320SNavdeep Parhar struct sge_qset *qs = &sc->sge.qs[G_HDR_QSET(oh->flags)];
2367d722cab4SKip Macy
236809fe6320SNavdeep Parhar if (oh->flags & F_HDR_CTRL) {
236909fe6320SNavdeep Parhar m_adj(m, sizeof (*oh)); /* trim ofld_hdr off */
237009fe6320SNavdeep Parhar return (ctrl_xmit(sc, qs, m));
237109fe6320SNavdeep Parhar } else
237209fe6320SNavdeep Parhar return (ofld_xmit(sc, qs, m));
2373d722cab4SKip Macy }
237409fe6320SNavdeep Parhar #endif
2375b6d90eb7SKip Macy
2376b6d90eb7SKip Macy static void
restart_tx(struct sge_qset * qs)2377b6d90eb7SKip Macy restart_tx(struct sge_qset *qs)
2378b6d90eb7SKip Macy {
2379d722cab4SKip Macy struct adapter *sc = qs->port->adapter;
2380d722cab4SKip Macy
2381d722cab4SKip Macy if (isset(&qs->txq_stopped, TXQ_OFLD) &&
2382d722cab4SKip Macy should_restart_tx(&qs->txq[TXQ_OFLD]) &&
2383d722cab4SKip Macy test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
2384d722cab4SKip Macy qs->txq[TXQ_OFLD].restarts++;
2385b8fe6051SKip Macy taskqueue_enqueue(sc->tq, &qs->txq[TXQ_OFLD].qresume_task);
2386d722cab4SKip Macy }
23878090c9f5SKip Macy
2388d722cab4SKip Macy if (isset(&qs->txq_stopped, TXQ_CTRL) &&
2389d722cab4SKip Macy should_restart_tx(&qs->txq[TXQ_CTRL]) &&
2390d722cab4SKip Macy test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
2391d722cab4SKip Macy qs->txq[TXQ_CTRL].restarts++;
2392b8fe6051SKip Macy taskqueue_enqueue(sc->tq, &qs->txq[TXQ_CTRL].qresume_task);
2393d722cab4SKip Macy }
2394d722cab4SKip Macy }
2395d722cab4SKip Macy
2396d722cab4SKip Macy /**
2397d722cab4SKip Macy * t3_sge_alloc_qset - initialize an SGE queue set
2398d722cab4SKip Macy * @sc: the controller softc
2399d722cab4SKip Macy * @id: the queue set id
2400d722cab4SKip Macy * @nports: how many Ethernet ports will be using this queue set
2401d722cab4SKip Macy * @irq_vec_idx: the IRQ vector index for response queue interrupts
2402d722cab4SKip Macy * @p: configuration parameters for this queue set
2403d722cab4SKip Macy * @ntxq: number of Tx queues for the queue set
2404d722cab4SKip Macy * @pi: port info for queue set
2405d722cab4SKip Macy *
2406d722cab4SKip Macy * Allocate resources and initialize an SGE queue set. A queue set
2407d722cab4SKip Macy * comprises a response queue, two Rx free-buffer queues, and up to 3
2408d722cab4SKip Macy * Tx queues. The Tx queues are assigned roles in the order Ethernet
2409d722cab4SKip Macy * queue, offload queue, and control queue.
2410d722cab4SKip Macy */
2411d722cab4SKip Macy int
t3_sge_alloc_qset(adapter_t * sc,u_int id,int nports,int irq_vec_idx,const struct qset_params * p,int ntxq,struct port_info * pi)2412d722cab4SKip Macy t3_sge_alloc_qset(adapter_t *sc, u_int id, int nports, int irq_vec_idx,
2413d722cab4SKip Macy const struct qset_params *p, int ntxq, struct port_info *pi)
2414d722cab4SKip Macy {
2415d722cab4SKip Macy struct sge_qset *q = &sc->sge.qs[id];
24163f345a5dSKip Macy int i, ret = 0;
24173f345a5dSKip Macy
24183f345a5dSKip Macy MTX_INIT(&q->lock, q->namebuf, NULL, MTX_DEF);
24193f345a5dSKip Macy q->port = pi;
242009fe6320SNavdeep Parhar q->adap = sc;
2421d722cab4SKip Macy
2422bb51f7c8SZhenlei Huang q->txq[TXQ_ETH].txq_mr = buf_ring_alloc(cxgb_txq_buf_ring_size,
2423bb51f7c8SZhenlei Huang M_DEVBUF, M_WAITOK, &q->lock);
242497ae3bc3SNavdeep Parhar if ((q->txq[TXQ_ETH].txq_ifq = malloc(sizeof(struct ifaltq), M_DEVBUF,
242597ae3bc3SNavdeep Parhar M_NOWAIT | M_ZERO)) == NULL) {
2426a02573bcSKip Macy device_printf(sc->dev, "failed to allocate ifq\n");
2427a02573bcSKip Macy goto err;
24288090c9f5SKip Macy }
242997ae3bc3SNavdeep Parhar ifq_init(q->txq[TXQ_ETH].txq_ifq, pi->ifp);
243097ae3bc3SNavdeep Parhar callout_init(&q->txq[TXQ_ETH].txq_timer, 1);
243197ae3bc3SNavdeep Parhar callout_init(&q->txq[TXQ_ETH].txq_watchdog, 1);
243297ae3bc3SNavdeep Parhar q->txq[TXQ_ETH].txq_timer.c_cpu = id % mp_ncpus;
243397ae3bc3SNavdeep Parhar q->txq[TXQ_ETH].txq_watchdog.c_cpu = id % mp_ncpus;
243497ae3bc3SNavdeep Parhar
2435d722cab4SKip Macy init_qset_cntxt(q, id);
2436139edb19SKip Macy q->idx = id;
2437d722cab4SKip Macy if ((ret = alloc_ring(sc, p->fl_size, sizeof(struct rx_desc),
2438d722cab4SKip Macy sizeof(struct rx_sw_desc), &q->fl[0].phys_addr,
2439d722cab4SKip Macy &q->fl[0].desc, &q->fl[0].sdesc,
2440d722cab4SKip Macy &q->fl[0].desc_tag, &q->fl[0].desc_map,
2441d722cab4SKip Macy sc->rx_dmat, &q->fl[0].entry_tag)) != 0) {
2442d722cab4SKip Macy printf("error %d from alloc ring fl0\n", ret);
2443d722cab4SKip Macy goto err;
2444d722cab4SKip Macy }
2445d722cab4SKip Macy
2446d722cab4SKip Macy if ((ret = alloc_ring(sc, p->jumbo_size, sizeof(struct rx_desc),
2447d722cab4SKip Macy sizeof(struct rx_sw_desc), &q->fl[1].phys_addr,
2448d722cab4SKip Macy &q->fl[1].desc, &q->fl[1].sdesc,
2449d722cab4SKip Macy &q->fl[1].desc_tag, &q->fl[1].desc_map,
2450d722cab4SKip Macy sc->rx_jumbo_dmat, &q->fl[1].entry_tag)) != 0) {
2451d722cab4SKip Macy printf("error %d from alloc ring fl1\n", ret);
2452d722cab4SKip Macy goto err;
2453d722cab4SKip Macy }
2454d722cab4SKip Macy
2455d722cab4SKip Macy if ((ret = alloc_ring(sc, p->rspq_size, sizeof(struct rsp_desc), 0,
2456d722cab4SKip Macy &q->rspq.phys_addr, &q->rspq.desc, NULL,
2457d722cab4SKip Macy &q->rspq.desc_tag, &q->rspq.desc_map,
2458d722cab4SKip Macy NULL, NULL)) != 0) {
2459d722cab4SKip Macy printf("error %d from alloc ring rspq\n", ret);
2460d722cab4SKip Macy goto err;
2461d722cab4SKip Macy }
2462d722cab4SKip Macy
2463fef542feSNavdeep Parhar snprintf(q->rspq.lockbuf, RSPQ_NAME_LEN, "t3 rspq lock %d:%d",
2464fef542feSNavdeep Parhar device_get_unit(sc->dev), irq_vec_idx);
2465fef542feSNavdeep Parhar MTX_INIT(&q->rspq.lock, q->rspq.lockbuf, NULL, MTX_DEF);
2466fef542feSNavdeep Parhar
2467d722cab4SKip Macy for (i = 0; i < ntxq; ++i) {
2468d722cab4SKip Macy size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc);
2469d722cab4SKip Macy
2470d722cab4SKip Macy if ((ret = alloc_ring(sc, p->txq_size[i],
2471d722cab4SKip Macy sizeof(struct tx_desc), sz,
2472d722cab4SKip Macy &q->txq[i].phys_addr, &q->txq[i].desc,
2473d722cab4SKip Macy &q->txq[i].sdesc, &q->txq[i].desc_tag,
2474d722cab4SKip Macy &q->txq[i].desc_map,
2475d722cab4SKip Macy sc->tx_dmat, &q->txq[i].entry_tag)) != 0) {
2476d722cab4SKip Macy printf("error %d from alloc ring tx %i\n", ret, i);
2477d722cab4SKip Macy goto err;
2478d722cab4SKip Macy }
2479c578b6acSGleb Smirnoff mbufq_init(&q->txq[i].sendq, INT_MAX);
2480d722cab4SKip Macy q->txq[i].gen = 1;
2481d722cab4SKip Macy q->txq[i].size = p->txq_size[i];
2482d722cab4SKip Macy }
2483d722cab4SKip Macy
248409fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
2485b8fe6051SKip Macy TASK_INIT(&q->txq[TXQ_OFLD].qresume_task, 0, restart_offloadq, q);
248609fe6320SNavdeep Parhar #endif
2487b8fe6051SKip Macy TASK_INIT(&q->txq[TXQ_CTRL].qresume_task, 0, restart_ctrlq, q);
24883f345a5dSKip Macy TASK_INIT(&q->txq[TXQ_ETH].qreclaim_task, 0, sge_txq_reclaim_handler, q);
24893f345a5dSKip Macy TASK_INIT(&q->txq[TXQ_OFLD].qreclaim_task, 0, sge_txq_reclaim_handler, q);
2490b8fe6051SKip Macy
2491d722cab4SKip Macy q->fl[0].gen = q->fl[1].gen = 1;
2492d722cab4SKip Macy q->fl[0].size = p->fl_size;
2493d722cab4SKip Macy q->fl[1].size = p->jumbo_size;
2494d722cab4SKip Macy
2495d722cab4SKip Macy q->rspq.gen = 1;
2496ac3a6d9cSKip Macy q->rspq.cidx = 0;
2497d722cab4SKip Macy q->rspq.size = p->rspq_size;
2498d722cab4SKip Macy
2499d722cab4SKip Macy q->txq[TXQ_ETH].stop_thres = nports *
2500d722cab4SKip Macy flits_to_desc(sgl_len(TX_MAX_SEGS + 1) + 3);
2501d722cab4SKip Macy
25023f345a5dSKip Macy q->fl[0].buf_size = MCLBYTES;
25033f345a5dSKip Macy q->fl[0].zone = zone_pack;
25043f345a5dSKip Macy q->fl[0].type = EXT_PACKET;
250597ae3bc3SNavdeep Parhar
250697ae3bc3SNavdeep Parhar if (p->jumbo_buf_size == MJUM16BYTES) {
25078090c9f5SKip Macy q->fl[1].zone = zone_jumbo16;
25088090c9f5SKip Macy q->fl[1].type = EXT_JUMBO16;
250997ae3bc3SNavdeep Parhar } else if (p->jumbo_buf_size == MJUM9BYTES) {
2510f001b63dSKip Macy q->fl[1].zone = zone_jumbo9;
2511f001b63dSKip Macy q->fl[1].type = EXT_JUMBO9;
251297ae3bc3SNavdeep Parhar } else if (p->jumbo_buf_size == MJUMPAGESIZE) {
2513d722cab4SKip Macy q->fl[1].zone = zone_jumbop;
2514d722cab4SKip Macy q->fl[1].type = EXT_JUMBOP;
251597ae3bc3SNavdeep Parhar } else {
251697ae3bc3SNavdeep Parhar KASSERT(0, ("can't deal with jumbo_buf_size %d.", p->jumbo_buf_size));
251797ae3bc3SNavdeep Parhar ret = EDOOFUS;
251897ae3bc3SNavdeep Parhar goto err;
251997ae3bc3SNavdeep Parhar }
252097ae3bc3SNavdeep Parhar q->fl[1].buf_size = p->jumbo_buf_size;
252125292debSKip Macy
2522e97121daSKip Macy /* Allocate and setup the lro_ctrl structure */
2523954712e8SJustin Hibbits q->lro.enabled = !!(if_getcapenable(pi->ifp) & IFCAP_LRO);
252447cfa99aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
252525292debSKip Macy ret = tcp_lro_init(&q->lro.ctrl);
252625292debSKip Macy if (ret) {
252725292debSKip Macy printf("error %d from tcp_lro_init\n", ret);
252825292debSKip Macy goto err;
252925292debSKip Macy }
253063122c7eSNavdeep Parhar #endif
253125292debSKip Macy q->lro.ctrl.ifp = pi->ifp;
2532d722cab4SKip Macy
25338e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock);
2534d722cab4SKip Macy ret = -t3_sge_init_rspcntxt(sc, q->rspq.cntxt_id, irq_vec_idx,
2535d722cab4SKip Macy q->rspq.phys_addr, q->rspq.size,
2536d722cab4SKip Macy q->fl[0].buf_size, 1, 0);
2537d722cab4SKip Macy if (ret) {
2538d722cab4SKip Macy printf("error %d from t3_sge_init_rspcntxt\n", ret);
2539d722cab4SKip Macy goto err_unlock;
2540d722cab4SKip Macy }
2541d722cab4SKip Macy
2542d722cab4SKip Macy for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
2543d722cab4SKip Macy ret = -t3_sge_init_flcntxt(sc, q->fl[i].cntxt_id, 0,
2544d722cab4SKip Macy q->fl[i].phys_addr, q->fl[i].size,
2545d722cab4SKip Macy q->fl[i].buf_size, p->cong_thres, 1,
2546d722cab4SKip Macy 0);
2547d722cab4SKip Macy if (ret) {
2548d722cab4SKip Macy printf("error %d from t3_sge_init_flcntxt for index i=%d\n", ret, i);
2549d722cab4SKip Macy goto err_unlock;
2550d722cab4SKip Macy }
2551d722cab4SKip Macy }
2552d722cab4SKip Macy
2553d722cab4SKip Macy ret = -t3_sge_init_ecntxt(sc, q->txq[TXQ_ETH].cntxt_id, USE_GTS,
2554d722cab4SKip Macy SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr,
2555d722cab4SKip Macy q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token,
2556d722cab4SKip Macy 1, 0);
2557d722cab4SKip Macy if (ret) {
2558d722cab4SKip Macy printf("error %d from t3_sge_init_ecntxt\n", ret);
2559d722cab4SKip Macy goto err_unlock;
2560d722cab4SKip Macy }
2561d722cab4SKip Macy
2562d722cab4SKip Macy if (ntxq > 1) {
2563d722cab4SKip Macy ret = -t3_sge_init_ecntxt(sc, q->txq[TXQ_OFLD].cntxt_id,
2564d722cab4SKip Macy USE_GTS, SGE_CNTXT_OFLD, id,
2565d722cab4SKip Macy q->txq[TXQ_OFLD].phys_addr,
2566d722cab4SKip Macy q->txq[TXQ_OFLD].size, 0, 1, 0);
2567d722cab4SKip Macy if (ret) {
2568d722cab4SKip Macy printf("error %d from t3_sge_init_ecntxt\n", ret);
2569d722cab4SKip Macy goto err_unlock;
2570d722cab4SKip Macy }
2571d722cab4SKip Macy }
2572d722cab4SKip Macy
2573d722cab4SKip Macy if (ntxq > 2) {
2574d722cab4SKip Macy ret = -t3_sge_init_ecntxt(sc, q->txq[TXQ_CTRL].cntxt_id, 0,
2575d722cab4SKip Macy SGE_CNTXT_CTRL, id,
2576d722cab4SKip Macy q->txq[TXQ_CTRL].phys_addr,
2577d722cab4SKip Macy q->txq[TXQ_CTRL].size,
2578d722cab4SKip Macy q->txq[TXQ_CTRL].token, 1, 0);
2579d722cab4SKip Macy if (ret) {
2580d722cab4SKip Macy printf("error %d from t3_sge_init_ecntxt\n", ret);
2581d722cab4SKip Macy goto err_unlock;
2582d722cab4SKip Macy }
2583d722cab4SKip Macy }
2584d722cab4SKip Macy
25858e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock);
2586d722cab4SKip Macy t3_update_qset_coalesce(q, p);
2587d722cab4SKip Macy
2588d722cab4SKip Macy refill_fl(sc, &q->fl[0], q->fl[0].size);
2589d722cab4SKip Macy refill_fl(sc, &q->fl[1], q->fl[1].size);
2590d722cab4SKip Macy refill_rspq(sc, &q->rspq, q->rspq.size - 1);
2591d722cab4SKip Macy
2592d722cab4SKip Macy t3_write_reg(sc, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
2593d722cab4SKip Macy V_NEWTIMER(q->rspq.holdoff_tmr));
2594d722cab4SKip Macy
2595d722cab4SKip Macy return (0);
2596d722cab4SKip Macy
2597d722cab4SKip Macy err_unlock:
25988e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock);
2599d722cab4SKip Macy err:
26003f345a5dSKip Macy TXQ_LOCK(q);
2601d722cab4SKip Macy t3_free_qset(sc, q);
2602d722cab4SKip Macy
2603d722cab4SKip Macy return (ret);
2604b6d90eb7SKip Macy }
2605b6d90eb7SKip Macy
260625292debSKip Macy /*
260725292debSKip Macy * Remove CPL_RX_PKT headers from the mbuf and reduce it to a regular mbuf with
260825292debSKip Macy * ethernet data. Hardware assistance with various checksums and any vlan tag
260925292debSKip Macy * will also be taken into account here.
261025292debSKip Macy */
2611b6d90eb7SKip Macy void
t3_rx_eth(struct adapter * adap,struct mbuf * m,int ethpad)26120a704909SNavdeep Parhar t3_rx_eth(struct adapter *adap, struct mbuf *m, int ethpad)
2613b6d90eb7SKip Macy {
2614ef72318fSKip Macy struct cpl_rx_pkt *cpl = (struct cpl_rx_pkt *)(mtod(m, uint8_t *) + ethpad);
26157ac2e6c3SKip Macy struct port_info *pi = &adap->port[adap->rxpkt_map[cpl->iff]];
2616954712e8SJustin Hibbits if_t ifp = pi->ifp;
2617b6d90eb7SKip Macy
2618e83ec3e5SNavdeep Parhar if (cpl->vlan_valid) {
2619b6d90eb7SKip Macy m->m_pkthdr.ether_vtag = ntohs(cpl->vlan);
2620b6d90eb7SKip Macy m->m_flags |= M_VLANTAG;
2621b6d90eb7SKip Macy }
2622b6d90eb7SKip Macy
262351580731SKip Macy m->m_pkthdr.rcvif = ifp;
262451580731SKip Macy /*
262551580731SKip Macy * adjust after conversion to mbuf chain
262651580731SKip Macy */
26278090c9f5SKip Macy m->m_pkthdr.len -= (sizeof(*cpl) + ethpad);
26288090c9f5SKip Macy m->m_len -= (sizeof(*cpl) + ethpad);
26298090c9f5SKip Macy m->m_data += (sizeof(*cpl) + ethpad);
26300a704909SNavdeep Parhar
26310a704909SNavdeep Parhar if (!cpl->fragment && cpl->csum_valid && cpl->csum == 0xffff) {
26320a704909SNavdeep Parhar struct ether_header *eh = mtod(m, void *);
26330a704909SNavdeep Parhar uint16_t eh_type;
26340a704909SNavdeep Parhar
26350a704909SNavdeep Parhar if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
26360a704909SNavdeep Parhar struct ether_vlan_header *evh = mtod(m, void *);
26370a704909SNavdeep Parhar
26380a704909SNavdeep Parhar eh_type = evh->evl_proto;
26390a704909SNavdeep Parhar } else
26400a704909SNavdeep Parhar eh_type = eh->ether_type;
26410a704909SNavdeep Parhar
2642954712e8SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_RXCSUM &&
26430a704909SNavdeep Parhar eh_type == htons(ETHERTYPE_IP)) {
26440a704909SNavdeep Parhar m->m_pkthdr.csum_flags = (CSUM_IP_CHECKED |
26450a704909SNavdeep Parhar CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
26460a704909SNavdeep Parhar m->m_pkthdr.csum_data = 0xffff;
2647954712e8SJustin Hibbits } else if (if_getcapenable(ifp) & IFCAP_RXCSUM_IPV6 &&
26480a704909SNavdeep Parhar eh_type == htons(ETHERTYPE_IPV6)) {
26490a704909SNavdeep Parhar m->m_pkthdr.csum_flags = (CSUM_DATA_VALID_IPV6 |
26500a704909SNavdeep Parhar CSUM_PSEUDO_HDR);
26510a704909SNavdeep Parhar m->m_pkthdr.csum_data = 0xffff;
26520a704909SNavdeep Parhar }
26530a704909SNavdeep Parhar }
2654b6d90eb7SKip Macy }
2655b6d90eb7SKip Macy
2656f001b63dSKip Macy /**
2657f001b63dSKip Macy * get_packet - return the next ingress packet buffer from a free list
2658f001b63dSKip Macy * @adap: the adapter that received the packet
2659f001b63dSKip Macy * @drop_thres: # of remaining buffers before we start dropping packets
2660f001b63dSKip Macy * @qs: the qset that the SGE free list holding the packet belongs to
2661f001b63dSKip Macy * @mh: the mbuf header, contains a pointer to the head and tail of the mbuf chain
2662f001b63dSKip Macy * @r: response descriptor
2663f001b63dSKip Macy *
2664f001b63dSKip Macy * Get the next packet from a free list and complete setup of the
2665f001b63dSKip Macy * sk_buff. If the packet is small we make a copy and recycle the
2666f001b63dSKip Macy * original buffer, otherwise we use the original buffer itself. If a
2667f001b63dSKip Macy * positive drop threshold is supplied packets are dropped and their
2668f001b63dSKip Macy * buffers recycled if (a) the number of remaining buffers is under the
2669f001b63dSKip Macy * threshold and the packet is too big to copy, or (b) the packet should
2670f001b63dSKip Macy * be copied but there is no memory for the copy.
2671f001b63dSKip Macy */
2672f001b63dSKip Macy static int
get_packet(adapter_t * adap,unsigned int drop_thres,struct sge_qset * qs,struct t3_mbuf_hdr * mh,struct rsp_desc * r)2673f001b63dSKip Macy get_packet(adapter_t *adap, unsigned int drop_thres, struct sge_qset *qs,
267460f1e276SKip Macy struct t3_mbuf_hdr *mh, struct rsp_desc *r)
2675f001b63dSKip Macy {
2676f001b63dSKip Macy
2677f001b63dSKip Macy unsigned int len_cq = ntohl(r->len_cq);
2678f001b63dSKip Macy struct sge_fl *fl = (len_cq & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
26793f345a5dSKip Macy int mask, cidx = fl->cidx;
26803f345a5dSKip Macy struct rx_sw_desc *sd = &fl->sdesc[cidx];
2681f001b63dSKip Macy uint32_t len = G_RSPD_LEN(len_cq);
26823f345a5dSKip Macy uint32_t flags = M_EXT;
26833f345a5dSKip Macy uint8_t sopeop = G_RSPD_SOP_EOP(ntohl(r->flags));
2684a57927a1SKip Macy caddr_t cl;
26853f345a5dSKip Macy struct mbuf *m;
2686f001b63dSKip Macy int ret = 0;
2687f001b63dSKip Macy
26883f345a5dSKip Macy mask = fl->size - 1;
26893f345a5dSKip Macy prefetch(fl->sdesc[(cidx + 1) & mask].m);
26903f345a5dSKip Macy prefetch(fl->sdesc[(cidx + 2) & mask].m);
26913f345a5dSKip Macy prefetch(fl->sdesc[(cidx + 1) & mask].rxsd_cl);
26923f345a5dSKip Macy prefetch(fl->sdesc[(cidx + 2) & mask].rxsd_cl);
2693f001b63dSKip Macy
2694f001b63dSKip Macy fl->credits--;
2695f001b63dSKip Macy bus_dmamap_sync(fl->entry_tag, sd->map, BUS_DMASYNC_POSTREAD);
2696f001b63dSKip Macy
26973f345a5dSKip Macy if (recycle_enable && len <= SGE_RX_COPY_THRES &&
26983f345a5dSKip Macy sopeop == RSPQ_SOP_EOP) {
2699c6499eccSGleb Smirnoff if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
2700f001b63dSKip Macy goto skip_recycle;
27013f345a5dSKip Macy cl = mtod(m, void *);
27023f345a5dSKip Macy memcpy(cl, sd->rxsd_cl, len);
2703f001b63dSKip Macy recycle_rx_buf(adap, fl, fl->cidx);
27043f345a5dSKip Macy m->m_pkthdr.len = m->m_len = len;
27053f345a5dSKip Macy m->m_flags = 0;
27063f345a5dSKip Macy mh->mh_head = mh->mh_tail = m;
27073f345a5dSKip Macy ret = 1;
27083f345a5dSKip Macy goto done;
2709f001b63dSKip Macy } else {
2710f001b63dSKip Macy skip_recycle:
2711f001b63dSKip Macy bus_dmamap_unload(fl->entry_tag, sd->map);
2712f001b63dSKip Macy cl = sd->rxsd_cl;
27133f345a5dSKip Macy m = sd->m;
2714f001b63dSKip Macy
2715f001b63dSKip Macy if ((sopeop == RSPQ_SOP_EOP) ||
2716f001b63dSKip Macy (sopeop == RSPQ_SOP))
27173f345a5dSKip Macy flags |= M_PKTHDR;
2718b4b12e52SGleb Smirnoff m_init(m, M_NOWAIT, MT_DATA, flags);
27193f345a5dSKip Macy if (fl->zone == zone_pack) {
27203f345a5dSKip Macy /*
27213f345a5dSKip Macy * restore clobbered data pointer
27223f345a5dSKip Macy */
27233f345a5dSKip Macy m->m_data = m->m_ext.ext_buf;
27243f345a5dSKip Macy } else {
27253f345a5dSKip Macy m_cljset(m, cl, fl->type);
27263f345a5dSKip Macy }
27273f345a5dSKip Macy m->m_len = len;
2728f001b63dSKip Macy }
2729f001b63dSKip Macy switch(sopeop) {
2730f001b63dSKip Macy case RSPQ_SOP_EOP:
27313f345a5dSKip Macy ret = 1;
27323f345a5dSKip Macy /* FALLTHROUGH */
27333f345a5dSKip Macy case RSPQ_SOP:
2734f001b63dSKip Macy mh->mh_head = mh->mh_tail = m;
2735f001b63dSKip Macy m->m_pkthdr.len = len;
2736f001b63dSKip Macy break;
27373f345a5dSKip Macy case RSPQ_EOP:
27383f345a5dSKip Macy ret = 1;
27393f345a5dSKip Macy /* FALLTHROUGH */
2740f001b63dSKip Macy case RSPQ_NSOP_NEOP:
2741f001b63dSKip Macy if (mh->mh_tail == NULL) {
2742a57927a1SKip Macy log(LOG_ERR, "discarding intermediate descriptor entry\n");
2743f001b63dSKip Macy m_freem(m);
274416f8f89cSMark Johnston m = NULL;
2745f001b63dSKip Macy break;
2746f001b63dSKip Macy }
2747f001b63dSKip Macy mh->mh_tail->m_next = m;
2748f001b63dSKip Macy mh->mh_tail = m;
2749f001b63dSKip Macy mh->mh_head->m_pkthdr.len += len;
2750f001b63dSKip Macy break;
2751f001b63dSKip Macy }
275216f8f89cSMark Johnston if (cxgb_debug && m != NULL)
27533f345a5dSKip Macy printf("len=%d pktlen=%d\n", m->m_len, m->m_pkthdr.len);
2754c0a24dd4SKip Macy done:
2755b6d90eb7SKip Macy if (++fl->cidx == fl->size)
2756b6d90eb7SKip Macy fl->cidx = 0;
2757b6d90eb7SKip Macy
2758b6d90eb7SKip Macy return (ret);
2759b6d90eb7SKip Macy }
27603f345a5dSKip Macy
2761b6d90eb7SKip Macy /**
2762b6d90eb7SKip Macy * handle_rsp_cntrl_info - handles control information in a response
2763b6d90eb7SKip Macy * @qs: the queue set corresponding to the response
2764b6d90eb7SKip Macy * @flags: the response control flags
2765b6d90eb7SKip Macy *
2766b6d90eb7SKip Macy * Handles the control information of an SGE response, such as GTS
2767b6d90eb7SKip Macy * indications and completion credits for the queue set's Tx queues.
2768b6d90eb7SKip Macy * HW coalesces credits, we don't do any extra SW coalescing.
2769b6d90eb7SKip Macy */
2770b6d90eb7SKip Macy static __inline void
handle_rsp_cntrl_info(struct sge_qset * qs,uint32_t flags)2771b6d90eb7SKip Macy handle_rsp_cntrl_info(struct sge_qset *qs, uint32_t flags)
2772b6d90eb7SKip Macy {
2773b6d90eb7SKip Macy unsigned int credits;
2774b6d90eb7SKip Macy
2775b6d90eb7SKip Macy #if USE_GTS
2776b6d90eb7SKip Macy if (flags & F_RSPD_TXQ0_GTS)
2777b6d90eb7SKip Macy clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags);
2778b6d90eb7SKip Macy #endif
2779b6d90eb7SKip Macy credits = G_RSPD_TXQ0_CR(flags);
2780f001b63dSKip Macy if (credits)
2781b6d90eb7SKip Macy qs->txq[TXQ_ETH].processed += credits;
2782b6d90eb7SKip Macy
2783b6d90eb7SKip Macy credits = G_RSPD_TXQ2_CR(flags);
2784b6d90eb7SKip Macy if (credits)
2785b6d90eb7SKip Macy qs->txq[TXQ_CTRL].processed += credits;
2786b6d90eb7SKip Macy
2787b6d90eb7SKip Macy # if USE_GTS
2788b6d90eb7SKip Macy if (flags & F_RSPD_TXQ1_GTS)
2789b6d90eb7SKip Macy clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags);
2790b6d90eb7SKip Macy # endif
2791b6d90eb7SKip Macy credits = G_RSPD_TXQ1_CR(flags);
2792b6d90eb7SKip Macy if (credits)
2793b6d90eb7SKip Macy qs->txq[TXQ_OFLD].processed += credits;
27948090c9f5SKip Macy
2795b6d90eb7SKip Macy }
2796b6d90eb7SKip Macy
2797b6d90eb7SKip Macy static void
check_ring_db(adapter_t * adap,struct sge_qset * qs,unsigned int sleeping)2798b6d90eb7SKip Macy check_ring_db(adapter_t *adap, struct sge_qset *qs,
2799b6d90eb7SKip Macy unsigned int sleeping)
2800b6d90eb7SKip Macy {
2801b6d90eb7SKip Macy ;
2802b6d90eb7SKip Macy }
2803b6d90eb7SKip Macy
2804b6d90eb7SKip Macy /**
2805b6d90eb7SKip Macy * process_responses - process responses from an SGE response queue
2806b6d90eb7SKip Macy * @adap: the adapter
2807b6d90eb7SKip Macy * @qs: the queue set to which the response queue belongs
2808b6d90eb7SKip Macy * @budget: how many responses can be processed in this round
2809b6d90eb7SKip Macy *
2810b6d90eb7SKip Macy * Process responses from an SGE response queue up to the supplied budget.
2811b6d90eb7SKip Macy * Responses include received packets as well as credits and other events
2812b6d90eb7SKip Macy * for the queues that belong to the response queue's queue set.
2813b6d90eb7SKip Macy * A negative budget is effectively unlimited.
2814b6d90eb7SKip Macy *
2815b6d90eb7SKip Macy * Additionally choose the interrupt holdoff time for the next interrupt
2816b6d90eb7SKip Macy * on this queue. If the system is under memory shortage use a fairly
2817b6d90eb7SKip Macy * long delay to help recovery.
2818b6d90eb7SKip Macy */
28193f345a5dSKip Macy static int
process_responses(adapter_t * adap,struct sge_qset * qs,int budget)2820b6d90eb7SKip Macy process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
2821b6d90eb7SKip Macy {
2822b6d90eb7SKip Macy struct sge_rspq *rspq = &qs->rspq;
2823b6d90eb7SKip Macy struct rsp_desc *r = &rspq->desc[rspq->cidx];
2824b6d90eb7SKip Macy int budget_left = budget;
2825b6d90eb7SKip Macy unsigned int sleeping = 0;
282647cfa99aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
282725292debSKip Macy int lro_enabled = qs->lro.enabled;
28285ec372d1SKip Macy int skip_lro;
282925292debSKip Macy struct lro_ctrl *lro_ctrl = &qs->lro.ctrl;
283047cfa99aSBjoern A. Zeeb #endif
283127d1c65eSNavdeep Parhar struct t3_mbuf_hdr *mh = &rspq->rspq_mh;
2832b6d90eb7SKip Macy #ifdef DEBUG
2833b6d90eb7SKip Macy static int last_holdoff = 0;
2834ac3a6d9cSKip Macy if (cxgb_debug && rspq->holdoff_tmr != last_holdoff) {
2835b6d90eb7SKip Macy printf("next_holdoff=%d\n", rspq->holdoff_tmr);
2836b6d90eb7SKip Macy last_holdoff = rspq->holdoff_tmr;
2837b6d90eb7SKip Macy }
2838b6d90eb7SKip Macy #endif
2839b6d90eb7SKip Macy rspq->next_holdoff = rspq->holdoff_tmr;
2840b6d90eb7SKip Macy
2841b6d90eb7SKip Macy while (__predict_true(budget_left && is_new_response(r, rspq))) {
2842b6d90eb7SKip Macy int eth, eop = 0, ethpad = 0;
2843b6d90eb7SKip Macy uint32_t flags = ntohl(r->flags);
28448090c9f5SKip Macy uint32_t rss_hash = be32toh(r->rss_hdr.rss_hash_val);
284509fe6320SNavdeep Parhar uint8_t opcode = r->rss_hdr.opcode;
2846b6d90eb7SKip Macy
284709fe6320SNavdeep Parhar eth = (opcode == CPL_RX_PKT);
2848b6d90eb7SKip Macy
2849b6d90eb7SKip Macy if (__predict_false(flags & F_RSPD_ASYNC_NOTIF)) {
28508e10660fSKip Macy struct mbuf *m;
28518e10660fSKip Macy
28528e10660fSKip Macy if (cxgb_debug)
2853b6d90eb7SKip Macy printf("async notification\n");
2854b6d90eb7SKip Macy
285527d1c65eSNavdeep Parhar if (mh->mh_head == NULL) {
2856c6499eccSGleb Smirnoff mh->mh_head = m_gethdr(M_NOWAIT, MT_DATA);
285727d1c65eSNavdeep Parhar m = mh->mh_head;
28588e10660fSKip Macy } else {
2859c6499eccSGleb Smirnoff m = m_gethdr(M_NOWAIT, MT_DATA);
28608e10660fSKip Macy }
28618e10660fSKip Macy if (m == NULL)
28628e10660fSKip Macy goto no_mem;
28638e10660fSKip Macy
28648e10660fSKip Macy memcpy(mtod(m, char *), r, AN_PKT_SIZE);
28658e10660fSKip Macy m->m_len = m->m_pkthdr.len = AN_PKT_SIZE;
28662db7b9f2SDimitry Andric *mtod(m, uint8_t *) = CPL_ASYNC_NOTIF;
286709fe6320SNavdeep Parhar opcode = CPL_ASYNC_NOTIF;
28688e10660fSKip Macy eop = 1;
28698e10660fSKip Macy rspq->async_notif++;
28708e10660fSKip Macy goto skip;
2871b6d90eb7SKip Macy } else if (flags & F_RSPD_IMM_DATA_VALID) {
2872c6499eccSGleb Smirnoff struct mbuf *m = m_gethdr(M_NOWAIT, MT_DATA);
2873f001b63dSKip Macy
287409fe6320SNavdeep Parhar if (m == NULL) {
28758e10660fSKip Macy no_mem:
2876b6d90eb7SKip Macy rspq->next_holdoff = NOMEM_INTR_DELAY;
2877b6d90eb7SKip Macy budget_left--;
2878b6d90eb7SKip Macy break;
2879b6d90eb7SKip Macy }
288009fe6320SNavdeep Parhar if (mh->mh_head == NULL)
288109fe6320SNavdeep Parhar mh->mh_head = m;
288209fe6320SNavdeep Parhar else
288309fe6320SNavdeep Parhar mh->mh_tail->m_next = m;
288409fe6320SNavdeep Parhar mh->mh_tail = m;
288509fe6320SNavdeep Parhar
288609fe6320SNavdeep Parhar get_imm_packet(adap, r, m);
288709fe6320SNavdeep Parhar mh->mh_head->m_pkthdr.len += m->m_len;
2888c0a24dd4SKip Macy eop = 1;
2889b6d90eb7SKip Macy rspq->imm_data++;
2890b6d90eb7SKip Macy } else if (r->len_cq) {
2891b6d90eb7SKip Macy int drop_thresh = eth ? SGE_RX_DROP_THRES : 0;
2892fa0521c0SKip Macy
289327d1c65eSNavdeep Parhar eop = get_packet(adap, drop_thresh, qs, mh, r);
28943f345a5dSKip Macy if (eop) {
2895c2529042SHans Petter Selasky if (r->rss_hdr.hash_type && !adap->timestamp) {
289636ad8372SSepherosa Ziehau M_HASHTYPE_SET(mh->mh_head,
289736ad8372SSepherosa Ziehau M_HASHTYPE_OPAQUE_HASH);
289827d1c65eSNavdeep Parhar mh->mh_head->m_pkthdr.flowid = rss_hash;
28993f345a5dSKip Macy }
2900c2529042SHans Petter Selasky }
29013f345a5dSKip Macy
2902b6d90eb7SKip Macy ethpad = 2;
2903b6d90eb7SKip Macy } else {
2904b6d90eb7SKip Macy rspq->pure_rsps++;
2905b6d90eb7SKip Macy }
29068e10660fSKip Macy skip:
2907b6d90eb7SKip Macy if (flags & RSPD_CTRL_MASK) {
2908b6d90eb7SKip Macy sleeping |= flags & RSPD_GTS_MASK;
2909b6d90eb7SKip Macy handle_rsp_cntrl_info(qs, flags);
2910b6d90eb7SKip Macy }
29118090c9f5SKip Macy
29128090c9f5SKip Macy if (!eth && eop) {
291309fe6320SNavdeep Parhar rspq->offload_pkts++;
291409fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
291509fe6320SNavdeep Parhar adap->cpl_handler[opcode](qs, r, mh->mh_head);
291609fe6320SNavdeep Parhar #else
291709fe6320SNavdeep Parhar m_freem(mh->mh_head);
291809fe6320SNavdeep Parhar #endif
291927d1c65eSNavdeep Parhar mh->mh_head = NULL;
29208090c9f5SKip Macy } else if (eth && eop) {
292127d1c65eSNavdeep Parhar struct mbuf *m = mh->mh_head;
29228090c9f5SKip Macy
29230a704909SNavdeep Parhar t3_rx_eth(adap, m, ethpad);
29245ec372d1SKip Macy
29255ec372d1SKip Macy /*
29265ec372d1SKip Macy * The T304 sends incoming packets on any qset. If LRO
29275ec372d1SKip Macy * is also enabled, we could end up sending packet up
29285ec372d1SKip Macy * lro_ctrl->ifp's input. That is incorrect.
29295ec372d1SKip Macy *
29305ec372d1SKip Macy * The mbuf's rcvif was derived from the cpl header and
29315ec372d1SKip Macy * is accurate. Skip LRO and just use that.
29325ec372d1SKip Macy */
293347cfa99aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
29345ec372d1SKip Macy skip_lro = __predict_false(qs->port->ifp != m->m_pkthdr.rcvif);
29355ec372d1SKip Macy
293663122c7eSNavdeep Parhar if (lro_enabled && lro_ctrl->lro_cnt && !skip_lro
293763122c7eSNavdeep Parhar && (tcp_lro_rx(lro_ctrl, m, 0) == 0)
293863122c7eSNavdeep Parhar ) {
293925292debSKip Macy /* successfully queue'd for LRO */
294047cfa99aSBjoern A. Zeeb } else
294147cfa99aSBjoern A. Zeeb #endif
294247cfa99aSBjoern A. Zeeb {
294325292debSKip Macy /*
294425292debSKip Macy * LRO not enabled, packet unsuitable for LRO,
294525292debSKip Macy * or unable to queue. Pass it up right now in
294625292debSKip Macy * either case.
294725292debSKip Macy */
2948954712e8SJustin Hibbits if_t ifp = m->m_pkthdr.rcvif;
2949954712e8SJustin Hibbits if_input(ifp, m);
295025292debSKip Macy }
295127d1c65eSNavdeep Parhar mh->mh_head = NULL;
29528870f0e1SKip Macy
2953b6d90eb7SKip Macy }
295409fe6320SNavdeep Parhar
295509fe6320SNavdeep Parhar r++;
295609fe6320SNavdeep Parhar if (__predict_false(++rspq->cidx == rspq->size)) {
295709fe6320SNavdeep Parhar rspq->cidx = 0;
295809fe6320SNavdeep Parhar rspq->gen ^= 1;
295909fe6320SNavdeep Parhar r = rspq->desc;
296009fe6320SNavdeep Parhar }
296109fe6320SNavdeep Parhar
296209fe6320SNavdeep Parhar if (++rspq->credits >= 64) {
296309fe6320SNavdeep Parhar refill_rspq(adap, rspq, rspq->credits);
296409fe6320SNavdeep Parhar rspq->credits = 0;
296509fe6320SNavdeep Parhar }
29668090c9f5SKip Macy __refill_fl_lt(adap, &qs->fl[0], 32);
29678090c9f5SKip Macy __refill_fl_lt(adap, &qs->fl[1], 32);
2968b6d90eb7SKip Macy --budget_left;
2969b6d90eb7SKip Macy }
2970d722cab4SKip Macy
297147cfa99aSBjoern A. Zeeb #if defined(INET6) || defined(INET)
297225292debSKip Macy /* Flush LRO */
29736dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro_ctrl);
297463122c7eSNavdeep Parhar #endif
2975b6d90eb7SKip Macy
2976b6d90eb7SKip Macy if (sleeping)
2977b6d90eb7SKip Macy check_ring_db(adap, qs, sleeping);
2978b6d90eb7SKip Macy
29793f345a5dSKip Macy mb(); /* commit Tx queue processed updates */
298081af4f18SNavdeep Parhar if (__predict_false(qs->txq_stopped > 1))
29818090c9f5SKip Macy restart_tx(qs);
29828090c9f5SKip Macy
29838090c9f5SKip Macy __refill_fl_lt(adap, &qs->fl[0], 512);
29848090c9f5SKip Macy __refill_fl_lt(adap, &qs->fl[1], 512);
2985b6d90eb7SKip Macy budget -= budget_left;
2986b6d90eb7SKip Macy return (budget);
2987b6d90eb7SKip Macy }
2988b6d90eb7SKip Macy
2989b6d90eb7SKip Macy /*
2990b6d90eb7SKip Macy * A helper function that processes responses and issues GTS.
2991b6d90eb7SKip Macy */
2992b6d90eb7SKip Macy static __inline int
process_responses_gts(adapter_t * adap,struct sge_rspq * rq)2993b6d90eb7SKip Macy process_responses_gts(adapter_t *adap, struct sge_rspq *rq)
2994b6d90eb7SKip Macy {
2995b6d90eb7SKip Macy int work;
2996b6d90eb7SKip Macy static int last_holdoff = 0;
2997b6d90eb7SKip Macy
2998b6d90eb7SKip Macy work = process_responses(adap, rspq_to_qset(rq), -1);
2999b6d90eb7SKip Macy
3000b6d90eb7SKip Macy if (cxgb_debug && (rq->next_holdoff != last_holdoff)) {
3001b6d90eb7SKip Macy printf("next_holdoff=%d\n", rq->next_holdoff);
3002b6d90eb7SKip Macy last_holdoff = rq->next_holdoff;
3003b6d90eb7SKip Macy }
3004b6d90eb7SKip Macy t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) |
3005b6d90eb7SKip Macy V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx));
30069cce0038SKip Macy
30079cce0038SKip Macy return (work);
3008b6d90eb7SKip Macy }
3009b6d90eb7SKip Macy
30107790c8c1SConrad Meyer #ifdef DEBUGNET
3011eb07d67eSMark Johnston int
cxgb_debugnet_poll_rx(adapter_t * adap,struct sge_qset * qs)30127790c8c1SConrad Meyer cxgb_debugnet_poll_rx(adapter_t *adap, struct sge_qset *qs)
3013eb07d67eSMark Johnston {
3014eb07d67eSMark Johnston
3015eb07d67eSMark Johnston return (process_responses_gts(adap, &qs->rspq));
3016eb07d67eSMark Johnston }
3017eb07d67eSMark Johnston #endif
3018b6d90eb7SKip Macy
3019b6d90eb7SKip Macy /*
3020b6d90eb7SKip Macy * Interrupt handler for legacy INTx interrupts for T3B-based cards.
3021b6d90eb7SKip Macy * Handles data events from SGE response queues as well as error and other
3022b6d90eb7SKip Macy * async events as they all use the same interrupt pin. We use one SGE
3023b6d90eb7SKip Macy * response queue per port in this mode and protect all response queues with
3024b6d90eb7SKip Macy * queue 0's lock.
3025b6d90eb7SKip Macy */
3026b6d90eb7SKip Macy void
t3b_intr(void * data)3027b6d90eb7SKip Macy t3b_intr(void *data)
3028b6d90eb7SKip Macy {
30297ac2e6c3SKip Macy uint32_t i, map;
3030b6d90eb7SKip Macy adapter_t *adap = data;
3031b6d90eb7SKip Macy struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
3032b6d90eb7SKip Macy
3033b6d90eb7SKip Macy t3_write_reg(adap, A_PL_CLI, 0);
3034b6d90eb7SKip Macy map = t3_read_reg(adap, A_SG_DATA_INTR);
3035b6d90eb7SKip Macy
3036b6d90eb7SKip Macy if (!map)
3037b6d90eb7SKip Macy return;
3038b6d90eb7SKip Macy
30392c32b502SNavdeep Parhar if (__predict_false(map & F_ERRINTR)) {
30402c32b502SNavdeep Parhar t3_write_reg(adap, A_PL_INT_ENABLE0, 0);
30412c32b502SNavdeep Parhar (void) t3_read_reg(adap, A_PL_INT_ENABLE0);
3042b6d90eb7SKip Macy taskqueue_enqueue(adap->tq, &adap->slow_intr_task);
30432c32b502SNavdeep Parhar }
3044b6d90eb7SKip Macy
3045b6d90eb7SKip Macy mtx_lock(&q0->lock);
30467ac2e6c3SKip Macy for_each_port(adap, i)
30477ac2e6c3SKip Macy if (map & (1 << i))
30487ac2e6c3SKip Macy process_responses_gts(adap, &adap->sge.qs[i].rspq);
3049b6d90eb7SKip Macy mtx_unlock(&q0->lock);
3050b6d90eb7SKip Macy }
3051b6d90eb7SKip Macy
3052b6d90eb7SKip Macy /*
3053b6d90eb7SKip Macy * The MSI interrupt handler. This needs to handle data events from SGE
3054b6d90eb7SKip Macy * response queues as well as error and other async events as they all use
3055b6d90eb7SKip Macy * the same MSI vector. We use one SGE response queue per port in this mode
3056b6d90eb7SKip Macy * and protect all response queues with queue 0's lock.
3057b6d90eb7SKip Macy */
3058b6d90eb7SKip Macy void
t3_intr_msi(void * data)3059b6d90eb7SKip Macy t3_intr_msi(void *data)
3060b6d90eb7SKip Macy {
3061b6d90eb7SKip Macy adapter_t *adap = data;
3062b6d90eb7SKip Macy struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
30637ac2e6c3SKip Macy int i, new_packets = 0;
3064b6d90eb7SKip Macy
3065b6d90eb7SKip Macy mtx_lock(&q0->lock);
3066b6d90eb7SKip Macy
30677ac2e6c3SKip Macy for_each_port(adap, i)
30687ac2e6c3SKip Macy if (process_responses_gts(adap, &adap->sge.qs[i].rspq))
3069b6d90eb7SKip Macy new_packets = 1;
3070b6d90eb7SKip Macy mtx_unlock(&q0->lock);
30712c32b502SNavdeep Parhar if (new_packets == 0) {
30722c32b502SNavdeep Parhar t3_write_reg(adap, A_PL_INT_ENABLE0, 0);
30732c32b502SNavdeep Parhar (void) t3_read_reg(adap, A_PL_INT_ENABLE0);
3074b6d90eb7SKip Macy taskqueue_enqueue(adap->tq, &adap->slow_intr_task);
3075b6d90eb7SKip Macy }
30762c32b502SNavdeep Parhar }
3077b6d90eb7SKip Macy
3078b6d90eb7SKip Macy void
t3_intr_msix(void * data)3079b6d90eb7SKip Macy t3_intr_msix(void *data)
3080b6d90eb7SKip Macy {
3081b6d90eb7SKip Macy struct sge_qset *qs = data;
3082b6d90eb7SKip Macy adapter_t *adap = qs->port->adapter;
3083b6d90eb7SKip Macy struct sge_rspq *rspq = &qs->rspq;
3084b6d90eb7SKip Macy
3085d722cab4SKip Macy if (process_responses_gts(adap, rspq) == 0)
3086b6d90eb7SKip Macy rspq->unhandled_irqs++;
30878090c9f5SKip Macy }
3088b6d90eb7SKip Macy
3089f001b63dSKip Macy #define QDUMP_SBUF_SIZE 32 * 400
309010b16b26SKip Macy static int
t3_dump_rspq(SYSCTL_HANDLER_ARGS)309110b16b26SKip Macy t3_dump_rspq(SYSCTL_HANDLER_ARGS)
309210b16b26SKip Macy {
309310b16b26SKip Macy struct sge_rspq *rspq;
30949cce0038SKip Macy struct sge_qset *qs;
309510b16b26SKip Macy int i, err, dump_end, idx;
309610b16b26SKip Macy struct sbuf *sb;
309710b16b26SKip Macy struct rsp_desc *rspd;
30989cce0038SKip Macy uint32_t data[4];
309910b16b26SKip Macy
310010b16b26SKip Macy rspq = arg1;
31019cce0038SKip Macy qs = rspq_to_qset(rspq);
310210b16b26SKip Macy if (rspq->rspq_dump_count == 0)
310310b16b26SKip Macy return (0);
310410b16b26SKip Macy if (rspq->rspq_dump_count > RSPQ_Q_SIZE) {
310510b16b26SKip Macy log(LOG_WARNING,
310610b16b26SKip Macy "dump count is too large %d\n", rspq->rspq_dump_count);
310710b16b26SKip Macy rspq->rspq_dump_count = 0;
310810b16b26SKip Macy return (EINVAL);
310910b16b26SKip Macy }
311010b16b26SKip Macy if (rspq->rspq_dump_start > (RSPQ_Q_SIZE-1)) {
311110b16b26SKip Macy log(LOG_WARNING,
311210b16b26SKip Macy "dump start of %d is greater than queue size\n",
311310b16b26SKip Macy rspq->rspq_dump_start);
311410b16b26SKip Macy rspq->rspq_dump_start = 0;
311510b16b26SKip Macy return (EINVAL);
311610b16b26SKip Macy }
31179cce0038SKip Macy err = t3_sge_read_rspq(qs->port->adapter, rspq->cntxt_id, data);
31189cce0038SKip Macy if (err)
31199cce0038SKip Macy return (err);
312000f0e671SMatthew D Fleming err = sysctl_wire_old_buffer(req, 0);
312100f0e671SMatthew D Fleming if (err)
312200f0e671SMatthew D Fleming return (err);
31234e657159SMatthew D Fleming sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req);
312410b16b26SKip Macy
31259cce0038SKip Macy sbuf_printf(sb, " \n index=%u size=%u MSI-X/RspQ=%u intr enable=%u intr armed=%u\n",
31269cce0038SKip Macy (data[0] & 0xffff), data[0] >> 16, ((data[2] >> 20) & 0x3f),
31279cce0038SKip Macy ((data[2] >> 26) & 1), ((data[2] >> 27) & 1));
31289cce0038SKip Macy sbuf_printf(sb, " generation=%u CQ mode=%u FL threshold=%u\n",
31299cce0038SKip Macy ((data[2] >> 28) & 1), ((data[2] >> 31) & 1), data[3]);
31309cce0038SKip Macy
31319cce0038SKip Macy sbuf_printf(sb, " start=%d -> end=%d\n", rspq->rspq_dump_start,
313210b16b26SKip Macy (rspq->rspq_dump_start + rspq->rspq_dump_count) & (RSPQ_Q_SIZE-1));
313310b16b26SKip Macy
313410b16b26SKip Macy dump_end = rspq->rspq_dump_start + rspq->rspq_dump_count;
313510b16b26SKip Macy for (i = rspq->rspq_dump_start; i < dump_end; i++) {
313610b16b26SKip Macy idx = i & (RSPQ_Q_SIZE-1);
313710b16b26SKip Macy
313810b16b26SKip Macy rspd = &rspq->desc[idx];
313910b16b26SKip Macy sbuf_printf(sb, "\tidx=%04d opcode=%02x cpu_idx=%x hash_type=%x cq_idx=%x\n",
314010b16b26SKip Macy idx, rspd->rss_hdr.opcode, rspd->rss_hdr.cpu_idx,
314110b16b26SKip Macy rspd->rss_hdr.hash_type, be16toh(rspd->rss_hdr.cq_idx));
314210b16b26SKip Macy sbuf_printf(sb, "\trss_hash_val=%x flags=%08x len_cq=%x intr_gen=%x\n",
314310b16b26SKip Macy rspd->rss_hdr.rss_hash_val, be32toh(rspd->flags),
314410b16b26SKip Macy be32toh(rspd->len_cq), rspd->intr_gen);
314510b16b26SKip Macy }
31464e657159SMatthew D Fleming
31474e657159SMatthew D Fleming err = sbuf_finish(sb);
314810b16b26SKip Macy sbuf_delete(sb);
314910b16b26SKip Macy return (err);
315010b16b26SKip Macy }
315110b16b26SKip Macy
3152b6d90eb7SKip Macy static int
t3_dump_txq_eth(SYSCTL_HANDLER_ARGS)31538e10660fSKip Macy t3_dump_txq_eth(SYSCTL_HANDLER_ARGS)
3154f001b63dSKip Macy {
3155f001b63dSKip Macy struct sge_txq *txq;
3156f001b63dSKip Macy struct sge_qset *qs;
3157f001b63dSKip Macy int i, j, err, dump_end;
3158f001b63dSKip Macy struct sbuf *sb;
3159f001b63dSKip Macy struct tx_desc *txd;
3160f001b63dSKip Macy uint32_t *WR, wr_hi, wr_lo, gen;
31619cce0038SKip Macy uint32_t data[4];
3162f001b63dSKip Macy
3163f001b63dSKip Macy txq = arg1;
3164f001b63dSKip Macy qs = txq_to_qset(txq, TXQ_ETH);
3165f001b63dSKip Macy if (txq->txq_dump_count == 0) {
3166f001b63dSKip Macy return (0);
3167f001b63dSKip Macy }
3168f001b63dSKip Macy if (txq->txq_dump_count > TX_ETH_Q_SIZE) {
3169f001b63dSKip Macy log(LOG_WARNING,
3170f001b63dSKip Macy "dump count is too large %d\n", txq->txq_dump_count);
3171f001b63dSKip Macy txq->txq_dump_count = 1;
3172f001b63dSKip Macy return (EINVAL);
3173f001b63dSKip Macy }
3174f001b63dSKip Macy if (txq->txq_dump_start > (TX_ETH_Q_SIZE-1)) {
3175f001b63dSKip Macy log(LOG_WARNING,
3176f001b63dSKip Macy "dump start of %d is greater than queue size\n",
3177f001b63dSKip Macy txq->txq_dump_start);
3178f001b63dSKip Macy txq->txq_dump_start = 0;
3179f001b63dSKip Macy return (EINVAL);
3180f001b63dSKip Macy }
31818e10660fSKip Macy err = t3_sge_read_ecntxt(qs->port->adapter, qs->rspq.cntxt_id, data);
31829cce0038SKip Macy if (err)
31839cce0038SKip Macy return (err);
318400f0e671SMatthew D Fleming err = sysctl_wire_old_buffer(req, 0);
318500f0e671SMatthew D Fleming if (err)
318600f0e671SMatthew D Fleming return (err);
31874e657159SMatthew D Fleming sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req);
3188f001b63dSKip Macy
31899cce0038SKip Macy sbuf_printf(sb, " \n credits=%u GTS=%u index=%u size=%u rspq#=%u cmdq#=%u\n",
31909cce0038SKip Macy (data[0] & 0x7fff), ((data[0] >> 15) & 1), (data[0] >> 16),
31919cce0038SKip Macy (data[1] & 0xffff), ((data[3] >> 4) & 7), ((data[3] >> 7) & 1));
31929cce0038SKip Macy sbuf_printf(sb, " TUN=%u TOE=%u generation%u uP token=%u valid=%u\n",
31939cce0038SKip Macy ((data[3] >> 8) & 1), ((data[3] >> 9) & 1), ((data[3] >> 10) & 1),
31949cce0038SKip Macy ((data[3] >> 11) & 0xfffff), ((data[3] >> 31) & 1));
31959cce0038SKip Macy sbuf_printf(sb, " qid=%d start=%d -> end=%d\n", qs->idx,
3196f001b63dSKip Macy txq->txq_dump_start,
3197f001b63dSKip Macy (txq->txq_dump_start + txq->txq_dump_count) & (TX_ETH_Q_SIZE-1));
3198f001b63dSKip Macy
3199f001b63dSKip Macy dump_end = txq->txq_dump_start + txq->txq_dump_count;
3200f001b63dSKip Macy for (i = txq->txq_dump_start; i < dump_end; i++) {
3201f001b63dSKip Macy txd = &txq->desc[i & (TX_ETH_Q_SIZE-1)];
3202f001b63dSKip Macy WR = (uint32_t *)txd->flit;
3203f001b63dSKip Macy wr_hi = ntohl(WR[0]);
3204f001b63dSKip Macy wr_lo = ntohl(WR[1]);
3205f001b63dSKip Macy gen = G_WR_GEN(wr_lo);
3206f001b63dSKip Macy
3207f001b63dSKip Macy sbuf_printf(sb," wr_hi %08x wr_lo %08x gen %d\n",
3208f001b63dSKip Macy wr_hi, wr_lo, gen);
3209f001b63dSKip Macy for (j = 2; j < 30; j += 4)
3210f001b63dSKip Macy sbuf_printf(sb, "\t%08x %08x %08x %08x \n",
3211f001b63dSKip Macy WR[j], WR[j + 1], WR[j + 2], WR[j + 3]);
3212f001b63dSKip Macy
3213f001b63dSKip Macy }
32144e657159SMatthew D Fleming err = sbuf_finish(sb);
3215f001b63dSKip Macy sbuf_delete(sb);
3216f001b63dSKip Macy return (err);
3217f001b63dSKip Macy }
3218f001b63dSKip Macy
32198e10660fSKip Macy static int
t3_dump_txq_ctrl(SYSCTL_HANDLER_ARGS)32208e10660fSKip Macy t3_dump_txq_ctrl(SYSCTL_HANDLER_ARGS)
32218e10660fSKip Macy {
32228e10660fSKip Macy struct sge_txq *txq;
32238e10660fSKip Macy struct sge_qset *qs;
32248e10660fSKip Macy int i, j, err, dump_end;
32258e10660fSKip Macy struct sbuf *sb;
32268e10660fSKip Macy struct tx_desc *txd;
32278e10660fSKip Macy uint32_t *WR, wr_hi, wr_lo, gen;
32288e10660fSKip Macy
32298e10660fSKip Macy txq = arg1;
32308e10660fSKip Macy qs = txq_to_qset(txq, TXQ_CTRL);
32318e10660fSKip Macy if (txq->txq_dump_count == 0) {
32328e10660fSKip Macy return (0);
32338e10660fSKip Macy }
32348e10660fSKip Macy if (txq->txq_dump_count > 256) {
32358e10660fSKip Macy log(LOG_WARNING,
32368e10660fSKip Macy "dump count is too large %d\n", txq->txq_dump_count);
32378e10660fSKip Macy txq->txq_dump_count = 1;
32388e10660fSKip Macy return (EINVAL);
32398e10660fSKip Macy }
32408e10660fSKip Macy if (txq->txq_dump_start > 255) {
32418e10660fSKip Macy log(LOG_WARNING,
32428e10660fSKip Macy "dump start of %d is greater than queue size\n",
32438e10660fSKip Macy txq->txq_dump_start);
32448e10660fSKip Macy txq->txq_dump_start = 0;
32458e10660fSKip Macy return (EINVAL);
32468e10660fSKip Macy }
32478e10660fSKip Macy
324800f0e671SMatthew D Fleming err = sysctl_wire_old_buffer(req, 0);
324900f0e671SMatthew D Fleming if (err != 0)
325000f0e671SMatthew D Fleming return (err);
32514e657159SMatthew D Fleming sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req);
32528e10660fSKip Macy sbuf_printf(sb, " qid=%d start=%d -> end=%d\n", qs->idx,
32538e10660fSKip Macy txq->txq_dump_start,
32548e10660fSKip Macy (txq->txq_dump_start + txq->txq_dump_count) & 255);
32558e10660fSKip Macy
32568e10660fSKip Macy dump_end = txq->txq_dump_start + txq->txq_dump_count;
32578e10660fSKip Macy for (i = txq->txq_dump_start; i < dump_end; i++) {
32588e10660fSKip Macy txd = &txq->desc[i & (255)];
32598e10660fSKip Macy WR = (uint32_t *)txd->flit;
32608e10660fSKip Macy wr_hi = ntohl(WR[0]);
32618e10660fSKip Macy wr_lo = ntohl(WR[1]);
32628e10660fSKip Macy gen = G_WR_GEN(wr_lo);
32638e10660fSKip Macy
32648e10660fSKip Macy sbuf_printf(sb," wr_hi %08x wr_lo %08x gen %d\n",
32658e10660fSKip Macy wr_hi, wr_lo, gen);
32668e10660fSKip Macy for (j = 2; j < 30; j += 4)
32678e10660fSKip Macy sbuf_printf(sb, "\t%08x %08x %08x %08x \n",
32688e10660fSKip Macy WR[j], WR[j + 1], WR[j + 2], WR[j + 3]);
32698e10660fSKip Macy
32708e10660fSKip Macy }
32714e657159SMatthew D Fleming err = sbuf_finish(sb);
32728e10660fSKip Macy sbuf_delete(sb);
32738e10660fSKip Macy return (err);
32748e10660fSKip Macy }
3275f001b63dSKip Macy
3276f001b63dSKip Macy static int
t3_set_coalesce_usecs(SYSCTL_HANDLER_ARGS)32774af83c8cSKip Macy t3_set_coalesce_usecs(SYSCTL_HANDLER_ARGS)
3278b6d90eb7SKip Macy {
3279b6d90eb7SKip Macy adapter_t *sc = arg1;
3280b6d90eb7SKip Macy struct qset_params *qsp = &sc->params.sge.qset[0];
32814af83c8cSKip Macy int coalesce_usecs;
3282b6d90eb7SKip Macy struct sge_qset *qs;
3283b6d90eb7SKip Macy int i, j, err, nqsets = 0;
3284b6d90eb7SKip Macy struct mtx *lock;
3285b6d90eb7SKip Macy
32868090c9f5SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0)
32878090c9f5SKip Macy return (ENXIO);
32888090c9f5SKip Macy
32894af83c8cSKip Macy coalesce_usecs = qsp->coalesce_usecs;
32904af83c8cSKip Macy err = sysctl_handle_int(oidp, &coalesce_usecs, arg2, req);
3291b6d90eb7SKip Macy
3292b6d90eb7SKip Macy if (err != 0) {
3293b6d90eb7SKip Macy return (err);
3294b6d90eb7SKip Macy }
32954af83c8cSKip Macy if (coalesce_usecs == qsp->coalesce_usecs)
3296b6d90eb7SKip Macy return (0);
3297b6d90eb7SKip Macy
3298b6d90eb7SKip Macy for (i = 0; i < sc->params.nports; i++)
3299b6d90eb7SKip Macy for (j = 0; j < sc->port[i].nqsets; j++)
3300b6d90eb7SKip Macy nqsets++;
3301b6d90eb7SKip Macy
33024af83c8cSKip Macy coalesce_usecs = max(1, coalesce_usecs);
3303b6d90eb7SKip Macy
3304b6d90eb7SKip Macy for (i = 0; i < nqsets; i++) {
3305b6d90eb7SKip Macy qs = &sc->sge.qs[i];
3306b6d90eb7SKip Macy qsp = &sc->params.sge.qset[i];
33074af83c8cSKip Macy qsp->coalesce_usecs = coalesce_usecs;
3308b6d90eb7SKip Macy
3309b6d90eb7SKip Macy lock = (sc->flags & USING_MSIX) ? &qs->rspq.lock :
3310b6d90eb7SKip Macy &sc->sge.qs[0].rspq.lock;
3311b6d90eb7SKip Macy
3312b6d90eb7SKip Macy mtx_lock(lock);
3313b6d90eb7SKip Macy t3_update_qset_coalesce(qs, qsp);
3314b6d90eb7SKip Macy t3_write_reg(sc, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
3315b6d90eb7SKip Macy V_NEWTIMER(qs->rspq.holdoff_tmr));
3316b6d90eb7SKip Macy mtx_unlock(lock);
3317b6d90eb7SKip Macy }
3318b6d90eb7SKip Macy
3319b6d90eb7SKip Macy return (0);
3320b6d90eb7SKip Macy }
3321b6d90eb7SKip Macy
332227d1c65eSNavdeep Parhar static int
t3_pkt_timestamp(SYSCTL_HANDLER_ARGS)332327d1c65eSNavdeep Parhar t3_pkt_timestamp(SYSCTL_HANDLER_ARGS)
332427d1c65eSNavdeep Parhar {
332527d1c65eSNavdeep Parhar adapter_t *sc = arg1;
332627d1c65eSNavdeep Parhar int rc, timestamp;
332727d1c65eSNavdeep Parhar
332827d1c65eSNavdeep Parhar if ((sc->flags & FULL_INIT_DONE) == 0)
332927d1c65eSNavdeep Parhar return (ENXIO);
333027d1c65eSNavdeep Parhar
333127d1c65eSNavdeep Parhar timestamp = sc->timestamp;
333227d1c65eSNavdeep Parhar rc = sysctl_handle_int(oidp, ×tamp, arg2, req);
333327d1c65eSNavdeep Parhar
333427d1c65eSNavdeep Parhar if (rc != 0)
333527d1c65eSNavdeep Parhar return (rc);
333627d1c65eSNavdeep Parhar
333727d1c65eSNavdeep Parhar if (timestamp != sc->timestamp) {
333827d1c65eSNavdeep Parhar t3_set_reg_field(sc, A_TP_PC_CONFIG2, F_ENABLERXPKTTMSTPRSS,
333927d1c65eSNavdeep Parhar timestamp ? F_ENABLERXPKTTMSTPRSS : 0);
334027d1c65eSNavdeep Parhar sc->timestamp = timestamp;
334127d1c65eSNavdeep Parhar }
334227d1c65eSNavdeep Parhar
334327d1c65eSNavdeep Parhar return (0);
334427d1c65eSNavdeep Parhar }
3345b6d90eb7SKip Macy
3346b6d90eb7SKip Macy void
t3_add_attach_sysctls(adapter_t * sc)33478090c9f5SKip Macy t3_add_attach_sysctls(adapter_t *sc)
3348b6d90eb7SKip Macy {
3349b6d90eb7SKip Macy struct sysctl_ctx_list *ctx;
3350b6d90eb7SKip Macy struct sysctl_oid_list *children;
3351b6d90eb7SKip Macy
3352b6d90eb7SKip Macy ctx = device_get_sysctl_ctx(sc->dev);
3353b6d90eb7SKip Macy children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
3354b6d90eb7SKip Macy
3355b6d90eb7SKip Macy /* random information */
3356b6d90eb7SKip Macy SYSCTL_ADD_STRING(ctx, children, OID_AUTO,
3357b6d90eb7SKip Macy "firmware_version",
3358f0188618SHans Petter Selasky CTLFLAG_RD, sc->fw_version,
3359b6d90eb7SKip Macy 0, "firmware version");
3360deceab87SMatthew D Fleming SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
33618e10660fSKip Macy "hw_revision",
33628e10660fSKip Macy CTLFLAG_RD, &sc->params.rev,
33638e10660fSKip Macy 0, "chip model");
33640bbdea77SGeorge V. Neville-Neil SYSCTL_ADD_STRING(ctx, children, OID_AUTO,
33650bbdea77SGeorge V. Neville-Neil "port_types",
3366f0188618SHans Petter Selasky CTLFLAG_RD, sc->port_types,
33670bbdea77SGeorge V. Neville-Neil 0, "type of ports");
3368b6d90eb7SKip Macy SYSCTL_ADD_INT(ctx, children, OID_AUTO,
3369b6d90eb7SKip Macy "enable_debug",
3370b6d90eb7SKip Macy CTLFLAG_RW, &cxgb_debug,
3371b6d90eb7SKip Macy 0, "enable verbose debugging output");
3372deceab87SMatthew D Fleming SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, "tunq_coalesce",
33738090c9f5SKip Macy CTLFLAG_RD, &sc->tunq_coalesce,
33748090c9f5SKip Macy "#tunneled packets freed");
3375b8fe6051SKip Macy SYSCTL_ADD_INT(ctx, children, OID_AUTO,
3376b8fe6051SKip Macy "txq_overrun",
3377b8fe6051SKip Macy CTLFLAG_RD, &txq_fills,
3378b8fe6051SKip Macy 0, "#times txq overrun");
3379deceab87SMatthew D Fleming SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
338027d1c65eSNavdeep Parhar "core_clock",
338127d1c65eSNavdeep Parhar CTLFLAG_RD, &sc->params.vpd.cclk,
338227d1c65eSNavdeep Parhar 0, "core clock frequency (in KHz)");
33838090c9f5SKip Macy }
33848090c9f5SKip Macy
338510b16b26SKip Macy
338610b16b26SKip Macy static const char *rspq_name = "rspq";
338710b16b26SKip Macy static const char *txq_names[] =
338810b16b26SKip Macy {
338910b16b26SKip Macy "txq_eth",
339010b16b26SKip Macy "txq_ofld",
339110b16b26SKip Macy "txq_ctrl"
339210b16b26SKip Macy };
339310b16b26SKip Macy
3394706cb31fSKip Macy static int
sysctl_handle_macstat(SYSCTL_HANDLER_ARGS)3395706cb31fSKip Macy sysctl_handle_macstat(SYSCTL_HANDLER_ARGS)
3396706cb31fSKip Macy {
3397706cb31fSKip Macy struct port_info *p = arg1;
3398706cb31fSKip Macy uint64_t *parg;
3399706cb31fSKip Macy
3400706cb31fSKip Macy if (!p)
3401706cb31fSKip Macy return (EINVAL);
3402706cb31fSKip Macy
3403e26e6373SNavdeep Parhar cxgb_refresh_stats(p);
3404706cb31fSKip Macy parg = (uint64_t *) ((uint8_t *)&p->mac.stats + arg2);
3405706cb31fSKip Macy
3406cbc134adSMatthew D Fleming return (sysctl_handle_64(oidp, parg, 0, req));
3407706cb31fSKip Macy }
3408706cb31fSKip Macy
34098090c9f5SKip Macy void
t3_add_configured_sysctls(adapter_t * sc)34108090c9f5SKip Macy t3_add_configured_sysctls(adapter_t *sc)
34118090c9f5SKip Macy {
34128090c9f5SKip Macy struct sysctl_ctx_list *ctx;
34138090c9f5SKip Macy struct sysctl_oid_list *children;
34148090c9f5SKip Macy int i, j;
34158090c9f5SKip Macy
34168090c9f5SKip Macy ctx = device_get_sysctl_ctx(sc->dev);
34178090c9f5SKip Macy children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
34188090c9f5SKip Macy
34198090c9f5SKip Macy SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
34208090c9f5SKip Macy "intr_coal",
34217029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,
34224af83c8cSKip Macy 0, t3_set_coalesce_usecs,
34234af83c8cSKip Macy "I", "interrupt coalescing timer (us)");
34248090c9f5SKip Macy
342527d1c65eSNavdeep Parhar SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
342627d1c65eSNavdeep Parhar "pkt_timestamp",
34277029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,
342827d1c65eSNavdeep Parhar 0, t3_pkt_timestamp,
342927d1c65eSNavdeep Parhar "I", "provide packet timestamp instead of connection hash");
343027d1c65eSNavdeep Parhar
34318090c9f5SKip Macy for (i = 0; i < sc->params.nports; i++) {
34328090c9f5SKip Macy struct port_info *pi = &sc->port[i];
34338090c9f5SKip Macy struct sysctl_oid *poid;
34348090c9f5SKip Macy struct sysctl_oid_list *poidlist;
3435706cb31fSKip Macy struct mac_stats *mstats = &pi->mac.stats;
34368090c9f5SKip Macy
34378090c9f5SKip Macy snprintf(pi->namebuf, PORT_NAME_LEN, "port%d", i);
34388090c9f5SKip Macy poid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO,
34397029da5cSPawel Biernacki pi->namebuf, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
34407029da5cSPawel Biernacki "port statistics");
34418090c9f5SKip Macy poidlist = SYSCTL_CHILDREN(poid);
3442deceab87SMatthew D Fleming SYSCTL_ADD_UINT(ctx, poidlist, OID_AUTO,
34438090c9f5SKip Macy "nqsets", CTLFLAG_RD, &pi->nqsets,
34448090c9f5SKip Macy 0, "#queue sets");
34458090c9f5SKip Macy
34468090c9f5SKip Macy for (j = 0; j < pi->nqsets; j++) {
34478090c9f5SKip Macy struct sge_qset *qs = &sc->sge.qs[pi->first_qset + j];
3448f2d8ff04SGeorge V. Neville-Neil struct sysctl_oid *qspoid, *rspqpoid, *txqpoid,
3449f2d8ff04SGeorge V. Neville-Neil *ctrlqpoid, *lropoid;
3450f2d8ff04SGeorge V. Neville-Neil struct sysctl_oid_list *qspoidlist, *rspqpoidlist,
3451f2d8ff04SGeorge V. Neville-Neil *txqpoidlist, *ctrlqpoidlist,
3452f2d8ff04SGeorge V. Neville-Neil *lropoidlist;
34538090c9f5SKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
34548090c9f5SKip Macy
34558090c9f5SKip Macy snprintf(qs->namebuf, QS_NAME_LEN, "qs%d", j);
34568090c9f5SKip Macy
34578090c9f5SKip Macy qspoid = SYSCTL_ADD_NODE(ctx, poidlist, OID_AUTO,
34587029da5cSPawel Biernacki qs->namebuf, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
34597029da5cSPawel Biernacki "qset statistics");
34608090c9f5SKip Macy qspoidlist = SYSCTL_CHILDREN(qspoid);
34618090c9f5SKip Macy
3462f2d8ff04SGeorge V. Neville-Neil SYSCTL_ADD_UINT(ctx, qspoidlist, OID_AUTO, "fl0_empty",
3463f2d8ff04SGeorge V. Neville-Neil CTLFLAG_RD, &qs->fl[0].empty, 0,
3464f2d8ff04SGeorge V. Neville-Neil "freelist #0 empty");
3465f2d8ff04SGeorge V. Neville-Neil SYSCTL_ADD_UINT(ctx, qspoidlist, OID_AUTO, "fl1_empty",
3466f2d8ff04SGeorge V. Neville-Neil CTLFLAG_RD, &qs->fl[1].empty, 0,
3467f2d8ff04SGeorge V. Neville-Neil "freelist #1 empty");
3468f2d8ff04SGeorge V. Neville-Neil
346910b16b26SKip Macy rspqpoid = SYSCTL_ADD_NODE(ctx, qspoidlist, OID_AUTO,
34707029da5cSPawel Biernacki rspq_name, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
34717029da5cSPawel Biernacki "rspq statistics");
347210b16b26SKip Macy rspqpoidlist = SYSCTL_CHILDREN(rspqpoid);
347310b16b26SKip Macy
347410b16b26SKip Macy txqpoid = SYSCTL_ADD_NODE(ctx, qspoidlist, OID_AUTO,
34757029da5cSPawel Biernacki txq_names[0], CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
34767029da5cSPawel Biernacki "txq statistics");
347710b16b26SKip Macy txqpoidlist = SYSCTL_CHILDREN(txqpoid);
347810b16b26SKip Macy
34798e10660fSKip Macy ctrlqpoid = SYSCTL_ADD_NODE(ctx, qspoidlist, OID_AUTO,
34807029da5cSPawel Biernacki txq_names[2], CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
34817029da5cSPawel Biernacki "ctrlq statistics");
34828e10660fSKip Macy ctrlqpoidlist = SYSCTL_CHILDREN(ctrlqpoid);
348310b16b26SKip Macy
3484706cb31fSKip Macy lropoid = SYSCTL_ADD_NODE(ctx, qspoidlist, OID_AUTO,
34857029da5cSPawel Biernacki "lro_stats", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
34867029da5cSPawel Biernacki "LRO statistics");
3487706cb31fSKip Macy lropoidlist = SYSCTL_CHILDREN(lropoid);
3488706cb31fSKip Macy
348910b16b26SKip Macy SYSCTL_ADD_UINT(ctx, rspqpoidlist, OID_AUTO, "size",
349010b16b26SKip Macy CTLFLAG_RD, &qs->rspq.size,
349110b16b26SKip Macy 0, "#entries in response queue");
349210b16b26SKip Macy SYSCTL_ADD_UINT(ctx, rspqpoidlist, OID_AUTO, "cidx",
349310b16b26SKip Macy CTLFLAG_RD, &qs->rspq.cidx,
349410b16b26SKip Macy 0, "consumer index");
349510b16b26SKip Macy SYSCTL_ADD_UINT(ctx, rspqpoidlist, OID_AUTO, "credits",
349610b16b26SKip Macy CTLFLAG_RD, &qs->rspq.credits,
349710b16b26SKip Macy 0, "#credits");
3498489ca05bSNavdeep Parhar SYSCTL_ADD_UINT(ctx, rspqpoidlist, OID_AUTO, "starved",
3499489ca05bSNavdeep Parhar CTLFLAG_RD, &qs->rspq.starved,
3500489ca05bSNavdeep Parhar 0, "#times starved");
3501f0188618SHans Petter Selasky SYSCTL_ADD_UAUTO(ctx, rspqpoidlist, OID_AUTO, "phys_addr",
350210b16b26SKip Macy CTLFLAG_RD, &qs->rspq.phys_addr,
350310b16b26SKip Macy "physical_address_of the queue");
350410b16b26SKip Macy SYSCTL_ADD_UINT(ctx, rspqpoidlist, OID_AUTO, "dump_start",
350510b16b26SKip Macy CTLFLAG_RW, &qs->rspq.rspq_dump_start,
350610b16b26SKip Macy 0, "start rspq dump entry");
350710b16b26SKip Macy SYSCTL_ADD_UINT(ctx, rspqpoidlist, OID_AUTO, "dump_count",
350810b16b26SKip Macy CTLFLAG_RW, &qs->rspq.rspq_dump_count,
350910b16b26SKip Macy 0, "#rspq entries to dump");
351010b16b26SKip Macy SYSCTL_ADD_PROC(ctx, rspqpoidlist, OID_AUTO, "qdump",
35117029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
35127029da5cSPawel Biernacki &qs->rspq, 0, t3_dump_rspq, "A",
35137029da5cSPawel Biernacki "dump of the response queue");
351410b16b26SKip Macy
3515deceab87SMatthew D Fleming SYSCTL_ADD_UQUAD(ctx, txqpoidlist, OID_AUTO, "dropped",
351692f61ecbSNavdeep Parhar CTLFLAG_RD, &qs->txq[TXQ_ETH].txq_mr->br_drops,
351792f61ecbSNavdeep Parhar "#tunneled packets dropped");
3518deceab87SMatthew D Fleming SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "sendqlen",
3519c578b6acSGleb Smirnoff CTLFLAG_RD, &qs->txq[TXQ_ETH].sendq.mq_len,
35208090c9f5SKip Macy 0, "#tunneled packets waiting to be sent");
3521db7f0b97SKip Macy #if 0
352210b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "queue_pidx",
35238090c9f5SKip Macy CTLFLAG_RD, (uint32_t *)(uintptr_t)&qs->txq[TXQ_ETH].txq_mr.br_prod,
35248090c9f5SKip Macy 0, "#tunneled packets queue producer index");
352510b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "queue_cidx",
35268090c9f5SKip Macy CTLFLAG_RD, (uint32_t *)(uintptr_t)&qs->txq[TXQ_ETH].txq_mr.br_cons,
35278090c9f5SKip Macy 0, "#tunneled packets queue consumer index");
3528db7f0b97SKip Macy #endif
3529deceab87SMatthew D Fleming SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "processed",
35308090c9f5SKip Macy CTLFLAG_RD, &qs->txq[TXQ_ETH].processed,
35318090c9f5SKip Macy 0, "#tunneled packets processed by the card");
353210b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "cleaned",
35338090c9f5SKip Macy CTLFLAG_RD, &txq->cleaned,
35348090c9f5SKip Macy 0, "#tunneled packets cleaned");
353510b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "in_use",
35368090c9f5SKip Macy CTLFLAG_RD, &txq->in_use,
35378090c9f5SKip Macy 0, "#tunneled packet slots in use");
3538f0188618SHans Petter Selasky SYSCTL_ADD_UQUAD(ctx, txqpoidlist, OID_AUTO, "frees",
35398090c9f5SKip Macy CTLFLAG_RD, &txq->txq_frees,
35408090c9f5SKip Macy "#tunneled packets freed");
354110b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "skipped",
35428090c9f5SKip Macy CTLFLAG_RD, &txq->txq_skipped,
35438090c9f5SKip Macy 0, "#tunneled packet descriptors skipped");
3544deceab87SMatthew D Fleming SYSCTL_ADD_UQUAD(ctx, txqpoidlist, OID_AUTO, "coalesced",
35458090c9f5SKip Macy CTLFLAG_RD, &txq->txq_coalesced,
35463f345a5dSKip Macy "#tunneled packets coalesced");
354710b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "enqueued",
35488090c9f5SKip Macy CTLFLAG_RD, &txq->txq_enqueued,
35498090c9f5SKip Macy 0, "#tunneled packets enqueued to hardware");
355010b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "stopped_flags",
35518090c9f5SKip Macy CTLFLAG_RD, &qs->txq_stopped,
35528090c9f5SKip Macy 0, "tx queues stopped");
3553f0188618SHans Petter Selasky SYSCTL_ADD_UAUTO(ctx, txqpoidlist, OID_AUTO, "phys_addr",
3554f001b63dSKip Macy CTLFLAG_RD, &txq->phys_addr,
3555f001b63dSKip Macy "physical_address_of the queue");
355610b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "qgen",
3557f001b63dSKip Macy CTLFLAG_RW, &qs->txq[TXQ_ETH].gen,
3558f001b63dSKip Macy 0, "txq generation");
355910b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "hw_cidx",
3560f001b63dSKip Macy CTLFLAG_RD, &txq->cidx,
3561f001b63dSKip Macy 0, "hardware queue cidx");
356210b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "hw_pidx",
3563f001b63dSKip Macy CTLFLAG_RD, &txq->pidx,
3564f001b63dSKip Macy 0, "hardware queue pidx");
356510b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "dump_start",
3566f001b63dSKip Macy CTLFLAG_RW, &qs->txq[TXQ_ETH].txq_dump_start,
3567f001b63dSKip Macy 0, "txq start idx for dump");
356810b16b26SKip Macy SYSCTL_ADD_UINT(ctx, txqpoidlist, OID_AUTO, "dump_count",
3569f001b63dSKip Macy CTLFLAG_RW, &qs->txq[TXQ_ETH].txq_dump_count,
3570f001b63dSKip Macy 0, "txq #entries to dump");
357110b16b26SKip Macy SYSCTL_ADD_PROC(ctx, txqpoidlist, OID_AUTO, "qdump",
35727029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
35737029da5cSPawel Biernacki &qs->txq[TXQ_ETH], 0, t3_dump_txq_eth, "A",
35747029da5cSPawel Biernacki "dump of the transmit queue");
35758e10660fSKip Macy
35768e10660fSKip Macy SYSCTL_ADD_UINT(ctx, ctrlqpoidlist, OID_AUTO, "dump_start",
35778e10660fSKip Macy CTLFLAG_RW, &qs->txq[TXQ_CTRL].txq_dump_start,
35788e10660fSKip Macy 0, "ctrlq start idx for dump");
35798e10660fSKip Macy SYSCTL_ADD_UINT(ctx, ctrlqpoidlist, OID_AUTO, "dump_count",
35808e10660fSKip Macy CTLFLAG_RW, &qs->txq[TXQ_CTRL].txq_dump_count,
35818e10660fSKip Macy 0, "ctrl #entries to dump");
35828e10660fSKip Macy SYSCTL_ADD_PROC(ctx, ctrlqpoidlist, OID_AUTO, "qdump",
35837029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
35847029da5cSPawel Biernacki &qs->txq[TXQ_CTRL], 0, t3_dump_txq_ctrl, "A",
35857029da5cSPawel Biernacki "dump of the transmit queue");
35868e10660fSKip Macy
3587e936121dSHans Petter Selasky SYSCTL_ADD_U64(ctx, lropoidlist, OID_AUTO, "lro_queued",
3588706cb31fSKip Macy CTLFLAG_RD, &qs->lro.ctrl.lro_queued, 0, NULL);
3589e936121dSHans Petter Selasky SYSCTL_ADD_U64(ctx, lropoidlist, OID_AUTO, "lro_flushed",
3590706cb31fSKip Macy CTLFLAG_RD, &qs->lro.ctrl.lro_flushed, 0, NULL);
3591e936121dSHans Petter Selasky SYSCTL_ADD_U64(ctx, lropoidlist, OID_AUTO, "lro_bad_csum",
3592706cb31fSKip Macy CTLFLAG_RD, &qs->lro.ctrl.lro_bad_csum, 0, NULL);
3593706cb31fSKip Macy SYSCTL_ADD_INT(ctx, lropoidlist, OID_AUTO, "lro_cnt",
3594706cb31fSKip Macy CTLFLAG_RD, &qs->lro.ctrl.lro_cnt, 0, NULL);
35958090c9f5SKip Macy }
3596706cb31fSKip Macy
3597706cb31fSKip Macy /* Now add a node for mac stats. */
3598706cb31fSKip Macy poid = SYSCTL_ADD_NODE(ctx, poidlist, OID_AUTO, "mac_stats",
35997029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "MAC statistics");
3600706cb31fSKip Macy poidlist = SYSCTL_CHILDREN(poid);
3601706cb31fSKip Macy
3602706cb31fSKip Macy /*
3603706cb31fSKip Macy * We (ab)use the length argument (arg2) to pass on the offset
3604706cb31fSKip Macy * of the data that we are interested in. This is only required
3605706cb31fSKip Macy * for the quad counters that are updated from the hardware (we
3606706cb31fSKip Macy * make sure that we return the latest value).
3607706cb31fSKip Macy * sysctl_handle_macstat first updates *all* the counters from
3608706cb31fSKip Macy * the hardware, and then returns the latest value of the
3609706cb31fSKip Macy * requested counter. Best would be to update only the
3610706cb31fSKip Macy * requested counter from hardware, but t3_mac_update_stats()
3611706cb31fSKip Macy * hides all the register details and we don't want to dive into
3612706cb31fSKip Macy * all that here.
3613706cb31fSKip Macy */
3614706cb31fSKip Macy #define CXGB_SYSCTL_ADD_QUAD(a) SYSCTL_ADD_OID(ctx, poidlist, OID_AUTO, #a, \
36157029da5cSPawel Biernacki CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_NEEDGIANT, pi, \
36167029da5cSPawel Biernacki offsetof(struct mac_stats, a), sysctl_handle_macstat, "QU", 0)
3617706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_octets);
3618706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_octets_bad);
3619706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames);
3620706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_mcast_frames);
3621706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_bcast_frames);
3622706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_pause);
3623706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_deferred);
3624706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_late_collisions);
3625706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_total_collisions);
3626706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_excess_collisions);
3627706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_underrun);
3628706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_len_errs);
3629706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_mac_internal_errs);
3630706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_excess_deferral);
3631706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_fcs_errs);
3632706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_64);
3633706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_65_127);
3634706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_128_255);
3635706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_256_511);
3636706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_512_1023);
3637706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_1024_1518);
3638706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(tx_frames_1519_max);
3639706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_octets);
3640706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_octets_bad);
3641706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames);
3642706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_mcast_frames);
3643706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_bcast_frames);
3644706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_pause);
364574b0900fSGeorge V. Neville-Neil CXGB_SYSCTL_ADD_QUAD(rx_fcs_errs);
3646706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_align_errs);
3647706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_symbol_errs);
3648706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_data_errs);
3649706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_sequence_errs);
3650706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_runt);
3651706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_jabber);
3652706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_short);
3653706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_too_long);
3654706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_mac_internal_errs);
3655706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_cong_drops);
3656706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_64);
3657706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_65_127);
3658706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_128_255);
3659706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_256_511);
3660706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_512_1023);
3661706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_1024_1518);
3662706cb31fSKip Macy CXGB_SYSCTL_ADD_QUAD(rx_frames_1519_max);
3663706cb31fSKip Macy #undef CXGB_SYSCTL_ADD_QUAD
3664706cb31fSKip Macy
3665706cb31fSKip Macy #define CXGB_SYSCTL_ADD_ULONG(a) SYSCTL_ADD_ULONG(ctx, poidlist, OID_AUTO, #a, \
3666706cb31fSKip Macy CTLFLAG_RD, &mstats->a, 0)
3667706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(tx_fifo_parity_err);
3668706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(rx_fifo_parity_err);
3669706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(tx_fifo_urun);
3670706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(rx_fifo_ovfl);
3671706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(serdes_signal_loss);
3672706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(xaui_pcs_ctc_err);
3673706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(xaui_pcs_align_change);
3674706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(num_toggled);
3675706cb31fSKip Macy CXGB_SYSCTL_ADD_ULONG(num_resets);
36760bbdea77SGeorge V. Neville-Neil CXGB_SYSCTL_ADD_ULONG(link_faults);
3677706cb31fSKip Macy #undef CXGB_SYSCTL_ADD_ULONG
36788090c9f5SKip Macy }
3679b6d90eb7SKip Macy }
3680b6d90eb7SKip Macy
3681b6d90eb7SKip Macy /**
3682b6d90eb7SKip Macy * t3_get_desc - dump an SGE descriptor for debugging purposes
3683b6d90eb7SKip Macy * @qs: the queue set
3684b6d90eb7SKip Macy * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
3685b6d90eb7SKip Macy * @idx: the descriptor index in the queue
3686b6d90eb7SKip Macy * @data: where to dump the descriptor contents
3687b6d90eb7SKip Macy *
3688b6d90eb7SKip Macy * Dumps the contents of a HW descriptor of an SGE queue. Returns the
3689b6d90eb7SKip Macy * size of the descriptor.
3690b6d90eb7SKip Macy */
3691b6d90eb7SKip Macy int
t3_get_desc(const struct sge_qset * qs,unsigned int qnum,unsigned int idx,unsigned char * data)3692b6d90eb7SKip Macy t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
3693b6d90eb7SKip Macy unsigned char *data)
3694b6d90eb7SKip Macy {
3695b6d90eb7SKip Macy if (qnum >= 6)
3696b6d90eb7SKip Macy return (EINVAL);
3697b6d90eb7SKip Macy
3698b6d90eb7SKip Macy if (qnum < 3) {
3699b6d90eb7SKip Macy if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
3700b6d90eb7SKip Macy return -EINVAL;
3701b6d90eb7SKip Macy memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
3702b6d90eb7SKip Macy return sizeof(struct tx_desc);
3703b6d90eb7SKip Macy }
3704b6d90eb7SKip Macy
3705b6d90eb7SKip Macy if (qnum == 3) {
3706b6d90eb7SKip Macy if (!qs->rspq.desc || idx >= qs->rspq.size)
3707b6d90eb7SKip Macy return (EINVAL);
3708b6d90eb7SKip Macy memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
3709b6d90eb7SKip Macy return sizeof(struct rsp_desc);
3710b6d90eb7SKip Macy }
3711b6d90eb7SKip Macy
3712b6d90eb7SKip Macy qnum -= 4;
3713b6d90eb7SKip Macy if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
3714b6d90eb7SKip Macy return (EINVAL);
3715b6d90eb7SKip Macy memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
3716b6d90eb7SKip Macy return sizeof(struct rx_desc);
3717b6d90eb7SKip Macy }
3718