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