xref: /onnv-gate/usr/src/uts/intel/io/dnet/dnet.c (revision 9860)
1*9860Sgdamore@opensolaris.org /*
2*9860Sgdamore@opensolaris.org  * CDDL HEADER START
3*9860Sgdamore@opensolaris.org  *
4*9860Sgdamore@opensolaris.org  * The contents of this file are subject to the terms of the
5*9860Sgdamore@opensolaris.org  * Common Development and Distribution License (the "License").
6*9860Sgdamore@opensolaris.org  * You may not use this file except in compliance with the License.
7*9860Sgdamore@opensolaris.org  *
8*9860Sgdamore@opensolaris.org  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9860Sgdamore@opensolaris.org  * or http://www.opensolaris.org/os/licensing.
10*9860Sgdamore@opensolaris.org  * See the License for the specific language governing permissions
11*9860Sgdamore@opensolaris.org  * and limitations under the License.
12*9860Sgdamore@opensolaris.org  *
13*9860Sgdamore@opensolaris.org  * When distributing Covered Code, include this CDDL HEADER in each
14*9860Sgdamore@opensolaris.org  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9860Sgdamore@opensolaris.org  * If applicable, add the following below this CDDL HEADER, with the
16*9860Sgdamore@opensolaris.org  * fields enclosed by brackets "[]" replaced with your own identifying
17*9860Sgdamore@opensolaris.org  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9860Sgdamore@opensolaris.org  *
19*9860Sgdamore@opensolaris.org  * CDDL HEADER END
20*9860Sgdamore@opensolaris.org  */
21*9860Sgdamore@opensolaris.org 
22*9860Sgdamore@opensolaris.org /*
23*9860Sgdamore@opensolaris.org  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*9860Sgdamore@opensolaris.org  * Use is subject to license terms.
25*9860Sgdamore@opensolaris.org  */
26*9860Sgdamore@opensolaris.org 
27*9860Sgdamore@opensolaris.org 
28*9860Sgdamore@opensolaris.org /*
29*9860Sgdamore@opensolaris.org  * dnet -- DEC 21x4x
30*9860Sgdamore@opensolaris.org  *
31*9860Sgdamore@opensolaris.org  * Currently supports:
32*9860Sgdamore@opensolaris.org  *	21040, 21041, 21140, 21142, 21143
33*9860Sgdamore@opensolaris.org  *	SROM versions 1, 3, 3.03, 4
34*9860Sgdamore@opensolaris.org  *	TP, AUI, BNC, 100BASETX, 100BASET4
35*9860Sgdamore@opensolaris.org  *
36*9860Sgdamore@opensolaris.org  * XXX NEEDSWORK
37*9860Sgdamore@opensolaris.org  *	All media SHOULD work, FX is untested
38*9860Sgdamore@opensolaris.org  *
39*9860Sgdamore@opensolaris.org  * Depends on the Generic LAN Driver utility functions in /kernel/misc/gld
40*9860Sgdamore@opensolaris.org  */
41*9860Sgdamore@opensolaris.org 
42*9860Sgdamore@opensolaris.org #define	BUG_4010796	/* See 4007871, 4010796 */
43*9860Sgdamore@opensolaris.org 
44*9860Sgdamore@opensolaris.org #include <sys/types.h>
45*9860Sgdamore@opensolaris.org #include <sys/errno.h>
46*9860Sgdamore@opensolaris.org #include <sys/param.h>
47*9860Sgdamore@opensolaris.org #include <sys/stropts.h>
48*9860Sgdamore@opensolaris.org #include <sys/stream.h>
49*9860Sgdamore@opensolaris.org #include <sys/kmem.h>
50*9860Sgdamore@opensolaris.org #include <sys/conf.h>
51*9860Sgdamore@opensolaris.org #include <sys/devops.h>
52*9860Sgdamore@opensolaris.org #include <sys/ksynch.h>
53*9860Sgdamore@opensolaris.org #include <sys/stat.h>
54*9860Sgdamore@opensolaris.org #include <sys/modctl.h>
55*9860Sgdamore@opensolaris.org #include <sys/debug.h>
56*9860Sgdamore@opensolaris.org #include <sys/dlpi.h>
57*9860Sgdamore@opensolaris.org #include <sys/ethernet.h>
58*9860Sgdamore@opensolaris.org #include <sys/gld.h>
59*9860Sgdamore@opensolaris.org #include <sys/pci.h>
60*9860Sgdamore@opensolaris.org #include <sys/ddi.h>
61*9860Sgdamore@opensolaris.org #include <sys/sunddi.h>
62*9860Sgdamore@opensolaris.org 
63*9860Sgdamore@opensolaris.org #include "dnet_mii.h"
64*9860Sgdamore@opensolaris.org #include "dnet.h"
65*9860Sgdamore@opensolaris.org 
66*9860Sgdamore@opensolaris.org char _depends_on[] = "misc/gld";
67*9860Sgdamore@opensolaris.org 
68*9860Sgdamore@opensolaris.org /*
69*9860Sgdamore@opensolaris.org  *	Declarations and Module Linkage
70*9860Sgdamore@opensolaris.org  */
71*9860Sgdamore@opensolaris.org 
72*9860Sgdamore@opensolaris.org #define	IDENT	"DNET 21x4x"
73*9860Sgdamore@opensolaris.org 
74*9860Sgdamore@opensolaris.org /*
75*9860Sgdamore@opensolaris.org  * #define	DNET_NOISY
76*9860Sgdamore@opensolaris.org  * #define	SROMDEBUG
77*9860Sgdamore@opensolaris.org  * #define	SROMDUMPSTRUCTURES
78*9860Sgdamore@opensolaris.org  */
79*9860Sgdamore@opensolaris.org 
80*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
81*9860Sgdamore@opensolaris.org #ifdef DNET_NOISY
82*9860Sgdamore@opensolaris.org int	dnetdebug = -1;
83*9860Sgdamore@opensolaris.org #else
84*9860Sgdamore@opensolaris.org int	dnetdebug = 0;
85*9860Sgdamore@opensolaris.org #endif
86*9860Sgdamore@opensolaris.org #endif
87*9860Sgdamore@opensolaris.org 
88*9860Sgdamore@opensolaris.org /* used for message allocated using desballoc() */
89*9860Sgdamore@opensolaris.org struct free_ptr {
90*9860Sgdamore@opensolaris.org 	struct free_rtn	free_rtn;
91*9860Sgdamore@opensolaris.org 	caddr_t buf;
92*9860Sgdamore@opensolaris.org };
93*9860Sgdamore@opensolaris.org 
94*9860Sgdamore@opensolaris.org struct rbuf_list {
95*9860Sgdamore@opensolaris.org 	struct rbuf_list	*rbuf_next;	/* next in the list */
96*9860Sgdamore@opensolaris.org 	caddr_t			rbuf_vaddr;	/* virual addr of the buf */
97*9860Sgdamore@opensolaris.org 	uint32_t		rbuf_paddr;	/* physical addr of the buf */
98*9860Sgdamore@opensolaris.org 	uint32_t		rbuf_endpaddr;	/* physical addr at the end */
99*9860Sgdamore@opensolaris.org 	ddi_dma_handle_t	rbuf_dmahdl;	/* dma handle */
100*9860Sgdamore@opensolaris.org 	ddi_acc_handle_t	rbuf_acchdl;	/* handle for DDI functions */
101*9860Sgdamore@opensolaris.org };
102*9860Sgdamore@opensolaris.org 
103*9860Sgdamore@opensolaris.org /* Required system entry points */
104*9860Sgdamore@opensolaris.org static int dnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
105*9860Sgdamore@opensolaris.org static int dnetprobe(dev_info_t *);
106*9860Sgdamore@opensolaris.org static int dnetattach(dev_info_t *, ddi_attach_cmd_t);
107*9860Sgdamore@opensolaris.org static int dnetdetach(dev_info_t *, ddi_detach_cmd_t);
108*9860Sgdamore@opensolaris.org 
109*9860Sgdamore@opensolaris.org /* Required driver entry points for GLD */
110*9860Sgdamore@opensolaris.org static int dnet_reset(gld_mac_info_t *);
111*9860Sgdamore@opensolaris.org static int dnet_start_board(gld_mac_info_t *);
112*9860Sgdamore@opensolaris.org static int dnet_stop_board(gld_mac_info_t *);
113*9860Sgdamore@opensolaris.org static int dnet_set_mac_addr(gld_mac_info_t *, uchar_t *);
114*9860Sgdamore@opensolaris.org static int dnet_set_multicast(gld_mac_info_t *, uchar_t *, int);
115*9860Sgdamore@opensolaris.org static int dnet_set_promiscuous(gld_mac_info_t *, int);
116*9860Sgdamore@opensolaris.org static int dnet_get_stats(gld_mac_info_t *, struct gld_stats *);
117*9860Sgdamore@opensolaris.org static int dnet_send(gld_mac_info_t *, mblk_t *);
118*9860Sgdamore@opensolaris.org static uint_t dnetintr(gld_mac_info_t *);
119*9860Sgdamore@opensolaris.org 
120*9860Sgdamore@opensolaris.org /* Internal functions used by the above entry points */
121*9860Sgdamore@opensolaris.org static void write_gpr(struct dnetinstance *dnetp, uint32_t val);
122*9860Sgdamore@opensolaris.org static void dnet_reset_board(gld_mac_info_t *);
123*9860Sgdamore@opensolaris.org static void dnet_init_board(gld_mac_info_t *);
124*9860Sgdamore@opensolaris.org static void dnet_chip_init(gld_mac_info_t *);
125*9860Sgdamore@opensolaris.org static unsigned int hashindex(uchar_t *);
126*9860Sgdamore@opensolaris.org static int dnet_start(gld_mac_info_t *);
127*9860Sgdamore@opensolaris.org static int dnet_set_addr(gld_mac_info_t *);
128*9860Sgdamore@opensolaris.org 
129*9860Sgdamore@opensolaris.org static void dnet_getp(gld_mac_info_t *);
130*9860Sgdamore@opensolaris.org static void update_rx_stats(gld_mac_info_t *, int);
131*9860Sgdamore@opensolaris.org static void update_tx_stats(gld_mac_info_t *, int);
132*9860Sgdamore@opensolaris.org 
133*9860Sgdamore@opensolaris.org /* Media Selection Setup Routines */
134*9860Sgdamore@opensolaris.org static void set_gpr(gld_mac_info_t *macinfo);
135*9860Sgdamore@opensolaris.org static void set_opr(gld_mac_info_t *macinfo);
136*9860Sgdamore@opensolaris.org static void set_sia(gld_mac_info_t *macinfo);
137*9860Sgdamore@opensolaris.org 
138*9860Sgdamore@opensolaris.org /* Buffer Management Routines */
139*9860Sgdamore@opensolaris.org static int dnet_alloc_bufs(gld_mac_info_t *);
140*9860Sgdamore@opensolaris.org static void dnet_free_bufs(gld_mac_info_t *);
141*9860Sgdamore@opensolaris.org static void dnet_init_txrx_bufs(gld_mac_info_t *);
142*9860Sgdamore@opensolaris.org static int alloc_descriptor(gld_mac_info_t *);
143*9860Sgdamore@opensolaris.org static void dnet_reclaim_Tx_desc(gld_mac_info_t *);
144*9860Sgdamore@opensolaris.org static int dnet_rbuf_init(dev_info_t *, int);
145*9860Sgdamore@opensolaris.org static int dnet_rbuf_destroy();
146*9860Sgdamore@opensolaris.org static struct rbuf_list *dnet_rbuf_alloc(dev_info_t *, int);
147*9860Sgdamore@opensolaris.org static void dnet_rbuf_free(caddr_t);
148*9860Sgdamore@opensolaris.org static void dnet_freemsg_buf(struct free_ptr *);
149*9860Sgdamore@opensolaris.org 
150*9860Sgdamore@opensolaris.org static void setup_block(gld_mac_info_t *macinfo);
151*9860Sgdamore@opensolaris.org 
152*9860Sgdamore@opensolaris.org /* SROM read functions */
153*9860Sgdamore@opensolaris.org static int dnet_read_srom(dev_info_t *, int, ddi_acc_handle_t, caddr_t,
154*9860Sgdamore@opensolaris.org     uchar_t *, int);
155*9860Sgdamore@opensolaris.org static void dnet_read21040addr(dev_info_t *, ddi_acc_handle_t, caddr_t,
156*9860Sgdamore@opensolaris.org     uchar_t *, int *);
157*9860Sgdamore@opensolaris.org static void dnet_read21140srom(ddi_acc_handle_t, caddr_t, uchar_t *, int);
158*9860Sgdamore@opensolaris.org static int get_alternative_srom_image(dev_info_t *, uchar_t *, int);
159*9860Sgdamore@opensolaris.org static void dnet_print_srom(SROM_FORMAT *sr);
160*9860Sgdamore@opensolaris.org static void dnet_dump_leaf(LEAF_FORMAT *leaf);
161*9860Sgdamore@opensolaris.org static void dnet_dump_block(media_block_t *block);
162*9860Sgdamore@opensolaris.org #ifdef BUG_4010796
163*9860Sgdamore@opensolaris.org static void set_alternative_srom_image(dev_info_t *, uchar_t *, int);
164*9860Sgdamore@opensolaris.org static int dnethack(dev_info_t *);
165*9860Sgdamore@opensolaris.org #endif
166*9860Sgdamore@opensolaris.org 
167*9860Sgdamore@opensolaris.org static int dnet_hack_interrupts(gld_mac_info_t *, int);
168*9860Sgdamore@opensolaris.org static int dnet_detach_hacked_interrupt(dev_info_t *devinfo);
169*9860Sgdamore@opensolaris.org static void enable_interrupts(struct dnetinstance *dnetp, int enable_xmit);
170*9860Sgdamore@opensolaris.org 
171*9860Sgdamore@opensolaris.org /* SROM parsing functions */
172*9860Sgdamore@opensolaris.org static void dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr,
173*9860Sgdamore@opensolaris.org     uchar_t *vi);
174*9860Sgdamore@opensolaris.org static void parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
175*9860Sgdamore@opensolaris.org     uchar_t *vi);
176*9860Sgdamore@opensolaris.org static uchar_t *parse_media_block(struct dnetinstance *dnetp,
177*9860Sgdamore@opensolaris.org     media_block_t *block, uchar_t *vi);
178*9860Sgdamore@opensolaris.org static int check_srom_valid(uchar_t *);
179*9860Sgdamore@opensolaris.org static void dnet_dumpbin(char *msg, uchar_t *, int size, int len);
180*9860Sgdamore@opensolaris.org static void setup_legacy_blocks();
181*9860Sgdamore@opensolaris.org /* Active Media Determination Routines */
182*9860Sgdamore@opensolaris.org static void find_active_media(gld_mac_info_t *);
183*9860Sgdamore@opensolaris.org static int send_test_packet(gld_mac_info_t *);
184*9860Sgdamore@opensolaris.org static int dnet_link_sense(gld_mac_info_t *macinfo);
185*9860Sgdamore@opensolaris.org 
186*9860Sgdamore@opensolaris.org /* PHY MII Routines */
187*9860Sgdamore@opensolaris.org static ushort_t dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num);
188*9860Sgdamore@opensolaris.org static void dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num,
189*9860Sgdamore@opensolaris.org 			int reg_dat);
190*9860Sgdamore@opensolaris.org static void write_mii(struct dnetinstance *, uint32_t, int);
191*9860Sgdamore@opensolaris.org static void mii_tristate(struct dnetinstance *);
192*9860Sgdamore@opensolaris.org static void do_phy(gld_mac_info_t *);
193*9860Sgdamore@opensolaris.org static void dnet_mii_link_cb(dev_info_t *, int, enum mii_phy_state);
194*9860Sgdamore@opensolaris.org static void set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf);
195*9860Sgdamore@opensolaris.org 
196*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
197*9860Sgdamore@opensolaris.org uint32_t dnet_usecelapsed(struct dnetinstance *dnetp);
198*9860Sgdamore@opensolaris.org void dnet_timestamp(struct dnetinstance *, char *);
199*9860Sgdamore@opensolaris.org void dnet_usectimeout(struct dnetinstance *, uint32_t, int, timercb_t);
200*9860Sgdamore@opensolaris.org #endif
201*9860Sgdamore@opensolaris.org static char *media_str[] = {
202*9860Sgdamore@opensolaris.org 	"10BaseT",
203*9860Sgdamore@opensolaris.org 	"10Base2",
204*9860Sgdamore@opensolaris.org 	"10Base5",
205*9860Sgdamore@opensolaris.org 	"100BaseTX",
206*9860Sgdamore@opensolaris.org 	"10BaseT FD",
207*9860Sgdamore@opensolaris.org 	"100BaseTX FD",
208*9860Sgdamore@opensolaris.org 	"100BaseT4",
209*9860Sgdamore@opensolaris.org 	"100BaseFX",
210*9860Sgdamore@opensolaris.org 	"100BaseFX FD",
211*9860Sgdamore@opensolaris.org 	"MII"
212*9860Sgdamore@opensolaris.org };
213*9860Sgdamore@opensolaris.org 
214*9860Sgdamore@opensolaris.org /* default SROM info for cards with no SROMs */
215*9860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_default_100;
216*9860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_asante;
217*9860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_phylegacy;
218*9860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_cogent_100;
219*9860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_21041;
220*9860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_21040;
221*9860Sgdamore@opensolaris.org 
222*9860Sgdamore@opensolaris.org int rx_buf_size = (ETHERMAX + ETHERFCSL + 3) & ~3;	/* roundup to 4 */
223*9860Sgdamore@opensolaris.org 
224*9860Sgdamore@opensolaris.org int max_rx_desc_21040 = MAX_RX_DESC_21040;
225*9860Sgdamore@opensolaris.org int max_rx_desc_21140 = MAX_RX_DESC_21140;
226*9860Sgdamore@opensolaris.org int max_tx_desc = MAX_TX_DESC;
227*9860Sgdamore@opensolaris.org int dnet_xmit_threshold = MAX_TX_DESC >> 2;	/* XXX need tuning? */
228*9860Sgdamore@opensolaris.org 
229*9860Sgdamore@opensolaris.org static kmutex_t dnet_rbuf_lock;		/* mutex to protect rbuf_list data */
230*9860Sgdamore@opensolaris.org 
231*9860Sgdamore@opensolaris.org /* used for buffers allocated by ddi_dma_mem_alloc() */
232*9860Sgdamore@opensolaris.org static ddi_dma_attr_t dma_attr = {
233*9860Sgdamore@opensolaris.org 	DMA_ATTR_V0,		/* dma_attr version */
234*9860Sgdamore@opensolaris.org 	0,			/* dma_attr_addr_lo */
235*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
236*9860Sgdamore@opensolaris.org 	0x7FFFFFFF,		/* dma_attr_count_max */
237*9860Sgdamore@opensolaris.org 	4,			/* dma_attr_align */
238*9860Sgdamore@opensolaris.org 	0x3F,			/* dma_attr_burstsizes */
239*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_minxfer */
240*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
241*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_seg */
242*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_sgllen */
243*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_granular */
244*9860Sgdamore@opensolaris.org 	0,			/* dma_attr_flags */
245*9860Sgdamore@opensolaris.org };
246*9860Sgdamore@opensolaris.org 
247*9860Sgdamore@opensolaris.org /* used for buffers allocated for rbuf, allow 2 cookies */
248*9860Sgdamore@opensolaris.org static ddi_dma_attr_t dma_attr_rb = {
249*9860Sgdamore@opensolaris.org 	DMA_ATTR_V0,		/* dma_attr version */
250*9860Sgdamore@opensolaris.org 	0,			/* dma_attr_addr_lo */
251*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
252*9860Sgdamore@opensolaris.org 	0x7FFFFFFF,		/* dma_attr_count_max */
253*9860Sgdamore@opensolaris.org 	4,			/* dma_attr_align */
254*9860Sgdamore@opensolaris.org 	0x3F,			/* dma_attr_burstsizes */
255*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_minxfer */
256*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
257*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_seg */
258*9860Sgdamore@opensolaris.org 	2,			/* dma_attr_sgllen */
259*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_granular */
260*9860Sgdamore@opensolaris.org 	0,			/* dma_attr_flags */
261*9860Sgdamore@opensolaris.org };
262*9860Sgdamore@opensolaris.org /* used for buffers which are NOT from ddi_dma_mem_alloc() - xmit side */
263*9860Sgdamore@opensolaris.org static ddi_dma_attr_t dma_attr_tx = {
264*9860Sgdamore@opensolaris.org 	DMA_ATTR_V0,		/* dma_attr version */
265*9860Sgdamore@opensolaris.org 	0,			/* dma_attr_addr_lo */
266*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
267*9860Sgdamore@opensolaris.org 	0x7FFFFFFF,		/* dma_attr_count_max */
268*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_align */
269*9860Sgdamore@opensolaris.org 	0x3F,			/* dma_attr_burstsizes */
270*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_minxfer */
271*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
272*9860Sgdamore@opensolaris.org 	(uint64_t)0xFFFFFFFF,	/* dma_attr_seg */
273*9860Sgdamore@opensolaris.org 	0x7FFF,			/* dma_attr_sgllen */
274*9860Sgdamore@opensolaris.org 	1,			/* dma_attr_granular */
275*9860Sgdamore@opensolaris.org 	0,			/* dma_attr_flags */
276*9860Sgdamore@opensolaris.org };
277*9860Sgdamore@opensolaris.org 
278*9860Sgdamore@opensolaris.org static ddi_device_acc_attr_t accattr = {
279*9860Sgdamore@opensolaris.org 	DDI_DEVICE_ATTR_V0,
280*9860Sgdamore@opensolaris.org 	DDI_NEVERSWAP_ACC,
281*9860Sgdamore@opensolaris.org 	DDI_STRICTORDER_ACC,
282*9860Sgdamore@opensolaris.org };
283*9860Sgdamore@opensolaris.org 
284*9860Sgdamore@opensolaris.org uchar_t dnet_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
285*9860Sgdamore@opensolaris.org 
286*9860Sgdamore@opensolaris.org /* Standard Streams initialization */
287*9860Sgdamore@opensolaris.org static struct module_info minfo = {
288*9860Sgdamore@opensolaris.org 	DNETIDNUM, "dnet", 0, INFPSZ, DNETHIWAT, DNETLOWAT
289*9860Sgdamore@opensolaris.org };
290*9860Sgdamore@opensolaris.org 
291*9860Sgdamore@opensolaris.org static struct qinit rinit = {	/* read queues */
292*9860Sgdamore@opensolaris.org 	NULL, gld_rsrv, gld_open, gld_close, NULL, &minfo, NULL
293*9860Sgdamore@opensolaris.org };
294*9860Sgdamore@opensolaris.org 
295*9860Sgdamore@opensolaris.org static struct qinit winit = {	/* write queues */
296*9860Sgdamore@opensolaris.org 	gld_wput, gld_wsrv, NULL, NULL, NULL, &minfo, NULL
297*9860Sgdamore@opensolaris.org };
298*9860Sgdamore@opensolaris.org 
299*9860Sgdamore@opensolaris.org static struct streamtab dnetinfo = {&rinit, &winit, NULL, NULL};
300*9860Sgdamore@opensolaris.org 
301*9860Sgdamore@opensolaris.org /* Standard Module linkage initialization for a Streams driver */
302*9860Sgdamore@opensolaris.org extern struct mod_ops mod_driverops;
303*9860Sgdamore@opensolaris.org 
304*9860Sgdamore@opensolaris.org static struct cb_ops cb_dnetops = {
305*9860Sgdamore@opensolaris.org 	nulldev,		/* cb_open */
306*9860Sgdamore@opensolaris.org 	nulldev,		/* cb_close */
307*9860Sgdamore@opensolaris.org 	nodev,			/* cb_strategy */
308*9860Sgdamore@opensolaris.org 	nodev,			/* cb_print */
309*9860Sgdamore@opensolaris.org 	nodev,			/* cb_dump */
310*9860Sgdamore@opensolaris.org 	nodev,			/* cb_read */
311*9860Sgdamore@opensolaris.org 	nodev,			/* cb_write */
312*9860Sgdamore@opensolaris.org 	nodev,			/* cb_ioctl */
313*9860Sgdamore@opensolaris.org 	nodev,			/* cb_devmap */
314*9860Sgdamore@opensolaris.org 	nodev,			/* cb_mmap */
315*9860Sgdamore@opensolaris.org 	nodev,			/* cb_segmap */
316*9860Sgdamore@opensolaris.org 	nochpoll,		/* cb_chpoll */
317*9860Sgdamore@opensolaris.org 	ddi_prop_op,		/* cb_prop_op */
318*9860Sgdamore@opensolaris.org 	&dnetinfo,		/* cb_stream */
319*9860Sgdamore@opensolaris.org 	(int)(D_MP | D_HOTPLUG)	/* cb_flag */
320*9860Sgdamore@opensolaris.org };
321*9860Sgdamore@opensolaris.org 
322*9860Sgdamore@opensolaris.org static struct dev_ops dnetops = {
323*9860Sgdamore@opensolaris.org 	DEVO_REV,		/* devo_rev */
324*9860Sgdamore@opensolaris.org 	0,			/* devo_refcnt */
325*9860Sgdamore@opensolaris.org 	gld_getinfo,		/* devo_getinfo */
326*9860Sgdamore@opensolaris.org 	nulldev,		/* devo_identify */
327*9860Sgdamore@opensolaris.org 	dnetprobe,		/* devo_probe */
328*9860Sgdamore@opensolaris.org 	dnetattach,		/* devo_attach */
329*9860Sgdamore@opensolaris.org 	dnetdetach,		/* devo_detach */
330*9860Sgdamore@opensolaris.org 	nodev,			/* devo_reset */
331*9860Sgdamore@opensolaris.org 	&cb_dnetops,		/* devo_cb_ops */
332*9860Sgdamore@opensolaris.org 	(struct bus_ops *)NULL,	/* devo_bus_ops */
333*9860Sgdamore@opensolaris.org 	NULL,			/* devo_power */
334*9860Sgdamore@opensolaris.org 	ddi_quiesce_not_supported,	/* devo_quiesce */
335*9860Sgdamore@opensolaris.org };
336*9860Sgdamore@opensolaris.org 
337*9860Sgdamore@opensolaris.org static struct modldrv modldrv = {
338*9860Sgdamore@opensolaris.org 	&mod_driverops,		/* Type of module.  This one is a driver */
339*9860Sgdamore@opensolaris.org 	IDENT,			/* short description */
340*9860Sgdamore@opensolaris.org 	&dnetops		/* driver specific ops */
341*9860Sgdamore@opensolaris.org };
342*9860Sgdamore@opensolaris.org 
343*9860Sgdamore@opensolaris.org static struct modlinkage modlinkage = {
344*9860Sgdamore@opensolaris.org 	MODREV_1, (void *)&modldrv, NULL
345*9860Sgdamore@opensolaris.org };
346*9860Sgdamore@opensolaris.org 
347*9860Sgdamore@opensolaris.org 
348*9860Sgdamore@opensolaris.org /*
349*9860Sgdamore@opensolaris.org  * Passed to the hacked interrupt for multiport Cogent and ZNYX cards with
350*9860Sgdamore@opensolaris.org  * dodgy interrupt routing
351*9860Sgdamore@opensolaris.org  */
352*9860Sgdamore@opensolaris.org #define	MAX_INST 8 /* Maximum instances on a multiport adapter. */
353*9860Sgdamore@opensolaris.org struct hackintr_inf
354*9860Sgdamore@opensolaris.org {
355*9860Sgdamore@opensolaris.org 	gld_mac_info_t *macinfos[MAX_INST]; /* macinfos for each port */
356*9860Sgdamore@opensolaris.org 	dev_info_t *devinfo;		    /* Devinfo of the primary device */
357*9860Sgdamore@opensolaris.org 	kmutex_t lock;
358*9860Sgdamore@opensolaris.org 		/* Ensures the interrupt doesn't get called while detaching */
359*9860Sgdamore@opensolaris.org };
360*9860Sgdamore@opensolaris.org static char hackintr_propname[] = "InterruptData";
361*9860Sgdamore@opensolaris.org static char macoffset_propname[] = "MAC_offset";
362*9860Sgdamore@opensolaris.org static char speed_propname[] = "speed";
363*9860Sgdamore@opensolaris.org static char ofloprob_propname[] = "dmaworkaround";
364*9860Sgdamore@opensolaris.org static char duplex_propname[] = "full-duplex"; /* Must agree with MII */
365*9860Sgdamore@opensolaris.org static char printsrom_propname[] = "print-srom";
366*9860Sgdamore@opensolaris.org 
367*9860Sgdamore@opensolaris.org static uint_t dnet_hack_intr(struct hackintr_inf *);
368*9860Sgdamore@opensolaris.org 
369*9860Sgdamore@opensolaris.org /*
370*9860Sgdamore@opensolaris.org  *	========== Module Loading Entry Points ==========
371*9860Sgdamore@opensolaris.org  */
372*9860Sgdamore@opensolaris.org 
373*9860Sgdamore@opensolaris.org int
374*9860Sgdamore@opensolaris.org _init(void)
375*9860Sgdamore@opensolaris.org {
376*9860Sgdamore@opensolaris.org 	int i;
377*9860Sgdamore@opensolaris.org 
378*9860Sgdamore@opensolaris.org 	/* Configure fake sroms for legacy cards */
379*9860Sgdamore@opensolaris.org 	mutex_init(&dnet_rbuf_lock, NULL, MUTEX_DRIVER, NULL);
380*9860Sgdamore@opensolaris.org 	setup_legacy_blocks();
381*9860Sgdamore@opensolaris.org 	if ((i = mod_install(&modlinkage)) != 0) {
382*9860Sgdamore@opensolaris.org 		mutex_destroy(&dnet_rbuf_lock);
383*9860Sgdamore@opensolaris.org 	}
384*9860Sgdamore@opensolaris.org 	return (i);
385*9860Sgdamore@opensolaris.org }
386*9860Sgdamore@opensolaris.org 
387*9860Sgdamore@opensolaris.org int
388*9860Sgdamore@opensolaris.org _fini(void)
389*9860Sgdamore@opensolaris.org {
390*9860Sgdamore@opensolaris.org 	int i;
391*9860Sgdamore@opensolaris.org 	if ((i = mod_remove(&modlinkage)) == 0) { /* module can be unloaded */
392*9860Sgdamore@opensolaris.org 		/* loop until all the receive buffers are freed */
393*9860Sgdamore@opensolaris.org 		while (dnet_rbuf_destroy() != 0) {
394*9860Sgdamore@opensolaris.org 			delay(drv_usectohz(100000));
395*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
396*9860Sgdamore@opensolaris.org 			if (dnetdebug & DNETDDI)
397*9860Sgdamore@opensolaris.org 				cmn_err(CE_WARN, "dnet _fini delay");
398*9860Sgdamore@opensolaris.org #endif
399*9860Sgdamore@opensolaris.org 		}
400*9860Sgdamore@opensolaris.org 		mutex_destroy(&dnet_rbuf_lock);
401*9860Sgdamore@opensolaris.org 	}
402*9860Sgdamore@opensolaris.org 	return (i);
403*9860Sgdamore@opensolaris.org }
404*9860Sgdamore@opensolaris.org 
405*9860Sgdamore@opensolaris.org int
406*9860Sgdamore@opensolaris.org _info(struct modinfo *modinfop)
407*9860Sgdamore@opensolaris.org {
408*9860Sgdamore@opensolaris.org 	return (mod_info(&modlinkage, modinfop));
409*9860Sgdamore@opensolaris.org }
410*9860Sgdamore@opensolaris.org 
411*9860Sgdamore@opensolaris.org /*
412*9860Sgdamore@opensolaris.org  *	========== DDI Entry Points ==========
413*9860Sgdamore@opensolaris.org  */
414*9860Sgdamore@opensolaris.org 
415*9860Sgdamore@opensolaris.org /*
416*9860Sgdamore@opensolaris.org  * probe(9E) -- Determine if a device is present
417*9860Sgdamore@opensolaris.org  */
418*9860Sgdamore@opensolaris.org static int
419*9860Sgdamore@opensolaris.org dnetprobe(dev_info_t *devinfo)
420*9860Sgdamore@opensolaris.org {
421*9860Sgdamore@opensolaris.org 	ddi_acc_handle_t handle;
422*9860Sgdamore@opensolaris.org 	uint16_t	vendorid;
423*9860Sgdamore@opensolaris.org 	uint16_t	deviceid;
424*9860Sgdamore@opensolaris.org 
425*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
426*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETDDI)
427*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnetprobe(0x%p)", (void *) devinfo);
428*9860Sgdamore@opensolaris.org #endif
429*9860Sgdamore@opensolaris.org 
430*9860Sgdamore@opensolaris.org 	if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
431*9860Sgdamore@opensolaris.org 		return (DDI_PROBE_FAILURE);
432*9860Sgdamore@opensolaris.org 
433*9860Sgdamore@opensolaris.org 	vendorid = pci_config_get16(handle, PCI_CONF_VENID);
434*9860Sgdamore@opensolaris.org 
435*9860Sgdamore@opensolaris.org 	if (vendorid != DEC_VENDOR_ID) {
436*9860Sgdamore@opensolaris.org 		pci_config_teardown(&handle);
437*9860Sgdamore@opensolaris.org 		return (DDI_PROBE_FAILURE);
438*9860Sgdamore@opensolaris.org 	}
439*9860Sgdamore@opensolaris.org 
440*9860Sgdamore@opensolaris.org 	deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
441*9860Sgdamore@opensolaris.org 	switch (deviceid) {
442*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21040:
443*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21041:
444*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21140:
445*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21143: /* And 142 */
446*9860Sgdamore@opensolaris.org 		break;
447*9860Sgdamore@opensolaris.org 	default:
448*9860Sgdamore@opensolaris.org 		pci_config_teardown(&handle);
449*9860Sgdamore@opensolaris.org 		return (DDI_PROBE_FAILURE);
450*9860Sgdamore@opensolaris.org 	}
451*9860Sgdamore@opensolaris.org 
452*9860Sgdamore@opensolaris.org 	pci_config_teardown(&handle);
453*9860Sgdamore@opensolaris.org #ifndef BUG_4010796
454*9860Sgdamore@opensolaris.org 	return (DDI_PROBE_SUCCESS);
455*9860Sgdamore@opensolaris.org #else
456*9860Sgdamore@opensolaris.org 	return (dnethack(devinfo));
457*9860Sgdamore@opensolaris.org #endif
458*9860Sgdamore@opensolaris.org }
459*9860Sgdamore@opensolaris.org 
460*9860Sgdamore@opensolaris.org #ifdef BUG_4010796
461*9860Sgdamore@opensolaris.org /*
462*9860Sgdamore@opensolaris.org  * If we have a device, but we cannot presently access its SROM data,
463*9860Sgdamore@opensolaris.org  * then we return DDI_PROBE_PARTIAL and hope that sometime later we
464*9860Sgdamore@opensolaris.org  * will be able to get at the SROM data.  This can only happen if we
465*9860Sgdamore@opensolaris.org  * are a secondary port with no SROM, and the bootstrap failed to set
466*9860Sgdamore@opensolaris.org  * our DNET_SROM property, and our primary sibling has not yet probed.
467*9860Sgdamore@opensolaris.org  */
468*9860Sgdamore@opensolaris.org static int
469*9860Sgdamore@opensolaris.org dnethack(dev_info_t *devinfo)
470*9860Sgdamore@opensolaris.org {
471*9860Sgdamore@opensolaris.org 	uchar_t 	vendor_info[SROM_SIZE];
472*9860Sgdamore@opensolaris.org 	uint32_t	csr;
473*9860Sgdamore@opensolaris.org 	uint16_t	deviceid;
474*9860Sgdamore@opensolaris.org 	ddi_acc_handle_t handle;
475*9860Sgdamore@opensolaris.org 	uint32_t	retval;
476*9860Sgdamore@opensolaris.org 	int		secondary;
477*9860Sgdamore@opensolaris.org 	ddi_acc_handle_t io_handle;
478*9860Sgdamore@opensolaris.org 	caddr_t		io_reg;
479*9860Sgdamore@opensolaris.org 
480*9860Sgdamore@opensolaris.org #define	DNET_PCI_RNUMBER	1
481*9860Sgdamore@opensolaris.org 
482*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
483*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETDDI)
484*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnethack(0x%p)", (void *) devinfo);
485*9860Sgdamore@opensolaris.org #endif
486*9860Sgdamore@opensolaris.org 
487*9860Sgdamore@opensolaris.org 	if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
488*9860Sgdamore@opensolaris.org 		return (DDI_PROBE_FAILURE);
489*9860Sgdamore@opensolaris.org 
490*9860Sgdamore@opensolaris.org 	deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
491*9860Sgdamore@opensolaris.org 
492*9860Sgdamore@opensolaris.org 	/*
493*9860Sgdamore@opensolaris.org 	 * Turn on Master Enable and IO Enable bits.
494*9860Sgdamore@opensolaris.org 	 */
495*9860Sgdamore@opensolaris.org 	csr = pci_config_get32(handle, PCI_CONF_COMM);
496*9860Sgdamore@opensolaris.org 	pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO));
497*9860Sgdamore@opensolaris.org 
498*9860Sgdamore@opensolaris.org 	pci_config_teardown(&handle);
499*9860Sgdamore@opensolaris.org 
500*9860Sgdamore@opensolaris.org 	/* Now map I/O register */
501*9860Sgdamore@opensolaris.org 	if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER,
502*9860Sgdamore@opensolaris.org 	    &io_reg, 0, 0, &accattr, &io_handle) != DDI_SUCCESS) {
503*9860Sgdamore@opensolaris.org 		return (DDI_PROBE_FAILURE);
504*9860Sgdamore@opensolaris.org 	}
505*9860Sgdamore@opensolaris.org 
506*9860Sgdamore@opensolaris.org 	/*
507*9860Sgdamore@opensolaris.org 	 * Reset the chip
508*9860Sgdamore@opensolaris.org 	 */
509*9860Sgdamore@opensolaris.org 	ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), SW_RESET);
510*9860Sgdamore@opensolaris.org 	drv_usecwait(3);
511*9860Sgdamore@opensolaris.org 	ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), 0);
512*9860Sgdamore@opensolaris.org 	drv_usecwait(8);
513*9860Sgdamore@opensolaris.org 
514*9860Sgdamore@opensolaris.org 	secondary = dnet_read_srom(devinfo, deviceid, io_handle,
515*9860Sgdamore@opensolaris.org 	    io_reg, vendor_info, sizeof (vendor_info));
516*9860Sgdamore@opensolaris.org 
517*9860Sgdamore@opensolaris.org 	switch (secondary) {
518*9860Sgdamore@opensolaris.org 	case -1:
519*9860Sgdamore@opensolaris.org 		/* We can't access our SROM data! */
520*9860Sgdamore@opensolaris.org 		retval = DDI_PROBE_PARTIAL;
521*9860Sgdamore@opensolaris.org 		break;
522*9860Sgdamore@opensolaris.org 	case 0:
523*9860Sgdamore@opensolaris.org 		retval = DDI_PROBE_SUCCESS;
524*9860Sgdamore@opensolaris.org 		break;
525*9860Sgdamore@opensolaris.org 	default:
526*9860Sgdamore@opensolaris.org 		retval = DDI_PROBE_SUCCESS;
527*9860Sgdamore@opensolaris.org 	}
528*9860Sgdamore@opensolaris.org 
529*9860Sgdamore@opensolaris.org 	ddi_regs_map_free(&io_handle);
530*9860Sgdamore@opensolaris.org 	return (retval);
531*9860Sgdamore@opensolaris.org }
532*9860Sgdamore@opensolaris.org #endif /* BUG_4010796 */
533*9860Sgdamore@opensolaris.org 
534*9860Sgdamore@opensolaris.org /*
535*9860Sgdamore@opensolaris.org  * attach(9E) -- Attach a device to the system
536*9860Sgdamore@opensolaris.org  *
537*9860Sgdamore@opensolaris.org  * Called once for each board successfully probed.
538*9860Sgdamore@opensolaris.org  */
539*9860Sgdamore@opensolaris.org static int
540*9860Sgdamore@opensolaris.org dnetattach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
541*9860Sgdamore@opensolaris.org {
542*9860Sgdamore@opensolaris.org 	uint16_t revid;
543*9860Sgdamore@opensolaris.org 	struct dnetinstance 	*dnetp;		/* Our private device info */
544*9860Sgdamore@opensolaris.org 	gld_mac_info_t		*macinfo;		/* GLD structure */
545*9860Sgdamore@opensolaris.org 	uchar_t 		vendor_info[SROM_SIZE];
546*9860Sgdamore@opensolaris.org 	uint32_t		csr;
547*9860Sgdamore@opensolaris.org 	uint16_t		deviceid;
548*9860Sgdamore@opensolaris.org 	ddi_acc_handle_t 	handle;
549*9860Sgdamore@opensolaris.org 	int			secondary;
550*9860Sgdamore@opensolaris.org 
551*9860Sgdamore@opensolaris.org #define	DNET_PCI_RNUMBER	1
552*9860Sgdamore@opensolaris.org 
553*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
554*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETDDI)
555*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnetattach(0x%p)", (void *) devinfo);
556*9860Sgdamore@opensolaris.org #endif
557*9860Sgdamore@opensolaris.org 
558*9860Sgdamore@opensolaris.org 	switch (cmd) {
559*9860Sgdamore@opensolaris.org 	case DDI_ATTACH:
560*9860Sgdamore@opensolaris.org 		break;
561*9860Sgdamore@opensolaris.org 
562*9860Sgdamore@opensolaris.org 	case DDI_RESUME:
563*9860Sgdamore@opensolaris.org 
564*9860Sgdamore@opensolaris.org 		/* Get the driver private (gld_mac_info_t) structure */
565*9860Sgdamore@opensolaris.org 		macinfo = ddi_get_driver_private(devinfo);
566*9860Sgdamore@opensolaris.org 		dnetp = (struct dnetinstance *)(macinfo->gldm_private);
567*9860Sgdamore@opensolaris.org 
568*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->intrlock);
569*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->txlock);
570*9860Sgdamore@opensolaris.org 		dnet_reset_board(macinfo);
571*9860Sgdamore@opensolaris.org 		dnet_init_board(macinfo);
572*9860Sgdamore@opensolaris.org 		dnetp->suspended = B_FALSE;
573*9860Sgdamore@opensolaris.org 
574*9860Sgdamore@opensolaris.org 		if (dnetp->running) {
575*9860Sgdamore@opensolaris.org 			dnetp->need_gld_sched = 0;
576*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->txlock);
577*9860Sgdamore@opensolaris.org 			(void) dnet_start(macinfo);
578*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->intrlock);
579*9860Sgdamore@opensolaris.org 			gld_sched(macinfo);
580*9860Sgdamore@opensolaris.org 		} else {
581*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->txlock);
582*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->intrlock);
583*9860Sgdamore@opensolaris.org 		}
584*9860Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
585*9860Sgdamore@opensolaris.org 	default:
586*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
587*9860Sgdamore@opensolaris.org 	}
588*9860Sgdamore@opensolaris.org 	if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
589*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
590*9860Sgdamore@opensolaris.org 
591*9860Sgdamore@opensolaris.org 	deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
592*9860Sgdamore@opensolaris.org 	switch (deviceid) {
593*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21040:
594*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21041:
595*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21140:
596*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21143: /* And 142 */
597*9860Sgdamore@opensolaris.org 		break;
598*9860Sgdamore@opensolaris.org 	default:
599*9860Sgdamore@opensolaris.org 		pci_config_teardown(&handle);
600*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
601*9860Sgdamore@opensolaris.org 	}
602*9860Sgdamore@opensolaris.org 
603*9860Sgdamore@opensolaris.org 	/*
604*9860Sgdamore@opensolaris.org 	 * Turn on Master Enable and IO Enable bits.
605*9860Sgdamore@opensolaris.org 	 */
606*9860Sgdamore@opensolaris.org 	csr = pci_config_get32(handle, PCI_CONF_COMM);
607*9860Sgdamore@opensolaris.org 	pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO));
608*9860Sgdamore@opensolaris.org 
609*9860Sgdamore@opensolaris.org 	/* Make sure the device is not asleep */
610*9860Sgdamore@opensolaris.org 	csr = pci_config_get32(handle, PCI_DNET_CONF_CFDD);
611*9860Sgdamore@opensolaris.org 	pci_config_put32(handle, PCI_DNET_CONF_CFDD,
612*9860Sgdamore@opensolaris.org 	    csr &  ~(CFDD_SLEEP|CFDD_SNOOZE));
613*9860Sgdamore@opensolaris.org 
614*9860Sgdamore@opensolaris.org 	revid = pci_config_get8(handle, PCI_CONF_REVID);
615*9860Sgdamore@opensolaris.org 	pci_config_teardown(&handle);
616*9860Sgdamore@opensolaris.org 
617*9860Sgdamore@opensolaris.org 	/*
618*9860Sgdamore@opensolaris.org 	 *	Allocate gld_mac_info_t and dnetinstance structures
619*9860Sgdamore@opensolaris.org 	 */
620*9860Sgdamore@opensolaris.org 	if ((macinfo = gld_mac_alloc(devinfo)) == NULL)
621*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
622*9860Sgdamore@opensolaris.org 
623*9860Sgdamore@opensolaris.org 	if ((dnetp = (struct dnetinstance *)
624*9860Sgdamore@opensolaris.org 	    kmem_zalloc(sizeof (struct dnetinstance), KM_SLEEP)) == NULL) {
625*9860Sgdamore@opensolaris.org 		gld_mac_free(macinfo);
626*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
627*9860Sgdamore@opensolaris.org 	}
628*9860Sgdamore@opensolaris.org 
629*9860Sgdamore@opensolaris.org 	/* Now map I/O register */
630*9860Sgdamore@opensolaris.org 	if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, &dnetp->io_reg,
631*9860Sgdamore@opensolaris.org 	    0, 0, &accattr, &dnetp->io_handle) != DDI_SUCCESS) {
632*9860Sgdamore@opensolaris.org 		kmem_free(dnetp, sizeof (struct dnetinstance));
633*9860Sgdamore@opensolaris.org 		gld_mac_free(macinfo);
634*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
635*9860Sgdamore@opensolaris.org 	}
636*9860Sgdamore@opensolaris.org 
637*9860Sgdamore@opensolaris.org 	dnetp->devinfo = devinfo;
638*9860Sgdamore@opensolaris.org 	dnetp->board_type = deviceid;
639*9860Sgdamore@opensolaris.org 
640*9860Sgdamore@opensolaris.org 	/*
641*9860Sgdamore@opensolaris.org 	 * Initialize our private fields in macinfo and dnetinstance
642*9860Sgdamore@opensolaris.org 	 */
643*9860Sgdamore@opensolaris.org 	macinfo->gldm_private = (caddr_t)dnetp;
644*9860Sgdamore@opensolaris.org 
645*9860Sgdamore@opensolaris.org 	/*
646*9860Sgdamore@opensolaris.org 	 * Initialize pointers to device specific functions which will be
647*9860Sgdamore@opensolaris.org 	 * used by the generic layer.
648*9860Sgdamore@opensolaris.org 	 */
649*9860Sgdamore@opensolaris.org 	macinfo->gldm_reset	= dnet_reset;
650*9860Sgdamore@opensolaris.org 	macinfo->gldm_start	= dnet_start_board;
651*9860Sgdamore@opensolaris.org 	macinfo->gldm_stop	= dnet_stop_board;
652*9860Sgdamore@opensolaris.org 	macinfo->gldm_set_mac_addr	= dnet_set_mac_addr;
653*9860Sgdamore@opensolaris.org 	macinfo->gldm_set_multicast	= dnet_set_multicast;
654*9860Sgdamore@opensolaris.org 	macinfo->gldm_set_promiscuous	= dnet_set_promiscuous;
655*9860Sgdamore@opensolaris.org 	macinfo->gldm_get_stats	= dnet_get_stats;
656*9860Sgdamore@opensolaris.org 	macinfo->gldm_send	= dnet_send;
657*9860Sgdamore@opensolaris.org 	macinfo->gldm_intr	= dnetintr;
658*9860Sgdamore@opensolaris.org 	macinfo->gldm_ioctl	= NULL;
659*9860Sgdamore@opensolaris.org 
660*9860Sgdamore@opensolaris.org 	/*
661*9860Sgdamore@opensolaris.org 	 *	Initialize board characteristics needed by the generic layer.
662*9860Sgdamore@opensolaris.org 	 */
663*9860Sgdamore@opensolaris.org 	macinfo->gldm_ident = IDENT;
664*9860Sgdamore@opensolaris.org 	macinfo->gldm_type = DL_ETHER;
665*9860Sgdamore@opensolaris.org 	macinfo->gldm_minpkt = 0;		/* assumes we pad ourselves */
666*9860Sgdamore@opensolaris.org 	macinfo->gldm_maxpkt = DNETMAXPKT;
667*9860Sgdamore@opensolaris.org 	macinfo->gldm_addrlen = ETHERADDRL;
668*9860Sgdamore@opensolaris.org 	macinfo->gldm_saplen = -2;
669*9860Sgdamore@opensolaris.org 
670*9860Sgdamore@opensolaris.org 	/* Other required initialization */
671*9860Sgdamore@opensolaris.org 	macinfo->gldm_ppa = ddi_get_instance(devinfo);
672*9860Sgdamore@opensolaris.org 	macinfo->gldm_vendor_addr = dnetp->vendor_addr;
673*9860Sgdamore@opensolaris.org 	macinfo->gldm_broadcast_addr = dnet_broadcastaddr;
674*9860Sgdamore@opensolaris.org 	macinfo->gldm_devinfo = devinfo;
675*9860Sgdamore@opensolaris.org 
676*9860Sgdamore@opensolaris.org 
677*9860Sgdamore@opensolaris.org 	/*
678*9860Sgdamore@opensolaris.org 	 * Get the iblock cookie with which to initialize the mutexes.
679*9860Sgdamore@opensolaris.org 	 */
680*9860Sgdamore@opensolaris.org 	if (ddi_get_iblock_cookie(devinfo, 0, &macinfo->gldm_cookie)
681*9860Sgdamore@opensolaris.org 	    != DDI_SUCCESS)
682*9860Sgdamore@opensolaris.org 		goto fail;
683*9860Sgdamore@opensolaris.org 
684*9860Sgdamore@opensolaris.org 	/*
685*9860Sgdamore@opensolaris.org 	 * Initialize mutex's for this device.
686*9860Sgdamore@opensolaris.org 	 * Do this before registering the interrupt handler to avoid
687*9860Sgdamore@opensolaris.org 	 * condition where interrupt handler can try using uninitialized
688*9860Sgdamore@opensolaris.org 	 * mutex.
689*9860Sgdamore@opensolaris.org 	 * Lock ordering rules: always lock intrlock first before
690*9860Sgdamore@opensolaris.org 	 * txlock if both are required.
691*9860Sgdamore@opensolaris.org 	 */
692*9860Sgdamore@opensolaris.org 	mutex_init(&dnetp->txlock,
693*9860Sgdamore@opensolaris.org 	    NULL, MUTEX_DRIVER, macinfo->gldm_cookie);
694*9860Sgdamore@opensolaris.org 	mutex_init(&dnetp->intrlock,
695*9860Sgdamore@opensolaris.org 	    NULL, MUTEX_DRIVER, macinfo->gldm_cookie);
696*9860Sgdamore@opensolaris.org 
697*9860Sgdamore@opensolaris.org 	/*
698*9860Sgdamore@opensolaris.org 	 * Get the BNC/TP indicator from the conf file for 21040
699*9860Sgdamore@opensolaris.org 	 */
700*9860Sgdamore@opensolaris.org 	dnetp->bnc_indicator =
701*9860Sgdamore@opensolaris.org 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
702*9860Sgdamore@opensolaris.org 	    "bncaui", -1);
703*9860Sgdamore@opensolaris.org 
704*9860Sgdamore@opensolaris.org 	/*
705*9860Sgdamore@opensolaris.org 	 * For 21140 check the data rate set in the conf file. Default is
706*9860Sgdamore@opensolaris.org 	 * 100Mb/s. Disallow connections at settings that would conflict
707*9860Sgdamore@opensolaris.org 	 * with what's in the conf file
708*9860Sgdamore@opensolaris.org 	 */
709*9860Sgdamore@opensolaris.org 	dnetp->speed =
710*9860Sgdamore@opensolaris.org 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
711*9860Sgdamore@opensolaris.org 	    speed_propname, 0);
712*9860Sgdamore@opensolaris.org 	dnetp->full_duplex =
713*9860Sgdamore@opensolaris.org 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
714*9860Sgdamore@opensolaris.org 	    duplex_propname, -1);
715*9860Sgdamore@opensolaris.org 
716*9860Sgdamore@opensolaris.org 	if (dnetp->speed == 100) {
717*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media |= (1UL<<MEDIA_TP) | (1UL<<MEDIA_TP_FD);
718*9860Sgdamore@opensolaris.org 	} else if (dnetp->speed == 10) {
719*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media |=
720*9860Sgdamore@opensolaris.org 		    (1UL<<MEDIA_SYM_SCR) | (1UL<<MEDIA_SYM_SCR_FD);
721*9860Sgdamore@opensolaris.org 	}
722*9860Sgdamore@opensolaris.org 
723*9860Sgdamore@opensolaris.org 	if (dnetp->full_duplex == 1) {
724*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media |=
725*9860Sgdamore@opensolaris.org 		    (1UL<<MEDIA_TP) | (1UL<<MEDIA_SYM_SCR);
726*9860Sgdamore@opensolaris.org 	} else if (dnetp->full_duplex == 0) {
727*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media |=
728*9860Sgdamore@opensolaris.org 		    (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_SYM_SCR_FD);
729*9860Sgdamore@opensolaris.org 	}
730*9860Sgdamore@opensolaris.org 
731*9860Sgdamore@opensolaris.org 	if (dnetp->bnc_indicator == 0) /* Disable BNC and AUI media */
732*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media |= (1UL<<MEDIA_BNC) | (1UL<<MEDIA_AUI);
733*9860Sgdamore@opensolaris.org 	else if (dnetp->bnc_indicator == 1) /* Force BNC only */
734*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media =  (uint32_t)~(1U<<MEDIA_BNC);
735*9860Sgdamore@opensolaris.org 	else if (dnetp->bnc_indicator == 2) /* Force AUI only */
736*9860Sgdamore@opensolaris.org 		dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_AUI);
737*9860Sgdamore@opensolaris.org 
738*9860Sgdamore@opensolaris.org 	dnet_reset_board(macinfo);
739*9860Sgdamore@opensolaris.org 
740*9860Sgdamore@opensolaris.org 	secondary = dnet_read_srom(devinfo, dnetp->board_type, dnetp->io_handle,
741*9860Sgdamore@opensolaris.org 	    dnetp->io_reg, vendor_info, sizeof (vendor_info));
742*9860Sgdamore@opensolaris.org 
743*9860Sgdamore@opensolaris.org 	if (secondary == -1) /* ASSERT (vendor_info not big enough) */
744*9860Sgdamore@opensolaris.org 		goto fail1;
745*9860Sgdamore@opensolaris.org 
746*9860Sgdamore@opensolaris.org 	dnet_parse_srom(dnetp, &dnetp->sr, vendor_info);
747*9860Sgdamore@opensolaris.org 
748*9860Sgdamore@opensolaris.org 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
749*9860Sgdamore@opensolaris.org 	    printsrom_propname, 0))
750*9860Sgdamore@opensolaris.org 		dnet_print_srom(&dnetp->sr);
751*9860Sgdamore@opensolaris.org 
752*9860Sgdamore@opensolaris.org 	dnetp->sr.netaddr[ETHERADDRL-1] += secondary;	/* unique ether addr */
753*9860Sgdamore@opensolaris.org 
754*9860Sgdamore@opensolaris.org 	BCOPY((caddr_t)dnetp->sr.netaddr,
755*9860Sgdamore@opensolaris.org 	    (caddr_t)dnetp->vendor_addr, ETHERADDRL);
756*9860Sgdamore@opensolaris.org 
757*9860Sgdamore@opensolaris.org 	BCOPY((caddr_t)dnetp->sr.netaddr,
758*9860Sgdamore@opensolaris.org 	    (caddr_t)dnetp->curr_macaddr, ETHERADDRL);
759*9860Sgdamore@opensolaris.org 
760*9860Sgdamore@opensolaris.org 
761*9860Sgdamore@opensolaris.org 	/*
762*9860Sgdamore@opensolaris.org 	 * determine whether to implement workaround from DEC
763*9860Sgdamore@opensolaris.org 	 * for DMA overrun errata.
764*9860Sgdamore@opensolaris.org 	 */
765*9860Sgdamore@opensolaris.org 	dnetp->overrun_workaround =
766*9860Sgdamore@opensolaris.org 	    ((dnetp->board_type == DEVICE_ID_21140 && revid >= 0x20) ||
767*9860Sgdamore@opensolaris.org 	    (dnetp->board_type == DEVICE_ID_21143 && revid <= 0x30)) ? 1 : 0;
768*9860Sgdamore@opensolaris.org 
769*9860Sgdamore@opensolaris.org 	dnetp->overrun_workaround =
770*9860Sgdamore@opensolaris.org 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
771*9860Sgdamore@opensolaris.org 	    ofloprob_propname, dnetp->overrun_workaround);
772*9860Sgdamore@opensolaris.org 
773*9860Sgdamore@opensolaris.org 	/*
774*9860Sgdamore@opensolaris.org 	 * Add the interrupt handler if dnet_hack_interrupts() returns 0.
775*9860Sgdamore@opensolaris.org 	 * Otherwise dnet_hack_interrupts() itself adds the handler.
776*9860Sgdamore@opensolaris.org 	 */
777*9860Sgdamore@opensolaris.org 	if (!dnet_hack_interrupts(macinfo, secondary)) {
778*9860Sgdamore@opensolaris.org 		(void) ddi_add_intr(devinfo, 0, NULL,
779*9860Sgdamore@opensolaris.org 		    NULL, gld_intr, (caddr_t)macinfo);
780*9860Sgdamore@opensolaris.org 	}
781*9860Sgdamore@opensolaris.org 
782*9860Sgdamore@opensolaris.org 	dnetp->max_tx_desc = max_tx_desc;
783*9860Sgdamore@opensolaris.org 	dnetp->max_rx_desc = max_rx_desc_21040;
784*9860Sgdamore@opensolaris.org 	if (dnetp->board_type != DEVICE_ID_21040 &&
785*9860Sgdamore@opensolaris.org 	    dnetp->board_type != DEVICE_ID_21041 &&
786*9860Sgdamore@opensolaris.org 	    dnetp->speed != 10)
787*9860Sgdamore@opensolaris.org 		dnetp->max_rx_desc = max_rx_desc_21140;
788*9860Sgdamore@opensolaris.org 
789*9860Sgdamore@opensolaris.org 	/* Allocate the TX and RX descriptors/buffers. */
790*9860Sgdamore@opensolaris.org 	if (dnet_alloc_bufs(macinfo) == FAILURE) {
791*9860Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "DNET: Not enough DMA memory for buffers.");
792*9860Sgdamore@opensolaris.org 		goto fail2;
793*9860Sgdamore@opensolaris.org 	}
794*9860Sgdamore@opensolaris.org 
795*9860Sgdamore@opensolaris.org 	/*
796*9860Sgdamore@opensolaris.org 	 *	Register ourselves with the GLD interface
797*9860Sgdamore@opensolaris.org 	 *
798*9860Sgdamore@opensolaris.org 	 *	gld_register will:
799*9860Sgdamore@opensolaris.org 	 *	link us with the GLD system;
800*9860Sgdamore@opensolaris.org 	 *	set our ddi_set_driver_private(9F) data to the macinfo pointer;
801*9860Sgdamore@opensolaris.org 	 *	save the devinfo pointer in macinfo->gldm_devinfo;
802*9860Sgdamore@opensolaris.org 	 *	map the registers, putting the kvaddr into macinfo->gldm_memp;
803*9860Sgdamore@opensolaris.org 	 *	add the interrupt, putting the cookie in gldm_cookie;
804*9860Sgdamore@opensolaris.org 	 *	init the gldm_intrlock mutex which will block that interrupt;
805*9860Sgdamore@opensolaris.org 	 *	create the minor node.
806*9860Sgdamore@opensolaris.org 	 */
807*9860Sgdamore@opensolaris.org 
808*9860Sgdamore@opensolaris.org 	if (gld_register(devinfo, "dnet", macinfo) == DDI_SUCCESS) {
809*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->intrlock);
810*9860Sgdamore@opensolaris.org 		dnetp->phyaddr = -1;
811*9860Sgdamore@opensolaris.org 		if (dnetp->board_type == DEVICE_ID_21140 ||
812*9860Sgdamore@opensolaris.org 		    dnetp->board_type == DEVICE_ID_21143)
813*9860Sgdamore@opensolaris.org 			do_phy(macinfo);	/* Initialize the PHY, if any */
814*9860Sgdamore@opensolaris.org 		find_active_media(macinfo);
815*9860Sgdamore@opensolaris.org 
816*9860Sgdamore@opensolaris.org 		/* if the chosen media is non-MII, stop the port monitor */
817*9860Sgdamore@opensolaris.org 		if (dnetp->selected_media_block->media_code != MEDIA_MII &&
818*9860Sgdamore@opensolaris.org 		    dnetp->mii != NULL) {
819*9860Sgdamore@opensolaris.org 			mii_destroy(dnetp->mii);
820*9860Sgdamore@opensolaris.org 			dnetp->mii = NULL;
821*9860Sgdamore@opensolaris.org 			dnetp->phyaddr = -1;
822*9860Sgdamore@opensolaris.org 		}
823*9860Sgdamore@opensolaris.org 
824*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
825*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETSENSE)
826*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE, "dnet: link configured : %s",
827*9860Sgdamore@opensolaris.org 			    media_str[dnetp->selected_media_block->media_code]);
828*9860Sgdamore@opensolaris.org #endif
829*9860Sgdamore@opensolaris.org 		bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE);
830*9860Sgdamore@opensolaris.org 		dnet_reset_board(macinfo);
831*9860Sgdamore@opensolaris.org 		dnet_init_board(macinfo);
832*9860Sgdamore@opensolaris.org 		/* XXX function return value ignored */
833*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
834*9860Sgdamore@opensolaris.org 		/* dropped intrlock as dnet_stop_board() grabs intrlock */
835*9860Sgdamore@opensolaris.org 		(void) dnet_stop_board(macinfo);
836*9860Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
837*9860Sgdamore@opensolaris.org 	}
838*9860Sgdamore@opensolaris.org fail2:
839*9860Sgdamore@opensolaris.org 	/* XXX function return value ignored */
840*9860Sgdamore@opensolaris.org 	/*
841*9860Sgdamore@opensolaris.org 	 * dnet_detach_hacked_interrupt() will remove
842*9860Sgdamore@opensolaris.org 	 * interrupt for the non-hacked case also.
843*9860Sgdamore@opensolaris.org 	 */
844*9860Sgdamore@opensolaris.org 	(void) dnet_detach_hacked_interrupt(devinfo);
845*9860Sgdamore@opensolaris.org 	dnet_free_bufs(macinfo);
846*9860Sgdamore@opensolaris.org fail1:
847*9860Sgdamore@opensolaris.org 	mutex_destroy(&dnetp->txlock);
848*9860Sgdamore@opensolaris.org 	mutex_destroy(&dnetp->intrlock);
849*9860Sgdamore@opensolaris.org fail:
850*9860Sgdamore@opensolaris.org 	ddi_regs_map_free(&dnetp->io_handle);
851*9860Sgdamore@opensolaris.org 	kmem_free(dnetp, sizeof (struct dnetinstance));
852*9860Sgdamore@opensolaris.org 	gld_mac_free(macinfo);
853*9860Sgdamore@opensolaris.org 	return (DDI_FAILURE);
854*9860Sgdamore@opensolaris.org }
855*9860Sgdamore@opensolaris.org 
856*9860Sgdamore@opensolaris.org /*
857*9860Sgdamore@opensolaris.org  * detach(9E) -- Detach a device from the system
858*9860Sgdamore@opensolaris.org  */
859*9860Sgdamore@opensolaris.org static int
860*9860Sgdamore@opensolaris.org dnetdetach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
861*9860Sgdamore@opensolaris.org {
862*9860Sgdamore@opensolaris.org 	int32_t rc;
863*9860Sgdamore@opensolaris.org 	gld_mac_info_t	*macinfo;		/* GLD structure */
864*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp;		/* Our private device info */
865*9860Sgdamore@opensolaris.org 	int32_t		proplen;
866*9860Sgdamore@opensolaris.org 
867*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
868*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETDDI)
869*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnetdetach(0x%p)", (void *) devinfo);
870*9860Sgdamore@opensolaris.org #endif
871*9860Sgdamore@opensolaris.org 
872*9860Sgdamore@opensolaris.org 	/* Get the driver private (gld_mac_info_t) structure */
873*9860Sgdamore@opensolaris.org 	macinfo = ddi_get_driver_private(devinfo);
874*9860Sgdamore@opensolaris.org 	dnetp = (struct dnetinstance *)(macinfo->gldm_private);
875*9860Sgdamore@opensolaris.org 
876*9860Sgdamore@opensolaris.org 	switch (cmd) {
877*9860Sgdamore@opensolaris.org 	case DDI_DETACH:
878*9860Sgdamore@opensolaris.org 		break;
879*9860Sgdamore@opensolaris.org 
880*9860Sgdamore@opensolaris.org 	case DDI_SUSPEND:
881*9860Sgdamore@opensolaris.org 		/*
882*9860Sgdamore@opensolaris.org 		 * NB: dnetp->suspended can only be modified (marked true)
883*9860Sgdamore@opensolaris.org 		 * if both intrlock and txlock are held.  This keeps both
884*9860Sgdamore@opensolaris.org 		 * tx and rx code paths excluded.
885*9860Sgdamore@opensolaris.org 		 */
886*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->intrlock);
887*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->txlock);
888*9860Sgdamore@opensolaris.org 		dnetp->suspended = B_TRUE;
889*9860Sgdamore@opensolaris.org 		dnet_reset_board(macinfo);
890*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
891*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
892*9860Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
893*9860Sgdamore@opensolaris.org 
894*9860Sgdamore@opensolaris.org 	default:
895*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
896*9860Sgdamore@opensolaris.org 	}
897*9860Sgdamore@opensolaris.org 
898*9860Sgdamore@opensolaris.org 	/*
899*9860Sgdamore@opensolaris.org 	 *	Unregister ourselves from the GLD interface
900*9860Sgdamore@opensolaris.org 	 *
901*9860Sgdamore@opensolaris.org 	 *	gld_unregister will:
902*9860Sgdamore@opensolaris.org 	 *	remove the minor node;
903*9860Sgdamore@opensolaris.org 	 *	unmap the registers;
904*9860Sgdamore@opensolaris.org 	 *	remove the interrupt;
905*9860Sgdamore@opensolaris.org 	 *	destroy the gldm_intrlock mutex;
906*9860Sgdamore@opensolaris.org 	 *	unlink us from the GLD system.
907*9860Sgdamore@opensolaris.org 	 */
908*9860Sgdamore@opensolaris.org 	if (gld_unregister(macinfo) != DDI_SUCCESS)
909*9860Sgdamore@opensolaris.org 		return (DDI_FAILURE);
910*9860Sgdamore@opensolaris.org 
911*9860Sgdamore@opensolaris.org 	/* stop the board if it is running */
912*9860Sgdamore@opensolaris.org 	dnet_reset_board(macinfo);
913*9860Sgdamore@opensolaris.org 
914*9860Sgdamore@opensolaris.org 	if ((rc = dnet_detach_hacked_interrupt(devinfo)) != DDI_SUCCESS)
915*9860Sgdamore@opensolaris.org 		return (rc);
916*9860Sgdamore@opensolaris.org 
917*9860Sgdamore@opensolaris.org 	if (dnetp->mii != NULL)
918*9860Sgdamore@opensolaris.org 		mii_destroy(dnetp->mii);
919*9860Sgdamore@opensolaris.org 
920*9860Sgdamore@opensolaris.org 	/* Free leaf information */
921*9860Sgdamore@opensolaris.org 	set_leaf(&dnetp->sr, NULL);
922*9860Sgdamore@opensolaris.org 
923*9860Sgdamore@opensolaris.org 	ddi_regs_map_free(&dnetp->io_handle);
924*9860Sgdamore@opensolaris.org 	dnet_free_bufs(macinfo);
925*9860Sgdamore@opensolaris.org 	mutex_destroy(&dnetp->txlock);
926*9860Sgdamore@opensolaris.org 	mutex_destroy(&dnetp->intrlock);
927*9860Sgdamore@opensolaris.org 	kmem_free(dnetp, sizeof (struct dnetinstance));
928*9860Sgdamore@opensolaris.org 	gld_mac_free(macinfo);
929*9860Sgdamore@opensolaris.org 
930*9860Sgdamore@opensolaris.org #ifdef BUG_4010796
931*9860Sgdamore@opensolaris.org 	if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, 0,
932*9860Sgdamore@opensolaris.org 	    "DNET_HACK", &proplen) != DDI_PROP_SUCCESS)
933*9860Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
934*9860Sgdamore@opensolaris.org 
935*9860Sgdamore@opensolaris.org 	/*
936*9860Sgdamore@opensolaris.org 	 * We must remove the properties we added, because if we leave
937*9860Sgdamore@opensolaris.org 	 * them in the devinfo nodes and the driver is unloaded, when
938*9860Sgdamore@opensolaris.org 	 * the driver is reloaded the info will still be there, causing
939*9860Sgdamore@opensolaris.org 	 * nodes which had returned PROBE_PARTIAL the first time to
940*9860Sgdamore@opensolaris.org 	 * instead return PROBE_SUCCESS, in turn causing the nodes to be
941*9860Sgdamore@opensolaris.org 	 * attached in a different order, causing their PPA numbers to
942*9860Sgdamore@opensolaris.org 	 * be different the second time around, which is undesirable.
943*9860Sgdamore@opensolaris.org 	 */
944*9860Sgdamore@opensolaris.org 	(void) ddi_prop_remove(DDI_DEV_T_NONE, devinfo, "DNET_HACK");
945*9860Sgdamore@opensolaris.org 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
946*9860Sgdamore@opensolaris.org 	    "DNET_SROM");
947*9860Sgdamore@opensolaris.org 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
948*9860Sgdamore@opensolaris.org 	    "DNET_DEVNUM");
949*9860Sgdamore@opensolaris.org #endif
950*9860Sgdamore@opensolaris.org 
951*9860Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
952*9860Sgdamore@opensolaris.org }
953*9860Sgdamore@opensolaris.org 
954*9860Sgdamore@opensolaris.org /*
955*9860Sgdamore@opensolaris.org  *	========== GLD Entry Points ==========
956*9860Sgdamore@opensolaris.org  */
957*9860Sgdamore@opensolaris.org 
958*9860Sgdamore@opensolaris.org /*
959*9860Sgdamore@opensolaris.org  *	dnet_reset() -- reset the board to initial state;
960*9860Sgdamore@opensolaris.org  */
961*9860Sgdamore@opensolaris.org static int
962*9860Sgdamore@opensolaris.org dnet_reset(gld_mac_info_t *macinfo)
963*9860Sgdamore@opensolaris.org {
964*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
965*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
966*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
967*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
968*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_reset(0x%p)", (void *) macinfo);
969*9860Sgdamore@opensolaris.org #endif
970*9860Sgdamore@opensolaris.org 
971*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
972*9860Sgdamore@opensolaris.org 	/*
973*9860Sgdamore@opensolaris.org 	 * Initialize internal data structures
974*9860Sgdamore@opensolaris.org 	 */
975*9860Sgdamore@opensolaris.org 	bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE);
976*9860Sgdamore@opensolaris.org 	bzero(dnetp->multicast_cnt, MCASTBUF_SIZE);
977*9860Sgdamore@opensolaris.org 	dnetp->promisc = 0;
978*9860Sgdamore@opensolaris.org 
979*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->txlock);
980*9860Sgdamore@opensolaris.org 	dnetp->need_saddr = 0;
981*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->txlock);
982*9860Sgdamore@opensolaris.org 
983*9860Sgdamore@opensolaris.org 	if (dnetp->suspended) {
984*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
985*9860Sgdamore@opensolaris.org 		return (0);
986*9860Sgdamore@opensolaris.org 	}
987*9860Sgdamore@opensolaris.org 	dnet_reset_board(macinfo);
988*9860Sgdamore@opensolaris.org 
989*9860Sgdamore@opensolaris.org 	if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, DDI_PROP_DONTPASS,
990*9860Sgdamore@opensolaris.org 	    "reset_do_find_active_media", 0)) {
991*9860Sgdamore@opensolaris.org 		find_active_media(macinfo);	/* Redetermine active media */
992*9860Sgdamore@opensolaris.org 		/* Go back to a good state */
993*9860Sgdamore@opensolaris.org 		bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE);
994*9860Sgdamore@opensolaris.org 		dnet_reset_board(macinfo);
995*9860Sgdamore@opensolaris.org 	}
996*9860Sgdamore@opensolaris.org 	dnet_init_board(macinfo);
997*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
998*9860Sgdamore@opensolaris.org 	return (0);
999*9860Sgdamore@opensolaris.org }
1000*9860Sgdamore@opensolaris.org 
1001*9860Sgdamore@opensolaris.org static void
1002*9860Sgdamore@opensolaris.org dnet_reset_board(gld_mac_info_t *macinfo)
1003*9860Sgdamore@opensolaris.org {
1004*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1005*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1006*9860Sgdamore@opensolaris.org 	uint32_t	val;
1007*9860Sgdamore@opensolaris.org 
1008*9860Sgdamore@opensolaris.org 	/*
1009*9860Sgdamore@opensolaris.org 	 * before initializing the dnet should be in STOP state
1010*9860Sgdamore@opensolaris.org 	 */
1011*9860Sgdamore@opensolaris.org 	/* XXX function return value ignored */
1012*9860Sgdamore@opensolaris.org 	/* (void) dnet_stop_board(macinfo); */
1013*9860Sgdamore@opensolaris.org 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
1014*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
1015*9860Sgdamore@opensolaris.org 	    val & ~(START_TRANSMIT | START_RECEIVE));
1016*9860Sgdamore@opensolaris.org 
1017*9860Sgdamore@opensolaris.org 	/*
1018*9860Sgdamore@opensolaris.org 	 * Reset the chip
1019*9860Sgdamore@opensolaris.org 	 */
1020*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0);
1021*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle,
1022*9860Sgdamore@opensolaris.org 	    REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET);
1023*9860Sgdamore@opensolaris.org 	drv_usecwait(5);
1024*9860Sgdamore@opensolaris.org }
1025*9860Sgdamore@opensolaris.org 
1026*9860Sgdamore@opensolaris.org /*
1027*9860Sgdamore@opensolaris.org  * dnet_init_board() -- initialize the specified network board short of
1028*9860Sgdamore@opensolaris.org  * actually starting the board.  Call after dnet_reset_board().
1029*9860Sgdamore@opensolaris.org  * called with intrlock held.
1030*9860Sgdamore@opensolaris.org  */
1031*9860Sgdamore@opensolaris.org static void
1032*9860Sgdamore@opensolaris.org dnet_init_board(gld_mac_info_t *macinfo)
1033*9860Sgdamore@opensolaris.org {
1034*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1035*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1036*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_init_board(0x%p)", (void *) macinfo);
1037*9860Sgdamore@opensolaris.org #endif
1038*9860Sgdamore@opensolaris.org 	set_opr(macinfo);
1039*9860Sgdamore@opensolaris.org 	set_gpr(macinfo);
1040*9860Sgdamore@opensolaris.org 	set_sia(macinfo);
1041*9860Sgdamore@opensolaris.org 	dnet_chip_init(macinfo);
1042*9860Sgdamore@opensolaris.org }
1043*9860Sgdamore@opensolaris.org 
1044*9860Sgdamore@opensolaris.org /* dnet_chip_init() - called with intrlock held */
1045*9860Sgdamore@opensolaris.org static void
1046*9860Sgdamore@opensolaris.org dnet_chip_init(gld_mac_info_t *macinfo)
1047*9860Sgdamore@opensolaris.org {
1048*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
1049*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
1050*9860Sgdamore@opensolaris.org 
1051*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, BUS_MODE_REG),
1052*9860Sgdamore@opensolaris.org 	    CACHE_ALIGN | BURST_SIZE);		/* CSR0 */
1053*9860Sgdamore@opensolaris.org 
1054*9860Sgdamore@opensolaris.org 	/*
1055*9860Sgdamore@opensolaris.org 	 * Initialize the TX and RX descriptors/buffers
1056*9860Sgdamore@opensolaris.org 	 */
1057*9860Sgdamore@opensolaris.org 	dnet_init_txrx_bufs(macinfo);
1058*9860Sgdamore@opensolaris.org 
1059*9860Sgdamore@opensolaris.org 	/*
1060*9860Sgdamore@opensolaris.org 	 * Set the base address of the Rx descriptor list in CSR3
1061*9860Sgdamore@opensolaris.org 	 */
1062*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, RX_BASE_ADDR_REG),
1063*9860Sgdamore@opensolaris.org 	    dnetp->rx_desc_paddr);
1064*9860Sgdamore@opensolaris.org 
1065*9860Sgdamore@opensolaris.org 	/*
1066*9860Sgdamore@opensolaris.org 	 * Set the base address of the Tx descrptor list in CSR4
1067*9860Sgdamore@opensolaris.org 	 */
1068*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_BASE_ADDR_REG),
1069*9860Sgdamore@opensolaris.org 	    dnetp->tx_desc_paddr);
1070*9860Sgdamore@opensolaris.org 
1071*9860Sgdamore@opensolaris.org 	dnetp->tx_current_desc = dnetp->rx_current_desc = 0;
1072*9860Sgdamore@opensolaris.org 	dnetp->transmitted_desc = 0;
1073*9860Sgdamore@opensolaris.org 	dnetp->free_desc = dnetp->max_tx_desc;
1074*9860Sgdamore@opensolaris.org 	enable_interrupts(dnetp, 1);
1075*9860Sgdamore@opensolaris.org }
1076*9860Sgdamore@opensolaris.org 
1077*9860Sgdamore@opensolaris.org /*
1078*9860Sgdamore@opensolaris.org  *	dnet_start() -- start the board receiving and allow transmits.
1079*9860Sgdamore@opensolaris.org  *  Called with intrlock held.
1080*9860Sgdamore@opensolaris.org  */
1081*9860Sgdamore@opensolaris.org static int
1082*9860Sgdamore@opensolaris.org dnet_start(gld_mac_info_t *macinfo)
1083*9860Sgdamore@opensolaris.org {
1084*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1085*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1086*9860Sgdamore@opensolaris.org 	uint32_t		val;
1087*9860Sgdamore@opensolaris.org 
1088*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1089*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1090*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_start(0x%p)", (void *) macinfo);
1091*9860Sgdamore@opensolaris.org #endif
1092*9860Sgdamore@opensolaris.org 
1093*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
1094*9860Sgdamore@opensolaris.org 	/*
1095*9860Sgdamore@opensolaris.org 	 * start the board and enable receiving
1096*9860Sgdamore@opensolaris.org 	 */
1097*9860Sgdamore@opensolaris.org 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
1098*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
1099*9860Sgdamore@opensolaris.org 	    val | START_TRANSMIT);
1100*9860Sgdamore@opensolaris.org 	(void) dnet_set_addr(macinfo);
1101*9860Sgdamore@opensolaris.org 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
1102*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
1103*9860Sgdamore@opensolaris.org 	    val | START_RECEIVE);
1104*9860Sgdamore@opensolaris.org 	enable_interrupts(dnetp, 1);
1105*9860Sgdamore@opensolaris.org 	return (0);
1106*9860Sgdamore@opensolaris.org }
1107*9860Sgdamore@opensolaris.org 
1108*9860Sgdamore@opensolaris.org /*
1109*9860Sgdamore@opensolaris.org  *	dnet_start_board() -- start the board receiving and allow transmits.
1110*9860Sgdamore@opensolaris.org  */
1111*9860Sgdamore@opensolaris.org static int
1112*9860Sgdamore@opensolaris.org dnet_start_board(gld_mac_info_t *macinfo)
1113*9860Sgdamore@opensolaris.org {
1114*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1115*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1116*9860Sgdamore@opensolaris.org 
1117*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1118*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1119*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_start_board(0x%p)", (void *) macinfo);
1120*9860Sgdamore@opensolaris.org #endif
1121*9860Sgdamore@opensolaris.org 
1122*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1123*9860Sgdamore@opensolaris.org 	dnetp->running = B_TRUE;
1124*9860Sgdamore@opensolaris.org 	/*
1125*9860Sgdamore@opensolaris.org 	 * start the board and enable receiving
1126*9860Sgdamore@opensolaris.org 	 */
1127*9860Sgdamore@opensolaris.org 	if (!dnetp->suspended)
1128*9860Sgdamore@opensolaris.org 		(void) dnet_start(macinfo);
1129*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1130*9860Sgdamore@opensolaris.org 	return (0);
1131*9860Sgdamore@opensolaris.org }
1132*9860Sgdamore@opensolaris.org 
1133*9860Sgdamore@opensolaris.org /*
1134*9860Sgdamore@opensolaris.org  *	dnet_stop_board() -- stop board receiving
1135*9860Sgdamore@opensolaris.org  */
1136*9860Sgdamore@opensolaris.org static int
1137*9860Sgdamore@opensolaris.org dnet_stop_board(gld_mac_info_t *macinfo)
1138*9860Sgdamore@opensolaris.org {
1139*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1140*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1141*9860Sgdamore@opensolaris.org 	uint32_t		val;
1142*9860Sgdamore@opensolaris.org 
1143*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1144*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1145*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_stop_board(0x%p)", (void *) macinfo);
1146*9860Sgdamore@opensolaris.org #endif
1147*9860Sgdamore@opensolaris.org 	/*
1148*9860Sgdamore@opensolaris.org 	 * stop the board and disable transmit/receive
1149*9860Sgdamore@opensolaris.org 	 */
1150*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1151*9860Sgdamore@opensolaris.org 	if (!dnetp->suspended) {
1152*9860Sgdamore@opensolaris.org 		val = ddi_get32(dnetp->io_handle,
1153*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, OPN_MODE_REG));
1154*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
1155*9860Sgdamore@opensolaris.org 		    val & ~(START_TRANSMIT | START_RECEIVE));
1156*9860Sgdamore@opensolaris.org 	}
1157*9860Sgdamore@opensolaris.org 	dnetp->running = B_FALSE;
1158*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1159*9860Sgdamore@opensolaris.org 	return (0);
1160*9860Sgdamore@opensolaris.org }
1161*9860Sgdamore@opensolaris.org 
1162*9860Sgdamore@opensolaris.org /*
1163*9860Sgdamore@opensolaris.org  *	dnet_set_addr() -- set the physical network address on the board
1164*9860Sgdamore@opensolaris.org  *  Called with intrlock held.
1165*9860Sgdamore@opensolaris.org  */
1166*9860Sgdamore@opensolaris.org static int
1167*9860Sgdamore@opensolaris.org dnet_set_addr(gld_mac_info_t *macinfo)
1168*9860Sgdamore@opensolaris.org {
1169*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1170*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1171*9860Sgdamore@opensolaris.org 	struct tx_desc_type *desc;
1172*9860Sgdamore@opensolaris.org 	int 		current_desc;
1173*9860Sgdamore@opensolaris.org 	uint32_t	val;
1174*9860Sgdamore@opensolaris.org 
1175*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
1176*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1177*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1178*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_set_addr(0x%p)", (void *) macinfo);
1179*9860Sgdamore@opensolaris.org #endif
1180*9860Sgdamore@opensolaris.org 
1181*9860Sgdamore@opensolaris.org 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
1182*9860Sgdamore@opensolaris.org 	if (!(val & START_TRANSMIT))
1183*9860Sgdamore@opensolaris.org 		return (0);
1184*9860Sgdamore@opensolaris.org 
1185*9860Sgdamore@opensolaris.org 	current_desc = dnetp->tx_current_desc;
1186*9860Sgdamore@opensolaris.org 	desc = &dnetp->tx_desc[current_desc];
1187*9860Sgdamore@opensolaris.org 
1188*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->txlock);
1189*9860Sgdamore@opensolaris.org 	dnetp->need_saddr = 0;
1190*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->txlock);
1191*9860Sgdamore@opensolaris.org 
1192*9860Sgdamore@opensolaris.org 	if ((alloc_descriptor(macinfo)) == FAILURE) {
1193*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->txlock);
1194*9860Sgdamore@opensolaris.org 		dnetp->need_saddr = 1;
1195*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1196*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1197*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETTRACE)
1198*9860Sgdamore@opensolaris.org 			cmn_err(CE_WARN, "DNET saddr:alloc descriptor failure");
1199*9860Sgdamore@opensolaris.org #endif
1200*9860Sgdamore@opensolaris.org 		return (0);
1201*9860Sgdamore@opensolaris.org 	}
1202*9860Sgdamore@opensolaris.org 
1203*9860Sgdamore@opensolaris.org 	desc->buffer1			= dnetp->setup_buf_paddr;
1204*9860Sgdamore@opensolaris.org 	desc->buffer2			= 0;
1205*9860Sgdamore@opensolaris.org 	desc->desc1.buffer_size1 	= SETUPBUF_SIZE;
1206*9860Sgdamore@opensolaris.org 	desc->desc1.buffer_size2 	= 0;
1207*9860Sgdamore@opensolaris.org 	desc->desc1.setup_packet	= 1;
1208*9860Sgdamore@opensolaris.org 	desc->desc1.first_desc		= 0;
1209*9860Sgdamore@opensolaris.org 	desc->desc1.last_desc 		= 0;
1210*9860Sgdamore@opensolaris.org 	desc->desc1.filter_type0 	= 1;
1211*9860Sgdamore@opensolaris.org 	desc->desc1.filter_type1 	= 1;
1212*9860Sgdamore@opensolaris.org 	desc->desc1.int_on_comp		= 1;
1213*9860Sgdamore@opensolaris.org 
1214*9860Sgdamore@opensolaris.org 	desc->desc0.own = 1;
1215*9860Sgdamore@opensolaris.org 	ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
1216*9860Sgdamore@opensolaris.org 	    TX_POLL_DEMAND);
1217*9860Sgdamore@opensolaris.org 	return (0);
1218*9860Sgdamore@opensolaris.org }
1219*9860Sgdamore@opensolaris.org 
1220*9860Sgdamore@opensolaris.org /*
1221*9860Sgdamore@opensolaris.org  *	dnet_set_mac_addr() -- set the physical network address on the board
1222*9860Sgdamore@opensolaris.org  */
1223*9860Sgdamore@opensolaris.org static int
1224*9860Sgdamore@opensolaris.org dnet_set_mac_addr(gld_mac_info_t *macinfo, uchar_t *macaddr)
1225*9860Sgdamore@opensolaris.org {
1226*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1227*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1228*9860Sgdamore@opensolaris.org 	uint32_t	index;
1229*9860Sgdamore@opensolaris.org 	uint32_t	*hashp;
1230*9860Sgdamore@opensolaris.org 
1231*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1232*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1233*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_set_mac_addr(0x%p)", (void *) macinfo);
1234*9860Sgdamore@opensolaris.org #endif
1235*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1236*9860Sgdamore@opensolaris.org 
1237*9860Sgdamore@opensolaris.org 	bcopy(macaddr, dnetp->curr_macaddr, ETHERADDRL);
1238*9860Sgdamore@opensolaris.org 
1239*9860Sgdamore@opensolaris.org 	/*
1240*9860Sgdamore@opensolaris.org 	 * As we are using Imperfect filtering, the broadcast address has to
1241*9860Sgdamore@opensolaris.org 	 * be set explicitly in the 512 bit hash table.  Hence the index into
1242*9860Sgdamore@opensolaris.org 	 * the hash table is calculated and the bit set to enable reception
1243*9860Sgdamore@opensolaris.org 	 * of broadcast packets.
1244*9860Sgdamore@opensolaris.org 	 *
1245*9860Sgdamore@opensolaris.org 	 * We also use HASH_ONLY mode, without using the perfect filter for
1246*9860Sgdamore@opensolaris.org 	 * our station address, because there appears to be a bug in the
1247*9860Sgdamore@opensolaris.org 	 * 21140 where it fails to receive the specified perfect filter
1248*9860Sgdamore@opensolaris.org 	 * address.
1249*9860Sgdamore@opensolaris.org 	 *
1250*9860Sgdamore@opensolaris.org 	 * Since dlsdmult comes through here, it doesn't matter that the count
1251*9860Sgdamore@opensolaris.org 	 * is wrong for the two bits that correspond to the cases below. The
1252*9860Sgdamore@opensolaris.org 	 * worst that could happen is that we'd leave on a bit for an old
1253*9860Sgdamore@opensolaris.org 	 * macaddr, in the case where the macaddr gets changed, which is rare.
1254*9860Sgdamore@opensolaris.org 	 * Since filtering is imperfect, it is OK if that happens.
1255*9860Sgdamore@opensolaris.org 	 */
1256*9860Sgdamore@opensolaris.org 	hashp = (uint32_t *)dnetp->setup_buf_vaddr;
1257*9860Sgdamore@opensolaris.org 	index = hashindex((uchar_t *)dnet_broadcastaddr);
1258*9860Sgdamore@opensolaris.org 	hashp[ index / 16 ] |= 1 << (index % 16);
1259*9860Sgdamore@opensolaris.org 
1260*9860Sgdamore@opensolaris.org 	index = hashindex((uchar_t *)dnetp->curr_macaddr);
1261*9860Sgdamore@opensolaris.org 	hashp[ index / 16 ] |= 1 << (index % 16);
1262*9860Sgdamore@opensolaris.org 
1263*9860Sgdamore@opensolaris.org 	if (!dnetp->suspended)
1264*9860Sgdamore@opensolaris.org 		(void) dnet_set_addr(macinfo);
1265*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1266*9860Sgdamore@opensolaris.org 	return (0);
1267*9860Sgdamore@opensolaris.org }
1268*9860Sgdamore@opensolaris.org 
1269*9860Sgdamore@opensolaris.org /*
1270*9860Sgdamore@opensolaris.org  *	dnet_set_multicast() -- set (enable) or disable a multicast address
1271*9860Sgdamore@opensolaris.org  *
1272*9860Sgdamore@opensolaris.org  *	Program the hardware to enable/disable the multicast address
1273*9860Sgdamore@opensolaris.org  *	in "mcast".  Enable if "op" is non-zero, disable if zero.
1274*9860Sgdamore@opensolaris.org  */
1275*9860Sgdamore@opensolaris.org static int
1276*9860Sgdamore@opensolaris.org dnet_set_multicast(gld_mac_info_t *macinfo, uchar_t *mcast, int op)
1277*9860Sgdamore@opensolaris.org {
1278*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1279*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1280*9860Sgdamore@opensolaris.org 	uint32_t	index;
1281*9860Sgdamore@opensolaris.org 	uint32_t	*hashp;
1282*9860Sgdamore@opensolaris.org 	uint32_t	retval;
1283*9860Sgdamore@opensolaris.org 
1284*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1285*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1286*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_set_multicast(0x%p, %s)",
1287*9860Sgdamore@opensolaris.org 		    (void *) macinfo, op ? "ON" : "OFF");
1288*9860Sgdamore@opensolaris.org #endif
1289*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1290*9860Sgdamore@opensolaris.org 	index = hashindex(mcast);
1291*9860Sgdamore@opensolaris.org 	hashp = (uint32_t *)dnetp->setup_buf_vaddr;
1292*9860Sgdamore@opensolaris.org 	if (op == GLD_MULTI_ENABLE) {
1293*9860Sgdamore@opensolaris.org 		if (dnetp->multicast_cnt[index]++) {
1294*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->intrlock);
1295*9860Sgdamore@opensolaris.org 			return (0);
1296*9860Sgdamore@opensolaris.org 		}
1297*9860Sgdamore@opensolaris.org 		hashp[ index / 16 ] |= 1 << (index % 16);
1298*9860Sgdamore@opensolaris.org 	} else {
1299*9860Sgdamore@opensolaris.org 		if (--dnetp->multicast_cnt[index]) {
1300*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->intrlock);
1301*9860Sgdamore@opensolaris.org 			return (0);
1302*9860Sgdamore@opensolaris.org 		}
1303*9860Sgdamore@opensolaris.org 		hashp[ index / 16 ] &= ~ (1 << (index % 16));
1304*9860Sgdamore@opensolaris.org 	}
1305*9860Sgdamore@opensolaris.org 	if (!dnetp->suspended)
1306*9860Sgdamore@opensolaris.org 		retval = dnet_set_addr(macinfo);
1307*9860Sgdamore@opensolaris.org 	else
1308*9860Sgdamore@opensolaris.org 		retval = 0;
1309*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1310*9860Sgdamore@opensolaris.org 	return (retval);
1311*9860Sgdamore@opensolaris.org }
1312*9860Sgdamore@opensolaris.org 
1313*9860Sgdamore@opensolaris.org /*
1314*9860Sgdamore@opensolaris.org  * A hashing function used for setting the
1315*9860Sgdamore@opensolaris.org  * node address or a multicast address
1316*9860Sgdamore@opensolaris.org  */
1317*9860Sgdamore@opensolaris.org static uint32_t
1318*9860Sgdamore@opensolaris.org hashindex(uchar_t *address)
1319*9860Sgdamore@opensolaris.org {
1320*9860Sgdamore@opensolaris.org 	uint32_t	crc = (uint32_t)HASH_CRC;
1321*9860Sgdamore@opensolaris.org 	uint32_t const 	POLY = HASH_POLY;
1322*9860Sgdamore@opensolaris.org 	uint32_t	msb;
1323*9860Sgdamore@opensolaris.org 	int32_t 	byteslength;
1324*9860Sgdamore@opensolaris.org 	uint8_t 	currentbyte;
1325*9860Sgdamore@opensolaris.org 	uint32_t 	index;
1326*9860Sgdamore@opensolaris.org 	int32_t 	bit;
1327*9860Sgdamore@opensolaris.org 	int32_t		shift;
1328*9860Sgdamore@opensolaris.org 
1329*9860Sgdamore@opensolaris.org 	for (byteslength = 0; byteslength < ETHERADDRL; byteslength++) {
1330*9860Sgdamore@opensolaris.org 		currentbyte = address[byteslength];
1331*9860Sgdamore@opensolaris.org 		for (bit = 0; bit < 8; bit++) {
1332*9860Sgdamore@opensolaris.org 			msb = crc >> 31;
1333*9860Sgdamore@opensolaris.org 			crc <<= 1;
1334*9860Sgdamore@opensolaris.org 			if (msb ^ (currentbyte & 1)) {
1335*9860Sgdamore@opensolaris.org 				crc ^= POLY;
1336*9860Sgdamore@opensolaris.org 				crc |= 0x00000001;
1337*9860Sgdamore@opensolaris.org 			}
1338*9860Sgdamore@opensolaris.org 			currentbyte >>= 1;
1339*9860Sgdamore@opensolaris.org 		}
1340*9860Sgdamore@opensolaris.org 	}
1341*9860Sgdamore@opensolaris.org 
1342*9860Sgdamore@opensolaris.org 	for (index = 0, bit = 23, shift = 8; shift >= 0; bit++, shift--) {
1343*9860Sgdamore@opensolaris.org 		index |= (((crc >> bit) & 1) << shift);
1344*9860Sgdamore@opensolaris.org 	}
1345*9860Sgdamore@opensolaris.org 	return (index);
1346*9860Sgdamore@opensolaris.org }
1347*9860Sgdamore@opensolaris.org 
1348*9860Sgdamore@opensolaris.org /*
1349*9860Sgdamore@opensolaris.org  * dnet_set_promiscuous() -- set or reset promiscuous mode on the board
1350*9860Sgdamore@opensolaris.org  *
1351*9860Sgdamore@opensolaris.org  *	Program the hardware to enable/disable promiscuous mode.
1352*9860Sgdamore@opensolaris.org  *	Enable if "on" is non-zero, disable if zero.
1353*9860Sgdamore@opensolaris.org  */
1354*9860Sgdamore@opensolaris.org 
1355*9860Sgdamore@opensolaris.org static int
1356*9860Sgdamore@opensolaris.org dnet_set_promiscuous(gld_mac_info_t *macinfo, int on)
1357*9860Sgdamore@opensolaris.org {
1358*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp;
1359*9860Sgdamore@opensolaris.org 	uint32_t val;
1360*9860Sgdamore@opensolaris.org 
1361*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1362*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1363*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_set_promiscuous(0x%p, %s)",
1364*9860Sgdamore@opensolaris.org 		    (void *) macinfo, on ? "ON" : "OFF");
1365*9860Sgdamore@opensolaris.org #endif
1366*9860Sgdamore@opensolaris.org 
1367*9860Sgdamore@opensolaris.org 	dnetp = (struct dnetinstance *)macinfo->gldm_private;
1368*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1369*9860Sgdamore@opensolaris.org 	if (dnetp->promisc == on) {
1370*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
1371*9860Sgdamore@opensolaris.org 		return (SUCCESS);
1372*9860Sgdamore@opensolaris.org 	}
1373*9860Sgdamore@opensolaris.org 	dnetp->promisc = on;
1374*9860Sgdamore@opensolaris.org 
1375*9860Sgdamore@opensolaris.org 	if (!dnetp->suspended) {
1376*9860Sgdamore@opensolaris.org 		val = ddi_get32(dnetp->io_handle,
1377*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, OPN_MODE_REG));
1378*9860Sgdamore@opensolaris.org 		if (on != GLD_MAC_PROMISC_NONE)
1379*9860Sgdamore@opensolaris.org 			ddi_put32(dnetp->io_handle,
1380*9860Sgdamore@opensolaris.org 			    REG32(dnetp->io_reg, OPN_MODE_REG),
1381*9860Sgdamore@opensolaris.org 			    val | PROM_MODE);
1382*9860Sgdamore@opensolaris.org 		else
1383*9860Sgdamore@opensolaris.org 			ddi_put32(dnetp->io_handle,
1384*9860Sgdamore@opensolaris.org 			    REG32(dnetp->io_reg, OPN_MODE_REG),
1385*9860Sgdamore@opensolaris.org 			    val & (~PROM_MODE));
1386*9860Sgdamore@opensolaris.org 	}
1387*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1388*9860Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
1389*9860Sgdamore@opensolaris.org }
1390*9860Sgdamore@opensolaris.org 
1391*9860Sgdamore@opensolaris.org /*
1392*9860Sgdamore@opensolaris.org  * dnet_get_stats() -- update statistics
1393*9860Sgdamore@opensolaris.org  *
1394*9860Sgdamore@opensolaris.org  *	GLD calls this routine just before it reads the driver's statistics
1395*9860Sgdamore@opensolaris.org  *	structure.  If your board maintains statistics, this is the time to
1396*9860Sgdamore@opensolaris.org  *	read them in and update the values in the structure.  If the driver
1397*9860Sgdamore@opensolaris.org  *	maintains statistics continuously, this routine need do nothing.
1398*9860Sgdamore@opensolaris.org  */
1399*9860Sgdamore@opensolaris.org 
1400*9860Sgdamore@opensolaris.org static int
1401*9860Sgdamore@opensolaris.org dnet_get_stats(gld_mac_info_t *macinfo, struct gld_stats *sp)
1402*9860Sgdamore@opensolaris.org {
1403*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1404*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1405*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1406*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
1407*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_get_stats(0x%p)", (void *) macinfo);
1408*9860Sgdamore@opensolaris.org #endif
1409*9860Sgdamore@opensolaris.org 	sp->glds_errrcv = dnetp->stat_errrcv;
1410*9860Sgdamore@opensolaris.org 	sp->glds_overflow = dnetp->stat_overflow;
1411*9860Sgdamore@opensolaris.org 	sp->glds_intr = dnetp->stat_intr;
1412*9860Sgdamore@opensolaris.org 	sp->glds_defer = dnetp->stat_defer;
1413*9860Sgdamore@opensolaris.org 	sp->glds_missed	= dnetp->stat_missed;
1414*9860Sgdamore@opensolaris.org 	sp->glds_norcvbuf = dnetp->stat_norcvbuf;
1415*9860Sgdamore@opensolaris.org 	sp->glds_crc = dnetp->stat_crc;
1416*9860Sgdamore@opensolaris.org 	sp->glds_short = dnetp->stat_short;
1417*9860Sgdamore@opensolaris.org 	sp->glds_frame = dnetp->stat_frame;
1418*9860Sgdamore@opensolaris.org 	sp->glds_errxmt = dnetp->stat_errxmt;
1419*9860Sgdamore@opensolaris.org 	sp->glds_collisions	= dnetp->stat_collisions;
1420*9860Sgdamore@opensolaris.org 	sp->glds_xmtlatecoll = dnetp->stat_xmtlatecoll;
1421*9860Sgdamore@opensolaris.org 	sp->glds_excoll = dnetp->stat_excoll;
1422*9860Sgdamore@opensolaris.org 	sp->glds_underflow = dnetp->stat_underflow;
1423*9860Sgdamore@opensolaris.org 	sp->glds_nocarrier = dnetp->stat_nocarrier;
1424*9860Sgdamore@opensolaris.org 
1425*9860Sgdamore@opensolaris.org 	/* stats from instance structure */
1426*9860Sgdamore@opensolaris.org 	if (dnetp->mii_up) {
1427*9860Sgdamore@opensolaris.org 		sp->glds_speed = dnetp->mii_speed * 1000000;
1428*9860Sgdamore@opensolaris.org 		sp->glds_duplex = dnetp->mii_duplex ?
1429*9860Sgdamore@opensolaris.org 		    GLD_DUPLEX_FULL : GLD_DUPLEX_HALF;
1430*9860Sgdamore@opensolaris.org 	} else {
1431*9860Sgdamore@opensolaris.org 		sp->glds_speed = dnetp->speed * 1000000;
1432*9860Sgdamore@opensolaris.org 		sp->glds_duplex =
1433*9860Sgdamore@opensolaris.org 		    dnetp->full_duplex ? GLD_DUPLEX_FULL : GLD_DUPLEX_HALF;
1434*9860Sgdamore@opensolaris.org 	}
1435*9860Sgdamore@opensolaris.org 
1436*9860Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
1437*9860Sgdamore@opensolaris.org }
1438*9860Sgdamore@opensolaris.org 
1439*9860Sgdamore@opensolaris.org /*
1440*9860Sgdamore@opensolaris.org  *	dnet_send() -- send a packet
1441*9860Sgdamore@opensolaris.org  *
1442*9860Sgdamore@opensolaris.org  *	Called when a packet is ready to be transmitted. A pointer to an
1443*9860Sgdamore@opensolaris.org  *	M_DATA message that contains the packet is passed to this routine.
1444*9860Sgdamore@opensolaris.org  *	The complete LLC header is contained in the message's first message
1445*9860Sgdamore@opensolaris.org  *	block, and the remainder of the packet is contained within
1446*9860Sgdamore@opensolaris.org  *	additional M_DATA message blocks linked to the first message block.
1447*9860Sgdamore@opensolaris.org  */
1448*9860Sgdamore@opensolaris.org 
1449*9860Sgdamore@opensolaris.org #define	NextTXIndex(index) (((index)+1) % dnetp->max_tx_desc)
1450*9860Sgdamore@opensolaris.org #define	PrevTXIndex(index) (((index)-1) < 0 ? dnetp->max_tx_desc - 1: (index)-1)
1451*9860Sgdamore@opensolaris.org 
1452*9860Sgdamore@opensolaris.org static int
1453*9860Sgdamore@opensolaris.org dnet_send(gld_mac_info_t *macinfo, mblk_t *mp)
1454*9860Sgdamore@opensolaris.org {
1455*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =		/* Our private device info */
1456*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1457*9860Sgdamore@opensolaris.org 	struct tx_desc_type	*ring = dnetp->tx_desc;
1458*9860Sgdamore@opensolaris.org 	int		mblen, totlen;
1459*9860Sgdamore@opensolaris.org 	int		index, end_index, start_index;
1460*9860Sgdamore@opensolaris.org 	int		avail;
1461*9860Sgdamore@opensolaris.org 	int		error;
1462*9860Sgdamore@opensolaris.org 	int		bufn;
1463*9860Sgdamore@opensolaris.org 	int		bp_count;
1464*9860Sgdamore@opensolaris.org 	int		retval;
1465*9860Sgdamore@opensolaris.org 	mblk_t		*bp;
1466*9860Sgdamore@opensolaris.org 	uint32_t	tx_interrupt_mask;
1467*9860Sgdamore@opensolaris.org 
1468*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1469*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETSEND)
1470*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_send(0x%p, 0x%p)",
1471*9860Sgdamore@opensolaris.org 		    (void *) macinfo, (void *) mp);
1472*9860Sgdamore@opensolaris.org #endif
1473*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->txlock);
1474*9860Sgdamore@opensolaris.org 	/* if suspended, drop the packet on the floor, we missed it */
1475*9860Sgdamore@opensolaris.org 	if (dnetp->suspended) {
1476*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1477*9860Sgdamore@opensolaris.org 		freemsg(mp);
1478*9860Sgdamore@opensolaris.org 		return (0);
1479*9860Sgdamore@opensolaris.org 	}
1480*9860Sgdamore@opensolaris.org 	if (dnetp->need_saddr) {
1481*9860Sgdamore@opensolaris.org 		/* XXX function return value ignored */
1482*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1483*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->intrlock);
1484*9860Sgdamore@opensolaris.org 		(void) dnet_set_addr(macinfo);
1485*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
1486*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->txlock);
1487*9860Sgdamore@opensolaris.org 	}
1488*9860Sgdamore@opensolaris.org 
1489*9860Sgdamore@opensolaris.org 	/* reclaim any xmit descriptors completed */
1490*9860Sgdamore@opensolaris.org 	dnet_reclaim_Tx_desc(macinfo);
1491*9860Sgdamore@opensolaris.org 
1492*9860Sgdamore@opensolaris.org 	/*
1493*9860Sgdamore@opensolaris.org 	 * Use the data buffers from the message and construct the
1494*9860Sgdamore@opensolaris.org 	 * scatter/gather list by calling ddi_dma_addr_bind_handle().
1495*9860Sgdamore@opensolaris.org 	 */
1496*9860Sgdamore@opensolaris.org 	error = bp_count = 0;
1497*9860Sgdamore@opensolaris.org 	totlen = 0;
1498*9860Sgdamore@opensolaris.org 	bp = mp;
1499*9860Sgdamore@opensolaris.org 	bufn = 0;
1500*9860Sgdamore@opensolaris.org 	index = start_index = dnetp->tx_current_desc;
1501*9860Sgdamore@opensolaris.org 	avail = dnetp->free_desc;
1502*9860Sgdamore@opensolaris.org 	while (bp != NULL) {
1503*9860Sgdamore@opensolaris.org 		uint_t ncookies;
1504*9860Sgdamore@opensolaris.org 		ddi_dma_cookie_t dma_cookie;
1505*9860Sgdamore@opensolaris.org 
1506*9860Sgdamore@opensolaris.org 		if (++bp_count > DNET_MAX_FRAG) {
1507*9860Sgdamore@opensolaris.org #ifndef DNET_NOISY
1508*9860Sgdamore@opensolaris.org 			(void) pullupmsg(bp, -1);
1509*9860Sgdamore@opensolaris.org #else
1510*9860Sgdamore@opensolaris.org 			if (pullupmsg(bp, -1))
1511*9860Sgdamore@opensolaris.org 				cmn_err(CE_NOTE, "DNET: pulled up send msg");
1512*9860Sgdamore@opensolaris.org 			else
1513*9860Sgdamore@opensolaris.org 				cmn_err(CE_NOTE,
1514*9860Sgdamore@opensolaris.org 				    "DNET: couldn't pullup send msg");
1515*9860Sgdamore@opensolaris.org #endif
1516*9860Sgdamore@opensolaris.org 		}
1517*9860Sgdamore@opensolaris.org 
1518*9860Sgdamore@opensolaris.org 		mblen = (int)(bp->b_wptr - bp->b_rptr);
1519*9860Sgdamore@opensolaris.org 
1520*9860Sgdamore@opensolaris.org 		if (!mblen) {	/* skip zero-length message blocks */
1521*9860Sgdamore@opensolaris.org 			bp = bp->b_cont;
1522*9860Sgdamore@opensolaris.org 			continue;
1523*9860Sgdamore@opensolaris.org 		}
1524*9860Sgdamore@opensolaris.org 
1525*9860Sgdamore@opensolaris.org 		retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL,
1526*9860Sgdamore@opensolaris.org 		    (caddr_t)bp->b_rptr, mblen,
1527*9860Sgdamore@opensolaris.org 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
1528*9860Sgdamore@opensolaris.org 		    &dma_cookie, &ncookies);
1529*9860Sgdamore@opensolaris.org 
1530*9860Sgdamore@opensolaris.org 		switch (retval) {
1531*9860Sgdamore@opensolaris.org 		case DDI_DMA_MAPPED:
1532*9860Sgdamore@opensolaris.org 			break;		/* everything's fine */
1533*9860Sgdamore@opensolaris.org 
1534*9860Sgdamore@opensolaris.org 		case DDI_DMA_NORESOURCES:
1535*9860Sgdamore@opensolaris.org 			error = 1;	/* allow retry by gld */
1536*9860Sgdamore@opensolaris.org 			break;
1537*9860Sgdamore@opensolaris.org 
1538*9860Sgdamore@opensolaris.org 		case DDI_DMA_NOMAPPING:
1539*9860Sgdamore@opensolaris.org 		case DDI_DMA_INUSE:
1540*9860Sgdamore@opensolaris.org 		case DDI_DMA_TOOBIG:
1541*9860Sgdamore@opensolaris.org 		default:
1542*9860Sgdamore@opensolaris.org 			error = 2;	/* error, no retry */
1543*9860Sgdamore@opensolaris.org 			break;
1544*9860Sgdamore@opensolaris.org 		}
1545*9860Sgdamore@opensolaris.org 
1546*9860Sgdamore@opensolaris.org 		/*
1547*9860Sgdamore@opensolaris.org 		 * we can use two cookies per descriptor (i.e buffer1 and
1548*9860Sgdamore@opensolaris.org 		 * buffer2) so we need at least (ncookies+1)/2 descriptors.
1549*9860Sgdamore@opensolaris.org 		 */
1550*9860Sgdamore@opensolaris.org 		if (((ncookies + 1) >> 1) > dnetp->free_desc) {
1551*9860Sgdamore@opensolaris.org 			(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1552*9860Sgdamore@opensolaris.org 			error = 1;
1553*9860Sgdamore@opensolaris.org 			break;
1554*9860Sgdamore@opensolaris.org 		}
1555*9860Sgdamore@opensolaris.org 
1556*9860Sgdamore@opensolaris.org 		/* setup the descriptors for this data buffer */
1557*9860Sgdamore@opensolaris.org 		while (ncookies) {
1558*9860Sgdamore@opensolaris.org 			end_index = index;
1559*9860Sgdamore@opensolaris.org 			if (bufn % 2) {
1560*9860Sgdamore@opensolaris.org 				ring[index].buffer2 =
1561*9860Sgdamore@opensolaris.org 				    (uint32_t)dma_cookie.dmac_address;
1562*9860Sgdamore@opensolaris.org 				ring[index].desc1.buffer_size2 =
1563*9860Sgdamore@opensolaris.org 				    dma_cookie.dmac_size;
1564*9860Sgdamore@opensolaris.org 				index = NextTXIndex(index); /* goto next desc */
1565*9860Sgdamore@opensolaris.org 			} else {
1566*9860Sgdamore@opensolaris.org 				/* initialize the descriptor */
1567*9860Sgdamore@opensolaris.org 				ASSERT(ring[index].desc0.own == 0);
1568*9860Sgdamore@opensolaris.org 				*(uint32_t *)&ring[index].desc0 = 0;
1569*9860Sgdamore@opensolaris.org 				*(uint32_t *)&ring[index].desc1 &=
1570*9860Sgdamore@opensolaris.org 				    DNET_END_OF_RING;
1571*9860Sgdamore@opensolaris.org 				ring[index].buffer1 =
1572*9860Sgdamore@opensolaris.org 				    (uint32_t)dma_cookie.dmac_address;
1573*9860Sgdamore@opensolaris.org 				ring[index].desc1.buffer_size1 =
1574*9860Sgdamore@opensolaris.org 				    dma_cookie.dmac_size;
1575*9860Sgdamore@opensolaris.org 				ring[index].buffer2 = (uint32_t)(0);
1576*9860Sgdamore@opensolaris.org 				dnetp->free_desc--;
1577*9860Sgdamore@opensolaris.org 				ASSERT(dnetp->free_desc >= 0);
1578*9860Sgdamore@opensolaris.org 			}
1579*9860Sgdamore@opensolaris.org 			totlen += dma_cookie.dmac_size;
1580*9860Sgdamore@opensolaris.org 			bufn++;
1581*9860Sgdamore@opensolaris.org 			if (--ncookies)
1582*9860Sgdamore@opensolaris.org 				ddi_dma_nextcookie(dnetp->dma_handle_tx,
1583*9860Sgdamore@opensolaris.org 				    &dma_cookie);
1584*9860Sgdamore@opensolaris.org 		}
1585*9860Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1586*9860Sgdamore@opensolaris.org 		bp = bp->b_cont;
1587*9860Sgdamore@opensolaris.org 	}
1588*9860Sgdamore@opensolaris.org 
1589*9860Sgdamore@opensolaris.org 	if (error == 1) {
1590*9860Sgdamore@opensolaris.org 		dnetp->stat_defer++;
1591*9860Sgdamore@opensolaris.org 		dnetp->free_desc = avail;
1592*9860Sgdamore@opensolaris.org 		dnetp->need_gld_sched = 1;
1593*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1594*9860Sgdamore@opensolaris.org 		return (GLD_TX_RESEND);
1595*9860Sgdamore@opensolaris.org 	} else if (error) {
1596*9860Sgdamore@opensolaris.org 		dnetp->free_desc = avail;
1597*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1598*9860Sgdamore@opensolaris.org 		freemsg(mp);
1599*9860Sgdamore@opensolaris.org 		return (0);	/* Drop packet, don't retry */
1600*9860Sgdamore@opensolaris.org 	}
1601*9860Sgdamore@opensolaris.org 
1602*9860Sgdamore@opensolaris.org 	if (totlen > ETHERMAX) {
1603*9860Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen);
1604*9860Sgdamore@opensolaris.org 		dnetp->free_desc = avail;
1605*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1606*9860Sgdamore@opensolaris.org 		freemsg(mp);
1607*9860Sgdamore@opensolaris.org 		return (0);	/* We don't want to repeat this attempt */
1608*9860Sgdamore@opensolaris.org 	}
1609*9860Sgdamore@opensolaris.org 
1610*9860Sgdamore@opensolaris.org 	/*
1611*9860Sgdamore@opensolaris.org 	 * Remeber the message buffer pointer to do freemsg() at xmit
1612*9860Sgdamore@opensolaris.org 	 * interrupt time.
1613*9860Sgdamore@opensolaris.org 	 */
1614*9860Sgdamore@opensolaris.org 	dnetp->tx_msgbufp[end_index] = mp;
1615*9860Sgdamore@opensolaris.org 
1616*9860Sgdamore@opensolaris.org 	/*
1617*9860Sgdamore@opensolaris.org 	 * Now set the first/last buffer and own bits
1618*9860Sgdamore@opensolaris.org 	 * Since the 21040 looks for these bits set in the
1619*9860Sgdamore@opensolaris.org 	 * first buffer, work backwards in multiple buffers.
1620*9860Sgdamore@opensolaris.org 	 */
1621*9860Sgdamore@opensolaris.org 	ring[end_index].desc1.last_desc = 1;
1622*9860Sgdamore@opensolaris.org 	ring[end_index].desc1.int_on_comp = 1;
1623*9860Sgdamore@opensolaris.org 	for (index = end_index; index != start_index;
1624*9860Sgdamore@opensolaris.org 	    index = PrevTXIndex(index))
1625*9860Sgdamore@opensolaris.org 		ring[index].desc0.own = 1;
1626*9860Sgdamore@opensolaris.org 	ring[start_index].desc1.first_desc = 1;
1627*9860Sgdamore@opensolaris.org 	ring[start_index].desc0.own = 1;
1628*9860Sgdamore@opensolaris.org 
1629*9860Sgdamore@opensolaris.org 	dnetp->tx_current_desc = NextTXIndex(end_index);
1630*9860Sgdamore@opensolaris.org 
1631*9860Sgdamore@opensolaris.org 	/*
1632*9860Sgdamore@opensolaris.org 	 * Safety check: make sure end-of-ring is set in last desc.
1633*9860Sgdamore@opensolaris.org 	 */
1634*9860Sgdamore@opensolaris.org 	ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0);
1635*9860Sgdamore@opensolaris.org 
1636*9860Sgdamore@opensolaris.org 	/*
1637*9860Sgdamore@opensolaris.org 	 * Enable xmit interrupt if we are running out of xmit descriptors
1638*9860Sgdamore@opensolaris.org 	 * or there are more packets on the queue waiting to be transmitted.
1639*9860Sgdamore@opensolaris.org 	 */
1640*9860Sgdamore@opensolaris.org #ifdef GLD_INTR_WAIT	/* XXX This relies on new GLD changes */
1641*9860Sgdamore@opensolaris.org 	if (dnetp->free_desc <= dnet_xmit_threshold)
1642*9860Sgdamore@opensolaris.org 		tx_interrupt_mask = TX_INTERRUPT_MASK;
1643*9860Sgdamore@opensolaris.org 	else
1644*9860Sgdamore@opensolaris.org 		tx_interrupt_mask = (macinfo->gldm_GLD_flags & GLD_INTR_WAIT) ?
1645*9860Sgdamore@opensolaris.org 		    TX_INTERRUPT_MASK : 0;
1646*9860Sgdamore@opensolaris.org #else
1647*9860Sgdamore@opensolaris.org 	tx_interrupt_mask = TX_INTERRUPT_MASK;
1648*9860Sgdamore@opensolaris.org #endif
1649*9860Sgdamore@opensolaris.org 
1650*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->txlock);
1651*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1652*9860Sgdamore@opensolaris.org 	enable_interrupts(dnetp, tx_interrupt_mask);
1653*9860Sgdamore@opensolaris.org 
1654*9860Sgdamore@opensolaris.org 	/*
1655*9860Sgdamore@opensolaris.org 	 * Kick the transmitter
1656*9860Sgdamore@opensolaris.org 	 */
1657*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_POLL_REG),
1658*9860Sgdamore@opensolaris.org 	    TX_POLL_DEMAND);
1659*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1660*9860Sgdamore@opensolaris.org 	return (GLD_TX_OK);		/* successful transmit attempt */
1661*9860Sgdamore@opensolaris.org }
1662*9860Sgdamore@opensolaris.org 
1663*9860Sgdamore@opensolaris.org /*
1664*9860Sgdamore@opensolaris.org  *	dnetintr() -- interrupt from board to inform us that a receive or
1665*9860Sgdamore@opensolaris.org  *	transmit has completed.
1666*9860Sgdamore@opensolaris.org  */
1667*9860Sgdamore@opensolaris.org 
1668*9860Sgdamore@opensolaris.org 
1669*9860Sgdamore@opensolaris.org static uint_t
1670*9860Sgdamore@opensolaris.org dnetintr(gld_mac_info_t *macinfo)
1671*9860Sgdamore@opensolaris.org {
1672*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =	/* Our private device info */
1673*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1674*9860Sgdamore@opensolaris.org 	uint32_t		int_status;
1675*9860Sgdamore@opensolaris.org 	uint32_t		tx_interrupt_mask;
1676*9860Sgdamore@opensolaris.org 
1677*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
1678*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1679*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETINT)
1680*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnetintr(0x%p)", (void *)macinfo);
1681*9860Sgdamore@opensolaris.org #endif
1682*9860Sgdamore@opensolaris.org 	if (dnetp->suspended) {
1683*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
1684*9860Sgdamore@opensolaris.org 		return (DDI_INTR_UNCLAIMED);
1685*9860Sgdamore@opensolaris.org 	}
1686*9860Sgdamore@opensolaris.org 
1687*9860Sgdamore@opensolaris.org 	int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg,
1688*9860Sgdamore@opensolaris.org 	    STATUS_REG));
1689*9860Sgdamore@opensolaris.org 
1690*9860Sgdamore@opensolaris.org 	/*
1691*9860Sgdamore@opensolaris.org 	 * If interrupt was not from this board
1692*9860Sgdamore@opensolaris.org 	 */
1693*9860Sgdamore@opensolaris.org 	if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) {
1694*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
1695*9860Sgdamore@opensolaris.org 		return (DDI_INTR_UNCLAIMED);
1696*9860Sgdamore@opensolaris.org 	}
1697*9860Sgdamore@opensolaris.org 
1698*9860Sgdamore@opensolaris.org 	dnetp->stat_intr++;
1699*9860Sgdamore@opensolaris.org 
1700*9860Sgdamore@opensolaris.org 	if (int_status & GPTIMER_INTR) {
1701*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
1702*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR);
1703*9860Sgdamore@opensolaris.org 		if (dnetp->timer.cb)
1704*9860Sgdamore@opensolaris.org 			dnetp->timer.cb(dnetp);
1705*9860Sgdamore@opensolaris.org 		else
1706*9860Sgdamore@opensolaris.org 			cmn_err(CE_WARN, "dnet: unhandled timer interrupt");
1707*9860Sgdamore@opensolaris.org 	}
1708*9860Sgdamore@opensolaris.org 
1709*9860Sgdamore@opensolaris.org 	if (int_status & TX_INTR) {
1710*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
1711*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, STATUS_REG), TX_INTR);
1712*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->txlock);
1713*9860Sgdamore@opensolaris.org 		if (dnetp->need_gld_sched) {
1714*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->txlock);
1715*9860Sgdamore@opensolaris.org 			mutex_exit(&dnetp->intrlock);
1716*9860Sgdamore@opensolaris.org 			gld_sched(macinfo);
1717*9860Sgdamore@opensolaris.org 			mutex_enter(&dnetp->intrlock);
1718*9860Sgdamore@opensolaris.org 			mutex_enter(&dnetp->txlock);
1719*9860Sgdamore@opensolaris.org 			dnetp->need_gld_sched = 0;
1720*9860Sgdamore@opensolaris.org 		}
1721*9860Sgdamore@opensolaris.org 		/* reclaim any xmit descriptors that are completed */
1722*9860Sgdamore@opensolaris.org 		dnet_reclaim_Tx_desc(macinfo);
1723*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
1724*9860Sgdamore@opensolaris.org 	}
1725*9860Sgdamore@opensolaris.org 
1726*9860Sgdamore@opensolaris.org 	/*
1727*9860Sgdamore@opensolaris.org 	 * Check if receive interrupt bit is set
1728*9860Sgdamore@opensolaris.org 	 */
1729*9860Sgdamore@opensolaris.org 	if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) {
1730*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
1731*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, STATUS_REG),
1732*9860Sgdamore@opensolaris.org 		    int_status & (RX_INTR | RX_UNAVAIL_INTR));
1733*9860Sgdamore@opensolaris.org 		dnet_getp(macinfo);
1734*9860Sgdamore@opensolaris.org 	}
1735*9860Sgdamore@opensolaris.org 
1736*9860Sgdamore@opensolaris.org 	if (int_status & ABNORMAL_INTR_SUMM) {
1737*9860Sgdamore@opensolaris.org 		/*
1738*9860Sgdamore@opensolaris.org 		 * Check for system error
1739*9860Sgdamore@opensolaris.org 		 */
1740*9860Sgdamore@opensolaris.org 		if (int_status & SYS_ERR) {
1741*9860Sgdamore@opensolaris.org 			if ((int_status & SYS_ERR_BITS) == MASTER_ABORT)
1742*9860Sgdamore@opensolaris.org 				cmn_err(CE_WARN, "DNET: Bus Master Abort");
1743*9860Sgdamore@opensolaris.org 			if ((int_status & SYS_ERR_BITS) == TARGET_ABORT)
1744*9860Sgdamore@opensolaris.org 				cmn_err(CE_WARN, "DNET: Bus Target Abort");
1745*9860Sgdamore@opensolaris.org 			if ((int_status & SYS_ERR_BITS) == PARITY_ERROR)
1746*9860Sgdamore@opensolaris.org 				cmn_err(CE_WARN, "DNET: Parity error");
1747*9860Sgdamore@opensolaris.org 		}
1748*9860Sgdamore@opensolaris.org 
1749*9860Sgdamore@opensolaris.org 		/*
1750*9860Sgdamore@opensolaris.org 		 * If the jabber has timed out then reset the chip
1751*9860Sgdamore@opensolaris.org 		 */
1752*9860Sgdamore@opensolaris.org 		if (int_status & TX_JABBER_TIMEOUT)
1753*9860Sgdamore@opensolaris.org 			cmn_err(CE_WARN, "DNET: Jabber timeout.");
1754*9860Sgdamore@opensolaris.org 
1755*9860Sgdamore@opensolaris.org 		/*
1756*9860Sgdamore@opensolaris.org 		 * If an underflow has occurred, reset the chip
1757*9860Sgdamore@opensolaris.org 		 */
1758*9860Sgdamore@opensolaris.org 		if (int_status & TX_UNDERFLOW)
1759*9860Sgdamore@opensolaris.org 			cmn_err(CE_WARN, "DNET: Tx Underflow.");
1760*9860Sgdamore@opensolaris.org 
1761*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1762*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETINT)
1763*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE, "Trying to reset...");
1764*9860Sgdamore@opensolaris.org #endif
1765*9860Sgdamore@opensolaris.org 		dnet_reset_board(macinfo);
1766*9860Sgdamore@opensolaris.org 		dnet_init_board(macinfo);
1767*9860Sgdamore@opensolaris.org 		/* XXX function return value ignored */
1768*9860Sgdamore@opensolaris.org 		(void) dnet_start(macinfo);
1769*9860Sgdamore@opensolaris.org 	}
1770*9860Sgdamore@opensolaris.org 
1771*9860Sgdamore@opensolaris.org 	/*
1772*9860Sgdamore@opensolaris.org 	 * Enable the interrupts. Enable xmit interrupt only if we are
1773*9860Sgdamore@opensolaris.org 	 * running out of free descriptors or if there are packets
1774*9860Sgdamore@opensolaris.org 	 * in the queue waiting to be transmitted.
1775*9860Sgdamore@opensolaris.org 	 */
1776*9860Sgdamore@opensolaris.org #ifdef GLD_INTR_WAIT	/* XXX This relies on new GLD changes */
1777*9860Sgdamore@opensolaris.org 	if (dnetp->free_desc <= dnet_xmit_threshold)
1778*9860Sgdamore@opensolaris.org 		tx_interrupt_mask = TX_INTERRUPT_MASK;
1779*9860Sgdamore@opensolaris.org 	else
1780*9860Sgdamore@opensolaris.org 		tx_interrupt_mask = (macinfo->gldm_GLD_flags & GLD_INTR_WAIT) ?
1781*9860Sgdamore@opensolaris.org 		    TX_INTERRUPT_MASK : 0;
1782*9860Sgdamore@opensolaris.org #else
1783*9860Sgdamore@opensolaris.org 	tx_interrupt_mask = TX_INTERRUPT_MASK;
1784*9860Sgdamore@opensolaris.org #endif
1785*9860Sgdamore@opensolaris.org 	enable_interrupts(dnetp, tx_interrupt_mask);
1786*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
1787*9860Sgdamore@opensolaris.org 	return (DDI_INTR_CLAIMED);	/* Indicate it was our interrupt */
1788*9860Sgdamore@opensolaris.org }
1789*9860Sgdamore@opensolaris.org 
1790*9860Sgdamore@opensolaris.org static void
1791*9860Sgdamore@opensolaris.org dnet_getp(gld_mac_info_t *macinfo)
1792*9860Sgdamore@opensolaris.org {
1793*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =
1794*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
1795*9860Sgdamore@opensolaris.org 	int packet_length, index;
1796*9860Sgdamore@opensolaris.org 	mblk_t	*mp;
1797*9860Sgdamore@opensolaris.org 	caddr_t 	virtual_address;
1798*9860Sgdamore@opensolaris.org 	struct	rx_desc_type *desc = dnetp->rx_desc;
1799*9860Sgdamore@opensolaris.org 	int marker = dnetp->rx_current_desc;
1800*9860Sgdamore@opensolaris.org 	int misses;
1801*9860Sgdamore@opensolaris.org 
1802*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1803*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETRECV)
1804*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_getp(0x%p)", (void *)macinfo);
1805*9860Sgdamore@opensolaris.org #endif
1806*9860Sgdamore@opensolaris.org 
1807*9860Sgdamore@opensolaris.org 	if (!dnetp->overrun_workaround) {
1808*9860Sgdamore@opensolaris.org 		/*
1809*9860Sgdamore@opensolaris.org 		 * If the workaround is not in place, we must still update
1810*9860Sgdamore@opensolaris.org 		 * the missed frame statistic from the on-chip counter.
1811*9860Sgdamore@opensolaris.org 		 */
1812*9860Sgdamore@opensolaris.org 		misses = ddi_get32(dnetp->io_handle,
1813*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, MISSED_FRAME_REG));
1814*9860Sgdamore@opensolaris.org 		dnetp->stat_missed += (misses & MISSED_FRAME_MASK);
1815*9860Sgdamore@opensolaris.org 	}
1816*9860Sgdamore@opensolaris.org 
1817*9860Sgdamore@opensolaris.org 	/* While host owns the current descriptor */
1818*9860Sgdamore@opensolaris.org 	while (!(desc[dnetp->rx_current_desc].desc0.own)) {
1819*9860Sgdamore@opensolaris.org 		struct free_ptr *frp;
1820*9860Sgdamore@opensolaris.org 		caddr_t newbuf;
1821*9860Sgdamore@opensolaris.org 		struct rbuf_list *rp;
1822*9860Sgdamore@opensolaris.org 
1823*9860Sgdamore@opensolaris.org 		index = dnetp->rx_current_desc;
1824*9860Sgdamore@opensolaris.org 		ASSERT(desc[index].desc0.first_desc != 0);
1825*9860Sgdamore@opensolaris.org 
1826*9860Sgdamore@opensolaris.org 		/*
1827*9860Sgdamore@opensolaris.org 		 * DMA overrun errata from DEC: avoid possible bus hangs
1828*9860Sgdamore@opensolaris.org 		 * and data corruption
1829*9860Sgdamore@opensolaris.org 		 */
1830*9860Sgdamore@opensolaris.org 		if (dnetp->overrun_workaround &&
1831*9860Sgdamore@opensolaris.org 		    marker == dnetp->rx_current_desc) {
1832*9860Sgdamore@opensolaris.org 			int opn;
1833*9860Sgdamore@opensolaris.org 			do {
1834*9860Sgdamore@opensolaris.org 				marker = (marker+1) % dnetp->max_rx_desc;
1835*9860Sgdamore@opensolaris.org 			} while (!(dnetp->rx_desc[marker].desc0.own) &&
1836*9860Sgdamore@opensolaris.org 			    marker != index);
1837*9860Sgdamore@opensolaris.org 
1838*9860Sgdamore@opensolaris.org 			misses = ddi_get32(dnetp->io_handle,
1839*9860Sgdamore@opensolaris.org 			    REG32(dnetp->io_reg, MISSED_FRAME_REG));
1840*9860Sgdamore@opensolaris.org 			dnetp->stat_missed +=
1841*9860Sgdamore@opensolaris.org 			    (misses & MISSED_FRAME_MASK);
1842*9860Sgdamore@opensolaris.org 			if (misses & OVERFLOW_COUNTER_MASK) {
1843*9860Sgdamore@opensolaris.org 				/*
1844*9860Sgdamore@opensolaris.org 				 * Overflow(s) have occurred : stop receiver,
1845*9860Sgdamore@opensolaris.org 				 * and wait until in stopped state
1846*9860Sgdamore@opensolaris.org 				 */
1847*9860Sgdamore@opensolaris.org 				opn = ddi_get32(dnetp->io_handle,
1848*9860Sgdamore@opensolaris.org 				    REG32(dnetp->io_reg, OPN_MODE_REG));
1849*9860Sgdamore@opensolaris.org 				ddi_put32(dnetp->io_handle,
1850*9860Sgdamore@opensolaris.org 				    REG32(dnetp->io_reg, OPN_MODE_REG),
1851*9860Sgdamore@opensolaris.org 				    opn & ~(START_RECEIVE));
1852*9860Sgdamore@opensolaris.org 
1853*9860Sgdamore@opensolaris.org 				do {
1854*9860Sgdamore@opensolaris.org 					drv_usecwait(10);
1855*9860Sgdamore@opensolaris.org 				} while ((ddi_get32(dnetp->io_handle,
1856*9860Sgdamore@opensolaris.org 				    REG32(dnetp->io_reg, STATUS_REG)) &
1857*9860Sgdamore@opensolaris.org 				    RECEIVE_PROCESS_STATE) != 0);
1858*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1859*9860Sgdamore@opensolaris.org 				if (dnetdebug & DNETRECV)
1860*9860Sgdamore@opensolaris.org 					cmn_err(CE_CONT, "^*");
1861*9860Sgdamore@opensolaris.org #endif
1862*9860Sgdamore@opensolaris.org 				/* Discard probably corrupt frames */
1863*9860Sgdamore@opensolaris.org 				while (!(dnetp->rx_desc[index].desc0.own)) {
1864*9860Sgdamore@opensolaris.org 					dnetp->rx_desc[index].desc0.own = 1;
1865*9860Sgdamore@opensolaris.org 					index = (index+1) % dnetp->max_rx_desc;
1866*9860Sgdamore@opensolaris.org 					dnetp->stat_missed++;
1867*9860Sgdamore@opensolaris.org 				}
1868*9860Sgdamore@opensolaris.org 
1869*9860Sgdamore@opensolaris.org 				/* restart the receiver */
1870*9860Sgdamore@opensolaris.org 				opn = ddi_get32(dnetp->io_handle,
1871*9860Sgdamore@opensolaris.org 				    REG32(dnetp->io_reg, OPN_MODE_REG));
1872*9860Sgdamore@opensolaris.org 				ddi_put32(dnetp->io_handle,
1873*9860Sgdamore@opensolaris.org 				    REG32(dnetp->io_reg, OPN_MODE_REG),
1874*9860Sgdamore@opensolaris.org 				    opn | START_RECEIVE);
1875*9860Sgdamore@opensolaris.org 				marker = dnetp->rx_current_desc = index;
1876*9860Sgdamore@opensolaris.org 				continue;
1877*9860Sgdamore@opensolaris.org 			}
1878*9860Sgdamore@opensolaris.org 			/*
1879*9860Sgdamore@opensolaris.org 			 * At this point, we know that all packets before
1880*9860Sgdamore@opensolaris.org 			 * "marker" were received before a dma overrun occurred
1881*9860Sgdamore@opensolaris.org 			 */
1882*9860Sgdamore@opensolaris.org 		}
1883*9860Sgdamore@opensolaris.org 
1884*9860Sgdamore@opensolaris.org 		/*
1885*9860Sgdamore@opensolaris.org 		 * If we get an oversized packet it could span multiple
1886*9860Sgdamore@opensolaris.org 		 * descriptors.  If this happens an error bit should be set.
1887*9860Sgdamore@opensolaris.org 		 */
1888*9860Sgdamore@opensolaris.org 		while (desc[index].desc0.last_desc == 0) {
1889*9860Sgdamore@opensolaris.org 			index = (index + 1) % dnetp->max_rx_desc;
1890*9860Sgdamore@opensolaris.org 			if (desc[index].desc0.own)
1891*9860Sgdamore@opensolaris.org 				return;	/* not done receiving large packet */
1892*9860Sgdamore@opensolaris.org 		}
1893*9860Sgdamore@opensolaris.org 		while (dnetp->rx_current_desc != index) {
1894*9860Sgdamore@opensolaris.org 			desc[dnetp->rx_current_desc].desc0.own = 1;
1895*9860Sgdamore@opensolaris.org 			dnetp->rx_current_desc =
1896*9860Sgdamore@opensolaris.org 			    (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc;
1897*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1898*9860Sgdamore@opensolaris.org 			if (dnetdebug & DNETRECV)
1899*9860Sgdamore@opensolaris.org 				cmn_err(CE_WARN, "dnet: received large packet");
1900*9860Sgdamore@opensolaris.org #endif
1901*9860Sgdamore@opensolaris.org 		}
1902*9860Sgdamore@opensolaris.org 
1903*9860Sgdamore@opensolaris.org 		packet_length = desc[index].desc0.frame_len;
1904*9860Sgdamore@opensolaris.org 
1905*9860Sgdamore@opensolaris.org 		/*
1906*9860Sgdamore@opensolaris.org 		 * Remove CRC from received data. This is an artefact of the
1907*9860Sgdamore@opensolaris.org 		 * 21x4x chip and should not be passed higher up the network
1908*9860Sgdamore@opensolaris.org 		 * stack.
1909*9860Sgdamore@opensolaris.org 		 */
1910*9860Sgdamore@opensolaris.org 		packet_length -= ETHERFCSL;
1911*9860Sgdamore@opensolaris.org 
1912*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
1913*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETRECV) {
1914*9860Sgdamore@opensolaris.org 			if (packet_length > ETHERMAX)
1915*9860Sgdamore@opensolaris.org 				cmn_err(CE_WARN, "dnet: large packet size %d",
1916*9860Sgdamore@opensolaris.org 				    packet_length);
1917*9860Sgdamore@opensolaris.org 		}
1918*9860Sgdamore@opensolaris.org #endif
1919*9860Sgdamore@opensolaris.org 
1920*9860Sgdamore@opensolaris.org 		/* get the virtual address of the packet received */
1921*9860Sgdamore@opensolaris.org 		virtual_address =
1922*9860Sgdamore@opensolaris.org 		    dnetp->rx_buf_vaddr[index];
1923*9860Sgdamore@opensolaris.org 
1924*9860Sgdamore@opensolaris.org 		/*
1925*9860Sgdamore@opensolaris.org 		 * If no packet errors then do:
1926*9860Sgdamore@opensolaris.org 		 * 	1. Allocate a new receive buffer so that we can
1927*9860Sgdamore@opensolaris.org 		 *	   use the current buffer as streams buffer to
1928*9860Sgdamore@opensolaris.org 		 *	   avoid bcopy.
1929*9860Sgdamore@opensolaris.org 		 *	2. If we got a new receive buffer then allocate
1930*9860Sgdamore@opensolaris.org 		 *	   an mblk using desballoc().
1931*9860Sgdamore@opensolaris.org 		 *	3. Otherwise use the mblk from allocb() and do
1932*9860Sgdamore@opensolaris.org 		 *	   the bcopy.
1933*9860Sgdamore@opensolaris.org 		 */
1934*9860Sgdamore@opensolaris.org 		frp = NULL;
1935*9860Sgdamore@opensolaris.org 		rp = NULL;
1936*9860Sgdamore@opensolaris.org 		newbuf = NULL;
1937*9860Sgdamore@opensolaris.org 		mp = NULL;
1938*9860Sgdamore@opensolaris.org 		if (!desc[index].desc0.err_summary) {
1939*9860Sgdamore@opensolaris.org 			ASSERT(packet_length < rx_buf_size);
1940*9860Sgdamore@opensolaris.org 			/*
1941*9860Sgdamore@opensolaris.org 			 * Allocate another receive buffer for this descriptor.
1942*9860Sgdamore@opensolaris.org 			 * If we fail to allocate then we do the normal bcopy.
1943*9860Sgdamore@opensolaris.org 			 */
1944*9860Sgdamore@opensolaris.org 			rp = dnet_rbuf_alloc(dnetp->devinfo, 0);
1945*9860Sgdamore@opensolaris.org 			if (rp != NULL) {
1946*9860Sgdamore@opensolaris.org 				newbuf = rp->rbuf_vaddr;
1947*9860Sgdamore@opensolaris.org 				frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP);
1948*9860Sgdamore@opensolaris.org 				if (frp != NULL) {
1949*9860Sgdamore@opensolaris.org 					frp->free_rtn.free_func =
1950*9860Sgdamore@opensolaris.org 					    dnet_freemsg_buf;
1951*9860Sgdamore@opensolaris.org 					frp->free_rtn.free_arg = (char *)frp;
1952*9860Sgdamore@opensolaris.org 					frp->buf = virtual_address;
1953*9860Sgdamore@opensolaris.org 					mp = desballoc(
1954*9860Sgdamore@opensolaris.org 					    (uchar_t *)virtual_address,
1955*9860Sgdamore@opensolaris.org 					    packet_length, 0, &frp->free_rtn);
1956*9860Sgdamore@opensolaris.org 					if (mp == NULL) {
1957*9860Sgdamore@opensolaris.org 						kmem_free(frp, sizeof (*frp));
1958*9860Sgdamore@opensolaris.org 						dnet_rbuf_free((caddr_t)newbuf);
1959*9860Sgdamore@opensolaris.org 						frp = NULL;
1960*9860Sgdamore@opensolaris.org 						newbuf = NULL;
1961*9860Sgdamore@opensolaris.org 					}
1962*9860Sgdamore@opensolaris.org 				}
1963*9860Sgdamore@opensolaris.org 			}
1964*9860Sgdamore@opensolaris.org 			if (mp == NULL) {
1965*9860Sgdamore@opensolaris.org 				if (newbuf != NULL)
1966*9860Sgdamore@opensolaris.org 					dnet_rbuf_free((caddr_t)newbuf);
1967*9860Sgdamore@opensolaris.org 				mp = allocb(packet_length, 0);
1968*9860Sgdamore@opensolaris.org 			}
1969*9860Sgdamore@opensolaris.org 		}
1970*9860Sgdamore@opensolaris.org 
1971*9860Sgdamore@opensolaris.org 		if (desc[index].desc0.err_summary || (mp == NULL)) {
1972*9860Sgdamore@opensolaris.org 
1973*9860Sgdamore@opensolaris.org 			/* Update gld statistics */
1974*9860Sgdamore@opensolaris.org 			if (desc[index].desc0.err_summary)
1975*9860Sgdamore@opensolaris.org 				update_rx_stats(macinfo, index);
1976*9860Sgdamore@opensolaris.org 			else
1977*9860Sgdamore@opensolaris.org 				dnetp->stat_norcvbuf++;
1978*9860Sgdamore@opensolaris.org 
1979*9860Sgdamore@opensolaris.org 			/*
1980*9860Sgdamore@opensolaris.org 			 * Reset ownership of the descriptor.
1981*9860Sgdamore@opensolaris.org 			 */
1982*9860Sgdamore@opensolaris.org 			desc[index].desc0.own = 1;
1983*9860Sgdamore@opensolaris.org 			dnetp->rx_current_desc =
1984*9860Sgdamore@opensolaris.org 			    (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1985*9860Sgdamore@opensolaris.org 
1986*9860Sgdamore@opensolaris.org 			/* Demand receive polling by the chip */
1987*9860Sgdamore@opensolaris.org 			ddi_put32(dnetp->io_handle,
1988*9860Sgdamore@opensolaris.org 			    REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1989*9860Sgdamore@opensolaris.org 
1990*9860Sgdamore@opensolaris.org 			continue;
1991*9860Sgdamore@opensolaris.org 		}
1992*9860Sgdamore@opensolaris.org 
1993*9860Sgdamore@opensolaris.org 		if (newbuf != NULL) {
1994*9860Sgdamore@opensolaris.org 			uint32_t end_paddr;
1995*9860Sgdamore@opensolaris.org 			/* attach the new buffer to the rx descriptor */
1996*9860Sgdamore@opensolaris.org 			dnetp->rx_buf_vaddr[index] = newbuf;
1997*9860Sgdamore@opensolaris.org 			dnetp->rx_buf_paddr[index] = rp->rbuf_paddr;
1998*9860Sgdamore@opensolaris.org 			desc[index].buffer1 = rp->rbuf_paddr;
1999*9860Sgdamore@opensolaris.org 			desc[index].desc1.buffer_size1 = rx_buf_size;
2000*9860Sgdamore@opensolaris.org 			desc[index].desc1.buffer_size2 = 0;
2001*9860Sgdamore@opensolaris.org 			end_paddr = rp->rbuf_endpaddr;
2002*9860Sgdamore@opensolaris.org 			if ((desc[index].buffer1 & ~dnetp->pgmask) !=
2003*9860Sgdamore@opensolaris.org 			    (end_paddr & ~dnetp->pgmask)) {
2004*9860Sgdamore@opensolaris.org 				/* discontiguous */
2005*9860Sgdamore@opensolaris.org 				desc[index].buffer2 = end_paddr&~dnetp->pgmask;
2006*9860Sgdamore@opensolaris.org 				desc[index].desc1.buffer_size2 =
2007*9860Sgdamore@opensolaris.org 				    (end_paddr & dnetp->pgmask) + 1;
2008*9860Sgdamore@opensolaris.org 				desc[index].desc1.buffer_size1 =
2009*9860Sgdamore@opensolaris.org 				    rx_buf_size-desc[index].desc1.buffer_size2;
2010*9860Sgdamore@opensolaris.org 			}
2011*9860Sgdamore@opensolaris.org 		} else {
2012*9860Sgdamore@opensolaris.org 			/* couldn't allocate another buffer; copy the data */
2013*9860Sgdamore@opensolaris.org 			BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr,
2014*9860Sgdamore@opensolaris.org 			    packet_length);
2015*9860Sgdamore@opensolaris.org 		}
2016*9860Sgdamore@opensolaris.org 
2017*9860Sgdamore@opensolaris.org 		mp->b_wptr += packet_length;
2018*9860Sgdamore@opensolaris.org 
2019*9860Sgdamore@opensolaris.org 		desc[dnetp->rx_current_desc].desc0.own = 1;
2020*9860Sgdamore@opensolaris.org 
2021*9860Sgdamore@opensolaris.org 		/*
2022*9860Sgdamore@opensolaris.org 		 * Increment receive desc index. This is for the scan of
2023*9860Sgdamore@opensolaris.org 		 * next packet
2024*9860Sgdamore@opensolaris.org 		 */
2025*9860Sgdamore@opensolaris.org 		dnetp->rx_current_desc =
2026*9860Sgdamore@opensolaris.org 		    (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
2027*9860Sgdamore@opensolaris.org 
2028*9860Sgdamore@opensolaris.org 		/* Demand polling by chip */
2029*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2030*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
2031*9860Sgdamore@opensolaris.org 
2032*9860Sgdamore@opensolaris.org 		/* send the packet upstream */
2033*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->intrlock);
2034*9860Sgdamore@opensolaris.org 		gld_recv(macinfo, mp);
2035*9860Sgdamore@opensolaris.org 		mutex_enter(&dnetp->intrlock);
2036*9860Sgdamore@opensolaris.org 	}
2037*9860Sgdamore@opensolaris.org }
2038*9860Sgdamore@opensolaris.org /*
2039*9860Sgdamore@opensolaris.org  * Function to update receive statistics
2040*9860Sgdamore@opensolaris.org  */
2041*9860Sgdamore@opensolaris.org static void
2042*9860Sgdamore@opensolaris.org update_rx_stats(gld_mac_info_t *macinfo, int index)
2043*9860Sgdamore@opensolaris.org {
2044*9860Sgdamore@opensolaris.org 	struct	dnetinstance	*dnetp =
2045*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
2046*9860Sgdamore@opensolaris.org 	struct rx_desc_type *descp = &(dnetp->rx_desc[index]);
2047*9860Sgdamore@opensolaris.org 
2048*9860Sgdamore@opensolaris.org 	/*
2049*9860Sgdamore@opensolaris.org 	 * Update gld statistics
2050*9860Sgdamore@opensolaris.org 	 */
2051*9860Sgdamore@opensolaris.org 	dnetp->stat_errrcv++;
2052*9860Sgdamore@opensolaris.org 
2053*9860Sgdamore@opensolaris.org 	if (descp->desc0.overflow)	{
2054*9860Sgdamore@opensolaris.org 		/* FIFO Overrun */
2055*9860Sgdamore@opensolaris.org 		dnetp->stat_overflow++;
2056*9860Sgdamore@opensolaris.org 	}
2057*9860Sgdamore@opensolaris.org 
2058*9860Sgdamore@opensolaris.org 	if (descp->desc0.collision) {
2059*9860Sgdamore@opensolaris.org 		/*EMPTY*/
2060*9860Sgdamore@opensolaris.org 		/* Late Colllision on receive */
2061*9860Sgdamore@opensolaris.org 		/* no appropriate counter */
2062*9860Sgdamore@opensolaris.org 	}
2063*9860Sgdamore@opensolaris.org 
2064*9860Sgdamore@opensolaris.org 	if (descp->desc0.crc) {
2065*9860Sgdamore@opensolaris.org 		/* CRC Error */
2066*9860Sgdamore@opensolaris.org 		dnetp->stat_crc++;
2067*9860Sgdamore@opensolaris.org 	}
2068*9860Sgdamore@opensolaris.org 
2069*9860Sgdamore@opensolaris.org 	if (descp->desc0.runt_frame) {
2070*9860Sgdamore@opensolaris.org 		/* Runt Error */
2071*9860Sgdamore@opensolaris.org 		dnetp->stat_short++;
2072*9860Sgdamore@opensolaris.org 	}
2073*9860Sgdamore@opensolaris.org 
2074*9860Sgdamore@opensolaris.org 	if (descp->desc0.desc_err) {
2075*9860Sgdamore@opensolaris.org 		/*EMPTY*/
2076*9860Sgdamore@opensolaris.org 		/* Not enough receive descriptors */
2077*9860Sgdamore@opensolaris.org 		/* This condition is accounted in dnetintr() */
2078*9860Sgdamore@opensolaris.org 		/* macinfo->gldm_stats.glds_missed++; */
2079*9860Sgdamore@opensolaris.org 	}
2080*9860Sgdamore@opensolaris.org 
2081*9860Sgdamore@opensolaris.org 	if (descp->desc0.frame2long) {
2082*9860Sgdamore@opensolaris.org 		dnetp->stat_frame++;
2083*9860Sgdamore@opensolaris.org 	}
2084*9860Sgdamore@opensolaris.org }
2085*9860Sgdamore@opensolaris.org 
2086*9860Sgdamore@opensolaris.org /*
2087*9860Sgdamore@opensolaris.org  * Function to update transmit statistics
2088*9860Sgdamore@opensolaris.org  */
2089*9860Sgdamore@opensolaris.org static void
2090*9860Sgdamore@opensolaris.org update_tx_stats(gld_mac_info_t *macinfo, int index)
2091*9860Sgdamore@opensolaris.org {
2092*9860Sgdamore@opensolaris.org 	struct	dnetinstance	*dnetp =
2093*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
2094*9860Sgdamore@opensolaris.org 	struct tx_desc_type *descp = &(dnetp->tx_desc[index]);
2095*9860Sgdamore@opensolaris.org 	int	fd;
2096*9860Sgdamore@opensolaris.org 	media_block_t	*block = dnetp->selected_media_block;
2097*9860Sgdamore@opensolaris.org 
2098*9860Sgdamore@opensolaris.org 
2099*9860Sgdamore@opensolaris.org 	/* Update gld statistics */
2100*9860Sgdamore@opensolaris.org 	dnetp->stat_errxmt++;
2101*9860Sgdamore@opensolaris.org 
2102*9860Sgdamore@opensolaris.org 	/* If we're in full-duplex don't count collisions or carrier loss. */
2103*9860Sgdamore@opensolaris.org 	if (dnetp->mii_up) {
2104*9860Sgdamore@opensolaris.org 		fd = dnetp->mii_duplex;
2105*9860Sgdamore@opensolaris.org 	} else {
2106*9860Sgdamore@opensolaris.org 		/* Rely on media code */
2107*9860Sgdamore@opensolaris.org 		fd = block->media_code == MEDIA_TP_FD ||
2108*9860Sgdamore@opensolaris.org 		    block->media_code == MEDIA_SYM_SCR_FD;
2109*9860Sgdamore@opensolaris.org 	}
2110*9860Sgdamore@opensolaris.org 
2111*9860Sgdamore@opensolaris.org 	if (descp->desc0.collision_count && !fd) {
2112*9860Sgdamore@opensolaris.org 		dnetp->stat_collisions += descp->desc0.collision_count;
2113*9860Sgdamore@opensolaris.org 	}
2114*9860Sgdamore@opensolaris.org 
2115*9860Sgdamore@opensolaris.org 	if (descp->desc0.late_collision && !fd) {
2116*9860Sgdamore@opensolaris.org 		dnetp->stat_xmtlatecoll++;
2117*9860Sgdamore@opensolaris.org 	}
2118*9860Sgdamore@opensolaris.org 
2119*9860Sgdamore@opensolaris.org 	if (descp->desc0.excess_collision && !fd) {
2120*9860Sgdamore@opensolaris.org 		dnetp->stat_excoll++;
2121*9860Sgdamore@opensolaris.org 	}
2122*9860Sgdamore@opensolaris.org 
2123*9860Sgdamore@opensolaris.org 	if (descp->desc0.underflow) {
2124*9860Sgdamore@opensolaris.org 		dnetp->stat_underflow++;
2125*9860Sgdamore@opensolaris.org 	}
2126*9860Sgdamore@opensolaris.org 
2127*9860Sgdamore@opensolaris.org #if 0
2128*9860Sgdamore@opensolaris.org 	if (descp->desc0.tx_jabber_to) {
2129*9860Sgdamore@opensolaris.org 		/* no appropriate counter */
2130*9860Sgdamore@opensolaris.org 	}
2131*9860Sgdamore@opensolaris.org #endif
2132*9860Sgdamore@opensolaris.org 
2133*9860Sgdamore@opensolaris.org 	if (descp->desc0.carrier_loss && !fd) {
2134*9860Sgdamore@opensolaris.org 		dnetp->stat_nocarrier++;
2135*9860Sgdamore@opensolaris.org 	}
2136*9860Sgdamore@opensolaris.org 
2137*9860Sgdamore@opensolaris.org 	if (descp->desc0.no_carrier && !fd) {
2138*9860Sgdamore@opensolaris.org 		dnetp->stat_nocarrier++;
2139*9860Sgdamore@opensolaris.org 	}
2140*9860Sgdamore@opensolaris.org }
2141*9860Sgdamore@opensolaris.org 
2142*9860Sgdamore@opensolaris.org /*
2143*9860Sgdamore@opensolaris.org  *	========== Media Selection Setup Routines ==========
2144*9860Sgdamore@opensolaris.org  */
2145*9860Sgdamore@opensolaris.org 
2146*9860Sgdamore@opensolaris.org 
2147*9860Sgdamore@opensolaris.org static void
2148*9860Sgdamore@opensolaris.org write_gpr(struct dnetinstance *dnetp, uint32_t val)
2149*9860Sgdamore@opensolaris.org {
2150*9860Sgdamore@opensolaris.org #ifdef DEBUG
2151*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETREGCFG)
2152*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "GPR: %x", val);
2153*9860Sgdamore@opensolaris.org #endif
2154*9860Sgdamore@opensolaris.org 	switch (dnetp->board_type) {
2155*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21143:
2156*9860Sgdamore@opensolaris.org 		/* Set the correct bit for a control write */
2157*9860Sgdamore@opensolaris.org 		if (val & GPR_CONTROL_WRITE)
2158*9860Sgdamore@opensolaris.org 			val |= CWE_21143, val &= ~GPR_CONTROL_WRITE;
2159*9860Sgdamore@opensolaris.org 		/* Write to upper half of CSR15 */
2160*9860Sgdamore@opensolaris.org 		dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16);
2161*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2162*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia);
2163*9860Sgdamore@opensolaris.org 		break;
2164*9860Sgdamore@opensolaris.org 	default:
2165*9860Sgdamore@opensolaris.org 		/* Set the correct bit for a control write */
2166*9860Sgdamore@opensolaris.org 		if (val & GPR_CONTROL_WRITE)
2167*9860Sgdamore@opensolaris.org 			val |= CWE_21140, val &= ~GPR_CONTROL_WRITE;
2168*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val);
2169*9860Sgdamore@opensolaris.org 		break;
2170*9860Sgdamore@opensolaris.org 	}
2171*9860Sgdamore@opensolaris.org }
2172*9860Sgdamore@opensolaris.org 
2173*9860Sgdamore@opensolaris.org static uint32_t
2174*9860Sgdamore@opensolaris.org read_gpr(struct dnetinstance *dnetp)
2175*9860Sgdamore@opensolaris.org {
2176*9860Sgdamore@opensolaris.org 	switch (dnetp->board_type) {
2177*9860Sgdamore@opensolaris.org 	case DEVICE_ID_21143:
2178*9860Sgdamore@opensolaris.org 		/* Read upper half of CSR15 */
2179*9860Sgdamore@opensolaris.org 		return (ddi_get32(dnetp->io_handle,
2180*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16);
2181*9860Sgdamore@opensolaris.org 	default:
2182*9860Sgdamore@opensolaris.org 		return (ddi_get32(dnetp->io_handle,
2183*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, GP_REG)));
2184*9860Sgdamore@opensolaris.org 	}
2185*9860Sgdamore@opensolaris.org }
2186*9860Sgdamore@opensolaris.org 
2187*9860Sgdamore@opensolaris.org static void
2188*9860Sgdamore@opensolaris.org set_gpr(gld_mac_info_t *macinfo)
2189*9860Sgdamore@opensolaris.org {
2190*9860Sgdamore@opensolaris.org 	uint32_t *sequence;
2191*9860Sgdamore@opensolaris.org 	int len;
2192*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp = (struct dnetinstance *)
2193*9860Sgdamore@opensolaris.org 	    macinfo->gldm_private;
2194*9860Sgdamore@opensolaris.org 	LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
2195*9860Sgdamore@opensolaris.org 	media_block_t *block = dnetp->selected_media_block;
2196*9860Sgdamore@opensolaris.org 	int i;
2197*9860Sgdamore@opensolaris.org 
2198*9860Sgdamore@opensolaris.org 	if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo,
2199*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence,
2200*9860Sgdamore@opensolaris.org 	    &len) == DDI_PROP_SUCCESS) {
2201*9860Sgdamore@opensolaris.org 		for (i = 0; i < len / sizeof (uint32_t); i++)
2202*9860Sgdamore@opensolaris.org 			write_gpr(dnetp, sequence[i]);
2203*9860Sgdamore@opensolaris.org 		kmem_free(sequence, len);
2204*9860Sgdamore@opensolaris.org 	} else {
2205*9860Sgdamore@opensolaris.org 		/*
2206*9860Sgdamore@opensolaris.org 		 * Write the reset sequence if this is the first time this
2207*9860Sgdamore@opensolaris.org 		 * block has been selected.
2208*9860Sgdamore@opensolaris.org 		 */
2209*9860Sgdamore@opensolaris.org 		if (block->rstseqlen) {
2210*9860Sgdamore@opensolaris.org 			for (i = 0; i < block->rstseqlen; i++)
2211*9860Sgdamore@opensolaris.org 				write_gpr(dnetp, block->rstseq[i]);
2212*9860Sgdamore@opensolaris.org 			/*
2213*9860Sgdamore@opensolaris.org 			 * XXX Legacy blocks do not have reset sequences, so the
2214*9860Sgdamore@opensolaris.org 			 * static blocks will never be modified by this
2215*9860Sgdamore@opensolaris.org 			 */
2216*9860Sgdamore@opensolaris.org 			block->rstseqlen = 0;
2217*9860Sgdamore@opensolaris.org 		}
2218*9860Sgdamore@opensolaris.org 		if (leaf->gpr)
2219*9860Sgdamore@opensolaris.org 			write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE);
2220*9860Sgdamore@opensolaris.org 
2221*9860Sgdamore@opensolaris.org 		/* write GPR sequence each time */
2222*9860Sgdamore@opensolaris.org 		for (i = 0; i < block->gprseqlen; i++)
2223*9860Sgdamore@opensolaris.org 			write_gpr(dnetp, block->gprseq[i]);
2224*9860Sgdamore@opensolaris.org 	}
2225*9860Sgdamore@opensolaris.org 
2226*9860Sgdamore@opensolaris.org 	/* This has possibly caused a PHY to reset.  Let MII know */
2227*9860Sgdamore@opensolaris.org 	if (dnetp->phyaddr != -1)
2228*9860Sgdamore@opensolaris.org 		/* XXX function return value ignored */
2229*9860Sgdamore@opensolaris.org 		(void) mii_sync(dnetp->mii, dnetp->phyaddr);
2230*9860Sgdamore@opensolaris.org 	drv_usecwait(5);
2231*9860Sgdamore@opensolaris.org }
2232*9860Sgdamore@opensolaris.org 
2233*9860Sgdamore@opensolaris.org /* set_opr() - must be called with intrlock held */
2234*9860Sgdamore@opensolaris.org 
2235*9860Sgdamore@opensolaris.org static void
2236*9860Sgdamore@opensolaris.org set_opr(gld_mac_info_t *macinfo)
2237*9860Sgdamore@opensolaris.org {
2238*9860Sgdamore@opensolaris.org 	uint32_t fd, mb1, sf;
2239*9860Sgdamore@opensolaris.org 
2240*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =
2241*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
2242*9860Sgdamore@opensolaris.org 	int 		opnmode_len;
2243*9860Sgdamore@opensolaris.org 	uint32_t val;
2244*9860Sgdamore@opensolaris.org 	media_block_t *block = dnetp->selected_media_block;
2245*9860Sgdamore@opensolaris.org 
2246*9860Sgdamore@opensolaris.org 	ASSERT(block);
2247*9860Sgdamore@opensolaris.org 
2248*9860Sgdamore@opensolaris.org 	/* Check for custom "opnmode_reg" property */
2249*9860Sgdamore@opensolaris.org 	opnmode_len = sizeof (val);
2250*9860Sgdamore@opensolaris.org 	if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo,
2251*9860Sgdamore@opensolaris.org 	    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg",
2252*9860Sgdamore@opensolaris.org 	    (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS)
2253*9860Sgdamore@opensolaris.org 		opnmode_len = 0;
2254*9860Sgdamore@opensolaris.org 
2255*9860Sgdamore@opensolaris.org 	/* Some bits exist only on 21140 and greater */
2256*9860Sgdamore@opensolaris.org 	if (dnetp->board_type != DEVICE_ID_21040 &&
2257*9860Sgdamore@opensolaris.org 	    dnetp->board_type != DEVICE_ID_21041) {
2258*9860Sgdamore@opensolaris.org 		mb1 = OPN_REG_MB1;
2259*9860Sgdamore@opensolaris.org 		sf = STORE_AND_FORWARD;
2260*9860Sgdamore@opensolaris.org 	} else {
2261*9860Sgdamore@opensolaris.org 		mb1 = sf = 0;
2262*9860Sgdamore@opensolaris.org 		mb1 = OPN_REG_MB1; /* Needed for 21040? */
2263*9860Sgdamore@opensolaris.org 	}
2264*9860Sgdamore@opensolaris.org 
2265*9860Sgdamore@opensolaris.org 	if (opnmode_len) {
2266*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2267*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, OPN_MODE_REG), val);
2268*9860Sgdamore@opensolaris.org 		dnet_reset_board(macinfo);
2269*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2270*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, OPN_MODE_REG), val);
2271*9860Sgdamore@opensolaris.org 		return;
2272*9860Sgdamore@opensolaris.org 	}
2273*9860Sgdamore@opensolaris.org 
2274*9860Sgdamore@opensolaris.org 	/*
2275*9860Sgdamore@opensolaris.org 	 * Set each bit in CSR6 that we want
2276*9860Sgdamore@opensolaris.org 	 */
2277*9860Sgdamore@opensolaris.org 
2278*9860Sgdamore@opensolaris.org 	/* Always want these bits set */
2279*9860Sgdamore@opensolaris.org 	val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf;
2280*9860Sgdamore@opensolaris.org 
2281*9860Sgdamore@opensolaris.org 	/* Promiscuous mode */
2282*9860Sgdamore@opensolaris.org 	val |= dnetp->promisc ? PROM_MODE : 0;
2283*9860Sgdamore@opensolaris.org 
2284*9860Sgdamore@opensolaris.org 	/* Scrambler for SYM style media */
2285*9860Sgdamore@opensolaris.org 	val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ?
2286*9860Sgdamore@opensolaris.org 	    SCRAMBLER_MODE : 0;
2287*9860Sgdamore@opensolaris.org 
2288*9860Sgdamore@opensolaris.org 	/* Full duplex */
2289*9860Sgdamore@opensolaris.org 	if (dnetp->mii_up) {
2290*9860Sgdamore@opensolaris.org 		fd = dnetp->mii_duplex;
2291*9860Sgdamore@opensolaris.org 	} else {
2292*9860Sgdamore@opensolaris.org 		/* Rely on media code */
2293*9860Sgdamore@opensolaris.org 		fd = block->media_code == MEDIA_TP_FD ||
2294*9860Sgdamore@opensolaris.org 		    block->media_code == MEDIA_SYM_SCR_FD;
2295*9860Sgdamore@opensolaris.org 	}
2296*9860Sgdamore@opensolaris.org 
2297*9860Sgdamore@opensolaris.org 	/* Port select (and therefore, heartbeat disable) */
2298*9860Sgdamore@opensolaris.org 	val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0;
2299*9860Sgdamore@opensolaris.org 
2300*9860Sgdamore@opensolaris.org 	/* PCS function */
2301*9860Sgdamore@opensolaris.org 	val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0;
2302*9860Sgdamore@opensolaris.org 	val |= fd ? FULL_DUPLEX : 0;
2303*9860Sgdamore@opensolaris.org 
2304*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
2305*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETREGCFG)
2306*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "OPN: %x", val);
2307*9860Sgdamore@opensolaris.org #endif
2308*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
2309*9860Sgdamore@opensolaris.org 	dnet_reset_board(macinfo);
2310*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
2311*9860Sgdamore@opensolaris.org }
2312*9860Sgdamore@opensolaris.org 
2313*9860Sgdamore@opensolaris.org static void
2314*9860Sgdamore@opensolaris.org set_sia(gld_mac_info_t *macinfo)
2315*9860Sgdamore@opensolaris.org {
2316*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp = (struct dnetinstance *)
2317*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
2318*9860Sgdamore@opensolaris.org 	media_block_t *block = dnetp->selected_media_block;
2319*9860Sgdamore@opensolaris.org 
2320*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
2321*9860Sgdamore@opensolaris.org 	if (block->type == 2) {
2322*9860Sgdamore@opensolaris.org 		int sia_delay;
2323*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
2324*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETREGCFG)
2325*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE,
2326*9860Sgdamore@opensolaris.org 			    "SIA: CSR13: %x, CSR14: %x, CSR15: %x",
2327*9860Sgdamore@opensolaris.org 			    block->un.sia.csr13,
2328*9860Sgdamore@opensolaris.org 			    block->un.sia.csr14,
2329*9860Sgdamore@opensolaris.org 			    block->un.sia.csr15);
2330*9860Sgdamore@opensolaris.org #endif
2331*9860Sgdamore@opensolaris.org 		sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
2332*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, "sia-delay", 10000);
2333*9860Sgdamore@opensolaris.org 
2334*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2335*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2336*9860Sgdamore@opensolaris.org 
2337*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG),
2338*9860Sgdamore@opensolaris.org 		    block->un.sia.csr14);
2339*9860Sgdamore@opensolaris.org 
2340*9860Sgdamore@opensolaris.org 		/*
2341*9860Sgdamore@opensolaris.org 		 * For '143, we need to write through a copy of the register
2342*9860Sgdamore@opensolaris.org 		 * to keep the GP half intact
2343*9860Sgdamore@opensolaris.org 		 */
2344*9860Sgdamore@opensolaris.org 		dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15;
2345*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2346*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_GENERAL_REG),
2347*9860Sgdamore@opensolaris.org 		    dnetp->gprsia);
2348*9860Sgdamore@opensolaris.org 
2349*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2350*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_CONNECT_REG),
2351*9860Sgdamore@opensolaris.org 		    block->un.sia.csr13);
2352*9860Sgdamore@opensolaris.org 
2353*9860Sgdamore@opensolaris.org 		drv_usecwait(sia_delay);
2354*9860Sgdamore@opensolaris.org 
2355*9860Sgdamore@opensolaris.org 	} else if (dnetp->board_type != DEVICE_ID_21140) {
2356*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2357*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2358*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
2359*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, SIA_TXRX_REG), 0);
2360*9860Sgdamore@opensolaris.org 	}
2361*9860Sgdamore@opensolaris.org }
2362*9860Sgdamore@opensolaris.org 
2363*9860Sgdamore@opensolaris.org /*
2364*9860Sgdamore@opensolaris.org  *	========== Buffer Management Routines ==========
2365*9860Sgdamore@opensolaris.org  */
2366*9860Sgdamore@opensolaris.org 
2367*9860Sgdamore@opensolaris.org /*
2368*9860Sgdamore@opensolaris.org  * This function (re)allocates the receive and transmit buffers and
2369*9860Sgdamore@opensolaris.org  * descriptors.  It can be called more than once per instance, though
2370*9860Sgdamore@opensolaris.org  * currently it is only called from attach.  It should only be called
2371*9860Sgdamore@opensolaris.org  * while the device is reset.
2372*9860Sgdamore@opensolaris.org  */
2373*9860Sgdamore@opensolaris.org static int
2374*9860Sgdamore@opensolaris.org dnet_alloc_bufs(gld_mac_info_t *macinfo)
2375*9860Sgdamore@opensolaris.org {
2376*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
2377*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
2378*9860Sgdamore@opensolaris.org 	int i;
2379*9860Sgdamore@opensolaris.org 	size_t len;
2380*9860Sgdamore@opensolaris.org 	int page_size;
2381*9860Sgdamore@opensolaris.org 	int realloc = 0;
2382*9860Sgdamore@opensolaris.org 	int nrecv_desc_old = 0;
2383*9860Sgdamore@opensolaris.org 	ddi_dma_cookie_t cookie;
2384*9860Sgdamore@opensolaris.org 	uint_t ncookies;
2385*9860Sgdamore@opensolaris.org 
2386*9860Sgdamore@opensolaris.org 	/*
2387*9860Sgdamore@opensolaris.org 	 * check if we are trying to reallocate with different xmit/recv
2388*9860Sgdamore@opensolaris.org 	 * descriptor ring sizes.
2389*9860Sgdamore@opensolaris.org 	 */
2390*9860Sgdamore@opensolaris.org 	if ((dnetp->tx_desc != NULL) &&
2391*9860Sgdamore@opensolaris.org 	    (dnetp->nxmit_desc != dnetp->max_tx_desc))
2392*9860Sgdamore@opensolaris.org 		realloc = 1;
2393*9860Sgdamore@opensolaris.org 
2394*9860Sgdamore@opensolaris.org 	if ((dnetp->rx_desc != NULL) &&
2395*9860Sgdamore@opensolaris.org 	    (dnetp->nrecv_desc != dnetp->max_rx_desc))
2396*9860Sgdamore@opensolaris.org 		realloc = 1;
2397*9860Sgdamore@opensolaris.org 
2398*9860Sgdamore@opensolaris.org 	/* free up the old buffers if we are reallocating them */
2399*9860Sgdamore@opensolaris.org 	if (realloc) {
2400*9860Sgdamore@opensolaris.org 		nrecv_desc_old = dnetp->nrecv_desc;
2401*9860Sgdamore@opensolaris.org 		dnet_free_bufs(macinfo); /* free the old buffers */
2402*9860Sgdamore@opensolaris.org 	}
2403*9860Sgdamore@opensolaris.org 
2404*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle == NULL)
2405*9860Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2406*9860Sgdamore@opensolaris.org 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS)
2407*9860Sgdamore@opensolaris.org 			return (FAILURE);
2408*9860Sgdamore@opensolaris.org 
2409*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle_tx == NULL)
2410*9860Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx,
2411*9860Sgdamore@opensolaris.org 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS)
2412*9860Sgdamore@opensolaris.org 			return (FAILURE);
2413*9860Sgdamore@opensolaris.org 
2414*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle_txdesc == NULL)
2415*9860Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2416*9860Sgdamore@opensolaris.org 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS)
2417*9860Sgdamore@opensolaris.org 			return (FAILURE);
2418*9860Sgdamore@opensolaris.org 
2419*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle_setbuf == NULL)
2420*9860Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2421*9860Sgdamore@opensolaris.org 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS)
2422*9860Sgdamore@opensolaris.org 			return (FAILURE);
2423*9860Sgdamore@opensolaris.org 
2424*9860Sgdamore@opensolaris.org 	page_size = ddi_ptob(dnetp->devinfo, 1);
2425*9860Sgdamore@opensolaris.org 
2426*9860Sgdamore@opensolaris.org 	dnetp->pgmask = page_size - 1;
2427*9860Sgdamore@opensolaris.org 
2428*9860Sgdamore@opensolaris.org 	/* allocate setup buffer if necessary */
2429*9860Sgdamore@opensolaris.org 	if (dnetp->setup_buf_vaddr == NULL) {
2430*9860Sgdamore@opensolaris.org 		if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf,
2431*9860Sgdamore@opensolaris.org 		    SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING,
2432*9860Sgdamore@opensolaris.org 		    DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr,
2433*9860Sgdamore@opensolaris.org 		    &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS)
2434*9860Sgdamore@opensolaris.org 			return (FAILURE);
2435*9860Sgdamore@opensolaris.org 
2436*9860Sgdamore@opensolaris.org 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf,
2437*9860Sgdamore@opensolaris.org 		    NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE,
2438*9860Sgdamore@opensolaris.org 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2439*9860Sgdamore@opensolaris.org 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2440*9860Sgdamore@opensolaris.org 			return (FAILURE);
2441*9860Sgdamore@opensolaris.org 
2442*9860Sgdamore@opensolaris.org 		dnetp->setup_buf_paddr = cookie.dmac_address;
2443*9860Sgdamore@opensolaris.org 		bzero(dnetp->setup_buf_vaddr, len);
2444*9860Sgdamore@opensolaris.org 	}
2445*9860Sgdamore@opensolaris.org 
2446*9860Sgdamore@opensolaris.org 	/* allocate xmit descriptor array of size dnetp->max_tx_desc */
2447*9860Sgdamore@opensolaris.org 	if (dnetp->tx_desc == NULL) {
2448*9860Sgdamore@opensolaris.org 		if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc,
2449*9860Sgdamore@opensolaris.org 		    sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2450*9860Sgdamore@opensolaris.org 		    &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2451*9860Sgdamore@opensolaris.org 		    (caddr_t *)&dnetp->tx_desc, &len,
2452*9860Sgdamore@opensolaris.org 		    &dnetp->tx_desc_acchdl) != DDI_SUCCESS)
2453*9860Sgdamore@opensolaris.org 			return (FAILURE);
2454*9860Sgdamore@opensolaris.org 
2455*9860Sgdamore@opensolaris.org 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc,
2456*9860Sgdamore@opensolaris.org 		    NULL, (caddr_t)dnetp->tx_desc,
2457*9860Sgdamore@opensolaris.org 		    sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2458*9860Sgdamore@opensolaris.org 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2459*9860Sgdamore@opensolaris.org 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2460*9860Sgdamore@opensolaris.org 			return (FAILURE);
2461*9860Sgdamore@opensolaris.org 		dnetp->tx_desc_paddr = cookie.dmac_address;
2462*9860Sgdamore@opensolaris.org 		bzero(dnetp->tx_desc, len);
2463*9860Sgdamore@opensolaris.org 		dnetp->nxmit_desc = dnetp->max_tx_desc;
2464*9860Sgdamore@opensolaris.org 
2465*9860Sgdamore@opensolaris.org 		dnetp->tx_msgbufp =
2466*9860Sgdamore@opensolaris.org 		    kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **),
2467*9860Sgdamore@opensolaris.org 		    KM_SLEEP);
2468*9860Sgdamore@opensolaris.org 	}
2469*9860Sgdamore@opensolaris.org 
2470*9860Sgdamore@opensolaris.org 	/* allocate receive descriptor array of size dnetp->max_rx_desc */
2471*9860Sgdamore@opensolaris.org 	if (dnetp->rx_desc == NULL) {
2472*9860Sgdamore@opensolaris.org 		int ndesc;
2473*9860Sgdamore@opensolaris.org 
2474*9860Sgdamore@opensolaris.org 		if (ddi_dma_mem_alloc(dnetp->dma_handle,
2475*9860Sgdamore@opensolaris.org 		    sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2476*9860Sgdamore@opensolaris.org 		    &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2477*9860Sgdamore@opensolaris.org 		    (caddr_t *)&dnetp->rx_desc, &len,
2478*9860Sgdamore@opensolaris.org 		    &dnetp->rx_desc_acchdl) != DDI_SUCCESS)
2479*9860Sgdamore@opensolaris.org 			return (FAILURE);
2480*9860Sgdamore@opensolaris.org 
2481*9860Sgdamore@opensolaris.org 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle,
2482*9860Sgdamore@opensolaris.org 		    NULL, (caddr_t)dnetp->rx_desc,
2483*9860Sgdamore@opensolaris.org 		    sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2484*9860Sgdamore@opensolaris.org 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2485*9860Sgdamore@opensolaris.org 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2486*9860Sgdamore@opensolaris.org 			return (FAILURE);
2487*9860Sgdamore@opensolaris.org 
2488*9860Sgdamore@opensolaris.org 		dnetp->rx_desc_paddr = cookie.dmac_address;
2489*9860Sgdamore@opensolaris.org 		bzero(dnetp->rx_desc, len);
2490*9860Sgdamore@opensolaris.org 		dnetp->nrecv_desc = dnetp->max_rx_desc;
2491*9860Sgdamore@opensolaris.org 
2492*9860Sgdamore@opensolaris.org 		dnetp->rx_buf_vaddr =
2493*9860Sgdamore@opensolaris.org 		    kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t),
2494*9860Sgdamore@opensolaris.org 		    KM_SLEEP);
2495*9860Sgdamore@opensolaris.org 		dnetp->rx_buf_paddr =
2496*9860Sgdamore@opensolaris.org 		    kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t),
2497*9860Sgdamore@opensolaris.org 		    KM_SLEEP);
2498*9860Sgdamore@opensolaris.org 		/*
2499*9860Sgdamore@opensolaris.org 		 * Allocate or add to the pool of receive buffers.  The pool
2500*9860Sgdamore@opensolaris.org 		 * is shared among all instances of dnet.
2501*9860Sgdamore@opensolaris.org 		 *
2502*9860Sgdamore@opensolaris.org 		 * XXX NEEDSWORK
2503*9860Sgdamore@opensolaris.org 		 *
2504*9860Sgdamore@opensolaris.org 		 * We arbitrarily allocate twice as many receive buffers as
2505*9860Sgdamore@opensolaris.org 		 * receive descriptors because we use the buffers for streams
2506*9860Sgdamore@opensolaris.org 		 * messages to pass the packets up the stream.  We should
2507*9860Sgdamore@opensolaris.org 		 * instead have initialized constants reflecting
2508*9860Sgdamore@opensolaris.org 		 * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2509*9860Sgdamore@opensolaris.org 		 * probably have a total maximum for the free pool, so that we
2510*9860Sgdamore@opensolaris.org 		 * don't get out of hand when someone puts in an 8-port board.
2511*9860Sgdamore@opensolaris.org 		 * The maximum for the entire pool should be the total number
2512*9860Sgdamore@opensolaris.org 		 * of descriptors for all attached instances together, plus the
2513*9860Sgdamore@opensolaris.org 		 * total maximum for the free pool.  This maximum would only be
2514*9860Sgdamore@opensolaris.org 		 * reached after some number of instances allocate buffers:
2515*9860Sgdamore@opensolaris.org 		 * each instance would add (max_rx_buf-max_rx_desc) to the free
2516*9860Sgdamore@opensolaris.org 		 * pool.
2517*9860Sgdamore@opensolaris.org 		 */
2518*9860Sgdamore@opensolaris.org 		ndesc = dnetp->max_rx_desc - nrecv_desc_old;
2519*9860Sgdamore@opensolaris.org 		if ((ndesc > 0) &&
2520*9860Sgdamore@opensolaris.org 		    (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0))
2521*9860Sgdamore@opensolaris.org 			return (FAILURE);
2522*9860Sgdamore@opensolaris.org 
2523*9860Sgdamore@opensolaris.org 		for (i = 0; i < dnetp->max_rx_desc; i++) {
2524*9860Sgdamore@opensolaris.org 			struct rbuf_list *rp;
2525*9860Sgdamore@opensolaris.org 
2526*9860Sgdamore@opensolaris.org 			rp = dnet_rbuf_alloc(dnetp->devinfo, 1);
2527*9860Sgdamore@opensolaris.org 			if (rp == NULL)
2528*9860Sgdamore@opensolaris.org 				return (FAILURE);
2529*9860Sgdamore@opensolaris.org 			dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr;
2530*9860Sgdamore@opensolaris.org 			dnetp->rx_buf_paddr[i] = rp->rbuf_paddr;
2531*9860Sgdamore@opensolaris.org 		}
2532*9860Sgdamore@opensolaris.org 	}
2533*9860Sgdamore@opensolaris.org 
2534*9860Sgdamore@opensolaris.org 	return (SUCCESS);
2535*9860Sgdamore@opensolaris.org }
2536*9860Sgdamore@opensolaris.org /*
2537*9860Sgdamore@opensolaris.org  * free descriptors/buffers allocated for this device instance.  This routine
2538*9860Sgdamore@opensolaris.org  * should only be called while the device is reset.
2539*9860Sgdamore@opensolaris.org  */
2540*9860Sgdamore@opensolaris.org static void
2541*9860Sgdamore@opensolaris.org dnet_free_bufs(gld_mac_info_t *macinfo)
2542*9860Sgdamore@opensolaris.org {
2543*9860Sgdamore@opensolaris.org 	int i;
2544*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
2545*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
2546*9860Sgdamore@opensolaris.org 	/* free up any xmit descriptors/buffers */
2547*9860Sgdamore@opensolaris.org 	if (dnetp->tx_desc != NULL) {
2548*9860Sgdamore@opensolaris.org 		ddi_dma_mem_free(&dnetp->tx_desc_acchdl);
2549*9860Sgdamore@opensolaris.org 		dnetp->tx_desc = NULL;
2550*9860Sgdamore@opensolaris.org 		/* we use streams buffers for DMA in xmit process */
2551*9860Sgdamore@opensolaris.org 		if (dnetp->tx_msgbufp != NULL) {
2552*9860Sgdamore@opensolaris.org 			/* free up any streams message buffers unclaimed */
2553*9860Sgdamore@opensolaris.org 			for (i = 0; i < dnetp->nxmit_desc; i++) {
2554*9860Sgdamore@opensolaris.org 				if (dnetp->tx_msgbufp[i] != NULL) {
2555*9860Sgdamore@opensolaris.org 					freemsg(dnetp->tx_msgbufp[i]);
2556*9860Sgdamore@opensolaris.org 				}
2557*9860Sgdamore@opensolaris.org 			}
2558*9860Sgdamore@opensolaris.org 			kmem_free(dnetp->tx_msgbufp,
2559*9860Sgdamore@opensolaris.org 			    dnetp->nxmit_desc * sizeof (mblk_t **));
2560*9860Sgdamore@opensolaris.org 			dnetp->tx_msgbufp = NULL;
2561*9860Sgdamore@opensolaris.org 		}
2562*9860Sgdamore@opensolaris.org 		dnetp->nxmit_desc = 0;
2563*9860Sgdamore@opensolaris.org 	}
2564*9860Sgdamore@opensolaris.org 
2565*9860Sgdamore@opensolaris.org 	/* free up any receive descriptors/buffers */
2566*9860Sgdamore@opensolaris.org 	if (dnetp->rx_desc != NULL) {
2567*9860Sgdamore@opensolaris.org 		ddi_dma_mem_free(&dnetp->rx_desc_acchdl);
2568*9860Sgdamore@opensolaris.org 		dnetp->rx_desc = NULL;
2569*9860Sgdamore@opensolaris.org 		if (dnetp->rx_buf_vaddr != NULL) {
2570*9860Sgdamore@opensolaris.org 			/* free up the attached rbufs if any */
2571*9860Sgdamore@opensolaris.org 			for (i = 0; i < dnetp->nrecv_desc; i++) {
2572*9860Sgdamore@opensolaris.org 				if (dnetp->rx_buf_vaddr[i])
2573*9860Sgdamore@opensolaris.org 					dnet_rbuf_free(
2574*9860Sgdamore@opensolaris.org 					    (caddr_t)dnetp->rx_buf_vaddr[i]);
2575*9860Sgdamore@opensolaris.org 			}
2576*9860Sgdamore@opensolaris.org 			kmem_free(dnetp->rx_buf_vaddr,
2577*9860Sgdamore@opensolaris.org 			    dnetp->nrecv_desc * sizeof (caddr_t));
2578*9860Sgdamore@opensolaris.org 			kmem_free(dnetp->rx_buf_paddr,
2579*9860Sgdamore@opensolaris.org 			    dnetp->nrecv_desc * sizeof (uint32_t));
2580*9860Sgdamore@opensolaris.org 			dnetp->rx_buf_vaddr = NULL;
2581*9860Sgdamore@opensolaris.org 			dnetp->rx_buf_paddr = NULL;
2582*9860Sgdamore@opensolaris.org 		}
2583*9860Sgdamore@opensolaris.org 		dnetp->nrecv_desc = 0;
2584*9860Sgdamore@opensolaris.org 	}
2585*9860Sgdamore@opensolaris.org 
2586*9860Sgdamore@opensolaris.org 	if (dnetp->setup_buf_vaddr != NULL) {
2587*9860Sgdamore@opensolaris.org 		ddi_dma_mem_free(&dnetp->setup_buf_acchdl);
2588*9860Sgdamore@opensolaris.org 		dnetp->setup_buf_vaddr = NULL;
2589*9860Sgdamore@opensolaris.org 	}
2590*9860Sgdamore@opensolaris.org 
2591*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle != NULL) {
2592*9860Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(dnetp->dma_handle);
2593*9860Sgdamore@opensolaris.org 		ddi_dma_free_handle(&dnetp->dma_handle);
2594*9860Sgdamore@opensolaris.org 		dnetp->dma_handle = NULL;
2595*9860Sgdamore@opensolaris.org 	}
2596*9860Sgdamore@opensolaris.org 
2597*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle_tx != NULL) {
2598*9860Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
2599*9860Sgdamore@opensolaris.org 		ddi_dma_free_handle(&dnetp->dma_handle_tx);
2600*9860Sgdamore@opensolaris.org 		dnetp->dma_handle_tx = NULL;
2601*9860Sgdamore@opensolaris.org 	}
2602*9860Sgdamore@opensolaris.org 
2603*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle_txdesc != NULL) {
2604*9860Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc);
2605*9860Sgdamore@opensolaris.org 		ddi_dma_free_handle(&dnetp->dma_handle_txdesc);
2606*9860Sgdamore@opensolaris.org 		dnetp->dma_handle_txdesc = NULL;
2607*9860Sgdamore@opensolaris.org 	}
2608*9860Sgdamore@opensolaris.org 
2609*9860Sgdamore@opensolaris.org 	if (dnetp->dma_handle_setbuf != NULL) {
2610*9860Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf);
2611*9860Sgdamore@opensolaris.org 		ddi_dma_free_handle(&dnetp->dma_handle_setbuf);
2612*9860Sgdamore@opensolaris.org 		dnetp->dma_handle_setbuf = NULL;
2613*9860Sgdamore@opensolaris.org 	}
2614*9860Sgdamore@opensolaris.org 
2615*9860Sgdamore@opensolaris.org }
2616*9860Sgdamore@opensolaris.org 
2617*9860Sgdamore@opensolaris.org /*
2618*9860Sgdamore@opensolaris.org  * Initialize transmit and receive descriptors.
2619*9860Sgdamore@opensolaris.org  */
2620*9860Sgdamore@opensolaris.org static void
2621*9860Sgdamore@opensolaris.org dnet_init_txrx_bufs(gld_mac_info_t *macinfo)
2622*9860Sgdamore@opensolaris.org {
2623*9860Sgdamore@opensolaris.org 	int		i;
2624*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
2625*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
2626*9860Sgdamore@opensolaris.org 
2627*9860Sgdamore@opensolaris.org 	/*
2628*9860Sgdamore@opensolaris.org 	 * Initilize all the Tx descriptors
2629*9860Sgdamore@opensolaris.org 	 */
2630*9860Sgdamore@opensolaris.org 	for (i = 0; i < dnetp->nxmit_desc; i++) {
2631*9860Sgdamore@opensolaris.org 		/*
2632*9860Sgdamore@opensolaris.org 		 * We may be resetting the device due to errors,
2633*9860Sgdamore@opensolaris.org 		 * so free up any streams message buffer unclaimed.
2634*9860Sgdamore@opensolaris.org 		 */
2635*9860Sgdamore@opensolaris.org 		if (dnetp->tx_msgbufp[i] != NULL) {
2636*9860Sgdamore@opensolaris.org 			freemsg(dnetp->tx_msgbufp[i]);
2637*9860Sgdamore@opensolaris.org 			dnetp->tx_msgbufp[i] = NULL;
2638*9860Sgdamore@opensolaris.org 		}
2639*9860Sgdamore@opensolaris.org 		*(uint32_t *)&dnetp->tx_desc[i].desc0 = 0;
2640*9860Sgdamore@opensolaris.org 		*(uint32_t *)&dnetp->tx_desc[i].desc1 = 0;
2641*9860Sgdamore@opensolaris.org 		dnetp->tx_desc[i].buffer1 = 0;
2642*9860Sgdamore@opensolaris.org 		dnetp->tx_desc[i].buffer2 = 0;
2643*9860Sgdamore@opensolaris.org 	}
2644*9860Sgdamore@opensolaris.org 	dnetp->tx_desc[i - 1].desc1.end_of_ring = 1;
2645*9860Sgdamore@opensolaris.org 
2646*9860Sgdamore@opensolaris.org 	/*
2647*9860Sgdamore@opensolaris.org 	 * Initialize the Rx descriptors
2648*9860Sgdamore@opensolaris.org 	 */
2649*9860Sgdamore@opensolaris.org 	for (i = 0; i < dnetp->nrecv_desc; i++) {
2650*9860Sgdamore@opensolaris.org 		uint32_t end_paddr;
2651*9860Sgdamore@opensolaris.org 		*(uint32_t *)&dnetp->rx_desc[i].desc0 = 0;
2652*9860Sgdamore@opensolaris.org 		*(uint32_t *)&dnetp->rx_desc[i].desc1 = 0;
2653*9860Sgdamore@opensolaris.org 		dnetp->rx_desc[i].desc0.own = 1;
2654*9860Sgdamore@opensolaris.org 		dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size;
2655*9860Sgdamore@opensolaris.org 		dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i];
2656*9860Sgdamore@opensolaris.org 		dnetp->rx_desc[i].buffer2 = 0;
2657*9860Sgdamore@opensolaris.org 		end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1;
2658*9860Sgdamore@opensolaris.org 
2659*9860Sgdamore@opensolaris.org 		if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) !=
2660*9860Sgdamore@opensolaris.org 		    (end_paddr & ~dnetp->pgmask)) {
2661*9860Sgdamore@opensolaris.org 			/* discontiguous */
2662*9860Sgdamore@opensolaris.org 			dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask;
2663*9860Sgdamore@opensolaris.org 			dnetp->rx_desc[i].desc1.buffer_size2 =
2664*9860Sgdamore@opensolaris.org 			    (end_paddr & dnetp->pgmask) + 1;
2665*9860Sgdamore@opensolaris.org 			dnetp->rx_desc[i].desc1.buffer_size1 =
2666*9860Sgdamore@opensolaris.org 			    rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2;
2667*9860Sgdamore@opensolaris.org 		}
2668*9860Sgdamore@opensolaris.org 	}
2669*9860Sgdamore@opensolaris.org 	dnetp->rx_desc[i - 1].desc1.end_of_ring = 1;
2670*9860Sgdamore@opensolaris.org }
2671*9860Sgdamore@opensolaris.org 
2672*9860Sgdamore@opensolaris.org static int
2673*9860Sgdamore@opensolaris.org alloc_descriptor(gld_mac_info_t *macinfo)
2674*9860Sgdamore@opensolaris.org {
2675*9860Sgdamore@opensolaris.org 	int index;
2676*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =	/* Our private device info */
2677*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
2678*9860Sgdamore@opensolaris.org 	struct tx_desc_type    *ring = dnetp->tx_desc;
2679*9860Sgdamore@opensolaris.org 
2680*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
2681*9860Sgdamore@opensolaris.org alloctop:
2682*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->txlock);
2683*9860Sgdamore@opensolaris.org 	index = dnetp->tx_current_desc;
2684*9860Sgdamore@opensolaris.org 
2685*9860Sgdamore@opensolaris.org 	dnet_reclaim_Tx_desc(macinfo);
2686*9860Sgdamore@opensolaris.org 
2687*9860Sgdamore@opensolaris.org 	/* we do have free descriptors, right? */
2688*9860Sgdamore@opensolaris.org 	if (dnetp->free_desc <= 0) {
2689*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
2690*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETRECV)
2691*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE, "dnet: Ring buffer is full");
2692*9860Sgdamore@opensolaris.org #endif
2693*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
2694*9860Sgdamore@opensolaris.org 		return (FAILURE);
2695*9860Sgdamore@opensolaris.org 	}
2696*9860Sgdamore@opensolaris.org 
2697*9860Sgdamore@opensolaris.org 	/* sanity, make sure the next descriptor is free for use (should be) */
2698*9860Sgdamore@opensolaris.org 	if (ring[index].desc0.own) {
2699*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
2700*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETRECV)
2701*9860Sgdamore@opensolaris.org 			cmn_err(CE_WARN,
2702*9860Sgdamore@opensolaris.org 			    "dnet: next descriptor is not free for use");
2703*9860Sgdamore@opensolaris.org #endif
2704*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
2705*9860Sgdamore@opensolaris.org 		return (FAILURE);
2706*9860Sgdamore@opensolaris.org 	}
2707*9860Sgdamore@opensolaris.org 	if (dnetp->need_saddr) {
2708*9860Sgdamore@opensolaris.org 		mutex_exit(&dnetp->txlock);
2709*9860Sgdamore@opensolaris.org 		/* XXX function return value ignored */
2710*9860Sgdamore@opensolaris.org 		if (!dnetp->suspended)
2711*9860Sgdamore@opensolaris.org 			(void) dnet_set_addr(macinfo);
2712*9860Sgdamore@opensolaris.org 		goto alloctop;
2713*9860Sgdamore@opensolaris.org 	}
2714*9860Sgdamore@opensolaris.org 
2715*9860Sgdamore@opensolaris.org 	*(uint32_t *)&ring[index].desc0 = 0;  /* init descs */
2716*9860Sgdamore@opensolaris.org 	*(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING;
2717*9860Sgdamore@opensolaris.org 
2718*9860Sgdamore@opensolaris.org 	/* hardware will own this descriptor when poll activated */
2719*9860Sgdamore@opensolaris.org 	dnetp->free_desc--;
2720*9860Sgdamore@opensolaris.org 
2721*9860Sgdamore@opensolaris.org 	/* point to next free descriptor to be used */
2722*9860Sgdamore@opensolaris.org 	dnetp->tx_current_desc = NextTXIndex(index);
2723*9860Sgdamore@opensolaris.org 
2724*9860Sgdamore@opensolaris.org #ifdef DNET_NOISY
2725*9860Sgdamore@opensolaris.org 	cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x",
2726*9860Sgdamore@opensolaris.org 	    dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc);
2727*9860Sgdamore@opensolaris.org #endif
2728*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->txlock);
2729*9860Sgdamore@opensolaris.org 	return (SUCCESS);
2730*9860Sgdamore@opensolaris.org }
2731*9860Sgdamore@opensolaris.org 
2732*9860Sgdamore@opensolaris.org /*
2733*9860Sgdamore@opensolaris.org  * dnet_reclaim_Tx_desc() - called with txlock held.
2734*9860Sgdamore@opensolaris.org  */
2735*9860Sgdamore@opensolaris.org static void
2736*9860Sgdamore@opensolaris.org dnet_reclaim_Tx_desc(gld_mac_info_t *macinfo)
2737*9860Sgdamore@opensolaris.org {
2738*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
2739*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
2740*9860Sgdamore@opensolaris.org 	struct tx_desc_type	*desc = dnetp->tx_desc;
2741*9860Sgdamore@opensolaris.org 	int index;
2742*9860Sgdamore@opensolaris.org 
2743*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->txlock));
2744*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
2745*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETTRACE)
2746*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet_reclaim_Tx_desc(0x%p)",
2747*9860Sgdamore@opensolaris.org 		    (void *) macinfo);
2748*9860Sgdamore@opensolaris.org #endif
2749*9860Sgdamore@opensolaris.org 
2750*9860Sgdamore@opensolaris.org 	index = dnetp->transmitted_desc;
2751*9860Sgdamore@opensolaris.org 	while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) &&
2752*9860Sgdamore@opensolaris.org 	    !(desc[index].desc0.own)) {
2753*9860Sgdamore@opensolaris.org 		/*
2754*9860Sgdamore@opensolaris.org 		 * Check for Tx Error that gets set
2755*9860Sgdamore@opensolaris.org 		 * in the last desc.
2756*9860Sgdamore@opensolaris.org 		 */
2757*9860Sgdamore@opensolaris.org 		if (desc[index].desc1.setup_packet == 0 &&
2758*9860Sgdamore@opensolaris.org 		    desc[index].desc1.last_desc &&
2759*9860Sgdamore@opensolaris.org 		    desc[index].desc0.err_summary)
2760*9860Sgdamore@opensolaris.org 			update_tx_stats(macinfo, index);
2761*9860Sgdamore@opensolaris.org 
2762*9860Sgdamore@opensolaris.org 		/*
2763*9860Sgdamore@opensolaris.org 		 * If we have used the streams message buffer for this
2764*9860Sgdamore@opensolaris.org 		 * descriptor then free up the message now.
2765*9860Sgdamore@opensolaris.org 		 */
2766*9860Sgdamore@opensolaris.org 		if (dnetp->tx_msgbufp[index] != NULL) {
2767*9860Sgdamore@opensolaris.org 			freemsg(dnetp->tx_msgbufp[index]);
2768*9860Sgdamore@opensolaris.org 			dnetp->tx_msgbufp[index] = NULL;
2769*9860Sgdamore@opensolaris.org 		}
2770*9860Sgdamore@opensolaris.org 		dnetp->free_desc++;
2771*9860Sgdamore@opensolaris.org 		index = (index+1) % dnetp->max_tx_desc;
2772*9860Sgdamore@opensolaris.org 	}
2773*9860Sgdamore@opensolaris.org 
2774*9860Sgdamore@opensolaris.org 	dnetp->transmitted_desc = index;
2775*9860Sgdamore@opensolaris.org }
2776*9860Sgdamore@opensolaris.org 
2777*9860Sgdamore@opensolaris.org /*
2778*9860Sgdamore@opensolaris.org  * Receive buffer allocation/freeing routines.
2779*9860Sgdamore@opensolaris.org  *
2780*9860Sgdamore@opensolaris.org  * There is a common pool of receive buffers shared by all dnet instances.
2781*9860Sgdamore@opensolaris.org  *
2782*9860Sgdamore@opensolaris.org  * XXX NEEDSWORK
2783*9860Sgdamore@opensolaris.org  *
2784*9860Sgdamore@opensolaris.org  * We arbitrarily allocate twice as many receive buffers as
2785*9860Sgdamore@opensolaris.org  * receive descriptors because we use the buffers for streams
2786*9860Sgdamore@opensolaris.org  * messages to pass the packets up the stream.  We should
2787*9860Sgdamore@opensolaris.org  * instead have initialized constants reflecting
2788*9860Sgdamore@opensolaris.org  * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2789*9860Sgdamore@opensolaris.org  * probably have a total maximum for the free pool, so that we
2790*9860Sgdamore@opensolaris.org  * don't get out of hand when someone puts in an 8-port board.
2791*9860Sgdamore@opensolaris.org  * The maximum for the entire pool should be the total number
2792*9860Sgdamore@opensolaris.org  * of descriptors for all attached instances together, plus the
2793*9860Sgdamore@opensolaris.org  * total maximum for the free pool.  This maximum would only be
2794*9860Sgdamore@opensolaris.org  * reached after some number of instances allocate buffers:
2795*9860Sgdamore@opensolaris.org  * each instance would add (max_rx_buf-max_rx_desc) to the free
2796*9860Sgdamore@opensolaris.org  * pool.
2797*9860Sgdamore@opensolaris.org  */
2798*9860Sgdamore@opensolaris.org 
2799*9860Sgdamore@opensolaris.org static struct rbuf_list *rbuf_usedlist_head;
2800*9860Sgdamore@opensolaris.org static struct rbuf_list *rbuf_freelist_head;
2801*9860Sgdamore@opensolaris.org static struct rbuf_list *rbuf_usedlist_end;	/* last buffer allocated */
2802*9860Sgdamore@opensolaris.org 
2803*9860Sgdamore@opensolaris.org static int rbuf_freebufs;	/* no. of free buffers in the pool */
2804*9860Sgdamore@opensolaris.org static int rbuf_pool_size;	/* total no. of buffers in the pool */
2805*9860Sgdamore@opensolaris.org 
2806*9860Sgdamore@opensolaris.org /* initialize/add 'nbufs' buffers to the rbuf pool */
2807*9860Sgdamore@opensolaris.org /* ARGSUSED */
2808*9860Sgdamore@opensolaris.org static int
2809*9860Sgdamore@opensolaris.org dnet_rbuf_init(dev_info_t *dip, int nbufs)
2810*9860Sgdamore@opensolaris.org {
2811*9860Sgdamore@opensolaris.org 	int i;
2812*9860Sgdamore@opensolaris.org 	struct rbuf_list *rp;
2813*9860Sgdamore@opensolaris.org 	ddi_dma_cookie_t cookie;
2814*9860Sgdamore@opensolaris.org 	uint_t ncookies;
2815*9860Sgdamore@opensolaris.org 	size_t len;
2816*9860Sgdamore@opensolaris.org 
2817*9860Sgdamore@opensolaris.org 	mutex_enter(&dnet_rbuf_lock);
2818*9860Sgdamore@opensolaris.org 
2819*9860Sgdamore@opensolaris.org 	/* allocate buffers and add them to the pool */
2820*9860Sgdamore@opensolaris.org 	for (i = 0; i < nbufs; i++) {
2821*9860Sgdamore@opensolaris.org 		/* allocate rbuf_list element */
2822*9860Sgdamore@opensolaris.org 		rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2823*9860Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2824*9860Sgdamore@opensolaris.org 		    0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2825*9860Sgdamore@opensolaris.org 			goto fail_kfree;
2826*9860Sgdamore@opensolaris.org 
2827*9860Sgdamore@opensolaris.org 		/* allocate dma memory for the buffer */
2828*9860Sgdamore@opensolaris.org 		if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2829*9860Sgdamore@opensolaris.org 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2830*9860Sgdamore@opensolaris.org 		    &rp->rbuf_vaddr, &len,
2831*9860Sgdamore@opensolaris.org 		    &rp->rbuf_acchdl) != DDI_SUCCESS)
2832*9860Sgdamore@opensolaris.org 			goto fail_freehdl;
2833*9860Sgdamore@opensolaris.org 
2834*9860Sgdamore@opensolaris.org 		if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2835*9860Sgdamore@opensolaris.org 		    rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2836*9860Sgdamore@opensolaris.org 		    DDI_DMA_SLEEP, NULL, &cookie,
2837*9860Sgdamore@opensolaris.org 		    &ncookies) != DDI_DMA_MAPPED)
2838*9860Sgdamore@opensolaris.org 			goto fail_free;
2839*9860Sgdamore@opensolaris.org 
2840*9860Sgdamore@opensolaris.org 		if (ncookies > 2)
2841*9860Sgdamore@opensolaris.org 			goto fail_unbind;
2842*9860Sgdamore@opensolaris.org 		if (ncookies == 1) {
2843*9860Sgdamore@opensolaris.org 			rp->rbuf_endpaddr =
2844*9860Sgdamore@opensolaris.org 			    cookie.dmac_address + rx_buf_size - 1;
2845*9860Sgdamore@opensolaris.org 		} else {
2846*9860Sgdamore@opensolaris.org 			ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2847*9860Sgdamore@opensolaris.org 			rp->rbuf_endpaddr =
2848*9860Sgdamore@opensolaris.org 			    cookie.dmac_address + cookie.dmac_size - 1;
2849*9860Sgdamore@opensolaris.org 		}
2850*9860Sgdamore@opensolaris.org 		rp->rbuf_paddr = cookie.dmac_address;
2851*9860Sgdamore@opensolaris.org 
2852*9860Sgdamore@opensolaris.org 		rp->rbuf_next = rbuf_freelist_head;
2853*9860Sgdamore@opensolaris.org 		rbuf_freelist_head = rp;
2854*9860Sgdamore@opensolaris.org 		rbuf_pool_size++;
2855*9860Sgdamore@opensolaris.org 		rbuf_freebufs++;
2856*9860Sgdamore@opensolaris.org 	}
2857*9860Sgdamore@opensolaris.org 
2858*9860Sgdamore@opensolaris.org 	mutex_exit(&dnet_rbuf_lock);
2859*9860Sgdamore@opensolaris.org 	return (0);
2860*9860Sgdamore@opensolaris.org fail_unbind:
2861*9860Sgdamore@opensolaris.org 	(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2862*9860Sgdamore@opensolaris.org fail_free:
2863*9860Sgdamore@opensolaris.org 	ddi_dma_mem_free(&rp->rbuf_acchdl);
2864*9860Sgdamore@opensolaris.org fail_freehdl:
2865*9860Sgdamore@opensolaris.org 	ddi_dma_free_handle(&rp->rbuf_dmahdl);
2866*9860Sgdamore@opensolaris.org fail_kfree:
2867*9860Sgdamore@opensolaris.org 	kmem_free(rp, sizeof (struct rbuf_list));
2868*9860Sgdamore@opensolaris.org 
2869*9860Sgdamore@opensolaris.org 	mutex_exit(&dnet_rbuf_lock);
2870*9860Sgdamore@opensolaris.org 	return (-1);
2871*9860Sgdamore@opensolaris.org }
2872*9860Sgdamore@opensolaris.org 
2873*9860Sgdamore@opensolaris.org /*
2874*9860Sgdamore@opensolaris.org  * Try to free up all the rbufs in the pool. Returns 0 if it frees up all
2875*9860Sgdamore@opensolaris.org  * buffers. The buffers in the used list are considered busy so these
2876*9860Sgdamore@opensolaris.org  * buffers are not freed.
2877*9860Sgdamore@opensolaris.org  */
2878*9860Sgdamore@opensolaris.org static int
2879*9860Sgdamore@opensolaris.org dnet_rbuf_destroy()
2880*9860Sgdamore@opensolaris.org {
2881*9860Sgdamore@opensolaris.org 	struct rbuf_list *rp, *next;
2882*9860Sgdamore@opensolaris.org 
2883*9860Sgdamore@opensolaris.org 	mutex_enter(&dnet_rbuf_lock);
2884*9860Sgdamore@opensolaris.org 
2885*9860Sgdamore@opensolaris.org 	for (rp = rbuf_freelist_head; rp; rp = next) {
2886*9860Sgdamore@opensolaris.org 		next = rp->rbuf_next;
2887*9860Sgdamore@opensolaris.org 		ddi_dma_mem_free(&rp->rbuf_acchdl);
2888*9860Sgdamore@opensolaris.org 		(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2889*9860Sgdamore@opensolaris.org 		kmem_free(rp, sizeof (struct rbuf_list));
2890*9860Sgdamore@opensolaris.org 		rbuf_pool_size--;
2891*9860Sgdamore@opensolaris.org 		rbuf_freebufs--;
2892*9860Sgdamore@opensolaris.org 	}
2893*9860Sgdamore@opensolaris.org 	rbuf_freelist_head = NULL;
2894*9860Sgdamore@opensolaris.org 
2895*9860Sgdamore@opensolaris.org 	if (rbuf_pool_size) { /* pool is still not empty */
2896*9860Sgdamore@opensolaris.org 		mutex_exit(&dnet_rbuf_lock);
2897*9860Sgdamore@opensolaris.org 		return (-1);
2898*9860Sgdamore@opensolaris.org 	}
2899*9860Sgdamore@opensolaris.org 	mutex_exit(&dnet_rbuf_lock);
2900*9860Sgdamore@opensolaris.org 	return (0);
2901*9860Sgdamore@opensolaris.org }
2902*9860Sgdamore@opensolaris.org static struct rbuf_list *
2903*9860Sgdamore@opensolaris.org dnet_rbuf_alloc(dev_info_t *dip, int cansleep)
2904*9860Sgdamore@opensolaris.org {
2905*9860Sgdamore@opensolaris.org 	struct rbuf_list *rp;
2906*9860Sgdamore@opensolaris.org 	size_t len;
2907*9860Sgdamore@opensolaris.org 	ddi_dma_cookie_t cookie;
2908*9860Sgdamore@opensolaris.org 	uint_t ncookies;
2909*9860Sgdamore@opensolaris.org 
2910*9860Sgdamore@opensolaris.org 	mutex_enter(&dnet_rbuf_lock);
2911*9860Sgdamore@opensolaris.org 
2912*9860Sgdamore@opensolaris.org 	if (rbuf_freelist_head == NULL) {
2913*9860Sgdamore@opensolaris.org 
2914*9860Sgdamore@opensolaris.org 		if (!cansleep) {
2915*9860Sgdamore@opensolaris.org 			mutex_exit(&dnet_rbuf_lock);
2916*9860Sgdamore@opensolaris.org 			return (NULL);
2917*9860Sgdamore@opensolaris.org 		}
2918*9860Sgdamore@opensolaris.org 
2919*9860Sgdamore@opensolaris.org 		/* allocate rbuf_list element */
2920*9860Sgdamore@opensolaris.org 		rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2921*9860Sgdamore@opensolaris.org 		if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2922*9860Sgdamore@opensolaris.org 		    0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2923*9860Sgdamore@opensolaris.org 			goto fail_kfree;
2924*9860Sgdamore@opensolaris.org 
2925*9860Sgdamore@opensolaris.org 		/* allocate dma memory for the buffer */
2926*9860Sgdamore@opensolaris.org 		if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2927*9860Sgdamore@opensolaris.org 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2928*9860Sgdamore@opensolaris.org 		    &rp->rbuf_vaddr, &len,
2929*9860Sgdamore@opensolaris.org 		    &rp->rbuf_acchdl) != DDI_SUCCESS)
2930*9860Sgdamore@opensolaris.org 			goto fail_freehdl;
2931*9860Sgdamore@opensolaris.org 
2932*9860Sgdamore@opensolaris.org 		if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2933*9860Sgdamore@opensolaris.org 		    rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2934*9860Sgdamore@opensolaris.org 		    DDI_DMA_SLEEP, NULL, &cookie,
2935*9860Sgdamore@opensolaris.org 		    &ncookies) != DDI_DMA_MAPPED)
2936*9860Sgdamore@opensolaris.org 			goto fail_free;
2937*9860Sgdamore@opensolaris.org 
2938*9860Sgdamore@opensolaris.org 		if (ncookies > 2)
2939*9860Sgdamore@opensolaris.org 			goto fail_unbind;
2940*9860Sgdamore@opensolaris.org 		if (ncookies == 1) {
2941*9860Sgdamore@opensolaris.org 			rp->rbuf_endpaddr =
2942*9860Sgdamore@opensolaris.org 			    cookie.dmac_address + rx_buf_size - 1;
2943*9860Sgdamore@opensolaris.org 		} else {
2944*9860Sgdamore@opensolaris.org 			ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2945*9860Sgdamore@opensolaris.org 			rp->rbuf_endpaddr =
2946*9860Sgdamore@opensolaris.org 			    cookie.dmac_address + cookie.dmac_size - 1;
2947*9860Sgdamore@opensolaris.org 		}
2948*9860Sgdamore@opensolaris.org 		rp->rbuf_paddr = cookie.dmac_address;
2949*9860Sgdamore@opensolaris.org 
2950*9860Sgdamore@opensolaris.org 		rbuf_freelist_head = rp;
2951*9860Sgdamore@opensolaris.org 		rbuf_pool_size++;
2952*9860Sgdamore@opensolaris.org 		rbuf_freebufs++;
2953*9860Sgdamore@opensolaris.org 	}
2954*9860Sgdamore@opensolaris.org 
2955*9860Sgdamore@opensolaris.org 	/* take the buffer from the head of the free list */
2956*9860Sgdamore@opensolaris.org 	rp = rbuf_freelist_head;
2957*9860Sgdamore@opensolaris.org 	rbuf_freelist_head = rbuf_freelist_head->rbuf_next;
2958*9860Sgdamore@opensolaris.org 
2959*9860Sgdamore@opensolaris.org 	/* update the used list; put the entry at the end */
2960*9860Sgdamore@opensolaris.org 	if (rbuf_usedlist_head == NULL)
2961*9860Sgdamore@opensolaris.org 		rbuf_usedlist_head = rp;
2962*9860Sgdamore@opensolaris.org 	else
2963*9860Sgdamore@opensolaris.org 		rbuf_usedlist_end->rbuf_next = rp;
2964*9860Sgdamore@opensolaris.org 	rp->rbuf_next = NULL;
2965*9860Sgdamore@opensolaris.org 	rbuf_usedlist_end = rp;
2966*9860Sgdamore@opensolaris.org 	rbuf_freebufs--;
2967*9860Sgdamore@opensolaris.org 
2968*9860Sgdamore@opensolaris.org 	mutex_exit(&dnet_rbuf_lock);
2969*9860Sgdamore@opensolaris.org 
2970*9860Sgdamore@opensolaris.org 	return (rp);
2971*9860Sgdamore@opensolaris.org fail_unbind:
2972*9860Sgdamore@opensolaris.org 	(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2973*9860Sgdamore@opensolaris.org fail_free:
2974*9860Sgdamore@opensolaris.org 	ddi_dma_mem_free(&rp->rbuf_acchdl);
2975*9860Sgdamore@opensolaris.org fail_freehdl:
2976*9860Sgdamore@opensolaris.org 	ddi_dma_free_handle(&rp->rbuf_dmahdl);
2977*9860Sgdamore@opensolaris.org fail_kfree:
2978*9860Sgdamore@opensolaris.org 	kmem_free(rp, sizeof (struct rbuf_list));
2979*9860Sgdamore@opensolaris.org 	mutex_exit(&dnet_rbuf_lock);
2980*9860Sgdamore@opensolaris.org 	return (NULL);
2981*9860Sgdamore@opensolaris.org }
2982*9860Sgdamore@opensolaris.org 
2983*9860Sgdamore@opensolaris.org static void
2984*9860Sgdamore@opensolaris.org dnet_rbuf_free(caddr_t vaddr)
2985*9860Sgdamore@opensolaris.org {
2986*9860Sgdamore@opensolaris.org 	struct rbuf_list *rp, *prev;
2987*9860Sgdamore@opensolaris.org 
2988*9860Sgdamore@opensolaris.org 	ASSERT(vaddr != NULL);
2989*9860Sgdamore@opensolaris.org 	ASSERT(rbuf_usedlist_head != NULL);
2990*9860Sgdamore@opensolaris.org 
2991*9860Sgdamore@opensolaris.org 	mutex_enter(&dnet_rbuf_lock);
2992*9860Sgdamore@opensolaris.org 
2993*9860Sgdamore@opensolaris.org 	/* find the entry in the used list */
2994*9860Sgdamore@opensolaris.org 	for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) {
2995*9860Sgdamore@opensolaris.org 		if (rp->rbuf_vaddr == vaddr)
2996*9860Sgdamore@opensolaris.org 			break;
2997*9860Sgdamore@opensolaris.org 		prev = rp;
2998*9860Sgdamore@opensolaris.org 	}
2999*9860Sgdamore@opensolaris.org 
3000*9860Sgdamore@opensolaris.org 	if (rp == NULL) {
3001*9860Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p",
3002*9860Sgdamore@opensolaris.org 		    (void *)vaddr);
3003*9860Sgdamore@opensolaris.org 		mutex_exit(&dnet_rbuf_lock);
3004*9860Sgdamore@opensolaris.org 		return;
3005*9860Sgdamore@opensolaris.org 	}
3006*9860Sgdamore@opensolaris.org 
3007*9860Sgdamore@opensolaris.org 	/* update the used list and put the buffer back in the free list */
3008*9860Sgdamore@opensolaris.org 	if (rbuf_usedlist_head != rp) {
3009*9860Sgdamore@opensolaris.org 		prev->rbuf_next = rp->rbuf_next;
3010*9860Sgdamore@opensolaris.org 		if (rbuf_usedlist_end == rp)
3011*9860Sgdamore@opensolaris.org 			rbuf_usedlist_end = prev;
3012*9860Sgdamore@opensolaris.org 	} else {
3013*9860Sgdamore@opensolaris.org 		rbuf_usedlist_head = rp->rbuf_next;
3014*9860Sgdamore@opensolaris.org 		if (rbuf_usedlist_end == rp)
3015*9860Sgdamore@opensolaris.org 			rbuf_usedlist_end = NULL;
3016*9860Sgdamore@opensolaris.org 	}
3017*9860Sgdamore@opensolaris.org 	rp->rbuf_next = rbuf_freelist_head;
3018*9860Sgdamore@opensolaris.org 	rbuf_freelist_head = rp;
3019*9860Sgdamore@opensolaris.org 	rbuf_freebufs++;
3020*9860Sgdamore@opensolaris.org 
3021*9860Sgdamore@opensolaris.org 	mutex_exit(&dnet_rbuf_lock);
3022*9860Sgdamore@opensolaris.org }
3023*9860Sgdamore@opensolaris.org 
3024*9860Sgdamore@opensolaris.org /*
3025*9860Sgdamore@opensolaris.org  * Free the receive buffer used in a stream's message block allocated
3026*9860Sgdamore@opensolaris.org  * thru desballoc().
3027*9860Sgdamore@opensolaris.org  */
3028*9860Sgdamore@opensolaris.org static void
3029*9860Sgdamore@opensolaris.org dnet_freemsg_buf(struct free_ptr *frp)
3030*9860Sgdamore@opensolaris.org {
3031*9860Sgdamore@opensolaris.org 	dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */
3032*9860Sgdamore@opensolaris.org 	kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */
3033*9860Sgdamore@opensolaris.org }
3034*9860Sgdamore@opensolaris.org 
3035*9860Sgdamore@opensolaris.org /*
3036*9860Sgdamore@opensolaris.org  *	========== SROM Read Routines ==========
3037*9860Sgdamore@opensolaris.org  */
3038*9860Sgdamore@opensolaris.org 
3039*9860Sgdamore@opensolaris.org /*
3040*9860Sgdamore@opensolaris.org  * The following code gets the SROM information, either by reading it
3041*9860Sgdamore@opensolaris.org  * from the device or, failing that, by reading a property.
3042*9860Sgdamore@opensolaris.org  */
3043*9860Sgdamore@opensolaris.org static int
3044*9860Sgdamore@opensolaris.org dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle,
3045*9860Sgdamore@opensolaris.org     caddr_t io_reg, uchar_t *vi, int maxlen)
3046*9860Sgdamore@opensolaris.org {
3047*9860Sgdamore@opensolaris.org 	int all_ones, zerocheck, i;
3048*9860Sgdamore@opensolaris.org 
3049*9860Sgdamore@opensolaris.org 	/*
3050*9860Sgdamore@opensolaris.org 	 * Load SROM into vendor_info
3051*9860Sgdamore@opensolaris.org 	 */
3052*9860Sgdamore@opensolaris.org 	if (board_type == DEVICE_ID_21040)
3053*9860Sgdamore@opensolaris.org 		dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen);
3054*9860Sgdamore@opensolaris.org 	else
3055*9860Sgdamore@opensolaris.org 		/* 21041/21140 serial rom */
3056*9860Sgdamore@opensolaris.org 		dnet_read21140srom(io_handle, io_reg, vi, maxlen);
3057*9860Sgdamore@opensolaris.org 	/*
3058*9860Sgdamore@opensolaris.org 	 * If the dumpsrom property is present in the conf file, print
3059*9860Sgdamore@opensolaris.org 	 * the contents of the SROM to the console
3060*9860Sgdamore@opensolaris.org 	 */
3061*9860Sgdamore@opensolaris.org 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3062*9860Sgdamore@opensolaris.org 	    "dumpsrom", 0))
3063*9860Sgdamore@opensolaris.org 		dnet_dumpbin("SROM", vi, 1, maxlen);
3064*9860Sgdamore@opensolaris.org 
3065*9860Sgdamore@opensolaris.org 	for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) {
3066*9860Sgdamore@opensolaris.org 		zerocheck |= vi[i];
3067*9860Sgdamore@opensolaris.org 		all_ones &= vi[i];
3068*9860Sgdamore@opensolaris.org 	}
3069*9860Sgdamore@opensolaris.org 	if (zerocheck == 0 || all_ones == 0xff) {
3070*9860Sgdamore@opensolaris.org 		return (get_alternative_srom_image(devinfo, vi, maxlen));
3071*9860Sgdamore@opensolaris.org 	} else {
3072*9860Sgdamore@opensolaris.org #ifdef BUG_4010796
3073*9860Sgdamore@opensolaris.org 		set_alternative_srom_image(devinfo, vi, maxlen);
3074*9860Sgdamore@opensolaris.org #endif
3075*9860Sgdamore@opensolaris.org 		return (0);	/* Primary */
3076*9860Sgdamore@opensolaris.org 	}
3077*9860Sgdamore@opensolaris.org }
3078*9860Sgdamore@opensolaris.org 
3079*9860Sgdamore@opensolaris.org /*
3080*9860Sgdamore@opensolaris.org  * The function reads the ethernet address of the 21040 adapter
3081*9860Sgdamore@opensolaris.org  */
3082*9860Sgdamore@opensolaris.org static void
3083*9860Sgdamore@opensolaris.org dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg,
3084*9860Sgdamore@opensolaris.org     uchar_t *addr, int *len)
3085*9860Sgdamore@opensolaris.org {
3086*9860Sgdamore@opensolaris.org 	uint32_t	val;
3087*9860Sgdamore@opensolaris.org 	int		i;
3088*9860Sgdamore@opensolaris.org 
3089*9860Sgdamore@opensolaris.org 	/* No point reading more than the ethernet address */
3090*9860Sgdamore@opensolaris.org 	*len = ddi_getprop(DDI_DEV_T_ANY, dip,
3091*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL;
3092*9860Sgdamore@opensolaris.org 
3093*9860Sgdamore@opensolaris.org 	/* Reset ROM pointer */
3094*9860Sgdamore@opensolaris.org 	ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0);
3095*9860Sgdamore@opensolaris.org 	for (i = 0; i < *len; i++) {
3096*9860Sgdamore@opensolaris.org 		do {
3097*9860Sgdamore@opensolaris.org 			val = ddi_get32(io_handle,
3098*9860Sgdamore@opensolaris.org 			    REG32(io_reg, ETHER_ROM_REG));
3099*9860Sgdamore@opensolaris.org 		} while (val & 0x80000000);
3100*9860Sgdamore@opensolaris.org 		addr[i] = val & 0xFF;
3101*9860Sgdamore@opensolaris.org 	}
3102*9860Sgdamore@opensolaris.org }
3103*9860Sgdamore@opensolaris.org 
3104*9860Sgdamore@opensolaris.org #define	drv_nsecwait(x)	drv_usecwait(((x)+999)/1000) /* XXX */
3105*9860Sgdamore@opensolaris.org 
3106*9860Sgdamore@opensolaris.org /*
3107*9860Sgdamore@opensolaris.org  * The function reads the SROM	of the 21140 adapter
3108*9860Sgdamore@opensolaris.org  */
3109*9860Sgdamore@opensolaris.org static void
3110*9860Sgdamore@opensolaris.org dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr,
3111*9860Sgdamore@opensolaris.org     int maxlen)
3112*9860Sgdamore@opensolaris.org {
3113*9860Sgdamore@opensolaris.org 	uint32_t 	i, j;
3114*9860Sgdamore@opensolaris.org 	uint32_t	dout;
3115*9860Sgdamore@opensolaris.org 	uint16_t	word;
3116*9860Sgdamore@opensolaris.org 	uint8_t		rom_addr;
3117*9860Sgdamore@opensolaris.org 	uint8_t		bit;
3118*9860Sgdamore@opensolaris.org 
3119*9860Sgdamore@opensolaris.org 
3120*9860Sgdamore@opensolaris.org 	rom_addr = 0;
3121*9860Sgdamore@opensolaris.org 	for (i = 0; i <	maxlen; i += 2) {
3122*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3123*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM);
3124*9860Sgdamore@opensolaris.org 		drv_nsecwait(30);
3125*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3126*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP);
3127*9860Sgdamore@opensolaris.org 		drv_nsecwait(50);
3128*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3129*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
3130*9860Sgdamore@opensolaris.org 		drv_nsecwait(250);
3131*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3132*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP);
3133*9860Sgdamore@opensolaris.org 		drv_nsecwait(100);
3134*9860Sgdamore@opensolaris.org 
3135*9860Sgdamore@opensolaris.org 		/* command */
3136*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3137*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
3138*9860Sgdamore@opensolaris.org 		drv_nsecwait(150);
3139*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3140*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
3141*9860Sgdamore@opensolaris.org 		drv_nsecwait(250);
3142*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3143*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
3144*9860Sgdamore@opensolaris.org 		drv_nsecwait(250);
3145*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3146*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
3147*9860Sgdamore@opensolaris.org 		drv_nsecwait(250);
3148*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3149*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
3150*9860Sgdamore@opensolaris.org 		drv_nsecwait(100);
3151*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3152*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP);
3153*9860Sgdamore@opensolaris.org 		drv_nsecwait(150);
3154*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3155*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
3156*9860Sgdamore@opensolaris.org 		drv_nsecwait(250);
3157*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3158*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM | SEL_CHIP);
3159*9860Sgdamore@opensolaris.org 		drv_nsecwait(100);
3160*9860Sgdamore@opensolaris.org 
3161*9860Sgdamore@opensolaris.org 		/* Address */
3162*9860Sgdamore@opensolaris.org 		for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) {
3163*9860Sgdamore@opensolaris.org 			bit = (rom_addr & j) ? DATA_IN : 0;
3164*9860Sgdamore@opensolaris.org 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3165*9860Sgdamore@opensolaris.org 			    READ_OP | SEL_ROM | SEL_CHIP | bit);
3166*9860Sgdamore@opensolaris.org 			drv_nsecwait(150);
3167*9860Sgdamore@opensolaris.org 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3168*9860Sgdamore@opensolaris.org 			    READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK);
3169*9860Sgdamore@opensolaris.org 			drv_nsecwait(250);
3170*9860Sgdamore@opensolaris.org 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3171*9860Sgdamore@opensolaris.org 			    READ_OP | SEL_ROM | SEL_CHIP | bit);
3172*9860Sgdamore@opensolaris.org 			drv_nsecwait(100);
3173*9860Sgdamore@opensolaris.org 		}
3174*9860Sgdamore@opensolaris.org 		drv_nsecwait(150);
3175*9860Sgdamore@opensolaris.org 
3176*9860Sgdamore@opensolaris.org 		/* Data */
3177*9860Sgdamore@opensolaris.org 		word = 0;
3178*9860Sgdamore@opensolaris.org 		for (j = 0x8000; j >= 1; j >>= 1) {
3179*9860Sgdamore@opensolaris.org 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3180*9860Sgdamore@opensolaris.org 			    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
3181*9860Sgdamore@opensolaris.org 			drv_nsecwait(100);
3182*9860Sgdamore@opensolaris.org 			dout = ddi_get32(io_handle,
3183*9860Sgdamore@opensolaris.org 			    REG32(io_reg, ETHER_ROM_REG));
3184*9860Sgdamore@opensolaris.org 			drv_nsecwait(150);
3185*9860Sgdamore@opensolaris.org 			if (dout & DATA_OUT)
3186*9860Sgdamore@opensolaris.org 				word |= j;
3187*9860Sgdamore@opensolaris.org 			ddi_put32(io_handle,
3188*9860Sgdamore@opensolaris.org 			    REG32(io_reg, ETHER_ROM_REG),
3189*9860Sgdamore@opensolaris.org 			    READ_OP | SEL_ROM | SEL_CHIP);
3190*9860Sgdamore@opensolaris.org 			drv_nsecwait(250);
3191*9860Sgdamore@opensolaris.org 		}
3192*9860Sgdamore@opensolaris.org 		addr[i] = (word & 0x0000FF);
3193*9860Sgdamore@opensolaris.org 		addr[i + 1] = (word >> 8);
3194*9860Sgdamore@opensolaris.org 		rom_addr++;
3195*9860Sgdamore@opensolaris.org 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
3196*9860Sgdamore@opensolaris.org 		    READ_OP | SEL_ROM);
3197*9860Sgdamore@opensolaris.org 		drv_nsecwait(100);
3198*9860Sgdamore@opensolaris.org 	}
3199*9860Sgdamore@opensolaris.org }
3200*9860Sgdamore@opensolaris.org 
3201*9860Sgdamore@opensolaris.org 
3202*9860Sgdamore@opensolaris.org /*
3203*9860Sgdamore@opensolaris.org  * XXX NEEDSWORK
3204*9860Sgdamore@opensolaris.org  *
3205*9860Sgdamore@opensolaris.org  * Some lame multiport cards have only one SROM, which can be accessed
3206*9860Sgdamore@opensolaris.org  * only from the "first" 21x4x chip, whichever that one is.  If we can't
3207*9860Sgdamore@opensolaris.org  * get at our SROM, we look for its contents in a property instead, which
3208*9860Sgdamore@opensolaris.org  * we rely on the bootstrap to have properly set.
3209*9860Sgdamore@opensolaris.org  * #ifdef BUG_4010796
3210*9860Sgdamore@opensolaris.org  * We also have a hack to try to set it ourselves, when the "first" port
3211*9860Sgdamore@opensolaris.org  * attaches, if it has not already been properly set.  However, this method
3212*9860Sgdamore@opensolaris.org  * is not reliable, since it makes the unwarrented assumption that the
3213*9860Sgdamore@opensolaris.org  * "first" port will attach first.
3214*9860Sgdamore@opensolaris.org  * #endif
3215*9860Sgdamore@opensolaris.org  */
3216*9860Sgdamore@opensolaris.org 
3217*9860Sgdamore@opensolaris.org static int
3218*9860Sgdamore@opensolaris.org get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
3219*9860Sgdamore@opensolaris.org {
3220*9860Sgdamore@opensolaris.org 	int	l = len;
3221*9860Sgdamore@opensolaris.org 
3222*9860Sgdamore@opensolaris.org 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3223*9860Sgdamore@opensolaris.org 	    "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS &&
3224*9860Sgdamore@opensolaris.org 	    (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY,
3225*9860Sgdamore@opensolaris.org 	    ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM",
3226*9860Sgdamore@opensolaris.org 	    (caddr_t)vi, &len) != DDI_PROP_SUCCESS)
3227*9860Sgdamore@opensolaris.org 		return (-1);	/* Can't find it! */
3228*9860Sgdamore@opensolaris.org 
3229*9860Sgdamore@opensolaris.org 	/*
3230*9860Sgdamore@opensolaris.org 	 * The return value from this routine specifies which port number
3231*9860Sgdamore@opensolaris.org 	 * we are.  The primary port is denoted port 0.  On a QUAD card we
3232*9860Sgdamore@opensolaris.org 	 * should return 1, 2, and 3 from this routine.  The return value
3233*9860Sgdamore@opensolaris.org 	 * is used to modify the ethernet address from the SROM data.
3234*9860Sgdamore@opensolaris.org 	 */
3235*9860Sgdamore@opensolaris.org 
3236*9860Sgdamore@opensolaris.org #ifdef BUG_4010796
3237*9860Sgdamore@opensolaris.org 	{
3238*9860Sgdamore@opensolaris.org 	/*
3239*9860Sgdamore@opensolaris.org 	 * For the present, we remember the device number of our primary
3240*9860Sgdamore@opensolaris.org 	 * sibling and hope we and our other siblings are consecutively
3241*9860Sgdamore@opensolaris.org 	 * numbered up from there.  In the future perhaps the bootstrap
3242*9860Sgdamore@opensolaris.org 	 * will pass us the necessary information telling us which physical
3243*9860Sgdamore@opensolaris.org 	 * port we really are.
3244*9860Sgdamore@opensolaris.org 	 */
3245*9860Sgdamore@opensolaris.org 	pci_regspec_t	*assignp;
3246*9860Sgdamore@opensolaris.org 	int		assign_len;
3247*9860Sgdamore@opensolaris.org 	int 		devnum;
3248*9860Sgdamore@opensolaris.org 	int		primary_devnum;
3249*9860Sgdamore@opensolaris.org 
3250*9860Sgdamore@opensolaris.org 	primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0,
3251*9860Sgdamore@opensolaris.org 	    "DNET_DEVNUM", -1);
3252*9860Sgdamore@opensolaris.org 	if (primary_devnum == -1)
3253*9860Sgdamore@opensolaris.org 		return (1);	/* XXX NEEDSWORK -- We have no better idea */
3254*9860Sgdamore@opensolaris.org 
3255*9860Sgdamore@opensolaris.org 	if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3256*9860Sgdamore@opensolaris.org 	    "assigned-addresses", (caddr_t)&assignp,
3257*9860Sgdamore@opensolaris.org 	    &assign_len)) != DDI_PROP_SUCCESS)
3258*9860Sgdamore@opensolaris.org 		return (1);	/* XXX NEEDSWORK -- We have no better idea */
3259*9860Sgdamore@opensolaris.org 
3260*9860Sgdamore@opensolaris.org 	devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3261*9860Sgdamore@opensolaris.org 	kmem_free(assignp, assign_len);
3262*9860Sgdamore@opensolaris.org 	return (devnum - primary_devnum);
3263*9860Sgdamore@opensolaris.org 	}
3264*9860Sgdamore@opensolaris.org #else
3265*9860Sgdamore@opensolaris.org 	return (1);	/* XXX NEEDSWORK -- We have no better idea */
3266*9860Sgdamore@opensolaris.org #endif
3267*9860Sgdamore@opensolaris.org }
3268*9860Sgdamore@opensolaris.org 
3269*9860Sgdamore@opensolaris.org 
3270*9860Sgdamore@opensolaris.org #ifdef BUG_4010796
3271*9860Sgdamore@opensolaris.org static void
3272*9860Sgdamore@opensolaris.org set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
3273*9860Sgdamore@opensolaris.org {
3274*9860Sgdamore@opensolaris.org 	int 		proplen;
3275*9860Sgdamore@opensolaris.org 	pci_regspec_t	*assignp;
3276*9860Sgdamore@opensolaris.org 	int		assign_len;
3277*9860Sgdamore@opensolaris.org 	int 		devnum;
3278*9860Sgdamore@opensolaris.org 
3279*9860Sgdamore@opensolaris.org 	if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3280*9860Sgdamore@opensolaris.org 	    "DNET_SROM", &proplen) == DDI_PROP_SUCCESS ||
3281*9860Sgdamore@opensolaris.org 	    ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3282*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS)
3283*9860Sgdamore@opensolaris.org 		return;		/* Already done! */
3284*9860Sgdamore@opensolaris.org 
3285*9860Sgdamore@opensolaris.org 	/* function return value ignored */
3286*9860Sgdamore@opensolaris.org 	(void) ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3287*9860Sgdamore@opensolaris.org 	    ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len);
3288*9860Sgdamore@opensolaris.org 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo,
3289*9860Sgdamore@opensolaris.org 	    "DNET_HACK", "hack");
3290*9860Sgdamore@opensolaris.org 
3291*9860Sgdamore@opensolaris.org 	if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3292*9860Sgdamore@opensolaris.org 	    "assigned-addresses", (caddr_t)&assignp,
3293*9860Sgdamore@opensolaris.org 	    &assign_len)) == DDI_PROP_SUCCESS) {
3294*9860Sgdamore@opensolaris.org 		devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3295*9860Sgdamore@opensolaris.org 		kmem_free(assignp, assign_len);
3296*9860Sgdamore@opensolaris.org 		/* function return value ignored */
3297*9860Sgdamore@opensolaris.org 		(void) ddi_prop_update_int(DDI_DEV_T_NONE,
3298*9860Sgdamore@opensolaris.org 		    ddi_get_parent(devinfo), "DNET_DEVNUM", devnum);
3299*9860Sgdamore@opensolaris.org 	}
3300*9860Sgdamore@opensolaris.org }
3301*9860Sgdamore@opensolaris.org #endif
3302*9860Sgdamore@opensolaris.org 
3303*9860Sgdamore@opensolaris.org /*
3304*9860Sgdamore@opensolaris.org  *	========== SROM Parsing Routines ==========
3305*9860Sgdamore@opensolaris.org  */
3306*9860Sgdamore@opensolaris.org 
3307*9860Sgdamore@opensolaris.org static int
3308*9860Sgdamore@opensolaris.org check_srom_valid(uchar_t *vi)
3309*9860Sgdamore@opensolaris.org {
3310*9860Sgdamore@opensolaris.org 	int		word, bit;
3311*9860Sgdamore@opensolaris.org 	uint8_t		crc;
3312*9860Sgdamore@opensolaris.org 	uint16_t	*wvi;		/* word16 pointer to vendor info */
3313*9860Sgdamore@opensolaris.org 	uint16_t	bitval;
3314*9860Sgdamore@opensolaris.org 
3315*9860Sgdamore@opensolaris.org 	/* verify that the number of controllers on the card is within range */
3316*9860Sgdamore@opensolaris.org 	if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS)
3317*9860Sgdamore@opensolaris.org 		return (0);
3318*9860Sgdamore@opensolaris.org 
3319*9860Sgdamore@opensolaris.org 	/*
3320*9860Sgdamore@opensolaris.org 	 * version 1 and 3 of this card did not check the id block CRC value
3321*9860Sgdamore@opensolaris.org 	 * and this can't be changed without retesting every supported card
3322*9860Sgdamore@opensolaris.org 	 *
3323*9860Sgdamore@opensolaris.org 	 * however version 4 of the SROM can have this test applied
3324*9860Sgdamore@opensolaris.org 	 * without fear of breaking something that used to work.
3325*9860Sgdamore@opensolaris.org 	 * the CRC algorithm is taken from the Intel document
3326*9860Sgdamore@opensolaris.org 	 *	"21x4 Serial ROM Format"
3327*9860Sgdamore@opensolaris.org 	 *	version 4.09
3328*9860Sgdamore@opensolaris.org 	 *	3-Mar-1999
3329*9860Sgdamore@opensolaris.org 	 */
3330*9860Sgdamore@opensolaris.org 
3331*9860Sgdamore@opensolaris.org 	switch (vi[SROM_VERSION]) {
3332*9860Sgdamore@opensolaris.org 	case 1:
3333*9860Sgdamore@opensolaris.org 	    /* fallthru */
3334*9860Sgdamore@opensolaris.org 	case 3:
3335*9860Sgdamore@opensolaris.org 		return (vi[SROM_MBZ] == 0 &&	/* must be zero */
3336*9860Sgdamore@opensolaris.org 		    vi[SROM_MBZ2] == 0 &&	/* must be zero */
3337*9860Sgdamore@opensolaris.org 		    vi[SROM_MBZ3] == 0);	/* must be zero */
3338*9860Sgdamore@opensolaris.org 
3339*9860Sgdamore@opensolaris.org 	case 4:
3340*9860Sgdamore@opensolaris.org 		wvi = (uint16_t *)vi;
3341*9860Sgdamore@opensolaris.org 		crc = 0xff;
3342*9860Sgdamore@opensolaris.org 		for (word = 0; word < 9; word++)
3343*9860Sgdamore@opensolaris.org 			for (bit = 15; bit >= 0; bit--) {
3344*9860Sgdamore@opensolaris.org 				if (word == 8 && bit == 7)
3345*9860Sgdamore@opensolaris.org 					return (crc == vi[16]);
3346*9860Sgdamore@opensolaris.org 				bitval =
3347*9860Sgdamore@opensolaris.org 				    ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1);
3348*9860Sgdamore@opensolaris.org 				crc <<= 1;
3349*9860Sgdamore@opensolaris.org 				if (bitval == 1) {
3350*9860Sgdamore@opensolaris.org 					crc ^= 7;
3351*9860Sgdamore@opensolaris.org 				}
3352*9860Sgdamore@opensolaris.org 			}
3353*9860Sgdamore@opensolaris.org 
3354*9860Sgdamore@opensolaris.org 	default:
3355*9860Sgdamore@opensolaris.org 		return (0);
3356*9860Sgdamore@opensolaris.org 	}
3357*9860Sgdamore@opensolaris.org }
3358*9860Sgdamore@opensolaris.org 
3359*9860Sgdamore@opensolaris.org /*
3360*9860Sgdamore@opensolaris.org  *	========== Active Media Determination Routines ==========
3361*9860Sgdamore@opensolaris.org  */
3362*9860Sgdamore@opensolaris.org 
3363*9860Sgdamore@opensolaris.org /* This routine is also called for V3 Compact and extended type 0 SROMs */
3364*9860Sgdamore@opensolaris.org static int
3365*9860Sgdamore@opensolaris.org is_fdmedia(int media)
3366*9860Sgdamore@opensolaris.org {
3367*9860Sgdamore@opensolaris.org 	if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD)
3368*9860Sgdamore@opensolaris.org 		return (1);
3369*9860Sgdamore@opensolaris.org 	else
3370*9860Sgdamore@opensolaris.org 		return (0);
3371*9860Sgdamore@opensolaris.org }
3372*9860Sgdamore@opensolaris.org 
3373*9860Sgdamore@opensolaris.org /*
3374*9860Sgdamore@opensolaris.org  * "Linkset" is used to merge media that use the same link test check. So,
3375*9860Sgdamore@opensolaris.org  * if the TP link is added to the linkset, so is the TP Full duplex link.
3376*9860Sgdamore@opensolaris.org  * Used to avoid checking the same link status twice.
3377*9860Sgdamore@opensolaris.org  */
3378*9860Sgdamore@opensolaris.org static void
3379*9860Sgdamore@opensolaris.org linkset_add(uint32_t *set, int media)
3380*9860Sgdamore@opensolaris.org {
3381*9860Sgdamore@opensolaris.org 	if (media == MEDIA_TP_FD || media == MEDIA_TP)
3382*9860Sgdamore@opensolaris.org 		*set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP);
3383*9860Sgdamore@opensolaris.org 	else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR)
3384*9860Sgdamore@opensolaris.org 		*set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR);
3385*9860Sgdamore@opensolaris.org 	else *set |= 1UL<<media;
3386*9860Sgdamore@opensolaris.org }
3387*9860Sgdamore@opensolaris.org static int
3388*9860Sgdamore@opensolaris.org linkset_isset(uint32_t linkset, int media)
3389*9860Sgdamore@opensolaris.org {
3390*9860Sgdamore@opensolaris.org 	return (((1UL<<media)  & linkset) ? 1:0);
3391*9860Sgdamore@opensolaris.org }
3392*9860Sgdamore@opensolaris.org 
3393*9860Sgdamore@opensolaris.org /*
3394*9860Sgdamore@opensolaris.org  * The following code detects which Media is connected for 21041/21140
3395*9860Sgdamore@opensolaris.org  * Expect to change this code to support new 21140 variants.
3396*9860Sgdamore@opensolaris.org  * find_active_media() - called with intrlock held.
3397*9860Sgdamore@opensolaris.org  */
3398*9860Sgdamore@opensolaris.org static void
3399*9860Sgdamore@opensolaris.org find_active_media(gld_mac_info_t *macinfo)
3400*9860Sgdamore@opensolaris.org {
3401*9860Sgdamore@opensolaris.org 	int i;
3402*9860Sgdamore@opensolaris.org 	media_block_t *block;
3403*9860Sgdamore@opensolaris.org 	media_block_t *best_allowed = NULL;
3404*9860Sgdamore@opensolaris.org 	media_block_t *hd_found = NULL;
3405*9860Sgdamore@opensolaris.org 	media_block_t *fd_found = NULL;
3406*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
3407*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
3408*9860Sgdamore@opensolaris.org 	LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
3409*9860Sgdamore@opensolaris.org 	uint32_t checked = 0, links_up = 0;
3410*9860Sgdamore@opensolaris.org 
3411*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3412*9860Sgdamore@opensolaris.org #ifdef SROMDEBUG
3413*9860Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "find_active_media 0x%x,0x%x", sr->version, macinfo);
3414*9860Sgdamore@opensolaris.org #endif
3415*9860Sgdamore@opensolaris.org 	dnetp->selected_media_block = leaf->default_block;
3416*9860Sgdamore@opensolaris.org 
3417*9860Sgdamore@opensolaris.org 	if (dnetp->phyaddr != -1) {
3418*9860Sgdamore@opensolaris.org 		dnetp->selected_media_block = leaf->mii_block;
3419*9860Sgdamore@opensolaris.org 		setup_block(macinfo);
3420*9860Sgdamore@opensolaris.org 
3421*9860Sgdamore@opensolaris.org 		if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3422*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, "portmon", 1)) {
3423*9860Sgdamore@opensolaris.org 			/* XXX return value ignored */
3424*9860Sgdamore@opensolaris.org 			(void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb,
3425*9860Sgdamore@opensolaris.org 			    &dnetp->intrlock);
3426*9860Sgdamore@opensolaris.org 			/*
3427*9860Sgdamore@opensolaris.org 			 * If the port monitor detects the link is already
3428*9860Sgdamore@opensolaris.org 			 * up, there is no point going through the rest of the
3429*9860Sgdamore@opensolaris.org 			 * link sense
3430*9860Sgdamore@opensolaris.org 			 */
3431*9860Sgdamore@opensolaris.org 			if (dnetp->mii_up) {
3432*9860Sgdamore@opensolaris.org 				return;
3433*9860Sgdamore@opensolaris.org 			}
3434*9860Sgdamore@opensolaris.org 		}
3435*9860Sgdamore@opensolaris.org 	}
3436*9860Sgdamore@opensolaris.org 
3437*9860Sgdamore@opensolaris.org 	/*
3438*9860Sgdamore@opensolaris.org 	 * Media is searched for in order of Precedence. This DEC SROM spec
3439*9860Sgdamore@opensolaris.org 	 * tells us that the first media entry in the SROM is the lowest
3440*9860Sgdamore@opensolaris.org 	 * precedence and should be checked last. This is why we go to the last
3441*9860Sgdamore@opensolaris.org 	 * Media block and work back to the beginning.
3442*9860Sgdamore@opensolaris.org 	 *
3443*9860Sgdamore@opensolaris.org 	 * However, some older SROMs (Cogent EM110's etc.) have this the wrong
3444*9860Sgdamore@opensolaris.org 	 * way around. As a result, following the SROM spec would result in a
3445*9860Sgdamore@opensolaris.org 	 * 10 link being chosen over a 100 link if both media are available.
3446*9860Sgdamore@opensolaris.org 	 * So we continue trying the media until we have at least tried the
3447*9860Sgdamore@opensolaris.org 	 * DEFAULT media.
3448*9860Sgdamore@opensolaris.org 	 */
3449*9860Sgdamore@opensolaris.org 
3450*9860Sgdamore@opensolaris.org 	/* Search for an active medium, and select it */
3451*9860Sgdamore@opensolaris.org 	for (block = leaf->block + leaf->block_count  - 1;
3452*9860Sgdamore@opensolaris.org 	    block >= leaf->block; block--) {
3453*9860Sgdamore@opensolaris.org 		int media = block->media_code;
3454*9860Sgdamore@opensolaris.org 
3455*9860Sgdamore@opensolaris.org 		/* User settings disallow selection of this block */
3456*9860Sgdamore@opensolaris.org 		if (dnetp->disallowed_media & (1UL<<media))
3457*9860Sgdamore@opensolaris.org 			continue;
3458*9860Sgdamore@opensolaris.org 
3459*9860Sgdamore@opensolaris.org 		/* We may not be able to pick the default */
3460*9860Sgdamore@opensolaris.org 		if (best_allowed == NULL || block == leaf->default_block)
3461*9860Sgdamore@opensolaris.org 			best_allowed = block;
3462*9860Sgdamore@opensolaris.org #ifdef DEBUG
3463*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETSENSE)
3464*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE, "Testing %s medium (block type %d)",
3465*9860Sgdamore@opensolaris.org 			    media_str[media], block->type);
3466*9860Sgdamore@opensolaris.org #endif
3467*9860Sgdamore@opensolaris.org 
3468*9860Sgdamore@opensolaris.org 		dnetp->selected_media_block = block;
3469*9860Sgdamore@opensolaris.org 		switch (block->type) {
3470*9860Sgdamore@opensolaris.org 
3471*9860Sgdamore@opensolaris.org 		case 2: /* SIA Media block: Best we can do is send a packet */
3472*9860Sgdamore@opensolaris.org 			setup_block(macinfo);
3473*9860Sgdamore@opensolaris.org 			if (send_test_packet(macinfo)) {
3474*9860Sgdamore@opensolaris.org 				if (!is_fdmedia(media))
3475*9860Sgdamore@opensolaris.org 					return;
3476*9860Sgdamore@opensolaris.org 				if (!fd_found)
3477*9860Sgdamore@opensolaris.org 					fd_found = block;
3478*9860Sgdamore@opensolaris.org 			}
3479*9860Sgdamore@opensolaris.org 			break;
3480*9860Sgdamore@opensolaris.org 
3481*9860Sgdamore@opensolaris.org 		/* SYM/SCR or TP block: Use the link-sense bits */
3482*9860Sgdamore@opensolaris.org 		case 0:
3483*9860Sgdamore@opensolaris.org 			if (!linkset_isset(checked, media)) {
3484*9860Sgdamore@opensolaris.org 				linkset_add(&checked, media);
3485*9860Sgdamore@opensolaris.org 				if (((media == MEDIA_BNC ||
3486*9860Sgdamore@opensolaris.org 				    media == MEDIA_AUI) &&
3487*9860Sgdamore@opensolaris.org 				    send_test_packet(macinfo)) ||
3488*9860Sgdamore@opensolaris.org 				    dnet_link_sense(macinfo))
3489*9860Sgdamore@opensolaris.org 					linkset_add(&links_up, media);
3490*9860Sgdamore@opensolaris.org 			}
3491*9860Sgdamore@opensolaris.org 
3492*9860Sgdamore@opensolaris.org 			if (linkset_isset(links_up, media)) {
3493*9860Sgdamore@opensolaris.org 				/*
3494*9860Sgdamore@opensolaris.org 				 * Half Duplex is *always* the favoured media.
3495*9860Sgdamore@opensolaris.org 				 * Full Duplex can be set and forced via the
3496*9860Sgdamore@opensolaris.org 				 * conf file.
3497*9860Sgdamore@opensolaris.org 				 */
3498*9860Sgdamore@opensolaris.org 				if (!is_fdmedia(media) &&
3499*9860Sgdamore@opensolaris.org 				    dnetp->selected_media_block ==
3500*9860Sgdamore@opensolaris.org 				    leaf->default_block) {
3501*9860Sgdamore@opensolaris.org 					/*
3502*9860Sgdamore@opensolaris.org 					 * Cogent cards have the media in
3503*9860Sgdamore@opensolaris.org 					 * opposite order to the spec.,
3504*9860Sgdamore@opensolaris.org 					 * this code forces the media test to
3505*9860Sgdamore@opensolaris.org 					 * keep going until the default media
3506*9860Sgdamore@opensolaris.org 					 * is tested.
3507*9860Sgdamore@opensolaris.org 					 *
3508*9860Sgdamore@opensolaris.org 					 * In Cogent case, 10, 10FD, 100FD, 100
3509*9860Sgdamore@opensolaris.org 					 * 100 is the default but 10 could have
3510*9860Sgdamore@opensolaris.org 					 * been detected and would have been
3511*9860Sgdamore@opensolaris.org 					 * chosen but now we force it through to
3512*9860Sgdamore@opensolaris.org 					 * 100.
3513*9860Sgdamore@opensolaris.org 					 */
3514*9860Sgdamore@opensolaris.org 					setup_block(macinfo);
3515*9860Sgdamore@opensolaris.org 					return;
3516*9860Sgdamore@opensolaris.org 				} else if (!is_fdmedia(media)) {
3517*9860Sgdamore@opensolaris.org 					/*
3518*9860Sgdamore@opensolaris.org 					 * This allows all the others to work
3519*9860Sgdamore@opensolaris.org 					 * properly by remembering the media
3520*9860Sgdamore@opensolaris.org 					 * that works and not defaulting to
3521*9860Sgdamore@opensolaris.org 					 * a FD link.
3522*9860Sgdamore@opensolaris.org 					 */
3523*9860Sgdamore@opensolaris.org 						if (hd_found == NULL)
3524*9860Sgdamore@opensolaris.org 							hd_found = block;
3525*9860Sgdamore@opensolaris.org 				} else if (fd_found == NULL) {
3526*9860Sgdamore@opensolaris.org 					/*
3527*9860Sgdamore@opensolaris.org 					 * No media have already been found
3528*9860Sgdamore@opensolaris.org 					 * so far, this is FD, it works so
3529*9860Sgdamore@opensolaris.org 					 * remember it and if no others are
3530*9860Sgdamore@opensolaris.org 					 * detected, use it.
3531*9860Sgdamore@opensolaris.org 					 */
3532*9860Sgdamore@opensolaris.org 					fd_found = block;
3533*9860Sgdamore@opensolaris.org 				}
3534*9860Sgdamore@opensolaris.org 			}
3535*9860Sgdamore@opensolaris.org 			break;
3536*9860Sgdamore@opensolaris.org 
3537*9860Sgdamore@opensolaris.org 		/*
3538*9860Sgdamore@opensolaris.org 		 * MII block: May take up to a second or so to settle if
3539*9860Sgdamore@opensolaris.org 		 * setup causes a PHY reset
3540*9860Sgdamore@opensolaris.org 		 */
3541*9860Sgdamore@opensolaris.org 		case 1: case 3:
3542*9860Sgdamore@opensolaris.org 			setup_block(macinfo);
3543*9860Sgdamore@opensolaris.org 			for (i = 0; ; i++) {
3544*9860Sgdamore@opensolaris.org 				if (mii_linkup(dnetp->mii, dnetp->phyaddr)) {
3545*9860Sgdamore@opensolaris.org 					/* XXX function return value ignored */
3546*9860Sgdamore@opensolaris.org 					(void) mii_getspeed(dnetp->mii,
3547*9860Sgdamore@opensolaris.org 					    dnetp->phyaddr,
3548*9860Sgdamore@opensolaris.org 					    &dnetp->mii_speed,
3549*9860Sgdamore@opensolaris.org 					    &dnetp->mii_duplex);
3550*9860Sgdamore@opensolaris.org 					dnetp->mii_up = 1;
3551*9860Sgdamore@opensolaris.org 					leaf->mii_block = block;
3552*9860Sgdamore@opensolaris.org 					return;
3553*9860Sgdamore@opensolaris.org 				}
3554*9860Sgdamore@opensolaris.org 				if (i == 10)
3555*9860Sgdamore@opensolaris.org 					break;
3556*9860Sgdamore@opensolaris.org 				delay(drv_usectohz(150000));
3557*9860Sgdamore@opensolaris.org 			}
3558*9860Sgdamore@opensolaris.org 			dnetp->mii_up = 0;
3559*9860Sgdamore@opensolaris.org 			break;
3560*9860Sgdamore@opensolaris.org 		}
3561*9860Sgdamore@opensolaris.org 	} /* for loop */
3562*9860Sgdamore@opensolaris.org 	if (hd_found) {
3563*9860Sgdamore@opensolaris.org 		dnetp->selected_media_block = hd_found;
3564*9860Sgdamore@opensolaris.org 	} else if (fd_found) {
3565*9860Sgdamore@opensolaris.org 		dnetp->selected_media_block = fd_found;
3566*9860Sgdamore@opensolaris.org 	} else {
3567*9860Sgdamore@opensolaris.org 		if (best_allowed == NULL)
3568*9860Sgdamore@opensolaris.org 			best_allowed = leaf->default_block;
3569*9860Sgdamore@opensolaris.org 		dnetp->selected_media_block = best_allowed;
3570*9860Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "!dnet: Default media selected\n");
3571*9860Sgdamore@opensolaris.org 	}
3572*9860Sgdamore@opensolaris.org 	setup_block(macinfo);
3573*9860Sgdamore@opensolaris.org }
3574*9860Sgdamore@opensolaris.org 
3575*9860Sgdamore@opensolaris.org /*
3576*9860Sgdamore@opensolaris.org  * Do anything neccessary to select the selected_media_block.
3577*9860Sgdamore@opensolaris.org  * setup_block() - called with intrlock held.
3578*9860Sgdamore@opensolaris.org  */
3579*9860Sgdamore@opensolaris.org static void
3580*9860Sgdamore@opensolaris.org setup_block(gld_mac_info_t *macinfo)
3581*9860Sgdamore@opensolaris.org {
3582*9860Sgdamore@opensolaris.org 	dnet_reset_board(macinfo);
3583*9860Sgdamore@opensolaris.org 	dnet_init_board(macinfo);
3584*9860Sgdamore@opensolaris.org 	/* XXX function return value ignored */
3585*9860Sgdamore@opensolaris.org 	(void) dnet_start(macinfo);
3586*9860Sgdamore@opensolaris.org }
3587*9860Sgdamore@opensolaris.org 
3588*9860Sgdamore@opensolaris.org /* dnet_link_sense() - called with intrlock held */
3589*9860Sgdamore@opensolaris.org static int
3590*9860Sgdamore@opensolaris.org dnet_link_sense(gld_mac_info_t *macinfo)
3591*9860Sgdamore@opensolaris.org {
3592*9860Sgdamore@opensolaris.org 	/*
3593*9860Sgdamore@opensolaris.org 	 * This routine makes use of the command word from the srom config.
3594*9860Sgdamore@opensolaris.org 	 * Details of the auto-sensing information contained in this can
3595*9860Sgdamore@opensolaris.org 	 * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03"
3596*9860Sgdamore@opensolaris.org 	 * spec. Section 4.3.2.1, and 4.5.2.1.3
3597*9860Sgdamore@opensolaris.org 	 */
3598*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp = (struct dnetinstance *)
3599*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
3600*9860Sgdamore@opensolaris.org 	media_block_t *block = dnetp->selected_media_block;
3601*9860Sgdamore@opensolaris.org 	uint32_t link, status, mask, polarity;
3602*9860Sgdamore@opensolaris.org 	int settletime, stabletime, waittime, upsamples;
3603*9860Sgdamore@opensolaris.org 	int delay_100, delay_10;
3604*9860Sgdamore@opensolaris.org 
3605*9860Sgdamore@opensolaris.org 
3606*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3607*9860Sgdamore@opensolaris.org 	/* Don't autosense if the medium does not support it */
3608*9860Sgdamore@opensolaris.org 	if (block->command & (1 << 15)) {
3609*9860Sgdamore@opensolaris.org 		/* This should be the default block */
3610*9860Sgdamore@opensolaris.org 		if (block->command & (1UL<<14))
3611*9860Sgdamore@opensolaris.org 			dnetp->sr.leaf[dnetp->leaf].default_block = block;
3612*9860Sgdamore@opensolaris.org 		return (0);
3613*9860Sgdamore@opensolaris.org 	}
3614*9860Sgdamore@opensolaris.org 
3615*9860Sgdamore@opensolaris.org 	delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3616*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, "autosense-delay-100", 2000);
3617*9860Sgdamore@opensolaris.org 
3618*9860Sgdamore@opensolaris.org 	delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3619*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, "autosense-delay-10", 400);
3620*9860Sgdamore@opensolaris.org 
3621*9860Sgdamore@opensolaris.org 	/*
3622*9860Sgdamore@opensolaris.org 	 * Scrambler may need to be disabled for link sensing
3623*9860Sgdamore@opensolaris.org 	 * to work
3624*9860Sgdamore@opensolaris.org 	 */
3625*9860Sgdamore@opensolaris.org 	dnetp->disable_scrambler = 1;
3626*9860Sgdamore@opensolaris.org 	setup_block(macinfo);
3627*9860Sgdamore@opensolaris.org 	dnetp->disable_scrambler = 0;
3628*9860Sgdamore@opensolaris.org 
3629*9860Sgdamore@opensolaris.org 	if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD)
3630*9860Sgdamore@opensolaris.org 		settletime = delay_10;
3631*9860Sgdamore@opensolaris.org 	else
3632*9860Sgdamore@opensolaris.org 		settletime = delay_100;
3633*9860Sgdamore@opensolaris.org 	stabletime = settletime / 4;
3634*9860Sgdamore@opensolaris.org 
3635*9860Sgdamore@opensolaris.org 	mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1);
3636*9860Sgdamore@opensolaris.org 	polarity = block->command & CMD_POL ? 0xffffffff : 0;
3637*9860Sgdamore@opensolaris.org 
3638*9860Sgdamore@opensolaris.org 	for (waittime = 0, upsamples = 0;
3639*9860Sgdamore@opensolaris.org 	    waittime <= settletime + stabletime && upsamples < 8;
3640*9860Sgdamore@opensolaris.org 	    waittime += stabletime/8) {
3641*9860Sgdamore@opensolaris.org 		delay(drv_usectohz(stabletime*1000 / 8));
3642*9860Sgdamore@opensolaris.org 		status = read_gpr(dnetp);
3643*9860Sgdamore@opensolaris.org 		link = (status^polarity) & mask;
3644*9860Sgdamore@opensolaris.org 		if (link)
3645*9860Sgdamore@opensolaris.org 			upsamples++;
3646*9860Sgdamore@opensolaris.org 		else
3647*9860Sgdamore@opensolaris.org 			upsamples = 0;
3648*9860Sgdamore@opensolaris.org 	}
3649*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
3650*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETSENSE)
3651*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x "
3652*9860Sgdamore@opensolaris.org 		    "mask:%x link:%x",
3653*9860Sgdamore@opensolaris.org 		    upsamples == 8 ? "UP":"DOWN",
3654*9860Sgdamore@opensolaris.org 		    upsamples, status, polarity, mask, link);
3655*9860Sgdamore@opensolaris.org #endif
3656*9860Sgdamore@opensolaris.org 	if (upsamples == 8)
3657*9860Sgdamore@opensolaris.org 		return (1);
3658*9860Sgdamore@opensolaris.org 	return (0);
3659*9860Sgdamore@opensolaris.org }
3660*9860Sgdamore@opensolaris.org 
3661*9860Sgdamore@opensolaris.org static int
3662*9860Sgdamore@opensolaris.org send_test_packet(gld_mac_info_t *macinfo)
3663*9860Sgdamore@opensolaris.org {
3664*9860Sgdamore@opensolaris.org 	int packet_delay;
3665*9860Sgdamore@opensolaris.org 	struct dnetinstance	*dnetp = (struct dnetinstance *)
3666*9860Sgdamore@opensolaris.org 	    (macinfo->gldm_private);
3667*9860Sgdamore@opensolaris.org 	struct tx_desc_type *desc;
3668*9860Sgdamore@opensolaris.org 	int bufindex;
3669*9860Sgdamore@opensolaris.org 	int media_code = dnetp->selected_media_block->media_code;
3670*9860Sgdamore@opensolaris.org 	uint32_t del;
3671*9860Sgdamore@opensolaris.org 
3672*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3673*9860Sgdamore@opensolaris.org 	/*
3674*9860Sgdamore@opensolaris.org 	 * For a successful test packet, the card must have settled into
3675*9860Sgdamore@opensolaris.org 	 * its current setting.  Almost all cards we've tested manage to
3676*9860Sgdamore@opensolaris.org 	 * do this with all media within 50ms.  However, the SMC 8432
3677*9860Sgdamore@opensolaris.org 	 * requires 300ms to settle into BNC mode.  We now only do this
3678*9860Sgdamore@opensolaris.org 	 * from attach, and we do sleeping delay() instead of drv_usecwait()
3679*9860Sgdamore@opensolaris.org 	 * so we hope this .2 second delay won't cause too much suffering.
3680*9860Sgdamore@opensolaris.org 	 * ALSO: with an autonegotiating hub, an aditional 1 second delay is
3681*9860Sgdamore@opensolaris.org 	 * required. This is done if the media type is TP
3682*9860Sgdamore@opensolaris.org 	 */
3683*9860Sgdamore@opensolaris.org 	if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) {
3684*9860Sgdamore@opensolaris.org 		packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3685*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000);
3686*9860Sgdamore@opensolaris.org 	} else {
3687*9860Sgdamore@opensolaris.org 		packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3688*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, "test_packet_delay", 300000);
3689*9860Sgdamore@opensolaris.org 	}
3690*9860Sgdamore@opensolaris.org 	delay(drv_usectohz(packet_delay));
3691*9860Sgdamore@opensolaris.org 
3692*9860Sgdamore@opensolaris.org 	desc = dnetp->tx_desc;
3693*9860Sgdamore@opensolaris.org 
3694*9860Sgdamore@opensolaris.org 	bufindex = dnetp->tx_current_desc;
3695*9860Sgdamore@opensolaris.org 	if (alloc_descriptor(macinfo) == FAILURE) {
3696*9860Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor"
3697*9860Sgdamore@opensolaris.org 		    "failed");
3698*9860Sgdamore@opensolaris.org 		return (0);
3699*9860Sgdamore@opensolaris.org 	}
3700*9860Sgdamore@opensolaris.org 
3701*9860Sgdamore@opensolaris.org 	/*
3702*9860Sgdamore@opensolaris.org 	 * use setup buffer as the buffer for the test packet
3703*9860Sgdamore@opensolaris.org 	 * instead of allocating one.
3704*9860Sgdamore@opensolaris.org 	 */
3705*9860Sgdamore@opensolaris.org 
3706*9860Sgdamore@opensolaris.org 	ASSERT(dnetp->setup_buf_vaddr != NULL);
3707*9860Sgdamore@opensolaris.org 	/* Put something decent in dest address so we don't annoy other cards */
3708*9860Sgdamore@opensolaris.org 	BCOPY((caddr_t)dnetp->curr_macaddr,
3709*9860Sgdamore@opensolaris.org 	    (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL);
3710*9860Sgdamore@opensolaris.org 	BCOPY((caddr_t)dnetp->curr_macaddr,
3711*9860Sgdamore@opensolaris.org 	    (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL);
3712*9860Sgdamore@opensolaris.org 
3713*9860Sgdamore@opensolaris.org 	desc[bufindex].buffer1 = dnetp->setup_buf_paddr;
3714*9860Sgdamore@opensolaris.org 	desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE;
3715*9860Sgdamore@opensolaris.org 	desc[bufindex].buffer2 = (uint32_t)(0);
3716*9860Sgdamore@opensolaris.org 	desc[bufindex].desc1.first_desc = 1;
3717*9860Sgdamore@opensolaris.org 	desc[bufindex].desc1.last_desc = 1;
3718*9860Sgdamore@opensolaris.org 	desc[bufindex].desc1.int_on_comp = 1;
3719*9860Sgdamore@opensolaris.org 	desc[bufindex].desc0.own = 1;
3720*9860Sgdamore@opensolaris.org 
3721*9860Sgdamore@opensolaris.org 	ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
3722*9860Sgdamore@opensolaris.org 	    TX_POLL_DEMAND);
3723*9860Sgdamore@opensolaris.org 
3724*9860Sgdamore@opensolaris.org 	/*
3725*9860Sgdamore@opensolaris.org 	 * Give enough time for the chip to transmit the packet
3726*9860Sgdamore@opensolaris.org 	 */
3727*9860Sgdamore@opensolaris.org #if 1
3728*9860Sgdamore@opensolaris.org 	del = 1000;
3729*9860Sgdamore@opensolaris.org 	while (desc[bufindex].desc0.own && --del)
3730*9860Sgdamore@opensolaris.org 		drv_usecwait(10);	/* quickly wait up to 10ms */
3731*9860Sgdamore@opensolaris.org 	if (desc[bufindex].desc0.own)
3732*9860Sgdamore@opensolaris.org 		delay(drv_usectohz(200000));	/* nicely wait a longer time */
3733*9860Sgdamore@opensolaris.org #else
3734*9860Sgdamore@opensolaris.org 	del = 0x10000;
3735*9860Sgdamore@opensolaris.org 	while (desc[bufindex].desc0.own && --del)
3736*9860Sgdamore@opensolaris.org 		drv_usecwait(10);
3737*9860Sgdamore@opensolaris.org #endif
3738*9860Sgdamore@opensolaris.org 
3739*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
3740*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETSENSE)
3741*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u",
3742*9860Sgdamore@opensolaris.org 		    desc[bufindex].desc0.own,
3743*9860Sgdamore@opensolaris.org 		    desc[bufindex].desc0.err_summary,
3744*9860Sgdamore@opensolaris.org 		    desc[bufindex].desc0.carrier_loss,
3745*9860Sgdamore@opensolaris.org 		    desc[bufindex].desc0.no_carrier,
3746*9860Sgdamore@opensolaris.org 		    desc[bufindex].desc0.late_collision,
3747*9860Sgdamore@opensolaris.org 		    desc[bufindex].desc0.link_fail);
3748*9860Sgdamore@opensolaris.org #endif
3749*9860Sgdamore@opensolaris.org 	if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */
3750*9860Sgdamore@opensolaris.org 		return (0);
3751*9860Sgdamore@opensolaris.org 
3752*9860Sgdamore@opensolaris.org 	return (!desc[bufindex].desc0.err_summary);
3753*9860Sgdamore@opensolaris.org }
3754*9860Sgdamore@opensolaris.org 
3755*9860Sgdamore@opensolaris.org /* enable_interrupts - called with intrlock held */
3756*9860Sgdamore@opensolaris.org static void
3757*9860Sgdamore@opensolaris.org enable_interrupts(struct dnetinstance *dnetp, int enable_xmit)
3758*9860Sgdamore@opensolaris.org {
3759*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3760*9860Sgdamore@opensolaris.org 	/* Don't enable interrupts if they have been forced off */
3761*9860Sgdamore@opensolaris.org 	if (dnetp->interrupts_disabled)
3762*9860Sgdamore@opensolaris.org 		return;
3763*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG),
3764*9860Sgdamore@opensolaris.org 	    NORMAL_INTR_MASK | ABNORMAL_INTR_MASK | TX_UNDERFLOW_MASK |
3765*9860Sgdamore@opensolaris.org 	    (enable_xmit ? TX_INTERRUPT_MASK : 0) |
3766*9860Sgdamore@opensolaris.org 	    (dnetp->timer.cb ? GPTIMER_INTR : 0) |
3767*9860Sgdamore@opensolaris.org 	    RX_INTERRUPT_MASK | SYSTEM_ERROR_MASK | TX_JABBER_MASK);
3768*9860Sgdamore@opensolaris.org 
3769*9860Sgdamore@opensolaris.org }
3770*9860Sgdamore@opensolaris.org 
3771*9860Sgdamore@opensolaris.org /*
3772*9860Sgdamore@opensolaris.org  * Some older multiport cards are non-PCI compliant in their interrupt routing.
3773*9860Sgdamore@opensolaris.org  * Second and subsequent devices are incorrectly configured by the BIOS
3774*9860Sgdamore@opensolaris.org  * (either in their ILINE configuration or the MP Configuration Table for PC+MP
3775*9860Sgdamore@opensolaris.org  * systems).
3776*9860Sgdamore@opensolaris.org  * The hack stops gldregister() registering the interrupt routine for the
3777*9860Sgdamore@opensolaris.org  * FIRST device on the adapter, and registers its own. It builds up a table
3778*9860Sgdamore@opensolaris.org  * of macinfo structures for each device, and the new interrupt routine
3779*9860Sgdamore@opensolaris.org  * calls gldintr for each of them.
3780*9860Sgdamore@opensolaris.org  * Known cards that suffer from this problem are:
3781*9860Sgdamore@opensolaris.org  *	All Cogent multiport cards;
3782*9860Sgdamore@opensolaris.org  * 	Znyx 314;
3783*9860Sgdamore@opensolaris.org  *	Znyx 315.
3784*9860Sgdamore@opensolaris.org  *
3785*9860Sgdamore@opensolaris.org  * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This
3786*9860Sgdamore@opensolaris.org  * hack relies on the fact that the offending cards will have only one SROM.
3787*9860Sgdamore@opensolaris.org  * It uses this fact to identify devices that are on the same multiport
3788*9860Sgdamore@opensolaris.org  * adapter, as opposed to multiple devices from the same vendor (as
3789*9860Sgdamore@opensolaris.org  * indicated by "secondary")
3790*9860Sgdamore@opensolaris.org  */
3791*9860Sgdamore@opensolaris.org static int
3792*9860Sgdamore@opensolaris.org dnet_hack_interrupts(gld_mac_info_t *macinfo, int secondary)
3793*9860Sgdamore@opensolaris.org {
3794*9860Sgdamore@opensolaris.org 	int i;
3795*9860Sgdamore@opensolaris.org 	struct hackintr_inf *hackintr_inf;
3796*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =
3797*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
3798*9860Sgdamore@opensolaris.org 	dev_info_t *devinfo = dnetp->devinfo;
3799*9860Sgdamore@opensolaris.org 	uint32_t oui = 0;	/* Organizationally Unique ID */
3800*9860Sgdamore@opensolaris.org 
3801*9860Sgdamore@opensolaris.org 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3802*9860Sgdamore@opensolaris.org 	    "no_INTA_workaround", 0) != 0)
3803*9860Sgdamore@opensolaris.org 		return (0);
3804*9860Sgdamore@opensolaris.org 
3805*9860Sgdamore@opensolaris.org 	for (i = 0; i < 3; i++)
3806*9860Sgdamore@opensolaris.org 		oui = (oui << 8) | dnetp->vendor_addr[i];
3807*9860Sgdamore@opensolaris.org 
3808*9860Sgdamore@opensolaris.org 	/* Check wheather or not we need to implement the hack */
3809*9860Sgdamore@opensolaris.org 
3810*9860Sgdamore@opensolaris.org 	switch (oui) {
3811*9860Sgdamore@opensolaris.org 	case ZNYX_ETHER:
3812*9860Sgdamore@opensolaris.org 		/* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */
3813*9860Sgdamore@opensolaris.org 		if (dnetp->board_type != DEVICE_ID_21040)
3814*9860Sgdamore@opensolaris.org 			return (0);
3815*9860Sgdamore@opensolaris.org 		break;
3816*9860Sgdamore@opensolaris.org 
3817*9860Sgdamore@opensolaris.org 	case COGENT_ETHER:
3818*9860Sgdamore@opensolaris.org 		/* All known Cogent multiport cards */
3819*9860Sgdamore@opensolaris.org 		break;
3820*9860Sgdamore@opensolaris.org 
3821*9860Sgdamore@opensolaris.org 	case ADAPTEC_ETHER:
3822*9860Sgdamore@opensolaris.org 		/* Adaptec multiport cards */
3823*9860Sgdamore@opensolaris.org 		break;
3824*9860Sgdamore@opensolaris.org 
3825*9860Sgdamore@opensolaris.org 	default:
3826*9860Sgdamore@opensolaris.org 		/* Other cards work correctly */
3827*9860Sgdamore@opensolaris.org 		return (0);
3828*9860Sgdamore@opensolaris.org 	}
3829*9860Sgdamore@opensolaris.org 
3830*9860Sgdamore@opensolaris.org 	/* card is (probably) non-PCI compliant in its interrupt routing */
3831*9860Sgdamore@opensolaris.org 
3832*9860Sgdamore@opensolaris.org 
3833*9860Sgdamore@opensolaris.org 	if (!secondary) {
3834*9860Sgdamore@opensolaris.org 
3835*9860Sgdamore@opensolaris.org 		/*
3836*9860Sgdamore@opensolaris.org 		 * If we have already registered a hacked interrupt, and
3837*9860Sgdamore@opensolaris.org 		 * this is also a 'primary' adapter, then this is NOT part of
3838*9860Sgdamore@opensolaris.org 		 * a multiport card, but a second card on the same PCI bus.
3839*9860Sgdamore@opensolaris.org 		 * BUGID: 4057747
3840*9860Sgdamore@opensolaris.org 		 */
3841*9860Sgdamore@opensolaris.org 		if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3842*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, hackintr_propname, 0) != 0)
3843*9860Sgdamore@opensolaris.org 			return (0);
3844*9860Sgdamore@opensolaris.org 				/* ... Primary not part of a multiport device */
3845*9860Sgdamore@opensolaris.org 
3846*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
3847*9860Sgdamore@opensolaris.org 		if (dnetdebug & DNETTRACE)
3848*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE, "dnet: Implementing hardware "
3849*9860Sgdamore@opensolaris.org 			    "interrupt flaw workaround");
3850*9860Sgdamore@opensolaris.org #endif
3851*9860Sgdamore@opensolaris.org 		dnetp->hackintr_inf = hackintr_inf =
3852*9860Sgdamore@opensolaris.org 		    kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP);
3853*9860Sgdamore@opensolaris.org 		if (hackintr_inf == NULL)
3854*9860Sgdamore@opensolaris.org 			goto fail;
3855*9860Sgdamore@opensolaris.org 
3856*9860Sgdamore@opensolaris.org 		hackintr_inf->macinfos[0] = macinfo;
3857*9860Sgdamore@opensolaris.org 		hackintr_inf->devinfo = devinfo;
3858*9860Sgdamore@opensolaris.org 
3859*9860Sgdamore@opensolaris.org 		/*
3860*9860Sgdamore@opensolaris.org 		 * Add a property to allow successive attaches to find the
3861*9860Sgdamore@opensolaris.org 		 * table
3862*9860Sgdamore@opensolaris.org 		 */
3863*9860Sgdamore@opensolaris.org 
3864*9860Sgdamore@opensolaris.org 		if (ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3865*9860Sgdamore@opensolaris.org 		    ddi_get_parent(devinfo), hackintr_propname,
3866*9860Sgdamore@opensolaris.org 		    (uchar_t *)&dnetp->hackintr_inf,
3867*9860Sgdamore@opensolaris.org 		    sizeof (void *)) != DDI_PROP_SUCCESS)
3868*9860Sgdamore@opensolaris.org 			goto fail;
3869*9860Sgdamore@opensolaris.org 
3870*9860Sgdamore@opensolaris.org 
3871*9860Sgdamore@opensolaris.org 		/* Register our hacked interrupt routine */
3872*9860Sgdamore@opensolaris.org 		if (ddi_add_intr(devinfo, 0, &macinfo->gldm_cookie, NULL,
3873*9860Sgdamore@opensolaris.org 		    (uint_t (*)(char *))dnet_hack_intr,
3874*9860Sgdamore@opensolaris.org 		    (caddr_t)hackintr_inf) != DDI_SUCCESS) {
3875*9860Sgdamore@opensolaris.org 			/* XXX function return value ignored */
3876*9860Sgdamore@opensolaris.org 			(void) ddi_prop_remove(DDI_DEV_T_NONE,
3877*9860Sgdamore@opensolaris.org 			    ddi_get_parent(devinfo),
3878*9860Sgdamore@opensolaris.org 			    hackintr_propname);
3879*9860Sgdamore@opensolaris.org 			goto fail;
3880*9860Sgdamore@opensolaris.org 		}
3881*9860Sgdamore@opensolaris.org 
3882*9860Sgdamore@opensolaris.org 		/*
3883*9860Sgdamore@opensolaris.org 		 * Mutex required to ensure interrupt routine has completed
3884*9860Sgdamore@opensolaris.org 		 * when detaching devices
3885*9860Sgdamore@opensolaris.org 		 */
3886*9860Sgdamore@opensolaris.org 		mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER,
3887*9860Sgdamore@opensolaris.org 		    macinfo->gldm_cookie);
3888*9860Sgdamore@opensolaris.org 
3889*9860Sgdamore@opensolaris.org 		/* Stop GLD registering an interrupt */
3890*9860Sgdamore@opensolaris.org 		return (-1);
3891*9860Sgdamore@opensolaris.org 	} else {
3892*9860Sgdamore@opensolaris.org 
3893*9860Sgdamore@opensolaris.org 		/* Add the macinfo for this secondary device to the table */
3894*9860Sgdamore@opensolaris.org 
3895*9860Sgdamore@opensolaris.org 		hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3896*9860Sgdamore@opensolaris.org 		    ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3897*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, hackintr_propname, 0);
3898*9860Sgdamore@opensolaris.org 
3899*9860Sgdamore@opensolaris.org 		if (hackintr_inf == NULL)
3900*9860Sgdamore@opensolaris.org 			goto fail;
3901*9860Sgdamore@opensolaris.org 
3902*9860Sgdamore@opensolaris.org 		/* Find an empty slot */
3903*9860Sgdamore@opensolaris.org 		for (i = 0; i < MAX_INST; i++)
3904*9860Sgdamore@opensolaris.org 			if (hackintr_inf->macinfos[i] == NULL)
3905*9860Sgdamore@opensolaris.org 				break;
3906*9860Sgdamore@opensolaris.org 
3907*9860Sgdamore@opensolaris.org 		/* More than 8 ports on adapter ?! */
3908*9860Sgdamore@opensolaris.org 		if (i == MAX_INST)
3909*9860Sgdamore@opensolaris.org 			goto fail;
3910*9860Sgdamore@opensolaris.org 
3911*9860Sgdamore@opensolaris.org 		hackintr_inf->macinfos[i] = macinfo;
3912*9860Sgdamore@opensolaris.org 
3913*9860Sgdamore@opensolaris.org 		/*
3914*9860Sgdamore@opensolaris.org 		 * Allow GLD to register a handler for this
3915*9860Sgdamore@opensolaris.org 		 * device. If the card is actually broken, as we suspect, this
3916*9860Sgdamore@opensolaris.org 		 * handler will never get called. However, by registering the
3917*9860Sgdamore@opensolaris.org 		 * interrupt handler, we can copy gracefully with new multiport
3918*9860Sgdamore@opensolaris.org 		 * Cogent cards that decide to fix the hardware problem
3919*9860Sgdamore@opensolaris.org 		 */
3920*9860Sgdamore@opensolaris.org 		return (0);
3921*9860Sgdamore@opensolaris.org 	}
3922*9860Sgdamore@opensolaris.org 
3923*9860Sgdamore@opensolaris.org fail:
3924*9860Sgdamore@opensolaris.org 	cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt"
3925*9860Sgdamore@opensolaris.org 	    " routing problem");
3926*9860Sgdamore@opensolaris.org 	return (0);
3927*9860Sgdamore@opensolaris.org }
3928*9860Sgdamore@opensolaris.org 
3929*9860Sgdamore@opensolaris.org /*
3930*9860Sgdamore@opensolaris.org  * Call gld_intr for all adapters on a multiport card
3931*9860Sgdamore@opensolaris.org  */
3932*9860Sgdamore@opensolaris.org 
3933*9860Sgdamore@opensolaris.org static uint_t
3934*9860Sgdamore@opensolaris.org dnet_hack_intr(struct hackintr_inf *hackintr_inf)
3935*9860Sgdamore@opensolaris.org {
3936*9860Sgdamore@opensolaris.org 	int i;
3937*9860Sgdamore@opensolaris.org 	int claimed = DDI_INTR_UNCLAIMED;
3938*9860Sgdamore@opensolaris.org 
3939*9860Sgdamore@opensolaris.org 	/* Stop detaches while processing interrupts */
3940*9860Sgdamore@opensolaris.org 	mutex_enter(&hackintr_inf->lock);
3941*9860Sgdamore@opensolaris.org 
3942*9860Sgdamore@opensolaris.org 	for (i = 0; i < MAX_INST; i++) {
3943*9860Sgdamore@opensolaris.org 		if (hackintr_inf->macinfos[i] &&
3944*9860Sgdamore@opensolaris.org 		    gld_intr(hackintr_inf->macinfos[i]) == DDI_INTR_CLAIMED)
3945*9860Sgdamore@opensolaris.org 			claimed = DDI_INTR_CLAIMED;
3946*9860Sgdamore@opensolaris.org 	}
3947*9860Sgdamore@opensolaris.org 	mutex_exit(&hackintr_inf->lock);
3948*9860Sgdamore@opensolaris.org 	return (claimed);
3949*9860Sgdamore@opensolaris.org }
3950*9860Sgdamore@opensolaris.org 
3951*9860Sgdamore@opensolaris.org /*
3952*9860Sgdamore@opensolaris.org  * This removes the detaching device from the table procesed by the hacked
3953*9860Sgdamore@opensolaris.org  * interrupt routine. Because the interrupts from all devices come in to the
3954*9860Sgdamore@opensolaris.org  * same interrupt handler, ALL devices must stop interrupting once the
3955*9860Sgdamore@opensolaris.org  * primary device detaches. This isn't a problem at present, because all
3956*9860Sgdamore@opensolaris.org  * instances of a device are detached when the driver is unloaded.
3957*9860Sgdamore@opensolaris.org  */
3958*9860Sgdamore@opensolaris.org static int
3959*9860Sgdamore@opensolaris.org dnet_detach_hacked_interrupt(dev_info_t *devinfo)
3960*9860Sgdamore@opensolaris.org {
3961*9860Sgdamore@opensolaris.org 	int i;
3962*9860Sgdamore@opensolaris.org 	struct hackintr_inf *hackintr_inf;
3963*9860Sgdamore@opensolaris.org 	gld_mac_info_t *mac, *macinfo = ddi_get_driver_private(devinfo);
3964*9860Sgdamore@opensolaris.org 
3965*9860Sgdamore@opensolaris.org 	hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3966*9860Sgdamore@opensolaris.org 	    ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3967*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, hackintr_propname, 0);
3968*9860Sgdamore@opensolaris.org 
3969*9860Sgdamore@opensolaris.org 	/*
3970*9860Sgdamore@opensolaris.org 	 * No hackintr_inf implies hack was not required or the primary has
3971*9860Sgdamore@opensolaris.org 	 * detached, and our interrupts are already disabled
3972*9860Sgdamore@opensolaris.org 	 */
3973*9860Sgdamore@opensolaris.org 	if (!hackintr_inf) {
3974*9860Sgdamore@opensolaris.org 		/* remove the interrupt for the non-hacked case */
3975*9860Sgdamore@opensolaris.org 		ddi_remove_intr(devinfo, 0, macinfo->gldm_cookie);
3976*9860Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
3977*9860Sgdamore@opensolaris.org 	}
3978*9860Sgdamore@opensolaris.org 
3979*9860Sgdamore@opensolaris.org 	/* Remove this device from the handled table */
3980*9860Sgdamore@opensolaris.org 	mutex_enter(&hackintr_inf->lock);
3981*9860Sgdamore@opensolaris.org 	for (i = 0; i < MAX_INST; i++) {
3982*9860Sgdamore@opensolaris.org 		if (hackintr_inf->macinfos[i] == macinfo) {
3983*9860Sgdamore@opensolaris.org 			hackintr_inf->macinfos[i] = NULL;
3984*9860Sgdamore@opensolaris.org 			break;
3985*9860Sgdamore@opensolaris.org 		}
3986*9860Sgdamore@opensolaris.org 	}
3987*9860Sgdamore@opensolaris.org 
3988*9860Sgdamore@opensolaris.org 	mutex_exit(&hackintr_inf->lock);
3989*9860Sgdamore@opensolaris.org 
3990*9860Sgdamore@opensolaris.org 	/* Not the primary card, we are done */
3991*9860Sgdamore@opensolaris.org 	if (devinfo != hackintr_inf->devinfo)
3992*9860Sgdamore@opensolaris.org 		return (DDI_SUCCESS);
3993*9860Sgdamore@opensolaris.org 
3994*9860Sgdamore@opensolaris.org 	/*
3995*9860Sgdamore@opensolaris.org 	 * This is the primary card. All remaining adapters on this device
3996*9860Sgdamore@opensolaris.org 	 * must have their interrupts disabled before we remove the handler
3997*9860Sgdamore@opensolaris.org 	 */
3998*9860Sgdamore@opensolaris.org 	for (i = 0; i < MAX_INST; i++) {
3999*9860Sgdamore@opensolaris.org 		if ((mac = hackintr_inf->macinfos[i]) != NULL) {
4000*9860Sgdamore@opensolaris.org 			struct dnetinstance *altdnetp =
4001*9860Sgdamore@opensolaris.org 			    (struct dnetinstance *)mac->gldm_private;
4002*9860Sgdamore@opensolaris.org 			altdnetp->interrupts_disabled = 1;
4003*9860Sgdamore@opensolaris.org 			ddi_put32(altdnetp->io_handle,
4004*9860Sgdamore@opensolaris.org 			    REG32(altdnetp->io_reg, INT_MASK_REG), 0);
4005*9860Sgdamore@opensolaris.org 		}
4006*9860Sgdamore@opensolaris.org 	}
4007*9860Sgdamore@opensolaris.org 
4008*9860Sgdamore@opensolaris.org 	/* It should now be safe to remove the interrupt handler */
4009*9860Sgdamore@opensolaris.org 
4010*9860Sgdamore@opensolaris.org 	ddi_remove_intr(devinfo, 0, macinfo->gldm_cookie);
4011*9860Sgdamore@opensolaris.org 	mutex_destroy(&hackintr_inf->lock);
4012*9860Sgdamore@opensolaris.org 	/* XXX function return value ignored */
4013*9860Sgdamore@opensolaris.org 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
4014*9860Sgdamore@opensolaris.org 	    hackintr_propname);
4015*9860Sgdamore@opensolaris.org 	kmem_free(hackintr_inf, sizeof (struct hackintr_inf));
4016*9860Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
4017*9860Sgdamore@opensolaris.org }
4018*9860Sgdamore@opensolaris.org 
4019*9860Sgdamore@opensolaris.org /*
4020*9860Sgdamore@opensolaris.org  *	========== PHY MII Routines ==========
4021*9860Sgdamore@opensolaris.org  */
4022*9860Sgdamore@opensolaris.org 
4023*9860Sgdamore@opensolaris.org /* do_phy() - called with intrlock held */
4024*9860Sgdamore@opensolaris.org static void
4025*9860Sgdamore@opensolaris.org do_phy(gld_mac_info_t *macinfo)
4026*9860Sgdamore@opensolaris.org {
4027*9860Sgdamore@opensolaris.org 	dev_info_t *dip;
4028*9860Sgdamore@opensolaris.org 	struct dnetinstance
4029*9860Sgdamore@opensolaris.org 	    *dnetp = (struct dnetinstance *)macinfo->gldm_private;
4030*9860Sgdamore@opensolaris.org 	LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf;
4031*9860Sgdamore@opensolaris.org 	media_block_t *block;
4032*9860Sgdamore@opensolaris.org 	int phy;
4033*9860Sgdamore@opensolaris.org 
4034*9860Sgdamore@opensolaris.org 	dip = dnetp->devinfo;
4035*9860Sgdamore@opensolaris.org 
4036*9860Sgdamore@opensolaris.org 	/*
4037*9860Sgdamore@opensolaris.org 	 * Find and configure the PHY media block. If NO PHY blocks are
4038*9860Sgdamore@opensolaris.org 	 * found on the SROM, but a PHY device is present, we assume the card
4039*9860Sgdamore@opensolaris.org 	 * is a legacy device, and that there is ONLY a PHY interface on the
4040*9860Sgdamore@opensolaris.org 	 * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY
4041*9860Sgdamore@opensolaris.org 	 */
4042*9860Sgdamore@opensolaris.org 
4043*9860Sgdamore@opensolaris.org 	for (block = leaf->block + leaf->block_count -1;
4044*9860Sgdamore@opensolaris.org 	    block >= leaf->block; block --) {
4045*9860Sgdamore@opensolaris.org 		if (block->type == 3 || block->type == 1) {
4046*9860Sgdamore@opensolaris.org 			leaf->mii_block = block;
4047*9860Sgdamore@opensolaris.org 			break;
4048*9860Sgdamore@opensolaris.org 		}
4049*9860Sgdamore@opensolaris.org 	}
4050*9860Sgdamore@opensolaris.org 
4051*9860Sgdamore@opensolaris.org 	/*
4052*9860Sgdamore@opensolaris.org 	 * If no MII block, select default, and hope this configuration will
4053*9860Sgdamore@opensolaris.org 	 * allow the phy to be read/written if it is present
4054*9860Sgdamore@opensolaris.org 	 */
4055*9860Sgdamore@opensolaris.org 	dnetp->selected_media_block = leaf->mii_block ?
4056*9860Sgdamore@opensolaris.org 	    leaf->mii_block : leaf->default_block;
4057*9860Sgdamore@opensolaris.org 
4058*9860Sgdamore@opensolaris.org 	setup_block(macinfo);
4059*9860Sgdamore@opensolaris.org 	/* XXX function return value ignored */
4060*9860Sgdamore@opensolaris.org 	(void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii);
4061*9860Sgdamore@opensolaris.org 
4062*9860Sgdamore@opensolaris.org 	/*
4063*9860Sgdamore@opensolaris.org 	 * We try PHY 0 LAST because it is less likely to be connected
4064*9860Sgdamore@opensolaris.org 	 */
4065*9860Sgdamore@opensolaris.org 	for (phy = 1; phy < 33; phy++)
4066*9860Sgdamore@opensolaris.org 		if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS &&
4067*9860Sgdamore@opensolaris.org 		    mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) {
4068*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
4069*9860Sgdamore@opensolaris.org 			if (dnetdebug & DNETSENSE)
4070*9860Sgdamore@opensolaris.org 				cmn_err(CE_NOTE, "dnet: "
4071*9860Sgdamore@opensolaris.org 				    "PHY at address %d", phy % 32);
4072*9860Sgdamore@opensolaris.org #endif
4073*9860Sgdamore@opensolaris.org 			dnetp->phyaddr = phy % 32;
4074*9860Sgdamore@opensolaris.org 			if (!leaf->mii_block) {
4075*9860Sgdamore@opensolaris.org 				/* Legacy card, change the leaf node */
4076*9860Sgdamore@opensolaris.org 				set_leaf(&dnetp->sr, &leaf_phylegacy);
4077*9860Sgdamore@opensolaris.org 			}
4078*9860Sgdamore@opensolaris.org 			return;
4079*9860Sgdamore@opensolaris.org 		}
4080*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
4081*9860Sgdamore@opensolaris.org 	if (dnetdebug & DNETSENSE)
4082*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "dnet: No PHY found");
4083*9860Sgdamore@opensolaris.org #endif
4084*9860Sgdamore@opensolaris.org }
4085*9860Sgdamore@opensolaris.org 
4086*9860Sgdamore@opensolaris.org static ushort_t
4087*9860Sgdamore@opensolaris.org dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num)
4088*9860Sgdamore@opensolaris.org {
4089*9860Sgdamore@opensolaris.org 	gld_mac_info_t *macinfo;
4090*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp;
4091*9860Sgdamore@opensolaris.org 
4092*9860Sgdamore@opensolaris.org 	uint32_t command_word;
4093*9860Sgdamore@opensolaris.org 	uint32_t tmp;
4094*9860Sgdamore@opensolaris.org 	uint32_t data = 0;
4095*9860Sgdamore@opensolaris.org 	int i;
4096*9860Sgdamore@opensolaris.org 	int bits_in_ushort = ((sizeof (ushort_t))*8);
4097*9860Sgdamore@opensolaris.org 	int turned_around = 0;
4098*9860Sgdamore@opensolaris.org 
4099*9860Sgdamore@opensolaris.org 	macinfo = ddi_get_driver_private(dip);
4100*9860Sgdamore@opensolaris.org 	dnetp = (struct dnetinstance *)macinfo->gldm_private;
4101*9860Sgdamore@opensolaris.org 
4102*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
4103*9860Sgdamore@opensolaris.org 	/* Write Preamble */
4104*9860Sgdamore@opensolaris.org 	write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
4105*9860Sgdamore@opensolaris.org 
4106*9860Sgdamore@opensolaris.org 	/* Prepare command word */
4107*9860Sgdamore@opensolaris.org 	command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN;
4108*9860Sgdamore@opensolaris.org 	command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN;
4109*9860Sgdamore@opensolaris.org 	command_word |= MII_READ_FRAME;
4110*9860Sgdamore@opensolaris.org 
4111*9860Sgdamore@opensolaris.org 	write_mii(dnetp, command_word, bits_in_ushort-2);
4112*9860Sgdamore@opensolaris.org 
4113*9860Sgdamore@opensolaris.org 	mii_tristate(dnetp);
4114*9860Sgdamore@opensolaris.org 
4115*9860Sgdamore@opensolaris.org 	/* Check that the PHY generated a zero bit the 2nd clock */
4116*9860Sgdamore@opensolaris.org 	tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG));
4117*9860Sgdamore@opensolaris.org 
4118*9860Sgdamore@opensolaris.org 	turned_around = (tmp & MII_DATA_IN) ? 0 : 1;
4119*9860Sgdamore@opensolaris.org 
4120*9860Sgdamore@opensolaris.org 	/* read data WORD */
4121*9860Sgdamore@opensolaris.org 	for (i = 0; i < bits_in_ushort; i++) {
4122*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
4123*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ);
4124*9860Sgdamore@opensolaris.org 		drv_usecwait(MII_DELAY);
4125*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
4126*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK);
4127*9860Sgdamore@opensolaris.org 		drv_usecwait(MII_DELAY);
4128*9860Sgdamore@opensolaris.org 		tmp = ddi_get32(dnetp->io_handle,
4129*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, ETHER_ROM_REG));
4130*9860Sgdamore@opensolaris.org 		drv_usecwait(MII_DELAY);
4131*9860Sgdamore@opensolaris.org 		data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001;
4132*9860Sgdamore@opensolaris.org 	}
4133*9860Sgdamore@opensolaris.org 
4134*9860Sgdamore@opensolaris.org 	mii_tristate(dnetp);
4135*9860Sgdamore@opensolaris.org 	return (turned_around ? data: -1);
4136*9860Sgdamore@opensolaris.org }
4137*9860Sgdamore@opensolaris.org 
4138*9860Sgdamore@opensolaris.org static void
4139*9860Sgdamore@opensolaris.org dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat)
4140*9860Sgdamore@opensolaris.org {
4141*9860Sgdamore@opensolaris.org 	gld_mac_info_t *macinfo;
4142*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp;
4143*9860Sgdamore@opensolaris.org 	uint32_t command_word;
4144*9860Sgdamore@opensolaris.org 	int bits_in_ushort = ((sizeof (ushort_t))*8);
4145*9860Sgdamore@opensolaris.org 
4146*9860Sgdamore@opensolaris.org 	macinfo = ddi_get_driver_private(dip);
4147*9860Sgdamore@opensolaris.org 	dnetp = (struct dnetinstance *)macinfo->gldm_private;
4148*9860Sgdamore@opensolaris.org 
4149*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
4150*9860Sgdamore@opensolaris.org 	write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
4151*9860Sgdamore@opensolaris.org 
4152*9860Sgdamore@opensolaris.org 	/* Prepare command word */
4153*9860Sgdamore@opensolaris.org 	command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN);
4154*9860Sgdamore@opensolaris.org 	command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN);
4155*9860Sgdamore@opensolaris.org 	command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat);
4156*9860Sgdamore@opensolaris.org 
4157*9860Sgdamore@opensolaris.org 	write_mii(dnetp, command_word, 2*bits_in_ushort);
4158*9860Sgdamore@opensolaris.org 	mii_tristate(dnetp);
4159*9860Sgdamore@opensolaris.org }
4160*9860Sgdamore@opensolaris.org 
4161*9860Sgdamore@opensolaris.org /*
4162*9860Sgdamore@opensolaris.org  * Write data size bits from mii_data to the MII control lines.
4163*9860Sgdamore@opensolaris.org  */
4164*9860Sgdamore@opensolaris.org static void
4165*9860Sgdamore@opensolaris.org write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size)
4166*9860Sgdamore@opensolaris.org {
4167*9860Sgdamore@opensolaris.org 	int i;
4168*9860Sgdamore@opensolaris.org 	uint32_t dbit;
4169*9860Sgdamore@opensolaris.org 
4170*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
4171*9860Sgdamore@opensolaris.org 	for (i = data_size; i > 0; i--) {
4172*9860Sgdamore@opensolaris.org 		dbit = ((mii_data >>
4173*9860Sgdamore@opensolaris.org 		    (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA);
4174*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
4175*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, ETHER_ROM_REG),
4176*9860Sgdamore@opensolaris.org 		    MII_WRITE | dbit);
4177*9860Sgdamore@opensolaris.org 		drv_usecwait(MII_DELAY);
4178*9860Sgdamore@opensolaris.org 		ddi_put32(dnetp->io_handle,
4179*9860Sgdamore@opensolaris.org 		    REG32(dnetp->io_reg, ETHER_ROM_REG),
4180*9860Sgdamore@opensolaris.org 		    MII_WRITE | MII_CLOCK | dbit);
4181*9860Sgdamore@opensolaris.org 		drv_usecwait(MII_DELAY);
4182*9860Sgdamore@opensolaris.org 		mii_data <<= 1;
4183*9860Sgdamore@opensolaris.org 	}
4184*9860Sgdamore@opensolaris.org }
4185*9860Sgdamore@opensolaris.org 
4186*9860Sgdamore@opensolaris.org /*
4187*9860Sgdamore@opensolaris.org  * Put the MDIO port in tri-state for the turn around bits
4188*9860Sgdamore@opensolaris.org  * in MII read and at end of MII management sequence.
4189*9860Sgdamore@opensolaris.org  */
4190*9860Sgdamore@opensolaris.org static void
4191*9860Sgdamore@opensolaris.org mii_tristate(struct dnetinstance *dnetp)
4192*9860Sgdamore@opensolaris.org {
4193*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
4194*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
4195*9860Sgdamore@opensolaris.org 	    MII_WRITE_TS);
4196*9860Sgdamore@opensolaris.org 	drv_usecwait(MII_DELAY);
4197*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
4198*9860Sgdamore@opensolaris.org 	    MII_WRITE_TS | MII_CLOCK);
4199*9860Sgdamore@opensolaris.org 	drv_usecwait(MII_DELAY);
4200*9860Sgdamore@opensolaris.org }
4201*9860Sgdamore@opensolaris.org 
4202*9860Sgdamore@opensolaris.org 
4203*9860Sgdamore@opensolaris.org static void
4204*9860Sgdamore@opensolaris.org set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf)
4205*9860Sgdamore@opensolaris.org {
4206*9860Sgdamore@opensolaris.org 	if (sr->leaf && !sr->leaf->is_static)
4207*9860Sgdamore@opensolaris.org 		kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT));
4208*9860Sgdamore@opensolaris.org 	sr->leaf = leaf;
4209*9860Sgdamore@opensolaris.org }
4210*9860Sgdamore@opensolaris.org 
4211*9860Sgdamore@opensolaris.org /*
4212*9860Sgdamore@opensolaris.org  * Callback from MII module. Makes sure that the CSR registers are
4213*9860Sgdamore@opensolaris.org  * configured properly if the PHY changes mode.
4214*9860Sgdamore@opensolaris.org  */
4215*9860Sgdamore@opensolaris.org /* ARGSUSED */
4216*9860Sgdamore@opensolaris.org /* dnet_mii_link_cb - called with intrlock held */
4217*9860Sgdamore@opensolaris.org static void
4218*9860Sgdamore@opensolaris.org dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state)
4219*9860Sgdamore@opensolaris.org {
4220*9860Sgdamore@opensolaris.org 	gld_mac_info_t *macinfo = ddi_get_driver_private(dip);
4221*9860Sgdamore@opensolaris.org 	struct dnetinstance *dnetp =
4222*9860Sgdamore@opensolaris.org 	    (struct dnetinstance *)macinfo->gldm_private;
4223*9860Sgdamore@opensolaris.org 	LEAF_FORMAT *leaf;
4224*9860Sgdamore@opensolaris.org 
4225*9860Sgdamore@opensolaris.org 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
4226*9860Sgdamore@opensolaris.org 	leaf = dnetp->sr.leaf + dnetp->leaf;
4227*9860Sgdamore@opensolaris.org 	if (state == phy_state_linkup) {
4228*9860Sgdamore@opensolaris.org 		dnetp->mii_up = 1;
4229*9860Sgdamore@opensolaris.org 		/* XXX function return value ignored */
4230*9860Sgdamore@opensolaris.org 		(void) mii_getspeed(dnetp->mii,
4231*9860Sgdamore@opensolaris.org 		    dnetp->phyaddr, &dnetp->mii_speed,
4232*9860Sgdamore@opensolaris.org 		    &dnetp->mii_duplex);
4233*9860Sgdamore@opensolaris.org 		dnetp->selected_media_block = leaf->mii_block;
4234*9860Sgdamore@opensolaris.org 		setup_block(macinfo);
4235*9860Sgdamore@opensolaris.org 	} else {
4236*9860Sgdamore@opensolaris.org 		/* NEEDSWORK: Probably can call find_active_media here */
4237*9860Sgdamore@opensolaris.org 		dnetp->mii_up = 0;
4238*9860Sgdamore@opensolaris.org 		dnetp->mii_speed = 0;
4239*9860Sgdamore@opensolaris.org 		dnetp->mii_duplex = 0;
4240*9860Sgdamore@opensolaris.org 		if (leaf->default_block->media_code == MEDIA_MII)
4241*9860Sgdamore@opensolaris.org 			dnetp->selected_media_block = leaf->default_block;
4242*9860Sgdamore@opensolaris.org 		setup_block(macinfo);
4243*9860Sgdamore@opensolaris.org 	}
4244*9860Sgdamore@opensolaris.org }
4245*9860Sgdamore@opensolaris.org 
4246*9860Sgdamore@opensolaris.org /*
4247*9860Sgdamore@opensolaris.org  * SROM parsing routines.
4248*9860Sgdamore@opensolaris.org  * Refer to the Digital 3.03 SROM spec while reading this! (references refer
4249*9860Sgdamore@opensolaris.org  * to this document)
4250*9860Sgdamore@opensolaris.org  * Where possible ALL vendor specific changes should be localised here. The
4251*9860Sgdamore@opensolaris.org  * SROM data should be capable of describing any programmatic irregularities
4252*9860Sgdamore@opensolaris.org  * of DNET cards (via SIA or GP registers, in particular), so vendor specific
4253*9860Sgdamore@opensolaris.org  * code elsewhere should not be required
4254*9860Sgdamore@opensolaris.org  */
4255*9860Sgdamore@opensolaris.org static void
4256*9860Sgdamore@opensolaris.org dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi)
4257*9860Sgdamore@opensolaris.org {
4258*9860Sgdamore@opensolaris.org 	uint32_t ether_mfg = 0;
4259*9860Sgdamore@opensolaris.org 	int i;
4260*9860Sgdamore@opensolaris.org 	uchar_t *p;
4261*9860Sgdamore@opensolaris.org 
4262*9860Sgdamore@opensolaris.org 	if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
4263*9860Sgdamore@opensolaris.org 	    DDI_PROP_DONTPASS, "no_sromconfig", 0))
4264*9860Sgdamore@opensolaris.org 		dnetp->sr.init_from_srom = check_srom_valid(vi);
4265*9860Sgdamore@opensolaris.org 
4266*9860Sgdamore@opensolaris.org 	if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) {
4267*9860Sgdamore@opensolaris.org 		/* Section 2/3: General SROM Format/ ID Block */
4268*9860Sgdamore@opensolaris.org 		p = vi+18;
4269*9860Sgdamore@opensolaris.org 		sr->version = *p++;
4270*9860Sgdamore@opensolaris.org 		sr->adapters = *p++;
4271*9860Sgdamore@opensolaris.org 
4272*9860Sgdamore@opensolaris.org 		sr->leaf =
4273*9860Sgdamore@opensolaris.org 		    kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP);
4274*9860Sgdamore@opensolaris.org 		for (i = 0; i < 6; i++)
4275*9860Sgdamore@opensolaris.org 			sr->netaddr[i] = *p++;
4276*9860Sgdamore@opensolaris.org 
4277*9860Sgdamore@opensolaris.org 		for (i = 0; i < sr->adapters; i++) {
4278*9860Sgdamore@opensolaris.org 			uchar_t devno = *p++;
4279*9860Sgdamore@opensolaris.org 			uint16_t offset = *p++;
4280*9860Sgdamore@opensolaris.org 			offset |= *p++ << 8;
4281*9860Sgdamore@opensolaris.org 			sr->leaf[i].device_number = devno;
4282*9860Sgdamore@opensolaris.org 			parse_controller_leaf(dnetp, sr->leaf+i, vi+offset);
4283*9860Sgdamore@opensolaris.org 		}
4284*9860Sgdamore@opensolaris.org 		/*
4285*9860Sgdamore@opensolaris.org 		 * 'Orrible hack for cogent cards. The 6911A board seems to
4286*9860Sgdamore@opensolaris.org 		 * have an incorrect SROM. (From the OEMDEMO program
4287*9860Sgdamore@opensolaris.org 		 * supplied by cogent, it seems that the ROM matches a setup
4288*9860Sgdamore@opensolaris.org 		 * or a board with a QSI or ICS PHY.
4289*9860Sgdamore@opensolaris.org 		 */
4290*9860Sgdamore@opensolaris.org 		for (i = 0; i < 3; i++)
4291*9860Sgdamore@opensolaris.org 			ether_mfg = (ether_mfg << 8) | sr->netaddr[i];
4292*9860Sgdamore@opensolaris.org 
4293*9860Sgdamore@opensolaris.org 		if (ether_mfg == ADAPTEC_ETHER) {
4294*9860Sgdamore@opensolaris.org 			static uint16_t cogent_gprseq[] = {0x821, 0};
4295*9860Sgdamore@opensolaris.org 			switch (vi[COGENT_SROM_ID]) {
4296*9860Sgdamore@opensolaris.org 			case COGENT_ANA6911A_C:
4297*9860Sgdamore@opensolaris.org 			case COGENT_ANA6911AC_C:
4298*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
4299*9860Sgdamore@opensolaris.org 				if (dnetdebug & DNETTRACE)
4300*9860Sgdamore@opensolaris.org 					cmn_err(CE_WARN,
4301*9860Sgdamore@opensolaris.org 					    "Suspected bad GPR sequence."
4302*9860Sgdamore@opensolaris.org 					    " Making a guess (821,0)");
4303*9860Sgdamore@opensolaris.org #endif
4304*9860Sgdamore@opensolaris.org 
4305*9860Sgdamore@opensolaris.org 				/* XXX function return value ignored */
4306*9860Sgdamore@opensolaris.org 				(void) ddi_prop_update_byte_array(
4307*9860Sgdamore@opensolaris.org 				    DDI_DEV_T_NONE, dnetp->devinfo,
4308*9860Sgdamore@opensolaris.org 				    "gpr-sequence", (uchar_t *)cogent_gprseq,
4309*9860Sgdamore@opensolaris.org 				    sizeof (cogent_gprseq));
4310*9860Sgdamore@opensolaris.org 				break;
4311*9860Sgdamore@opensolaris.org 			}
4312*9860Sgdamore@opensolaris.org 		}
4313*9860Sgdamore@opensolaris.org 	} else {
4314*9860Sgdamore@opensolaris.org 		/*
4315*9860Sgdamore@opensolaris.org 		 * Adhoc SROM, check for some cards which need special handling
4316*9860Sgdamore@opensolaris.org 		 * Assume vendor info contains ether address in first six bytes
4317*9860Sgdamore@opensolaris.org 		 */
4318*9860Sgdamore@opensolaris.org 
4319*9860Sgdamore@opensolaris.org 		uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
4320*9860Sgdamore@opensolaris.org 		    DDI_PROP_DONTPASS, macoffset_propname, 0);
4321*9860Sgdamore@opensolaris.org 
4322*9860Sgdamore@opensolaris.org 		for (i = 0; i < 6; i++)
4323*9860Sgdamore@opensolaris.org 			sr->netaddr[i] = mac[i];
4324*9860Sgdamore@opensolaris.org 
4325*9860Sgdamore@opensolaris.org 		if (dnetp->board_type == DEVICE_ID_21140) {
4326*9860Sgdamore@opensolaris.org 			for (i = 0; i < 3; i++)
4327*9860Sgdamore@opensolaris.org 				ether_mfg = (ether_mfg << 8) | mac[i];
4328*9860Sgdamore@opensolaris.org 
4329*9860Sgdamore@opensolaris.org 			switch (ether_mfg) {
4330*9860Sgdamore@opensolaris.org 			case ASANTE_ETHER:
4331*9860Sgdamore@opensolaris.org 				dnetp->vendor_21140 = ASANTE_TYPE;
4332*9860Sgdamore@opensolaris.org 				dnetp->vendor_revision = 0;
4333*9860Sgdamore@opensolaris.org 				set_leaf(sr, &leaf_asante);
4334*9860Sgdamore@opensolaris.org 				sr->adapters = 1;
4335*9860Sgdamore@opensolaris.org 				break;
4336*9860Sgdamore@opensolaris.org 
4337*9860Sgdamore@opensolaris.org 			case COGENT_ETHER:
4338*9860Sgdamore@opensolaris.org 			case ADAPTEC_ETHER:
4339*9860Sgdamore@opensolaris.org 				dnetp->vendor_21140 = COGENT_EM_TYPE;
4340*9860Sgdamore@opensolaris.org 				dnetp->vendor_revision =
4341*9860Sgdamore@opensolaris.org 				    vi[VENDOR_REVISION_OFFSET];
4342*9860Sgdamore@opensolaris.org 				set_leaf(sr, &leaf_cogent_100);
4343*9860Sgdamore@opensolaris.org 				sr->adapters = 1;
4344*9860Sgdamore@opensolaris.org 				break;
4345*9860Sgdamore@opensolaris.org 
4346*9860Sgdamore@opensolaris.org 			default:
4347*9860Sgdamore@opensolaris.org 				dnetp->vendor_21140 = DEFAULT_TYPE;
4348*9860Sgdamore@opensolaris.org 				dnetp->vendor_revision = 0;
4349*9860Sgdamore@opensolaris.org 				set_leaf(sr, &leaf_default_100);
4350*9860Sgdamore@opensolaris.org 				sr->adapters = 1;
4351*9860Sgdamore@opensolaris.org 				break;
4352*9860Sgdamore@opensolaris.org 			}
4353*9860Sgdamore@opensolaris.org 		} else if (dnetp->board_type == DEVICE_ID_21041) {
4354*9860Sgdamore@opensolaris.org 			set_leaf(sr, &leaf_21041);
4355*9860Sgdamore@opensolaris.org 		} else if (dnetp->board_type == DEVICE_ID_21040) {
4356*9860Sgdamore@opensolaris.org 			set_leaf(sr, &leaf_21040);
4357*9860Sgdamore@opensolaris.org 		}
4358*9860Sgdamore@opensolaris.org 	}
4359*9860Sgdamore@opensolaris.org }
4360*9860Sgdamore@opensolaris.org 
4361*9860Sgdamore@opensolaris.org /* Section 4.2, 4.3, 4.4, 4.5 */
4362*9860Sgdamore@opensolaris.org static void
4363*9860Sgdamore@opensolaris.org parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
4364*9860Sgdamore@opensolaris.org 	uchar_t *vi)
4365*9860Sgdamore@opensolaris.org {
4366*9860Sgdamore@opensolaris.org 	int i;
4367*9860Sgdamore@opensolaris.org 
4368*9860Sgdamore@opensolaris.org 	leaf->selected_contype = *vi++;
4369*9860Sgdamore@opensolaris.org 	leaf->selected_contype |= *vi++ << 8;
4370*9860Sgdamore@opensolaris.org 
4371*9860Sgdamore@opensolaris.org 	if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */
4372*9860Sgdamore@opensolaris.org 		leaf->gpr = *vi++;
4373*9860Sgdamore@opensolaris.org 
4374*9860Sgdamore@opensolaris.org 	leaf->block_count = *vi++;
4375*9860Sgdamore@opensolaris.org 
4376*9860Sgdamore@opensolaris.org 	if (leaf->block_count > MAX_MEDIA) {
4377*9860Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "dnet: Too many media in SROM!");
4378*9860Sgdamore@opensolaris.org 		leaf->block_count = 1;
4379*9860Sgdamore@opensolaris.org 	}
4380*9860Sgdamore@opensolaris.org 	for (i = 0; i <= leaf->block_count; i++) {
4381*9860Sgdamore@opensolaris.org 		vi = parse_media_block(dnetp, leaf->block + i, vi);
4382*9860Sgdamore@opensolaris.org 		if (leaf->block[i].command & CMD_DEFAULT_MEDIUM)
4383*9860Sgdamore@opensolaris.org 			leaf->default_block = leaf->block+i;
4384*9860Sgdamore@opensolaris.org 	}
4385*9860Sgdamore@opensolaris.org 	/* No explicit default block: use last in the ROM */
4386*9860Sgdamore@opensolaris.org 	if (leaf->default_block == NULL)
4387*9860Sgdamore@opensolaris.org 		leaf->default_block = leaf->block + leaf->block_count -1;
4388*9860Sgdamore@opensolaris.org 
4389*9860Sgdamore@opensolaris.org }
4390*9860Sgdamore@opensolaris.org 
4391*9860Sgdamore@opensolaris.org static uchar_t *
4392*9860Sgdamore@opensolaris.org parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi)
4393*9860Sgdamore@opensolaris.org {
4394*9860Sgdamore@opensolaris.org 	int i;
4395*9860Sgdamore@opensolaris.org 
4396*9860Sgdamore@opensolaris.org 	/*
4397*9860Sgdamore@opensolaris.org 	 * There are three kinds of media block we need to worry about:
4398*9860Sgdamore@opensolaris.org 	 * The 21041 blocks.
4399*9860Sgdamore@opensolaris.org 	 * 21140 blocks from a version 1 SROM
4400*9860Sgdamore@opensolaris.org 	 * 2114[023] block from a version 3 SROM
4401*9860Sgdamore@opensolaris.org 	 */
4402*9860Sgdamore@opensolaris.org 
4403*9860Sgdamore@opensolaris.org 	if (dnetp->board_type == DEVICE_ID_21041) {
4404*9860Sgdamore@opensolaris.org 		/* Section 4.2 */
4405*9860Sgdamore@opensolaris.org 		block->media_code = *vi & 0x3f;
4406*9860Sgdamore@opensolaris.org 		block->type = 2;
4407*9860Sgdamore@opensolaris.org 		if (*vi++ & 0x40) {
4408*9860Sgdamore@opensolaris.org 			block->un.sia.csr13 = *vi++;
4409*9860Sgdamore@opensolaris.org 			block->un.sia.csr13 |= *vi++ << 8;
4410*9860Sgdamore@opensolaris.org 			block->un.sia.csr14 = *vi++;
4411*9860Sgdamore@opensolaris.org 			block->un.sia.csr14 |= *vi++ << 8;
4412*9860Sgdamore@opensolaris.org 			block->un.sia.csr15 = *vi++;
4413*9860Sgdamore@opensolaris.org 			block->un.sia.csr15 |= *vi++ << 8;
4414*9860Sgdamore@opensolaris.org 		} else {
4415*9860Sgdamore@opensolaris.org 			/* No media data (csrs 13,14,15). Insert defaults */
4416*9860Sgdamore@opensolaris.org 			switch (block->media_code) {
4417*9860Sgdamore@opensolaris.org 			case MEDIA_TP:
4418*9860Sgdamore@opensolaris.org 				block->un.sia.csr13 = 0xef01;
4419*9860Sgdamore@opensolaris.org 				block->un.sia.csr14 = 0x7f3f;
4420*9860Sgdamore@opensolaris.org 				block->un.sia.csr15 = 0x0008;
4421*9860Sgdamore@opensolaris.org 				break;
4422*9860Sgdamore@opensolaris.org 			case MEDIA_TP_FD:
4423*9860Sgdamore@opensolaris.org 				block->un.sia.csr13 = 0xef01;
4424*9860Sgdamore@opensolaris.org 				block->un.sia.csr14 = 0x7f3d;
4425*9860Sgdamore@opensolaris.org 				block->un.sia.csr15 = 0x0008;
4426*9860Sgdamore@opensolaris.org 				break;
4427*9860Sgdamore@opensolaris.org 			case MEDIA_BNC:
4428*9860Sgdamore@opensolaris.org 				block->un.sia.csr13 = 0xef09;
4429*9860Sgdamore@opensolaris.org 				block->un.sia.csr14 = 0x0705;
4430*9860Sgdamore@opensolaris.org 				block->un.sia.csr15 = 0x0006;
4431*9860Sgdamore@opensolaris.org 				break;
4432*9860Sgdamore@opensolaris.org 			case MEDIA_AUI:
4433*9860Sgdamore@opensolaris.org 				block->un.sia.csr13 = 0xef09;
4434*9860Sgdamore@opensolaris.org 				block->un.sia.csr14 = 0x0705;
4435*9860Sgdamore@opensolaris.org 				block->un.sia.csr15 = 0x000e;
4436*9860Sgdamore@opensolaris.org 				break;
4437*9860Sgdamore@opensolaris.org 			}
4438*9860Sgdamore@opensolaris.org 		}
4439*9860Sgdamore@opensolaris.org 	} else  if (*vi & 0x80) {  /* Extended format: Section 4.3.2.2 */
4440*9860Sgdamore@opensolaris.org 		int blocklen = *vi++ & 0x7f;
4441*9860Sgdamore@opensolaris.org 		block->type = *vi++;
4442*9860Sgdamore@opensolaris.org 		switch (block->type) {
4443*9860Sgdamore@opensolaris.org 		case 0: /* "non-MII": Section 4.3.2.2.1 */
4444*9860Sgdamore@opensolaris.org 			block->media_code = (*vi++) & 0x3f;
4445*9860Sgdamore@opensolaris.org 			block->gprseqlen = 1;
4446*9860Sgdamore@opensolaris.org 			block->gprseq[0] = *vi++;
4447*9860Sgdamore@opensolaris.org 			block->command = *vi++;
4448*9860Sgdamore@opensolaris.org 			block->command |= *vi++ << 8;
4449*9860Sgdamore@opensolaris.org 			break;
4450*9860Sgdamore@opensolaris.org 
4451*9860Sgdamore@opensolaris.org 		case 1: /* MII/PHY: Section 4.3.2.2.2 */
4452*9860Sgdamore@opensolaris.org 			block->command = CMD_PS;
4453*9860Sgdamore@opensolaris.org 			block->media_code = MEDIA_MII;
4454*9860Sgdamore@opensolaris.org 				/* This is whats needed in CSR6 */
4455*9860Sgdamore@opensolaris.org 
4456*9860Sgdamore@opensolaris.org 			block->un.mii.phy_num = *vi++;
4457*9860Sgdamore@opensolaris.org 			block->gprseqlen = *vi++;
4458*9860Sgdamore@opensolaris.org 
4459*9860Sgdamore@opensolaris.org 			for (i = 0; i < block->gprseqlen; i++)
4460*9860Sgdamore@opensolaris.org 				block->gprseq[i] = *vi++;
4461*9860Sgdamore@opensolaris.org 			block->rstseqlen = *vi++;
4462*9860Sgdamore@opensolaris.org 			for (i = 0; i < block->rstseqlen; i++)
4463*9860Sgdamore@opensolaris.org 				block->rstseq[i] = *vi++;
4464*9860Sgdamore@opensolaris.org 
4465*9860Sgdamore@opensolaris.org 			block->un.mii.mediacaps = *vi++;
4466*9860Sgdamore@opensolaris.org 			block->un.mii.mediacaps |= *vi++ << 8;
4467*9860Sgdamore@opensolaris.org 			block->un.mii.nwayadvert = *vi++;
4468*9860Sgdamore@opensolaris.org 			block->un.mii.nwayadvert |= *vi++ << 8;
4469*9860Sgdamore@opensolaris.org 			block->un.mii.fdxmask = *vi++;
4470*9860Sgdamore@opensolaris.org 			block->un.mii.fdxmask |= *vi++ << 8;
4471*9860Sgdamore@opensolaris.org 			block->un.mii.ttmmask = *vi++;
4472*9860Sgdamore@opensolaris.org 			block->un.mii.ttmmask |= *vi++ << 8;
4473*9860Sgdamore@opensolaris.org 			break;
4474*9860Sgdamore@opensolaris.org 
4475*9860Sgdamore@opensolaris.org 		case 2: /* SIA Media: Section 4.4.2.1.1 */
4476*9860Sgdamore@opensolaris.org 			block->media_code = *vi & 0x3f;
4477*9860Sgdamore@opensolaris.org 			if (*vi++ & 0x40) {
4478*9860Sgdamore@opensolaris.org 				block->un.sia.csr13 = *vi++;
4479*9860Sgdamore@opensolaris.org 				block->un.sia.csr13 |= *vi++ << 8;
4480*9860Sgdamore@opensolaris.org 				block->un.sia.csr14 = *vi++;
4481*9860Sgdamore@opensolaris.org 				block->un.sia.csr14 |= *vi++ << 8;
4482*9860Sgdamore@opensolaris.org 				block->un.sia.csr15 = *vi++;
4483*9860Sgdamore@opensolaris.org 				block->un.sia.csr15 |= *vi++ << 8;
4484*9860Sgdamore@opensolaris.org 			} else {
4485*9860Sgdamore@opensolaris.org 				/*
4486*9860Sgdamore@opensolaris.org 				 * SIA values not provided by SROM; provide
4487*9860Sgdamore@opensolaris.org 				 * defaults. See appendix D of 2114[23] manuals.
4488*9860Sgdamore@opensolaris.org 				 */
4489*9860Sgdamore@opensolaris.org 				switch (block->media_code) {
4490*9860Sgdamore@opensolaris.org 				case MEDIA_BNC:
4491*9860Sgdamore@opensolaris.org 					block->un.sia.csr13 = 0x0009;
4492*9860Sgdamore@opensolaris.org 					block->un.sia.csr14 = 0x0705;
4493*9860Sgdamore@opensolaris.org 					block->un.sia.csr15 = 0x0000;
4494*9860Sgdamore@opensolaris.org 					break;
4495*9860Sgdamore@opensolaris.org 				case MEDIA_AUI:
4496*9860Sgdamore@opensolaris.org 					block->un.sia.csr13 = 0x0009;
4497*9860Sgdamore@opensolaris.org 					block->un.sia.csr14 = 0x0705;
4498*9860Sgdamore@opensolaris.org 					block->un.sia.csr15 = 0x0008;
4499*9860Sgdamore@opensolaris.org 					break;
4500*9860Sgdamore@opensolaris.org 				case MEDIA_TP:
4501*9860Sgdamore@opensolaris.org 					block->un.sia.csr13 = 0x0001;
4502*9860Sgdamore@opensolaris.org 					block->un.sia.csr14 = 0x7f3f;
4503*9860Sgdamore@opensolaris.org 					block->un.sia.csr15 = 0x0000;
4504*9860Sgdamore@opensolaris.org 					break;
4505*9860Sgdamore@opensolaris.org 				case MEDIA_TP_FD:
4506*9860Sgdamore@opensolaris.org 					block->un.sia.csr13 = 0x0001;
4507*9860Sgdamore@opensolaris.org 					block->un.sia.csr14 = 0x7f3d;
4508*9860Sgdamore@opensolaris.org 					block->un.sia.csr15 = 0x0000;
4509*9860Sgdamore@opensolaris.org 					break;
4510*9860Sgdamore@opensolaris.org 				default:
4511*9860Sgdamore@opensolaris.org 					block->un.sia.csr13 = 0x0000;
4512*9860Sgdamore@opensolaris.org 					block->un.sia.csr14 = 0x0000;
4513*9860Sgdamore@opensolaris.org 					block->un.sia.csr15 = 0x0000;
4514*9860Sgdamore@opensolaris.org 				}
4515*9860Sgdamore@opensolaris.org 			}
4516*9860Sgdamore@opensolaris.org 
4517*9860Sgdamore@opensolaris.org 			/* Treat GP control/data as a GPR sequence */
4518*9860Sgdamore@opensolaris.org 			block->gprseqlen = 2;
4519*9860Sgdamore@opensolaris.org 			block->gprseq[0] = *vi++;
4520*9860Sgdamore@opensolaris.org 			block->gprseq[0] |= *vi++ << 8;
4521*9860Sgdamore@opensolaris.org 			block->gprseq[0] |= GPR_CONTROL_WRITE;
4522*9860Sgdamore@opensolaris.org 			block->gprseq[1] = *vi++;
4523*9860Sgdamore@opensolaris.org 			block->gprseq[1] |= *vi++ << 8;
4524*9860Sgdamore@opensolaris.org 			break;
4525*9860Sgdamore@opensolaris.org 
4526*9860Sgdamore@opensolaris.org 		case 3: /* MII/PHY : Section 4.4.2.1.2 */
4527*9860Sgdamore@opensolaris.org 			block->command = CMD_PS;
4528*9860Sgdamore@opensolaris.org 			block->media_code = MEDIA_MII;
4529*9860Sgdamore@opensolaris.org 			block->un.mii.phy_num = *vi++;
4530*9860Sgdamore@opensolaris.org 
4531*9860Sgdamore@opensolaris.org 			block->gprseqlen = *vi++;
4532*9860Sgdamore@opensolaris.org 			for (i = 0; i < block->gprseqlen; i++) {
4533*9860Sgdamore@opensolaris.org 				block->gprseq[i] = *vi++;
4534*9860Sgdamore@opensolaris.org 				block->gprseq[i] |= *vi++ << 8;
4535*9860Sgdamore@opensolaris.org 			}
4536*9860Sgdamore@opensolaris.org 
4537*9860Sgdamore@opensolaris.org 			block->rstseqlen = *vi++;
4538*9860Sgdamore@opensolaris.org 			for (i = 0; i < block->rstseqlen; i++) {
4539*9860Sgdamore@opensolaris.org 				block->rstseq[i] = *vi++;
4540*9860Sgdamore@opensolaris.org 				block->rstseq[i] |= *vi++ << 8;
4541*9860Sgdamore@opensolaris.org 			}
4542*9860Sgdamore@opensolaris.org 			block->un.mii.mediacaps = *vi++;
4543*9860Sgdamore@opensolaris.org 			block->un.mii.mediacaps |= *vi++ << 8;
4544*9860Sgdamore@opensolaris.org 			block->un.mii.nwayadvert = *vi++;
4545*9860Sgdamore@opensolaris.org 			block->un.mii.nwayadvert |= *vi++ << 8;
4546*9860Sgdamore@opensolaris.org 			block->un.mii.fdxmask = *vi++;
4547*9860Sgdamore@opensolaris.org 			block->un.mii.fdxmask |= *vi++ << 8;
4548*9860Sgdamore@opensolaris.org 			block->un.mii.ttmmask = *vi++;
4549*9860Sgdamore@opensolaris.org 			block->un.mii.ttmmask |= *vi++ << 8;
4550*9860Sgdamore@opensolaris.org 			block->un.mii.miiintr |= *vi++;
4551*9860Sgdamore@opensolaris.org 			break;
4552*9860Sgdamore@opensolaris.org 
4553*9860Sgdamore@opensolaris.org 		case 4: /* SYM Media: 4.5.2.1.3 */
4554*9860Sgdamore@opensolaris.org 			block->media_code = *vi++ & 0x3f;
4555*9860Sgdamore@opensolaris.org 			/* Treat GP control and data as a GPR sequence */
4556*9860Sgdamore@opensolaris.org 			block->gprseqlen = 2;
4557*9860Sgdamore@opensolaris.org 			block->gprseq[0] = *vi++;
4558*9860Sgdamore@opensolaris.org 			block->gprseq[0] |= *vi++ << 8;
4559*9860Sgdamore@opensolaris.org 			block->gprseq[0] |= GPR_CONTROL_WRITE;
4560*9860Sgdamore@opensolaris.org 			block->gprseq[1]  = *vi++;
4561*9860Sgdamore@opensolaris.org 			block->gprseq[1] |= *vi++ << 8;
4562*9860Sgdamore@opensolaris.org 			block->command = *vi++;
4563*9860Sgdamore@opensolaris.org 			block->command |= *vi++ << 8;
4564*9860Sgdamore@opensolaris.org 			break;
4565*9860Sgdamore@opensolaris.org 
4566*9860Sgdamore@opensolaris.org 		case 5: /* GPR reset sequence:  Section 4.5.2.1.4 */
4567*9860Sgdamore@opensolaris.org 			block->rstseqlen = *vi++;
4568*9860Sgdamore@opensolaris.org 			for (i = 0; i < block->rstseqlen; i++)
4569*9860Sgdamore@opensolaris.org 				block->rstseq[i] = *vi++;
4570*9860Sgdamore@opensolaris.org 			break;
4571*9860Sgdamore@opensolaris.org 
4572*9860Sgdamore@opensolaris.org 		default: /* Unknown media block. Skip it. */
4573*9860Sgdamore@opensolaris.org 			cmn_err(CE_WARN, "dnet: Unsupported SROM block.");
4574*9860Sgdamore@opensolaris.org 			vi += blocklen;
4575*9860Sgdamore@opensolaris.org 			break;
4576*9860Sgdamore@opensolaris.org 		}
4577*9860Sgdamore@opensolaris.org 	} else { /* Compact format (or V1 SROM): Section 4.3.2.1 */
4578*9860Sgdamore@opensolaris.org 		block->type = 0;
4579*9860Sgdamore@opensolaris.org 		block->media_code = *vi++ & 0x3f;
4580*9860Sgdamore@opensolaris.org 		block->gprseqlen = 1;
4581*9860Sgdamore@opensolaris.org 		block->gprseq[0] = *vi++;
4582*9860Sgdamore@opensolaris.org 		block->command = *vi++;
4583*9860Sgdamore@opensolaris.org 		block->command |= (*vi++) << 8;
4584*9860Sgdamore@opensolaris.org 	}
4585*9860Sgdamore@opensolaris.org 	return (vi);
4586*9860Sgdamore@opensolaris.org }
4587*9860Sgdamore@opensolaris.org 
4588*9860Sgdamore@opensolaris.org 
4589*9860Sgdamore@opensolaris.org /*
4590*9860Sgdamore@opensolaris.org  * An alternative to doing this would be to store the legacy ROMs in binary
4591*9860Sgdamore@opensolaris.org  * format in the conf file, and in read_srom, pick out the data. This would
4592*9860Sgdamore@opensolaris.org  * then allow the parser to continue on as normal. This makes it a little
4593*9860Sgdamore@opensolaris.org  * easier to read.
4594*9860Sgdamore@opensolaris.org  */
4595*9860Sgdamore@opensolaris.org static void
4596*9860Sgdamore@opensolaris.org setup_legacy_blocks()
4597*9860Sgdamore@opensolaris.org {
4598*9860Sgdamore@opensolaris.org 	LEAF_FORMAT *leaf;
4599*9860Sgdamore@opensolaris.org 	media_block_t *block;
4600*9860Sgdamore@opensolaris.org 
4601*9860Sgdamore@opensolaris.org 	/* Default FAKE SROM */
4602*9860Sgdamore@opensolaris.org 	leaf = &leaf_default_100;
4603*9860Sgdamore@opensolaris.org 	leaf->is_static = 1;
4604*9860Sgdamore@opensolaris.org 	leaf->default_block = &leaf->block[3];
4605*9860Sgdamore@opensolaris.org 	leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */
4606*9860Sgdamore@opensolaris.org 	block = leaf->block;
4607*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP_FD;
4608*9860Sgdamore@opensolaris.org 	block->type = 0;
4609*9860Sgdamore@opensolaris.org 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4610*9860Sgdamore@opensolaris.org 	block++;
4611*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP;
4612*9860Sgdamore@opensolaris.org 	block->type = 0;
4613*9860Sgdamore@opensolaris.org 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4614*9860Sgdamore@opensolaris.org 	block++;
4615*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_SYM_SCR_FD;
4616*9860Sgdamore@opensolaris.org 	block->type = 0;
4617*9860Sgdamore@opensolaris.org 	block->command = 0x6d;  /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4618*9860Sgdamore@opensolaris.org 	block++;
4619*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_SYM_SCR;
4620*9860Sgdamore@opensolaris.org 	block->type = 0;
4621*9860Sgdamore@opensolaris.org 	block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4622*9860Sgdamore@opensolaris.org 
4623*9860Sgdamore@opensolaris.org 	/* COGENT FAKE SROM */
4624*9860Sgdamore@opensolaris.org 	leaf = &leaf_cogent_100;
4625*9860Sgdamore@opensolaris.org 	leaf->is_static = 1;
4626*9860Sgdamore@opensolaris.org 	leaf->default_block = &leaf->block[4];
4627*9860Sgdamore@opensolaris.org 	leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */
4628*9860Sgdamore@opensolaris.org 	block = leaf->block; /* BNC */
4629*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_BNC;
4630*9860Sgdamore@opensolaris.org 	block->type = 0;
4631*9860Sgdamore@opensolaris.org 	block->command =  0x8000; /* No media sense, PCS, SCR, PS all off */
4632*9860Sgdamore@opensolaris.org 	block->gprseqlen = 2;
4633*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4634*9860Sgdamore@opensolaris.org 	block->gprseq[0] = 0x13f;
4635*9860Sgdamore@opensolaris.org 	block->gprseq[1] = 1;
4636*9860Sgdamore@opensolaris.org 
4637*9860Sgdamore@opensolaris.org 	block++;
4638*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP_FD;
4639*9860Sgdamore@opensolaris.org 	block->type = 0;
4640*9860Sgdamore@opensolaris.org 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4641*9860Sgdamore@opensolaris.org 	block->gprseqlen = 2;
4642*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4643*9860Sgdamore@opensolaris.org 	block->gprseq[0] = 0x13f;
4644*9860Sgdamore@opensolaris.org 	block->gprseq[1] = 0x26;
4645*9860Sgdamore@opensolaris.org 
4646*9860Sgdamore@opensolaris.org 	block++; /* 10BaseT */
4647*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP;
4648*9860Sgdamore@opensolaris.org 	block->type = 0;
4649*9860Sgdamore@opensolaris.org 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4650*9860Sgdamore@opensolaris.org 	block->gprseqlen = 2;
4651*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4652*9860Sgdamore@opensolaris.org 	block->gprseq[0] = 0x13f;
4653*9860Sgdamore@opensolaris.org 	block->gprseq[1] = 0x3e;
4654*9860Sgdamore@opensolaris.org 
4655*9860Sgdamore@opensolaris.org 	block++; /* 100BaseTX-FD */
4656*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_SYM_SCR_FD;
4657*9860Sgdamore@opensolaris.org 	block->type = 0;
4658*9860Sgdamore@opensolaris.org 	block->command = 0x6d;  /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4659*9860Sgdamore@opensolaris.org 	block->gprseqlen = 2;
4660*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4661*9860Sgdamore@opensolaris.org 	block->gprseq[0] = 0x13f;
4662*9860Sgdamore@opensolaris.org 	block->gprseq[1] = 1;
4663*9860Sgdamore@opensolaris.org 
4664*9860Sgdamore@opensolaris.org 	block++; /* 100BaseTX */
4665*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_SYM_SCR;
4666*9860Sgdamore@opensolaris.org 	block->type = 0;
4667*9860Sgdamore@opensolaris.org 	block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4668*9860Sgdamore@opensolaris.org 	block->gprseqlen = 2;
4669*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4670*9860Sgdamore@opensolaris.org 	block->gprseq[0] = 0x13f;
4671*9860Sgdamore@opensolaris.org 	block->gprseq[1] = 1;
4672*9860Sgdamore@opensolaris.org 
4673*9860Sgdamore@opensolaris.org 	/* Generic legacy card with a PHY. */
4674*9860Sgdamore@opensolaris.org 	leaf = &leaf_phylegacy;
4675*9860Sgdamore@opensolaris.org 	leaf->block_count = 1;
4676*9860Sgdamore@opensolaris.org 	leaf->mii_block = leaf->block;
4677*9860Sgdamore@opensolaris.org 	leaf->default_block = &leaf->block[0];
4678*9860Sgdamore@opensolaris.org 	leaf->is_static = 1;
4679*9860Sgdamore@opensolaris.org 	block = leaf->block;
4680*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_MII;
4681*9860Sgdamore@opensolaris.org 	block->type = 1; /* MII Block type 1 */
4682*9860Sgdamore@opensolaris.org 	block->command = 1; /* Port select */
4683*9860Sgdamore@opensolaris.org 	block->gprseqlen = 0;
4684*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4685*9860Sgdamore@opensolaris.org 
4686*9860Sgdamore@opensolaris.org 	/* ASANTE FAKE SROM */
4687*9860Sgdamore@opensolaris.org 	leaf = &leaf_asante;
4688*9860Sgdamore@opensolaris.org 	leaf->is_static = 1;
4689*9860Sgdamore@opensolaris.org 	leaf->default_block = &leaf->block[0];
4690*9860Sgdamore@opensolaris.org 	leaf->block_count = 1;
4691*9860Sgdamore@opensolaris.org 	block = leaf->block;
4692*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_MII;
4693*9860Sgdamore@opensolaris.org 	block->type = 1; /* MII Block type 1 */
4694*9860Sgdamore@opensolaris.org 	block->command = 1; /* Port select */
4695*9860Sgdamore@opensolaris.org 	block->gprseqlen = 3;
4696*9860Sgdamore@opensolaris.org 	block->rstseqlen = 0;
4697*9860Sgdamore@opensolaris.org 	block->gprseq[0] = 0x180;
4698*9860Sgdamore@opensolaris.org 	block->gprseq[1] = 0x80;
4699*9860Sgdamore@opensolaris.org 	block->gprseq[2] = 0x0;
4700*9860Sgdamore@opensolaris.org 
4701*9860Sgdamore@opensolaris.org 	/* LEGACY 21041 card FAKE SROM */
4702*9860Sgdamore@opensolaris.org 	leaf = &leaf_21041;
4703*9860Sgdamore@opensolaris.org 	leaf->is_static = 1;
4704*9860Sgdamore@opensolaris.org 	leaf->block_count = 4;  /* SIA Blocks for TP, TPfd, BNC, AUI */
4705*9860Sgdamore@opensolaris.org 	leaf->default_block = &leaf->block[3];
4706*9860Sgdamore@opensolaris.org 
4707*9860Sgdamore@opensolaris.org 	block = leaf->block;
4708*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_AUI;
4709*9860Sgdamore@opensolaris.org 	block->type = 2;
4710*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0xef09;
4711*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x0705;
4712*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x000e;
4713*9860Sgdamore@opensolaris.org 
4714*9860Sgdamore@opensolaris.org 	block++;
4715*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP_FD;
4716*9860Sgdamore@opensolaris.org 	block->type = 2;
4717*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0xef01;
4718*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x7f3d;
4719*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x0008;
4720*9860Sgdamore@opensolaris.org 
4721*9860Sgdamore@opensolaris.org 	block++;
4722*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_BNC;
4723*9860Sgdamore@opensolaris.org 	block->type = 2;
4724*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0xef09;
4725*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x0705;
4726*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x0006;
4727*9860Sgdamore@opensolaris.org 
4728*9860Sgdamore@opensolaris.org 	block++;
4729*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP;
4730*9860Sgdamore@opensolaris.org 	block->type = 2;
4731*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0xef01;
4732*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x7f3f;
4733*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x0008;
4734*9860Sgdamore@opensolaris.org 
4735*9860Sgdamore@opensolaris.org 	/* LEGACY 21040 card FAKE SROM */
4736*9860Sgdamore@opensolaris.org 	leaf = &leaf_21040;
4737*9860Sgdamore@opensolaris.org 	leaf->is_static = 1;
4738*9860Sgdamore@opensolaris.org 	leaf->block_count = 4;  /* SIA Blocks for TP, TPfd, BNC, AUI */
4739*9860Sgdamore@opensolaris.org 	block = leaf->block;
4740*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_AUI;
4741*9860Sgdamore@opensolaris.org 	block->type = 2;
4742*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0x8f09;
4743*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x0705;
4744*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x000e;
4745*9860Sgdamore@opensolaris.org 	block++;
4746*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP_FD;
4747*9860Sgdamore@opensolaris.org 	block->type = 2;
4748*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0x0f01;
4749*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x7f3d;
4750*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x0008;
4751*9860Sgdamore@opensolaris.org 	block++;
4752*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_BNC;
4753*9860Sgdamore@opensolaris.org 	block->type = 2;
4754*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0xef09;
4755*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x0705;
4756*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x0006;
4757*9860Sgdamore@opensolaris.org 	block++;
4758*9860Sgdamore@opensolaris.org 	block->media_code = MEDIA_TP;
4759*9860Sgdamore@opensolaris.org 	block->type = 2;
4760*9860Sgdamore@opensolaris.org 	block->un.sia.csr13 = 0x8f01;
4761*9860Sgdamore@opensolaris.org 	block->un.sia.csr14 = 0x7f3f;
4762*9860Sgdamore@opensolaris.org 	block->un.sia.csr15 = 0x0008;
4763*9860Sgdamore@opensolaris.org }
4764*9860Sgdamore@opensolaris.org 
4765*9860Sgdamore@opensolaris.org static void
4766*9860Sgdamore@opensolaris.org dnet_print_srom(SROM_FORMAT *sr)
4767*9860Sgdamore@opensolaris.org {
4768*9860Sgdamore@opensolaris.org 	int i;
4769*9860Sgdamore@opensolaris.org 	uchar_t *a = sr->netaddr;
4770*9860Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d,"
4771*9860Sgdamore@opensolaris.org 	    "Addr:%x:%x:%x:%x:%x:%x",
4772*9860Sgdamore@opensolaris.org 	    sr->init_from_srom, sr->version, sr->adapters,
4773*9860Sgdamore@opensolaris.org 	    a[0], a[1], a[2], a[3], a[4], a[5]);
4774*9860Sgdamore@opensolaris.org 
4775*9860Sgdamore@opensolaris.org 	for (i = 0; i < sr->adapters; i++)
4776*9860Sgdamore@opensolaris.org 		dnet_dump_leaf(sr->leaf+i);
4777*9860Sgdamore@opensolaris.org }
4778*9860Sgdamore@opensolaris.org 
4779*9860Sgdamore@opensolaris.org static void
4780*9860Sgdamore@opensolaris.org dnet_dump_leaf(LEAF_FORMAT *leaf)
4781*9860Sgdamore@opensolaris.org {
4782*9860Sgdamore@opensolaris.org 	int i;
4783*9860Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x",
4784*9860Sgdamore@opensolaris.org 	    leaf->device_number, leaf->block_count, leaf->gpr);
4785*9860Sgdamore@opensolaris.org 	for (i = 0; i < leaf->block_count; i++)
4786*9860Sgdamore@opensolaris.org 		dnet_dump_block(leaf->block+i);
4787*9860Sgdamore@opensolaris.org }
4788*9860Sgdamore@opensolaris.org 
4789*9860Sgdamore@opensolaris.org static void
4790*9860Sgdamore@opensolaris.org dnet_dump_block(media_block_t *block)
4791*9860Sgdamore@opensolaris.org {
4792*9860Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ",
4793*9860Sgdamore@opensolaris.org 	    (void *)block,
4794*9860Sgdamore@opensolaris.org 	    block->type, media_str[block->media_code], block->command);
4795*9860Sgdamore@opensolaris.org 	dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2,
4796*9860Sgdamore@opensolaris.org 	    block->gprseqlen *2);
4797*9860Sgdamore@opensolaris.org 	dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2,
4798*9860Sgdamore@opensolaris.org 	    block->rstseqlen *2);
4799*9860Sgdamore@opensolaris.org 	switch (block->type) {
4800*9860Sgdamore@opensolaris.org 	case 1: case 3:
4801*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx"
4802*9860Sgdamore@opensolaris.org 		    "%x, ttm %x, mediacap %x",
4803*9860Sgdamore@opensolaris.org 		    block->un.mii.phy_num, block->un.mii.nwayadvert,
4804*9860Sgdamore@opensolaris.org 		    block->un.mii.fdxmask, block->un.mii.ttmmask,
4805*9860Sgdamore@opensolaris.org 		    block->un.mii.mediacaps);
4806*9860Sgdamore@opensolaris.org 		break;
4807*9860Sgdamore@opensolaris.org 	case 2:
4808*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x",
4809*9860Sgdamore@opensolaris.org 		    block->un.sia.csr13, block->un.sia.csr14,
4810*9860Sgdamore@opensolaris.org 		    block->un.sia.csr15);
4811*9860Sgdamore@opensolaris.org 		break;
4812*9860Sgdamore@opensolaris.org 	}
4813*9860Sgdamore@opensolaris.org }
4814*9860Sgdamore@opensolaris.org 
4815*9860Sgdamore@opensolaris.org 
4816*9860Sgdamore@opensolaris.org /* Utility to print out binary info dumps. Handy for SROMs, etc */
4817*9860Sgdamore@opensolaris.org 
4818*9860Sgdamore@opensolaris.org static int
4819*9860Sgdamore@opensolaris.org hexcode(unsigned val)
4820*9860Sgdamore@opensolaris.org {
4821*9860Sgdamore@opensolaris.org 	if (val <= 9)
4822*9860Sgdamore@opensolaris.org 		return (val +'0');
4823*9860Sgdamore@opensolaris.org 	if (val <= 15)
4824*9860Sgdamore@opensolaris.org 		return (val + 'a' - 10);
4825*9860Sgdamore@opensolaris.org 	return (-1);
4826*9860Sgdamore@opensolaris.org }
4827*9860Sgdamore@opensolaris.org 
4828*9860Sgdamore@opensolaris.org static void
4829*9860Sgdamore@opensolaris.org dnet_dumpbin(char *msg, unsigned char *data, int size, int len)
4830*9860Sgdamore@opensolaris.org {
4831*9860Sgdamore@opensolaris.org 	char hex[128], *p = hex;
4832*9860Sgdamore@opensolaris.org 	char ascii[128], *q = ascii;
4833*9860Sgdamore@opensolaris.org 	int i, j;
4834*9860Sgdamore@opensolaris.org 
4835*9860Sgdamore@opensolaris.org 	if (!len)
4836*9860Sgdamore@opensolaris.org 		return;
4837*9860Sgdamore@opensolaris.org 
4838*9860Sgdamore@opensolaris.org 	for (i = 0; i < len; i += size) {
4839*9860Sgdamore@opensolaris.org 		for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */
4840*9860Sgdamore@opensolaris.org 			*p++ = hexcode(data[i+j] >> 4);
4841*9860Sgdamore@opensolaris.org 			*p++ = hexcode(data[i+j] & 0xf);
4842*9860Sgdamore@opensolaris.org 			*q++ = (data[i+j] < 32 || data[i+j] > 127) ?
4843*9860Sgdamore@opensolaris.org 			    '.' : data[i];
4844*9860Sgdamore@opensolaris.org 		}
4845*9860Sgdamore@opensolaris.org 		*p++ = ' ';
4846*9860Sgdamore@opensolaris.org 		if (q-ascii >= 8) {
4847*9860Sgdamore@opensolaris.org 			*p = *q = 0;
4848*9860Sgdamore@opensolaris.org 			cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4849*9860Sgdamore@opensolaris.org 			p = hex;
4850*9860Sgdamore@opensolaris.org 			q = ascii;
4851*9860Sgdamore@opensolaris.org 		}
4852*9860Sgdamore@opensolaris.org 	}
4853*9860Sgdamore@opensolaris.org 	if (p != hex) {
4854*9860Sgdamore@opensolaris.org 		while ((p - hex) < 8*3)
4855*9860Sgdamore@opensolaris.org 			*p++ = ' ';
4856*9860Sgdamore@opensolaris.org 		*p = *q = 0;
4857*9860Sgdamore@opensolaris.org 		cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4858*9860Sgdamore@opensolaris.org 	}
4859*9860Sgdamore@opensolaris.org }
4860*9860Sgdamore@opensolaris.org 
4861*9860Sgdamore@opensolaris.org #ifdef DNETDEBUG
4862*9860Sgdamore@opensolaris.org void
4863*9860Sgdamore@opensolaris.org dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin,
4864*9860Sgdamore@opensolaris.org     timercb_t cback)
4865*9860Sgdamore@opensolaris.org {
4866*9860Sgdamore@opensolaris.org 	mutex_enter(&dnetp->intrlock);
4867*9860Sgdamore@opensolaris.org 	dnetp->timer.start_ticks = (usecs * 100) / 8192;
4868*9860Sgdamore@opensolaris.org 	dnetp->timer.cb = cback;
4869*9860Sgdamore@opensolaris.org 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG),
4870*9860Sgdamore@opensolaris.org 	    dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0));
4871*9860Sgdamore@opensolaris.org 	if (dnetp->timer.cb)
4872*9860Sgdamore@opensolaris.org 		enable_interrupts(dnetp, 1);
4873*9860Sgdamore@opensolaris.org 	mutex_exit(&dnetp->intrlock);
4874*9860Sgdamore@opensolaris.org }
4875*9860Sgdamore@opensolaris.org 
4876*9860Sgdamore@opensolaris.org uint32_t
4877*9860Sgdamore@opensolaris.org dnet_usecelapsed(struct dnetinstance *dnetp)
4878*9860Sgdamore@opensolaris.org {
4879*9860Sgdamore@opensolaris.org 	uint32_t ticks = dnetp->timer.start_ticks -
4880*9860Sgdamore@opensolaris.org 	    (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) &
4881*9860Sgdamore@opensolaris.org 	    0xffff);
4882*9860Sgdamore@opensolaris.org 	return ((ticks * 8192) / 100);
4883*9860Sgdamore@opensolaris.org }
4884*9860Sgdamore@opensolaris.org 
4885*9860Sgdamore@opensolaris.org /* ARGSUSED */
4886*9860Sgdamore@opensolaris.org void
4887*9860Sgdamore@opensolaris.org dnet_timestamp(struct dnetinstance *dnetp,  char *buf)
4888*9860Sgdamore@opensolaris.org {
4889*9860Sgdamore@opensolaris.org 	uint32_t elapsed = dnet_usecelapsed(dnetp);
4890*9860Sgdamore@opensolaris.org 	char loc[32], *p = loc;
4891*9860Sgdamore@opensolaris.org 	int firstdigit = 1;
4892*9860Sgdamore@opensolaris.org 	uint32_t divisor;
4893*9860Sgdamore@opensolaris.org 
4894*9860Sgdamore@opensolaris.org 	while (*p++ = *buf++)
4895*9860Sgdamore@opensolaris.org 		;
4896*9860Sgdamore@opensolaris.org 	p--;
4897*9860Sgdamore@opensolaris.org 
4898*9860Sgdamore@opensolaris.org 	for (divisor = 1000000000; divisor /= 10; ) {
4899*9860Sgdamore@opensolaris.org 		int digit = (elapsed / divisor);
4900*9860Sgdamore@opensolaris.org 		elapsed -= digit * divisor;
4901*9860Sgdamore@opensolaris.org 		if (!firstdigit || digit) {
4902*9860Sgdamore@opensolaris.org 			*p++ = digit + '0';
4903*9860Sgdamore@opensolaris.org 			firstdigit = 0;
4904*9860Sgdamore@opensolaris.org 		}
4905*9860Sgdamore@opensolaris.org 
4906*9860Sgdamore@opensolaris.org 	}
4907*9860Sgdamore@opensolaris.org 
4908*9860Sgdamore@opensolaris.org 	/* Actual zero, output it */
4909*9860Sgdamore@opensolaris.org 	if (firstdigit)
4910*9860Sgdamore@opensolaris.org 		*p++ = '0';
4911*9860Sgdamore@opensolaris.org 
4912*9860Sgdamore@opensolaris.org 	*p++ = '-';
4913*9860Sgdamore@opensolaris.org 	*p++ = '>';
4914*9860Sgdamore@opensolaris.org 	*p++ = 0;
4915*9860Sgdamore@opensolaris.org 
4916*9860Sgdamore@opensolaris.org 	printf(loc);
4917*9860Sgdamore@opensolaris.org 	dnet_usectimeout(dnetp, 1000000, 0, 0);
4918*9860Sgdamore@opensolaris.org }
4919*9860Sgdamore@opensolaris.org 
4920*9860Sgdamore@opensolaris.org #endif
4921