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