xref: /titanic_41/usr/src/uts/common/io/chxge/sge.c (revision d39a76e7b087a3d0927cbe6898dc0a6770fa6c68)
1*d39a76e7Sxw161283 /*
2*d39a76e7Sxw161283  * CDDL HEADER START
3*d39a76e7Sxw161283  *
4*d39a76e7Sxw161283  * The contents of this file are subject to the terms of the
5*d39a76e7Sxw161283  * Common Development and Distribution License (the "License").
6*d39a76e7Sxw161283  * You may not use this file except in compliance with the License.
7*d39a76e7Sxw161283  *
8*d39a76e7Sxw161283  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d39a76e7Sxw161283  * or http://www.opensolaris.org/os/licensing.
10*d39a76e7Sxw161283  * See the License for the specific language governing permissions
11*d39a76e7Sxw161283  * and limitations under the License.
12*d39a76e7Sxw161283  *
13*d39a76e7Sxw161283  * When distributing Covered Code, include this CDDL HEADER in each
14*d39a76e7Sxw161283  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d39a76e7Sxw161283  * If applicable, add the following below this CDDL HEADER, with the
16*d39a76e7Sxw161283  * fields enclosed by brackets "[]" replaced with your own identifying
17*d39a76e7Sxw161283  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d39a76e7Sxw161283  *
19*d39a76e7Sxw161283  * CDDL HEADER END
20*d39a76e7Sxw161283  */
21*d39a76e7Sxw161283 
22*d39a76e7Sxw161283 /*
23*d39a76e7Sxw161283  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*d39a76e7Sxw161283  * Use is subject to license terms.
25*d39a76e7Sxw161283  */
26*d39a76e7Sxw161283 
27*d39a76e7Sxw161283 /*
28*d39a76e7Sxw161283  * This file is part of the Chelsio T1 Ethernet driver.
29*d39a76e7Sxw161283  *
30*d39a76e7Sxw161283  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
31*d39a76e7Sxw161283  */
32*d39a76e7Sxw161283 
33*d39a76e7Sxw161283 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*d39a76e7Sxw161283 
35*d39a76e7Sxw161283 #include <sys/types.h>
36*d39a76e7Sxw161283 #include <sys/param.h>
37*d39a76e7Sxw161283 #include <sys/cmn_err.h>
38*d39a76e7Sxw161283 #include <sys/sunddi.h>
39*d39a76e7Sxw161283 #include <sys/kmem.h>
40*d39a76e7Sxw161283 #include <sys/cmn_err.h>
41*d39a76e7Sxw161283 #include <sys/byteorder.h>
42*d39a76e7Sxw161283 #include <sys/atomic.h>
43*d39a76e7Sxw161283 #include <sys/stropts.h>
44*d39a76e7Sxw161283 #include <sys/stream.h>
45*d39a76e7Sxw161283 #include <sys/strsubr.h>
46*d39a76e7Sxw161283 #include <sys/dlpi.h>
47*d39a76e7Sxw161283 #include <sys/kstat.h>
48*d39a76e7Sxw161283 #include <sys/ethernet.h>
49*d39a76e7Sxw161283 #include <netinet/in.h>
50*d39a76e7Sxw161283 #include <netinet/udp.h>
51*d39a76e7Sxw161283 #include <inet/common.h>
52*d39a76e7Sxw161283 #include <inet/nd.h>
53*d39a76e7Sxw161283 #include <inet/ip.h>
54*d39a76e7Sxw161283 #include <inet/tcp.h>
55*d39a76e7Sxw161283 #include <netinet/udp.h>
56*d39a76e7Sxw161283 #include <sys/gld.h>
57*d39a76e7Sxw161283 #include "ostypes.h"
58*d39a76e7Sxw161283 #include "common.h"
59*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
60*d39a76e7Sxw161283 #include "fpga_defs.h"
61*d39a76e7Sxw161283 #endif
62*d39a76e7Sxw161283 #include "regs.h"
63*d39a76e7Sxw161283 #include "suni1x10gexp_regs.h"
64*d39a76e7Sxw161283 #include "sge.h"
65*d39a76e7Sxw161283 #include "espi.h"
66*d39a76e7Sxw161283 
67*d39a76e7Sxw161283 #include "ch.h"
68*d39a76e7Sxw161283 
69*d39a76e7Sxw161283 extern uint32_t buffers_in_use[];
70*d39a76e7Sxw161283 
71*d39a76e7Sxw161283 uint32_t sge_cmdq0_cnt = SGE_CMDQ0_E_N;
72*d39a76e7Sxw161283 uint32_t sge_cmdq1_cnt = SGE_CMDQ1_E_N;
73*d39a76e7Sxw161283 uint32_t sge_flq0_cnt = SGE_FREELQ0_E_N;
74*d39a76e7Sxw161283 uint32_t sge_flq1_cnt = SGE_FREELQ1_E_N;
75*d39a76e7Sxw161283 uint32_t sge_respq_cnt = SGE_RESPQ_E_N;
76*d39a76e7Sxw161283 
77*d39a76e7Sxw161283 uint32_t sge_cmdq0_cnt_orig = SGE_CMDQ0_E_N;
78*d39a76e7Sxw161283 uint32_t sge_cmdq1_cnt_orig = SGE_CMDQ1_E_N;
79*d39a76e7Sxw161283 uint32_t sge_flq0_cnt_orig = SGE_FREELQ0_E_N;
80*d39a76e7Sxw161283 uint32_t sge_flq1_cnt_orig = SGE_FREELQ1_E_N;
81*d39a76e7Sxw161283 uint32_t sge_respq_cnt_orig = SGE_RESPQ_E_N;
82*d39a76e7Sxw161283 
83*d39a76e7Sxw161283 #ifdef HOST_PAUSE
84*d39a76e7Sxw161283 uint32_t do_host_pause = 1;
85*d39a76e7Sxw161283 uint32_t flq_pause_window = 64;
86*d39a76e7Sxw161283 #endif
87*d39a76e7Sxw161283 
88*d39a76e7Sxw161283 static uint64_t os_freelist_buffer_alloc(ch_t *sa, int sz, mblk_t **mb,
89*d39a76e7Sxw161283     ulong_t *dh);
90*d39a76e7Sxw161283 void pe_os_free_contig(ch_t *, size_t, void *, uint64_t, ulong_t, ulong_t);
91*d39a76e7Sxw161283 
92*d39a76e7Sxw161283 static inline uint32_t t1_sge_rx(pesge *sge, freelQ_t *Q,
93*d39a76e7Sxw161283     unsigned int len, unsigned int offload);
94*d39a76e7Sxw161283 #ifdef HOST_PAUSE
95*d39a76e7Sxw161283 static void t1_sge_check_pause(pesge *sge, struct freelQ *Q);
96*d39a76e7Sxw161283 #endif
97*d39a76e7Sxw161283 static void alloc_freelQ_buffers(pesge *sge, struct freelQ *Q);
98*d39a76e7Sxw161283 static void freelQs_empty(pesge *sge);
99*d39a76e7Sxw161283 static void free_cmdQ_buffers(pesge *sge, cmdQ_t *Q, uint32_t credits_pend);
100*d39a76e7Sxw161283 static int alloc_rx_resources(pesge *sge, struct sge_params *p);
101*d39a76e7Sxw161283 static int alloc_tx_resources(pesge *sge, struct sge_params *p);
102*d39a76e7Sxw161283 static inline void setup_ring_params(ch_t *adapter, u64 addr, u32 size,
103*d39a76e7Sxw161283     int base_reg_lo, int base_reg_hi, int size_reg);
104*d39a76e7Sxw161283 static void configure_sge(pesge *sge, struct sge_params *p);
105*d39a76e7Sxw161283 static void free_freelQ_buffers(pesge *sge, struct freelQ *Q);
106*d39a76e7Sxw161283 static void free_rx_resources(pesge *sge);
107*d39a76e7Sxw161283 static void free_tx_resources(pesge *sge);
108*d39a76e7Sxw161283 static inline unsigned int jumbo_payload_capacity(pesge *sge);
109*d39a76e7Sxw161283 #ifdef SUN_KSTATS
110*d39a76e7Sxw161283 static int sge_kstat_setup(pesge *);
111*d39a76e7Sxw161283 static void sge_kstat_remove(pesge *);
112*d39a76e7Sxw161283 static int sge_kstat_update(p_kstat_t, int);
113*d39a76e7Sxw161283 #endif
114*d39a76e7Sxw161283 static uint16_t calc_ocsum(mblk_t *, int);
115*d39a76e7Sxw161283 
116*d39a76e7Sxw161283 /*
117*d39a76e7Sxw161283  * Local routines.
118*d39a76e7Sxw161283  */
119*d39a76e7Sxw161283 static inline void sge_ring_doorbell(pesge *sge, u32 control_reg);
120*d39a76e7Sxw161283 
121*d39a76e7Sxw161283 static inline void
sge_ring_doorbell(pesge * sge,u32 control_reg)122*d39a76e7Sxw161283 sge_ring_doorbell(pesge *sge, u32 control_reg)
123*d39a76e7Sxw161283 {
124*d39a76e7Sxw161283 	membar_producer();
125*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_DOORBELL, control_reg);
126*d39a76e7Sxw161283 }
127*d39a76e7Sxw161283 
128*d39a76e7Sxw161283 /*
129*d39a76e7Sxw161283  * DESC:
130*d39a76e7Sxw161283  *
131*d39a76e7Sxw161283  * NOTES:   Must have at least 1 command queue and 1 freelist queue.
132*d39a76e7Sxw161283  *
133*d39a76e7Sxw161283  */
134*d39a76e7Sxw161283 pesge *
t1_sge_create(ch_t * sa,struct sge_params * p)135*d39a76e7Sxw161283 t1_sge_create(ch_t *sa, struct sge_params *p)
136*d39a76e7Sxw161283 {
137*d39a76e7Sxw161283 	pesge *sge;
138*d39a76e7Sxw161283 
139*d39a76e7Sxw161283 	sge = t1_os_malloc_wait_zero(sizeof (pesge));
140*d39a76e7Sxw161283 
141*d39a76e7Sxw161283 	if (sge == NULL)
142*d39a76e7Sxw161283 		goto error_no_mem;
143*d39a76e7Sxw161283 
144*d39a76e7Sxw161283 	memset(sge, 0, sizeof (*sge));
145*d39a76e7Sxw161283 
146*d39a76e7Sxw161283 	/*
147*d39a76e7Sxw161283 	 * PR2928 & PR3309
148*d39a76e7Sxw161283 	 * set default timeout value - 20 msec
149*d39a76e7Sxw161283 	 * we set the initial value to 2 which gurantees at least one tick.
150*d39a76e7Sxw161283 	 */
151*d39a76e7Sxw161283 	if (is_T2(sa))
152*d39a76e7Sxw161283 		sge->ptimeout = 1;
153*d39a76e7Sxw161283 
154*d39a76e7Sxw161283 	sge->obj = sa;
155*d39a76e7Sxw161283 #ifdef SUN_KSTATS
156*d39a76e7Sxw161283 	if (sge_kstat_setup(sge) != 0)
157*d39a76e7Sxw161283 		goto t1_sge_create_fail1;
158*d39a76e7Sxw161283 #endif
159*d39a76e7Sxw161283 	p->cmdQ_size[0] = sge_cmdq0_cnt;
160*d39a76e7Sxw161283 	p->cmdQ_size[1] = sge_cmdq1_cnt;
161*d39a76e7Sxw161283 
162*d39a76e7Sxw161283 	/* note that jumbo frame index is inverted for T2 */
163*d39a76e7Sxw161283 	if (is_T2(sa)) {
164*d39a76e7Sxw161283 		p->freelQ_size[1] = sge_flq0_cnt;
165*d39a76e7Sxw161283 		p->freelQ_size[0] = sge_flq1_cnt;
166*d39a76e7Sxw161283 	} else {
167*d39a76e7Sxw161283 		p->freelQ_size[0] = sge_flq0_cnt;
168*d39a76e7Sxw161283 		p->freelQ_size[1] = sge_flq1_cnt;
169*d39a76e7Sxw161283 	}
170*d39a76e7Sxw161283 
171*d39a76e7Sxw161283 #if CH_DEBUG
172*d39a76e7Sxw161283 	/* DEBUG only */
173*d39a76e7Sxw161283 	cmn_err(CE_NOTE, "sge: %p\n", sge);
174*d39a76e7Sxw161283 	cmn_err(CE_NOTE, "&sge->cmdQ[0]: %p\n", &sge->cmdQ[0]);
175*d39a76e7Sxw161283 	cmn_err(CE_NOTE, "&sge->freelQ[0]: %p\n", &sge->freelQ[0]);
176*d39a76e7Sxw161283 	cmn_err(CE_NOTE, "&sge->freelQ[1]: %p\n", &sge->freelQ[1]);
177*d39a76e7Sxw161283 	cmn_err(CE_NOTE, "&sge->respQ: %p\n", &sge->respQ);
178*d39a76e7Sxw161283 	cmn_err(CE_NOTE, "&sge->intr_cnt: %p\n", &sge->intr_cnt);
179*d39a76e7Sxw161283 #endif
180*d39a76e7Sxw161283 #ifdef SUN_KSTATS
181*d39a76e7Sxw161283 	goto error_no_mem;
182*d39a76e7Sxw161283 
183*d39a76e7Sxw161283 t1_sge_create_fail1:
184*d39a76e7Sxw161283 	t1_os_free(sge, sizeof (pesge));
185*d39a76e7Sxw161283 	sge = NULL;
186*d39a76e7Sxw161283 #endif
187*d39a76e7Sxw161283 error_no_mem:
188*d39a76e7Sxw161283 	return (sge);
189*d39a76e7Sxw161283 }
190*d39a76e7Sxw161283 
191*d39a76e7Sxw161283 int
t1_sge_destroy(pesge * sge)192*d39a76e7Sxw161283 t1_sge_destroy(pesge* sge)
193*d39a76e7Sxw161283 {
194*d39a76e7Sxw161283 	if (sge != NULL) {
195*d39a76e7Sxw161283 		free_tx_resources(sge);
196*d39a76e7Sxw161283 		free_rx_resources(sge);
197*d39a76e7Sxw161283 
198*d39a76e7Sxw161283 		/* PR2928 & PR3309 */
199*d39a76e7Sxw161283 		if ((is_T2(sge->obj)) && (sge->pskb))
200*d39a76e7Sxw161283 			pe_free_fake_arp(sge->pskb);
201*d39a76e7Sxw161283 #ifdef SUN_KSTATS
202*d39a76e7Sxw161283 		sge_kstat_remove(sge);
203*d39a76e7Sxw161283 #endif
204*d39a76e7Sxw161283 		t1_os_free(sge, sizeof (pesge));
205*d39a76e7Sxw161283 	}
206*d39a76e7Sxw161283 	return (0);
207*d39a76e7Sxw161283 }
208*d39a76e7Sxw161283 
209*d39a76e7Sxw161283 /*
210*d39a76e7Sxw161283  * PR2928 & PR3309
211*d39a76e7Sxw161283  * call out event from timeout
212*d39a76e7Sxw161283  *
213*d39a76e7Sxw161283  * there is a potential race between the timeout and the close.
214*d39a76e7Sxw161283  * unless we protect the timeout, the close could occur at the
215*d39a76e7Sxw161283  * same time. Then if the timeout service routine was slow or
216*d39a76e7Sxw161283  * interrupted, the sge_stop() could complete with a timeoutID
217*d39a76e7Sxw161283  * that has expired, thus letting another timeout occur. If the
218*d39a76e7Sxw161283  * service routine was delayed still further, a detach could occur.
219*d39a76e7Sxw161283  * the second time could then end up accessing memory that has been
220*d39a76e7Sxw161283  * released back to the system. Bad things could then occur. We
221*d39a76e7Sxw161283  * set a flag in sge_stop() to tell the service routine not to
222*d39a76e7Sxw161283  * issue further timeouts. sge_stop() will block until a timeout
223*d39a76e7Sxw161283  * has occured. If the command Q is full then we shouldn't put out
224*d39a76e7Sxw161283  * an arp.
225*d39a76e7Sxw161283  */
226*d39a76e7Sxw161283 
227*d39a76e7Sxw161283 void
t1_espi_workaround(ch_t * adapter)228*d39a76e7Sxw161283 t1_espi_workaround(ch_t *adapter)
229*d39a76e7Sxw161283 {
230*d39a76e7Sxw161283 	pesge *sge = adapter->sge;
231*d39a76e7Sxw161283 	ch_t *chp = (ch_t *)sge->obj;
232*d39a76e7Sxw161283 	int rv = 1;
233*d39a76e7Sxw161283 
234*d39a76e7Sxw161283 	if ((chp->ch_state == PERUNNING) &&
235*d39a76e7Sxw161283 	    atomic_read(&sge->cmdQ[0].cq_asleep)) {
236*d39a76e7Sxw161283 		u32 seop;
237*d39a76e7Sxw161283 		seop = t1_espi_get_mon(adapter, 0x930, 0);
238*d39a76e7Sxw161283 		if ((seop & 0xfff0fff) == 0xfff) {
239*d39a76e7Sxw161283 			/* after first arp */
240*d39a76e7Sxw161283 			if (sge->pskb)
241*d39a76e7Sxw161283 				rv = pe_start(adapter, (mblk_t *)sge->pskb,
242*d39a76e7Sxw161283 				    CH_ARP);
243*d39a76e7Sxw161283 				if (!rv)
244*d39a76e7Sxw161283 					sge->intr_cnt.arp_sent++;
245*d39a76e7Sxw161283 		}
246*d39a76e7Sxw161283 	}
247*d39a76e7Sxw161283 #ifdef HOST_PAUSE
248*d39a76e7Sxw161283 	/*
249*d39a76e7Sxw161283 	 * If we are already in sge_data_in, then we can skip calling
250*d39a76e7Sxw161283 	 * t1_sge_check_pause() this clock cycle. lockstat showed that
251*d39a76e7Sxw161283 	 * we were blocking on the mutex ~ 2% of the time.
252*d39a76e7Sxw161283 	 */
253*d39a76e7Sxw161283 	if (mutex_tryenter(&adapter->ch_intr)) {
254*d39a76e7Sxw161283 		t1_sge_check_pause(sge, &sge->freelQ[0]);
255*d39a76e7Sxw161283 		t1_sge_check_pause(sge, &sge->freelQ[1]);
256*d39a76e7Sxw161283 		mutex_exit(&adapter->ch_intr);
257*d39a76e7Sxw161283 	}
258*d39a76e7Sxw161283 #endif
259*d39a76e7Sxw161283 }
260*d39a76e7Sxw161283 
261*d39a76e7Sxw161283 int
sge_start(pesge * sge)262*d39a76e7Sxw161283 sge_start(pesge *sge)
263*d39a76e7Sxw161283 {
264*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_CONTROL, sge->sge_control);
265*d39a76e7Sxw161283 	/* PR2928 & PR3309, also need to avoid Pause deadlock */
266*d39a76e7Sxw161283 	ch_init_cyclic(sge->obj, &sge->espi_wa_cyclic,
267*d39a76e7Sxw161283 	    (void (*)(void *))t1_espi_workaround, sge->obj);
268*d39a76e7Sxw161283 	ch_start_cyclic(&sge->espi_wa_cyclic, sge->ptimeout);
269*d39a76e7Sxw161283 	return (0);
270*d39a76e7Sxw161283 }
271*d39a76e7Sxw161283 
272*d39a76e7Sxw161283 /*
273*d39a76e7Sxw161283  * Disables SGE queues.
274*d39a76e7Sxw161283  */
275*d39a76e7Sxw161283 int
sge_stop(pesge * sge)276*d39a76e7Sxw161283 sge_stop(pesge *sge)
277*d39a76e7Sxw161283 {
278*d39a76e7Sxw161283 	uint32_t status;
279*d39a76e7Sxw161283 	int loops;
280*d39a76e7Sxw161283 
281*d39a76e7Sxw161283 	DBGASSERT(sge);
282*d39a76e7Sxw161283 
283*d39a76e7Sxw161283 	/* PR2928 & PR3309, also need to avoid Pause deadlock */
284*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_CONTROL, 0x0);
285*d39a76e7Sxw161283 
286*d39a76e7Sxw161283 	/* wait until there's no more outstanding interrupts pending */
287*d39a76e7Sxw161283 	loops = 0;
288*d39a76e7Sxw161283 	do {
289*d39a76e7Sxw161283 		status = t1_read_reg_4(sge->obj, A_SG_INT_CAUSE);
290*d39a76e7Sxw161283 		t1_write_reg_4(sge->obj, A_SG_INT_CAUSE, status);
291*d39a76e7Sxw161283 		drv_usecwait(125);
292*d39a76e7Sxw161283 		loops++;
293*d39a76e7Sxw161283 	} while (status && (loops < 1000));
294*d39a76e7Sxw161283 
295*d39a76e7Sxw161283 	ch_stop_cyclic(&sge->espi_wa_cyclic);
296*d39a76e7Sxw161283 
297*d39a76e7Sxw161283 	return (0);
298*d39a76e7Sxw161283 }
299*d39a76e7Sxw161283 
300*d39a76e7Sxw161283 uint32_t sge_cmdq_send_fail;
301*d39a76e7Sxw161283 
302*d39a76e7Sxw161283 int
sge_data_out(pesge * sge,int qid,mblk_t * m0,cmdQ_ce_t * cmp,int count,uint32_t flg)303*d39a76e7Sxw161283 sge_data_out(pesge* sge, int qid, mblk_t *m0,
304*d39a76e7Sxw161283 			cmdQ_ce_t *cmp, int count, uint32_t flg)
305*d39a76e7Sxw161283 {
306*d39a76e7Sxw161283 	struct cmdQ *Q = &sge->cmdQ[qid];
307*d39a76e7Sxw161283 	ddi_dma_handle_t dh = (ddi_dma_handle_t)sge->cmdQ[qid].cq_dh;
308*d39a76e7Sxw161283 	spinlock_t *qlock = &Q->cq_qlock;
309*d39a76e7Sxw161283 	cmdQ_e *e;
310*d39a76e7Sxw161283 	cmdQ_e *q = Q->cq_entries;
311*d39a76e7Sxw161283 	uint32_t credits;
312*d39a76e7Sxw161283 	uint32_t pidx;
313*d39a76e7Sxw161283 	uint32_t genbit;
314*d39a76e7Sxw161283 	uint32_t entries_n = Q->cq_entries_n;
315*d39a76e7Sxw161283 	cmdQ_ce_t *ce;
316*d39a76e7Sxw161283 	cmdQ_ce_t *cq = Q->cq_centries;
317*d39a76e7Sxw161283 	dma_addr_t mapping;
318*d39a76e7Sxw161283 	uint32_t j = 0;
319*d39a76e7Sxw161283 	uint32_t offset;
320*d39a76e7Sxw161283 #if defined(TX_CKSUM_FIX)
321*d39a76e7Sxw161283 	uint16_t csum;
322*d39a76e7Sxw161283 	uint16_t *csum_loc;
323*d39a76e7Sxw161283 #endif
324*d39a76e7Sxw161283 #ifdef TX_THREAD_RECLAIM
325*d39a76e7Sxw161283 	uint32_t reclaim_cnt;
326*d39a76e7Sxw161283 #endif
327*d39a76e7Sxw161283 
328*d39a76e7Sxw161283 	/*
329*d39a76e7Sxw161283 	 * We must exit if we don't have enough free command queue entries
330*d39a76e7Sxw161283 	 * available.
331*d39a76e7Sxw161283 	 */
332*d39a76e7Sxw161283 
333*d39a76e7Sxw161283 	spin_lock(qlock);
334*d39a76e7Sxw161283 
335*d39a76e7Sxw161283 #if defined(TX_CKSUM_FIX)
336*d39a76e7Sxw161283 	/*
337*d39a76e7Sxw161283 	 * This checksum fix will address a fragmented datagram
338*d39a76e7Sxw161283 	 * checksum error. Which will lead to the next packet after
339*d39a76e7Sxw161283 	 * the last packet with the More fragment bit set having its
340*d39a76e7Sxw161283 	 * checksum corrupted. When the packet reaches this point
341*d39a76e7Sxw161283 	 * the 'flg' variable indicates whether a checksum is needed
342*d39a76e7Sxw161283 	 * or not. The algorithm is as follows, if the current packet
343*d39a76e7Sxw161283 	 * is a More fragment set the count of packets to be checksummed
344*d39a76e7Sxw161283 	 * after it to 3. If it't not and the count of is more than 0
345*d39a76e7Sxw161283 	 * then calculate the checksum in software, if a hardware checksum
346*d39a76e7Sxw161283 	 * was requested. Then decrment the count. Same algorithm applies
347*d39a76e7Sxw161283 	 * to TCP.
348*d39a76e7Sxw161283 	 */
349*d39a76e7Sxw161283 	if (flg & CH_UDP_MF) {
350*d39a76e7Sxw161283 		sge->do_udp_csum = 3;
351*d39a76e7Sxw161283 	} else if ((flg & CH_UDP) && (sge->do_udp_csum != 0)) {
352*d39a76e7Sxw161283 		if ((flg & CH_NO_HWCKSUM) == 0) {
353*d39a76e7Sxw161283 			/*
354*d39a76e7Sxw161283 			 *  Calc Checksum here.
355*d39a76e7Sxw161283 			 */
356*d39a76e7Sxw161283 			csum = calc_ocsum(m0,
357*d39a76e7Sxw161283 			    sizeof (struct ether_header) + CPL_FORMAT_0_SIZE);
358*d39a76e7Sxw161283 			csum_loc = (uint16_t *)(m0->b_rptr +
359*d39a76e7Sxw161283 			    sizeof (struct ether_header) + CPL_FORMAT_0_SIZE);
360*d39a76e7Sxw161283 			csum_loc += (((*(char *)csum_loc) & 0x0f) << 1);
361*d39a76e7Sxw161283 
362*d39a76e7Sxw161283 			sge->intr_cnt.tx_soft_cksums++;
363*d39a76e7Sxw161283 			((struct udphdr *)(csum_loc))->uh_sum = csum;
364*d39a76e7Sxw161283 			((struct cpl_tx_pkt *)m0->b_rptr)->l4_csum_dis = 1;
365*d39a76e7Sxw161283 		}
366*d39a76e7Sxw161283 		sge->do_udp_csum--;
367*d39a76e7Sxw161283 	} else if (flg & CH_TCP_MF) {
368*d39a76e7Sxw161283 		sge->do_tcp_csum = 3;
369*d39a76e7Sxw161283 	} else if (sge->do_tcp_csum != 0) {
370*d39a76e7Sxw161283 		if ((flg & CH_NO_HWCKSUM) == 0) {
371*d39a76e7Sxw161283 			sge->intr_cnt.tx_soft_cksums++;
372*d39a76e7Sxw161283 			/*
373*d39a76e7Sxw161283 			 *  Calc Checksum here.
374*d39a76e7Sxw161283 			 */
375*d39a76e7Sxw161283 		}
376*d39a76e7Sxw161283 		sge->do_tcp_csum--;
377*d39a76e7Sxw161283 	}
378*d39a76e7Sxw161283 #endif	/* TX_CKSUM_FIX */
379*d39a76e7Sxw161283 #ifdef TX_THREAD_RECLAIM
380*d39a76e7Sxw161283 	reclaim_cnt = Q->cq_complete;
381*d39a76e7Sxw161283 	if (reclaim_cnt > SGE_BATCH_THRESH) {
382*d39a76e7Sxw161283 		sge->intr_cnt.tx_reclaims[qid]++;
383*d39a76e7Sxw161283 		free_cmdQ_buffers(sge, Q, reclaim_cnt);
384*d39a76e7Sxw161283 		Q->cq_complete = 0;
385*d39a76e7Sxw161283 	}
386*d39a76e7Sxw161283 #endif
387*d39a76e7Sxw161283 	genbit = Q->cq_genbit;
388*d39a76e7Sxw161283 	pidx = Q->cq_pidx;
389*d39a76e7Sxw161283 	credits = Q->cq_credits;
390*d39a76e7Sxw161283 
391*d39a76e7Sxw161283 	if ((credits - 1) < count) {
392*d39a76e7Sxw161283 		spin_unlock(qlock);
393*d39a76e7Sxw161283 		sge->intr_cnt.cmdQ_full[qid]++;
394*d39a76e7Sxw161283 		return (1);
395*d39a76e7Sxw161283 	}
396*d39a76e7Sxw161283 
397*d39a76e7Sxw161283 	atomic_sub(count, &Q->cq_credits);
398*d39a76e7Sxw161283 	Q->cq_pidx += count;
399*d39a76e7Sxw161283 	if (Q->cq_pidx >= entries_n) {
400*d39a76e7Sxw161283 		Q->cq_pidx -= entries_n;
401*d39a76e7Sxw161283 		Q->cq_genbit ^= 1;
402*d39a76e7Sxw161283 	}
403*d39a76e7Sxw161283 
404*d39a76e7Sxw161283 	spin_unlock(qlock);
405*d39a76e7Sxw161283 
406*d39a76e7Sxw161283 #ifdef SUN_KSTATS
407*d39a76e7Sxw161283 	if (count > MBLK_MAX)
408*d39a76e7Sxw161283 		sge->intr_cnt.tx_descs[MBLK_MAX - 1]++;
409*d39a76e7Sxw161283 	else
410*d39a76e7Sxw161283 		sge->intr_cnt.tx_descs[count]++;
411*d39a76e7Sxw161283 #endif
412*d39a76e7Sxw161283 
413*d39a76e7Sxw161283 	ce = &cq[pidx];
414*d39a76e7Sxw161283 	*ce = *cmp;
415*d39a76e7Sxw161283 	mapping = cmp->ce_pa;
416*d39a76e7Sxw161283 	j++;
417*d39a76e7Sxw161283 
418*d39a76e7Sxw161283 	e = &q[pidx];
419*d39a76e7Sxw161283 
420*d39a76e7Sxw161283 	offset = (caddr_t)e - (caddr_t)q;
421*d39a76e7Sxw161283 
422*d39a76e7Sxw161283 	e->Sop =  1;
423*d39a76e7Sxw161283 	e->DataValid = 1;
424*d39a76e7Sxw161283 	e->BufferLength = cmp->ce_len;
425*d39a76e7Sxw161283 	e->AddrHigh = ((u64)mapping >> 32);
426*d39a76e7Sxw161283 	e->AddrLow = ((u64)mapping & 0xffffffff);
427*d39a76e7Sxw161283 
428*d39a76e7Sxw161283 	--count;
429*d39a76e7Sxw161283 	if (count > 0) {
430*d39a76e7Sxw161283 		unsigned int i;
431*d39a76e7Sxw161283 
432*d39a76e7Sxw161283 		e->Eop = 0;
433*d39a76e7Sxw161283 		wmb();
434*d39a76e7Sxw161283 		e->GenerationBit = e->GenerationBit2 = genbit;
435*d39a76e7Sxw161283 
436*d39a76e7Sxw161283 		for (i = 0; i < count; i++) {
437*d39a76e7Sxw161283 
438*d39a76e7Sxw161283 			ce++;
439*d39a76e7Sxw161283 			e++;
440*d39a76e7Sxw161283 			cmp++;
441*d39a76e7Sxw161283 			if (++pidx == entries_n) {
442*d39a76e7Sxw161283 				pidx = 0;
443*d39a76e7Sxw161283 				genbit ^= 1;
444*d39a76e7Sxw161283 				/* sync from offset to end of cmdQ */
445*d39a76e7Sxw161283 				(void) ddi_dma_sync(dh, (off_t)(offset),
446*d39a76e7Sxw161283 				    j*sizeof (*e), DDI_DMA_SYNC_FORDEV);
447*d39a76e7Sxw161283 				offset = j = 0;
448*d39a76e7Sxw161283 				ce = cq;
449*d39a76e7Sxw161283 				e = q;
450*d39a76e7Sxw161283 			}
451*d39a76e7Sxw161283 
452*d39a76e7Sxw161283 			*ce = *cmp;
453*d39a76e7Sxw161283 			mapping = cmp->ce_pa;
454*d39a76e7Sxw161283 			j++;
455*d39a76e7Sxw161283 			e->Sop = 0;
456*d39a76e7Sxw161283 			e->DataValid = 1;
457*d39a76e7Sxw161283 			e->BufferLength = cmp->ce_len;
458*d39a76e7Sxw161283 			e->AddrHigh = ((u64)mapping >> 32);
459*d39a76e7Sxw161283 			e->AddrLow = ((u64)mapping & 0xffffffff);
460*d39a76e7Sxw161283 
461*d39a76e7Sxw161283 			if (i < (count - 1)) {
462*d39a76e7Sxw161283 				e->Eop = 0;
463*d39a76e7Sxw161283 				wmb();
464*d39a76e7Sxw161283 				e->GenerationBit = e->GenerationBit2 = genbit;
465*d39a76e7Sxw161283 			}
466*d39a76e7Sxw161283 		}
467*d39a76e7Sxw161283 	}
468*d39a76e7Sxw161283 
469*d39a76e7Sxw161283 	ce->ce_mp = m0;
470*d39a76e7Sxw161283 
471*d39a76e7Sxw161283 	e->Eop = 1;
472*d39a76e7Sxw161283 	wmb();
473*d39a76e7Sxw161283 	e->GenerationBit = e->GenerationBit2 = genbit;
474*d39a76e7Sxw161283 
475*d39a76e7Sxw161283 	(void) ddi_dma_sync(dh, (off_t)(offset), j*sizeof (*e),
476*d39a76e7Sxw161283 	    DDI_DMA_SYNC_FORDEV);
477*d39a76e7Sxw161283 
478*d39a76e7Sxw161283 	/*
479*d39a76e7Sxw161283 	 * We always ring the doorbell for cmdQ1.  For cmdQ0, we only ring
480*d39a76e7Sxw161283 	 * the doorbell if the Q is asleep. There is a natural race, where
481*d39a76e7Sxw161283 	 * the hardware is going to sleep just after we checked, however,
482*d39a76e7Sxw161283 	 * then the interrupt handler will detect the outstanding TX packet
483*d39a76e7Sxw161283 	 * and ring the doorbell for us.
484*d39a76e7Sxw161283 	 */
485*d39a76e7Sxw161283 	if (qid) {
486*d39a76e7Sxw161283 		doorbell_pio(sge, F_CMDQ1_ENABLE);
487*d39a76e7Sxw161283 	} else {
488*d39a76e7Sxw161283 		if (atomic_read(Q->cq_asleep)) {
489*d39a76e7Sxw161283 			atomic_set(&Q->cq_asleep, 0);
490*d39a76e7Sxw161283 /* NOT YET		doorbell_pio(sge, F_CMDQ0_ENABLE); */
491*d39a76e7Sxw161283 			atomic_set(&Q->cq_pio_pidx, Q->cq_pidx);
492*d39a76e7Sxw161283 		}
493*d39a76e7Sxw161283 	}
494*d39a76e7Sxw161283 	doorbell_pio(sge, F_CMDQ0_ENABLE);
495*d39a76e7Sxw161283 
496*d39a76e7Sxw161283 	return (0);
497*d39a76e7Sxw161283 }
498*d39a76e7Sxw161283 
499*d39a76e7Sxw161283 #define	SGE_PL_INTR_MASK (F_PL_INTR_SGE_ERR | F_PL_INTR_SGE_DATA)
500*d39a76e7Sxw161283 
501*d39a76e7Sxw161283 /*
502*d39a76e7Sxw161283  * Disable SGE error interrupts.
503*d39a76e7Sxw161283  */
504*d39a76e7Sxw161283 int
t1_sge_intr_disable(pesge * sge)505*d39a76e7Sxw161283 t1_sge_intr_disable(pesge* sge)
506*d39a76e7Sxw161283 {
507*d39a76e7Sxw161283 	u32 val = t1_read_reg_4(sge->obj, A_PL_ENABLE);
508*d39a76e7Sxw161283 
509*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_PL_ENABLE, val & ~SGE_PL_INTR_MASK);
510*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_INT_ENABLE, 0);
511*d39a76e7Sxw161283 	return (0);
512*d39a76e7Sxw161283 }
513*d39a76e7Sxw161283 
514*d39a76e7Sxw161283 #define	SGE_INT_ENABLE (F_RESPQ_EXHAUSTED | F_RESPQ_OVERFLOW | \
515*d39a76e7Sxw161283 	F_FL_EXHAUSTED | F_PACKET_TOO_BIG | F_PACKET_MISMATCH)
516*d39a76e7Sxw161283 
517*d39a76e7Sxw161283 /*
518*d39a76e7Sxw161283  * Enable SGE error interrupts.
519*d39a76e7Sxw161283  */
520*d39a76e7Sxw161283 int
t1_sge_intr_enable(pesge * sge)521*d39a76e7Sxw161283 t1_sge_intr_enable(pesge* sge)
522*d39a76e7Sxw161283 {
523*d39a76e7Sxw161283 	u32 en = SGE_INT_ENABLE;
524*d39a76e7Sxw161283 	u32 val = t1_read_reg_4(sge->obj, A_PL_ENABLE);
525*d39a76e7Sxw161283 
526*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_PL_ENABLE, val | SGE_PL_INTR_MASK);
527*d39a76e7Sxw161283 
528*d39a76e7Sxw161283 	if (sge->obj->ch_flags & TSO_CAPABLE)
529*d39a76e7Sxw161283 		en &= ~F_PACKET_TOO_BIG;
530*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_INT_ENABLE, en);
531*d39a76e7Sxw161283 	return (0);
532*d39a76e7Sxw161283 }
533*d39a76e7Sxw161283 
534*d39a76e7Sxw161283 /*
535*d39a76e7Sxw161283  * Clear SGE error interrupts.
536*d39a76e7Sxw161283  */
537*d39a76e7Sxw161283 int
t1_sge_intr_clear(pesge * sge)538*d39a76e7Sxw161283 t1_sge_intr_clear(pesge* sge)
539*d39a76e7Sxw161283 {
540*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_PL_CAUSE, SGE_PL_INTR_MASK);
541*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_INT_CAUSE, 0xffffffff);
542*d39a76e7Sxw161283 	return (0);
543*d39a76e7Sxw161283 }
544*d39a76e7Sxw161283 
545*d39a76e7Sxw161283 #define	SGE_INT_FATAL (F_RESPQ_OVERFLOW | F_PACKET_TOO_BIG | F_PACKET_MISMATCH)
546*d39a76e7Sxw161283 
547*d39a76e7Sxw161283 int
t1_sge_intr_error_handler(pesge * sge)548*d39a76e7Sxw161283 t1_sge_intr_error_handler(pesge *sge)
549*d39a76e7Sxw161283 {
550*d39a76e7Sxw161283 	peobj *obj = sge->obj;
551*d39a76e7Sxw161283 	u32 cause = t1_read_reg_4(obj, A_SG_INT_CAUSE);
552*d39a76e7Sxw161283 
553*d39a76e7Sxw161283 	if (cause & F_RESPQ_EXHAUSTED)
554*d39a76e7Sxw161283 		sge->intr_cnt.respQ_empty++;
555*d39a76e7Sxw161283 	if (cause & F_RESPQ_OVERFLOW) {
556*d39a76e7Sxw161283 		sge->intr_cnt.respQ_overflow++;
557*d39a76e7Sxw161283 		cmn_err(CE_WARN, "%s: SGE response queue overflow\n",
558*d39a76e7Sxw161283 		    obj->ch_name);
559*d39a76e7Sxw161283 	}
560*d39a76e7Sxw161283 	if (cause & F_FL_EXHAUSTED) {
561*d39a76e7Sxw161283 		sge->intr_cnt.freelistQ_empty++;
562*d39a76e7Sxw161283 		freelQs_empty(sge);
563*d39a76e7Sxw161283 	}
564*d39a76e7Sxw161283 	if (cause & F_PACKET_TOO_BIG) {
565*d39a76e7Sxw161283 		sge->intr_cnt.pkt_too_big++;
566*d39a76e7Sxw161283 		cmn_err(CE_WARN, "%s: SGE max packet size exceeded\n",
567*d39a76e7Sxw161283 		    obj->ch_name);
568*d39a76e7Sxw161283 	}
569*d39a76e7Sxw161283 	if (cause & F_PACKET_MISMATCH) {
570*d39a76e7Sxw161283 		sge->intr_cnt.pkt_mismatch++;
571*d39a76e7Sxw161283 		cmn_err(CE_WARN, "%s: SGE packet mismatch\n",
572*d39a76e7Sxw161283 		    obj->ch_name);
573*d39a76e7Sxw161283 	}
574*d39a76e7Sxw161283 	if (cause & SGE_INT_FATAL)
575*d39a76e7Sxw161283 		t1_fatal_err(obj);
576*d39a76e7Sxw161283 
577*d39a76e7Sxw161283 	t1_write_reg_4(obj, A_SG_INT_CAUSE, cause);
578*d39a76e7Sxw161283 	return (0);
579*d39a76e7Sxw161283 }
580*d39a76e7Sxw161283 
581*d39a76e7Sxw161283 /*
582*d39a76e7Sxw161283  *
583*d39a76e7Sxw161283  * PARAM:   sge     - SGE instance pointer.
584*d39a76e7Sxw161283  */
585*d39a76e7Sxw161283 int
sge_data_in(pesge * sge)586*d39a76e7Sxw161283 sge_data_in(pesge *sge)
587*d39a76e7Sxw161283 {
588*d39a76e7Sxw161283 	peobj *adapter = sge->obj;
589*d39a76e7Sxw161283 	struct respQ *Q = &sge->respQ;
590*d39a76e7Sxw161283 	respQ_e *e;				/* response queue entry */
591*d39a76e7Sxw161283 	respQ_e *q = Q->rq_entries;		/* base response queue */
592*d39a76e7Sxw161283 	uint32_t cidx = Q->rq_cidx;
593*d39a76e7Sxw161283 	uint32_t genbit = Q->rq_genbit;
594*d39a76e7Sxw161283 	uint32_t entries_n = Q->rq_entries_n;
595*d39a76e7Sxw161283 	uint32_t credits = Q->rq_credits;
596*d39a76e7Sxw161283 	uint32_t credits_thresh = Q->rq_credits_thresh;
597*d39a76e7Sxw161283 	uint32_t ret = 0;
598*d39a76e7Sxw161283 #ifndef TX_THREAD_RECLAIM
599*d39a76e7Sxw161283 	uint32_t credits_pend[2] = {0, 0};
600*d39a76e7Sxw161283 #endif
601*d39a76e7Sxw161283 	uint32_t flags = 0;
602*d39a76e7Sxw161283 	uint32_t flagt;
603*d39a76e7Sxw161283 	ddi_dma_handle_t dh = (ddi_dma_handle_t)Q->rq_dh;
604*d39a76e7Sxw161283 
605*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_PL_CAUSE, F_PL_INTR_SGE_DATA);
606*d39a76e7Sxw161283 
607*d39a76e7Sxw161283 	/*
608*d39a76e7Sxw161283 	 * Catch the case where an interrupt arrives
609*d39a76e7Sxw161283 	 * early.
610*d39a76e7Sxw161283 	 */
611*d39a76e7Sxw161283 	if ((q == NULL) || (dh == NULL)) {
612*d39a76e7Sxw161283 		goto check_slow_ints;
613*d39a76e7Sxw161283 	}
614*d39a76e7Sxw161283 
615*d39a76e7Sxw161283 	/* initial response queue entry */
616*d39a76e7Sxw161283 	e = &q[cidx];
617*d39a76e7Sxw161283 
618*d39a76e7Sxw161283 	/* pull physical memory of response queue entry into cache */
619*d39a76e7Sxw161283 	(void) ddi_dma_sync(dh, (off_t)((caddr_t)e - (caddr_t)q),
620*d39a76e7Sxw161283 	    sizeof (*e), DDI_DMA_SYNC_FORKERNEL);
621*d39a76e7Sxw161283 
622*d39a76e7Sxw161283 	while (e->GenerationBit == genbit) {
623*d39a76e7Sxw161283 		if (--credits < credits_thresh) {
624*d39a76e7Sxw161283 			uint32_t n = entries_n - credits - 1;
625*d39a76e7Sxw161283 			t1_write_reg_4(adapter, A_SG_RSPQUEUECREDIT, n);
626*d39a76e7Sxw161283 			credits += n;
627*d39a76e7Sxw161283 		}
628*d39a76e7Sxw161283 		if (likely(e->DataValid)) {
629*d39a76e7Sxw161283 			(void) t1_sge_rx(sge, &sge->freelQ[e->FreelistQid],
630*d39a76e7Sxw161283 			    e->BufferLength, e->Offload);
631*d39a76e7Sxw161283 			if ((e->Sop != 1) || (e->Eop != 1)) {
632*d39a76e7Sxw161283 				sge->intr_cnt.rx_badEopSop++;
633*d39a76e7Sxw161283 				cmn_err(CE_WARN, "bad Sop %d or Eop %d: %d",
634*d39a76e7Sxw161283 				    e->Sop, e->Eop, e->BufferLength);
635*d39a76e7Sxw161283 			}
636*d39a76e7Sxw161283 		}
637*d39a76e7Sxw161283 		flagt = e->Qsleeping;
638*d39a76e7Sxw161283 		flags |= flagt;
639*d39a76e7Sxw161283 		if (flagt & F_CMDQ0_ENABLE)
640*d39a76e7Sxw161283 			sge->intr_cnt.rx_cmdq0++;
641*d39a76e7Sxw161283 		if (flagt & F_CMDQ1_ENABLE)
642*d39a76e7Sxw161283 			sge->intr_cnt.rx_cmdq1++;
643*d39a76e7Sxw161283 		if (flagt & F_FL0_ENABLE)
644*d39a76e7Sxw161283 			sge->intr_cnt.rx_flq0++;
645*d39a76e7Sxw161283 		if (flagt & F_FL1_ENABLE)
646*d39a76e7Sxw161283 			sge->intr_cnt.rx_flq1++;
647*d39a76e7Sxw161283 #ifdef TX_THREAD_RECLAIM
648*d39a76e7Sxw161283 		spin_lock(&sge->cmdQ[0].cq_qlock);
649*d39a76e7Sxw161283 		sge->cmdQ[0].cq_complete += e->Cmdq0CreditReturn;
650*d39a76e7Sxw161283 		spin_unlock(&sge->cmdQ[0].cq_qlock);
651*d39a76e7Sxw161283 		spin_lock(&sge->cmdQ[1].cq_qlock);
652*d39a76e7Sxw161283 		sge->cmdQ[1].cq_complete += e->Cmdq1CreditReturn;
653*d39a76e7Sxw161283 		if ((adapter->ch_blked) &&
654*d39a76e7Sxw161283 		    (sge->cmdQ[0].cq_complete +
655*d39a76e7Sxw161283 		    sge->cmdQ[1].cq_complete) > 16) {
656*d39a76e7Sxw161283 			adapter->ch_blked = 0;
657*d39a76e7Sxw161283 			ch_gld_ok(adapter);
658*d39a76e7Sxw161283 		}
659*d39a76e7Sxw161283 		spin_unlock(&sge->cmdQ[1].cq_qlock);
660*d39a76e7Sxw161283 #else
661*d39a76e7Sxw161283 		credits_pend[0] += e->Cmdq0CreditReturn;
662*d39a76e7Sxw161283 		credits_pend[1] += e->Cmdq1CreditReturn;
663*d39a76e7Sxw161283 #ifdef CONFIG_SMP
664*d39a76e7Sxw161283 		if (unlikely(credits_pend[0] > SGE_BATCH_THRESH)) {
665*d39a76e7Sxw161283 			free_cmdQ_buffers(sge, &sge->cmdQ[0], credits_pend[0]);
666*d39a76e7Sxw161283 			credits_pend[0] = 0;
667*d39a76e7Sxw161283 		}
668*d39a76e7Sxw161283 		if (unlikely(credits_pend[1] > SGE_BATCH_THRESH)) {
669*d39a76e7Sxw161283 			free_cmdQ_buffers(sge, &sge->cmdQ[1], credits_pend[1]);
670*d39a76e7Sxw161283 			credits_pend[1] = 0;
671*d39a76e7Sxw161283 		}
672*d39a76e7Sxw161283 #endif
673*d39a76e7Sxw161283 #endif
674*d39a76e7Sxw161283 #ifdef HOST_PAUSE
675*d39a76e7Sxw161283 		t1_sge_check_pause(sge, &sge->freelQ[e->FreelistQid]);
676*d39a76e7Sxw161283 #endif
677*d39a76e7Sxw161283 		e++;
678*d39a76e7Sxw161283 		if (unlikely(++cidx == entries_n)) {
679*d39a76e7Sxw161283 			cidx = 0;
680*d39a76e7Sxw161283 			genbit ^= 1;
681*d39a76e7Sxw161283 			e = q;
682*d39a76e7Sxw161283 		}
683*d39a76e7Sxw161283 
684*d39a76e7Sxw161283 		/* pull physical memory of response queue entry into cache */
685*d39a76e7Sxw161283 		(void) ddi_dma_sync(dh, (off_t)((caddr_t)e - (caddr_t)q),
686*d39a76e7Sxw161283 		    sizeof (*e), DDI_DMA_SYNC_FORKERNEL);
687*d39a76e7Sxw161283 
688*d39a76e7Sxw161283 		ret = 1;
689*d39a76e7Sxw161283 	}
690*d39a76e7Sxw161283 
691*d39a76e7Sxw161283 #ifndef TX_THREAD_RECLAIM
692*d39a76e7Sxw161283 	if (credits_pend[0])
693*d39a76e7Sxw161283 		free_cmdQ_buffers(sge, &sge->cmdQ[0], credits_pend[0]);
694*d39a76e7Sxw161283 	if (credits_pend[1])
695*d39a76e7Sxw161283 		free_cmdQ_buffers(sge, &sge->cmdQ[1], credits_pend[1]);
696*d39a76e7Sxw161283 #endif
697*d39a76e7Sxw161283 	if (flags & F_CMDQ0_ENABLE) {
698*d39a76e7Sxw161283 		struct cmdQ *cmdQ = &sge->cmdQ[0];
699*d39a76e7Sxw161283 		atomic_set(&cmdQ->cq_asleep, 1);
700*d39a76e7Sxw161283 		if (atomic_read(cmdQ->cq_pio_pidx) != cmdQ->cq_pidx) {
701*d39a76e7Sxw161283 			doorbell_pio(sge, F_CMDQ0_ENABLE);
702*d39a76e7Sxw161283 			atomic_set(&cmdQ->cq_pio_pidx, cmdQ->cq_pidx);
703*d39a76e7Sxw161283 		}
704*d39a76e7Sxw161283 	}
705*d39a76e7Sxw161283 
706*d39a76e7Sxw161283 	/* the SGE told us one of the free lists is empty */
707*d39a76e7Sxw161283 	if (unlikely(flags & (F_FL0_ENABLE | F_FL1_ENABLE)))
708*d39a76e7Sxw161283 		freelQs_empty(sge);
709*d39a76e7Sxw161283 
710*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
711*d39a76e7Sxw161283 	if (adapter->ch_tx_overflow_mutex)
712*d39a76e7Sxw161283 		mutex_enter(adapter->ch_tx_overflow_mutex);
713*d39a76e7Sxw161283 	if (adapter->ch_blked &&
714*d39a76e7Sxw161283 	    (sge->cmdQ[0].cq_credits > (sge->cmdQ[0].cq_entries_n>>2)) &&
715*d39a76e7Sxw161283 	    (sge->cmdQ[1].cq_credits > (sge->cmdQ[1].cq_entries_n>>2))) {
716*d39a76e7Sxw161283 		adapter->ch_blked = 0;
717*d39a76e7Sxw161283 		if (adapter->ch_tx_overflow_cv)
718*d39a76e7Sxw161283 			cv_broadcast(adapter->ch_tx_overflow_cv);
719*d39a76e7Sxw161283 		ch_gld_ok(adapter);
720*d39a76e7Sxw161283 	}
721*d39a76e7Sxw161283 	if (adapter->ch_tx_overflow_mutex)
722*d39a76e7Sxw161283 		mutex_exit(adapter->ch_tx_overflow_mutex);
723*d39a76e7Sxw161283 #else
724*d39a76e7Sxw161283 #ifndef TX_THREAD_RECLAIM
725*d39a76e7Sxw161283 	if (adapter->ch_blked &&
726*d39a76e7Sxw161283 	    (sge->cmdQ[0].cq_credits > (sge->cmdQ[0].cq_entries_n>>1)) &&
727*d39a76e7Sxw161283 	    (sge->cmdQ[1].cq_credits > (sge->cmdQ[1].cq_entries_n>>1))) {
728*d39a76e7Sxw161283 		adapter->ch_blked = 0;
729*d39a76e7Sxw161283 		ch_gld_ok(adapter);
730*d39a76e7Sxw161283 	}
731*d39a76e7Sxw161283 #endif
732*d39a76e7Sxw161283 #endif	/* CONFIG_CHELSIO_T1_OFFLOAD */
733*d39a76e7Sxw161283 
734*d39a76e7Sxw161283 	Q->rq_genbit = genbit;
735*d39a76e7Sxw161283 	Q->rq_cidx = cidx;
736*d39a76e7Sxw161283 	Q->rq_credits = credits;
737*d39a76e7Sxw161283 
738*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_SG_SLEEPING, cidx);
739*d39a76e7Sxw161283 
740*d39a76e7Sxw161283 check_slow_ints:
741*d39a76e7Sxw161283 	/* handle non-data interrupts */
742*d39a76e7Sxw161283 	if (unlikely(!ret))
743*d39a76e7Sxw161283 		ret = t1_slow_intr_handler(adapter);
744*d39a76e7Sxw161283 
745*d39a76e7Sxw161283 	return (ret);
746*d39a76e7Sxw161283 }
747*d39a76e7Sxw161283 
748*d39a76e7Sxw161283 /*
749*d39a76e7Sxw161283  * allocate a mblk with DMA mapped mblk.
750*d39a76e7Sxw161283  * When checksum offload is enabled, we start the DMA at a 2 byte offset so
751*d39a76e7Sxw161283  * the IP header will be aligned. We do this for sparc only.
752*d39a76e7Sxw161283  */
753*d39a76e7Sxw161283 static uint64_t
os_freelist_buffer_alloc(ch_t * sa,int sz,mblk_t ** mb,ulong_t * dh)754*d39a76e7Sxw161283 os_freelist_buffer_alloc(ch_t *sa, int sz, mblk_t **mb, ulong_t *dh)
755*d39a76e7Sxw161283 {
756*d39a76e7Sxw161283 	ch_esb_t *ch_get_small_rbuf(ch_t *sa);
757*d39a76e7Sxw161283 	ch_esb_t *ch_get_big_rbuf(ch_t *sa);
758*d39a76e7Sxw161283 	ch_esb_t *rbp;
759*d39a76e7Sxw161283 	uint32_t rxoff = sa->sge->rx_offset;
760*d39a76e7Sxw161283 
761*d39a76e7Sxw161283 	if (sz == SGE_SM_BUF_SZ(sa)) {
762*d39a76e7Sxw161283 		/* get pre-mapped buffer */
763*d39a76e7Sxw161283 		if ((rbp = ch_get_small_rbuf(sa)) == NULL) {
764*d39a76e7Sxw161283 			sa->norcvbuf++;
765*d39a76e7Sxw161283 			return ((uint64_t)0);
766*d39a76e7Sxw161283 		}
767*d39a76e7Sxw161283 
768*d39a76e7Sxw161283 		*mb = desballoc((unsigned char *)rbp->cs_buf + rxoff,
769*d39a76e7Sxw161283 		    SGE_SM_BUF_SZ(sa)-rxoff, BPRI_MED, &rbp->cs_frtn);
770*d39a76e7Sxw161283 		if (*mb == NULL) {
771*d39a76e7Sxw161283 			mutex_enter(&sa->ch_small_esbl);
772*d39a76e7Sxw161283 			rbp->cs_next = sa->ch_small_esb_free;
773*d39a76e7Sxw161283 			sa->ch_small_esb_free = rbp;
774*d39a76e7Sxw161283 			mutex_exit(&sa->ch_small_esbl);
775*d39a76e7Sxw161283 			return ((uint64_t)0);
776*d39a76e7Sxw161283 		}
777*d39a76e7Sxw161283 		*dh = rbp->cs_dh;
778*d39a76e7Sxw161283 
779*d39a76e7Sxw161283 		return (rbp->cs_pa + rxoff);
780*d39a76e7Sxw161283 	} else {
781*d39a76e7Sxw161283 		/* get pre-mapped buffer */
782*d39a76e7Sxw161283 		if ((rbp = ch_get_big_rbuf(sa)) == NULL) {
783*d39a76e7Sxw161283 			sa->norcvbuf++;
784*d39a76e7Sxw161283 			return ((uint64_t)0);
785*d39a76e7Sxw161283 		}
786*d39a76e7Sxw161283 
787*d39a76e7Sxw161283 		*mb = desballoc((unsigned char *)rbp->cs_buf + rxoff,
788*d39a76e7Sxw161283 		    SGE_BG_BUF_SZ(sa)-rxoff, BPRI_MED, &rbp->cs_frtn);
789*d39a76e7Sxw161283 		if (*mb == NULL) {
790*d39a76e7Sxw161283 			mutex_enter(&sa->ch_big_esbl);
791*d39a76e7Sxw161283 			rbp->cs_next = sa->ch_big_esb_free;
792*d39a76e7Sxw161283 			sa->ch_big_esb_free = rbp;
793*d39a76e7Sxw161283 			mutex_exit(&sa->ch_big_esbl);
794*d39a76e7Sxw161283 			return ((uint64_t)0);
795*d39a76e7Sxw161283 		}
796*d39a76e7Sxw161283 		*dh = rbp->cs_dh;
797*d39a76e7Sxw161283 
798*d39a76e7Sxw161283 		return (rbp->cs_pa + rxoff);
799*d39a76e7Sxw161283 	}
800*d39a76e7Sxw161283 }
801*d39a76e7Sxw161283 
802*d39a76e7Sxw161283 static inline unsigned int
t1_sge_rx(pesge * sge,struct freelQ * Q,unsigned int len,unsigned int offload)803*d39a76e7Sxw161283 t1_sge_rx(pesge *sge, struct freelQ *Q, unsigned int len, unsigned int offload)
804*d39a76e7Sxw161283 {
805*d39a76e7Sxw161283 	mblk_t *skb;
806*d39a76e7Sxw161283 	peobj *adapter = sge->obj;
807*d39a76e7Sxw161283 	struct freelQ_ce *cq = Q->fq_centries;
808*d39a76e7Sxw161283 	struct freelQ_ce *ce = &cq[Q->fq_cidx];
809*d39a76e7Sxw161283 	ddi_dma_handle_t dh = (ddi_dma_handle_t)ce->fe_dh;
810*d39a76e7Sxw161283 	uint32_t cidx = Q->fq_cidx;
811*d39a76e7Sxw161283 	uint32_t entries_n = Q->fq_entries_n;
812*d39a76e7Sxw161283 	uint32_t sz = Q->fq_rx_buffer_size;
813*d39a76e7Sxw161283 	uint32_t useit = 1;
814*d39a76e7Sxw161283 	uint32_t rxoff = sge->rx_offset;
815*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
816*d39a76e7Sxw161283 	uint32_t rv;
817*d39a76e7Sxw161283 #endif
818*d39a76e7Sxw161283 
819*d39a76e7Sxw161283 	if (Q->fq_id)
820*d39a76e7Sxw161283 		sge->intr_cnt.rx_flq1_cnt++;
821*d39a76e7Sxw161283 	else
822*d39a76e7Sxw161283 		sge->intr_cnt.rx_flq0_cnt++;
823*d39a76e7Sxw161283 	/*
824*d39a76e7Sxw161283 	 * If pkt size falls below threshold, then we'll copy data to
825*d39a76e7Sxw161283 	 * an blk and reuse mblk.
826*d39a76e7Sxw161283 	 *
827*d39a76e7Sxw161283 	 * NOTE that rxoff is 2 for T1 adapters. We align the the start
828*d39a76e7Sxw161283 	 * of the DMA buffer begin at rxoff offset for T1 cards instead of
829*d39a76e7Sxw161283 	 * at the beginning of the buffer, thus the length of the received
830*d39a76e7Sxw161283 	 * data does not include this offset. We therefore always add
831*d39a76e7Sxw161283 	 * SGE_RX_OFFSET to the allocb size so we have space to provide the
832*d39a76e7Sxw161283 	 * offset for the copied data.
833*d39a76e7Sxw161283 	 */
834*d39a76e7Sxw161283 #ifdef HOST_PAUSE
835*d39a76e7Sxw161283 	/*
836*d39a76e7Sxw161283 	 * If we have Host pause compiled in, then we look at the
837*d39a76e7Sxw161283 	 * free list, if the pause is on and we're not in offload
838*d39a76e7Sxw161283 	 * mode then we drop packets, this is designed to avoid
839*d39a76e7Sxw161283 	 * overwhelming the machine. If the machine is powerfull enough
840*d39a76e7Sxw161283 	 * this will not happen. The 'rx_pkt_drops' will show when
841*d39a76e7Sxw161283 	 * packets are being dropped and how much.
842*d39a76e7Sxw161283 	 */
843*d39a76e7Sxw161283 	if ((offload == 0) && adapter->pause_on) {
844*d39a76e7Sxw161283 		freelQ_e *e;
845*d39a76e7Sxw161283 		/* Ditch the packet and reuse original buffer */
846*d39a76e7Sxw161283 		e = &Q->fq_entries[cidx];
847*d39a76e7Sxw161283 		e->GenerationBit  ^= 1;
848*d39a76e7Sxw161283 		e->GenerationBit2 ^= 1;
849*d39a76e7Sxw161283 		sge->intr_cnt.rx_pkt_drops++;
850*d39a76e7Sxw161283 		goto rx_entry_consumed;
851*d39a76e7Sxw161283 	} else if (((adapter->pause_on ||
852*d39a76e7Sxw161283 	    (len <= SGE_RX_COPY_THRESHOLD)) &&
853*d39a76e7Sxw161283 	    (skb = allocb(len + SGE_RX_OFFSET, BPRI_HI))))
854*d39a76e7Sxw161283 #else
855*d39a76e7Sxw161283 	if ((len <= SGE_RX_COPY_THRESHOLD) &&
856*d39a76e7Sxw161283 	    (skb = allocb(len + SGE_RX_OFFSET, BPRI_HI)))
857*d39a76e7Sxw161283 #endif
858*d39a76e7Sxw161283 	{
859*d39a76e7Sxw161283 		freelQ_e *e;
860*d39a76e7Sxw161283 		char *src = (char *)((mblk_t *)ce->fe_mp)->b_rptr;
861*d39a76e7Sxw161283 
862*d39a76e7Sxw161283 		/*
863*d39a76e7Sxw161283 		 * pull physical memory of pkt data into cache
864*d39a76e7Sxw161283 		 * Note that len does not include offset for T1.
865*d39a76e7Sxw161283 		 */
866*d39a76e7Sxw161283 		(void) ddi_dma_sync(dh, (off_t)(rxoff), len,
867*d39a76e7Sxw161283 		    DDI_DMA_SYNC_FORKERNEL);
868*d39a76e7Sxw161283 
869*d39a76e7Sxw161283 		if (offload == 0) {
870*d39a76e7Sxw161283 			/*
871*d39a76e7Sxw161283 			 * create 2 byte offset so IP header aligned on
872*d39a76e7Sxw161283 			 * 4 byte boundry
873*d39a76e7Sxw161283 			 */
874*d39a76e7Sxw161283 			skb_reserve(skb, SGE_RX_OFFSET);
875*d39a76e7Sxw161283 			/*
876*d39a76e7Sxw161283 			 * if hardware inserted 2 byte offset then need to
877*d39a76e7Sxw161283 			 * start copying with extra offset
878*d39a76e7Sxw161283 			 */
879*d39a76e7Sxw161283 			src += sge->rx_pkt_pad;
880*d39a76e7Sxw161283 		}
881*d39a76e7Sxw161283 		memcpy(skb->b_rptr, src, len);
882*d39a76e7Sxw161283 		useit = 0;	/* mblk copy, don't inc esballoc in use cnt */
883*d39a76e7Sxw161283 
884*d39a76e7Sxw161283 		/* so we can reuse original buffer */
885*d39a76e7Sxw161283 		e = &Q->fq_entries[cidx];
886*d39a76e7Sxw161283 		e->GenerationBit  ^= 1;
887*d39a76e7Sxw161283 		e->GenerationBit2 ^= 1;
888*d39a76e7Sxw161283 		sge->intr_cnt.rx_pkt_copied++;
889*d39a76e7Sxw161283 	} else {
890*d39a76e7Sxw161283 		/* consume buffer off the ring */
891*d39a76e7Sxw161283 		skb = ce->fe_mp;
892*d39a76e7Sxw161283 		ce->fe_mp = NULL;
893*d39a76e7Sxw161283 
894*d39a76e7Sxw161283 		/*
895*d39a76e7Sxw161283 		 * if not offload (tunneled pkt), & hardward padded, then
896*d39a76e7Sxw161283 		 * adjust start of pkt to point to start of data i.e.
897*d39a76e7Sxw161283 		 * skip pad (2 bytes).
898*d39a76e7Sxw161283 		 */
899*d39a76e7Sxw161283 		if (!offload && sge->rx_pkt_pad)
900*d39a76e7Sxw161283 			__skb_pull(skb, SGE_RX_OFFSET);
901*d39a76e7Sxw161283 
902*d39a76e7Sxw161283 		/*
903*d39a76e7Sxw161283 		 * pull physical memory of pkt data into cache
904*d39a76e7Sxw161283 		 * Note that len does not include offset for T1.
905*d39a76e7Sxw161283 		 */
906*d39a76e7Sxw161283 		(void) ddi_dma_sync(dh, (off_t)(rxoff), len,
907*d39a76e7Sxw161283 		    DDI_DMA_SYNC_FORKERNEL);
908*d39a76e7Sxw161283 	}
909*d39a76e7Sxw161283 
910*d39a76e7Sxw161283 	/* set length of data in skb */
911*d39a76e7Sxw161283 	skb_put(skb, len);
912*d39a76e7Sxw161283 
913*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
914*d39a76e7Sxw161283 	if (likely(offload)) {
915*d39a76e7Sxw161283 		if (likely(toe_running(adapter))) {
916*d39a76e7Sxw161283 			/* sends pkt upstream to toe layer */
917*d39a76e7Sxw161283 			if (useit) {
918*d39a76e7Sxw161283 				if (sz == SGE_SM_BUF_SZ(adapter)) {
919*d39a76e7Sxw161283 					atomic_add(1,
920*d39a76e7Sxw161283 					&buffers_in_use[adapter->ch_sm_index]);
921*d39a76e7Sxw161283 				} else {
922*d39a76e7Sxw161283 					atomic_add(1,
923*d39a76e7Sxw161283 					&buffers_in_use[adapter->ch_big_index]);
924*d39a76e7Sxw161283 				}
925*d39a76e7Sxw161283 			}
926*d39a76e7Sxw161283 			if (adapter->toe_rcv)
927*d39a76e7Sxw161283 				adapter->toe_rcv(adapter->ch_toeinst, skb);
928*d39a76e7Sxw161283 			else
929*d39a76e7Sxw161283 				freemsg(skb);
930*d39a76e7Sxw161283 		} else {
931*d39a76e7Sxw161283 			cmn_err(CE_WARN,
932*d39a76e7Sxw161283 			    "%s: unexpected offloaded packet, cmd %u\n",
933*d39a76e7Sxw161283 			    adapter->ch_name, *skb->b_rptr);
934*d39a76e7Sxw161283 
935*d39a76e7Sxw161283 			/* discard packet */
936*d39a76e7Sxw161283 			freemsg(skb);
937*d39a76e7Sxw161283 		}
938*d39a76e7Sxw161283 	}
939*d39a76e7Sxw161283 #else
940*d39a76e7Sxw161283 	if (unlikely(offload)) {
941*d39a76e7Sxw161283 		cmn_err(CE_WARN,
942*d39a76e7Sxw161283 		    "%s: unexpected offloaded packet, cmd %u\n",
943*d39a76e7Sxw161283 		    adapter->ch_name, *skb->b_rptr);
944*d39a76e7Sxw161283 
945*d39a76e7Sxw161283 		/* discard paket */
946*d39a76e7Sxw161283 		freemsg(skb);
947*d39a76e7Sxw161283 	}
948*d39a76e7Sxw161283 #endif
949*d39a76e7Sxw161283 	else {
950*d39a76e7Sxw161283 		struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)skb->b_rptr;
951*d39a76e7Sxw161283 		int flg = 0;
952*d39a76e7Sxw161283 		uint32_t cksum;
953*d39a76e7Sxw161283 
954*d39a76e7Sxw161283 		/* adjust beginning of data to skip CPL header */
955*d39a76e7Sxw161283 		skb_pull(skb, SZ_CPL_RX_PKT);
956*d39a76e7Sxw161283 
957*d39a76e7Sxw161283 		/* extract checksum from CPL header here */
958*d39a76e7Sxw161283 
959*d39a76e7Sxw161283 		/*
960*d39a76e7Sxw161283 		 * bump count of mlbks in used by protocol stack(s)
961*d39a76e7Sxw161283 		 */
962*d39a76e7Sxw161283 		if (useit) {
963*d39a76e7Sxw161283 			if (sz == SGE_SM_BUF_SZ(adapter)) {
964*d39a76e7Sxw161283 				atomic_add(1,
965*d39a76e7Sxw161283 				    &buffers_in_use[adapter->ch_sm_index]);
966*d39a76e7Sxw161283 			} else {
967*d39a76e7Sxw161283 				atomic_add(1,
968*d39a76e7Sxw161283 				    &buffers_in_use[adapter->ch_big_index]);
969*d39a76e7Sxw161283 			}
970*d39a76e7Sxw161283 		}
971*d39a76e7Sxw161283 
972*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
973*d39a76e7Sxw161283 		/*
974*d39a76e7Sxw161283 		 * let the TOE layer have a crack at the packet first.
975*d39a76e7Sxw161283 		 */
976*d39a76e7Sxw161283 		if (adapter->toe_tunnel) {
977*d39a76e7Sxw161283 			rv = adapter->toe_tunnel(adapter->ch_toeinst, skb);
978*d39a76e7Sxw161283 			/*
979*d39a76e7Sxw161283 			 * The TOE may have consumed the packet.
980*d39a76e7Sxw161283 			 */
981*d39a76e7Sxw161283 			if (rv)
982*d39a76e7Sxw161283 				goto rx_entry_consumed;
983*d39a76e7Sxw161283 		}
984*d39a76e7Sxw161283 #endif	/* CONFIG_CHELSIO_T1_OFFLOAD */
985*d39a76e7Sxw161283 
986*d39a76e7Sxw161283 		cksum = p->csum;
987*d39a76e7Sxw161283 
988*d39a76e7Sxw161283 		/*
989*d39a76e7Sxw161283 		 * NOTE: 14+9 = size of MAC + offset to IP protocol field
990*d39a76e7Sxw161283 		 */
991*d39a76e7Sxw161283 		if (adapter->ch_config.cksum_enabled &&
992*d39a76e7Sxw161283 		    (ntohs(((struct ether_header *)skb->b_rptr)->ether_type) ==
993*d39a76e7Sxw161283 		    ETHERTYPE_IP) &&
994*d39a76e7Sxw161283 		    ((skb->b_rptr[14+9] == IPPROTO_TCP) ||
995*d39a76e7Sxw161283 		    (skb->b_rptr[14+9] == IPPROTO_UDP))) {
996*d39a76e7Sxw161283 			flg = 1;
997*d39a76e7Sxw161283 		}
998*d39a76e7Sxw161283 
999*d39a76e7Sxw161283 		ch_send_up(adapter, skb, cksum, flg);
1000*d39a76e7Sxw161283 	}
1001*d39a76e7Sxw161283 
1002*d39a76e7Sxw161283 rx_entry_consumed:
1003*d39a76e7Sxw161283 
1004*d39a76e7Sxw161283 	if (++cidx == entries_n)
1005*d39a76e7Sxw161283 		cidx = 0;
1006*d39a76e7Sxw161283 
1007*d39a76e7Sxw161283 	Q->fq_cidx = cidx;
1008*d39a76e7Sxw161283 
1009*d39a76e7Sxw161283 	if (unlikely(--Q->fq_credits < (entries_n>>2)))
1010*d39a76e7Sxw161283 		/* allocate new buffers on the free list */
1011*d39a76e7Sxw161283 		alloc_freelQ_buffers(sge, Q);
1012*d39a76e7Sxw161283 	return (1);
1013*d39a76e7Sxw161283 }
1014*d39a76e7Sxw161283 
1015*d39a76e7Sxw161283 #ifdef HOST_PAUSE
1016*d39a76e7Sxw161283 static void
t1_sge_check_pause(pesge * sge,struct freelQ * Q)1017*d39a76e7Sxw161283 t1_sge_check_pause(pesge *sge, struct freelQ *Q)
1018*d39a76e7Sxw161283 {
1019*d39a76e7Sxw161283 	peobj *adapter = sge->obj;
1020*d39a76e7Sxw161283 
1021*d39a76e7Sxw161283 	/*
1022*d39a76e7Sxw161283 	 * If the number of available credits shrinks below
1023*d39a76e7Sxw161283 	 * the Pause on threshold then enable the pause and
1024*d39a76e7Sxw161283 	 * try and allocate more buffers.
1025*d39a76e7Sxw161283 	 * On the next pass, if there's more credits returned
1026*d39a76e7Sxw161283 	 * then check that you've went above the pause
1027*d39a76e7Sxw161283 	 * threshold and then disable the pause.
1028*d39a76e7Sxw161283 	 */
1029*d39a76e7Sxw161283 	if (Q->fq_credits < Q->fq_pause_on_thresh) {
1030*d39a76e7Sxw161283 		if (do_host_pause) {
1031*d39a76e7Sxw161283 			sge->intr_cnt.rx_pause_on++;
1032*d39a76e7Sxw161283 			adapter->txxg_cfg1 |=
1033*d39a76e7Sxw161283 			    SUNI1x10GEXP_BITMSK_TXXG_HOSTPAUSE;
1034*d39a76e7Sxw161283 			(void) t1_tpi_write(adapter,
1035*d39a76e7Sxw161283 			    SUNI1x10GEXP_REG_TXXG_CONFIG_1 << 2,
1036*d39a76e7Sxw161283 			    adapter->txxg_cfg1);
1037*d39a76e7Sxw161283 			adapter->pause_on = 1;
1038*d39a76e7Sxw161283 			adapter->pause_time = gethrtime();
1039*d39a76e7Sxw161283 		}
1040*d39a76e7Sxw161283 		alloc_freelQ_buffers(sge, Q);
1041*d39a76e7Sxw161283 	} else if ((adapter->pause_on) &&
1042*d39a76e7Sxw161283 	    (Q->fq_credits > Q->fq_pause_off_thresh)) {
1043*d39a76e7Sxw161283 		hrtime_t time;
1044*d39a76e7Sxw161283 		sge->intr_cnt.rx_pause_off++;
1045*d39a76e7Sxw161283 		adapter->txxg_cfg1 &= ~SUNI1x10GEXP_BITMSK_TXXG_HOSTPAUSE;
1046*d39a76e7Sxw161283 		(void) t1_tpi_write(adapter,
1047*d39a76e7Sxw161283 		    SUNI1x10GEXP_REG_TXXG_CONFIG_1 << 2,
1048*d39a76e7Sxw161283 		    adapter->txxg_cfg1);
1049*d39a76e7Sxw161283 		adapter->pause_on = 0;
1050*d39a76e7Sxw161283 		time = (gethrtime() - adapter->pause_time)/1000;
1051*d39a76e7Sxw161283 		sge->intr_cnt.rx_pause_ms += time;
1052*d39a76e7Sxw161283 		if (time > sge->intr_cnt.rx_pause_spike)
1053*d39a76e7Sxw161283 			sge->intr_cnt.rx_pause_spike = (uint32_t)time;
1054*d39a76e7Sxw161283 	}
1055*d39a76e7Sxw161283 	sge->intr_cnt.rx_fl_credits = Q->fq_credits;
1056*d39a76e7Sxw161283 }
1057*d39a76e7Sxw161283 #endif	/* HOST_PAUSE */
1058*d39a76e7Sxw161283 
1059*d39a76e7Sxw161283 static void
alloc_freelQ_buffers(pesge * sge,struct freelQ * Q)1060*d39a76e7Sxw161283 alloc_freelQ_buffers(pesge *sge, struct freelQ *Q)
1061*d39a76e7Sxw161283 {
1062*d39a76e7Sxw161283 	uint32_t pidx = Q->fq_pidx;
1063*d39a76e7Sxw161283 	struct freelQ_ce *ce = &Q->fq_centries[pidx];
1064*d39a76e7Sxw161283 	freelQ_e *fq = Q->fq_entries;		/* base of freelist Q */
1065*d39a76e7Sxw161283 	freelQ_e *e = &Q->fq_entries[pidx];
1066*d39a76e7Sxw161283 	uint32_t sz = Q->fq_rx_buffer_size;
1067*d39a76e7Sxw161283 	uint32_t rxoff = sge->rx_offset;
1068*d39a76e7Sxw161283 	uint32_t credits = Q->fq_credits;
1069*d39a76e7Sxw161283 	uint32_t entries_n = Q->fq_entries_n;
1070*d39a76e7Sxw161283 	uint32_t genbit = Q->fq_genbit;
1071*d39a76e7Sxw161283 	ddi_dma_handle_t th = (ddi_dma_handle_t)Q->fq_dh;
1072*d39a76e7Sxw161283 	ulong_t dh;
1073*d39a76e7Sxw161283 	uint64_t mapping;
1074*d39a76e7Sxw161283 	off_t offset = (off_t)((caddr_t)e - (caddr_t)fq);
1075*d39a76e7Sxw161283 	size_t len = 0;
1076*d39a76e7Sxw161283 
1077*d39a76e7Sxw161283 	while (credits < entries_n) {
1078*d39a76e7Sxw161283 		if (e->GenerationBit != genbit) {
1079*d39a76e7Sxw161283 			mblk_t *skb;
1080*d39a76e7Sxw161283 
1081*d39a76e7Sxw161283 			mapping = os_freelist_buffer_alloc(sge->obj, sz,
1082*d39a76e7Sxw161283 			    &skb, &dh);
1083*d39a76e7Sxw161283 			if (mapping == 0) {
1084*d39a76e7Sxw161283 				sge->intr_cnt.rx_flbuf_fails++;
1085*d39a76e7Sxw161283 				break;
1086*d39a76e7Sxw161283 			}
1087*d39a76e7Sxw161283 			sge->intr_cnt.rx_flbuf_allocs++;
1088*d39a76e7Sxw161283 
1089*d39a76e7Sxw161283 			ce->fe_mp = skb;
1090*d39a76e7Sxw161283 			ce->fe_dh = dh;
1091*d39a76e7Sxw161283 
1092*d39a76e7Sxw161283 			/*
1093*d39a76e7Sxw161283 			 * Note that for T1, we've started the beginning of
1094*d39a76e7Sxw161283 			 * of the buffer by an offset of 2 bytes. We thus
1095*d39a76e7Sxw161283 			 * decrement the length to account for this.
1096*d39a76e7Sxw161283 			 */
1097*d39a76e7Sxw161283 			e->AddrLow = (u32)mapping;
1098*d39a76e7Sxw161283 			e->AddrHigh = (u64)mapping >> 32;
1099*d39a76e7Sxw161283 			e->BufferLength = sz - rxoff;
1100*d39a76e7Sxw161283 			wmb();
1101*d39a76e7Sxw161283 			e->GenerationBit = e->GenerationBit2 = genbit;
1102*d39a76e7Sxw161283 		}
1103*d39a76e7Sxw161283 
1104*d39a76e7Sxw161283 		len += sizeof (*e);
1105*d39a76e7Sxw161283 
1106*d39a76e7Sxw161283 		ce++;
1107*d39a76e7Sxw161283 		e++;
1108*d39a76e7Sxw161283 		credits++;
1109*d39a76e7Sxw161283 		if (++pidx == entries_n) {
1110*d39a76e7Sxw161283 			/*
1111*d39a76e7Sxw161283 			 * sync freelist entries to physical memory up to
1112*d39a76e7Sxw161283 			 * end of the table.
1113*d39a76e7Sxw161283 			 */
1114*d39a76e7Sxw161283 			(void) ddi_dma_sync(th, offset, len,
1115*d39a76e7Sxw161283 			    DDI_DMA_SYNC_FORDEV);
1116*d39a76e7Sxw161283 			offset = 0;
1117*d39a76e7Sxw161283 			len = 0;
1118*d39a76e7Sxw161283 
1119*d39a76e7Sxw161283 			pidx = 0;
1120*d39a76e7Sxw161283 			genbit ^= 1;
1121*d39a76e7Sxw161283 			ce = Q->fq_centries;
1122*d39a76e7Sxw161283 			e = Q->fq_entries;
1123*d39a76e7Sxw161283 		}
1124*d39a76e7Sxw161283 	}
1125*d39a76e7Sxw161283 
1126*d39a76e7Sxw161283 	/* sync freelist entries that have been modified. */
1127*d39a76e7Sxw161283 	if (len)
1128*d39a76e7Sxw161283 		(void) ddi_dma_sync(th, offset, len, DDI_DMA_SYNC_FORDEV);
1129*d39a76e7Sxw161283 
1130*d39a76e7Sxw161283 	Q->fq_genbit = genbit;
1131*d39a76e7Sxw161283 	Q->fq_pidx = pidx;
1132*d39a76e7Sxw161283 	Q->fq_credits = credits;
1133*d39a76e7Sxw161283 }
1134*d39a76e7Sxw161283 
1135*d39a76e7Sxw161283 static void
freelQs_empty(pesge * sge)1136*d39a76e7Sxw161283 freelQs_empty(pesge *sge)
1137*d39a76e7Sxw161283 {
1138*d39a76e7Sxw161283 	u32 irq_reg = t1_read_reg_4(sge->obj, A_SG_INT_ENABLE);
1139*d39a76e7Sxw161283 	u32 irqholdoff_reg;
1140*d39a76e7Sxw161283 
1141*d39a76e7Sxw161283 	alloc_freelQ_buffers(sge, &sge->freelQ[0]);
1142*d39a76e7Sxw161283 	alloc_freelQ_buffers(sge, &sge->freelQ[1]);
1143*d39a76e7Sxw161283 
1144*d39a76e7Sxw161283 	if ((sge->freelQ[0].fq_credits > sge->freelQ[0].fq_entries_n >> 2) &&
1145*d39a76e7Sxw161283 	    (sge->freelQ[1].fq_credits > sge->freelQ[1].fq_entries_n >> 2)) {
1146*d39a76e7Sxw161283 		irq_reg |= F_FL_EXHAUSTED;
1147*d39a76e7Sxw161283 		irqholdoff_reg = sge->intrtimer[sge->currIndex];
1148*d39a76e7Sxw161283 	} else {
1149*d39a76e7Sxw161283 		/* Clear the F_FL_EXHAUSTED interrupts for now */
1150*d39a76e7Sxw161283 		irq_reg &= ~F_FL_EXHAUSTED;
1151*d39a76e7Sxw161283 		irqholdoff_reg = sge->intrtimer_nres;
1152*d39a76e7Sxw161283 	}
1153*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_INTRTIMER, irqholdoff_reg);
1154*d39a76e7Sxw161283 	t1_write_reg_4(sge->obj, A_SG_INT_ENABLE, irq_reg);
1155*d39a76e7Sxw161283 
1156*d39a76e7Sxw161283 	/* We reenable the Qs to force an Freelist GTS interrupt later */
1157*d39a76e7Sxw161283 	doorbell_pio(sge, F_FL0_ENABLE | F_FL1_ENABLE);
1158*d39a76e7Sxw161283 }
1159*d39a76e7Sxw161283 
1160*d39a76e7Sxw161283 /*
1161*d39a76e7Sxw161283  * Frees 'credits_pend' TX buffers and returns the credits to Q->credits.
1162*d39a76e7Sxw161283  * Free xmit buffers
1163*d39a76e7Sxw161283  */
1164*d39a76e7Sxw161283 static void
free_cmdQ_buffers(pesge * sge,struct cmdQ * Q,unsigned int credits_pend)1165*d39a76e7Sxw161283 free_cmdQ_buffers(pesge *sge, struct cmdQ *Q, unsigned int credits_pend)
1166*d39a76e7Sxw161283 {
1167*d39a76e7Sxw161283 	mblk_t *skb;
1168*d39a76e7Sxw161283 	struct cmdQ_ce *ce;
1169*d39a76e7Sxw161283 	struct cmdQ_ce *cq = Q->cq_centries;
1170*d39a76e7Sxw161283 	uint32_t entries_n = Q->cq_entries_n;
1171*d39a76e7Sxw161283 	uint32_t cidx = Q->cq_cidx;
1172*d39a76e7Sxw161283 	uint32_t i = credits_pend;
1173*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1174*d39a76e7Sxw161283 	ch_t *chp = sge->obj;
1175*d39a76e7Sxw161283 #endif
1176*d39a76e7Sxw161283 	ce = &cq[cidx];
1177*d39a76e7Sxw161283 
1178*d39a76e7Sxw161283 	while (i--) {
1179*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_OFFLOAD
1180*d39a76e7Sxw161283 		/* if flag set, then toe buffer */
1181*d39a76e7Sxw161283 		switch (ce->ce_flg & 0x7) {
1182*d39a76e7Sxw161283 		case DH_DMA:
1183*d39a76e7Sxw161283 			if (ce->ce_dh) {
1184*d39a76e7Sxw161283 				ch_unbind_dma_handle(sge->obj, ce->ce_dh);
1185*d39a76e7Sxw161283 				ce->ce_dh = NULL;	/* may not be needed */
1186*d39a76e7Sxw161283 			}
1187*d39a76e7Sxw161283 			skb = ce->ce_mp;
1188*d39a76e7Sxw161283 			if (skb && ((ce->ce_flg & CH_ARP) == NULL)) {
1189*d39a76e7Sxw161283 				freemsg(skb);
1190*d39a76e7Sxw161283 			}
1191*d39a76e7Sxw161283 			ce->ce_mp = NULL;
1192*d39a76e7Sxw161283 			break;
1193*d39a76e7Sxw161283 
1194*d39a76e7Sxw161283 #if defined(__sparc)
1195*d39a76e7Sxw161283 		case DH_DVMA:
1196*d39a76e7Sxw161283 			if (ce->ce_dh) {
1197*d39a76e7Sxw161283 				ch_unbind_dvma_handle(sge->obj, ce->ce_dh);
1198*d39a76e7Sxw161283 				ce->ce_dh = NULL;	/* may not be needed */
1199*d39a76e7Sxw161283 			}
1200*d39a76e7Sxw161283 			skb = ce->ce_mp;
1201*d39a76e7Sxw161283 			if (skb && ((ce->ce_flg & CH_ARP) == NULL)) {
1202*d39a76e7Sxw161283 				freemsg(skb);
1203*d39a76e7Sxw161283 			}
1204*d39a76e7Sxw161283 			ce->ce_mp = NULL;
1205*d39a76e7Sxw161283 			break;
1206*d39a76e7Sxw161283 #endif	/* __sparc */
1207*d39a76e7Sxw161283 
1208*d39a76e7Sxw161283 		case DH_TOE:
1209*d39a76e7Sxw161283 			chp->toe_free(chp->ch_toeinst, (tbuf_t *)(ce->ce_mp));
1210*d39a76e7Sxw161283 			ce->ce_mp = NULL;
1211*d39a76e7Sxw161283 			break;
1212*d39a76e7Sxw161283 		}
1213*d39a76e7Sxw161283 #else	/* CONFIG_CHELSIO_T1_OFFLOAD */
1214*d39a76e7Sxw161283 		if (ce->ce_dh) {
1215*d39a76e7Sxw161283 			if ((ce->ce_flg & 7) == DH_DMA) {
1216*d39a76e7Sxw161283 				ch_unbind_dma_handle(sge->obj, ce->ce_dh);
1217*d39a76e7Sxw161283 			}
1218*d39a76e7Sxw161283 #if defined(__sparc)
1219*d39a76e7Sxw161283 			else {
1220*d39a76e7Sxw161283 				ch_unbind_dvma_handle(sge->obj, ce->ce_dh);
1221*d39a76e7Sxw161283 			}
1222*d39a76e7Sxw161283 #endif	/* __sparc */
1223*d39a76e7Sxw161283 			ce->ce_dh = NULL; /* may not be needed */
1224*d39a76e7Sxw161283 		}
1225*d39a76e7Sxw161283 
1226*d39a76e7Sxw161283 		skb = ce->ce_mp;
1227*d39a76e7Sxw161283 		if (skb && ((ce->ce_flg & CH_ARP) == NULL)) {
1228*d39a76e7Sxw161283 			freemsg(skb);
1229*d39a76e7Sxw161283 		}
1230*d39a76e7Sxw161283 		ce->ce_mp = NULL;
1231*d39a76e7Sxw161283 #endif	/* !CONFIG_CHELSIO_T1_OFFLOAD */
1232*d39a76e7Sxw161283 
1233*d39a76e7Sxw161283 		ce++;
1234*d39a76e7Sxw161283 		if (++cidx == entries_n) {
1235*d39a76e7Sxw161283 			cidx = 0;
1236*d39a76e7Sxw161283 			ce = cq;
1237*d39a76e7Sxw161283 		}
1238*d39a76e7Sxw161283 	}
1239*d39a76e7Sxw161283 
1240*d39a76e7Sxw161283 	Q->cq_cidx = cidx;
1241*d39a76e7Sxw161283 	atomic_add(credits_pend, &Q->cq_credits);
1242*d39a76e7Sxw161283 }
1243*d39a76e7Sxw161283 
1244*d39a76e7Sxw161283 struct sge_intr_counts *
sge_get_stat(pesge * sge)1245*d39a76e7Sxw161283 sge_get_stat(pesge *sge)
1246*d39a76e7Sxw161283 {
1247*d39a76e7Sxw161283 	return (&sge->intr_cnt);
1248*d39a76e7Sxw161283 }
1249*d39a76e7Sxw161283 
1250*d39a76e7Sxw161283 /*
1251*d39a76e7Sxw161283  * Allocates both RX and TX resources and configures the SGE. However,
1252*d39a76e7Sxw161283  * the hardware is not enabled yet.
1253*d39a76e7Sxw161283  *
1254*d39a76e7Sxw161283  * rx_pkt_pad is set, if the hardware supports aligning non-offload traffic.
1255*d39a76e7Sxw161283  * jumbo_fl is set to the index of the freelist containing the jumbo buffers.
1256*d39a76e7Sxw161283  */
1257*d39a76e7Sxw161283 int
t1_sge_configure(pesge * sge,struct sge_params * p)1258*d39a76e7Sxw161283 t1_sge_configure(pesge *sge, struct sge_params *p)
1259*d39a76e7Sxw161283 {
1260*d39a76e7Sxw161283 	sge->rx_pkt_pad = t1_is_T1B(sge->obj) ? 0 : SGE_RX_OFFSET;
1261*d39a76e7Sxw161283 	sge->jumbo_fl = t1_is_T1B(sge->obj) ? 1 : 0;
1262*d39a76e7Sxw161283 	/* if we're a T2 card, then we have hardware offset support */
1263*d39a76e7Sxw161283 	sge->rx_offset = t1_is_T1B(sge->obj) ? SGE_RX_OFFSET: 0;
1264*d39a76e7Sxw161283 
1265*d39a76e7Sxw161283 	if (alloc_rx_resources(sge, p))
1266*d39a76e7Sxw161283 		return (-ENOMEM);
1267*d39a76e7Sxw161283 	if (alloc_tx_resources(sge, p)) {
1268*d39a76e7Sxw161283 		free_rx_resources(sge);
1269*d39a76e7Sxw161283 		return (-ENOMEM);
1270*d39a76e7Sxw161283 	}
1271*d39a76e7Sxw161283 	configure_sge(sge, p);
1272*d39a76e7Sxw161283 
1273*d39a76e7Sxw161283 	/*
1274*d39a76e7Sxw161283 	 * Now that we have sized the free lists calculate the payload
1275*d39a76e7Sxw161283 	 * capacity of the large buffers.  Other parts of the driver use
1276*d39a76e7Sxw161283 	 * this to set the max offload coalescing size so that RX packets
1277*d39a76e7Sxw161283 	 * do not overflow our large buffers.
1278*d39a76e7Sxw161283 	 */
1279*d39a76e7Sxw161283 	p->large_buf_capacity = jumbo_payload_capacity(sge);
1280*d39a76e7Sxw161283 	return (0);
1281*d39a76e7Sxw161283 }
1282*d39a76e7Sxw161283 
1283*d39a76e7Sxw161283 /*
1284*d39a76e7Sxw161283  * Allocates basic RX resources, consisting of memory mapped freelist Qs and a
1285*d39a76e7Sxw161283  * response Q.
1286*d39a76e7Sxw161283  */
1287*d39a76e7Sxw161283 static int
alloc_rx_resources(pesge * sge,struct sge_params * p)1288*d39a76e7Sxw161283 alloc_rx_resources(pesge *sge, struct sge_params *p)
1289*d39a76e7Sxw161283 {
1290*d39a76e7Sxw161283 	unsigned int size, i;
1291*d39a76e7Sxw161283 
1292*d39a76e7Sxw161283 	for (i = 0; i < SGE_FREELQ_N; i++) {
1293*d39a76e7Sxw161283 		struct freelQ *Q = &sge->freelQ[i];
1294*d39a76e7Sxw161283 
1295*d39a76e7Sxw161283 		Q->fq_id = i;
1296*d39a76e7Sxw161283 		Q->fq_genbit = 1;
1297*d39a76e7Sxw161283 		Q->fq_entries_n = p->freelQ_size[i];
1298*d39a76e7Sxw161283 #ifdef HOST_PAUSE
1299*d39a76e7Sxw161283 		Q->fq_pause_on_thresh = flq_pause_window;
1300*d39a76e7Sxw161283 		Q->fq_pause_off_thresh = Q->fq_entries_n >> 1;
1301*d39a76e7Sxw161283 #endif
1302*d39a76e7Sxw161283 		size = sizeof (freelQ_e) * Q->fq_entries_n;
1303*d39a76e7Sxw161283 
1304*d39a76e7Sxw161283 		Q->fq_entries = pe_os_malloc_contig_wait_zero(sge->obj,
1305*d39a76e7Sxw161283 		    size, &Q->fq_pa, &Q->fq_dh, &Q->fq_ah, DMA_OUT);
1306*d39a76e7Sxw161283 
1307*d39a76e7Sxw161283 
1308*d39a76e7Sxw161283 		if (!Q->fq_entries)
1309*d39a76e7Sxw161283 			goto err_no_mem;
1310*d39a76e7Sxw161283 		memset(Q->fq_entries, 0, size);
1311*d39a76e7Sxw161283 		size = sizeof (struct freelQ_ce) * Q->fq_entries_n;
1312*d39a76e7Sxw161283 		Q->fq_centries = t1_os_malloc_wait_zero(size);
1313*d39a76e7Sxw161283 		if (!Q->fq_centries)
1314*d39a76e7Sxw161283 			goto err_no_mem;
1315*d39a76e7Sxw161283 		memset(Q->fq_centries, 0, size);
1316*d39a76e7Sxw161283 	}
1317*d39a76e7Sxw161283 
1318*d39a76e7Sxw161283 	/*
1319*d39a76e7Sxw161283 	 * Calculate the buffer sizes for the two free lists.  FL0 accommodates
1320*d39a76e7Sxw161283 	 * regular sized Ethernet frames, FL1 is sized not to exceed 16K,
1321*d39a76e7Sxw161283 	 * including all the sk_buff overhead.
1322*d39a76e7Sxw161283 	 * For T1C FL0 and FL1 are reversed.
1323*d39a76e7Sxw161283 	 */
1324*d39a76e7Sxw161283 #ifdef NOTYET
1325*d39a76e7Sxw161283 	sge->freelQ[1 ^ sge->jumbo_fl].fq_rx_buffer_size = SGE_RX_SM_BUF_SIZE +
1326*d39a76e7Sxw161283 	    sizeof (struct cpl_rx_data) +
1327*d39a76e7Sxw161283 	    SGE_RX_OFFSET - sge->rx_pkt_pad;
1328*d39a76e7Sxw161283 #else
1329*d39a76e7Sxw161283 	sge->freelQ[1 ^ sge->jumbo_fl].fq_rx_buffer_size =
1330*d39a76e7Sxw161283 	    sge->obj->ch_sm_buf_sz;
1331*d39a76e7Sxw161283 	if (is_T2(sge->obj))
1332*d39a76e7Sxw161283 		sge->intr_cnt.rx_flq1_sz = sge->obj->ch_sm_buf_sz;
1333*d39a76e7Sxw161283 	else
1334*d39a76e7Sxw161283 		sge->intr_cnt.rx_flq0_sz = sge->obj->ch_sm_buf_sz;
1335*d39a76e7Sxw161283 #endif
1336*d39a76e7Sxw161283 #ifdef NOTYET
1337*d39a76e7Sxw161283 	sge->freelQ[sge->jumbo_fl].fq_rx_buffer_size = (16 * 1024) -
1338*d39a76e7Sxw161283 	    SKB_DATA_ALIGN(sizeof (struct skb_shared_info));
1339*d39a76e7Sxw161283 #else
1340*d39a76e7Sxw161283 	sge->freelQ[sge->jumbo_fl].fq_rx_buffer_size = sge->obj->ch_bg_buf_sz;
1341*d39a76e7Sxw161283 	if (is_T2(sge->obj))
1342*d39a76e7Sxw161283 		sge->intr_cnt.rx_flq0_sz = sge->obj->ch_bg_buf_sz;
1343*d39a76e7Sxw161283 	else
1344*d39a76e7Sxw161283 		sge->intr_cnt.rx_flq1_sz = sge->obj->ch_bg_buf_sz;
1345*d39a76e7Sxw161283 #endif
1346*d39a76e7Sxw161283 
1347*d39a76e7Sxw161283 	sge->respQ.rq_genbit = 1;
1348*d39a76e7Sxw161283 	sge->respQ.rq_entries_n = sge_respq_cnt;
1349*d39a76e7Sxw161283 	sge->respQ.rq_credits = sge_respq_cnt;
1350*d39a76e7Sxw161283 	sge->respQ.rq_credits_thresh = sge_respq_cnt - (sge_respq_cnt >> 2);
1351*d39a76e7Sxw161283 	size = sizeof (respQ_e) * sge->respQ.rq_entries_n;
1352*d39a76e7Sxw161283 
1353*d39a76e7Sxw161283 	sge->respQ.rq_entries = pe_os_malloc_contig_wait_zero(sge->obj,
1354*d39a76e7Sxw161283 	    size, &(sge->respQ.rq_pa), &(sge->respQ.rq_dh),
1355*d39a76e7Sxw161283 	    &(sge->respQ.rq_ah), 0);
1356*d39a76e7Sxw161283 
1357*d39a76e7Sxw161283 	if (!sge->respQ.rq_entries)
1358*d39a76e7Sxw161283 		goto err_no_mem;
1359*d39a76e7Sxw161283 	memset(sge->respQ.rq_entries, 0, size);
1360*d39a76e7Sxw161283 	return (0);
1361*d39a76e7Sxw161283 
1362*d39a76e7Sxw161283 err_no_mem:
1363*d39a76e7Sxw161283 	free_rx_resources(sge);
1364*d39a76e7Sxw161283 	return (1);
1365*d39a76e7Sxw161283 }
1366*d39a76e7Sxw161283 
1367*d39a76e7Sxw161283 /*
1368*d39a76e7Sxw161283  * Allocates basic TX resources, consisting of memory mapped command Qs.
1369*d39a76e7Sxw161283  */
1370*d39a76e7Sxw161283 static int
alloc_tx_resources(pesge * sge,struct sge_params * p)1371*d39a76e7Sxw161283 alloc_tx_resources(pesge *sge, struct sge_params *p)
1372*d39a76e7Sxw161283 {
1373*d39a76e7Sxw161283 	unsigned int size, i;
1374*d39a76e7Sxw161283 
1375*d39a76e7Sxw161283 	for (i = 0; i < SGE_CMDQ_N; i++) {
1376*d39a76e7Sxw161283 		struct cmdQ *Q = &sge->cmdQ[i];
1377*d39a76e7Sxw161283 
1378*d39a76e7Sxw161283 		Q->cq_genbit = 1;
1379*d39a76e7Sxw161283 		Q->cq_entries_n = p->cmdQ_size[i];
1380*d39a76e7Sxw161283 		atomic_set(&Q->cq_credits, Q->cq_entries_n);
1381*d39a76e7Sxw161283 		atomic_set(&Q->cq_asleep, 1);
1382*d39a76e7Sxw161283 
1383*d39a76e7Sxw161283 		mutex_init(&Q->cq_qlock, NULL, MUTEX_DRIVER,
1384*d39a76e7Sxw161283 		    sge->obj->ch_icookp);
1385*d39a76e7Sxw161283 
1386*d39a76e7Sxw161283 		size = sizeof (cmdQ_e) * Q->cq_entries_n;
1387*d39a76e7Sxw161283 		Q->cq_entries = pe_os_malloc_contig_wait_zero(sge->obj,
1388*d39a76e7Sxw161283 		    size, &Q->cq_pa, &Q->cq_dh, &Q->cq_ah, DMA_OUT);
1389*d39a76e7Sxw161283 
1390*d39a76e7Sxw161283 		if (!Q->cq_entries)
1391*d39a76e7Sxw161283 			goto err_no_mem;
1392*d39a76e7Sxw161283 		memset(Q->cq_entries, 0, size);
1393*d39a76e7Sxw161283 		size = sizeof (struct cmdQ_ce) * Q->cq_entries_n;
1394*d39a76e7Sxw161283 		Q->cq_centries = t1_os_malloc_wait_zero(size);
1395*d39a76e7Sxw161283 		if (!Q->cq_centries)
1396*d39a76e7Sxw161283 			goto err_no_mem;
1397*d39a76e7Sxw161283 		memset(Q->cq_centries, 0, size);
1398*d39a76e7Sxw161283 
1399*d39a76e7Sxw161283 		/* allocate pre-mapped dma headers */
1400*d39a76e7Sxw161283 		pe_dma_handle_init(sge->obj, Q->cq_entries_n);
1401*d39a76e7Sxw161283 	}
1402*d39a76e7Sxw161283 
1403*d39a76e7Sxw161283 	return (0);
1404*d39a76e7Sxw161283 
1405*d39a76e7Sxw161283 err_no_mem:
1406*d39a76e7Sxw161283 	free_tx_resources(sge);
1407*d39a76e7Sxw161283 	return (1);
1408*d39a76e7Sxw161283 }
1409*d39a76e7Sxw161283 
1410*d39a76e7Sxw161283 /*
1411*d39a76e7Sxw161283  * Sets the interrupt latency timer when the adaptive Rx coalescing
1412*d39a76e7Sxw161283  * is turned off. Do nothing when it is turned on again.
1413*d39a76e7Sxw161283  *
1414*d39a76e7Sxw161283  * This routine relies on the fact that the caller has already set
1415*d39a76e7Sxw161283  * the adaptive policy in adapter->sge_params before calling it.
1416*d39a76e7Sxw161283  */
1417*d39a76e7Sxw161283 int
t1_sge_set_coalesce_params(pesge * sge,struct sge_params * p)1418*d39a76e7Sxw161283 t1_sge_set_coalesce_params(pesge *sge, struct sge_params *p)
1419*d39a76e7Sxw161283 {
1420*d39a76e7Sxw161283 	if (!p->coalesce_enable) {
1421*d39a76e7Sxw161283 		u32 newTimer = p->rx_coalesce_usecs *
1422*d39a76e7Sxw161283 		    (board_info(sge->obj)->clock_core / 1000000);
1423*d39a76e7Sxw161283 
1424*d39a76e7Sxw161283 		t1_write_reg_4(sge->obj, A_SG_INTRTIMER, newTimer);
1425*d39a76e7Sxw161283 	}
1426*d39a76e7Sxw161283 	return (0);
1427*d39a76e7Sxw161283 }
1428*d39a76e7Sxw161283 
1429*d39a76e7Sxw161283 /*
1430*d39a76e7Sxw161283  * Programs the various SGE registers. However, the engine is not yet enabled,
1431*d39a76e7Sxw161283  * but sge->sge_control is setup and ready to go.
1432*d39a76e7Sxw161283  */
1433*d39a76e7Sxw161283 static void
configure_sge(pesge * sge,struct sge_params * p)1434*d39a76e7Sxw161283 configure_sge(pesge *sge, struct sge_params *p)
1435*d39a76e7Sxw161283 {
1436*d39a76e7Sxw161283 	ch_t *ap = sge->obj;
1437*d39a76e7Sxw161283 	int i;
1438*d39a76e7Sxw161283 
1439*d39a76e7Sxw161283 	t1_write_reg_4(ap, A_SG_CONTROL, 0);
1440*d39a76e7Sxw161283 
1441*d39a76e7Sxw161283 	setup_ring_params(ap, sge->cmdQ[0].cq_pa, sge->cmdQ[0].cq_entries_n,
1442*d39a76e7Sxw161283 	    A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
1443*d39a76e7Sxw161283 	setup_ring_params(ap, sge->cmdQ[1].cq_pa, sge->cmdQ[1].cq_entries_n,
1444*d39a76e7Sxw161283 	    A_SG_CMD1BASELWR, A_SG_CMD1BASEUPR, A_SG_CMD1SIZE);
1445*d39a76e7Sxw161283 	setup_ring_params(ap, sge->freelQ[0].fq_pa,
1446*d39a76e7Sxw161283 	    sge->freelQ[0].fq_entries_n, A_SG_FL0BASELWR,
1447*d39a76e7Sxw161283 	    A_SG_FL0BASEUPR, A_SG_FL0SIZE);
1448*d39a76e7Sxw161283 	setup_ring_params(ap, sge->freelQ[1].fq_pa,
1449*d39a76e7Sxw161283 	    sge->freelQ[1].fq_entries_n, A_SG_FL1BASELWR,
1450*d39a76e7Sxw161283 	    A_SG_FL1BASEUPR, A_SG_FL1SIZE);
1451*d39a76e7Sxw161283 
1452*d39a76e7Sxw161283 	/* The threshold comparison uses <. */
1453*d39a76e7Sxw161283 	t1_write_reg_4(ap, A_SG_FLTHRESHOLD, SGE_RX_SM_BUF_SIZE(ap) -
1454*d39a76e7Sxw161283 	    SZ_CPL_RX_PKT - sge->rx_pkt_pad - sge->rx_offset + 1);
1455*d39a76e7Sxw161283 	setup_ring_params(ap, sge->respQ.rq_pa, sge->respQ.rq_entries_n,
1456*d39a76e7Sxw161283 	    A_SG_RSPBASELWR, A_SG_RSPBASEUPR, A_SG_RSPSIZE);
1457*d39a76e7Sxw161283 	t1_write_reg_4(ap, A_SG_RSPQUEUECREDIT, (u32)sge->respQ.rq_entries_n);
1458*d39a76e7Sxw161283 	sge->sge_control = F_CMDQ0_ENABLE | F_CMDQ1_ENABLE | F_FL0_ENABLE |
1459*d39a76e7Sxw161283 	    F_FL1_ENABLE | F_CPL_ENABLE | F_RESPONSE_QUEUE_ENABLE |
1460*d39a76e7Sxw161283 	    V_CMDQ_PRIORITY(2) | F_DISABLE_CMDQ1_GTS | F_ISCSI_COALESCE |
1461*d39a76e7Sxw161283 #if 1
1462*d39a76e7Sxw161283 		/*
1463*d39a76e7Sxw161283 		 * if the the following bit is not set, then we'll get an
1464*d39a76e7Sxw161283 		 * interrupt everytime command Q 0 goes empty. Since we're
1465*d39a76e7Sxw161283 		 * always ringing the doorbell, we can turn it on.
1466*d39a76e7Sxw161283 		 */
1467*d39a76e7Sxw161283 	    F_DISABLE_CMDQ0_GTS |
1468*d39a76e7Sxw161283 #endif
1469*d39a76e7Sxw161283 	    V_RX_PKT_OFFSET(sge->rx_pkt_pad);
1470*d39a76e7Sxw161283 
1471*d39a76e7Sxw161283 #if BYTE_ORDER == BIG_ENDIAN
1472*d39a76e7Sxw161283 	sge->sge_control |= F_ENABLE_BIG_ENDIAN;
1473*d39a76e7Sxw161283 #endif
1474*d39a76e7Sxw161283 
1475*d39a76e7Sxw161283 	/*
1476*d39a76e7Sxw161283 	 * Initialize the SGE Interrupt Timer arrray:
1477*d39a76e7Sxw161283 	 * intrtimer[0] = (SGE_INTRTIMER0) usec
1478*d39a76e7Sxw161283 	 * intrtimer[0<i<10] = (SGE_INTRTIMER0 + 2*i) usec
1479*d39a76e7Sxw161283 	 * intrtimer[10] = (SGE_INTRTIMER1) usec
1480*d39a76e7Sxw161283 	 *
1481*d39a76e7Sxw161283 	 */
1482*d39a76e7Sxw161283 	sge->intrtimer[0] = board_info(sge->obj)->clock_core / 1000000;
1483*d39a76e7Sxw161283 	for (i = 1; i < SGE_INTR_MAXBUCKETS - 1; ++i) {
1484*d39a76e7Sxw161283 		sge->intrtimer[i] = SGE_INTRTIMER0 + (2 * i);
1485*d39a76e7Sxw161283 		sge->intrtimer[i] *= sge->intrtimer[0];
1486*d39a76e7Sxw161283 	}
1487*d39a76e7Sxw161283 	sge->intrtimer[SGE_INTR_MAXBUCKETS - 1] =
1488*d39a76e7Sxw161283 	    sge->intrtimer[0] * SGE_INTRTIMER1;
1489*d39a76e7Sxw161283 	/* Initialize resource timer */
1490*d39a76e7Sxw161283 	sge->intrtimer_nres = (uint32_t)(sge->intrtimer[0] *
1491*d39a76e7Sxw161283 	    SGE_INTRTIMER_NRES);
1492*d39a76e7Sxw161283 	/* Finally finish initialization of intrtimer[0] */
1493*d39a76e7Sxw161283 	sge->intrtimer[0] = (uint32_t)(sge->intrtimer[0] * SGE_INTRTIMER0);
1494*d39a76e7Sxw161283 	/* Initialize for a throughput oriented workload */
1495*d39a76e7Sxw161283 	sge->currIndex = SGE_INTR_MAXBUCKETS - 1;
1496*d39a76e7Sxw161283 
1497*d39a76e7Sxw161283 	if (p->coalesce_enable)
1498*d39a76e7Sxw161283 		t1_write_reg_4(ap, A_SG_INTRTIMER,
1499*d39a76e7Sxw161283 		    sge->intrtimer[sge->currIndex]);
1500*d39a76e7Sxw161283 	else
1501*d39a76e7Sxw161283 		(void) t1_sge_set_coalesce_params(sge, p);
1502*d39a76e7Sxw161283 }
1503*d39a76e7Sxw161283 
1504*d39a76e7Sxw161283 static inline void
setup_ring_params(ch_t * adapter,u64 addr,u32 size,int base_reg_lo,int base_reg_hi,int size_reg)1505*d39a76e7Sxw161283 setup_ring_params(ch_t *adapter, u64 addr, u32 size, int base_reg_lo,
1506*d39a76e7Sxw161283     int base_reg_hi, int size_reg)
1507*d39a76e7Sxw161283 {
1508*d39a76e7Sxw161283 	t1_write_reg_4(adapter, base_reg_lo, (u32)addr);
1509*d39a76e7Sxw161283 	t1_write_reg_4(adapter, base_reg_hi, addr >> 32);
1510*d39a76e7Sxw161283 	t1_write_reg_4(adapter, size_reg, size);
1511*d39a76e7Sxw161283 }
1512*d39a76e7Sxw161283 
1513*d39a76e7Sxw161283 /*
1514*d39a76e7Sxw161283  * Frees RX resources.
1515*d39a76e7Sxw161283  */
1516*d39a76e7Sxw161283 static void
free_rx_resources(pesge * sge)1517*d39a76e7Sxw161283 free_rx_resources(pesge *sge)
1518*d39a76e7Sxw161283 {
1519*d39a76e7Sxw161283 	unsigned int size, i;
1520*d39a76e7Sxw161283 
1521*d39a76e7Sxw161283 	if (sge->respQ.rq_entries) {
1522*d39a76e7Sxw161283 		size = sizeof (respQ_e) * sge->respQ.rq_entries_n;
1523*d39a76e7Sxw161283 
1524*d39a76e7Sxw161283 		pe_os_free_contig(sge->obj, size, sge->respQ.rq_entries,
1525*d39a76e7Sxw161283 		    sge->respQ.rq_pa, sge->respQ.rq_dh, sge->respQ.rq_ah);
1526*d39a76e7Sxw161283 	}
1527*d39a76e7Sxw161283 
1528*d39a76e7Sxw161283 	for (i = 0; i < SGE_FREELQ_N; i++) {
1529*d39a76e7Sxw161283 		struct freelQ *Q = &sge->freelQ[i];
1530*d39a76e7Sxw161283 
1531*d39a76e7Sxw161283 		if (Q->fq_centries) {
1532*d39a76e7Sxw161283 			free_freelQ_buffers(sge, Q);
1533*d39a76e7Sxw161283 
1534*d39a76e7Sxw161283 			t1_os_free(Q->fq_centries,
1535*d39a76e7Sxw161283 			    Q->fq_entries_n * sizeof (freelQ_ce_t));
1536*d39a76e7Sxw161283 		}
1537*d39a76e7Sxw161283 		if (Q->fq_entries) {
1538*d39a76e7Sxw161283 			size = sizeof (freelQ_e) * Q->fq_entries_n;
1539*d39a76e7Sxw161283 
1540*d39a76e7Sxw161283 			/* free the freelist queue */
1541*d39a76e7Sxw161283 			pe_os_free_contig(sge->obj, size, Q->fq_entries,
1542*d39a76e7Sxw161283 			    Q->fq_pa, Q->fq_dh, Q->fq_ah);
1543*d39a76e7Sxw161283 
1544*d39a76e7Sxw161283 		}
1545*d39a76e7Sxw161283 	}
1546*d39a76e7Sxw161283 }
1547*d39a76e7Sxw161283 
1548*d39a76e7Sxw161283 /*
1549*d39a76e7Sxw161283  * Frees all RX buffers on the freelist Q. The caller must make sure that
1550*d39a76e7Sxw161283  * the SGE is turned off before calling this function.
1551*d39a76e7Sxw161283  */
1552*d39a76e7Sxw161283 static void
free_freelQ_buffers(pesge * sge,struct freelQ * Q)1553*d39a76e7Sxw161283 free_freelQ_buffers(pesge *sge, struct freelQ *Q)
1554*d39a76e7Sxw161283 {
1555*d39a76e7Sxw161283 	struct freelQ_ce *ce;
1556*d39a76e7Sxw161283 	struct freelQ_ce *cq = Q->fq_centries;
1557*d39a76e7Sxw161283 	uint32_t credits = Q->fq_credits;
1558*d39a76e7Sxw161283 	uint32_t entries_n = Q->fq_entries_n;
1559*d39a76e7Sxw161283 	uint32_t cidx = Q->fq_cidx;
1560*d39a76e7Sxw161283 	uint32_t i = Q->fq_id;
1561*d39a76e7Sxw161283 
1562*d39a76e7Sxw161283 	ce = &cq[cidx];
1563*d39a76e7Sxw161283 
1564*d39a76e7Sxw161283 	credits = entries_n;
1565*d39a76e7Sxw161283 	while (credits--) {
1566*d39a76e7Sxw161283 		mblk_t *mp;
1567*d39a76e7Sxw161283 		if ((mp = ce->fe_mp) != NULL) {
1568*d39a76e7Sxw161283 			/* bump in-use count of receive buffers */
1569*d39a76e7Sxw161283 			if (i != sge->jumbo_fl) {
1570*d39a76e7Sxw161283 				atomic_add(1,
1571*d39a76e7Sxw161283 				    &buffers_in_use[sge->obj->ch_sm_index]);
1572*d39a76e7Sxw161283 			} else {
1573*d39a76e7Sxw161283 				atomic_add(1,
1574*d39a76e7Sxw161283 				    &buffers_in_use[sge->obj->ch_big_index]);
1575*d39a76e7Sxw161283 			}
1576*d39a76e7Sxw161283 
1577*d39a76e7Sxw161283 			/*
1578*d39a76e7Sxw161283 			 * note. freeb() callback of esb-alloced mblk will
1579*d39a76e7Sxw161283 			 * cause receive buffer to be put back on sa free list.
1580*d39a76e7Sxw161283 			 */
1581*d39a76e7Sxw161283 			freeb(mp);
1582*d39a76e7Sxw161283 			ce->fe_mp = NULL;
1583*d39a76e7Sxw161283 		}
1584*d39a76e7Sxw161283 
1585*d39a76e7Sxw161283 		ce++;
1586*d39a76e7Sxw161283 		if (++cidx == entries_n) {
1587*d39a76e7Sxw161283 			cidx = 0;
1588*d39a76e7Sxw161283 			ce = cq;
1589*d39a76e7Sxw161283 		}
1590*d39a76e7Sxw161283 	}
1591*d39a76e7Sxw161283 
1592*d39a76e7Sxw161283 	Q->fq_cidx = cidx;
1593*d39a76e7Sxw161283 	Q->fq_credits = credits;
1594*d39a76e7Sxw161283 }
1595*d39a76e7Sxw161283 
1596*d39a76e7Sxw161283 /*
1597*d39a76e7Sxw161283  * Free TX resources.
1598*d39a76e7Sxw161283  *
1599*d39a76e7Sxw161283  * Assumes that SGE is stopped and all interrupts are disabled.
1600*d39a76e7Sxw161283  */
1601*d39a76e7Sxw161283 static void
free_tx_resources(pesge * sge)1602*d39a76e7Sxw161283 free_tx_resources(pesge *sge)
1603*d39a76e7Sxw161283 {
1604*d39a76e7Sxw161283 	unsigned int size;
1605*d39a76e7Sxw161283 	uint32_t i;
1606*d39a76e7Sxw161283 
1607*d39a76e7Sxw161283 	for (i = 0; i < SGE_CMDQ_N; i++) {
1608*d39a76e7Sxw161283 		struct cmdQ *Q = &sge->cmdQ[i];
1609*d39a76e7Sxw161283 
1610*d39a76e7Sxw161283 		if (Q->cq_centries) {
1611*d39a76e7Sxw161283 			unsigned int pending = Q->cq_entries_n -
1612*d39a76e7Sxw161283 			    atomic_read(Q->cq_credits);
1613*d39a76e7Sxw161283 
1614*d39a76e7Sxw161283 			mutex_destroy(&Q->cq_qlock);
1615*d39a76e7Sxw161283 
1616*d39a76e7Sxw161283 			if (pending)
1617*d39a76e7Sxw161283 				free_cmdQ_buffers(sge, Q, pending);
1618*d39a76e7Sxw161283 
1619*d39a76e7Sxw161283 			size = sizeof (struct cmdQ_ce) * Q->cq_entries_n;
1620*d39a76e7Sxw161283 			t1_os_free(Q->cq_centries, size);
1621*d39a76e7Sxw161283 		}
1622*d39a76e7Sxw161283 
1623*d39a76e7Sxw161283 		if (Q->cq_entries) {
1624*d39a76e7Sxw161283 			size = sizeof (cmdQ_e) * Q->cq_entries_n;
1625*d39a76e7Sxw161283 			pe_os_free_contig(sge->obj, size, Q->cq_entries,
1626*d39a76e7Sxw161283 			    Q->cq_pa, Q->cq_dh, Q->cq_ah);
1627*d39a76e7Sxw161283 		}
1628*d39a76e7Sxw161283 	}
1629*d39a76e7Sxw161283 }
1630*d39a76e7Sxw161283 
1631*d39a76e7Sxw161283 /*
1632*d39a76e7Sxw161283  * Return the payload capacity of the jumbo free-list buffers.
1633*d39a76e7Sxw161283  */
jumbo_payload_capacity(pesge * sge)1634*d39a76e7Sxw161283 static inline unsigned int jumbo_payload_capacity(pesge *sge)
1635*d39a76e7Sxw161283 {
1636*d39a76e7Sxw161283 	return (sge->freelQ[sge->jumbo_fl].fq_rx_buffer_size -
1637*d39a76e7Sxw161283 	    sizeof (struct cpl_rx_data) - sge->rx_pkt_pad - sge->rx_offset);
1638*d39a76e7Sxw161283 }
1639*d39a76e7Sxw161283 
1640*d39a76e7Sxw161283 /* PR2928 & PR3309 */
1641*d39a76e7Sxw161283 void
t1_sge_set_ptimeout(adapter_t * adapter,u32 val)1642*d39a76e7Sxw161283 t1_sge_set_ptimeout(adapter_t *adapter, u32 val)
1643*d39a76e7Sxw161283 {
1644*d39a76e7Sxw161283 	pesge *sge = adapter->sge;
1645*d39a76e7Sxw161283 
1646*d39a76e7Sxw161283 	if (is_T2(adapter))
1647*d39a76e7Sxw161283 		sge->ptimeout = max(val, 1);
1648*d39a76e7Sxw161283 }
1649*d39a76e7Sxw161283 
1650*d39a76e7Sxw161283 /* PR2928 & PR3309 */
1651*d39a76e7Sxw161283 u32
t1_sge_get_ptimeout(adapter_t * adapter)1652*d39a76e7Sxw161283 t1_sge_get_ptimeout(adapter_t *adapter)
1653*d39a76e7Sxw161283 {
1654*d39a76e7Sxw161283 	pesge *sge = adapter->sge;
1655*d39a76e7Sxw161283 
1656*d39a76e7Sxw161283 	return (is_T2(adapter) ? sge->ptimeout : 0);
1657*d39a76e7Sxw161283 }
1658*d39a76e7Sxw161283 
1659*d39a76e7Sxw161283 void
sge_add_fake_arp(pesge * sge,void * bp)1660*d39a76e7Sxw161283 sge_add_fake_arp(pesge *sge, void *bp)
1661*d39a76e7Sxw161283 {
1662*d39a76e7Sxw161283 	sge->pskb = bp;
1663*d39a76e7Sxw161283 }
1664*d39a76e7Sxw161283 
1665*d39a76e7Sxw161283 #ifdef SUN_KSTATS
1666*d39a76e7Sxw161283 static int
sge_kstat_setup(pesge * sge)1667*d39a76e7Sxw161283 sge_kstat_setup(pesge *sge)
1668*d39a76e7Sxw161283 {
1669*d39a76e7Sxw161283 	int status;
1670*d39a76e7Sxw161283 	p_kstat_t ksp;
1671*d39a76e7Sxw161283 	size_t ch_kstat_sz;
1672*d39a76e7Sxw161283 	p_ch_kstat_t chkp;
1673*d39a76e7Sxw161283 	char kstat_name[32];
1674*d39a76e7Sxw161283 	int instance;
1675*d39a76e7Sxw161283 	int i;
1676*d39a76e7Sxw161283 
1677*d39a76e7Sxw161283 	status = -1;
1678*d39a76e7Sxw161283 	ch_kstat_sz = sizeof (ch_kstat_t);
1679*d39a76e7Sxw161283 	instance = ddi_get_instance(sge->obj->ch_dip);
1680*d39a76e7Sxw161283 	if ((ksp = kstat_create(CHNAME "_debug", instance,
1681*d39a76e7Sxw161283 	    NULL, "net_debug", KSTAT_TYPE_NAMED,
1682*d39a76e7Sxw161283 	    ch_kstat_sz / sizeof (kstat_named_t), 0)) == NULL)
1683*d39a76e7Sxw161283 		goto sge_kstat_setup_exit;
1684*d39a76e7Sxw161283 	chkp = (p_ch_kstat_t)ksp->ks_data;
1685*d39a76e7Sxw161283 	kstat_named_init(&chkp->respQ_empty,		"respQ_empty",
1686*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1687*d39a76e7Sxw161283 	kstat_named_init(&chkp->respQ_overflow,		"respQ_overflow",
1688*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1689*d39a76e7Sxw161283 	kstat_named_init(&chkp->freelistQ_empty,	"freelistQ_empty",
1690*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1691*d39a76e7Sxw161283 	kstat_named_init(&chkp->pkt_too_big,		"pkt_too_big",
1692*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1693*d39a76e7Sxw161283 	kstat_named_init(&chkp->pkt_mismatch,		"pkt_mismatch",
1694*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1695*d39a76e7Sxw161283 	kstat_named_init(&chkp->cmdQ_full[0],		"cmdQ_full[0]",
1696*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1697*d39a76e7Sxw161283 	kstat_named_init(&chkp->cmdQ_full[1],		"cmdQ_full[1]",
1698*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1699*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_reclaims[0],		"tx_reclaims[0]",
1700*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1701*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_reclaims[1],		"tx_reclaims[1]",
1702*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1703*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_msg_pullups,		"tx_msg_pullups",
1704*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1705*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_hdr_pullups,		"tx_hdr_pullups",
1706*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1707*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_tcp_ip_frag,		"tx_tcp_ip_frag",
1708*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1709*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_udp_ip_frag,		"tx_udp_ip_frag",
1710*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1711*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_soft_cksums,		"tx_soft_cksums",
1712*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1713*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_need_cpl_space,	"tx_need_cpl_space",
1714*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1715*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_multi_mblks,		"tx_multi_mblks",
1716*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1717*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_no_dvma1,	"tx_num_multi_dvma_fails",
1718*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1719*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_no_dvma2,	"tx_num_single_dvma_fails",
1720*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1721*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_no_dma1,	"tx_num_multi_dma_fails",
1722*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1723*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_no_dma2,	"tx_num_single_dma_fails",
1724*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1725*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_cmdq0,		"rx_cmdq0",
1726*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1727*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_cmdq1,		"rx_cmdq1",
1728*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1729*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flq0,		"rx_flq0",
1730*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1731*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flq1,		"rx_flq1",
1732*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1733*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flq0_sz,		"rx_flq0_buffer_sz",
1734*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1735*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flq1_sz,		"rx_flq1_buffer_sz",
1736*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1737*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_pkt_drops,		"rx_pkt_drops",
1738*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1739*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_pkt_copied,		"rx_pkt_copied",
1740*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1741*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_pause_on,		"rx_pause_on",
1742*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1743*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_pause_off,		"rx_pause_off",
1744*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1745*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_pause_ms,		"rx_pause_ms",
1746*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1747*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_pause_spike,		"rx_pause_spike",
1748*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1749*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_fl_credits,		"rx_fl_credits",
1750*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1751*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flbuf_fails,		"rx_flbuf_fails",
1752*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1753*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flbuf_allocs,	"rx_flbuf_allocs",
1754*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1755*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_badEopSop,		"rx_badEopSop",
1756*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1757*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flq0_cnt,		"rx_flq0_cnt",
1758*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1759*d39a76e7Sxw161283 	kstat_named_init(&chkp->rx_flq1_cnt,		"rx_flq1_cnt",
1760*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1761*d39a76e7Sxw161283 	kstat_named_init(&chkp->arp_sent,		"arp_sent",
1762*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1763*d39a76e7Sxw161283 	kstat_named_init(&chkp->tx_doorbells,		"tx_doorbells",
1764*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1765*d39a76e7Sxw161283 	kstat_named_init(&chkp->intr_doorbells,		"intr_doorbells",
1766*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1767*d39a76e7Sxw161283 	kstat_named_init(&chkp->intr1_doorbells,	"intr1_doorbells",
1768*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1769*d39a76e7Sxw161283 	kstat_named_init(&chkp->sleep_cnt,		"sleep_cnt",
1770*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1771*d39a76e7Sxw161283 	kstat_named_init(&chkp->pe_allocb_cnt,		"pe_allocb_cnt",
1772*d39a76e7Sxw161283 	    KSTAT_DATA_UINT32);
1773*d39a76e7Sxw161283 	for (i = 0; i < MBLK_MAX; i++) {
1774*d39a76e7Sxw161283 		(void) sprintf(kstat_name, "tx_descs[%02d]", i);
1775*d39a76e7Sxw161283 		kstat_named_init(&chkp->tx_descs[i],
1776*d39a76e7Sxw161283 		    kstat_name, KSTAT_DATA_UINT32);
1777*d39a76e7Sxw161283 	}
1778*d39a76e7Sxw161283 	ksp->ks_update = sge_kstat_update;
1779*d39a76e7Sxw161283 	ksp->ks_private = (void *)sge;
1780*d39a76e7Sxw161283 	sge->ksp = ksp;
1781*d39a76e7Sxw161283 	kstat_install(ksp);
1782*d39a76e7Sxw161283 	status = 0;
1783*d39a76e7Sxw161283 
1784*d39a76e7Sxw161283 sge_kstat_setup_exit:
1785*d39a76e7Sxw161283 	return (status);
1786*d39a76e7Sxw161283 }
1787*d39a76e7Sxw161283 
1788*d39a76e7Sxw161283 static void
sge_kstat_remove(pesge * sge)1789*d39a76e7Sxw161283 sge_kstat_remove(pesge *sge)
1790*d39a76e7Sxw161283 {
1791*d39a76e7Sxw161283 	if (sge->ksp)
1792*d39a76e7Sxw161283 		kstat_delete(sge->ksp);
1793*d39a76e7Sxw161283 }
1794*d39a76e7Sxw161283 
1795*d39a76e7Sxw161283 static int
sge_kstat_update(p_kstat_t ksp,int rw)1796*d39a76e7Sxw161283 sge_kstat_update(p_kstat_t ksp, int rw)
1797*d39a76e7Sxw161283 {
1798*d39a76e7Sxw161283 	pesge *sge;
1799*d39a76e7Sxw161283 	p_ch_stats_t statsp;
1800*d39a76e7Sxw161283 	p_ch_kstat_t chkp;
1801*d39a76e7Sxw161283 	int i;
1802*d39a76e7Sxw161283 
1803*d39a76e7Sxw161283 	sge = (pesge *)ksp->ks_private;
1804*d39a76e7Sxw161283 	statsp = (p_ch_stats_t)&sge->intr_cnt;
1805*d39a76e7Sxw161283 	chkp = (p_ch_kstat_t)ksp->ks_data;
1806*d39a76e7Sxw161283 	if (rw == KSTAT_WRITE) {
1807*d39a76e7Sxw161283 		statsp->respQ_empty	= chkp->respQ_empty.value.ui32;
1808*d39a76e7Sxw161283 		statsp->respQ_overflow	= chkp->respQ_overflow.value.ui32;
1809*d39a76e7Sxw161283 		statsp->freelistQ_empty	= chkp->freelistQ_empty.value.ui32;
1810*d39a76e7Sxw161283 		statsp->pkt_too_big	= chkp->pkt_too_big.value.ui32;
1811*d39a76e7Sxw161283 		statsp->pkt_mismatch	= chkp->pkt_mismatch.value.ui32;
1812*d39a76e7Sxw161283 		statsp->cmdQ_full[0]	= chkp->cmdQ_full[0].value.ui32;
1813*d39a76e7Sxw161283 		statsp->cmdQ_full[1]	= chkp->cmdQ_full[1].value.ui32;
1814*d39a76e7Sxw161283 		statsp->tx_reclaims[0]	= chkp->tx_reclaims[0].value.ui32;
1815*d39a76e7Sxw161283 		statsp->tx_reclaims[1]	= chkp->tx_reclaims[1].value.ui32;
1816*d39a76e7Sxw161283 		statsp->tx_msg_pullups	= chkp->tx_msg_pullups.value.ui32;
1817*d39a76e7Sxw161283 		statsp->tx_hdr_pullups	= chkp->tx_hdr_pullups.value.ui32;
1818*d39a76e7Sxw161283 		statsp->tx_tcp_ip_frag	= chkp->tx_tcp_ip_frag.value.ui32;
1819*d39a76e7Sxw161283 		statsp->tx_udp_ip_frag	= chkp->tx_udp_ip_frag.value.ui32;
1820*d39a76e7Sxw161283 		statsp->tx_soft_cksums	= chkp->tx_soft_cksums.value.ui32;
1821*d39a76e7Sxw161283 		statsp->tx_need_cpl_space
1822*d39a76e7Sxw161283 		    = chkp->tx_need_cpl_space.value.ui32;
1823*d39a76e7Sxw161283 		statsp->tx_multi_mblks	= chkp->tx_multi_mblks.value.ui32;
1824*d39a76e7Sxw161283 		statsp->tx_no_dvma1	= chkp->tx_no_dvma1.value.ui32;
1825*d39a76e7Sxw161283 		statsp->tx_no_dvma2	= chkp->tx_no_dvma2.value.ui32;
1826*d39a76e7Sxw161283 		statsp->tx_no_dma1	= chkp->tx_no_dma1.value.ui32;
1827*d39a76e7Sxw161283 		statsp->tx_no_dma2	= chkp->tx_no_dma2.value.ui32;
1828*d39a76e7Sxw161283 		statsp->rx_cmdq0	= chkp->rx_cmdq0.value.ui32;
1829*d39a76e7Sxw161283 		statsp->rx_cmdq1	= chkp->rx_cmdq1.value.ui32;
1830*d39a76e7Sxw161283 		statsp->rx_flq0		= chkp->rx_flq0.value.ui32;
1831*d39a76e7Sxw161283 		statsp->rx_flq1		= chkp->rx_flq1.value.ui32;
1832*d39a76e7Sxw161283 		statsp->rx_flq0_sz	= chkp->rx_flq0_sz.value.ui32;
1833*d39a76e7Sxw161283 		statsp->rx_flq1_sz	= chkp->rx_flq1_sz.value.ui32;
1834*d39a76e7Sxw161283 		statsp->rx_pkt_drops	= chkp->rx_pkt_drops.value.ui32;
1835*d39a76e7Sxw161283 		statsp->rx_pkt_copied	= chkp->rx_pkt_copied.value.ui32;
1836*d39a76e7Sxw161283 		statsp->rx_pause_on	= chkp->rx_pause_on.value.ui32;
1837*d39a76e7Sxw161283 		statsp->rx_pause_off	= chkp->rx_pause_off.value.ui32;
1838*d39a76e7Sxw161283 		statsp->rx_pause_ms	= chkp->rx_pause_ms.value.ui32;
1839*d39a76e7Sxw161283 		statsp->rx_pause_spike	= chkp->rx_pause_spike.value.ui32;
1840*d39a76e7Sxw161283 		statsp->rx_fl_credits	= chkp->rx_fl_credits.value.ui32;
1841*d39a76e7Sxw161283 		statsp->rx_flbuf_fails	= chkp->rx_flbuf_fails.value.ui32;
1842*d39a76e7Sxw161283 		statsp->rx_flbuf_allocs	= chkp->rx_flbuf_allocs.value.ui32;
1843*d39a76e7Sxw161283 		statsp->rx_badEopSop	= chkp->rx_badEopSop.value.ui32;
1844*d39a76e7Sxw161283 		statsp->rx_flq0_cnt	= chkp->rx_flq0_cnt.value.ui32;
1845*d39a76e7Sxw161283 		statsp->rx_flq1_cnt	= chkp->rx_flq1_cnt.value.ui32;
1846*d39a76e7Sxw161283 		statsp->arp_sent	= chkp->arp_sent.value.ui32;
1847*d39a76e7Sxw161283 		statsp->tx_doorbells	= chkp->tx_doorbells.value.ui32;
1848*d39a76e7Sxw161283 		statsp->intr_doorbells	= chkp->intr_doorbells.value.ui32;
1849*d39a76e7Sxw161283 		statsp->intr1_doorbells = chkp->intr1_doorbells.value.ui32;
1850*d39a76e7Sxw161283 		statsp->sleep_cnt	= chkp->sleep_cnt.value.ui32;
1851*d39a76e7Sxw161283 		statsp->pe_allocb_cnt	= chkp->pe_allocb_cnt.value.ui32;
1852*d39a76e7Sxw161283 		for (i = 0; i < MBLK_MAX; i++) {
1853*d39a76e7Sxw161283 			statsp->tx_descs[i] = chkp->tx_descs[i].value.ui32;
1854*d39a76e7Sxw161283 		}
1855*d39a76e7Sxw161283 	} else {
1856*d39a76e7Sxw161283 		chkp->respQ_empty.value.ui32	= statsp->respQ_empty;
1857*d39a76e7Sxw161283 		chkp->respQ_overflow.value.ui32	= statsp->respQ_overflow;
1858*d39a76e7Sxw161283 		chkp->freelistQ_empty.value.ui32
1859*d39a76e7Sxw161283 		    = statsp->freelistQ_empty;
1860*d39a76e7Sxw161283 		chkp->pkt_too_big.value.ui32	= statsp->pkt_too_big;
1861*d39a76e7Sxw161283 		chkp->pkt_mismatch.value.ui32	= statsp->pkt_mismatch;
1862*d39a76e7Sxw161283 		chkp->cmdQ_full[0].value.ui32	= statsp->cmdQ_full[0];
1863*d39a76e7Sxw161283 		chkp->cmdQ_full[1].value.ui32	= statsp->cmdQ_full[1];
1864*d39a76e7Sxw161283 		chkp->tx_reclaims[0].value.ui32	= statsp->tx_reclaims[0];
1865*d39a76e7Sxw161283 		chkp->tx_reclaims[1].value.ui32	= statsp->tx_reclaims[1];
1866*d39a76e7Sxw161283 		chkp->tx_msg_pullups.value.ui32	= statsp->tx_msg_pullups;
1867*d39a76e7Sxw161283 		chkp->tx_hdr_pullups.value.ui32	= statsp->tx_hdr_pullups;
1868*d39a76e7Sxw161283 		chkp->tx_tcp_ip_frag.value.ui32	= statsp->tx_tcp_ip_frag;
1869*d39a76e7Sxw161283 		chkp->tx_udp_ip_frag.value.ui32	= statsp->tx_udp_ip_frag;
1870*d39a76e7Sxw161283 		chkp->tx_soft_cksums.value.ui32	= statsp->tx_soft_cksums;
1871*d39a76e7Sxw161283 		chkp->tx_need_cpl_space.value.ui32
1872*d39a76e7Sxw161283 		    = statsp->tx_need_cpl_space;
1873*d39a76e7Sxw161283 		chkp->tx_multi_mblks.value.ui32	= statsp->tx_multi_mblks;
1874*d39a76e7Sxw161283 		chkp->tx_no_dvma1.value.ui32	= statsp->tx_no_dvma1;
1875*d39a76e7Sxw161283 		chkp->tx_no_dvma2.value.ui32	= statsp->tx_no_dvma2;
1876*d39a76e7Sxw161283 		chkp->tx_no_dma1.value.ui32	= statsp->tx_no_dma1;
1877*d39a76e7Sxw161283 		chkp->tx_no_dma2.value.ui32	= statsp->tx_no_dma2;
1878*d39a76e7Sxw161283 		chkp->rx_cmdq0.value.ui32	= statsp->rx_cmdq0;
1879*d39a76e7Sxw161283 		chkp->rx_cmdq1.value.ui32	= statsp->rx_cmdq1;
1880*d39a76e7Sxw161283 		chkp->rx_flq0.value.ui32	= statsp->rx_flq0;
1881*d39a76e7Sxw161283 		chkp->rx_flq1.value.ui32	= statsp->rx_flq1;
1882*d39a76e7Sxw161283 		chkp->rx_flq0_sz.value.ui32	= statsp->rx_flq0_sz;
1883*d39a76e7Sxw161283 		chkp->rx_flq1_sz.value.ui32	= statsp->rx_flq1_sz;
1884*d39a76e7Sxw161283 		chkp->rx_pkt_drops.value.ui32	= statsp->rx_pkt_drops;
1885*d39a76e7Sxw161283 		chkp->rx_pkt_copied.value.ui32	= statsp->rx_pkt_copied;
1886*d39a76e7Sxw161283 		chkp->rx_pause_on.value.ui32	= statsp->rx_pause_on;
1887*d39a76e7Sxw161283 		chkp->rx_pause_off.value.ui32	= statsp->rx_pause_off;
1888*d39a76e7Sxw161283 		chkp->rx_pause_ms.value.ui32	= statsp->rx_pause_ms;
1889*d39a76e7Sxw161283 		chkp->rx_pause_spike.value.ui32	= statsp->rx_pause_spike;
1890*d39a76e7Sxw161283 		chkp->rx_fl_credits.value.ui32	= statsp->rx_fl_credits;
1891*d39a76e7Sxw161283 		chkp->rx_flbuf_fails.value.ui32
1892*d39a76e7Sxw161283 		    = statsp->rx_flbuf_fails;
1893*d39a76e7Sxw161283 		chkp->rx_flbuf_allocs.value.ui32
1894*d39a76e7Sxw161283 		    = statsp->rx_flbuf_allocs;
1895*d39a76e7Sxw161283 		chkp->rx_badEopSop.value.ui32	= statsp->rx_badEopSop;
1896*d39a76e7Sxw161283 		chkp->rx_flq0_cnt.value.ui32	= statsp->rx_flq0_cnt;
1897*d39a76e7Sxw161283 		chkp->rx_flq1_cnt.value.ui32	= statsp->rx_flq1_cnt;
1898*d39a76e7Sxw161283 		chkp->arp_sent.value.ui32	= statsp->arp_sent;
1899*d39a76e7Sxw161283 		chkp->tx_doorbells.value.ui32	= statsp->tx_doorbells;
1900*d39a76e7Sxw161283 		chkp->intr_doorbells.value.ui32	= statsp->intr_doorbells;
1901*d39a76e7Sxw161283 		chkp->intr1_doorbells.value.ui32
1902*d39a76e7Sxw161283 		    = statsp->intr1_doorbells;
1903*d39a76e7Sxw161283 		chkp->sleep_cnt.value.ui32	= statsp->sleep_cnt;
1904*d39a76e7Sxw161283 		chkp->pe_allocb_cnt.value.ui32	= statsp->pe_allocb_cnt;
1905*d39a76e7Sxw161283 		for (i = 0; i < MBLK_MAX; i++) {
1906*d39a76e7Sxw161283 			chkp->tx_descs[i].value.ui32 = statsp->tx_descs[i];
1907*d39a76e7Sxw161283 		}
1908*d39a76e7Sxw161283 	}
1909*d39a76e7Sxw161283 	return (0);
1910*d39a76e7Sxw161283 }
1911*d39a76e7Sxw161283 #endif
1912*d39a76e7Sxw161283 
1913*d39a76e7Sxw161283 static uint16_t
calc_ocsum(mblk_t * mp,int offset)1914*d39a76e7Sxw161283 calc_ocsum(mblk_t *mp, int offset)
1915*d39a76e7Sxw161283 {
1916*d39a76e7Sxw161283 	uint8_t *addrp;
1917*d39a76e7Sxw161283 	uint32_t src;
1918*d39a76e7Sxw161283 	uint32_t dst;
1919*d39a76e7Sxw161283 
1920*d39a76e7Sxw161283 	ipha_t *ihdr = (ipha_t *)(mp->b_rptr + offset);
1921*d39a76e7Sxw161283 	uint32_t sum;
1922*d39a76e7Sxw161283 	int iplen = IPH_HDR_LENGTH(ihdr);
1923*d39a76e7Sxw161283 	struct udphdr *udpp = (struct udphdr *)(mp->b_rptr + offset + iplen);
1924*d39a76e7Sxw161283 	uchar_t *byte;
1925*d39a76e7Sxw161283 	int len;
1926*d39a76e7Sxw161283 
1927*d39a76e7Sxw161283 	addrp = (uint8_t *)&ihdr->ipha_src;
1928*d39a76e7Sxw161283 	src =  ((uint32_t)(addrp[0]) << 24) | ((uint32_t)(addrp[1]) << 16) |
1929*d39a76e7Sxw161283 	    ((uint32_t)(addrp[2]) << 8) | (uint32_t)(addrp[3]);
1930*d39a76e7Sxw161283 
1931*d39a76e7Sxw161283 	addrp = (uint8_t *)&ihdr->ipha_dst;
1932*d39a76e7Sxw161283 	dst =  ((uint32_t)(addrp[0]) << 24) | ((uint32_t)(addrp[1]) << 16) |
1933*d39a76e7Sxw161283 	    ((uint32_t)(addrp[2]) << 8) | (uint32_t)(addrp[3]);
1934*d39a76e7Sxw161283 
1935*d39a76e7Sxw161283 	sum = (uint16_t)(src >> 16) +
1936*d39a76e7Sxw161283 	    (uint16_t)(src) +
1937*d39a76e7Sxw161283 	    (uint16_t)(dst >> 16) +
1938*d39a76e7Sxw161283 	    (uint16_t)(dst) + (udpp->uh_ulen + htons(IPPROTO_UDP));
1939*d39a76e7Sxw161283 
1940*d39a76e7Sxw161283 	sum = (uint16_t)(sum >> 16) + (uint16_t)(sum);
1941*d39a76e7Sxw161283 
1942*d39a76e7Sxw161283 	if (sum > 0xffff)
1943*d39a76e7Sxw161283 		sum -= 0xffff;
1944*d39a76e7Sxw161283 
1945*d39a76e7Sxw161283 	udpp->uh_sum = 0;
1946*d39a76e7Sxw161283 	byte = mp->b_rptr + offset + iplen;
1947*d39a76e7Sxw161283 	do {
1948*d39a76e7Sxw161283 		len = (mp->b_wptr - byte);
1949*d39a76e7Sxw161283 		sum = bcksum(byte, len, sum);
1950*d39a76e7Sxw161283 		if (sum > 0xffff)
1951*d39a76e7Sxw161283 			sum -= 0xffff;
1952*d39a76e7Sxw161283 		mp = mp->b_cont;
1953*d39a76e7Sxw161283 		if (mp)
1954*d39a76e7Sxw161283 			byte = mp->b_rptr;
1955*d39a76e7Sxw161283 	} while (mp);
1956*d39a76e7Sxw161283 
1957*d39a76e7Sxw161283 	sum = ~sum & 0xffff;
1958*d39a76e7Sxw161283 
1959*d39a76e7Sxw161283 	return (sum);
1960*d39a76e7Sxw161283 }
1961