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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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