xref: /illumos-gate/usr/src/uts/common/io/chxge/pe.c (revision 4e2c3273)
1d39a76e7Sxw /*
2d39a76e7Sxw  * CDDL HEADER START
3d39a76e7Sxw  *
4d39a76e7Sxw  * The contents of this file are subject to the terms of the
5d39a76e7Sxw  * Common Development and Distribution License (the "License").
6d39a76e7Sxw  * You may not use this file except in compliance with the License.
7d39a76e7Sxw  *
8d39a76e7Sxw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw  * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw  * See the License for the specific language governing permissions
11d39a76e7Sxw  * and limitations under the License.
12d39a76e7Sxw  *
13d39a76e7Sxw  * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw  * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw  * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw  * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw  *
19d39a76e7Sxw  * CDDL HEADER END
20d39a76e7Sxw  */
21d39a76e7Sxw 
22d39a76e7Sxw /*
23d39a76e7Sxw  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24d39a76e7Sxw  * Use is subject to license terms.
25d39a76e7Sxw  */
26d39a76e7Sxw 
27d39a76e7Sxw /*
28d39a76e7Sxw  * This file is part of the Chelsio T1 Ethernet driver.
29d39a76e7Sxw  *
30d39a76e7Sxw  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
31d39a76e7Sxw  */
32d39a76e7Sxw 
33d39a76e7Sxw /*
34d39a76e7Sxw  * Solaris Multithreaded STREAMS Chelsio PCI Ethernet Driver.
35d39a76e7Sxw  * Interface code
36d39a76e7Sxw  */
37d39a76e7Sxw 
38d39a76e7Sxw #include <sys/types.h>
39d39a76e7Sxw #include <sys/systm.h>
40d39a76e7Sxw #include <sys/cmn_err.h>
41d39a76e7Sxw #include <sys/ddi.h>
42d39a76e7Sxw #include <sys/sunddi.h>
43d39a76e7Sxw #include <sys/byteorder.h>
44d39a76e7Sxw #include <sys/atomic.h>
45d39a76e7Sxw #include <sys/ethernet.h>
46d39a76e7Sxw #if PE_PROFILING_ENABLED
47d39a76e7Sxw #include <sys/time.h>
48d39a76e7Sxw #endif
49d39a76e7Sxw #include <sys/gld.h>
50d39a76e7Sxw #include "ostypes.h"
51d39a76e7Sxw #include "common.h"
52d39a76e7Sxw #include "oschtoe.h"
53d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_1G
54d39a76e7Sxw #include "fpga_defs.h"
55d39a76e7Sxw #endif
56d39a76e7Sxw #include "regs.h"
57d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
58d39a76e7Sxw #include "mc3.h"
59d39a76e7Sxw #include "mc4.h"
60d39a76e7Sxw #endif
61d39a76e7Sxw #include "sge.h"
62d39a76e7Sxw #include "tp.h"
63d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
64d39a76e7Sxw #include "ulp.h"
65d39a76e7Sxw #endif
66d39a76e7Sxw #include "espi.h"
67d39a76e7Sxw #include "elmer0.h"
68d39a76e7Sxw #include "gmac.h"
69d39a76e7Sxw #include "cphy.h"
70d39a76e7Sxw #include "suni1x10gexp_regs.h"
71d39a76e7Sxw #include "ch.h"
72d39a76e7Sxw 
73d39a76e7Sxw #define	MLEN(mp) ((mp)->b_wptr - (mp)->b_rptr)
74d39a76e7Sxw 
75d39a76e7Sxw extern uint32_t buffers_in_use[];
76d39a76e7Sxw extern kmutex_t in_use_l;
77d39a76e7Sxw extern uint32_t in_use_index;
78d39a76e7Sxw 
79d39a76e7Sxw static void link_start(ch_t *sa, struct pe_port_t *pp);
80d39a76e7Sxw static ch_esb_t *ch_alloc_small_esbbuf(ch_t *sa, uint32_t i);
81d39a76e7Sxw static ch_esb_t *ch_alloc_big_esbbuf(ch_t *sa, uint32_t i);
82d39a76e7Sxw void ch_big_rbuf_recycle(ch_esb_t *rbp);
83d39a76e7Sxw void ch_small_rbuf_recycle(ch_esb_t *rbp);
84d39a76e7Sxw static const struct board_info *pe_sa_init(ch_t *sa);
85d39a76e7Sxw static int ch_set_config_data(ch_t *chp);
86d39a76e7Sxw void pe_rbuf_pool_free(ch_t *chp);
87d39a76e7Sxw static void pe_free_driver_resources(ch_t *sa);
88d39a76e7Sxw static void update_mtu_tab(ch_t *adapter);
89d39a76e7Sxw static int pe_change_mtu(ch_t *chp);
90d39a76e7Sxw 
91d39a76e7Sxw /*
92d39a76e7Sxw  * CPL5 Defines (from netinet/cpl5_commands.h)
93d39a76e7Sxw  */
94d39a76e7Sxw #define	FLITSTOBYTES	8
95d39a76e7Sxw 
96d39a76e7Sxw #define	CPL_FORMAT_0_SIZE 8
97d39a76e7Sxw #define	CPL_FORMAT_1_SIZE 16
98d39a76e7Sxw #define	CPL_FORMAT_2_SIZE 24
99d39a76e7Sxw #define	CPL_FORMAT_3_SIZE 32
100d39a76e7Sxw #define	CPL_FORMAT_4_SIZE 40
101d39a76e7Sxw #define	CPL_FORMAT_5_SIZE 48
102d39a76e7Sxw 
103d39a76e7Sxw #define	TID_MASK 0xffffff
104d39a76e7Sxw 
105d39a76e7Sxw #define	PE_LINK_SPEED_AUTONEG	5
106d39a76e7Sxw 
107d39a76e7Sxw static int pe_small_rbuf_pool_init(ch_t *sa);
108d39a76e7Sxw static int pe_big_rbuf_pool_init(ch_t *sa);
109d39a76e7Sxw static int pe_make_fake_arp(ch_t *chp, unsigned char *arpp);
110d39a76e7Sxw static uint32_t pe_get_ip(unsigned char *arpp);
111d39a76e7Sxw 
112d39a76e7Sxw /*
113d39a76e7Sxw  * May be set in /etc/system to 0 to use default latency timer for 10G.
114d39a76e7Sxw  * See PCI register 0xc definition.
115d39a76e7Sxw  */
116d39a76e7Sxw int enable_latency_timer = 1;
117d39a76e7Sxw 
118d39a76e7Sxw /*
119d39a76e7Sxw  * May be set in /etc/system to 0 to disable hardware checksum for
120d39a76e7Sxw  * TCP and UDP.
121d39a76e7Sxw  */
122d39a76e7Sxw int enable_checksum_offload = 1;
123d39a76e7Sxw 
124d39a76e7Sxw /*
125d39a76e7Sxw  * Multiplier for freelist pool.
126d39a76e7Sxw  */
127d39a76e7Sxw int fl_sz_multiplier = 6;
128d39a76e7Sxw 
129d39a76e7Sxw uint_t
pe_intr(ch_t * sa)130d39a76e7Sxw pe_intr(ch_t *sa)
131d39a76e7Sxw {
132d39a76e7Sxw 	mutex_enter(&sa->ch_intr);
133d39a76e7Sxw 
134d39a76e7Sxw 	if (sge_data_in(sa->sge)) {
135d39a76e7Sxw 		sa->isr_intr++;
136d39a76e7Sxw 		mutex_exit(&sa->ch_intr);
137d39a76e7Sxw 		return (DDI_INTR_CLAIMED);
138d39a76e7Sxw 	}
139d39a76e7Sxw 
140d39a76e7Sxw 	mutex_exit(&sa->ch_intr);
141d39a76e7Sxw 
142d39a76e7Sxw 	return (DDI_INTR_UNCLAIMED);
143d39a76e7Sxw }
144d39a76e7Sxw 
145d39a76e7Sxw /*
146d39a76e7Sxw  * Each setup struct will call this function to
147d39a76e7Sxw  * initialize.
148d39a76e7Sxw  */
149d39a76e7Sxw void
pe_init(void * xsa)150d39a76e7Sxw pe_init(void* xsa)
151d39a76e7Sxw {
152d39a76e7Sxw 	ch_t *sa = NULL;
153d39a76e7Sxw 	int i = 0;
154d39a76e7Sxw 
155d39a76e7Sxw 	sa = (ch_t *)xsa;
156d39a76e7Sxw 
157d39a76e7Sxw 	/*
158d39a76e7Sxw 	 * Need to count the number of times this routine is called
159d39a76e7Sxw 	 * because we only want the resources to be allocated once.
160d39a76e7Sxw 	 * The 7500 has four ports and so this routine can be called
161d39a76e7Sxw 	 * once for each port.
162d39a76e7Sxw 	 */
163d39a76e7Sxw 	if (sa->init_counter == 0) {
164d39a76e7Sxw 		for_each_port(sa, i) {
165d39a76e7Sxw 
166d39a76e7Sxw 			/*
167d39a76e7Sxw 			 * We only want to initialize the line if it is down.
168d39a76e7Sxw 			 */
169d39a76e7Sxw 			if (sa->port[i].line_up == 0) {
170d39a76e7Sxw 				link_start(sa, &sa->port[i]);
171d39a76e7Sxw 				sa->port[i].line_up = 1;
172d39a76e7Sxw 			}
173d39a76e7Sxw 		}
174d39a76e7Sxw 
175d39a76e7Sxw 		(void) t1_init_hw_modules(sa);
176d39a76e7Sxw 
177d39a76e7Sxw 		/*
178d39a76e7Sxw 		 * Enable/Disable checksum offloading.
179d39a76e7Sxw 		 */
180d39a76e7Sxw 		if (sa->ch_config.cksum_enabled) {
181d39a76e7Sxw 			if (sa->config_data.offload_ip_cksum) {
182d39a76e7Sxw 				/* Notify that HW will do the checksum. */
183d39a76e7Sxw 				t1_tp_set_ip_checksum_offload(sa->tp, 1);
184d39a76e7Sxw 			}
185d39a76e7Sxw 
186d39a76e7Sxw 			if (sa->config_data.offload_tcp_cksum) {
187d39a76e7Sxw 				/* Notify that HW will do the checksum. */
188d39a76e7Sxw 				t1_tp_set_tcp_checksum_offload(sa->tp, 1);
189d39a76e7Sxw 			}
190d39a76e7Sxw 
191d39a76e7Sxw 			if (sa->config_data.offload_udp_cksum) {
192d39a76e7Sxw 				/* Notify that HW will do the checksum. */
193d39a76e7Sxw 				t1_tp_set_udp_checksum_offload(sa->tp, 1);
194d39a76e7Sxw 			}
195d39a76e7Sxw 		}
196d39a76e7Sxw 
197d39a76e7Sxw 		sa->ch_flags |= PEINITDONE;
198d39a76e7Sxw 
199d39a76e7Sxw 		sa->init_counter++;
200d39a76e7Sxw 	}
201d39a76e7Sxw 
202d39a76e7Sxw 	/*
203d39a76e7Sxw 	 * Enable interrupts after starting the SGE so
204d39a76e7Sxw 	 * that the SGE is ready to handle interrupts.
205d39a76e7Sxw 	 */
206d39a76e7Sxw 	(void) sge_start(sa->sge);
207d39a76e7Sxw 	t1_interrupts_enable(sa);
208d39a76e7Sxw 
209d39a76e7Sxw 	/*
210d39a76e7Sxw 	 * set mtu (either 1500 or bigger)
211d39a76e7Sxw 	 */
212d39a76e7Sxw 	(void) pe_change_mtu(sa);
213d39a76e7Sxw #ifdef HOST_PAUSE
214d39a76e7Sxw 	/*
215d39a76e7Sxw 	 * get the configured value of the MAC.
216d39a76e7Sxw 	 */
217d39a76e7Sxw 	(void) t1_tpi_read(sa, SUNI1x10GEXP_REG_TXXG_CONFIG_1 << 2,
218d39a76e7Sxw 	    &sa->txxg_cfg1);
219d39a76e7Sxw #endif
220d39a76e7Sxw }
221d39a76e7Sxw 
222d39a76e7Sxw /* ARGSUSED */
223d39a76e7Sxw static void
link_start(ch_t * sa,struct pe_port_t * p)224d39a76e7Sxw link_start(ch_t *sa, struct pe_port_t *p)
225d39a76e7Sxw {
226d39a76e7Sxw 	struct cmac *mac = p->mac;
227d39a76e7Sxw 
228d39a76e7Sxw 	mac->ops->reset(mac);
229d39a76e7Sxw 	if (mac->ops->macaddress_set)
230d39a76e7Sxw 		mac->ops->macaddress_set(mac, p->enaddr);
231d39a76e7Sxw 	(void) t1_link_start(p->phy, mac, &p->link_config);
232d39a76e7Sxw 	mac->ops->enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
233d39a76e7Sxw }
234d39a76e7Sxw 
235d39a76e7Sxw /*
236d39a76e7Sxw  * turn off interrupts...
237d39a76e7Sxw  */
238d39a76e7Sxw void
pe_stop(ch_t * sa)239d39a76e7Sxw pe_stop(ch_t *sa)
240d39a76e7Sxw {
241d39a76e7Sxw 	t1_interrupts_disable(sa);
242d39a76e7Sxw 	(void) sge_stop(sa->sge);
243d39a76e7Sxw 
244d39a76e7Sxw 	/*
245d39a76e7Sxw 	 * we can still be running an interrupt thread in sge_data_in().
246d39a76e7Sxw 	 * If we are, we'll block on the ch_intr lock
247d39a76e7Sxw 	 */
248d39a76e7Sxw 	mutex_enter(&sa->ch_intr);
249d39a76e7Sxw 	mutex_exit(&sa->ch_intr);
250d39a76e7Sxw }
251d39a76e7Sxw 
252d39a76e7Sxw /*
253d39a76e7Sxw  * output mblk to SGE level and out to the wire.
254d39a76e7Sxw  */
255d39a76e7Sxw 
256d39a76e7Sxw int
pe_start(ch_t * sa,mblk_t * mp,uint32_t flg)257d39a76e7Sxw pe_start(ch_t *sa, mblk_t *mp, uint32_t flg)
258d39a76e7Sxw {
259d39a76e7Sxw 	mblk_t *m0 = mp;
260d39a76e7Sxw 	cmdQ_ce_t cm[16];
261d39a76e7Sxw 	cmdQ_ce_t *cmp;
262d39a76e7Sxw 	cmdQ_ce_t *hmp = &cm[0]; /* head of cm table (may be kmem_alloed) */
263d39a76e7Sxw 	int cm_flg = 0;		/* flag (1 - if kmem-alloced) */
264d39a76e7Sxw 	int nseg = 0;		/* number cmdQ_ce entries created */
265d39a76e7Sxw 	int mseg = 16;		/* maximum entries in hmp arrary */
266d39a76e7Sxw 	int freeme = 0;		/* we have an mblk to free in case of error */
267d39a76e7Sxw 	uint32_t ch_bind_dma_handle(ch_t *, int, caddr_t, cmdQ_ce_t *,
268d39a76e7Sxw 	    uint32_t);
269d39a76e7Sxw #if defined(__sparc)
270d39a76e7Sxw 	uint32_t ch_bind_dvma_handle(ch_t *, int, caddr_t, cmdQ_ce_t *,
271d39a76e7Sxw 	    uint32_t);
272d39a76e7Sxw #endif
273d39a76e7Sxw 	int rv;			/* return value on error */
274d39a76e7Sxw 
275d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
276d39a76e7Sxw 	if (flg & CH_OFFLOAD) {
277d39a76e7Sxw 		hmp->ce_pa = ((tbuf_t *)mp)->tb_pa;
278d39a76e7Sxw 		hmp->ce_dh = NULL;
279d39a76e7Sxw 		hmp->ce_flg = DH_TOE;
280d39a76e7Sxw 		hmp->ce_len = ((tbuf_t *)mp)->tb_len;
281d39a76e7Sxw 		hmp->ce_mp = mp;
282d39a76e7Sxw 
283d39a76e7Sxw 		/* make sure data is flushed to physical memory */
284d39a76e7Sxw 		(void) ddi_dma_sync((ddi_dma_handle_t)((tbuf_t *)mp)->tb_dh,
285d39a76e7Sxw 		    (off_t)0, hmp->ce_len, DDI_DMA_SYNC_FORDEV);
286d39a76e7Sxw 
287d39a76e7Sxw 		if (sge_data_out(sa->sge, 0, mp, hmp, 1, flg) == 0) {
288d39a76e7Sxw 			return (0);
289d39a76e7Sxw 		}
290d39a76e7Sxw 
291d39a76e7Sxw 		/*
292d39a76e7Sxw 		 * set a flag so we'll restart upper layer when
293d39a76e7Sxw 		 * resources become available.
294d39a76e7Sxw 		 */
295d39a76e7Sxw 		sa->ch_blked = 1;
296d39a76e7Sxw 		return (1);
297d39a76e7Sxw 	}
298d39a76e7Sxw #endif	/* CONFIG_CHELSIO_T1_OFFLOAD */
299d39a76e7Sxw 
300d39a76e7Sxw 	/* writes from toe will always have CPL header in place */
301d39a76e7Sxw 	if (flg & CH_NO_CPL) {
302d39a76e7Sxw 		struct cpl_tx_pkt *cpl;
303d39a76e7Sxw 
304d39a76e7Sxw 		/* PR2928 & PR3309 */
30511abda1eSToomas Soome 		if (sa->ch_ip == 0) {
306d39a76e7Sxw 			ushort_t ethertype = ntohs(*(short *)&mp->b_rptr[12]);
307d39a76e7Sxw 			if (ethertype == ETHERTYPE_ARP) {
308d39a76e7Sxw 				if (is_T2(sa)) {
309d39a76e7Sxw 					/*
310d39a76e7Sxw 					 * We assume here that the arp will be
311d39a76e7Sxw 					 * contained in one mblk.
312d39a76e7Sxw 					 */
313d39a76e7Sxw 					if (pe_make_fake_arp(sa, mp->b_rptr)) {
314d39a76e7Sxw 						freemsg(mp);
315d39a76e7Sxw 						sa->oerr++;
316d39a76e7Sxw 						return (0);
317d39a76e7Sxw 					}
318d39a76e7Sxw 				} else {
319d39a76e7Sxw 					sa->ch_ip = pe_get_ip(mp->b_rptr);
320d39a76e7Sxw 				}
321d39a76e7Sxw 			}
322d39a76e7Sxw 		}
323d39a76e7Sxw 
324d39a76e7Sxw 		/*
325d39a76e7Sxw 		 * if space in front of packet big enough for CPL
326d39a76e7Sxw 		 * header, then use it. We'll allocate an mblk
327d39a76e7Sxw 		 * otherwise.
328d39a76e7Sxw 		 */
329d39a76e7Sxw 		if ((mp->b_rptr - mp->b_datap->db_base) >= SZ_CPL_TX_PKT) {
330d39a76e7Sxw 
331d39a76e7Sxw 			mp->b_rptr -= SZ_CPL_TX_PKT;
332d39a76e7Sxw 
333d39a76e7Sxw 		} else {
334d39a76e7Sxw 
335d39a76e7Sxw #ifdef SUN_KSTATS
336d39a76e7Sxw 			sa->sge->intr_cnt.tx_need_cpl_space++;
337d39a76e7Sxw #endif
338d39a76e7Sxw 			m0 = allocb(SZ_CPL_TX_PKT, BPRI_HI);
339d39a76e7Sxw 			if (m0 == NULL) {
340d39a76e7Sxw 				freemsg(mp);
341d39a76e7Sxw 				sa->oerr++;
342d39a76e7Sxw 				return (0);
343d39a76e7Sxw 			}
344d39a76e7Sxw 
345d39a76e7Sxw 			m0->b_wptr = m0->b_rptr + SZ_CPL_TX_PKT;
346d39a76e7Sxw 			m0->b_cont = mp;
347d39a76e7Sxw 			freeme = 1;
348d39a76e7Sxw 
349d39a76e7Sxw 			mp = m0;
350d39a76e7Sxw 		}
351d39a76e7Sxw 
352d39a76e7Sxw 		/* fill in cpl header */
353d39a76e7Sxw 		cpl = (struct cpl_tx_pkt *)mp->b_rptr;
354d39a76e7Sxw 		cpl->opcode = CPL_TX_PKT;
355d39a76e7Sxw 		cpl->iff = 0;		/* XXX port 0 needs fixing with NEMO */
356d39a76e7Sxw 		cpl->ip_csum_dis = 1;	/* no IP header cksum */
357d39a76e7Sxw 		cpl->l4_csum_dis =
358d39a76e7Sxw 		    flg & CH_NO_HWCKSUM;	/* CH_NO_HWCKSUM == 1 */
359d39a76e7Sxw 		cpl->vlan_valid = 0;		/* no vlan */
360d39a76e7Sxw 	}
361d39a76e7Sxw 
362d39a76e7Sxw 	if (m0->b_cont) {
363d39a76e7Sxw 
364d39a76e7Sxw #ifdef SUN_KSTATS
365d39a76e7Sxw 			sa->sge->intr_cnt.tx_multi_mblks++;
366d39a76e7Sxw #endif
367d39a76e7Sxw 
368d39a76e7Sxw 		while (mp) {
369d39a76e7Sxw 			int lseg;	/* added by ch_bind_dma_handle() */
370d39a76e7Sxw 			int len;
371d39a76e7Sxw 
372d39a76e7Sxw 			len = MLEN(mp);
373d39a76e7Sxw 			/* skip mlks with no data */
374d39a76e7Sxw 			if (len == 0) {
375d39a76e7Sxw 				mp = mp->b_cont;
376d39a76e7Sxw 				continue;
377d39a76e7Sxw 			}
378d39a76e7Sxw 
379d39a76e7Sxw 			/*
380d39a76e7Sxw 			 * if we've run out of space on stack, then we
381d39a76e7Sxw 			 * allocate a temporary buffer to hold the
382d39a76e7Sxw 			 * information. This will kill the the performance,
383d39a76e7Sxw 			 * but since it shouldn't really occur, we can live
384d39a76e7Sxw 			 * with it. Since jumbo frames may map multiple
385d39a76e7Sxw 			 * descriptors, we reallocate the hmp[] array before
386d39a76e7Sxw 			 * we reach the end.
387d39a76e7Sxw 			 */
388d39a76e7Sxw 			if (nseg >= (mseg-4)) {
389d39a76e7Sxw 				cmdQ_ce_t *buf;
390d39a76e7Sxw 				int j;
391d39a76e7Sxw 
392d39a76e7Sxw 				buf = kmem_alloc(sizeof (cmdQ_ce_t) * 2 * mseg,
393d39a76e7Sxw 				    KM_SLEEP);
394d39a76e7Sxw 
395d39a76e7Sxw 				for (j = 0; j < nseg; j++)
396d39a76e7Sxw 					buf[j] = hmp[j];
397d39a76e7Sxw 
398d39a76e7Sxw 				if (cm_flg) {
399d39a76e7Sxw 					kmem_free(hmp,
400d39a76e7Sxw 					    mseg * sizeof (cmdQ_ce_t));
401d39a76e7Sxw 				} else
402d39a76e7Sxw 					cm_flg = 1;
403d39a76e7Sxw 
404d39a76e7Sxw 				hmp = buf;
405d39a76e7Sxw 				mseg = 2*mseg;
406d39a76e7Sxw 
407d39a76e7Sxw 				/*
408d39a76e7Sxw 				 * We've used up ch table on stack
409d39a76e7Sxw 				 */
410d39a76e7Sxw 			}
411d39a76e7Sxw 
412d39a76e7Sxw #if defined(__sparc)
413d39a76e7Sxw 			if (sa->ch_config.enable_dvma) {
414d39a76e7Sxw 				lseg = ch_bind_dvma_handle(sa, len,
415d39a76e7Sxw 				    (void *)mp->b_rptr,
416d39a76e7Sxw 				    &hmp[nseg], mseg - nseg);
417*4e2c3273SToomas Soome 				if (lseg == 0) {
418d39a76e7Sxw 					sa->sge->intr_cnt.tx_no_dvma1++;
419d39a76e7Sxw 					if ((lseg = ch_bind_dma_handle(sa, len,
420d39a76e7Sxw 					    (void *)mp->b_rptr,
421d39a76e7Sxw 					    &hmp[nseg],
422*4e2c3273SToomas Soome 					    mseg - nseg)) == 0) {
423d39a76e7Sxw 						sa->sge->intr_cnt.tx_no_dma1++;
424d39a76e7Sxw 
425d39a76e7Sxw 						/*
426d39a76e7Sxw 						 * ran out of space. Gonna bale
427d39a76e7Sxw 						 */
428d39a76e7Sxw 						rv = 0;
429d39a76e7Sxw 
430d39a76e7Sxw 						/*
431d39a76e7Sxw 						 * we may have processed
432d39a76e7Sxw 						 * previous mblks and have
433d39a76e7Sxw 						 * descriptors. If so, we need
434d39a76e7Sxw 						 * to free the meta struct
435d39a76e7Sxw 						 * entries before freeing
436d39a76e7Sxw 						 * the mblk.
437d39a76e7Sxw 						 */
438d39a76e7Sxw 						if (nseg)
439d39a76e7Sxw 							goto error;
440d39a76e7Sxw 						goto error1;
441d39a76e7Sxw 					}
442d39a76e7Sxw 				}
443d39a76e7Sxw 			} else {
444d39a76e7Sxw 				lseg = ch_bind_dma_handle(sa, len,
445d39a76e7Sxw 				    (void *)mp->b_rptr, &hmp[nseg],
446d39a76e7Sxw 				    mseg - nseg);
447*4e2c3273SToomas Soome 				if (lseg == 0) {
448d39a76e7Sxw 					sa->sge->intr_cnt.tx_no_dma1++;
449d39a76e7Sxw 
450d39a76e7Sxw 					/*
451d39a76e7Sxw 					 * ran out of space. Gona bale
452d39a76e7Sxw 					 */
453d39a76e7Sxw 					rv = 0;
454d39a76e7Sxw 
455d39a76e7Sxw 					/*
456d39a76e7Sxw 					 * we may have processed previous
457d39a76e7Sxw 					 * mblks and have descriptors. If so,
458d39a76e7Sxw 					 * we need to free the meta struct
459d39a76e7Sxw 					 * entries before freeing the mblk.
460d39a76e7Sxw 					 */
461d39a76e7Sxw 					if (nseg)
462d39a76e7Sxw 						goto error;
463d39a76e7Sxw 					goto error1;
464d39a76e7Sxw 				}
465d39a76e7Sxw 			}
466d39a76e7Sxw #else	/* defined(__sparc) */
467d39a76e7Sxw 			lseg = ch_bind_dma_handle(sa, len,
468d39a76e7Sxw 			    (void *)mp->b_rptr, &hmp[nseg],
469d39a76e7Sxw 			    mseg - nseg);
47011abda1eSToomas Soome 			if (lseg == 0) {
471d39a76e7Sxw 				sa->sge->intr_cnt.tx_no_dma1++;
472d39a76e7Sxw 
473d39a76e7Sxw 				/*
474d39a76e7Sxw 				 * ran out of space. Gona bale
475d39a76e7Sxw 				 */
476d39a76e7Sxw 				rv = 0;
477d39a76e7Sxw 
478d39a76e7Sxw 				/*
479d39a76e7Sxw 				 * we may have processed previous mblks and
480d39a76e7Sxw 				 * have descriptors. If so, we need to free
481d39a76e7Sxw 				 * the meta struct entries before freeing
482d39a76e7Sxw 				 * the mblk.
483d39a76e7Sxw 				 */
484d39a76e7Sxw 				if (nseg)
485d39a76e7Sxw 					goto error;
486d39a76e7Sxw 				goto error1;
487d39a76e7Sxw 			}
488d39a76e7Sxw #endif	/* defined(__sparc) */
489d39a76e7Sxw 			nseg += lseg;
490d39a76e7Sxw 			mp = mp->b_cont;
491d39a76e7Sxw 		}
492d39a76e7Sxw 
493d39a76e7Sxw 		/*
494d39a76e7Sxw 		 * SHOULD NEVER OCCUR, BUT...
495d39a76e7Sxw 		 * no data if nseg 0 or
496d39a76e7Sxw 		 * nseg 1 and a CPL mblk (CPL mblk only with offload mode)
497d39a76e7Sxw 		 * and no data
498d39a76e7Sxw 		 */
499d39a76e7Sxw 		if ((nseg == 0) || (freeme && (nseg == 1))) {
500d39a76e7Sxw 			rv = 0;
501d39a76e7Sxw 			goto error1;
502d39a76e7Sxw 		}
503d39a76e7Sxw 
504d39a76e7Sxw 	} else {
505d39a76e7Sxw 		int len;
506d39a76e7Sxw 
507d39a76e7Sxw 		/* we assume that we always have data with one packet */
508d39a76e7Sxw 		len = MLEN(mp);
509d39a76e7Sxw 
510d39a76e7Sxw #if defined(__sparc)
511d39a76e7Sxw 		if (sa->ch_config.enable_dvma) {
512d39a76e7Sxw 			nseg = ch_bind_dvma_handle(sa, len,
513d39a76e7Sxw 			    (void *)mp->b_rptr,
514d39a76e7Sxw 			    &hmp[0], 16);
515*4e2c3273SToomas Soome 			if (nseg == 0) {
516d39a76e7Sxw 				sa->sge->intr_cnt.tx_no_dvma2++;
517d39a76e7Sxw 				nseg = ch_bind_dma_handle(sa, len,
518d39a76e7Sxw 				    (void *)mp->b_rptr,
519d39a76e7Sxw 				    &hmp[0], 16);
520*4e2c3273SToomas Soome 				if (nseg == 0) {
521d39a76e7Sxw 					sa->sge->intr_cnt.tx_no_dma2++;
522d39a76e7Sxw 
523d39a76e7Sxw 					/*
524d39a76e7Sxw 					 * ran out of space. Gona bale
525d39a76e7Sxw 					 */
526d39a76e7Sxw 					rv = 0;
527d39a76e7Sxw 					goto error1;
528d39a76e7Sxw 				}
529d39a76e7Sxw 			}
530d39a76e7Sxw 		} else {
531d39a76e7Sxw 			nseg = ch_bind_dma_handle(sa, len,
532d39a76e7Sxw 			    (void *)mp->b_rptr, &hmp[0], 16);
533*4e2c3273SToomas Soome 			if (nseg == 0) {
534d39a76e7Sxw 				sa->sge->intr_cnt.tx_no_dma2++;
535d39a76e7Sxw 
536d39a76e7Sxw 				/*
537d39a76e7Sxw 				 * ran out of space. Gona bale
538d39a76e7Sxw 				 */
539d39a76e7Sxw 				rv = 0;
540d39a76e7Sxw 				goto error1;
541d39a76e7Sxw 			}
542d39a76e7Sxw 		}
543d39a76e7Sxw #else	/* defined(__sparc) */
544d39a76e7Sxw 		nseg = ch_bind_dma_handle(sa, len,
545d39a76e7Sxw 		    (void *)mp->b_rptr, &hmp[0], 16);
54611abda1eSToomas Soome 		if (nseg == 0) {
547d39a76e7Sxw 			sa->sge->intr_cnt.tx_no_dma2++;
548d39a76e7Sxw 
549d39a76e7Sxw 			/*
550d39a76e7Sxw 			 * ran out of space. Gona bale
551d39a76e7Sxw 			 */
552d39a76e7Sxw 			rv = 0;
553d39a76e7Sxw 			goto error1;
554d39a76e7Sxw 		}
555d39a76e7Sxw #endif	/* defined(__sparc) */
556d39a76e7Sxw 
557d39a76e7Sxw 		/*
558d39a76e7Sxw 		 * dummy arp message to handle PR3309 & PR2928
559d39a76e7Sxw 		 */
560d39a76e7Sxw 		if (flg & CH_ARP)
561d39a76e7Sxw 			hmp->ce_flg |= DH_ARP;
562d39a76e7Sxw 	}
563d39a76e7Sxw 
564d39a76e7Sxw 	if (sge_data_out(sa->sge, 0, m0, hmp, nseg, flg) == 0) {
565d39a76e7Sxw 		if (cm_flg)
566d39a76e7Sxw 			kmem_free(hmp, mseg * sizeof (cmdQ_ce_t));
567d39a76e7Sxw 		return (0);
568d39a76e7Sxw 	}
569d39a76e7Sxw 
570d39a76e7Sxw 	/*
571d39a76e7Sxw 	 * set a flag so we'll restart upper layer when
572d39a76e7Sxw 	 * resources become available.
573d39a76e7Sxw 	 */
574d39a76e7Sxw 	if ((flg & CH_ARP) == 0)
575d39a76e7Sxw 		sa->ch_blked = 1;
576d39a76e7Sxw 	rv = 1;
577d39a76e7Sxw 
578d39a76e7Sxw error:
579d39a76e7Sxw 	/*
580d39a76e7Sxw 	 * unmap the physical addresses allocated earlier.
581d39a76e7Sxw 	 */
582d39a76e7Sxw 	cmp = hmp;
583d39a76e7Sxw 	for (--nseg; nseg >= 0; nseg--) {
584d39a76e7Sxw 		if (cmp->ce_dh) {
585d39a76e7Sxw 			if (cmp->ce_flg == DH_DMA)
586d39a76e7Sxw 				ch_unbind_dma_handle(sa, cmp->ce_dh);
587d39a76e7Sxw #if defined(__sparc)
588d39a76e7Sxw 			else
589d39a76e7Sxw 				ch_unbind_dvma_handle(sa, cmp->ce_dh);
590d39a76e7Sxw #endif
591d39a76e7Sxw 		}
592d39a76e7Sxw 		cmp++;
593d39a76e7Sxw 	}
594d39a76e7Sxw 
595d39a76e7Sxw error1:
596d39a76e7Sxw 
597d39a76e7Sxw 	/* free the temporary array */
598d39a76e7Sxw 	if (cm_flg)
599d39a76e7Sxw 		kmem_free(hmp, mseg * sizeof (cmdQ_ce_t));
600d39a76e7Sxw 
601d39a76e7Sxw 	/*
602d39a76e7Sxw 	 * if we've allocated an mblk above, then we need to free it
603d39a76e7Sxw 	 * before returning. This is safe since we haven't done anything to
604d39a76e7Sxw 	 * the original message. The caller, gld, will still have a pointer
605d39a76e7Sxw 	 * to the original mblk.
606d39a76e7Sxw 	 */
607d39a76e7Sxw 	if (rv == 1) {
608d39a76e7Sxw 		if (freeme) {
609d39a76e7Sxw 			/* we had to allocate an mblk. Free it. */
610d39a76e7Sxw 			freeb(m0);
611d39a76e7Sxw 		} else {
612d39a76e7Sxw 			/* adjust the mblk back to original start */
613d39a76e7Sxw 			if (flg & CH_NO_CPL)
614d39a76e7Sxw 				m0->b_rptr += SZ_CPL_TX_PKT;
615d39a76e7Sxw 		}
616d39a76e7Sxw 	} else {
617d39a76e7Sxw 		freemsg(m0);
618d39a76e7Sxw 		sa->oerr++;
619d39a76e7Sxw 	}
620d39a76e7Sxw 
621d39a76e7Sxw 	return (rv);
622d39a76e7Sxw }
623d39a76e7Sxw 
624d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO PORT ZERO */
625d39a76e7Sxw void
pe_set_mac(ch_t * sa,unsigned char * ac_enaddr)626d39a76e7Sxw pe_set_mac(ch_t *sa, unsigned char *ac_enaddr)
627d39a76e7Sxw {
628d39a76e7Sxw 	sa->port[0].mac->ops->macaddress_set(sa->port[0].mac, ac_enaddr);
629d39a76e7Sxw }
630d39a76e7Sxw 
631d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO PORT ZERO */
632d39a76e7Sxw unsigned char *
pe_get_mac(ch_t * sa)633d39a76e7Sxw pe_get_mac(ch_t *sa)
634d39a76e7Sxw {
635d39a76e7Sxw 	return (sa->port[0].enaddr);
636d39a76e7Sxw }
637d39a76e7Sxw 
638d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO ONE PORT */
639d39a76e7Sxw void
pe_set_promiscuous(ch_t * sa,int flag)640d39a76e7Sxw pe_set_promiscuous(ch_t *sa, int flag)
641d39a76e7Sxw {
642d39a76e7Sxw 	struct cmac *mac = sa->port[0].mac;
643d39a76e7Sxw 	struct t1_rx_mode rm;
644d39a76e7Sxw 
645d39a76e7Sxw 	switch (flag) {
646d39a76e7Sxw 	case 0:		/* turn off promiscuous mode */
647d39a76e7Sxw 		sa->ch_flags &= ~(PEPROMISC|PEALLMULTI);
648d39a76e7Sxw 		break;
649d39a76e7Sxw 
650d39a76e7Sxw 	case 1:		/* turn on promiscuous mode */
651d39a76e7Sxw 		sa->ch_flags |= PEPROMISC;
652d39a76e7Sxw 		break;
653d39a76e7Sxw 
654d39a76e7Sxw 	case 2:		/* turn on multicast reception */
655d39a76e7Sxw 		sa->ch_flags |= PEALLMULTI;
656d39a76e7Sxw 		break;
657d39a76e7Sxw 	}
658d39a76e7Sxw 
659d39a76e7Sxw 	mutex_enter(&sa->ch_mc_lck);
660d39a76e7Sxw 	rm.chp = sa;
661d39a76e7Sxw 	rm.mc = sa->ch_mc;
662d39a76e7Sxw 
663d39a76e7Sxw 	mac->ops->set_rx_mode(mac, &rm);
664d39a76e7Sxw 	mutex_exit(&sa->ch_mc_lck);
665d39a76e7Sxw }
666d39a76e7Sxw 
667d39a76e7Sxw int
pe_set_mc(ch_t * sa,uint8_t * ep,int flg)668d39a76e7Sxw pe_set_mc(ch_t *sa, uint8_t *ep, int flg)
669d39a76e7Sxw {
670d39a76e7Sxw 	struct cmac *mac = sa->port[0].mac;
671d39a76e7Sxw 	struct t1_rx_mode rm;
672d39a76e7Sxw 
673d39a76e7Sxw 	if (flg == GLD_MULTI_ENABLE) {
674d39a76e7Sxw 		ch_mc_t *mcp;
675d39a76e7Sxw 
676d39a76e7Sxw 		mcp = (ch_mc_t *)kmem_zalloc(sizeof (struct ch_mc),
677d39a76e7Sxw 		    KM_NOSLEEP);
678d39a76e7Sxw 		if (mcp == NULL)
679d39a76e7Sxw 			return (GLD_NORESOURCES);
680d39a76e7Sxw 
681d39a76e7Sxw 		bcopy(ep, &mcp->cmc_mca, 6);
682d39a76e7Sxw 
683d39a76e7Sxw 		mutex_enter(&sa->ch_mc_lck);
684d39a76e7Sxw 		mcp->cmc_next = sa->ch_mc;
685d39a76e7Sxw 		sa->ch_mc = mcp;
686d39a76e7Sxw 		sa->ch_mc_cnt++;
687d39a76e7Sxw 		mutex_exit(&sa->ch_mc_lck);
688d39a76e7Sxw 
689d39a76e7Sxw 	} else if (flg == GLD_MULTI_DISABLE) {
690d39a76e7Sxw 		ch_mc_t **p = &sa->ch_mc;
691d39a76e7Sxw 		ch_mc_t *q = NULL;
692d39a76e7Sxw 
693d39a76e7Sxw 		mutex_enter(&sa->ch_mc_lck);
694d39a76e7Sxw 		p = &sa->ch_mc;
695d39a76e7Sxw 		while (*p) {
696d39a76e7Sxw 			if (bcmp(ep, (*p)->cmc_mca, 6) == 0) {
697d39a76e7Sxw 				q = *p;
698d39a76e7Sxw 				*p = (*p)->cmc_next;
699d39a76e7Sxw 				kmem_free(q, sizeof (*q));
700d39a76e7Sxw 				sa->ch_mc_cnt--;
701d39a76e7Sxw 				break;
702d39a76e7Sxw 			}
703d39a76e7Sxw 
704d39a76e7Sxw 			p = &(*p)->cmc_next;
705d39a76e7Sxw 		}
706d39a76e7Sxw 		mutex_exit(&sa->ch_mc_lck);
707d39a76e7Sxw 
708d39a76e7Sxw 		if (q == NULL)
709d39a76e7Sxw 			return (GLD_BADARG);
710d39a76e7Sxw 	} else
711d39a76e7Sxw 		return (GLD_BADARG);
712d39a76e7Sxw 
713d39a76e7Sxw 	mutex_enter(&sa->ch_mc_lck);
714d39a76e7Sxw 	rm.chp = sa;
715d39a76e7Sxw 	rm.mc = sa->ch_mc;
716d39a76e7Sxw 
717d39a76e7Sxw 	mac->ops->set_rx_mode(mac, &rm);
718d39a76e7Sxw 	mutex_exit(&sa->ch_mc_lck);
719d39a76e7Sxw 
720d39a76e7Sxw 	return (GLD_SUCCESS);
721d39a76e7Sxw }
722d39a76e7Sxw 
723d39a76e7Sxw /*
724d39a76e7Sxw  * return: speed       - bandwidth of interface
725d39a76e7Sxw  * return: intrcnt     - # interrupts
726d39a76e7Sxw  * return: norcvbuf    - # recedived packets dropped by driver
727d39a76e7Sxw  * return: oerrors     - # bad send packets
728d39a76e7Sxw  * return: ierrors     - # bad receive packets
729d39a76e7Sxw  * return: underrun    - # bad underrun xmit packets
730d39a76e7Sxw  * return: overrun     - # bad overrun recv packets
731d39a76e7Sxw  * return: framing     - # bad aligned recv packets
732d39a76e7Sxw  * return: crc         - # bad FCS (crc) recv packets
733d39a76e7Sxw  * return: carrier     - times carrier was lost
734d39a76e7Sxw  * return: collisions  - # xmit collisions
735d39a76e7Sxw  * return: xcollisions - # xmit pkts dropped due to collisions
736d39a76e7Sxw  * return: late        - # late xmit collisions
737d39a76e7Sxw  * return: defer       - # deferred xmit packets
738d39a76e7Sxw  * return: xerrs       - # xmit dropped packets
739d39a76e7Sxw  * return: rerrs       - # recv dropped packets
740d39a76e7Sxw  * return: toolong     - # recv pkts too long
741d39a76e7Sxw  * return: runt        - # recv runt pkts
742d39a76e7Sxw  * return: multixmt    - # multicast pkts xmitted
743d39a76e7Sxw  * return: multircv    - # multicast pkts recved
744d39a76e7Sxw  * return: brdcstxmt   - # broadcast pkts xmitted
745d39a76e7Sxw  * return: brdcstrcv   - # broadcast pkts rcv
746d39a76e7Sxw  */
747d39a76e7Sxw 
748d39a76e7Sxw int
pe_get_stats(ch_t * sa,uint64_t * speed,uint32_t * intrcnt,uint32_t * norcvbuf,uint32_t * oerrors,uint32_t * ierrors,uint32_t * underrun,uint32_t * overrun,uint32_t * framing,uint32_t * crc,uint32_t * carrier,uint32_t * collisions,uint32_t * xcollisions,uint32_t * late,uint32_t * defer,uint32_t * xerrs,uint32_t * rerrs,uint32_t * toolong,uint32_t * runt,ulong_t * multixmt,ulong_t * multircv,ulong_t * brdcstxmt,ulong_t * brdcstrcv)749d39a76e7Sxw pe_get_stats(ch_t *sa, uint64_t *speed, uint32_t *intrcnt, uint32_t *norcvbuf,
750d39a76e7Sxw     uint32_t *oerrors, uint32_t *ierrors, uint32_t *underrun,
751d39a76e7Sxw     uint32_t *overrun, uint32_t *framing, uint32_t *crc,
752d39a76e7Sxw     uint32_t *carrier, uint32_t *collisions, uint32_t *xcollisions,
753d39a76e7Sxw     uint32_t *late, uint32_t *defer, uint32_t *xerrs, uint32_t *rerrs,
754d39a76e7Sxw     uint32_t *toolong, uint32_t *runt, ulong_t  *multixmt, ulong_t  *multircv,
755d39a76e7Sxw     ulong_t  *brdcstxmt, ulong_t  *brdcstrcv)
756d39a76e7Sxw {
757d39a76e7Sxw 	struct pe_port_t *pt;
758d39a76e7Sxw 	int line_speed;
759d39a76e7Sxw 	int line_duplex;
760d39a76e7Sxw 	int line_is_active;
761d39a76e7Sxw 	uint64_t v;
762d39a76e7Sxw 	const struct cmac_statistics *sp;
763d39a76e7Sxw 
764d39a76e7Sxw 	pt = &(sa->port[0]);
765d39a76e7Sxw 	(void) pt->phy->ops->get_link_status(pt->phy,
766d39a76e7Sxw 	    &line_is_active, &line_speed, &line_duplex, NULL);
767d39a76e7Sxw 
768d39a76e7Sxw 	switch (line_speed) {
769d39a76e7Sxw 	case SPEED_10:
770d39a76e7Sxw 		*speed = 10000000;
771d39a76e7Sxw 		break;
772d39a76e7Sxw 	case SPEED_100:
773d39a76e7Sxw 		*speed = 100000000;
774d39a76e7Sxw 		break;
775d39a76e7Sxw 	case SPEED_1000:
776d39a76e7Sxw 		*speed = 1000000000;
777d39a76e7Sxw 		break;
778d39a76e7Sxw 	case SPEED_10000:
779d39a76e7Sxw 		/*
780d39a76e7Sxw 		 * kludge to get 10,000,000,000 constant (and keep
781d39a76e7Sxw 		 * compiler happy).
782d39a76e7Sxw 		 */
783d39a76e7Sxw 		v = 10000000;
784d39a76e7Sxw 		v *= 1000;
785d39a76e7Sxw 		*speed = v;
786d39a76e7Sxw 		break;
787d39a76e7Sxw 	default:
788d39a76e7Sxw 		goto error;
789d39a76e7Sxw 	}
790d39a76e7Sxw 
791d39a76e7Sxw 	*intrcnt = sa->isr_intr;
792d39a76e7Sxw 	*norcvbuf = sa->norcvbuf;
793d39a76e7Sxw 
794d39a76e7Sxw 	sp = sa->port[0].mac->ops->statistics_update(sa->port[0].mac,
795d39a76e7Sxw 	    MAC_STATS_UPDATE_FULL);
796d39a76e7Sxw 
797d39a76e7Sxw 	*ierrors = sp->RxOctetsBad;
798d39a76e7Sxw 
799d39a76e7Sxw 	/*
800d39a76e7Sxw 	 * not sure this is correct. # aborted at driver level +
801d39a76e7Sxw 	 * # at hardware level
802d39a76e7Sxw 	 */
803d39a76e7Sxw 	*oerrors = sa->oerr + sp->TxFramesAbortedDueToXSCollisions +
804d39a76e7Sxw 	    sp->TxUnderrun + sp->TxLengthErrors +
805d39a76e7Sxw 	    sp->TxInternalMACXmitError +
806d39a76e7Sxw 	    sp->TxFramesWithExcessiveDeferral +
807d39a76e7Sxw 	    sp->TxFCSErrors;
808d39a76e7Sxw 
809d39a76e7Sxw 	*underrun = sp->TxUnderrun;
810d39a76e7Sxw 	*overrun = sp->RxFrameTooLongErrors;
811d39a76e7Sxw 	*framing = sp->RxAlignErrors;
812d39a76e7Sxw 	*crc = sp->RxFCSErrors;
813d39a76e7Sxw 	*carrier = 0;		/* need to find this */
814d39a76e7Sxw 	*collisions = sp->TxTotalCollisions;
815d39a76e7Sxw 	*xcollisions = sp->TxFramesAbortedDueToXSCollisions;
816d39a76e7Sxw 	*late = sp->TxLateCollisions;
817d39a76e7Sxw 	*defer = sp->TxFramesWithDeferredXmissions;
818d39a76e7Sxw 	*xerrs = sp->TxUnderrun + sp->TxLengthErrors +
819d39a76e7Sxw 	    sp->TxInternalMACXmitError + sp->TxFCSErrors;
820d39a76e7Sxw 	*rerrs = sp->RxSymbolErrors + sp->RxSequenceErrors + sp->RxRuntErrors +
821d39a76e7Sxw 	    sp->RxJabberErrors + sp->RxInternalMACRcvError +
822d39a76e7Sxw 	    sp->RxInRangeLengthErrors + sp->RxOutOfRangeLengthField;
823d39a76e7Sxw 	*toolong = sp->RxFrameTooLongErrors;
824d39a76e7Sxw 	*runt = sp->RxRuntErrors;
825d39a76e7Sxw 
826d39a76e7Sxw 	*multixmt = sp->TxMulticastFramesOK;
827d39a76e7Sxw 	*multircv = sp->RxMulticastFramesOK;
828d39a76e7Sxw 	*brdcstxmt = sp->TxBroadcastFramesOK;
829d39a76e7Sxw 	*brdcstrcv = sp->RxBroadcastFramesOK;
830d39a76e7Sxw 
831d39a76e7Sxw 	return (0);
832d39a76e7Sxw 
833d39a76e7Sxw error:
834d39a76e7Sxw 	*speed = 0;
835d39a76e7Sxw 	*intrcnt = 0;
836d39a76e7Sxw 	*norcvbuf = 0;
837d39a76e7Sxw 	*norcvbuf = 0;
838d39a76e7Sxw 	*oerrors = 0;
839d39a76e7Sxw 	*ierrors = 0;
840d39a76e7Sxw 	*underrun = 0;
841d39a76e7Sxw 	*overrun = 0;
842d39a76e7Sxw 	*framing = 0;
843d39a76e7Sxw 	*crc = 0;
844d39a76e7Sxw 	*carrier = 0;
845d39a76e7Sxw 	*collisions = 0;
846d39a76e7Sxw 	*xcollisions = 0;
847d39a76e7Sxw 	*late = 0;
848d39a76e7Sxw 	*defer = 0;
849d39a76e7Sxw 	*xerrs = 0;
850d39a76e7Sxw 	*rerrs = 0;
851d39a76e7Sxw 	*toolong = 0;
852d39a76e7Sxw 	*runt = 0;
853d39a76e7Sxw 	*multixmt = 0;
854d39a76e7Sxw 	*multircv = 0;
855d39a76e7Sxw 	*brdcstxmt = 0;
856d39a76e7Sxw 	*brdcstrcv = 0;
857d39a76e7Sxw 
858d39a76e7Sxw 	return (1);
859d39a76e7Sxw }
860d39a76e7Sxw 
861d39a76e7Sxw uint32_t ch_gtm = 0;		/* Default: Global Tunnel Mode off */
862d39a76e7Sxw uint32_t ch_global_config = 0x07000000;	/* Default: errors, warnings, status */
863d39a76e7Sxw uint32_t ch_is_asic = 0;	/* Default: non-ASIC */
864d39a76e7Sxw uint32_t ch_link_speed = PE_LINK_SPEED_AUTONEG;	/* Default: auto-negoiate */
865d39a76e7Sxw uint32_t ch_num_of_ports = 1;	/* Default: 1 port */
866d39a76e7Sxw uint32_t ch_tp_reset_cm = 1;	/* Default: reset CM memory map */
867d39a76e7Sxw uint32_t ch_phy_tx_fifo = 0;	/* Default: 0 phy tx fifo depth */
868d39a76e7Sxw uint32_t ch_phy_rx_fifo = 0;	/* Default: 0 phy rx fifo depth */
869d39a76e7Sxw uint32_t ch_phy_force_master = 1;	/* Default: link always master mode */
870d39a76e7Sxw uint32_t ch_mc5_rtbl_size = 2048;	/* Default: TCAM routing table size */
871d39a76e7Sxw uint32_t ch_mc5_dbsvr_size = 128;	/* Default: TCAM server size */
872d39a76e7Sxw uint32_t ch_mc5_parity = 1;	/* Default: parity error checking */
873d39a76e7Sxw uint32_t ch_mc5_issue_syn = 0;	/* Default: Allow transaction overlap */
874d39a76e7Sxw uint32_t ch_packet_tracing = 0;		/* Default: no packet tracing */
875d39a76e7Sxw uint32_t ch_server_region_len =
876d39a76e7Sxw 	DEFAULT_SERVER_REGION_LEN;
877d39a76e7Sxw uint32_t ch_rt_region_len =
878d39a76e7Sxw 	DEFAULT_RT_REGION_LEN;
879d39a76e7Sxw uint32_t ch_offload_ip_cksum = 0;	/* Default: no checksum offloading */
880d39a76e7Sxw uint32_t ch_offload_udp_cksum = 1;	/* Default: offload UDP ckecksum */
881d39a76e7Sxw uint32_t ch_offload_tcp_cksum = 1;	/* Default: offload TCP checksum */
882d39a76e7Sxw uint32_t ch_sge_cmdq_threshold = 0;	/* Default: threshold 0 */
883d39a76e7Sxw uint32_t ch_sge_flq_threshold = 0;	/* Default: SGE flq threshold */
884d39a76e7Sxw uint32_t ch_sge_cmdq0_cnt =	/* Default: cmd queue 0 size */
885d39a76e7Sxw 	SGE_CMDQ0_CNT;
886d39a76e7Sxw uint32_t ch_sge_cmdq1_cnt =	/* Default: cmd queue 1 size */
887d39a76e7Sxw 	SGE_CMDQ0_CNT;
888d39a76e7Sxw uint32_t ch_sge_flq0_cnt =	/* Default: free list queue-0 length */
889d39a76e7Sxw 	SGE_FLQ0_CNT;
890d39a76e7Sxw uint32_t ch_sge_flq1_cnt =	/* Default: free list queue-1 length */
891d39a76e7Sxw 	SGE_FLQ0_CNT;
892d39a76e7Sxw uint32_t ch_sge_respq_cnt =	/* Default: reqsponse queue size */
893d39a76e7Sxw 	SGE_RESPQ_CNT;
894d39a76e7Sxw uint32_t ch_stats = 1;		/* Default: Automatic Update MAC stats */
895d39a76e7Sxw uint32_t ch_tx_delay_us = 0;	/* Default: No Msec delay to Tx pkts */
896d39a76e7Sxw int32_t ch_chip = -1;		/* Default: use hardware lookup tbl */
897d39a76e7Sxw uint32_t ch_exit_early = 0;	/* Default: complete initialization */
898d39a76e7Sxw uint32_t ch_rb_num_of_entries = 1000; /* Default: number ring buffer entries */
899d39a76e7Sxw uint32_t ch_rb_size_of_entries = 64;	/* Default: ring buffer entry size */
900d39a76e7Sxw uint32_t ch_rb_flag = 1;	/* Default: ring buffer flag */
901d39a76e7Sxw uint32_t ch_type;
902d39a76e7Sxw uint64_t ch_cat_opt0 = 0;
903d39a76e7Sxw uint64_t ch_cat_opt1 = 0;
904d39a76e7Sxw uint32_t ch_timer_delay = 0;	/* Default: use value from board entry */
905d39a76e7Sxw 
906d39a76e7Sxw int
pe_attach(ch_t * chp)907d39a76e7Sxw pe_attach(ch_t *chp)
908d39a76e7Sxw {
909d39a76e7Sxw 	int return_val = 1;
910d39a76e7Sxw 	const struct board_info *bi;
911d39a76e7Sxw 	uint32_t pcix_cmd;
912d39a76e7Sxw 
913d39a76e7Sxw 	(void) ch_set_config_data(chp);
914d39a76e7Sxw 
915d39a76e7Sxw 	bi = pe_sa_init(chp);
916d39a76e7Sxw 	if (bi == 0)
917d39a76e7Sxw 		return (1);
918d39a76e7Sxw 
919d39a76e7Sxw 	if (t1_init_sw_modules(chp, bi) < 0)
920d39a76e7Sxw 		return (1);
921d39a76e7Sxw 
92211abda1eSToomas Soome 	if (pe_small_rbuf_pool_init(chp) == 0)
923d39a76e7Sxw 		return (1);
924d39a76e7Sxw 
92511abda1eSToomas Soome 	if (pe_big_rbuf_pool_init(chp) == 0)
926d39a76e7Sxw 		return (1);
927d39a76e7Sxw 
928d39a76e7Sxw 	/*
929d39a76e7Sxw 	 * We gain significaint performance improvements when we
930d39a76e7Sxw 	 * increase the PCI's maximum memory read byte count to
931d39a76e7Sxw 	 * 2K(HW doesn't support 4K at this time) and set the PCI's
932d39a76e7Sxw 	 * maximum outstanding split transactions to 4. We want to do
933d39a76e7Sxw 	 * this for 10G. Done by software utility.
934d39a76e7Sxw 	 */
935d39a76e7Sxw 
936d39a76e7Sxw 	if (board_info(chp)->caps & SUPPORTED_10000baseT_Full) {
937d39a76e7Sxw 		(void) t1_os_pci_read_config_4(chp, A_PCICFG_PCIX_CMD,
938d39a76e7Sxw 		    &pcix_cmd);
939d39a76e7Sxw 		/*
940d39a76e7Sxw 		 * if the burstsize is set, then use it instead of default
941d39a76e7Sxw 		 */
942d39a76e7Sxw 		if (chp->ch_config.burstsize_set) {
943d39a76e7Sxw 			pcix_cmd &= ~0xc0000;
944d39a76e7Sxw 			pcix_cmd |= (chp->ch_config.burstsize << 18);
945d39a76e7Sxw 		}
946d39a76e7Sxw 		/*
947d39a76e7Sxw 		 * if the split transaction count is set, then use it.
948d39a76e7Sxw 		 */
949d39a76e7Sxw 		if (chp->ch_config.transaction_cnt_set) {
950d39a76e7Sxw 			pcix_cmd &= ~ 0x700000;
951d39a76e7Sxw 			pcix_cmd |= (chp->ch_config.transaction_cnt << 20);
952d39a76e7Sxw 		}
953d39a76e7Sxw 
954d39a76e7Sxw 		/*
955d39a76e7Sxw 		 * set ralaxed ordering flag as configured in chxge.conf
956d39a76e7Sxw 		 */
957d39a76e7Sxw 		pcix_cmd |= (chp->ch_config.relaxed_ordering << 17);
958d39a76e7Sxw 
959d39a76e7Sxw 		(void) t1_os_pci_write_config_4(chp, A_PCICFG_PCIX_CMD,
960d39a76e7Sxw 		    pcix_cmd);
961d39a76e7Sxw 	}
962d39a76e7Sxw 
963d39a76e7Sxw 	/*
964d39a76e7Sxw 	 * set the latency time to F8 for 10G cards.
965d39a76e7Sxw 	 * Done by software utiltiy.
966d39a76e7Sxw 	 */
967d39a76e7Sxw 	if (enable_latency_timer) {
968d39a76e7Sxw 		if (board_info(chp)->caps & SUPPORTED_10000baseT_Full) {
969d39a76e7Sxw 			(void) t1_os_pci_write_config_4(chp, 0xc, 0xf800);
970d39a76e7Sxw 		}
971d39a76e7Sxw 	}
972d39a76e7Sxw 
973d39a76e7Sxw 	/*
974d39a76e7Sxw 	 * update mtu table (regs: 0x404 - 0x420) with bigger values than
975d39a76e7Sxw 	 * default.
976d39a76e7Sxw 	 */
977d39a76e7Sxw 	update_mtu_tab(chp);
978d39a76e7Sxw 
979d39a76e7Sxw 	/*
980d39a76e7Sxw 	 * Clear all interrupts now.  Don't enable
981d39a76e7Sxw 	 * them until later.
982d39a76e7Sxw 	 */
983d39a76e7Sxw 	t1_interrupts_clear(chp);
984d39a76e7Sxw 
985d39a76e7Sxw 	/*
986d39a76e7Sxw 	 * Function succeeded.
987d39a76e7Sxw 	 */
988d39a76e7Sxw 	return_val = 0;
989d39a76e7Sxw 
990d39a76e7Sxw 	return (return_val);
991d39a76e7Sxw }
992d39a76e7Sxw 
993d39a76e7Sxw /*
994d39a76e7Sxw  * DESC: Read variables set in /boot/loader.conf and save
995d39a76e7Sxw  *       them internally. These internal values are then
996d39a76e7Sxw  *       used to make decisions at run-time on behavior thus
997d39a76e7Sxw  *       allowing a certain level of customization.
998d39a76e7Sxw  * OUT:  p_config - pointer to config structure that
999d39a76e7Sxw  *                  contains all of the new values.
1000d39a76e7Sxw  * RTN:  0 - Success;
1001d39a76e7Sxw  */
1002d39a76e7Sxw static int
ch_set_config_data(ch_t * chp)1003d39a76e7Sxw ch_set_config_data(ch_t *chp)
1004d39a76e7Sxw {
1005d39a76e7Sxw 	pe_config_data_t *p_config = (pe_config_data_t *)&chp->config_data;
1006d39a76e7Sxw 
1007d39a76e7Sxw 	bzero(p_config, sizeof (pe_config_data_t));
1008d39a76e7Sxw 
1009d39a76e7Sxw 	/*
1010d39a76e7Sxw 	 * Global Tunnel Mode configuration
1011d39a76e7Sxw 	 */
1012d39a76e7Sxw 	p_config->gtm = ch_gtm;
1013d39a76e7Sxw 
1014d39a76e7Sxw 	p_config->global_config = ch_global_config;
1015d39a76e7Sxw 
1016d39a76e7Sxw 	if (p_config->gtm)
1017d39a76e7Sxw 		p_config->global_config |= CFGMD_TUNNEL;
1018d39a76e7Sxw 
1019d39a76e7Sxw 	p_config->tp_reset_cm = ch_tp_reset_cm;
1020d39a76e7Sxw 	p_config->is_asic = ch_is_asic;
1021d39a76e7Sxw 
1022d39a76e7Sxw 	/*
1023d39a76e7Sxw 	 * MC5 configuration.
1024d39a76e7Sxw 	 */
1025d39a76e7Sxw 	p_config->mc5_rtbl_size = ch_mc5_rtbl_size;
1026d39a76e7Sxw 	p_config->mc5_dbsvr_size = ch_mc5_dbsvr_size;
1027d39a76e7Sxw 	p_config->mc5_parity = ch_mc5_parity;
1028d39a76e7Sxw 	p_config->mc5_issue_syn = ch_mc5_issue_syn;
1029d39a76e7Sxw 
1030d39a76e7Sxw 	p_config->offload_ip_cksum = ch_offload_ip_cksum;
1031d39a76e7Sxw 	p_config->offload_udp_cksum = ch_offload_udp_cksum;
1032d39a76e7Sxw 	p_config->offload_tcp_cksum = ch_offload_tcp_cksum;
1033d39a76e7Sxw 
1034d39a76e7Sxw 	p_config->packet_tracing = ch_packet_tracing;
1035d39a76e7Sxw 
1036d39a76e7Sxw 	p_config->server_region_len = ch_server_region_len;
1037d39a76e7Sxw 	p_config->rt_region_len = ch_rt_region_len;
1038d39a76e7Sxw 
1039d39a76e7Sxw 	/*
1040d39a76e7Sxw 	 * Link configuration.
1041d39a76e7Sxw 	 *
1042d39a76e7Sxw 	 * 5-auto-neg 2-1000Gbps; 1-100Gbps; 0-10Gbps
1043d39a76e7Sxw 	 */
1044d39a76e7Sxw 	p_config->link_speed = ch_link_speed;
1045d39a76e7Sxw 	p_config->num_of_ports = ch_num_of_ports;
1046d39a76e7Sxw 
1047d39a76e7Sxw 	/*
1048d39a76e7Sxw 	 * Catp options
1049d39a76e7Sxw 	 */
1050d39a76e7Sxw 	p_config->cat_opt0 = ch_cat_opt0;
1051d39a76e7Sxw 	p_config->cat_opt1 = ch_cat_opt1;
1052d39a76e7Sxw 
1053d39a76e7Sxw 	/*
1054d39a76e7Sxw 	 * SGE configuration.
1055d39a76e7Sxw 	 */
1056d39a76e7Sxw 	p_config->sge_cmdq0_cnt = ch_sge_cmdq0_cnt;
1057d39a76e7Sxw 	p_config->sge_cmdq1_cnt = ch_sge_cmdq1_cnt;
1058d39a76e7Sxw 	p_config->sge_flq0_cnt = ch_sge_flq0_cnt;
1059d39a76e7Sxw 	p_config->sge_flq1_cnt = ch_sge_flq1_cnt;
1060d39a76e7Sxw 	p_config->sge_respq_cnt = ch_sge_respq_cnt;
1061d39a76e7Sxw 
1062d39a76e7Sxw 	p_config->phy_rx_fifo = ch_phy_rx_fifo;
1063d39a76e7Sxw 	p_config->phy_tx_fifo = ch_phy_tx_fifo;
1064d39a76e7Sxw 
1065d39a76e7Sxw 	p_config->sge_cmdq_threshold = ch_sge_cmdq_threshold;
1066d39a76e7Sxw 
1067d39a76e7Sxw 	p_config->sge_flq_threshold = ch_sge_flq_threshold;
1068d39a76e7Sxw 
1069d39a76e7Sxw 	p_config->phy_force_master = ch_phy_force_master;
1070d39a76e7Sxw 
1071d39a76e7Sxw 	p_config->rb_num_of_entries = ch_rb_num_of_entries;
1072d39a76e7Sxw 
1073d39a76e7Sxw 	p_config->rb_size_of_entries = ch_rb_size_of_entries;
1074d39a76e7Sxw 
1075d39a76e7Sxw 	p_config->rb_flag = ch_rb_flag;
1076d39a76e7Sxw 
1077d39a76e7Sxw 	p_config->exit_early = ch_exit_early;
1078d39a76e7Sxw 
1079d39a76e7Sxw 	p_config->chip = ch_chip;
1080d39a76e7Sxw 
1081d39a76e7Sxw 	p_config->stats = ch_stats;
1082d39a76e7Sxw 
1083d39a76e7Sxw 	p_config->tx_delay_us = ch_tx_delay_us;
1084d39a76e7Sxw 
1085d39a76e7Sxw 	return (0);
1086d39a76e7Sxw }
1087d39a76e7Sxw 
1088d39a76e7Sxw static const struct board_info *
pe_sa_init(ch_t * sa)1089d39a76e7Sxw pe_sa_init(ch_t *sa)
1090d39a76e7Sxw {
1091d39a76e7Sxw 	uint16_t device_id;
1092d39a76e7Sxw 	uint16_t device_subid;
1093d39a76e7Sxw 	const struct board_info *bi;
1094d39a76e7Sxw 
1095d39a76e7Sxw 	sa->config = sa->config_data.global_config;
1096d39a76e7Sxw 	device_id = pci_config_get16(sa->ch_hpci, 2);
1097d39a76e7Sxw 	device_subid = pci_config_get16(sa->ch_hpci, 0x2e);
1098d39a76e7Sxw 
1099d39a76e7Sxw 	bi = t1_get_board_info_from_ids(device_id, device_subid);
1100d39a76e7Sxw 	if (bi == NULL) {
1101d39a76e7Sxw 		cmn_err(CE_NOTE,
1102d39a76e7Sxw 		    "The adapter with device_id %d %d is not supported.\n",
1103d39a76e7Sxw 		    device_id, device_subid);
1104d39a76e7Sxw 		return (NULL);
1105d39a76e7Sxw 	}
1106d39a76e7Sxw 
1107d39a76e7Sxw 	if (t1_get_board_rev(sa, bi, &sa->params)) {
1108d39a76e7Sxw 		cmn_err(CE_NOTE, "unknown device_id %d %d\n",
1109d39a76e7Sxw 		    device_id, device_subid);
1110d39a76e7Sxw 		return ((const struct board_info *)NULL);
1111d39a76e7Sxw 	}
1112d39a76e7Sxw 
1113d39a76e7Sxw 	return (bi);
1114d39a76e7Sxw }
1115d39a76e7Sxw 
1116d39a76e7Sxw /*
1117d39a76e7Sxw  * allocate pool of small receive buffers (with vaddr & paddr) and
1118d39a76e7Sxw  * receiver buffer control structure (ch_esb_t *rbp).
1119d39a76e7Sxw  * XXX we should allow better tuning of the # of preallocated
1120d39a76e7Sxw  * free buffers against the # of freelist entries.
1121d39a76e7Sxw  */
1122d39a76e7Sxw static int
pe_small_rbuf_pool_init(ch_t * sa)1123d39a76e7Sxw pe_small_rbuf_pool_init(ch_t *sa)
1124d39a76e7Sxw {
1125d39a76e7Sxw 	int i;
1126d39a76e7Sxw 	ch_esb_t *rbp;
1127d39a76e7Sxw 	extern uint32_t sge_flq0_cnt;
1128d39a76e7Sxw 	extern uint32_t sge_flq1_cnt;
1129d39a76e7Sxw 	int size;
1130d39a76e7Sxw 	uint32_t j;
1131d39a76e7Sxw 
1132d39a76e7Sxw 	if (is_T2(sa))
1133d39a76e7Sxw 		size = sge_flq1_cnt * fl_sz_multiplier;
1134d39a76e7Sxw 	else
1135d39a76e7Sxw 		size = sge_flq0_cnt * fl_sz_multiplier;
1136d39a76e7Sxw 
1137d39a76e7Sxw 	mutex_init(&sa->ch_small_esbl, NULL, MUTEX_DRIVER, sa->ch_icookp);
1138d39a76e7Sxw 
1139d39a76e7Sxw 	mutex_enter(&in_use_l);
1140d39a76e7Sxw 	j = in_use_index++;
1141d39a76e7Sxw 	if (in_use_index >= SZ_INUSE)
1142d39a76e7Sxw 		in_use_index = 0;
1143d39a76e7Sxw 	mutex_exit(&in_use_l);
1144d39a76e7Sxw 
1145d39a76e7Sxw 	sa->ch_small_owner = NULL;
1146d39a76e7Sxw 	sa->ch_sm_index = j;
1147d39a76e7Sxw 	sa->ch_small_esb_free = NULL;
1148d39a76e7Sxw 	for (i = 0; i < size; i++) {
1149d39a76e7Sxw 		rbp = ch_alloc_small_esbbuf(sa, j);
1150d39a76e7Sxw 		if (rbp == NULL)
1151d39a76e7Sxw 			goto error;
1152d39a76e7Sxw 		/*
1153d39a76e7Sxw 		 * add entry to free list
1154d39a76e7Sxw 		 */
1155d39a76e7Sxw 		rbp->cs_next = sa->ch_small_esb_free;
1156d39a76e7Sxw 		sa->ch_small_esb_free = rbp;
1157d39a76e7Sxw 
1158d39a76e7Sxw 		/*
1159d39a76e7Sxw 		 * add entry to owned list
1160d39a76e7Sxw 		 */
1161d39a76e7Sxw 		rbp->cs_owner = sa->ch_small_owner;
1162d39a76e7Sxw 		sa->ch_small_owner = rbp;
1163d39a76e7Sxw 	}
1164d39a76e7Sxw 	return (1);
1165d39a76e7Sxw 
1166d39a76e7Sxw error:
1167d39a76e7Sxw 	sa->ch_small_owner = NULL;
1168d39a76e7Sxw 
1169d39a76e7Sxw 	/* free whatever we've already allocated */
1170d39a76e7Sxw 	pe_rbuf_pool_free(sa);
1171d39a76e7Sxw 
1172d39a76e7Sxw 	return (0);
1173d39a76e7Sxw }
1174d39a76e7Sxw 
1175d39a76e7Sxw /*
1176d39a76e7Sxw  * allocate pool of receive buffers (with vaddr & paddr) and
1177d39a76e7Sxw  * receiver buffer control structure (ch_esb_t *rbp).
1178d39a76e7Sxw  * XXX we should allow better tuning of the # of preallocated
1179d39a76e7Sxw  * free buffers against the # of freelist entries.
1180d39a76e7Sxw  */
1181d39a76e7Sxw static int
pe_big_rbuf_pool_init(ch_t * sa)1182d39a76e7Sxw pe_big_rbuf_pool_init(ch_t *sa)
1183d39a76e7Sxw {
1184d39a76e7Sxw 	int i;
1185d39a76e7Sxw 	ch_esb_t *rbp;
1186d39a76e7Sxw 	extern uint32_t sge_flq0_cnt;
1187d39a76e7Sxw 	extern uint32_t sge_flq1_cnt;
1188d39a76e7Sxw 	int size;
1189d39a76e7Sxw 	uint32_t j;
1190d39a76e7Sxw 
1191d39a76e7Sxw 	if (is_T2(sa))
1192d39a76e7Sxw 		size = sge_flq0_cnt * fl_sz_multiplier;
1193d39a76e7Sxw 	else
1194d39a76e7Sxw 		size = sge_flq1_cnt * fl_sz_multiplier;
1195d39a76e7Sxw 
1196d39a76e7Sxw 	mutex_init(&sa->ch_big_esbl, NULL, MUTEX_DRIVER, sa->ch_icookp);
1197d39a76e7Sxw 
1198d39a76e7Sxw 	mutex_enter(&in_use_l);
1199d39a76e7Sxw 	j = in_use_index++;
1200d39a76e7Sxw 	if (in_use_index >= SZ_INUSE)
1201d39a76e7Sxw 		in_use_index = 0;
1202d39a76e7Sxw 	mutex_exit(&in_use_l);
1203d39a76e7Sxw 
1204d39a76e7Sxw 	sa->ch_big_owner = NULL;
1205d39a76e7Sxw 	sa->ch_big_index = j;
1206d39a76e7Sxw 	sa->ch_big_esb_free = NULL;
1207d39a76e7Sxw 	for (i = 0; i < size; i++) {
1208d39a76e7Sxw 		rbp = ch_alloc_big_esbbuf(sa, j);
1209d39a76e7Sxw 		if (rbp == NULL)
1210d39a76e7Sxw 			goto error;
1211d39a76e7Sxw 		rbp->cs_next = sa->ch_big_esb_free;
1212d39a76e7Sxw 		sa->ch_big_esb_free = rbp;
1213d39a76e7Sxw 
1214d39a76e7Sxw 		/*
1215d39a76e7Sxw 		 * add entry to owned list
1216d39a76e7Sxw 		 */
1217d39a76e7Sxw 		rbp->cs_owner = sa->ch_big_owner;
1218d39a76e7Sxw 		sa->ch_big_owner = rbp;
1219d39a76e7Sxw 	}
1220d39a76e7Sxw 	return (1);
1221d39a76e7Sxw 
1222d39a76e7Sxw error:
1223d39a76e7Sxw 	sa->ch_big_owner = NULL;
1224d39a76e7Sxw 
1225d39a76e7Sxw 	/* free whatever we've already allocated */
1226d39a76e7Sxw 	pe_rbuf_pool_free(sa);
1227d39a76e7Sxw 
1228d39a76e7Sxw 	return (0);
1229d39a76e7Sxw }
1230d39a76e7Sxw 
1231d39a76e7Sxw /*
1232d39a76e7Sxw  * allocate receive buffer structure and dma mapped buffer (SGE_SM_BUF_SZ bytes)
1233d39a76e7Sxw  * note that we will DMA at a 2 byte offset for Solaris when checksum offload
1234d39a76e7Sxw  * is enabled.
1235d39a76e7Sxw  */
1236d39a76e7Sxw static ch_esb_t *
ch_alloc_small_esbbuf(ch_t * sa,uint32_t i)1237d39a76e7Sxw ch_alloc_small_esbbuf(ch_t *sa, uint32_t i)
1238d39a76e7Sxw {
1239d39a76e7Sxw 	ch_esb_t *rbp;
1240d39a76e7Sxw 
1241d39a76e7Sxw 	rbp = (ch_esb_t *)kmem_zalloc(sizeof (ch_esb_t), KM_SLEEP);
1242d39a76e7Sxw 	if (rbp == NULL) {
1243d39a76e7Sxw 		return ((ch_esb_t *)0);
1244d39a76e7Sxw 	}
1245d39a76e7Sxw 
1246d39a76e7Sxw #if BYTE_ORDER == BIG_ENDIAN
1247d39a76e7Sxw 	rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 1, DMA_STREAM|DMA_SMALN,
1248d39a76e7Sxw 	    SGE_SM_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1249d39a76e7Sxw #else
1250d39a76e7Sxw 	rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 0, DMA_STREAM|DMA_SMALN,
1251d39a76e7Sxw 	    SGE_SM_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1252d39a76e7Sxw #endif
1253d39a76e7Sxw 
1254d39a76e7Sxw 	if (rbp->cs_buf == NULL) {
1255d39a76e7Sxw 		kmem_free(rbp, sizeof (ch_esb_t));
1256d39a76e7Sxw 		return ((ch_esb_t *)0);
1257d39a76e7Sxw 	}
1258d39a76e7Sxw 
1259d39a76e7Sxw 	rbp->cs_sa = sa;
1260d39a76e7Sxw 	rbp->cs_index = i;
1261d39a76e7Sxw 
1262d39a76e7Sxw 	rbp->cs_frtn.free_func = (void (*)())&ch_small_rbuf_recycle;
1263d39a76e7Sxw 	rbp->cs_frtn.free_arg  = (caddr_t)rbp;
1264d39a76e7Sxw 
1265d39a76e7Sxw 	return (rbp);
1266d39a76e7Sxw }
1267d39a76e7Sxw 
1268d39a76e7Sxw /*
1269d39a76e7Sxw  * allocate receive buffer structure and dma mapped buffer (SGE_BG_BUF_SZ bytes)
1270d39a76e7Sxw  * note that we will DMA at a 2 byte offset for Solaris when checksum offload
1271d39a76e7Sxw  * is enabled.
1272d39a76e7Sxw  */
1273d39a76e7Sxw static ch_esb_t *
ch_alloc_big_esbbuf(ch_t * sa,uint32_t i)1274d39a76e7Sxw ch_alloc_big_esbbuf(ch_t *sa, uint32_t i)
1275d39a76e7Sxw {
1276d39a76e7Sxw 	ch_esb_t *rbp;
1277d39a76e7Sxw 
1278d39a76e7Sxw 	rbp = (ch_esb_t *)kmem_zalloc(sizeof (ch_esb_t), KM_SLEEP);
1279d39a76e7Sxw 	if (rbp == NULL) {
1280d39a76e7Sxw 		return ((ch_esb_t *)0);
1281d39a76e7Sxw 	}
1282d39a76e7Sxw 
1283d39a76e7Sxw #if BYTE_ORDER == BIG_ENDIAN
1284d39a76e7Sxw 	rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 1, DMA_STREAM|DMA_BGALN,
1285d39a76e7Sxw 	    SGE_BG_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1286d39a76e7Sxw #else
1287d39a76e7Sxw 	rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 0, DMA_STREAM|DMA_BGALN,
1288d39a76e7Sxw 	    SGE_BG_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1289d39a76e7Sxw #endif
1290d39a76e7Sxw 
1291d39a76e7Sxw 	if (rbp->cs_buf == NULL) {
1292d39a76e7Sxw 		kmem_free(rbp, sizeof (ch_esb_t));
1293d39a76e7Sxw 		return ((ch_esb_t *)0);
1294d39a76e7Sxw 	}
1295d39a76e7Sxw 
1296d39a76e7Sxw 	rbp->cs_sa = sa;
1297d39a76e7Sxw 	rbp->cs_index = i;
1298d39a76e7Sxw 
1299d39a76e7Sxw 	rbp->cs_frtn.free_func = (void (*)())&ch_big_rbuf_recycle;
1300d39a76e7Sxw 	rbp->cs_frtn.free_arg  = (caddr_t)rbp;
1301d39a76e7Sxw 
1302d39a76e7Sxw 	return (rbp);
1303d39a76e7Sxw }
1304d39a76e7Sxw 
1305d39a76e7Sxw /*
1306d39a76e7Sxw  * free entries on the receive buffer list.
1307d39a76e7Sxw  */
1308d39a76e7Sxw void
pe_rbuf_pool_free(ch_t * sa)1309d39a76e7Sxw pe_rbuf_pool_free(ch_t *sa)
1310d39a76e7Sxw {
1311d39a76e7Sxw 	ch_esb_t *rbp;
1312d39a76e7Sxw 
1313d39a76e7Sxw 	mutex_enter(&sa->ch_small_esbl);
1314d39a76e7Sxw 
1315d39a76e7Sxw 	/*
1316d39a76e7Sxw 	 * Now set-up the rest to commit suicide.
1317d39a76e7Sxw 	 */
1318d39a76e7Sxw 	while (sa->ch_small_owner) {
1319d39a76e7Sxw 		rbp = sa->ch_small_owner;
1320d39a76e7Sxw 		sa->ch_small_owner = rbp->cs_owner;
1321d39a76e7Sxw 		rbp->cs_owner = NULL;
1322d39a76e7Sxw 		rbp->cs_flag = 1;
1323d39a76e7Sxw 	}
1324d39a76e7Sxw 
1325d39a76e7Sxw 	while ((rbp = sa->ch_small_esb_free) != NULL) {
1326d39a76e7Sxw 		/* advance head ptr to next entry */
1327d39a76e7Sxw 		sa->ch_small_esb_free = rbp->cs_next;
1328d39a76e7Sxw 		/* free private buffer allocated in ch_alloc_esbbuf() */
1329d39a76e7Sxw 		ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1330d39a76e7Sxw 		/* free descripter buffer */
1331d39a76e7Sxw 		kmem_free(rbp, sizeof (ch_esb_t));
1332d39a76e7Sxw 	}
1333d39a76e7Sxw 
1334d39a76e7Sxw 	mutex_exit(&sa->ch_small_esbl);
1335d39a76e7Sxw 
1336d39a76e7Sxw 	/* destroy ch_esbl lock */
1337d39a76e7Sxw 	mutex_destroy(&sa->ch_small_esbl);
1338d39a76e7Sxw 
1339d39a76e7Sxw 
1340d39a76e7Sxw 	mutex_enter(&sa->ch_big_esbl);
1341d39a76e7Sxw 
1342d39a76e7Sxw 	/*
1343d39a76e7Sxw 	 * Now set-up the rest to commit suicide.
1344d39a76e7Sxw 	 */
1345d39a76e7Sxw 	while (sa->ch_big_owner) {
1346d39a76e7Sxw 		rbp = sa->ch_big_owner;
1347d39a76e7Sxw 		sa->ch_big_owner = rbp->cs_owner;
1348d39a76e7Sxw 		rbp->cs_owner = NULL;
1349d39a76e7Sxw 		rbp->cs_flag = 1;
1350d39a76e7Sxw 	}
1351d39a76e7Sxw 
1352d39a76e7Sxw 	while ((rbp = sa->ch_big_esb_free) != NULL) {
1353d39a76e7Sxw 		/* advance head ptr to next entry */
1354d39a76e7Sxw 		sa->ch_big_esb_free = rbp->cs_next;
1355d39a76e7Sxw 		/* free private buffer allocated in ch_alloc_esbbuf() */
1356d39a76e7Sxw 		ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1357d39a76e7Sxw 		/* free descripter buffer */
1358d39a76e7Sxw 		kmem_free(rbp, sizeof (ch_esb_t));
1359d39a76e7Sxw 	}
1360d39a76e7Sxw 
1361d39a76e7Sxw 	mutex_exit(&sa->ch_big_esbl);
1362d39a76e7Sxw 
1363d39a76e7Sxw 	/* destroy ch_esbl lock */
1364d39a76e7Sxw 	mutex_destroy(&sa->ch_big_esbl);
1365d39a76e7Sxw }
1366d39a76e7Sxw 
1367d39a76e7Sxw void
ch_small_rbuf_recycle(ch_esb_t * rbp)1368d39a76e7Sxw ch_small_rbuf_recycle(ch_esb_t *rbp)
1369d39a76e7Sxw {
1370d39a76e7Sxw 	ch_t *sa = rbp->cs_sa;
1371d39a76e7Sxw 
1372d39a76e7Sxw 	if (rbp->cs_flag) {
1373d39a76e7Sxw 		uint32_t i;
1374d39a76e7Sxw 		/*
1375d39a76e7Sxw 		 * free private buffer allocated in ch_alloc_esbbuf()
1376d39a76e7Sxw 		 */
1377d39a76e7Sxw 		ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1378d39a76e7Sxw 
1379d39a76e7Sxw 		i = rbp->cs_index;
1380d39a76e7Sxw 
1381d39a76e7Sxw 		/*
1382d39a76e7Sxw 		 * free descripter buffer
1383d39a76e7Sxw 		 */
1384d39a76e7Sxw 		kmem_free(rbp, sizeof (ch_esb_t));
1385d39a76e7Sxw 
1386d39a76e7Sxw 		/*
1387d39a76e7Sxw 		 * decrement count of receive buffers freed by callback
1388d39a76e7Sxw 		 * We decrement here so anyone trying to do fini will
1389d39a76e7Sxw 		 * only remove the driver once the counts go to 0.
1390d39a76e7Sxw 		 */
13911a5e258fSJosef 'Jeff' Sipek 		atomic_dec_32(&buffers_in_use[i]);
1392d39a76e7Sxw 
1393d39a76e7Sxw 		return;
1394d39a76e7Sxw 	}
1395d39a76e7Sxw 
1396d39a76e7Sxw 	mutex_enter(&sa->ch_small_esbl);
1397d39a76e7Sxw 	rbp->cs_next = sa->ch_small_esb_free;
1398d39a76e7Sxw 	sa->ch_small_esb_free = rbp;
1399d39a76e7Sxw 	mutex_exit(&sa->ch_small_esbl);
1400d39a76e7Sxw 
1401d39a76e7Sxw 	/*
1402d39a76e7Sxw 	 * decrement count of receive buffers freed by callback
1403d39a76e7Sxw 	 */
14041a5e258fSJosef 'Jeff' Sipek 	atomic_dec_32(&buffers_in_use[rbp->cs_index]);
1405d39a76e7Sxw }
1406d39a76e7Sxw 
1407d39a76e7Sxw /*
1408d39a76e7Sxw  * callback function from freeb() when esballoced mblk freed.
1409d39a76e7Sxw  */
1410d39a76e7Sxw void
ch_big_rbuf_recycle(ch_esb_t * rbp)1411d39a76e7Sxw ch_big_rbuf_recycle(ch_esb_t *rbp)
1412d39a76e7Sxw {
1413d39a76e7Sxw 	ch_t *sa = rbp->cs_sa;
1414d39a76e7Sxw 
1415d39a76e7Sxw 	if (rbp->cs_flag) {
1416d39a76e7Sxw 		uint32_t i;
1417d39a76e7Sxw 		/*
1418d39a76e7Sxw 		 * free private buffer allocated in ch_alloc_esbbuf()
1419d39a76e7Sxw 		 */
1420d39a76e7Sxw 		ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1421d39a76e7Sxw 
1422d39a76e7Sxw 		i = rbp->cs_index;
1423d39a76e7Sxw 
1424d39a76e7Sxw 		/*
1425d39a76e7Sxw 		 * free descripter buffer
1426d39a76e7Sxw 		 */
1427d39a76e7Sxw 		kmem_free(rbp, sizeof (ch_esb_t));
1428d39a76e7Sxw 
1429d39a76e7Sxw 		/*
1430d39a76e7Sxw 		 * decrement count of receive buffers freed by callback
1431d39a76e7Sxw 		 * We decrement here so anyone trying to do fini will
1432d39a76e7Sxw 		 * only remove the driver once the counts go to 0.
1433d39a76e7Sxw 		 */
14341a5e258fSJosef 'Jeff' Sipek 		atomic_dec_32(&buffers_in_use[i]);
1435d39a76e7Sxw 
1436d39a76e7Sxw 		return;
1437d39a76e7Sxw 	}
1438d39a76e7Sxw 
1439d39a76e7Sxw 	mutex_enter(&sa->ch_big_esbl);
1440d39a76e7Sxw 	rbp->cs_next = sa->ch_big_esb_free;
1441d39a76e7Sxw 	sa->ch_big_esb_free = rbp;
1442d39a76e7Sxw 	mutex_exit(&sa->ch_big_esbl);
1443d39a76e7Sxw 
1444d39a76e7Sxw 	/*
1445d39a76e7Sxw 	 * decrement count of receive buffers freed by callback
1446d39a76e7Sxw 	 */
14471a5e258fSJosef 'Jeff' Sipek 	atomic_dec_32(&buffers_in_use[rbp->cs_index]);
1448d39a76e7Sxw }
1449d39a76e7Sxw 
1450d39a76e7Sxw /*
1451d39a76e7Sxw  * get a pre-allocated, pre-mapped receive buffer from free list.
1452d39a76e7Sxw  * (used sge.c)
1453d39a76e7Sxw  */
1454d39a76e7Sxw ch_esb_t *
ch_get_small_rbuf(ch_t * sa)1455d39a76e7Sxw ch_get_small_rbuf(ch_t *sa)
1456d39a76e7Sxw {
1457d39a76e7Sxw 	ch_esb_t *rbp;
1458d39a76e7Sxw 
1459d39a76e7Sxw 	mutex_enter(&sa->ch_small_esbl);
1460d39a76e7Sxw 	rbp = sa->ch_small_esb_free;
1461d39a76e7Sxw 	if (rbp) {
1462d39a76e7Sxw 		sa->ch_small_esb_free = rbp->cs_next;
1463d39a76e7Sxw 	}
1464d39a76e7Sxw 	mutex_exit(&sa->ch_small_esbl);
1465d39a76e7Sxw 
1466d39a76e7Sxw 	return (rbp);
1467d39a76e7Sxw }
1468d39a76e7Sxw 
1469d39a76e7Sxw /*
1470d39a76e7Sxw  * get a pre-allocated, pre-mapped receive buffer from free list.
1471d39a76e7Sxw  * (used sge.c)
1472d39a76e7Sxw  */
1473d39a76e7Sxw 
1474d39a76e7Sxw ch_esb_t *
ch_get_big_rbuf(ch_t * sa)1475d39a76e7Sxw ch_get_big_rbuf(ch_t *sa)
1476d39a76e7Sxw {
1477d39a76e7Sxw 	ch_esb_t *rbp;
1478d39a76e7Sxw 
1479d39a76e7Sxw 	mutex_enter(&sa->ch_big_esbl);
1480d39a76e7Sxw 	rbp = sa->ch_big_esb_free;
1481d39a76e7Sxw 	if (rbp) {
1482d39a76e7Sxw 		sa->ch_big_esb_free = rbp->cs_next;
1483d39a76e7Sxw 	}
1484d39a76e7Sxw 	mutex_exit(&sa->ch_big_esbl);
1485d39a76e7Sxw 
1486d39a76e7Sxw 	return (rbp);
1487d39a76e7Sxw }
1488d39a76e7Sxw 
1489d39a76e7Sxw void
pe_detach(ch_t * sa)1490d39a76e7Sxw pe_detach(ch_t *sa)
1491d39a76e7Sxw {
1492d39a76e7Sxw 	(void) sge_stop(sa->sge);
1493d39a76e7Sxw 
1494d39a76e7Sxw 	pe_free_driver_resources(sa);
1495d39a76e7Sxw }
1496d39a76e7Sxw 
1497d39a76e7Sxw static void
pe_free_driver_resources(ch_t * sa)1498d39a76e7Sxw pe_free_driver_resources(ch_t *sa)
1499d39a76e7Sxw {
1500d39a76e7Sxw 	if (sa) {
1501d39a76e7Sxw 		t1_free_sw_modules(sa);
1502d39a76e7Sxw 
1503d39a76e7Sxw 		/* free pool of receive buffers */
1504d39a76e7Sxw 		pe_rbuf_pool_free(sa);
1505d39a76e7Sxw 	}
1506d39a76e7Sxw }
1507d39a76e7Sxw 
1508d39a76e7Sxw /*
1509d39a76e7Sxw  * Processes elmer0 external interrupts in process context.
1510d39a76e7Sxw  */
1511d39a76e7Sxw static void
ext_intr_task(ch_t * adapter)1512d39a76e7Sxw ext_intr_task(ch_t *adapter)
1513d39a76e7Sxw {
1514d39a76e7Sxw 	u32 enable;
1515d39a76e7Sxw 
1516d39a76e7Sxw 	(void) elmer0_ext_intr_handler(adapter);
1517d39a76e7Sxw 
1518d39a76e7Sxw 	/* Now reenable external interrupts */
1519d39a76e7Sxw 	t1_write_reg_4(adapter, A_PL_CAUSE, F_PL_INTR_EXT);
1520d39a76e7Sxw 	enable = t1_read_reg_4(adapter, A_PL_ENABLE);
1521d39a76e7Sxw 	t1_write_reg_4(adapter, A_PL_ENABLE, enable | F_PL_INTR_EXT);
1522d39a76e7Sxw 	adapter->slow_intr_mask |= F_PL_INTR_EXT;
1523d39a76e7Sxw }
1524d39a76e7Sxw 
1525d39a76e7Sxw /*
1526d39a76e7Sxw  * Interrupt-context handler for elmer0 external interrupts.
1527d39a76e7Sxw  */
1528d39a76e7Sxw void
t1_os_elmer0_ext_intr(ch_t * adapter)1529d39a76e7Sxw t1_os_elmer0_ext_intr(ch_t *adapter)
1530d39a76e7Sxw {
1531d39a76e7Sxw 	u32 enable = t1_read_reg_4(adapter, A_PL_ENABLE);
1532d39a76e7Sxw 
1533d39a76e7Sxw 	adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
1534d39a76e7Sxw 	t1_write_reg_4(adapter, A_PL_ENABLE, enable & ~F_PL_INTR_EXT);
1535d39a76e7Sxw #ifdef NOTYET
1536d39a76e7Sxw 	schedule_work(&adapter->ext_intr_handler_task);
1537d39a76e7Sxw #else
1538d39a76e7Sxw 	ext_intr_task(adapter);
1539d39a76e7Sxw #endif
1540d39a76e7Sxw }
1541d39a76e7Sxw 
1542d39a76e7Sxw uint8_t *
t1_get_next_mcaddr(struct t1_rx_mode * rmp)1543d39a76e7Sxw t1_get_next_mcaddr(struct t1_rx_mode *rmp)
1544d39a76e7Sxw {
1545d39a76e7Sxw 	uint8_t *addr = 0;
1546d39a76e7Sxw 	if (rmp->mc) {
1547d39a76e7Sxw 		addr = rmp->mc->cmc_mca;
1548d39a76e7Sxw 		rmp->mc = rmp->mc->cmc_next;
1549d39a76e7Sxw 	}
1550d39a76e7Sxw 	return (addr);
1551d39a76e7Sxw }
1552d39a76e7Sxw 
1553d39a76e7Sxw void
pe_dma_handle_init(ch_t * chp,int cnt)1554d39a76e7Sxw pe_dma_handle_init(ch_t *chp, int cnt)
1555d39a76e7Sxw {
1556d39a76e7Sxw 	free_dh_t *dhe;
1557d39a76e7Sxw #if defined(__sparc)
1558d39a76e7Sxw 	int tcnt = cnt/2;
1559d39a76e7Sxw 
1560d39a76e7Sxw 	for (; cnt; cnt--) {
1561d39a76e7Sxw 		dhe = ch_get_dvma_handle(chp);
1562d39a76e7Sxw 		if (dhe == NULL)
1563d39a76e7Sxw 			break;
1564d39a76e7Sxw 		mutex_enter(&chp->ch_dh_lck);
1565d39a76e7Sxw 		dhe->dhe_next = chp->ch_vdh;
1566d39a76e7Sxw 		chp->ch_vdh = dhe;
1567d39a76e7Sxw 		mutex_exit(&chp->ch_dh_lck);
1568d39a76e7Sxw 	}
1569d39a76e7Sxw 
1570d39a76e7Sxw 	cnt += tcnt;
1571d39a76e7Sxw #endif
1572d39a76e7Sxw 	while (cnt--) {
1573d39a76e7Sxw 		dhe = ch_get_dma_handle(chp);
1574d39a76e7Sxw 		if (dhe == NULL)
1575d39a76e7Sxw 			return;
1576d39a76e7Sxw 		mutex_enter(&chp->ch_dh_lck);
1577d39a76e7Sxw 		dhe->dhe_next = chp->ch_dh;
1578d39a76e7Sxw 		chp->ch_dh = dhe;
1579d39a76e7Sxw 		mutex_exit(&chp->ch_dh_lck);
1580d39a76e7Sxw 	}
1581d39a76e7Sxw }
1582d39a76e7Sxw 
1583d39a76e7Sxw /*
1584d39a76e7Sxw  * Write new values to the MTU table.  Caller must validate that the new MTUs
1585d39a76e7Sxw  * are in ascending order. params.mtus[] is initialized by init_mtus()
1586d39a76e7Sxw  * called in t1_init_sw_modules().
1587d39a76e7Sxw  */
1588d39a76e7Sxw #define	MTUREG(idx) (A_TP_MTU_REG0 + (idx) * 4)
1589d39a76e7Sxw 
1590d39a76e7Sxw static void
update_mtu_tab(ch_t * adapter)1591d39a76e7Sxw update_mtu_tab(ch_t *adapter)
1592d39a76e7Sxw {
1593d39a76e7Sxw 	int i;
1594d39a76e7Sxw 
1595d39a76e7Sxw 	for (i = 0; i < NMTUS; ++i) {
1596d39a76e7Sxw 		int mtu = (unsigned int)adapter->params.mtus[i];
1597d39a76e7Sxw 
1598d39a76e7Sxw 		t1_write_reg_4(adapter, MTUREG(i), mtu);
1599d39a76e7Sxw 	}
1600d39a76e7Sxw }
1601d39a76e7Sxw 
1602d39a76e7Sxw static int
pe_change_mtu(ch_t * chp)1603d39a76e7Sxw pe_change_mtu(ch_t *chp)
1604d39a76e7Sxw {
1605d39a76e7Sxw 	struct cmac *mac = chp->port[0].mac;
1606d39a76e7Sxw 	int ret;
1607d39a76e7Sxw 
1608d39a76e7Sxw 	if (!mac->ops->set_mtu) {
1609d39a76e7Sxw 		return (EOPNOTSUPP);
1610d39a76e7Sxw 	}
1611d39a76e7Sxw 	if (chp->ch_mtu < 68) {
1612d39a76e7Sxw 		return (EINVAL);
1613d39a76e7Sxw 	}
1614d39a76e7Sxw 	if (ret = mac->ops->set_mtu(mac, chp->ch_mtu)) {
1615d39a76e7Sxw 		return (ret);
1616d39a76e7Sxw 	}
1617d39a76e7Sxw 
1618d39a76e7Sxw 	return (0);
1619d39a76e7Sxw }
1620d39a76e7Sxw 
1621d39a76e7Sxw typedef struct fake_arp {
1622d39a76e7Sxw 	char fa_dst[6];		/* ethernet header */
1623d39a76e7Sxw 	char fa_src[6];		/* ethernet header */
1624d39a76e7Sxw 	ushort_t fa_typ;		/* ethernet header */
1625d39a76e7Sxw 
1626d39a76e7Sxw 	ushort_t fa_hrd;		/* arp */
1627d39a76e7Sxw 	ushort_t fa_pro;
1628d39a76e7Sxw 	char fa_hln;
1629d39a76e7Sxw 	char fa_pln;
1630d39a76e7Sxw 	ushort_t fa_op;
1631d39a76e7Sxw 	char fa_src_mac[6];
1632d39a76e7Sxw 	uint_t fa_src_ip;
1633d39a76e7Sxw 	char fa_dst_mac[6];
1634d39a76e7Sxw 	char fa_dst_ip[4];
1635d39a76e7Sxw } fake_arp_t;
1636d39a76e7Sxw 
1637d39a76e7Sxw /*
1638d39a76e7Sxw  * PR2928 & PR3309
1639d39a76e7Sxw  * construct packet in mblk and attach it to sge structure.
1640d39a76e7Sxw  */
1641d39a76e7Sxw static int
pe_make_fake_arp(ch_t * chp,unsigned char * arpp)1642d39a76e7Sxw pe_make_fake_arp(ch_t *chp, unsigned char *arpp)
1643d39a76e7Sxw {
1644d39a76e7Sxw 	pesge *sge = chp->sge;
1645d39a76e7Sxw 	mblk_t *bp;
1646d39a76e7Sxw 	fake_arp_t *fap;
1647d39a76e7Sxw 	static char buf[6] = {0, 7, 0x43, 0, 0, 0};
1648d39a76e7Sxw 	struct cpl_tx_pkt *cpl;
1649d39a76e7Sxw 
1650d39a76e7Sxw 	bp = allocb(sizeof (struct fake_arp) + SZ_CPL_TX_PKT, BPRI_HI);
1651d39a76e7Sxw 	if (bp == NULL) {
1652d39a76e7Sxw 		return (1);
1653d39a76e7Sxw 	}
1654d39a76e7Sxw 	bzero(bp->b_rptr, sizeof (struct fake_arp) + SZ_CPL_TX_PKT);
1655d39a76e7Sxw 
1656d39a76e7Sxw 	/* fill in cpl header */
1657d39a76e7Sxw 	cpl = (struct cpl_tx_pkt *)bp->b_rptr;
1658d39a76e7Sxw 	cpl->opcode = CPL_TX_PKT;
1659d39a76e7Sxw 	cpl->iff = 0;			/* XXX port 0 needs fixing with NEMO */
1660d39a76e7Sxw 	cpl->ip_csum_dis = 1;		/* no IP header cksum */
1661d39a76e7Sxw 	cpl->l4_csum_dis = 1;		/* no tcp/udp cksum */
1662d39a76e7Sxw 	cpl->vlan_valid = 0;		/* no vlan */
1663d39a76e7Sxw 
1664d39a76e7Sxw 	fap = (fake_arp_t *)&bp->b_rptr[SZ_CPL_TX_PKT];
1665d39a76e7Sxw 
1666d39a76e7Sxw 	bcopy(arpp, fap, sizeof (*fap));	/* copy first arp to mblk */
1667d39a76e7Sxw 
1668d39a76e7Sxw 	bcopy(buf, fap->fa_dst, 6);		/* overwrite dst mac */
1669d39a76e7Sxw 	chp->ch_ip = fap->fa_src_ip;		/* not used yet */
1670d39a76e7Sxw 	bcopy(buf, fap->fa_dst_mac, 6);		/* overwrite dst mac */
1671d39a76e7Sxw 
1672d39a76e7Sxw 	bp->b_wptr = bp->b_rptr + sizeof (struct fake_arp)+SZ_CPL_TX_PKT;
1673d39a76e7Sxw 
1674d39a76e7Sxw 	sge_add_fake_arp(sge, (void *)bp);
1675d39a76e7Sxw 
1676d39a76e7Sxw 	return (0);
1677d39a76e7Sxw }
1678d39a76e7Sxw 
1679d39a76e7Sxw /*
1680d39a76e7Sxw  * PR2928 & PR3309
1681d39a76e7Sxw  * free the fake arp's mblk on sge structure.
1682d39a76e7Sxw  */
1683d39a76e7Sxw void
pe_free_fake_arp(void * arp)1684d39a76e7Sxw pe_free_fake_arp(void *arp)
1685d39a76e7Sxw {
1686d39a76e7Sxw 	mblk_t *bp = (mblk_t *)(arp);
1687d39a76e7Sxw 
1688d39a76e7Sxw 	freemsg(bp);
1689d39a76e7Sxw }
1690d39a76e7Sxw 
1691d39a76e7Sxw /*
1692d39a76e7Sxw  * extract ip address of nic from first outgoing arp.
1693d39a76e7Sxw  */
1694d39a76e7Sxw static uint32_t
pe_get_ip(unsigned char * arpp)1695d39a76e7Sxw pe_get_ip(unsigned char *arpp)
1696d39a76e7Sxw {
1697d39a76e7Sxw 	fake_arp_t fap;
1698d39a76e7Sxw 
1699d39a76e7Sxw 	/*
1700d39a76e7Sxw 	 * first copy packet to buffer so we know
1701d39a76e7Sxw 	 * it will be properly aligned.
1702d39a76e7Sxw 	 */
1703d39a76e7Sxw 	bcopy(arpp, &fap, sizeof (fap));	/* copy first arp to buffer */
1704d39a76e7Sxw 	return (fap.fa_src_ip);
1705d39a76e7Sxw }
1706d39a76e7Sxw 
1707d39a76e7Sxw /* ARGSUSED */
1708d39a76e7Sxw void
t1_os_link_changed(ch_t * obj,int port_id,int link_status,int speed,int duplex,int fc)1709d39a76e7Sxw t1_os_link_changed(ch_t *obj, int port_id, int link_status,
1710d39a76e7Sxw     int speed, int duplex, int fc)
1711d39a76e7Sxw {
1712d39a76e7Sxw 	gld_mac_info_t *macinfo = obj->ch_macp;
1713d39a76e7Sxw 	if (link_status) {
1714d39a76e7Sxw 		gld_linkstate(macinfo, GLD_LINKSTATE_UP);
1715d39a76e7Sxw 		/*
1716d39a76e7Sxw 		 * Link states should be reported to user
1717d39a76e7Sxw 		 * whenever it changes
1718d39a76e7Sxw 		 */
1719d39a76e7Sxw 		cmn_err(CE_NOTE, "%s: link is up", adapter_name(obj));
1720d39a76e7Sxw 	} else {
1721d39a76e7Sxw 		gld_linkstate(macinfo, GLD_LINKSTATE_DOWN);
1722d39a76e7Sxw 		/*
1723d39a76e7Sxw 		 * Link states should be reported to user
1724d39a76e7Sxw 		 * whenever it changes
1725d39a76e7Sxw 		 */
1726d39a76e7Sxw 		cmn_err(CE_NOTE, "%s: link is down", adapter_name(obj));
1727d39a76e7Sxw 	}
1728d39a76e7Sxw }
1729