xref: /freebsd/sys/dev/cxgb/cxgb_sge.c (revision e86d9dd6cee18b035a34d54dbab93fc1ad6b527e)
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, &timestamp, 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