xref: /illumos-gate/usr/src/uts/intel/io/dnet/dnet.c (revision f879aa946dba986685452e3cd77d8c2f1d5688d5)
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 /*
230dc2366fSVenugopal 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 */
3170dc2366fSVenugopal 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));
1334*f879aa94SToomas Soome 	end_index = 0;
1335bdb9230aSGarrett D'Amore 
1336bdb9230aSGarrett D'Amore 	/* reclaim any xmit descriptors completed */
133798e8d175SSteven Stallion 	dnet_reclaim_Tx_desc(dnetp);
1338bdb9230aSGarrett D'Amore 
1339bdb9230aSGarrett D'Amore 	/*
1340bdb9230aSGarrett D'Amore 	 * Use the data buffers from the message and construct the
1341bdb9230aSGarrett D'Amore 	 * scatter/gather list by calling ddi_dma_addr_bind_handle().
1342bdb9230aSGarrett D'Amore 	 */
134398e8d175SSteven Stallion 	error = 0;
1344bdb9230aSGarrett D'Amore 	totlen = 0;
1345bdb9230aSGarrett D'Amore 	bp = mp;
1346bdb9230aSGarrett D'Amore 	bufn = 0;
1347bdb9230aSGarrett D'Amore 	index = start_index = dnetp->tx_current_desc;
1348bdb9230aSGarrett D'Amore 	avail = dnetp->free_desc;
1349bdb9230aSGarrett D'Amore 	while (bp != NULL) {
1350bdb9230aSGarrett D'Amore 		uint_t ncookies;
1351bdb9230aSGarrett D'Amore 		ddi_dma_cookie_t dma_cookie;
1352bdb9230aSGarrett D'Amore 
135398e8d175SSteven Stallion 		mblen = MBLKL(bp);
1354bdb9230aSGarrett D'Amore 
1355bdb9230aSGarrett D'Amore 		if (!mblen) {	/* skip zero-length message blocks */
1356bdb9230aSGarrett D'Amore 			bp = bp->b_cont;
1357bdb9230aSGarrett D'Amore 			continue;
1358bdb9230aSGarrett D'Amore 		}
1359bdb9230aSGarrett D'Amore 
1360bdb9230aSGarrett D'Amore 		retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL,
1361bdb9230aSGarrett D'Amore 		    (caddr_t)bp->b_rptr, mblen,
1362bdb9230aSGarrett D'Amore 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
1363bdb9230aSGarrett D'Amore 		    &dma_cookie, &ncookies);
1364bdb9230aSGarrett D'Amore 
1365bdb9230aSGarrett D'Amore 		switch (retval) {
1366bdb9230aSGarrett D'Amore 		case DDI_DMA_MAPPED:
1367bdb9230aSGarrett D'Amore 			break;		/* everything's fine */
1368bdb9230aSGarrett D'Amore 
1369bdb9230aSGarrett D'Amore 		case DDI_DMA_NORESOURCES:
1370bdb9230aSGarrett D'Amore 			error = 1;	/* allow retry by gld */
1371bdb9230aSGarrett D'Amore 			break;
1372bdb9230aSGarrett D'Amore 
1373bdb9230aSGarrett D'Amore 		case DDI_DMA_NOMAPPING:
1374bdb9230aSGarrett D'Amore 		case DDI_DMA_INUSE:
1375bdb9230aSGarrett D'Amore 		case DDI_DMA_TOOBIG:
1376bdb9230aSGarrett D'Amore 		default:
1377bdb9230aSGarrett D'Amore 			error = 2;	/* error, no retry */
1378bdb9230aSGarrett D'Amore 			break;
1379bdb9230aSGarrett D'Amore 		}
1380bdb9230aSGarrett D'Amore 
1381bdb9230aSGarrett D'Amore 		/*
1382bdb9230aSGarrett D'Amore 		 * we can use two cookies per descriptor (i.e buffer1 and
1383bdb9230aSGarrett D'Amore 		 * buffer2) so we need at least (ncookies+1)/2 descriptors.
1384bdb9230aSGarrett D'Amore 		 */
1385bdb9230aSGarrett D'Amore 		if (((ncookies + 1) >> 1) > dnetp->free_desc) {
1386bdb9230aSGarrett D'Amore 			(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1387bdb9230aSGarrett D'Amore 			error = 1;
1388bdb9230aSGarrett D'Amore 			break;
1389bdb9230aSGarrett D'Amore 		}
1390bdb9230aSGarrett D'Amore 
1391bdb9230aSGarrett D'Amore 		/* setup the descriptors for this data buffer */
1392bdb9230aSGarrett D'Amore 		while (ncookies) {
1393bdb9230aSGarrett D'Amore 			end_index = index;
1394bdb9230aSGarrett D'Amore 			if (bufn % 2) {
1395bdb9230aSGarrett D'Amore 				ring[index].buffer2 =
1396bdb9230aSGarrett D'Amore 				    (uint32_t)dma_cookie.dmac_address;
1397bdb9230aSGarrett D'Amore 				ring[index].desc1.buffer_size2 =
1398bdb9230aSGarrett D'Amore 				    dma_cookie.dmac_size;
1399bdb9230aSGarrett D'Amore 				index = NextTXIndex(index); /* goto next desc */
1400bdb9230aSGarrett D'Amore 			} else {
1401bdb9230aSGarrett D'Amore 				/* initialize the descriptor */
1402bdb9230aSGarrett D'Amore 				ASSERT(ring[index].desc0.own == 0);
1403bdb9230aSGarrett D'Amore 				*(uint32_t *)&ring[index].desc0 = 0;
1404bdb9230aSGarrett D'Amore 				*(uint32_t *)&ring[index].desc1 &=
1405bdb9230aSGarrett D'Amore 				    DNET_END_OF_RING;
1406bdb9230aSGarrett D'Amore 				ring[index].buffer1 =
1407bdb9230aSGarrett D'Amore 				    (uint32_t)dma_cookie.dmac_address;
1408bdb9230aSGarrett D'Amore 				ring[index].desc1.buffer_size1 =
1409bdb9230aSGarrett D'Amore 				    dma_cookie.dmac_size;
1410bdb9230aSGarrett D'Amore 				ring[index].buffer2 = (uint32_t)(0);
1411bdb9230aSGarrett D'Amore 				dnetp->free_desc--;
1412bdb9230aSGarrett D'Amore 				ASSERT(dnetp->free_desc >= 0);
1413bdb9230aSGarrett D'Amore 			}
1414bdb9230aSGarrett D'Amore 			totlen += dma_cookie.dmac_size;
1415bdb9230aSGarrett D'Amore 			bufn++;
1416bdb9230aSGarrett D'Amore 			if (--ncookies)
1417bdb9230aSGarrett D'Amore 				ddi_dma_nextcookie(dnetp->dma_handle_tx,
1418bdb9230aSGarrett D'Amore 				    &dma_cookie);
1419bdb9230aSGarrett D'Amore 		}
1420bdb9230aSGarrett D'Amore 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1421bdb9230aSGarrett D'Amore 		bp = bp->b_cont;
1422bdb9230aSGarrett D'Amore 	}
1423bdb9230aSGarrett D'Amore 
1424bdb9230aSGarrett D'Amore 	if (error == 1) {
1425bdb9230aSGarrett D'Amore 		dnetp->stat_defer++;
1426bdb9230aSGarrett D'Amore 		dnetp->free_desc = avail;
142798e8d175SSteven Stallion 		dnetp->need_tx_update = B_TRUE;
142898e8d175SSteven Stallion 		return (B_FALSE);
1429bdb9230aSGarrett D'Amore 	} else if (error) {
1430bdb9230aSGarrett D'Amore 		dnetp->free_desc = avail;
1431bdb9230aSGarrett D'Amore 		freemsg(mp);
143298e8d175SSteven Stallion 		return (B_TRUE);	/* Drop packet, don't retry */
1433bdb9230aSGarrett D'Amore 	}
1434bdb9230aSGarrett D'Amore 
143598e8d175SSteven Stallion 	if (totlen > ETHERMAX + VLAN_TAGSZ) {
1436bdb9230aSGarrett D'Amore 		cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen);
1437bdb9230aSGarrett D'Amore 		dnetp->free_desc = avail;
1438bdb9230aSGarrett D'Amore 		freemsg(mp);
143998e8d175SSteven Stallion 		return (B_TRUE);	/* Don't repeat this attempt */
1440bdb9230aSGarrett D'Amore 	}
1441bdb9230aSGarrett D'Amore 
1442bdb9230aSGarrett D'Amore 	/*
1443bdb9230aSGarrett D'Amore 	 * Remeber the message buffer pointer to do freemsg() at xmit
1444bdb9230aSGarrett D'Amore 	 * interrupt time.
1445bdb9230aSGarrett D'Amore 	 */
1446bdb9230aSGarrett D'Amore 	dnetp->tx_msgbufp[end_index] = mp;
1447bdb9230aSGarrett D'Amore 
1448bdb9230aSGarrett D'Amore 	/*
1449bdb9230aSGarrett D'Amore 	 * Now set the first/last buffer and own bits
1450bdb9230aSGarrett D'Amore 	 * Since the 21040 looks for these bits set in the
1451bdb9230aSGarrett D'Amore 	 * first buffer, work backwards in multiple buffers.
1452bdb9230aSGarrett D'Amore 	 */
1453bdb9230aSGarrett D'Amore 	ring[end_index].desc1.last_desc = 1;
1454bdb9230aSGarrett D'Amore 	ring[end_index].desc1.int_on_comp = 1;
1455bdb9230aSGarrett D'Amore 	for (index = end_index; index != start_index;
1456bdb9230aSGarrett D'Amore 	    index = PrevTXIndex(index))
1457bdb9230aSGarrett D'Amore 		ring[index].desc0.own = 1;
1458bdb9230aSGarrett D'Amore 	ring[start_index].desc1.first_desc = 1;
1459bdb9230aSGarrett D'Amore 	ring[start_index].desc0.own = 1;
1460bdb9230aSGarrett D'Amore 
1461bdb9230aSGarrett D'Amore 	dnetp->tx_current_desc = NextTXIndex(end_index);
1462bdb9230aSGarrett D'Amore 
1463bdb9230aSGarrett D'Amore 	/*
1464bdb9230aSGarrett D'Amore 	 * Safety check: make sure end-of-ring is set in last desc.
1465bdb9230aSGarrett D'Amore 	 */
1466bdb9230aSGarrett D'Amore 	ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0);
1467bdb9230aSGarrett D'Amore 
146898e8d175SSteven Stallion 	return (B_TRUE);
1469bdb9230aSGarrett D'Amore }
1470bdb9230aSGarrett D'Amore 
1471bdb9230aSGarrett D'Amore /*
147298e8d175SSteven Stallion  *	dnet_intr() -- interrupt from board to inform us that a receive or
1473bdb9230aSGarrett D'Amore  *	transmit has completed.
1474bdb9230aSGarrett D'Amore  */
1475bdb9230aSGarrett D'Amore static uint_t
dnet_intr(caddr_t arg)147698e8d175SSteven Stallion dnet_intr(caddr_t arg)
1477bdb9230aSGarrett D'Amore {
147898e8d175SSteven Stallion 	struct dnetinstance *dnetp = (struct dnetinstance *)arg;
1479bdb9230aSGarrett D'Amore 	uint32_t int_status;
1480bdb9230aSGarrett D'Amore 
1481bdb9230aSGarrett D'Amore 	mutex_enter(&dnetp->intrlock);
148298e8d175SSteven Stallion 
1483bdb9230aSGarrett D'Amore 	if (dnetp->suspended) {
1484bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->intrlock);
1485bdb9230aSGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
1486bdb9230aSGarrett D'Amore 	}
1487bdb9230aSGarrett D'Amore 
1488bdb9230aSGarrett D'Amore 	int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg,
1489bdb9230aSGarrett D'Amore 	    STATUS_REG));
1490bdb9230aSGarrett D'Amore 
1491bdb9230aSGarrett D'Amore 	/*
1492bdb9230aSGarrett D'Amore 	 * If interrupt was not from this board
1493bdb9230aSGarrett D'Amore 	 */
1494bdb9230aSGarrett D'Amore 	if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) {
1495bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->intrlock);
1496bdb9230aSGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
1497bdb9230aSGarrett D'Amore 	}
1498bdb9230aSGarrett D'Amore 
1499bdb9230aSGarrett D'Amore 	dnetp->stat_intr++;
1500bdb9230aSGarrett D'Amore 
1501bdb9230aSGarrett D'Amore 	if (int_status & GPTIMER_INTR) {
1502bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
1503bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR);
1504bdb9230aSGarrett D'Amore 		if (dnetp->timer.cb)
1505bdb9230aSGarrett D'Amore 			dnetp->timer.cb(dnetp);
1506bdb9230aSGarrett D'Amore 		else
1507bdb9230aSGarrett D'Amore 			cmn_err(CE_WARN, "dnet: unhandled timer interrupt");
1508bdb9230aSGarrett D'Amore 	}
1509bdb9230aSGarrett D'Amore 
1510bdb9230aSGarrett D'Amore 	if (int_status & TX_INTR) {
1511bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
1512bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, STATUS_REG), TX_INTR);
1513bdb9230aSGarrett D'Amore 		mutex_enter(&dnetp->txlock);
151498e8d175SSteven Stallion 		if (dnetp->need_tx_update) {
1515bdb9230aSGarrett D'Amore 			mutex_exit(&dnetp->txlock);
1516bdb9230aSGarrett D'Amore 			mutex_exit(&dnetp->intrlock);
151798e8d175SSteven Stallion 			mac_tx_update(dnetp->mac_handle);
1518bdb9230aSGarrett D'Amore 			mutex_enter(&dnetp->intrlock);
1519bdb9230aSGarrett D'Amore 			mutex_enter(&dnetp->txlock);
152098e8d175SSteven Stallion 			dnetp->need_tx_update = B_FALSE;
1521bdb9230aSGarrett D'Amore 		}
1522bdb9230aSGarrett D'Amore 		/* reclaim any xmit descriptors that are completed */
152398e8d175SSteven Stallion 		dnet_reclaim_Tx_desc(dnetp);
1524bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->txlock);
1525bdb9230aSGarrett D'Amore 	}
1526bdb9230aSGarrett D'Amore 
1527bdb9230aSGarrett D'Amore 	/*
1528bdb9230aSGarrett D'Amore 	 * Check if receive interrupt bit is set
1529bdb9230aSGarrett D'Amore 	 */
1530bdb9230aSGarrett D'Amore 	if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) {
1531bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
1532bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, STATUS_REG),
1533bdb9230aSGarrett D'Amore 		    int_status & (RX_INTR | RX_UNAVAIL_INTR));
153498e8d175SSteven Stallion 		dnet_getp(dnetp);
1535bdb9230aSGarrett D'Amore 	}
1536bdb9230aSGarrett D'Amore 
1537bdb9230aSGarrett D'Amore 	if (int_status & ABNORMAL_INTR_SUMM) {
1538bdb9230aSGarrett D'Amore 		/*
1539bdb9230aSGarrett D'Amore 		 * Check for system error
1540bdb9230aSGarrett D'Amore 		 */
1541bdb9230aSGarrett D'Amore 		if (int_status & SYS_ERR) {
1542bdb9230aSGarrett D'Amore 			if ((int_status & SYS_ERR_BITS) == MASTER_ABORT)
1543bdb9230aSGarrett D'Amore 				cmn_err(CE_WARN, "DNET: Bus Master Abort");
1544bdb9230aSGarrett D'Amore 			if ((int_status & SYS_ERR_BITS) == TARGET_ABORT)
1545bdb9230aSGarrett D'Amore 				cmn_err(CE_WARN, "DNET: Bus Target Abort");
1546bdb9230aSGarrett D'Amore 			if ((int_status & SYS_ERR_BITS) == PARITY_ERROR)
1547bdb9230aSGarrett D'Amore 				cmn_err(CE_WARN, "DNET: Parity error");
1548bdb9230aSGarrett D'Amore 		}
1549bdb9230aSGarrett D'Amore 
1550bdb9230aSGarrett D'Amore 		/*
1551bdb9230aSGarrett D'Amore 		 * If the jabber has timed out then reset the chip
1552bdb9230aSGarrett D'Amore 		 */
1553bdb9230aSGarrett D'Amore 		if (int_status & TX_JABBER_TIMEOUT)
1554bdb9230aSGarrett D'Amore 			cmn_err(CE_WARN, "DNET: Jabber timeout.");
1555bdb9230aSGarrett D'Amore 
1556bdb9230aSGarrett D'Amore 		/*
1557bdb9230aSGarrett D'Amore 		 * If an underflow has occurred, reset the chip
1558bdb9230aSGarrett D'Amore 		 */
1559bdb9230aSGarrett D'Amore 		if (int_status & TX_UNDERFLOW)
1560bdb9230aSGarrett D'Amore 			cmn_err(CE_WARN, "DNET: Tx Underflow.");
1561bdb9230aSGarrett D'Amore 
1562bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1563bdb9230aSGarrett D'Amore 		if (dnetdebug & DNETINT)
1564bdb9230aSGarrett D'Amore 			cmn_err(CE_NOTE, "Trying to reset...");
1565bdb9230aSGarrett D'Amore #endif
156698e8d175SSteven Stallion 		dnet_reset_board(dnetp);
156798e8d175SSteven Stallion 		dnet_init_board(dnetp);
1568bdb9230aSGarrett D'Amore 		/* XXX function return value ignored */
156998e8d175SSteven Stallion 		(void) dnet_start(dnetp);
1570bdb9230aSGarrett D'Amore 	}
1571bdb9230aSGarrett D'Amore 
1572bdb9230aSGarrett D'Amore 	/*
157398e8d175SSteven Stallion 	 * Enable the interrupts. Enable xmit interrupt in case we are
1574bdb9230aSGarrett D'Amore 	 * running out of free descriptors or if there are packets
1575bdb9230aSGarrett D'Amore 	 * in the queue waiting to be transmitted.
1576bdb9230aSGarrett D'Amore 	 */
157798e8d175SSteven Stallion 	enable_interrupts(dnetp);
1578bdb9230aSGarrett D'Amore 	mutex_exit(&dnetp->intrlock);
1579bdb9230aSGarrett D'Amore 	return (DDI_INTR_CLAIMED);	/* Indicate it was our interrupt */
1580bdb9230aSGarrett D'Amore }
1581bdb9230aSGarrett D'Amore 
1582bdb9230aSGarrett D'Amore static void
dnet_getp(struct dnetinstance * dnetp)158398e8d175SSteven Stallion dnet_getp(struct dnetinstance *dnetp)
1584bdb9230aSGarrett D'Amore {
1585bdb9230aSGarrett D'Amore 	int packet_length, index;
1586bdb9230aSGarrett D'Amore 	mblk_t	*mp;
1587bdb9230aSGarrett D'Amore 	caddr_t	virtual_address;
1588bdb9230aSGarrett D'Amore 	struct	rx_desc_type *desc = dnetp->rx_desc;
1589bdb9230aSGarrett D'Amore 	int marker = dnetp->rx_current_desc;
1590bdb9230aSGarrett D'Amore 	int misses;
1591bdb9230aSGarrett D'Amore 
1592bdb9230aSGarrett D'Amore 	if (!dnetp->overrun_workaround) {
1593bdb9230aSGarrett D'Amore 		/*
1594bdb9230aSGarrett D'Amore 		 * If the workaround is not in place, we must still update
1595bdb9230aSGarrett D'Amore 		 * the missed frame statistic from the on-chip counter.
1596bdb9230aSGarrett D'Amore 		 */
1597bdb9230aSGarrett D'Amore 		misses = ddi_get32(dnetp->io_handle,
1598bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, MISSED_FRAME_REG));
1599bdb9230aSGarrett D'Amore 		dnetp->stat_missed += (misses & MISSED_FRAME_MASK);
1600bdb9230aSGarrett D'Amore 	}
1601bdb9230aSGarrett D'Amore 
1602bdb9230aSGarrett D'Amore 	/* While host owns the current descriptor */
1603bdb9230aSGarrett D'Amore 	while (!(desc[dnetp->rx_current_desc].desc0.own)) {
1604bdb9230aSGarrett D'Amore 		struct free_ptr *frp;
1605bdb9230aSGarrett D'Amore 		caddr_t newbuf;
1606bdb9230aSGarrett D'Amore 		struct rbuf_list *rp;
1607bdb9230aSGarrett D'Amore 
1608bdb9230aSGarrett D'Amore 		index = dnetp->rx_current_desc;
1609bdb9230aSGarrett D'Amore 		ASSERT(desc[index].desc0.first_desc != 0);
1610bdb9230aSGarrett D'Amore 
1611bdb9230aSGarrett D'Amore 		/*
1612bdb9230aSGarrett D'Amore 		 * DMA overrun errata from DEC: avoid possible bus hangs
1613bdb9230aSGarrett D'Amore 		 * and data corruption
1614bdb9230aSGarrett D'Amore 		 */
1615bdb9230aSGarrett D'Amore 		if (dnetp->overrun_workaround &&
1616bdb9230aSGarrett D'Amore 		    marker == dnetp->rx_current_desc) {
1617bdb9230aSGarrett D'Amore 			int opn;
1618bdb9230aSGarrett D'Amore 			do {
1619bdb9230aSGarrett D'Amore 				marker = (marker+1) % dnetp->max_rx_desc;
1620bdb9230aSGarrett D'Amore 			} while (!(dnetp->rx_desc[marker].desc0.own) &&
1621bdb9230aSGarrett D'Amore 			    marker != index);
1622bdb9230aSGarrett D'Amore 
1623bdb9230aSGarrett D'Amore 			misses = ddi_get32(dnetp->io_handle,
1624bdb9230aSGarrett D'Amore 			    REG32(dnetp->io_reg, MISSED_FRAME_REG));
1625bdb9230aSGarrett D'Amore 			dnetp->stat_missed +=
1626bdb9230aSGarrett D'Amore 			    (misses & MISSED_FRAME_MASK);
1627bdb9230aSGarrett D'Amore 			if (misses & OVERFLOW_COUNTER_MASK) {
1628bdb9230aSGarrett D'Amore 				/*
1629bdb9230aSGarrett D'Amore 				 * Overflow(s) have occurred : stop receiver,
1630bdb9230aSGarrett D'Amore 				 * and wait until in stopped state
1631bdb9230aSGarrett D'Amore 				 */
1632bdb9230aSGarrett D'Amore 				opn = ddi_get32(dnetp->io_handle,
1633bdb9230aSGarrett D'Amore 				    REG32(dnetp->io_reg, OPN_MODE_REG));
1634bdb9230aSGarrett D'Amore 				ddi_put32(dnetp->io_handle,
1635bdb9230aSGarrett D'Amore 				    REG32(dnetp->io_reg, OPN_MODE_REG),
1636bdb9230aSGarrett D'Amore 				    opn & ~(START_RECEIVE));
1637bdb9230aSGarrett D'Amore 
1638bdb9230aSGarrett D'Amore 				do {
1639bdb9230aSGarrett D'Amore 					drv_usecwait(10);
1640bdb9230aSGarrett D'Amore 				} while ((ddi_get32(dnetp->io_handle,
1641bdb9230aSGarrett D'Amore 				    REG32(dnetp->io_reg, STATUS_REG)) &
1642bdb9230aSGarrett D'Amore 				    RECEIVE_PROCESS_STATE) != 0);
1643bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1644bdb9230aSGarrett D'Amore 				if (dnetdebug & DNETRECV)
1645bdb9230aSGarrett D'Amore 					cmn_err(CE_CONT, "^*");
1646bdb9230aSGarrett D'Amore #endif
1647bdb9230aSGarrett D'Amore 				/* Discard probably corrupt frames */
1648bdb9230aSGarrett D'Amore 				while (!(dnetp->rx_desc[index].desc0.own)) {
1649bdb9230aSGarrett D'Amore 					dnetp->rx_desc[index].desc0.own = 1;
1650bdb9230aSGarrett D'Amore 					index = (index+1) % dnetp->max_rx_desc;
1651bdb9230aSGarrett D'Amore 					dnetp->stat_missed++;
1652bdb9230aSGarrett D'Amore 				}
1653bdb9230aSGarrett D'Amore 
1654bdb9230aSGarrett D'Amore 				/* restart the receiver */
1655bdb9230aSGarrett D'Amore 				opn = ddi_get32(dnetp->io_handle,
1656bdb9230aSGarrett D'Amore 				    REG32(dnetp->io_reg, OPN_MODE_REG));
1657bdb9230aSGarrett D'Amore 				ddi_put32(dnetp->io_handle,
1658bdb9230aSGarrett D'Amore 				    REG32(dnetp->io_reg, OPN_MODE_REG),
1659bdb9230aSGarrett D'Amore 				    opn | START_RECEIVE);
1660bdb9230aSGarrett D'Amore 				marker = dnetp->rx_current_desc = index;
1661bdb9230aSGarrett D'Amore 				continue;
1662bdb9230aSGarrett D'Amore 			}
1663bdb9230aSGarrett D'Amore 			/*
1664bdb9230aSGarrett D'Amore 			 * At this point, we know that all packets before
1665bdb9230aSGarrett D'Amore 			 * "marker" were received before a dma overrun occurred
1666bdb9230aSGarrett D'Amore 			 */
1667bdb9230aSGarrett D'Amore 		}
1668bdb9230aSGarrett D'Amore 
1669bdb9230aSGarrett D'Amore 		/*
1670bdb9230aSGarrett D'Amore 		 * If we get an oversized packet it could span multiple
1671bdb9230aSGarrett D'Amore 		 * descriptors.  If this happens an error bit should be set.
1672bdb9230aSGarrett D'Amore 		 */
1673bdb9230aSGarrett D'Amore 		while (desc[index].desc0.last_desc == 0) {
1674bdb9230aSGarrett D'Amore 			index = (index + 1) % dnetp->max_rx_desc;
1675bdb9230aSGarrett D'Amore 			if (desc[index].desc0.own)
1676bdb9230aSGarrett D'Amore 				return;	/* not done receiving large packet */
1677bdb9230aSGarrett D'Amore 		}
1678bdb9230aSGarrett D'Amore 		while (dnetp->rx_current_desc != index) {
1679bdb9230aSGarrett D'Amore 			desc[dnetp->rx_current_desc].desc0.own = 1;
1680bdb9230aSGarrett D'Amore 			dnetp->rx_current_desc =
1681bdb9230aSGarrett D'Amore 			    (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc;
1682bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1683bdb9230aSGarrett D'Amore 			if (dnetdebug & DNETRECV)
1684bdb9230aSGarrett D'Amore 				cmn_err(CE_WARN, "dnet: received large packet");
1685bdb9230aSGarrett D'Amore #endif
1686bdb9230aSGarrett D'Amore 		}
1687bdb9230aSGarrett D'Amore 
1688bdb9230aSGarrett D'Amore 		packet_length = desc[index].desc0.frame_len;
1689bdb9230aSGarrett D'Amore 
1690bdb9230aSGarrett D'Amore 		/*
1691bdb9230aSGarrett D'Amore 		 * Remove CRC from received data. This is an artefact of the
1692bdb9230aSGarrett D'Amore 		 * 21x4x chip and should not be passed higher up the network
1693bdb9230aSGarrett D'Amore 		 * stack.
1694bdb9230aSGarrett D'Amore 		 */
1695bdb9230aSGarrett D'Amore 		packet_length -= ETHERFCSL;
1696bdb9230aSGarrett D'Amore 
1697bdb9230aSGarrett D'Amore 		/* get the virtual address of the packet received */
1698bdb9230aSGarrett D'Amore 		virtual_address =
1699bdb9230aSGarrett D'Amore 		    dnetp->rx_buf_vaddr[index];
1700bdb9230aSGarrett D'Amore 
1701bdb9230aSGarrett D'Amore 		/*
1702bdb9230aSGarrett D'Amore 		 * If no packet errors then do:
1703bdb9230aSGarrett D'Amore 		 *	1. Allocate a new receive buffer so that we can
1704bdb9230aSGarrett D'Amore 		 *	   use the current buffer as streams buffer to
1705bdb9230aSGarrett D'Amore 		 *	   avoid bcopy.
1706bdb9230aSGarrett D'Amore 		 *	2. If we got a new receive buffer then allocate
1707bdb9230aSGarrett D'Amore 		 *	   an mblk using desballoc().
1708bdb9230aSGarrett D'Amore 		 *	3. Otherwise use the mblk from allocb() and do
1709bdb9230aSGarrett D'Amore 		 *	   the bcopy.
1710bdb9230aSGarrett D'Amore 		 */
1711bdb9230aSGarrett D'Amore 		frp = NULL;
1712bdb9230aSGarrett D'Amore 		rp = NULL;
1713bdb9230aSGarrett D'Amore 		newbuf = NULL;
1714bdb9230aSGarrett D'Amore 		mp = NULL;
171598e8d175SSteven Stallion 		if (!desc[index].desc0.err_summary ||
171698e8d175SSteven Stallion 		    (desc[index].desc0.frame2long &&
171798e8d175SSteven Stallion 		    packet_length < rx_buf_size)) {
1718bdb9230aSGarrett D'Amore 			ASSERT(packet_length < rx_buf_size);
1719bdb9230aSGarrett D'Amore 			/*
1720bdb9230aSGarrett D'Amore 			 * Allocate another receive buffer for this descriptor.
1721bdb9230aSGarrett D'Amore 			 * If we fail to allocate then we do the normal bcopy.
1722bdb9230aSGarrett D'Amore 			 */
1723bdb9230aSGarrett D'Amore 			rp = dnet_rbuf_alloc(dnetp->devinfo, 0);
1724bdb9230aSGarrett D'Amore 			if (rp != NULL) {
1725bdb9230aSGarrett D'Amore 				newbuf = rp->rbuf_vaddr;
1726bdb9230aSGarrett D'Amore 				frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP);
1727bdb9230aSGarrett D'Amore 				if (frp != NULL) {
1728bdb9230aSGarrett D'Amore 					frp->free_rtn.free_func =
1729bdb9230aSGarrett D'Amore 					    dnet_freemsg_buf;
1730bdb9230aSGarrett D'Amore 					frp->free_rtn.free_arg = (char *)frp;
1731bdb9230aSGarrett D'Amore 					frp->buf = virtual_address;
1732bdb9230aSGarrett D'Amore 					mp = desballoc(
1733bdb9230aSGarrett D'Amore 					    (uchar_t *)virtual_address,
1734bdb9230aSGarrett D'Amore 					    packet_length, 0, &frp->free_rtn);
1735bdb9230aSGarrett D'Amore 					if (mp == NULL) {
1736bdb9230aSGarrett D'Amore 						kmem_free(frp, sizeof (*frp));
1737bdb9230aSGarrett D'Amore 						dnet_rbuf_free((caddr_t)newbuf);
1738bdb9230aSGarrett D'Amore 						frp = NULL;
1739bdb9230aSGarrett D'Amore 						newbuf = NULL;
1740bdb9230aSGarrett D'Amore 					}
1741bdb9230aSGarrett D'Amore 				}
1742bdb9230aSGarrett D'Amore 			}
1743bdb9230aSGarrett D'Amore 			if (mp == NULL) {
1744bdb9230aSGarrett D'Amore 				if (newbuf != NULL)
1745bdb9230aSGarrett D'Amore 					dnet_rbuf_free((caddr_t)newbuf);
1746bdb9230aSGarrett D'Amore 				mp = allocb(packet_length, 0);
1747bdb9230aSGarrett D'Amore 			}
1748bdb9230aSGarrett D'Amore 		}
1749bdb9230aSGarrett D'Amore 
175098e8d175SSteven Stallion 		if ((desc[index].desc0.err_summary &&
175198e8d175SSteven Stallion 		    packet_length >= rx_buf_size) || mp == NULL) {
1752bdb9230aSGarrett D'Amore 
1753bdb9230aSGarrett D'Amore 			/* Update gld statistics */
1754bdb9230aSGarrett D'Amore 			if (desc[index].desc0.err_summary)
175598e8d175SSteven Stallion 				update_rx_stats(dnetp, index);
1756bdb9230aSGarrett D'Amore 			else
1757bdb9230aSGarrett D'Amore 				dnetp->stat_norcvbuf++;
1758bdb9230aSGarrett D'Amore 
1759bdb9230aSGarrett D'Amore 			/*
1760bdb9230aSGarrett D'Amore 			 * Reset ownership of the descriptor.
1761bdb9230aSGarrett D'Amore 			 */
1762bdb9230aSGarrett D'Amore 			desc[index].desc0.own = 1;
1763bdb9230aSGarrett D'Amore 			dnetp->rx_current_desc =
1764bdb9230aSGarrett D'Amore 			    (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1765bdb9230aSGarrett D'Amore 
1766bdb9230aSGarrett D'Amore 			/* Demand receive polling by the chip */
1767bdb9230aSGarrett D'Amore 			ddi_put32(dnetp->io_handle,
1768bdb9230aSGarrett D'Amore 			    REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1769bdb9230aSGarrett D'Amore 
1770bdb9230aSGarrett D'Amore 			continue;
1771bdb9230aSGarrett D'Amore 		}
1772bdb9230aSGarrett D'Amore 
1773bdb9230aSGarrett D'Amore 		if (newbuf != NULL) {
1774bdb9230aSGarrett D'Amore 			uint32_t end_paddr;
1775bdb9230aSGarrett D'Amore 			/* attach the new buffer to the rx descriptor */
1776bdb9230aSGarrett D'Amore 			dnetp->rx_buf_vaddr[index] = newbuf;
1777bdb9230aSGarrett D'Amore 			dnetp->rx_buf_paddr[index] = rp->rbuf_paddr;
1778bdb9230aSGarrett D'Amore 			desc[index].buffer1 = rp->rbuf_paddr;
1779bdb9230aSGarrett D'Amore 			desc[index].desc1.buffer_size1 = rx_buf_size;
1780bdb9230aSGarrett D'Amore 			desc[index].desc1.buffer_size2 = 0;
1781bdb9230aSGarrett D'Amore 			end_paddr = rp->rbuf_endpaddr;
1782bdb9230aSGarrett D'Amore 			if ((desc[index].buffer1 & ~dnetp->pgmask) !=
1783bdb9230aSGarrett D'Amore 			    (end_paddr & ~dnetp->pgmask)) {
1784bdb9230aSGarrett D'Amore 				/* discontiguous */
1785bdb9230aSGarrett D'Amore 				desc[index].buffer2 = end_paddr&~dnetp->pgmask;
1786bdb9230aSGarrett D'Amore 				desc[index].desc1.buffer_size2 =
1787bdb9230aSGarrett D'Amore 				    (end_paddr & dnetp->pgmask) + 1;
1788bdb9230aSGarrett D'Amore 				desc[index].desc1.buffer_size1 =
1789bdb9230aSGarrett D'Amore 				    rx_buf_size-desc[index].desc1.buffer_size2;
1790bdb9230aSGarrett D'Amore 			}
1791bdb9230aSGarrett D'Amore 		} else {
1792bdb9230aSGarrett D'Amore 			/* couldn't allocate another buffer; copy the data */
1793bdb9230aSGarrett D'Amore 			BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr,
1794bdb9230aSGarrett D'Amore 			    packet_length);
1795bdb9230aSGarrett D'Amore 		}
1796bdb9230aSGarrett D'Amore 
1797bdb9230aSGarrett D'Amore 		mp->b_wptr += packet_length;
1798bdb9230aSGarrett D'Amore 
1799bdb9230aSGarrett D'Amore 		desc[dnetp->rx_current_desc].desc0.own = 1;
1800bdb9230aSGarrett D'Amore 
1801bdb9230aSGarrett D'Amore 		/*
1802bdb9230aSGarrett D'Amore 		 * Increment receive desc index. This is for the scan of
1803bdb9230aSGarrett D'Amore 		 * next packet
1804bdb9230aSGarrett D'Amore 		 */
1805bdb9230aSGarrett D'Amore 		dnetp->rx_current_desc =
1806bdb9230aSGarrett D'Amore 		    (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1807bdb9230aSGarrett D'Amore 
1808bdb9230aSGarrett D'Amore 		/* Demand polling by chip */
1809bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
1810bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1811bdb9230aSGarrett D'Amore 
1812bdb9230aSGarrett D'Amore 		/* send the packet upstream */
1813bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->intrlock);
181498e8d175SSteven Stallion 		mac_rx(dnetp->mac_handle, NULL, mp);
1815bdb9230aSGarrett D'Amore 		mutex_enter(&dnetp->intrlock);
1816bdb9230aSGarrett D'Amore 	}
1817bdb9230aSGarrett D'Amore }
1818bdb9230aSGarrett D'Amore /*
1819bdb9230aSGarrett D'Amore  * Function to update receive statistics
1820bdb9230aSGarrett D'Amore  */
1821bdb9230aSGarrett D'Amore static void
update_rx_stats(struct dnetinstance * dnetp,int index)182298e8d175SSteven Stallion update_rx_stats(struct dnetinstance *dnetp, int index)
1823bdb9230aSGarrett D'Amore {
1824bdb9230aSGarrett D'Amore 	struct rx_desc_type *descp = &(dnetp->rx_desc[index]);
1825bdb9230aSGarrett D'Amore 
1826bdb9230aSGarrett D'Amore 	/*
1827bdb9230aSGarrett D'Amore 	 * Update gld statistics
1828bdb9230aSGarrett D'Amore 	 */
1829bdb9230aSGarrett D'Amore 	dnetp->stat_errrcv++;
1830bdb9230aSGarrett D'Amore 
1831bdb9230aSGarrett D'Amore 	if (descp->desc0.overflow)	{
1832bdb9230aSGarrett D'Amore 		/* FIFO Overrun */
1833bdb9230aSGarrett D'Amore 		dnetp->stat_overflow++;
1834bdb9230aSGarrett D'Amore 	}
1835bdb9230aSGarrett D'Amore 
1836bdb9230aSGarrett D'Amore 	if (descp->desc0.collision) {
1837bdb9230aSGarrett D'Amore 		/*EMPTY*/
1838bdb9230aSGarrett D'Amore 		/* Late Colllision on receive */
1839bdb9230aSGarrett D'Amore 		/* no appropriate counter */
1840bdb9230aSGarrett D'Amore 	}
1841bdb9230aSGarrett D'Amore 
1842bdb9230aSGarrett D'Amore 	if (descp->desc0.crc) {
1843bdb9230aSGarrett D'Amore 		/* CRC Error */
1844bdb9230aSGarrett D'Amore 		dnetp->stat_crc++;
1845bdb9230aSGarrett D'Amore 	}
1846bdb9230aSGarrett D'Amore 
1847bdb9230aSGarrett D'Amore 	if (descp->desc0.runt_frame) {
1848bdb9230aSGarrett D'Amore 		/* Runt Error */
1849bdb9230aSGarrett D'Amore 		dnetp->stat_short++;
1850bdb9230aSGarrett D'Amore 	}
1851bdb9230aSGarrett D'Amore 
1852bdb9230aSGarrett D'Amore 	if (descp->desc0.desc_err) {
1853bdb9230aSGarrett D'Amore 		/*EMPTY*/
1854bdb9230aSGarrett D'Amore 		/* Not enough receive descriptors */
185598e8d175SSteven Stallion 		/* This condition is accounted in dnet_intr() */
1856bdb9230aSGarrett D'Amore 	}
1857bdb9230aSGarrett D'Amore 
1858bdb9230aSGarrett D'Amore 	if (descp->desc0.frame2long) {
1859bdb9230aSGarrett D'Amore 		dnetp->stat_frame++;
1860bdb9230aSGarrett D'Amore 	}
1861bdb9230aSGarrett D'Amore }
1862bdb9230aSGarrett D'Amore 
1863bdb9230aSGarrett D'Amore /*
1864bdb9230aSGarrett D'Amore  * Function to update transmit statistics
1865bdb9230aSGarrett D'Amore  */
1866bdb9230aSGarrett D'Amore static void
update_tx_stats(struct dnetinstance * dnetp,int index)186798e8d175SSteven Stallion update_tx_stats(struct dnetinstance *dnetp, int index)
1868bdb9230aSGarrett D'Amore {
1869bdb9230aSGarrett D'Amore 	struct tx_desc_type *descp = &(dnetp->tx_desc[index]);
1870bdb9230aSGarrett D'Amore 	int	fd;
1871bdb9230aSGarrett D'Amore 	media_block_t	*block = dnetp->selected_media_block;
1872bdb9230aSGarrett D'Amore 
1873bdb9230aSGarrett D'Amore 
1874bdb9230aSGarrett D'Amore 	/* Update gld statistics */
1875bdb9230aSGarrett D'Amore 	dnetp->stat_errxmt++;
1876bdb9230aSGarrett D'Amore 
1877bdb9230aSGarrett D'Amore 	/* If we're in full-duplex don't count collisions or carrier loss. */
1878bdb9230aSGarrett D'Amore 	if (dnetp->mii_up) {
1879bdb9230aSGarrett D'Amore 		fd = dnetp->mii_duplex;
1880bdb9230aSGarrett D'Amore 	} else {
1881bdb9230aSGarrett D'Amore 		/* Rely on media code */
1882bdb9230aSGarrett D'Amore 		fd = block->media_code == MEDIA_TP_FD ||
1883bdb9230aSGarrett D'Amore 		    block->media_code == MEDIA_SYM_SCR_FD;
1884bdb9230aSGarrett D'Amore 	}
1885bdb9230aSGarrett D'Amore 
1886bdb9230aSGarrett D'Amore 	if (descp->desc0.collision_count && !fd) {
1887bdb9230aSGarrett D'Amore 		dnetp->stat_collisions += descp->desc0.collision_count;
1888bdb9230aSGarrett D'Amore 	}
1889bdb9230aSGarrett D'Amore 
1890bdb9230aSGarrett D'Amore 	if (descp->desc0.late_collision && !fd) {
1891bdb9230aSGarrett D'Amore 		dnetp->stat_xmtlatecoll++;
1892bdb9230aSGarrett D'Amore 	}
1893bdb9230aSGarrett D'Amore 
1894bdb9230aSGarrett D'Amore 	if (descp->desc0.excess_collision && !fd) {
1895bdb9230aSGarrett D'Amore 		dnetp->stat_excoll++;
1896bdb9230aSGarrett D'Amore 	}
1897bdb9230aSGarrett D'Amore 
1898bdb9230aSGarrett D'Amore 	if (descp->desc0.underflow) {
1899bdb9230aSGarrett D'Amore 		dnetp->stat_underflow++;
1900bdb9230aSGarrett D'Amore 	}
1901bdb9230aSGarrett D'Amore 
1902bdb9230aSGarrett D'Amore #if 0
1903bdb9230aSGarrett D'Amore 	if (descp->desc0.tx_jabber_to) {
1904bdb9230aSGarrett D'Amore 		/* no appropriate counter */
1905bdb9230aSGarrett D'Amore 	}
1906bdb9230aSGarrett D'Amore #endif
1907bdb9230aSGarrett D'Amore 
1908bdb9230aSGarrett D'Amore 	if (descp->desc0.carrier_loss && !fd) {
1909bdb9230aSGarrett D'Amore 		dnetp->stat_nocarrier++;
1910bdb9230aSGarrett D'Amore 	}
1911bdb9230aSGarrett D'Amore 
1912bdb9230aSGarrett D'Amore 	if (descp->desc0.no_carrier && !fd) {
1913bdb9230aSGarrett D'Amore 		dnetp->stat_nocarrier++;
1914bdb9230aSGarrett D'Amore 	}
1915bdb9230aSGarrett D'Amore }
1916bdb9230aSGarrett D'Amore 
1917bdb9230aSGarrett D'Amore /*
1918bdb9230aSGarrett D'Amore  *	========== Media Selection Setup Routines ==========
1919bdb9230aSGarrett D'Amore  */
1920bdb9230aSGarrett D'Amore 
1921bdb9230aSGarrett D'Amore 
1922bdb9230aSGarrett D'Amore static void
write_gpr(struct dnetinstance * dnetp,uint32_t val)1923bdb9230aSGarrett D'Amore write_gpr(struct dnetinstance *dnetp, uint32_t val)
1924bdb9230aSGarrett D'Amore {
1925bdb9230aSGarrett D'Amore #ifdef DEBUG
1926bdb9230aSGarrett D'Amore 	if (dnetdebug & DNETREGCFG)
1927bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "GPR: %x", val);
1928bdb9230aSGarrett D'Amore #endif
1929bdb9230aSGarrett D'Amore 	switch (dnetp->board_type) {
1930bdb9230aSGarrett D'Amore 	case DEVICE_ID_21143:
1931bdb9230aSGarrett D'Amore 		/* Set the correct bit for a control write */
1932bdb9230aSGarrett D'Amore 		if (val & GPR_CONTROL_WRITE)
1933bdb9230aSGarrett D'Amore 			val |= CWE_21143, val &= ~GPR_CONTROL_WRITE;
1934bdb9230aSGarrett D'Amore 		/* Write to upper half of CSR15 */
1935bdb9230aSGarrett D'Amore 		dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16);
1936bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
1937bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia);
1938bdb9230aSGarrett D'Amore 		break;
1939bdb9230aSGarrett D'Amore 	default:
1940bdb9230aSGarrett D'Amore 		/* Set the correct bit for a control write */
1941bdb9230aSGarrett D'Amore 		if (val & GPR_CONTROL_WRITE)
1942bdb9230aSGarrett D'Amore 			val |= CWE_21140, val &= ~GPR_CONTROL_WRITE;
1943bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val);
1944bdb9230aSGarrett D'Amore 		break;
1945bdb9230aSGarrett D'Amore 	}
1946bdb9230aSGarrett D'Amore }
1947bdb9230aSGarrett D'Amore 
1948bdb9230aSGarrett D'Amore static uint32_t
read_gpr(struct dnetinstance * dnetp)1949bdb9230aSGarrett D'Amore read_gpr(struct dnetinstance *dnetp)
1950bdb9230aSGarrett D'Amore {
1951bdb9230aSGarrett D'Amore 	switch (dnetp->board_type) {
1952bdb9230aSGarrett D'Amore 	case DEVICE_ID_21143:
1953bdb9230aSGarrett D'Amore 		/* Read upper half of CSR15 */
1954bdb9230aSGarrett D'Amore 		return (ddi_get32(dnetp->io_handle,
1955bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16);
1956bdb9230aSGarrett D'Amore 	default:
1957bdb9230aSGarrett D'Amore 		return (ddi_get32(dnetp->io_handle,
1958bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, GP_REG)));
1959bdb9230aSGarrett D'Amore 	}
1960bdb9230aSGarrett D'Amore }
1961bdb9230aSGarrett D'Amore 
1962bdb9230aSGarrett D'Amore static void
set_gpr(struct dnetinstance * dnetp)196398e8d175SSteven Stallion set_gpr(struct dnetinstance *dnetp)
1964bdb9230aSGarrett D'Amore {
1965bdb9230aSGarrett D'Amore 	uint32_t *sequence;
1966bdb9230aSGarrett D'Amore 	int len;
1967bdb9230aSGarrett D'Amore 	LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
1968bdb9230aSGarrett D'Amore 	media_block_t *block = dnetp->selected_media_block;
1969bdb9230aSGarrett D'Amore 	int i;
1970bdb9230aSGarrett D'Amore 
1971bdb9230aSGarrett D'Amore 	if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo,
1972bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence,
1973bdb9230aSGarrett D'Amore 	    &len) == DDI_PROP_SUCCESS) {
1974bdb9230aSGarrett D'Amore 		for (i = 0; i < len / sizeof (uint32_t); i++)
1975bdb9230aSGarrett D'Amore 			write_gpr(dnetp, sequence[i]);
1976bdb9230aSGarrett D'Amore 		kmem_free(sequence, len);
1977bdb9230aSGarrett D'Amore 	} else {
1978bdb9230aSGarrett D'Amore 		/*
1979bdb9230aSGarrett D'Amore 		 * Write the reset sequence if this is the first time this
1980bdb9230aSGarrett D'Amore 		 * block has been selected.
1981bdb9230aSGarrett D'Amore 		 */
1982bdb9230aSGarrett D'Amore 		if (block->rstseqlen) {
1983bdb9230aSGarrett D'Amore 			for (i = 0; i < block->rstseqlen; i++)
1984bdb9230aSGarrett D'Amore 				write_gpr(dnetp, block->rstseq[i]);
1985bdb9230aSGarrett D'Amore 			/*
1986bdb9230aSGarrett D'Amore 			 * XXX Legacy blocks do not have reset sequences, so the
1987bdb9230aSGarrett D'Amore 			 * static blocks will never be modified by this
1988bdb9230aSGarrett D'Amore 			 */
1989bdb9230aSGarrett D'Amore 			block->rstseqlen = 0;
1990bdb9230aSGarrett D'Amore 		}
1991bdb9230aSGarrett D'Amore 		if (leaf->gpr)
1992bdb9230aSGarrett D'Amore 			write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE);
1993bdb9230aSGarrett D'Amore 
1994bdb9230aSGarrett D'Amore 		/* write GPR sequence each time */
1995bdb9230aSGarrett D'Amore 		for (i = 0; i < block->gprseqlen; i++)
1996bdb9230aSGarrett D'Amore 			write_gpr(dnetp, block->gprseq[i]);
1997bdb9230aSGarrett D'Amore 	}
1998bdb9230aSGarrett D'Amore 
1999bdb9230aSGarrett D'Amore 	/* This has possibly caused a PHY to reset.  Let MII know */
2000bdb9230aSGarrett D'Amore 	if (dnetp->phyaddr != -1)
2001bdb9230aSGarrett D'Amore 		/* XXX function return value ignored */
2002bdb9230aSGarrett D'Amore 		(void) mii_sync(dnetp->mii, dnetp->phyaddr);
2003bdb9230aSGarrett D'Amore 	drv_usecwait(5);
2004bdb9230aSGarrett D'Amore }
2005bdb9230aSGarrett D'Amore 
2006bdb9230aSGarrett D'Amore /* set_opr() - must be called with intrlock held */
2007bdb9230aSGarrett D'Amore 
2008bdb9230aSGarrett D'Amore static void
set_opr(struct dnetinstance * dnetp)200998e8d175SSteven Stallion set_opr(struct dnetinstance *dnetp)
2010bdb9230aSGarrett D'Amore {
2011bdb9230aSGarrett D'Amore 	uint32_t fd, mb1, sf;
2012bdb9230aSGarrett D'Amore 
2013bdb9230aSGarrett D'Amore 	int		opnmode_len;
2014bdb9230aSGarrett D'Amore 	uint32_t val;
2015bdb9230aSGarrett D'Amore 	media_block_t *block = dnetp->selected_media_block;
2016bdb9230aSGarrett D'Amore 
2017bdb9230aSGarrett D'Amore 	ASSERT(block);
2018bdb9230aSGarrett D'Amore 
2019bdb9230aSGarrett D'Amore 	/* Check for custom "opnmode_reg" property */
2020bdb9230aSGarrett D'Amore 	opnmode_len = sizeof (val);
2021bdb9230aSGarrett D'Amore 	if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo,
2022bdb9230aSGarrett D'Amore 	    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg",
2023bdb9230aSGarrett D'Amore 	    (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS)
2024bdb9230aSGarrett D'Amore 		opnmode_len = 0;
2025bdb9230aSGarrett D'Amore 
2026bdb9230aSGarrett D'Amore 	/* Some bits exist only on 21140 and greater */
2027bdb9230aSGarrett D'Amore 	if (dnetp->board_type != DEVICE_ID_21040 &&
2028bdb9230aSGarrett D'Amore 	    dnetp->board_type != DEVICE_ID_21041) {
2029bdb9230aSGarrett D'Amore 		mb1 = OPN_REG_MB1;
2030bdb9230aSGarrett D'Amore 		sf = STORE_AND_FORWARD;
2031bdb9230aSGarrett D'Amore 	} else {
2032bdb9230aSGarrett D'Amore 		mb1 = sf = 0;
2033bdb9230aSGarrett D'Amore 		mb1 = OPN_REG_MB1; /* Needed for 21040? */
2034bdb9230aSGarrett D'Amore 	}
2035bdb9230aSGarrett D'Amore 
2036bdb9230aSGarrett D'Amore 	if (opnmode_len) {
2037bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2038bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, OPN_MODE_REG), val);
203998e8d175SSteven Stallion 		dnet_reset_board(dnetp);
2040bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2041bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, OPN_MODE_REG), val);
2042bdb9230aSGarrett D'Amore 		return;
2043bdb9230aSGarrett D'Amore 	}
2044bdb9230aSGarrett D'Amore 
2045bdb9230aSGarrett D'Amore 	/*
2046bdb9230aSGarrett D'Amore 	 * Set each bit in CSR6 that we want
2047bdb9230aSGarrett D'Amore 	 */
2048bdb9230aSGarrett D'Amore 
2049bdb9230aSGarrett D'Amore 	/* Always want these bits set */
2050bdb9230aSGarrett D'Amore 	val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf;
2051bdb9230aSGarrett D'Amore 
2052bdb9230aSGarrett D'Amore 	/* Promiscuous mode */
2053bdb9230aSGarrett D'Amore 	val |= dnetp->promisc ? PROM_MODE : 0;
2054bdb9230aSGarrett D'Amore 
2055bdb9230aSGarrett D'Amore 	/* Scrambler for SYM style media */
2056bdb9230aSGarrett D'Amore 	val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ?
2057bdb9230aSGarrett D'Amore 	    SCRAMBLER_MODE : 0;
2058bdb9230aSGarrett D'Amore 
2059bdb9230aSGarrett D'Amore 	/* Full duplex */
2060bdb9230aSGarrett D'Amore 	if (dnetp->mii_up) {
2061bdb9230aSGarrett D'Amore 		fd = dnetp->mii_duplex;
2062bdb9230aSGarrett D'Amore 	} else {
2063bdb9230aSGarrett D'Amore 		/* Rely on media code */
2064bdb9230aSGarrett D'Amore 		fd = block->media_code == MEDIA_TP_FD ||
2065bdb9230aSGarrett D'Amore 		    block->media_code == MEDIA_SYM_SCR_FD;
2066bdb9230aSGarrett D'Amore 	}
2067bdb9230aSGarrett D'Amore 
2068bdb9230aSGarrett D'Amore 	/* Port select (and therefore, heartbeat disable) */
2069bdb9230aSGarrett D'Amore 	val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0;
2070bdb9230aSGarrett D'Amore 
2071bdb9230aSGarrett D'Amore 	/* PCS function */
2072bdb9230aSGarrett D'Amore 	val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0;
2073bdb9230aSGarrett D'Amore 	val |= fd ? FULL_DUPLEX : 0;
2074bdb9230aSGarrett D'Amore 
2075bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2076bdb9230aSGarrett D'Amore 	if (dnetdebug & DNETREGCFG)
2077bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "OPN: %x", val);
2078bdb9230aSGarrett D'Amore #endif
2079bdb9230aSGarrett D'Amore 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
208098e8d175SSteven Stallion 	dnet_reset_board(dnetp);
2081bdb9230aSGarrett D'Amore 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
2082bdb9230aSGarrett D'Amore }
2083bdb9230aSGarrett D'Amore 
2084bdb9230aSGarrett D'Amore static void
set_sia(struct dnetinstance * dnetp)208598e8d175SSteven Stallion set_sia(struct dnetinstance *dnetp)
2086bdb9230aSGarrett D'Amore {
2087bdb9230aSGarrett D'Amore 	media_block_t *block = dnetp->selected_media_block;
2088bdb9230aSGarrett D'Amore 
2089bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
2090bdb9230aSGarrett D'Amore 	if (block->type == 2) {
2091bdb9230aSGarrett D'Amore 		int sia_delay;
2092bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2093bdb9230aSGarrett D'Amore 		if (dnetdebug & DNETREGCFG)
2094bdb9230aSGarrett D'Amore 			cmn_err(CE_NOTE,
2095bdb9230aSGarrett D'Amore 			    "SIA: CSR13: %x, CSR14: %x, CSR15: %x",
2096bdb9230aSGarrett D'Amore 			    block->un.sia.csr13,
2097bdb9230aSGarrett D'Amore 			    block->un.sia.csr14,
2098bdb9230aSGarrett D'Amore 			    block->un.sia.csr15);
2099bdb9230aSGarrett D'Amore #endif
2100bdb9230aSGarrett D'Amore 		sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
2101bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, "sia-delay", 10000);
2102bdb9230aSGarrett D'Amore 
2103bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2104bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2105bdb9230aSGarrett D'Amore 
2106bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG),
2107bdb9230aSGarrett D'Amore 		    block->un.sia.csr14);
2108bdb9230aSGarrett D'Amore 
2109bdb9230aSGarrett D'Amore 		/*
2110bdb9230aSGarrett D'Amore 		 * For '143, we need to write through a copy of the register
2111bdb9230aSGarrett D'Amore 		 * to keep the GP half intact
2112bdb9230aSGarrett D'Amore 		 */
2113bdb9230aSGarrett D'Amore 		dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15;
2114bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2115bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_GENERAL_REG),
2116bdb9230aSGarrett D'Amore 		    dnetp->gprsia);
2117bdb9230aSGarrett D'Amore 
2118bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2119bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_CONNECT_REG),
2120bdb9230aSGarrett D'Amore 		    block->un.sia.csr13);
2121bdb9230aSGarrett D'Amore 
2122bdb9230aSGarrett D'Amore 		drv_usecwait(sia_delay);
2123bdb9230aSGarrett D'Amore 
2124bdb9230aSGarrett D'Amore 	} else if (dnetp->board_type != DEVICE_ID_21140) {
2125bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2126bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2127bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
2128bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, SIA_TXRX_REG), 0);
2129bdb9230aSGarrett D'Amore 	}
2130bdb9230aSGarrett D'Amore }
2131bdb9230aSGarrett D'Amore 
2132bdb9230aSGarrett D'Amore /*
2133bdb9230aSGarrett D'Amore  * This function (re)allocates the receive and transmit buffers and
2134bdb9230aSGarrett D'Amore  * descriptors.  It can be called more than once per instance, though
2135bdb9230aSGarrett D'Amore  * currently it is only called from attach.  It should only be called
2136bdb9230aSGarrett D'Amore  * while the device is reset.
2137bdb9230aSGarrett D'Amore  */
2138bdb9230aSGarrett D'Amore static int
dnet_alloc_bufs(struct dnetinstance * dnetp)213998e8d175SSteven Stallion dnet_alloc_bufs(struct dnetinstance *dnetp)
2140bdb9230aSGarrett D'Amore {
2141bdb9230aSGarrett D'Amore 	int i;
2142bdb9230aSGarrett D'Amore 	size_t len;
2143bdb9230aSGarrett D'Amore 	int page_size;
2144bdb9230aSGarrett D'Amore 	int realloc = 0;
2145bdb9230aSGarrett D'Amore 	int nrecv_desc_old = 0;
2146bdb9230aSGarrett D'Amore 	ddi_dma_cookie_t cookie;
2147bdb9230aSGarrett D'Amore 	uint_t ncookies;
2148bdb9230aSGarrett D'Amore 
2149bdb9230aSGarrett D'Amore 	/*
2150bdb9230aSGarrett D'Amore 	 * check if we are trying to reallocate with different xmit/recv
2151bdb9230aSGarrett D'Amore 	 * descriptor ring sizes.
2152bdb9230aSGarrett D'Amore 	 */
2153bdb9230aSGarrett D'Amore 	if ((dnetp->tx_desc != NULL) &&
2154bdb9230aSGarrett D'Amore 	    (dnetp->nxmit_desc != dnetp->max_tx_desc))
2155bdb9230aSGarrett D'Amore 		realloc = 1;
2156bdb9230aSGarrett D'Amore 
2157bdb9230aSGarrett D'Amore 	if ((dnetp->rx_desc != NULL) &&
2158bdb9230aSGarrett D'Amore 	    (dnetp->nrecv_desc != dnetp->max_rx_desc))
2159bdb9230aSGarrett D'Amore 		realloc = 1;
2160bdb9230aSGarrett D'Amore 
2161bdb9230aSGarrett D'Amore 	/* free up the old buffers if we are reallocating them */
2162bdb9230aSGarrett D'Amore 	if (realloc) {
2163bdb9230aSGarrett D'Amore 		nrecv_desc_old = dnetp->nrecv_desc;
216498e8d175SSteven Stallion 		dnet_free_bufs(dnetp); /* free the old buffers */
2165bdb9230aSGarrett D'Amore 	}
2166bdb9230aSGarrett D'Amore 
2167bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle == NULL)
2168bdb9230aSGarrett D'Amore 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2169bdb9230aSGarrett D'Amore 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS)
2170bdb9230aSGarrett D'Amore 			return (FAILURE);
2171bdb9230aSGarrett D'Amore 
2172bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle_tx == NULL)
2173bdb9230aSGarrett D'Amore 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx,
2174bdb9230aSGarrett D'Amore 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS)
2175bdb9230aSGarrett D'Amore 			return (FAILURE);
2176bdb9230aSGarrett D'Amore 
2177bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle_txdesc == NULL)
2178bdb9230aSGarrett D'Amore 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2179bdb9230aSGarrett D'Amore 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS)
2180bdb9230aSGarrett D'Amore 			return (FAILURE);
2181bdb9230aSGarrett D'Amore 
2182bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle_setbuf == NULL)
2183bdb9230aSGarrett D'Amore 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2184bdb9230aSGarrett D'Amore 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS)
2185bdb9230aSGarrett D'Amore 			return (FAILURE);
2186bdb9230aSGarrett D'Amore 
2187bdb9230aSGarrett D'Amore 	page_size = ddi_ptob(dnetp->devinfo, 1);
2188bdb9230aSGarrett D'Amore 
2189bdb9230aSGarrett D'Amore 	dnetp->pgmask = page_size - 1;
2190bdb9230aSGarrett D'Amore 
2191bdb9230aSGarrett D'Amore 	/* allocate setup buffer if necessary */
2192bdb9230aSGarrett D'Amore 	if (dnetp->setup_buf_vaddr == NULL) {
2193bdb9230aSGarrett D'Amore 		if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf,
2194bdb9230aSGarrett D'Amore 		    SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING,
2195bdb9230aSGarrett D'Amore 		    DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr,
2196bdb9230aSGarrett D'Amore 		    &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS)
2197bdb9230aSGarrett D'Amore 			return (FAILURE);
2198bdb9230aSGarrett D'Amore 
2199bdb9230aSGarrett D'Amore 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf,
2200bdb9230aSGarrett D'Amore 		    NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE,
2201bdb9230aSGarrett D'Amore 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2202bdb9230aSGarrett D'Amore 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2203bdb9230aSGarrett D'Amore 			return (FAILURE);
2204bdb9230aSGarrett D'Amore 
2205bdb9230aSGarrett D'Amore 		dnetp->setup_buf_paddr = cookie.dmac_address;
2206bdb9230aSGarrett D'Amore 		bzero(dnetp->setup_buf_vaddr, len);
2207bdb9230aSGarrett D'Amore 	}
2208bdb9230aSGarrett D'Amore 
2209bdb9230aSGarrett D'Amore 	/* allocate xmit descriptor array of size dnetp->max_tx_desc */
2210bdb9230aSGarrett D'Amore 	if (dnetp->tx_desc == NULL) {
2211bdb9230aSGarrett D'Amore 		if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc,
2212bdb9230aSGarrett D'Amore 		    sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2213bdb9230aSGarrett D'Amore 		    &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2214bdb9230aSGarrett D'Amore 		    (caddr_t *)&dnetp->tx_desc, &len,
2215bdb9230aSGarrett D'Amore 		    &dnetp->tx_desc_acchdl) != DDI_SUCCESS)
2216bdb9230aSGarrett D'Amore 			return (FAILURE);
2217bdb9230aSGarrett D'Amore 
2218bdb9230aSGarrett D'Amore 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc,
2219bdb9230aSGarrett D'Amore 		    NULL, (caddr_t)dnetp->tx_desc,
2220bdb9230aSGarrett D'Amore 		    sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2221bdb9230aSGarrett D'Amore 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2222bdb9230aSGarrett D'Amore 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2223bdb9230aSGarrett D'Amore 			return (FAILURE);
2224bdb9230aSGarrett D'Amore 		dnetp->tx_desc_paddr = cookie.dmac_address;
2225bdb9230aSGarrett D'Amore 		bzero(dnetp->tx_desc, len);
2226bdb9230aSGarrett D'Amore 		dnetp->nxmit_desc = dnetp->max_tx_desc;
2227bdb9230aSGarrett D'Amore 
2228bdb9230aSGarrett D'Amore 		dnetp->tx_msgbufp =
2229bdb9230aSGarrett D'Amore 		    kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **),
2230bdb9230aSGarrett D'Amore 		    KM_SLEEP);
2231bdb9230aSGarrett D'Amore 	}
2232bdb9230aSGarrett D'Amore 
2233bdb9230aSGarrett D'Amore 	/* allocate receive descriptor array of size dnetp->max_rx_desc */
2234bdb9230aSGarrett D'Amore 	if (dnetp->rx_desc == NULL) {
2235bdb9230aSGarrett D'Amore 		int ndesc;
2236bdb9230aSGarrett D'Amore 
2237bdb9230aSGarrett D'Amore 		if (ddi_dma_mem_alloc(dnetp->dma_handle,
2238bdb9230aSGarrett D'Amore 		    sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2239bdb9230aSGarrett D'Amore 		    &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2240bdb9230aSGarrett D'Amore 		    (caddr_t *)&dnetp->rx_desc, &len,
2241bdb9230aSGarrett D'Amore 		    &dnetp->rx_desc_acchdl) != DDI_SUCCESS)
2242bdb9230aSGarrett D'Amore 			return (FAILURE);
2243bdb9230aSGarrett D'Amore 
2244bdb9230aSGarrett D'Amore 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle,
2245bdb9230aSGarrett D'Amore 		    NULL, (caddr_t)dnetp->rx_desc,
2246bdb9230aSGarrett D'Amore 		    sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2247bdb9230aSGarrett D'Amore 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2248bdb9230aSGarrett D'Amore 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2249bdb9230aSGarrett D'Amore 			return (FAILURE);
2250bdb9230aSGarrett D'Amore 
2251bdb9230aSGarrett D'Amore 		dnetp->rx_desc_paddr = cookie.dmac_address;
2252bdb9230aSGarrett D'Amore 		bzero(dnetp->rx_desc, len);
2253bdb9230aSGarrett D'Amore 		dnetp->nrecv_desc = dnetp->max_rx_desc;
2254bdb9230aSGarrett D'Amore 
2255bdb9230aSGarrett D'Amore 		dnetp->rx_buf_vaddr =
2256bdb9230aSGarrett D'Amore 		    kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t),
2257bdb9230aSGarrett D'Amore 		    KM_SLEEP);
2258bdb9230aSGarrett D'Amore 		dnetp->rx_buf_paddr =
2259bdb9230aSGarrett D'Amore 		    kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t),
2260bdb9230aSGarrett D'Amore 		    KM_SLEEP);
2261bdb9230aSGarrett D'Amore 		/*
2262bdb9230aSGarrett D'Amore 		 * Allocate or add to the pool of receive buffers.  The pool
2263bdb9230aSGarrett D'Amore 		 * is shared among all instances of dnet.
2264bdb9230aSGarrett D'Amore 		 *
2265bdb9230aSGarrett D'Amore 		 * XXX NEEDSWORK
2266bdb9230aSGarrett D'Amore 		 *
2267bdb9230aSGarrett D'Amore 		 * We arbitrarily allocate twice as many receive buffers as
2268bdb9230aSGarrett D'Amore 		 * receive descriptors because we use the buffers for streams
2269bdb9230aSGarrett D'Amore 		 * messages to pass the packets up the stream.  We should
2270bdb9230aSGarrett D'Amore 		 * instead have initialized constants reflecting
2271bdb9230aSGarrett D'Amore 		 * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2272bdb9230aSGarrett D'Amore 		 * probably have a total maximum for the free pool, so that we
2273bdb9230aSGarrett D'Amore 		 * don't get out of hand when someone puts in an 8-port board.
2274bdb9230aSGarrett D'Amore 		 * The maximum for the entire pool should be the total number
2275bdb9230aSGarrett D'Amore 		 * of descriptors for all attached instances together, plus the
2276bdb9230aSGarrett D'Amore 		 * total maximum for the free pool.  This maximum would only be
2277bdb9230aSGarrett D'Amore 		 * reached after some number of instances allocate buffers:
2278bdb9230aSGarrett D'Amore 		 * each instance would add (max_rx_buf-max_rx_desc) to the free
2279bdb9230aSGarrett D'Amore 		 * pool.
2280bdb9230aSGarrett D'Amore 		 */
2281bdb9230aSGarrett D'Amore 		ndesc = dnetp->max_rx_desc - nrecv_desc_old;
2282bdb9230aSGarrett D'Amore 		if ((ndesc > 0) &&
2283bdb9230aSGarrett D'Amore 		    (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0))
2284bdb9230aSGarrett D'Amore 			return (FAILURE);
2285bdb9230aSGarrett D'Amore 
2286bdb9230aSGarrett D'Amore 		for (i = 0; i < dnetp->max_rx_desc; i++) {
2287bdb9230aSGarrett D'Amore 			struct rbuf_list *rp;
2288bdb9230aSGarrett D'Amore 
2289bdb9230aSGarrett D'Amore 			rp = dnet_rbuf_alloc(dnetp->devinfo, 1);
2290bdb9230aSGarrett D'Amore 			if (rp == NULL)
2291bdb9230aSGarrett D'Amore 				return (FAILURE);
2292bdb9230aSGarrett D'Amore 			dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr;
2293bdb9230aSGarrett D'Amore 			dnetp->rx_buf_paddr[i] = rp->rbuf_paddr;
2294bdb9230aSGarrett D'Amore 		}
2295bdb9230aSGarrett D'Amore 	}
2296bdb9230aSGarrett D'Amore 
2297bdb9230aSGarrett D'Amore 	return (SUCCESS);
2298bdb9230aSGarrett D'Amore }
2299bdb9230aSGarrett D'Amore /*
2300bdb9230aSGarrett D'Amore  * free descriptors/buffers allocated for this device instance.  This routine
2301bdb9230aSGarrett D'Amore  * should only be called while the device is reset.
2302bdb9230aSGarrett D'Amore  */
2303bdb9230aSGarrett D'Amore static void
dnet_free_bufs(struct dnetinstance * dnetp)230498e8d175SSteven Stallion dnet_free_bufs(struct dnetinstance *dnetp)
2305bdb9230aSGarrett D'Amore {
2306bdb9230aSGarrett D'Amore 	int i;
2307bdb9230aSGarrett D'Amore 	/* free up any xmit descriptors/buffers */
2308bdb9230aSGarrett D'Amore 	if (dnetp->tx_desc != NULL) {
2309bdb9230aSGarrett D'Amore 		ddi_dma_mem_free(&dnetp->tx_desc_acchdl);
2310bdb9230aSGarrett D'Amore 		dnetp->tx_desc = NULL;
2311bdb9230aSGarrett D'Amore 		/* we use streams buffers for DMA in xmit process */
2312bdb9230aSGarrett D'Amore 		if (dnetp->tx_msgbufp != NULL) {
2313bdb9230aSGarrett D'Amore 			/* free up any streams message buffers unclaimed */
2314bdb9230aSGarrett D'Amore 			for (i = 0; i < dnetp->nxmit_desc; i++) {
2315bdb9230aSGarrett D'Amore 				if (dnetp->tx_msgbufp[i] != NULL) {
2316bdb9230aSGarrett D'Amore 					freemsg(dnetp->tx_msgbufp[i]);
2317bdb9230aSGarrett D'Amore 				}
2318bdb9230aSGarrett D'Amore 			}
2319bdb9230aSGarrett D'Amore 			kmem_free(dnetp->tx_msgbufp,
2320bdb9230aSGarrett D'Amore 			    dnetp->nxmit_desc * sizeof (mblk_t **));
2321bdb9230aSGarrett D'Amore 			dnetp->tx_msgbufp = NULL;
2322bdb9230aSGarrett D'Amore 		}
2323bdb9230aSGarrett D'Amore 		dnetp->nxmit_desc = 0;
2324bdb9230aSGarrett D'Amore 	}
2325bdb9230aSGarrett D'Amore 
2326bdb9230aSGarrett D'Amore 	/* free up any receive descriptors/buffers */
2327bdb9230aSGarrett D'Amore 	if (dnetp->rx_desc != NULL) {
2328bdb9230aSGarrett D'Amore 		ddi_dma_mem_free(&dnetp->rx_desc_acchdl);
2329bdb9230aSGarrett D'Amore 		dnetp->rx_desc = NULL;
2330bdb9230aSGarrett D'Amore 		if (dnetp->rx_buf_vaddr != NULL) {
2331bdb9230aSGarrett D'Amore 			/* free up the attached rbufs if any */
2332bdb9230aSGarrett D'Amore 			for (i = 0; i < dnetp->nrecv_desc; i++) {
2333bdb9230aSGarrett D'Amore 				if (dnetp->rx_buf_vaddr[i])
2334bdb9230aSGarrett D'Amore 					dnet_rbuf_free(
2335bdb9230aSGarrett D'Amore 					    (caddr_t)dnetp->rx_buf_vaddr[i]);
2336bdb9230aSGarrett D'Amore 			}
2337bdb9230aSGarrett D'Amore 			kmem_free(dnetp->rx_buf_vaddr,
2338bdb9230aSGarrett D'Amore 			    dnetp->nrecv_desc * sizeof (caddr_t));
2339bdb9230aSGarrett D'Amore 			kmem_free(dnetp->rx_buf_paddr,
2340bdb9230aSGarrett D'Amore 			    dnetp->nrecv_desc * sizeof (uint32_t));
2341bdb9230aSGarrett D'Amore 			dnetp->rx_buf_vaddr = NULL;
2342bdb9230aSGarrett D'Amore 			dnetp->rx_buf_paddr = NULL;
2343bdb9230aSGarrett D'Amore 		}
2344bdb9230aSGarrett D'Amore 		dnetp->nrecv_desc = 0;
2345bdb9230aSGarrett D'Amore 	}
2346bdb9230aSGarrett D'Amore 
2347bdb9230aSGarrett D'Amore 	if (dnetp->setup_buf_vaddr != NULL) {
2348bdb9230aSGarrett D'Amore 		ddi_dma_mem_free(&dnetp->setup_buf_acchdl);
2349bdb9230aSGarrett D'Amore 		dnetp->setup_buf_vaddr = NULL;
2350bdb9230aSGarrett D'Amore 	}
2351bdb9230aSGarrett D'Amore 
2352bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle != NULL) {
2353bdb9230aSGarrett D'Amore 		(void) ddi_dma_unbind_handle(dnetp->dma_handle);
2354bdb9230aSGarrett D'Amore 		ddi_dma_free_handle(&dnetp->dma_handle);
2355bdb9230aSGarrett D'Amore 		dnetp->dma_handle = NULL;
2356bdb9230aSGarrett D'Amore 	}
2357bdb9230aSGarrett D'Amore 
2358bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle_tx != NULL) {
2359bdb9230aSGarrett D'Amore 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
2360bdb9230aSGarrett D'Amore 		ddi_dma_free_handle(&dnetp->dma_handle_tx);
2361bdb9230aSGarrett D'Amore 		dnetp->dma_handle_tx = NULL;
2362bdb9230aSGarrett D'Amore 	}
2363bdb9230aSGarrett D'Amore 
2364bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle_txdesc != NULL) {
2365bdb9230aSGarrett D'Amore 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc);
2366bdb9230aSGarrett D'Amore 		ddi_dma_free_handle(&dnetp->dma_handle_txdesc);
2367bdb9230aSGarrett D'Amore 		dnetp->dma_handle_txdesc = NULL;
2368bdb9230aSGarrett D'Amore 	}
2369bdb9230aSGarrett D'Amore 
2370bdb9230aSGarrett D'Amore 	if (dnetp->dma_handle_setbuf != NULL) {
2371bdb9230aSGarrett D'Amore 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf);
2372bdb9230aSGarrett D'Amore 		ddi_dma_free_handle(&dnetp->dma_handle_setbuf);
2373bdb9230aSGarrett D'Amore 		dnetp->dma_handle_setbuf = NULL;
2374bdb9230aSGarrett D'Amore 	}
2375bdb9230aSGarrett D'Amore 
2376bdb9230aSGarrett D'Amore }
2377bdb9230aSGarrett D'Amore 
2378bdb9230aSGarrett D'Amore /*
2379bdb9230aSGarrett D'Amore  * Initialize transmit and receive descriptors.
2380bdb9230aSGarrett D'Amore  */
2381bdb9230aSGarrett D'Amore static void
dnet_init_txrx_bufs(struct dnetinstance * dnetp)238298e8d175SSteven Stallion dnet_init_txrx_bufs(struct dnetinstance *dnetp)
2383bdb9230aSGarrett D'Amore {
2384bdb9230aSGarrett D'Amore 	int		i;
2385bdb9230aSGarrett D'Amore 
2386bdb9230aSGarrett D'Amore 	/*
2387bdb9230aSGarrett D'Amore 	 * Initilize all the Tx descriptors
2388bdb9230aSGarrett D'Amore 	 */
2389bdb9230aSGarrett D'Amore 	for (i = 0; i < dnetp->nxmit_desc; i++) {
2390bdb9230aSGarrett D'Amore 		/*
2391bdb9230aSGarrett D'Amore 		 * We may be resetting the device due to errors,
2392bdb9230aSGarrett D'Amore 		 * so free up any streams message buffer unclaimed.
2393bdb9230aSGarrett D'Amore 		 */
2394bdb9230aSGarrett D'Amore 		if (dnetp->tx_msgbufp[i] != NULL) {
2395bdb9230aSGarrett D'Amore 			freemsg(dnetp->tx_msgbufp[i]);
2396bdb9230aSGarrett D'Amore 			dnetp->tx_msgbufp[i] = NULL;
2397bdb9230aSGarrett D'Amore 		}
2398bdb9230aSGarrett D'Amore 		*(uint32_t *)&dnetp->tx_desc[i].desc0 = 0;
2399bdb9230aSGarrett D'Amore 		*(uint32_t *)&dnetp->tx_desc[i].desc1 = 0;
2400bdb9230aSGarrett D'Amore 		dnetp->tx_desc[i].buffer1 = 0;
2401bdb9230aSGarrett D'Amore 		dnetp->tx_desc[i].buffer2 = 0;
2402bdb9230aSGarrett D'Amore 	}
2403bdb9230aSGarrett D'Amore 	dnetp->tx_desc[i - 1].desc1.end_of_ring = 1;
2404bdb9230aSGarrett D'Amore 
2405bdb9230aSGarrett D'Amore 	/*
2406bdb9230aSGarrett D'Amore 	 * Initialize the Rx descriptors
2407bdb9230aSGarrett D'Amore 	 */
2408bdb9230aSGarrett D'Amore 	for (i = 0; i < dnetp->nrecv_desc; i++) {
2409bdb9230aSGarrett D'Amore 		uint32_t end_paddr;
2410bdb9230aSGarrett D'Amore 		*(uint32_t *)&dnetp->rx_desc[i].desc0 = 0;
2411bdb9230aSGarrett D'Amore 		*(uint32_t *)&dnetp->rx_desc[i].desc1 = 0;
2412bdb9230aSGarrett D'Amore 		dnetp->rx_desc[i].desc0.own = 1;
2413bdb9230aSGarrett D'Amore 		dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size;
2414bdb9230aSGarrett D'Amore 		dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i];
2415bdb9230aSGarrett D'Amore 		dnetp->rx_desc[i].buffer2 = 0;
2416bdb9230aSGarrett D'Amore 		end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1;
2417bdb9230aSGarrett D'Amore 
2418bdb9230aSGarrett D'Amore 		if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) !=
2419bdb9230aSGarrett D'Amore 		    (end_paddr & ~dnetp->pgmask)) {
2420bdb9230aSGarrett D'Amore 			/* discontiguous */
2421bdb9230aSGarrett D'Amore 			dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask;
2422bdb9230aSGarrett D'Amore 			dnetp->rx_desc[i].desc1.buffer_size2 =
2423bdb9230aSGarrett D'Amore 			    (end_paddr & dnetp->pgmask) + 1;
2424bdb9230aSGarrett D'Amore 			dnetp->rx_desc[i].desc1.buffer_size1 =
2425bdb9230aSGarrett D'Amore 			    rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2;
2426bdb9230aSGarrett D'Amore 		}
2427bdb9230aSGarrett D'Amore 	}
2428bdb9230aSGarrett D'Amore 	dnetp->rx_desc[i - 1].desc1.end_of_ring = 1;
2429bdb9230aSGarrett D'Amore }
2430bdb9230aSGarrett D'Amore 
2431bdb9230aSGarrett D'Amore static int
alloc_descriptor(struct dnetinstance * dnetp)243298e8d175SSteven Stallion alloc_descriptor(struct dnetinstance *dnetp)
2433bdb9230aSGarrett D'Amore {
2434bdb9230aSGarrett D'Amore 	int index;
2435bdb9230aSGarrett D'Amore 	struct tx_desc_type    *ring = dnetp->tx_desc;
2436bdb9230aSGarrett D'Amore 
2437bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
2438bdb9230aSGarrett D'Amore alloctop:
2439bdb9230aSGarrett D'Amore 	mutex_enter(&dnetp->txlock);
2440bdb9230aSGarrett D'Amore 	index = dnetp->tx_current_desc;
2441bdb9230aSGarrett D'Amore 
244298e8d175SSteven Stallion 	dnet_reclaim_Tx_desc(dnetp);
2443bdb9230aSGarrett D'Amore 
2444bdb9230aSGarrett D'Amore 	/* we do have free descriptors, right? */
2445bdb9230aSGarrett D'Amore 	if (dnetp->free_desc <= 0) {
2446bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2447bdb9230aSGarrett D'Amore 		if (dnetdebug & DNETRECV)
2448bdb9230aSGarrett D'Amore 			cmn_err(CE_NOTE, "dnet: Ring buffer is full");
2449bdb9230aSGarrett D'Amore #endif
2450bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->txlock);
2451bdb9230aSGarrett D'Amore 		return (FAILURE);
2452bdb9230aSGarrett D'Amore 	}
2453bdb9230aSGarrett D'Amore 
2454bdb9230aSGarrett D'Amore 	/* sanity, make sure the next descriptor is free for use (should be) */
2455bdb9230aSGarrett D'Amore 	if (ring[index].desc0.own) {
2456bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2457bdb9230aSGarrett D'Amore 		if (dnetdebug & DNETRECV)
2458bdb9230aSGarrett D'Amore 			cmn_err(CE_WARN,
2459bdb9230aSGarrett D'Amore 			    "dnet: next descriptor is not free for use");
2460bdb9230aSGarrett D'Amore #endif
2461bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->txlock);
2462bdb9230aSGarrett D'Amore 		return (FAILURE);
2463bdb9230aSGarrett D'Amore 	}
2464bdb9230aSGarrett D'Amore 	if (dnetp->need_saddr) {
2465bdb9230aSGarrett D'Amore 		mutex_exit(&dnetp->txlock);
2466bdb9230aSGarrett D'Amore 		/* XXX function return value ignored */
2467bdb9230aSGarrett D'Amore 		if (!dnetp->suspended)
246898e8d175SSteven Stallion 			(void) dnet_set_addr(dnetp);
2469bdb9230aSGarrett D'Amore 		goto alloctop;
2470bdb9230aSGarrett D'Amore 	}
2471bdb9230aSGarrett D'Amore 
2472bdb9230aSGarrett D'Amore 	*(uint32_t *)&ring[index].desc0 = 0;  /* init descs */
2473bdb9230aSGarrett D'Amore 	*(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING;
2474bdb9230aSGarrett D'Amore 
2475bdb9230aSGarrett D'Amore 	/* hardware will own this descriptor when poll activated */
2476bdb9230aSGarrett D'Amore 	dnetp->free_desc--;
2477bdb9230aSGarrett D'Amore 
2478bdb9230aSGarrett D'Amore 	/* point to next free descriptor to be used */
2479bdb9230aSGarrett D'Amore 	dnetp->tx_current_desc = NextTXIndex(index);
2480bdb9230aSGarrett D'Amore 
2481bdb9230aSGarrett D'Amore #ifdef DNET_NOISY
2482bdb9230aSGarrett D'Amore 	cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x",
2483bdb9230aSGarrett D'Amore 	    dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc);
2484bdb9230aSGarrett D'Amore #endif
2485bdb9230aSGarrett D'Amore 	mutex_exit(&dnetp->txlock);
2486bdb9230aSGarrett D'Amore 	return (SUCCESS);
2487bdb9230aSGarrett D'Amore }
2488bdb9230aSGarrett D'Amore 
2489bdb9230aSGarrett D'Amore /*
2490bdb9230aSGarrett D'Amore  * dnet_reclaim_Tx_desc() - called with txlock held.
2491bdb9230aSGarrett D'Amore  */
2492bdb9230aSGarrett D'Amore static void
dnet_reclaim_Tx_desc(struct dnetinstance * dnetp)249398e8d175SSteven Stallion dnet_reclaim_Tx_desc(struct dnetinstance *dnetp)
2494bdb9230aSGarrett D'Amore {
2495bdb9230aSGarrett D'Amore 	struct tx_desc_type	*desc = dnetp->tx_desc;
2496bdb9230aSGarrett D'Amore 	int index;
2497bdb9230aSGarrett D'Amore 
2498bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->txlock));
2499bdb9230aSGarrett D'Amore 
2500bdb9230aSGarrett D'Amore 	index = dnetp->transmitted_desc;
2501bdb9230aSGarrett D'Amore 	while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) &&
2502bdb9230aSGarrett D'Amore 	    !(desc[index].desc0.own)) {
2503bdb9230aSGarrett D'Amore 		/*
2504bdb9230aSGarrett D'Amore 		 * Check for Tx Error that gets set
2505bdb9230aSGarrett D'Amore 		 * in the last desc.
2506bdb9230aSGarrett D'Amore 		 */
2507bdb9230aSGarrett D'Amore 		if (desc[index].desc1.setup_packet == 0 &&
2508bdb9230aSGarrett D'Amore 		    desc[index].desc1.last_desc &&
2509bdb9230aSGarrett D'Amore 		    desc[index].desc0.err_summary)
251098e8d175SSteven Stallion 			update_tx_stats(dnetp, index);
2511bdb9230aSGarrett D'Amore 
2512bdb9230aSGarrett D'Amore 		/*
2513bdb9230aSGarrett D'Amore 		 * If we have used the streams message buffer for this
2514bdb9230aSGarrett D'Amore 		 * descriptor then free up the message now.
2515bdb9230aSGarrett D'Amore 		 */
2516bdb9230aSGarrett D'Amore 		if (dnetp->tx_msgbufp[index] != NULL) {
2517bdb9230aSGarrett D'Amore 			freemsg(dnetp->tx_msgbufp[index]);
2518bdb9230aSGarrett D'Amore 			dnetp->tx_msgbufp[index] = NULL;
2519bdb9230aSGarrett D'Amore 		}
2520bdb9230aSGarrett D'Amore 		dnetp->free_desc++;
2521bdb9230aSGarrett D'Amore 		index = (index+1) % dnetp->max_tx_desc;
2522bdb9230aSGarrett D'Amore 	}
2523bdb9230aSGarrett D'Amore 
2524bdb9230aSGarrett D'Amore 	dnetp->transmitted_desc = index;
2525bdb9230aSGarrett D'Amore }
2526bdb9230aSGarrett D'Amore 
2527bdb9230aSGarrett D'Amore /*
2528bdb9230aSGarrett D'Amore  * Receive buffer allocation/freeing routines.
2529bdb9230aSGarrett D'Amore  *
2530bdb9230aSGarrett D'Amore  * There is a common pool of receive buffers shared by all dnet instances.
2531bdb9230aSGarrett D'Amore  *
2532bdb9230aSGarrett D'Amore  * XXX NEEDSWORK
2533bdb9230aSGarrett D'Amore  *
2534bdb9230aSGarrett D'Amore  * We arbitrarily allocate twice as many receive buffers as
2535bdb9230aSGarrett D'Amore  * receive descriptors because we use the buffers for streams
2536bdb9230aSGarrett D'Amore  * messages to pass the packets up the stream.  We should
2537bdb9230aSGarrett D'Amore  * instead have initialized constants reflecting
2538bdb9230aSGarrett D'Amore  * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2539bdb9230aSGarrett D'Amore  * probably have a total maximum for the free pool, so that we
2540bdb9230aSGarrett D'Amore  * don't get out of hand when someone puts in an 8-port board.
2541bdb9230aSGarrett D'Amore  * The maximum for the entire pool should be the total number
2542bdb9230aSGarrett D'Amore  * of descriptors for all attached instances together, plus the
2543bdb9230aSGarrett D'Amore  * total maximum for the free pool.  This maximum would only be
2544bdb9230aSGarrett D'Amore  * reached after some number of instances allocate buffers:
2545bdb9230aSGarrett D'Amore  * each instance would add (max_rx_buf-max_rx_desc) to the free
2546bdb9230aSGarrett D'Amore  * pool.
2547bdb9230aSGarrett D'Amore  */
2548bdb9230aSGarrett D'Amore 
2549bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_head;
2550bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_freelist_head;
2551bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_end;	/* last buffer allocated */
2552bdb9230aSGarrett D'Amore 
2553bdb9230aSGarrett D'Amore static int rbuf_freebufs;	/* no. of free buffers in the pool */
2554bdb9230aSGarrett D'Amore static int rbuf_pool_size;	/* total no. of buffers in the pool */
2555bdb9230aSGarrett D'Amore 
2556bdb9230aSGarrett D'Amore /* initialize/add 'nbufs' buffers to the rbuf pool */
2557bdb9230aSGarrett D'Amore /* ARGSUSED */
2558bdb9230aSGarrett D'Amore static int
dnet_rbuf_init(dev_info_t * dip,int nbufs)2559bdb9230aSGarrett D'Amore dnet_rbuf_init(dev_info_t *dip, int nbufs)
2560bdb9230aSGarrett D'Amore {
2561bdb9230aSGarrett D'Amore 	int i;
2562bdb9230aSGarrett D'Amore 	struct rbuf_list *rp;
2563bdb9230aSGarrett D'Amore 	ddi_dma_cookie_t cookie;
2564bdb9230aSGarrett D'Amore 	uint_t ncookies;
2565bdb9230aSGarrett D'Amore 	size_t len;
2566bdb9230aSGarrett D'Amore 
2567bdb9230aSGarrett D'Amore 	mutex_enter(&dnet_rbuf_lock);
2568bdb9230aSGarrett D'Amore 
2569bdb9230aSGarrett D'Amore 	/* allocate buffers and add them to the pool */
2570bdb9230aSGarrett D'Amore 	for (i = 0; i < nbufs; i++) {
2571bdb9230aSGarrett D'Amore 		/* allocate rbuf_list element */
2572bdb9230aSGarrett D'Amore 		rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2573bdb9230aSGarrett D'Amore 		if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2574bdb9230aSGarrett D'Amore 		    0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2575bdb9230aSGarrett D'Amore 			goto fail_kfree;
2576bdb9230aSGarrett D'Amore 
2577bdb9230aSGarrett D'Amore 		/* allocate dma memory for the buffer */
2578bdb9230aSGarrett D'Amore 		if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2579bdb9230aSGarrett D'Amore 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2580bdb9230aSGarrett D'Amore 		    &rp->rbuf_vaddr, &len,
2581bdb9230aSGarrett D'Amore 		    &rp->rbuf_acchdl) != DDI_SUCCESS)
2582bdb9230aSGarrett D'Amore 			goto fail_freehdl;
2583bdb9230aSGarrett D'Amore 
2584bdb9230aSGarrett D'Amore 		if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2585bdb9230aSGarrett D'Amore 		    rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2586bdb9230aSGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, &cookie,
2587bdb9230aSGarrett D'Amore 		    &ncookies) != DDI_DMA_MAPPED)
2588bdb9230aSGarrett D'Amore 			goto fail_free;
2589bdb9230aSGarrett D'Amore 
2590bdb9230aSGarrett D'Amore 		if (ncookies > 2)
2591bdb9230aSGarrett D'Amore 			goto fail_unbind;
2592bdb9230aSGarrett D'Amore 		if (ncookies == 1) {
2593bdb9230aSGarrett D'Amore 			rp->rbuf_endpaddr =
2594bdb9230aSGarrett D'Amore 			    cookie.dmac_address + rx_buf_size - 1;
2595bdb9230aSGarrett D'Amore 		} else {
2596bdb9230aSGarrett D'Amore 			ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2597bdb9230aSGarrett D'Amore 			rp->rbuf_endpaddr =
2598bdb9230aSGarrett D'Amore 			    cookie.dmac_address + cookie.dmac_size - 1;
2599bdb9230aSGarrett D'Amore 		}
2600bdb9230aSGarrett D'Amore 		rp->rbuf_paddr = cookie.dmac_address;
2601bdb9230aSGarrett D'Amore 
2602bdb9230aSGarrett D'Amore 		rp->rbuf_next = rbuf_freelist_head;
2603bdb9230aSGarrett D'Amore 		rbuf_freelist_head = rp;
2604bdb9230aSGarrett D'Amore 		rbuf_pool_size++;
2605bdb9230aSGarrett D'Amore 		rbuf_freebufs++;
2606bdb9230aSGarrett D'Amore 	}
2607bdb9230aSGarrett D'Amore 
2608bdb9230aSGarrett D'Amore 	mutex_exit(&dnet_rbuf_lock);
2609bdb9230aSGarrett D'Amore 	return (0);
2610bdb9230aSGarrett D'Amore fail_unbind:
2611bdb9230aSGarrett D'Amore 	(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2612bdb9230aSGarrett D'Amore fail_free:
2613bdb9230aSGarrett D'Amore 	ddi_dma_mem_free(&rp->rbuf_acchdl);
2614bdb9230aSGarrett D'Amore fail_freehdl:
2615bdb9230aSGarrett D'Amore 	ddi_dma_free_handle(&rp->rbuf_dmahdl);
2616bdb9230aSGarrett D'Amore fail_kfree:
2617bdb9230aSGarrett D'Amore 	kmem_free(rp, sizeof (struct rbuf_list));
2618bdb9230aSGarrett D'Amore 
2619bdb9230aSGarrett D'Amore 	mutex_exit(&dnet_rbuf_lock);
2620bdb9230aSGarrett D'Amore 	return (-1);
2621bdb9230aSGarrett D'Amore }
2622bdb9230aSGarrett D'Amore 
2623bdb9230aSGarrett D'Amore /*
2624bdb9230aSGarrett D'Amore  * Try to free up all the rbufs in the pool. Returns 0 if it frees up all
2625bdb9230aSGarrett D'Amore  * buffers. The buffers in the used list are considered busy so these
2626bdb9230aSGarrett D'Amore  * buffers are not freed.
2627bdb9230aSGarrett D'Amore  */
2628bdb9230aSGarrett D'Amore static int
dnet_rbuf_destroy()2629bdb9230aSGarrett D'Amore dnet_rbuf_destroy()
2630bdb9230aSGarrett D'Amore {
2631bdb9230aSGarrett D'Amore 	struct rbuf_list *rp, *next;
2632bdb9230aSGarrett D'Amore 
2633bdb9230aSGarrett D'Amore 	mutex_enter(&dnet_rbuf_lock);
2634bdb9230aSGarrett D'Amore 
2635bdb9230aSGarrett D'Amore 	for (rp = rbuf_freelist_head; rp; rp = next) {
2636bdb9230aSGarrett D'Amore 		next = rp->rbuf_next;
2637bdb9230aSGarrett D'Amore 		ddi_dma_mem_free(&rp->rbuf_acchdl);
2638bdb9230aSGarrett D'Amore 		(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2639bdb9230aSGarrett D'Amore 		kmem_free(rp, sizeof (struct rbuf_list));
2640bdb9230aSGarrett D'Amore 		rbuf_pool_size--;
2641bdb9230aSGarrett D'Amore 		rbuf_freebufs--;
2642bdb9230aSGarrett D'Amore 	}
2643bdb9230aSGarrett D'Amore 	rbuf_freelist_head = NULL;
2644bdb9230aSGarrett D'Amore 
2645bdb9230aSGarrett D'Amore 	if (rbuf_pool_size) { /* pool is still not empty */
2646bdb9230aSGarrett D'Amore 		mutex_exit(&dnet_rbuf_lock);
2647bdb9230aSGarrett D'Amore 		return (-1);
2648bdb9230aSGarrett D'Amore 	}
2649bdb9230aSGarrett D'Amore 	mutex_exit(&dnet_rbuf_lock);
2650bdb9230aSGarrett D'Amore 	return (0);
2651bdb9230aSGarrett D'Amore }
2652bdb9230aSGarrett D'Amore static struct rbuf_list *
dnet_rbuf_alloc(dev_info_t * dip,int cansleep)2653bdb9230aSGarrett D'Amore dnet_rbuf_alloc(dev_info_t *dip, int cansleep)
2654bdb9230aSGarrett D'Amore {
2655bdb9230aSGarrett D'Amore 	struct rbuf_list *rp;
2656bdb9230aSGarrett D'Amore 	size_t len;
2657bdb9230aSGarrett D'Amore 	ddi_dma_cookie_t cookie;
2658bdb9230aSGarrett D'Amore 	uint_t ncookies;
2659bdb9230aSGarrett D'Amore 
2660bdb9230aSGarrett D'Amore 	mutex_enter(&dnet_rbuf_lock);
2661bdb9230aSGarrett D'Amore 
2662bdb9230aSGarrett D'Amore 	if (rbuf_freelist_head == NULL) {
2663bdb9230aSGarrett D'Amore 
2664bdb9230aSGarrett D'Amore 		if (!cansleep) {
2665bdb9230aSGarrett D'Amore 			mutex_exit(&dnet_rbuf_lock);
2666bdb9230aSGarrett D'Amore 			return (NULL);
2667bdb9230aSGarrett D'Amore 		}
2668bdb9230aSGarrett D'Amore 
2669bdb9230aSGarrett D'Amore 		/* allocate rbuf_list element */
2670bdb9230aSGarrett D'Amore 		rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2671bdb9230aSGarrett D'Amore 		if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2672bdb9230aSGarrett D'Amore 		    0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2673bdb9230aSGarrett D'Amore 			goto fail_kfree;
2674bdb9230aSGarrett D'Amore 
2675bdb9230aSGarrett D'Amore 		/* allocate dma memory for the buffer */
2676bdb9230aSGarrett D'Amore 		if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2677bdb9230aSGarrett D'Amore 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2678bdb9230aSGarrett D'Amore 		    &rp->rbuf_vaddr, &len,
2679bdb9230aSGarrett D'Amore 		    &rp->rbuf_acchdl) != DDI_SUCCESS)
2680bdb9230aSGarrett D'Amore 			goto fail_freehdl;
2681bdb9230aSGarrett D'Amore 
2682bdb9230aSGarrett D'Amore 		if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2683bdb9230aSGarrett D'Amore 		    rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2684bdb9230aSGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, &cookie,
2685bdb9230aSGarrett D'Amore 		    &ncookies) != DDI_DMA_MAPPED)
2686bdb9230aSGarrett D'Amore 			goto fail_free;
2687bdb9230aSGarrett D'Amore 
2688bdb9230aSGarrett D'Amore 		if (ncookies > 2)
2689bdb9230aSGarrett D'Amore 			goto fail_unbind;
2690bdb9230aSGarrett D'Amore 		if (ncookies == 1) {
2691bdb9230aSGarrett D'Amore 			rp->rbuf_endpaddr =
2692bdb9230aSGarrett D'Amore 			    cookie.dmac_address + rx_buf_size - 1;
2693bdb9230aSGarrett D'Amore 		} else {
2694bdb9230aSGarrett D'Amore 			ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2695bdb9230aSGarrett D'Amore 			rp->rbuf_endpaddr =
2696bdb9230aSGarrett D'Amore 			    cookie.dmac_address + cookie.dmac_size - 1;
2697bdb9230aSGarrett D'Amore 		}
2698bdb9230aSGarrett D'Amore 		rp->rbuf_paddr = cookie.dmac_address;
2699bdb9230aSGarrett D'Amore 
2700bdb9230aSGarrett D'Amore 		rbuf_freelist_head = rp;
2701bdb9230aSGarrett D'Amore 		rbuf_pool_size++;
2702bdb9230aSGarrett D'Amore 		rbuf_freebufs++;
2703bdb9230aSGarrett D'Amore 	}
2704bdb9230aSGarrett D'Amore 
2705bdb9230aSGarrett D'Amore 	/* take the buffer from the head of the free list */
2706bdb9230aSGarrett D'Amore 	rp = rbuf_freelist_head;
2707bdb9230aSGarrett D'Amore 	rbuf_freelist_head = rbuf_freelist_head->rbuf_next;
2708bdb9230aSGarrett D'Amore 
2709bdb9230aSGarrett D'Amore 	/* update the used list; put the entry at the end */
2710bdb9230aSGarrett D'Amore 	if (rbuf_usedlist_head == NULL)
2711bdb9230aSGarrett D'Amore 		rbuf_usedlist_head = rp;
2712bdb9230aSGarrett D'Amore 	else
2713bdb9230aSGarrett D'Amore 		rbuf_usedlist_end->rbuf_next = rp;
2714bdb9230aSGarrett D'Amore 	rp->rbuf_next = NULL;
2715bdb9230aSGarrett D'Amore 	rbuf_usedlist_end = rp;
2716bdb9230aSGarrett D'Amore 	rbuf_freebufs--;
2717bdb9230aSGarrett D'Amore 
2718bdb9230aSGarrett D'Amore 	mutex_exit(&dnet_rbuf_lock);
2719bdb9230aSGarrett D'Amore 
2720bdb9230aSGarrett D'Amore 	return (rp);
2721bdb9230aSGarrett D'Amore fail_unbind:
2722bdb9230aSGarrett D'Amore 	(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2723bdb9230aSGarrett D'Amore fail_free:
2724bdb9230aSGarrett D'Amore 	ddi_dma_mem_free(&rp->rbuf_acchdl);
2725bdb9230aSGarrett D'Amore fail_freehdl:
2726bdb9230aSGarrett D'Amore 	ddi_dma_free_handle(&rp->rbuf_dmahdl);
2727bdb9230aSGarrett D'Amore fail_kfree:
2728bdb9230aSGarrett D'Amore 	kmem_free(rp, sizeof (struct rbuf_list));
2729bdb9230aSGarrett D'Amore 	mutex_exit(&dnet_rbuf_lock);
2730bdb9230aSGarrett D'Amore 	return (NULL);
2731bdb9230aSGarrett D'Amore }
2732bdb9230aSGarrett D'Amore 
2733bdb9230aSGarrett D'Amore static void
dnet_rbuf_free(caddr_t vaddr)2734bdb9230aSGarrett D'Amore dnet_rbuf_free(caddr_t vaddr)
2735bdb9230aSGarrett D'Amore {
2736bdb9230aSGarrett D'Amore 	struct rbuf_list *rp, *prev;
2737bdb9230aSGarrett D'Amore 
2738bdb9230aSGarrett D'Amore 	ASSERT(vaddr != NULL);
2739bdb9230aSGarrett D'Amore 	ASSERT(rbuf_usedlist_head != NULL);
2740bdb9230aSGarrett D'Amore 
2741bdb9230aSGarrett D'Amore 	mutex_enter(&dnet_rbuf_lock);
2742bdb9230aSGarrett D'Amore 
2743bdb9230aSGarrett D'Amore 	/* find the entry in the used list */
2744bdb9230aSGarrett D'Amore 	for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) {
2745bdb9230aSGarrett D'Amore 		if (rp->rbuf_vaddr == vaddr)
2746bdb9230aSGarrett D'Amore 			break;
2747bdb9230aSGarrett D'Amore 		prev = rp;
2748bdb9230aSGarrett D'Amore 	}
2749bdb9230aSGarrett D'Amore 
2750bdb9230aSGarrett D'Amore 	if (rp == NULL) {
2751bdb9230aSGarrett D'Amore 		cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p",
2752bdb9230aSGarrett D'Amore 		    (void *)vaddr);
2753bdb9230aSGarrett D'Amore 		mutex_exit(&dnet_rbuf_lock);
2754bdb9230aSGarrett D'Amore 		return;
2755bdb9230aSGarrett D'Amore 	}
2756bdb9230aSGarrett D'Amore 
2757bdb9230aSGarrett D'Amore 	/* update the used list and put the buffer back in the free list */
2758bdb9230aSGarrett D'Amore 	if (rbuf_usedlist_head != rp) {
2759bdb9230aSGarrett D'Amore 		prev->rbuf_next = rp->rbuf_next;
2760bdb9230aSGarrett D'Amore 		if (rbuf_usedlist_end == rp)
2761bdb9230aSGarrett D'Amore 			rbuf_usedlist_end = prev;
2762bdb9230aSGarrett D'Amore 	} else {
2763bdb9230aSGarrett D'Amore 		rbuf_usedlist_head = rp->rbuf_next;
2764bdb9230aSGarrett D'Amore 		if (rbuf_usedlist_end == rp)
2765bdb9230aSGarrett D'Amore 			rbuf_usedlist_end = NULL;
2766bdb9230aSGarrett D'Amore 	}
2767bdb9230aSGarrett D'Amore 	rp->rbuf_next = rbuf_freelist_head;
2768bdb9230aSGarrett D'Amore 	rbuf_freelist_head = rp;
2769bdb9230aSGarrett D'Amore 	rbuf_freebufs++;
2770bdb9230aSGarrett D'Amore 
2771bdb9230aSGarrett D'Amore 	mutex_exit(&dnet_rbuf_lock);
2772bdb9230aSGarrett D'Amore }
2773bdb9230aSGarrett D'Amore 
2774bdb9230aSGarrett D'Amore /*
2775bdb9230aSGarrett D'Amore  * Free the receive buffer used in a stream's message block allocated
2776bdb9230aSGarrett D'Amore  * thru desballoc().
2777bdb9230aSGarrett D'Amore  */
2778bdb9230aSGarrett D'Amore static void
dnet_freemsg_buf(struct free_ptr * frp)2779bdb9230aSGarrett D'Amore dnet_freemsg_buf(struct free_ptr *frp)
2780bdb9230aSGarrett D'Amore {
2781bdb9230aSGarrett D'Amore 	dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */
2782bdb9230aSGarrett D'Amore 	kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */
2783bdb9230aSGarrett D'Amore }
2784bdb9230aSGarrett D'Amore 
2785bdb9230aSGarrett D'Amore /*
2786bdb9230aSGarrett D'Amore  *	========== SROM Read Routines ==========
2787bdb9230aSGarrett D'Amore  */
2788bdb9230aSGarrett D'Amore 
2789bdb9230aSGarrett D'Amore /*
2790bdb9230aSGarrett D'Amore  * The following code gets the SROM information, either by reading it
2791bdb9230aSGarrett D'Amore  * from the device or, failing that, by reading a property.
2792bdb9230aSGarrett D'Amore  */
2793bdb9230aSGarrett 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)2794bdb9230aSGarrett D'Amore dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle,
2795bdb9230aSGarrett D'Amore     caddr_t io_reg, uchar_t *vi, int maxlen)
2796bdb9230aSGarrett D'Amore {
2797bdb9230aSGarrett D'Amore 	int all_ones, zerocheck, i;
2798bdb9230aSGarrett D'Amore 
2799bdb9230aSGarrett D'Amore 	/*
2800bdb9230aSGarrett D'Amore 	 * Load SROM into vendor_info
2801bdb9230aSGarrett D'Amore 	 */
2802bdb9230aSGarrett D'Amore 	if (board_type == DEVICE_ID_21040)
2803bdb9230aSGarrett D'Amore 		dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen);
2804bdb9230aSGarrett D'Amore 	else
2805bdb9230aSGarrett D'Amore 		/* 21041/21140 serial rom */
2806bdb9230aSGarrett D'Amore 		dnet_read21140srom(io_handle, io_reg, vi, maxlen);
2807bdb9230aSGarrett D'Amore 	/*
2808bdb9230aSGarrett D'Amore 	 * If the dumpsrom property is present in the conf file, print
2809bdb9230aSGarrett D'Amore 	 * the contents of the SROM to the console
2810bdb9230aSGarrett D'Amore 	 */
2811bdb9230aSGarrett D'Amore 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
2812bdb9230aSGarrett D'Amore 	    "dumpsrom", 0))
2813bdb9230aSGarrett D'Amore 		dnet_dumpbin("SROM", vi, 1, maxlen);
2814bdb9230aSGarrett D'Amore 
2815bdb9230aSGarrett D'Amore 	for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) {
2816bdb9230aSGarrett D'Amore 		zerocheck |= vi[i];
2817bdb9230aSGarrett D'Amore 		all_ones &= vi[i];
2818bdb9230aSGarrett D'Amore 	}
2819bdb9230aSGarrett D'Amore 	if (zerocheck == 0 || all_ones == 0xff) {
2820bdb9230aSGarrett D'Amore 		return (get_alternative_srom_image(devinfo, vi, maxlen));
2821bdb9230aSGarrett D'Amore 	} else {
2822bdb9230aSGarrett D'Amore #ifdef BUG_4010796
2823bdb9230aSGarrett D'Amore 		set_alternative_srom_image(devinfo, vi, maxlen);
2824bdb9230aSGarrett D'Amore #endif
2825bdb9230aSGarrett D'Amore 		return (0);	/* Primary */
2826bdb9230aSGarrett D'Amore 	}
2827bdb9230aSGarrett D'Amore }
2828bdb9230aSGarrett D'Amore 
2829bdb9230aSGarrett D'Amore /*
2830bdb9230aSGarrett D'Amore  * The function reads the ethernet address of the 21040 adapter
2831bdb9230aSGarrett D'Amore  */
2832bdb9230aSGarrett 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)2833bdb9230aSGarrett D'Amore dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg,
2834bdb9230aSGarrett D'Amore     uchar_t *addr, int *len)
2835bdb9230aSGarrett D'Amore {
2836bdb9230aSGarrett D'Amore 	uint32_t	val;
2837bdb9230aSGarrett D'Amore 	int		i;
2838bdb9230aSGarrett D'Amore 
2839bdb9230aSGarrett D'Amore 	/* No point reading more than the ethernet address */
2840bdb9230aSGarrett D'Amore 	*len = ddi_getprop(DDI_DEV_T_ANY, dip,
2841bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL;
2842bdb9230aSGarrett D'Amore 
2843bdb9230aSGarrett D'Amore 	/* Reset ROM pointer */
2844bdb9230aSGarrett D'Amore 	ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0);
2845bdb9230aSGarrett D'Amore 	for (i = 0; i < *len; i++) {
2846bdb9230aSGarrett D'Amore 		do {
2847bdb9230aSGarrett D'Amore 			val = ddi_get32(io_handle,
2848bdb9230aSGarrett D'Amore 			    REG32(io_reg, ETHER_ROM_REG));
2849bdb9230aSGarrett D'Amore 		} while (val & 0x80000000);
2850bdb9230aSGarrett D'Amore 		addr[i] = val & 0xFF;
2851bdb9230aSGarrett D'Amore 	}
2852bdb9230aSGarrett D'Amore }
2853bdb9230aSGarrett D'Amore 
2854bdb9230aSGarrett D'Amore #define	drv_nsecwait(x)	drv_usecwait(((x)+999)/1000) /* XXX */
2855bdb9230aSGarrett D'Amore 
2856bdb9230aSGarrett D'Amore /*
2857bdb9230aSGarrett D'Amore  * The function reads the SROM	of the 21140 adapter
2858bdb9230aSGarrett D'Amore  */
2859bdb9230aSGarrett D'Amore static void
dnet_read21140srom(ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * addr,int maxlen)2860bdb9230aSGarrett D'Amore dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr,
2861bdb9230aSGarrett D'Amore     int maxlen)
2862bdb9230aSGarrett D'Amore {
2863bdb9230aSGarrett D'Amore 	uint32_t	i, j;
2864bdb9230aSGarrett D'Amore 	uint32_t	dout;
2865bdb9230aSGarrett D'Amore 	uint16_t	word;
2866bdb9230aSGarrett D'Amore 	uint8_t		rom_addr;
2867bdb9230aSGarrett D'Amore 	uint8_t		bit;
2868bdb9230aSGarrett D'Amore 
2869bdb9230aSGarrett D'Amore 
2870bdb9230aSGarrett D'Amore 	rom_addr = 0;
2871bdb9230aSGarrett D'Amore 	for (i = 0; i <	maxlen; i += 2) {
2872bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2873bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM);
2874bdb9230aSGarrett D'Amore 		drv_nsecwait(30);
2875bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2876bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP);
2877bdb9230aSGarrett D'Amore 		drv_nsecwait(50);
2878bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2879bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2880bdb9230aSGarrett D'Amore 		drv_nsecwait(250);
2881bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2882bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP);
2883bdb9230aSGarrett D'Amore 		drv_nsecwait(100);
2884bdb9230aSGarrett D'Amore 
2885bdb9230aSGarrett D'Amore 		/* command */
2886bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2887bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2888bdb9230aSGarrett D'Amore 		drv_nsecwait(150);
2889bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2890bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
2891bdb9230aSGarrett D'Amore 		drv_nsecwait(250);
2892bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2893bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2894bdb9230aSGarrett D'Amore 		drv_nsecwait(250);
2895bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2896bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
2897bdb9230aSGarrett D'Amore 		drv_nsecwait(250);
2898bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2899bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2900bdb9230aSGarrett D'Amore 		drv_nsecwait(100);
2901bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2902bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP);
2903bdb9230aSGarrett D'Amore 		drv_nsecwait(150);
2904bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2905bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2906bdb9230aSGarrett D'Amore 		drv_nsecwait(250);
2907bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2908bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM | SEL_CHIP);
2909bdb9230aSGarrett D'Amore 		drv_nsecwait(100);
2910bdb9230aSGarrett D'Amore 
2911bdb9230aSGarrett D'Amore 		/* Address */
2912bdb9230aSGarrett D'Amore 		for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) {
2913bdb9230aSGarrett D'Amore 			bit = (rom_addr & j) ? DATA_IN : 0;
2914bdb9230aSGarrett D'Amore 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2915bdb9230aSGarrett D'Amore 			    READ_OP | SEL_ROM | SEL_CHIP | bit);
2916bdb9230aSGarrett D'Amore 			drv_nsecwait(150);
2917bdb9230aSGarrett D'Amore 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2918bdb9230aSGarrett D'Amore 			    READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK);
2919bdb9230aSGarrett D'Amore 			drv_nsecwait(250);
2920bdb9230aSGarrett D'Amore 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2921bdb9230aSGarrett D'Amore 			    READ_OP | SEL_ROM | SEL_CHIP | bit);
2922bdb9230aSGarrett D'Amore 			drv_nsecwait(100);
2923bdb9230aSGarrett D'Amore 		}
2924bdb9230aSGarrett D'Amore 		drv_nsecwait(150);
2925bdb9230aSGarrett D'Amore 
2926bdb9230aSGarrett D'Amore 		/* Data */
2927bdb9230aSGarrett D'Amore 		word = 0;
2928bdb9230aSGarrett D'Amore 		for (j = 0x8000; j >= 1; j >>= 1) {
2929bdb9230aSGarrett D'Amore 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2930bdb9230aSGarrett D'Amore 			    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2931bdb9230aSGarrett D'Amore 			drv_nsecwait(100);
2932bdb9230aSGarrett D'Amore 			dout = ddi_get32(io_handle,
2933bdb9230aSGarrett D'Amore 			    REG32(io_reg, ETHER_ROM_REG));
2934bdb9230aSGarrett D'Amore 			drv_nsecwait(150);
2935bdb9230aSGarrett D'Amore 			if (dout & DATA_OUT)
2936bdb9230aSGarrett D'Amore 				word |= j;
2937bdb9230aSGarrett D'Amore 			ddi_put32(io_handle,
2938bdb9230aSGarrett D'Amore 			    REG32(io_reg, ETHER_ROM_REG),
2939bdb9230aSGarrett D'Amore 			    READ_OP | SEL_ROM | SEL_CHIP);
2940bdb9230aSGarrett D'Amore 			drv_nsecwait(250);
2941bdb9230aSGarrett D'Amore 		}
2942bdb9230aSGarrett D'Amore 		addr[i] = (word & 0x0000FF);
2943bdb9230aSGarrett D'Amore 		addr[i + 1] = (word >> 8);
2944bdb9230aSGarrett D'Amore 		rom_addr++;
2945bdb9230aSGarrett D'Amore 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2946bdb9230aSGarrett D'Amore 		    READ_OP | SEL_ROM);
2947bdb9230aSGarrett D'Amore 		drv_nsecwait(100);
2948bdb9230aSGarrett D'Amore 	}
2949bdb9230aSGarrett D'Amore }
2950bdb9230aSGarrett D'Amore 
2951bdb9230aSGarrett D'Amore 
2952bdb9230aSGarrett D'Amore /*
2953bdb9230aSGarrett D'Amore  * XXX NEEDSWORK
2954bdb9230aSGarrett D'Amore  *
2955bdb9230aSGarrett D'Amore  * Some lame multiport cards have only one SROM, which can be accessed
2956bdb9230aSGarrett D'Amore  * only from the "first" 21x4x chip, whichever that one is.  If we can't
2957bdb9230aSGarrett D'Amore  * get at our SROM, we look for its contents in a property instead, which
2958bdb9230aSGarrett D'Amore  * we rely on the bootstrap to have properly set.
2959bdb9230aSGarrett D'Amore  * #ifdef BUG_4010796
2960bdb9230aSGarrett D'Amore  * We also have a hack to try to set it ourselves, when the "first" port
2961bdb9230aSGarrett D'Amore  * attaches, if it has not already been properly set.  However, this method
2962bdb9230aSGarrett D'Amore  * is not reliable, since it makes the unwarrented assumption that the
2963bdb9230aSGarrett D'Amore  * "first" port will attach first.
2964bdb9230aSGarrett D'Amore  * #endif
2965bdb9230aSGarrett D'Amore  */
2966bdb9230aSGarrett D'Amore 
2967bdb9230aSGarrett D'Amore static int
get_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)2968bdb9230aSGarrett D'Amore get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
2969bdb9230aSGarrett D'Amore {
2970bdb9230aSGarrett D'Amore 	int	l = len;
2971bdb9230aSGarrett D'Amore 
2972bdb9230aSGarrett D'Amore 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
2973bdb9230aSGarrett D'Amore 	    "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS &&
2974bdb9230aSGarrett D'Amore 	    (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY,
2975bdb9230aSGarrett D'Amore 	    ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM",
2976bdb9230aSGarrett D'Amore 	    (caddr_t)vi, &len) != DDI_PROP_SUCCESS)
2977bdb9230aSGarrett D'Amore 		return (-1);	/* Can't find it! */
2978bdb9230aSGarrett D'Amore 
2979bdb9230aSGarrett D'Amore 	/*
2980bdb9230aSGarrett D'Amore 	 * The return value from this routine specifies which port number
2981bdb9230aSGarrett D'Amore 	 * we are.  The primary port is denoted port 0.  On a QUAD card we
2982bdb9230aSGarrett D'Amore 	 * should return 1, 2, and 3 from this routine.  The return value
2983bdb9230aSGarrett D'Amore 	 * is used to modify the ethernet address from the SROM data.
2984bdb9230aSGarrett D'Amore 	 */
2985bdb9230aSGarrett D'Amore 
2986bdb9230aSGarrett D'Amore #ifdef BUG_4010796
2987bdb9230aSGarrett D'Amore 	{
2988bdb9230aSGarrett D'Amore 	/*
2989bdb9230aSGarrett D'Amore 	 * For the present, we remember the device number of our primary
2990bdb9230aSGarrett D'Amore 	 * sibling and hope we and our other siblings are consecutively
2991bdb9230aSGarrett D'Amore 	 * numbered up from there.  In the future perhaps the bootstrap
2992bdb9230aSGarrett D'Amore 	 * will pass us the necessary information telling us which physical
2993bdb9230aSGarrett D'Amore 	 * port we really are.
2994bdb9230aSGarrett D'Amore 	 */
2995bdb9230aSGarrett D'Amore 	pci_regspec_t	*assignp;
2996bdb9230aSGarrett D'Amore 	int		assign_len;
2997bdb9230aSGarrett D'Amore 	int		devnum;
2998bdb9230aSGarrett D'Amore 	int		primary_devnum;
2999bdb9230aSGarrett D'Amore 
3000bdb9230aSGarrett D'Amore 	primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0,
3001bdb9230aSGarrett D'Amore 	    "DNET_DEVNUM", -1);
3002bdb9230aSGarrett D'Amore 	if (primary_devnum == -1)
3003bdb9230aSGarrett D'Amore 		return (1);	/* XXX NEEDSWORK -- We have no better idea */
3004bdb9230aSGarrett D'Amore 
3005bdb9230aSGarrett D'Amore 	if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3006bdb9230aSGarrett D'Amore 	    "assigned-addresses", (caddr_t)&assignp,
3007bdb9230aSGarrett D'Amore 	    &assign_len)) != DDI_PROP_SUCCESS)
3008bdb9230aSGarrett D'Amore 		return (1);	/* XXX NEEDSWORK -- We have no better idea */
3009bdb9230aSGarrett D'Amore 
3010bdb9230aSGarrett D'Amore 	devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3011bdb9230aSGarrett D'Amore 	kmem_free(assignp, assign_len);
3012bdb9230aSGarrett D'Amore 	return (devnum - primary_devnum);
3013bdb9230aSGarrett D'Amore 	}
3014bdb9230aSGarrett D'Amore #else
3015bdb9230aSGarrett D'Amore 	return (1);	/* XXX NEEDSWORK -- We have no better idea */
3016bdb9230aSGarrett D'Amore #endif
3017bdb9230aSGarrett D'Amore }
3018bdb9230aSGarrett D'Amore 
3019bdb9230aSGarrett D'Amore 
3020bdb9230aSGarrett D'Amore #ifdef BUG_4010796
3021bdb9230aSGarrett D'Amore static void
set_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)3022bdb9230aSGarrett D'Amore set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
3023bdb9230aSGarrett D'Amore {
3024bdb9230aSGarrett D'Amore 	int		proplen;
3025bdb9230aSGarrett D'Amore 	pci_regspec_t	*assignp;
3026bdb9230aSGarrett D'Amore 	int		assign_len;
3027bdb9230aSGarrett D'Amore 	int		devnum;
3028bdb9230aSGarrett D'Amore 
3029bdb9230aSGarrett D'Amore 	if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3030bdb9230aSGarrett D'Amore 	    "DNET_SROM", &proplen) == DDI_PROP_SUCCESS ||
3031bdb9230aSGarrett D'Amore 	    ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3032bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS)
3033bdb9230aSGarrett D'Amore 		return;		/* Already done! */
3034bdb9230aSGarrett D'Amore 
3035bdb9230aSGarrett D'Amore 	/* function return value ignored */
3036bdb9230aSGarrett D'Amore 	(void) ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3037bdb9230aSGarrett D'Amore 	    ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len);
3038bdb9230aSGarrett D'Amore 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo,
3039bdb9230aSGarrett D'Amore 	    "DNET_HACK", "hack");
3040bdb9230aSGarrett D'Amore 
3041bdb9230aSGarrett D'Amore 	if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3042bdb9230aSGarrett D'Amore 	    "assigned-addresses", (caddr_t)&assignp,
3043bdb9230aSGarrett D'Amore 	    &assign_len)) == DDI_PROP_SUCCESS) {
3044bdb9230aSGarrett D'Amore 		devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3045bdb9230aSGarrett D'Amore 		kmem_free(assignp, assign_len);
3046bdb9230aSGarrett D'Amore 		/* function return value ignored */
3047bdb9230aSGarrett D'Amore 		(void) ddi_prop_update_int(DDI_DEV_T_NONE,
3048bdb9230aSGarrett D'Amore 		    ddi_get_parent(devinfo), "DNET_DEVNUM", devnum);
3049bdb9230aSGarrett D'Amore 	}
3050bdb9230aSGarrett D'Amore }
3051bdb9230aSGarrett D'Amore #endif
3052bdb9230aSGarrett D'Amore 
3053bdb9230aSGarrett D'Amore /*
3054bdb9230aSGarrett D'Amore  *	========== SROM Parsing Routines ==========
3055bdb9230aSGarrett D'Amore  */
3056bdb9230aSGarrett D'Amore 
3057bdb9230aSGarrett D'Amore static int
check_srom_valid(uchar_t * vi)3058bdb9230aSGarrett D'Amore check_srom_valid(uchar_t *vi)
3059bdb9230aSGarrett D'Amore {
3060bdb9230aSGarrett D'Amore 	int		word, bit;
3061bdb9230aSGarrett D'Amore 	uint8_t		crc;
3062bdb9230aSGarrett D'Amore 	uint16_t	*wvi;		/* word16 pointer to vendor info */
3063bdb9230aSGarrett D'Amore 	uint16_t	bitval;
3064bdb9230aSGarrett D'Amore 
3065bdb9230aSGarrett D'Amore 	/* verify that the number of controllers on the card is within range */
3066bdb9230aSGarrett D'Amore 	if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS)
3067bdb9230aSGarrett D'Amore 		return (0);
3068bdb9230aSGarrett D'Amore 
3069bdb9230aSGarrett D'Amore 	/*
3070bdb9230aSGarrett D'Amore 	 * version 1 and 3 of this card did not check the id block CRC value
3071bdb9230aSGarrett D'Amore 	 * and this can't be changed without retesting every supported card
3072bdb9230aSGarrett D'Amore 	 *
3073bdb9230aSGarrett D'Amore 	 * however version 4 of the SROM can have this test applied
3074bdb9230aSGarrett D'Amore 	 * without fear of breaking something that used to work.
3075bdb9230aSGarrett D'Amore 	 * the CRC algorithm is taken from the Intel document
3076bdb9230aSGarrett D'Amore 	 *	"21x4 Serial ROM Format"
3077bdb9230aSGarrett D'Amore 	 *	version 4.09
3078bdb9230aSGarrett D'Amore 	 *	3-Mar-1999
3079bdb9230aSGarrett D'Amore 	 */
3080bdb9230aSGarrett D'Amore 
3081bdb9230aSGarrett D'Amore 	switch (vi[SROM_VERSION]) {
3082bdb9230aSGarrett D'Amore 	case 1:
3083bdb9230aSGarrett D'Amore 	    /* fallthru */
3084bdb9230aSGarrett D'Amore 	case 3:
3085bdb9230aSGarrett D'Amore 		return (vi[SROM_MBZ] == 0 &&	/* must be zero */
3086bdb9230aSGarrett D'Amore 		    vi[SROM_MBZ2] == 0 &&	/* must be zero */
3087bdb9230aSGarrett D'Amore 		    vi[SROM_MBZ3] == 0);	/* must be zero */
3088bdb9230aSGarrett D'Amore 
3089bdb9230aSGarrett D'Amore 	case 4:
3090bdb9230aSGarrett D'Amore 		wvi = (uint16_t *)vi;
3091bdb9230aSGarrett D'Amore 		crc = 0xff;
3092bdb9230aSGarrett D'Amore 		for (word = 0; word < 9; word++)
3093bdb9230aSGarrett D'Amore 			for (bit = 15; bit >= 0; bit--) {
3094bdb9230aSGarrett D'Amore 				if (word == 8 && bit == 7)
3095bdb9230aSGarrett D'Amore 					return (crc == vi[16]);
3096bdb9230aSGarrett D'Amore 				bitval =
3097bdb9230aSGarrett D'Amore 				    ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1);
3098bdb9230aSGarrett D'Amore 				crc <<= 1;
3099bdb9230aSGarrett D'Amore 				if (bitval == 1) {
3100bdb9230aSGarrett D'Amore 					crc ^= 7;
3101bdb9230aSGarrett D'Amore 				}
3102bdb9230aSGarrett D'Amore 			}
3103daefc4e3SToomas Soome 		/* FALLTHROUGH */
3104bdb9230aSGarrett D'Amore 
3105bdb9230aSGarrett D'Amore 	default:
3106bdb9230aSGarrett D'Amore 		return (0);
3107bdb9230aSGarrett D'Amore 	}
3108bdb9230aSGarrett D'Amore }
3109bdb9230aSGarrett D'Amore 
3110bdb9230aSGarrett D'Amore /*
3111bdb9230aSGarrett D'Amore  *	========== Active Media Determination Routines ==========
3112bdb9230aSGarrett D'Amore  */
3113bdb9230aSGarrett D'Amore 
3114bdb9230aSGarrett D'Amore /* This routine is also called for V3 Compact and extended type 0 SROMs */
3115bdb9230aSGarrett D'Amore static int
is_fdmedia(int media)3116bdb9230aSGarrett D'Amore is_fdmedia(int media)
3117bdb9230aSGarrett D'Amore {
3118bdb9230aSGarrett D'Amore 	if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD)
3119bdb9230aSGarrett D'Amore 		return (1);
3120bdb9230aSGarrett D'Amore 	else
3121bdb9230aSGarrett D'Amore 		return (0);
3122bdb9230aSGarrett D'Amore }
3123bdb9230aSGarrett D'Amore 
3124bdb9230aSGarrett D'Amore /*
3125bdb9230aSGarrett D'Amore  * "Linkset" is used to merge media that use the same link test check. So,
3126bdb9230aSGarrett D'Amore  * if the TP link is added to the linkset, so is the TP Full duplex link.
3127bdb9230aSGarrett D'Amore  * Used to avoid checking the same link status twice.
3128bdb9230aSGarrett D'Amore  */
3129bdb9230aSGarrett D'Amore static void
linkset_add(uint32_t * set,int media)3130bdb9230aSGarrett D'Amore linkset_add(uint32_t *set, int media)
3131bdb9230aSGarrett D'Amore {
3132bdb9230aSGarrett D'Amore 	if (media == MEDIA_TP_FD || media == MEDIA_TP)
3133bdb9230aSGarrett D'Amore 		*set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP);
3134bdb9230aSGarrett D'Amore 	else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR)
3135bdb9230aSGarrett D'Amore 		*set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR);
3136bdb9230aSGarrett D'Amore 	else *set |= 1UL<<media;
3137bdb9230aSGarrett D'Amore }
3138bdb9230aSGarrett D'Amore static int
linkset_isset(uint32_t linkset,int media)3139bdb9230aSGarrett D'Amore linkset_isset(uint32_t linkset, int media)
3140bdb9230aSGarrett D'Amore {
3141bdb9230aSGarrett D'Amore 	return (((1UL<<media)  & linkset) ? 1:0);
3142bdb9230aSGarrett D'Amore }
3143bdb9230aSGarrett D'Amore 
3144bdb9230aSGarrett D'Amore /*
3145bdb9230aSGarrett D'Amore  * The following code detects which Media is connected for 21041/21140
3146bdb9230aSGarrett D'Amore  * Expect to change this code to support new 21140 variants.
3147bdb9230aSGarrett D'Amore  * find_active_media() - called with intrlock held.
3148bdb9230aSGarrett D'Amore  */
3149bdb9230aSGarrett D'Amore static void
find_active_media(struct dnetinstance * dnetp)315098e8d175SSteven Stallion find_active_media(struct dnetinstance *dnetp)
3151bdb9230aSGarrett D'Amore {
3152bdb9230aSGarrett D'Amore 	int i;
3153bdb9230aSGarrett D'Amore 	media_block_t *block;
3154bdb9230aSGarrett D'Amore 	media_block_t *best_allowed = NULL;
3155bdb9230aSGarrett D'Amore 	media_block_t *hd_found = NULL;
3156bdb9230aSGarrett D'Amore 	media_block_t *fd_found = NULL;
3157bdb9230aSGarrett D'Amore 	LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
3158bdb9230aSGarrett D'Amore 	uint32_t checked = 0, links_up = 0;
3159bdb9230aSGarrett D'Amore 
3160bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
316198e8d175SSteven Stallion 
3162bdb9230aSGarrett D'Amore 	dnetp->selected_media_block = leaf->default_block;
3163bdb9230aSGarrett D'Amore 
3164bdb9230aSGarrett D'Amore 	if (dnetp->phyaddr != -1) {
3165bdb9230aSGarrett D'Amore 		dnetp->selected_media_block = leaf->mii_block;
316698e8d175SSteven Stallion 		setup_block(dnetp);
3167bdb9230aSGarrett D'Amore 
3168bdb9230aSGarrett D'Amore 		if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3169bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, "portmon", 1)) {
3170bdb9230aSGarrett D'Amore 			/* XXX return value ignored */
3171bdb9230aSGarrett D'Amore 			(void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb,
3172bdb9230aSGarrett D'Amore 			    &dnetp->intrlock);
3173bdb9230aSGarrett D'Amore 			/*
3174bdb9230aSGarrett D'Amore 			 * If the port monitor detects the link is already
3175bdb9230aSGarrett D'Amore 			 * up, there is no point going through the rest of the
3176bdb9230aSGarrett D'Amore 			 * link sense
3177bdb9230aSGarrett D'Amore 			 */
3178bdb9230aSGarrett D'Amore 			if (dnetp->mii_up) {
3179bdb9230aSGarrett D'Amore 				return;
3180bdb9230aSGarrett D'Amore 			}
3181bdb9230aSGarrett D'Amore 		}
3182bdb9230aSGarrett D'Amore 	}
3183bdb9230aSGarrett D'Amore 
3184bdb9230aSGarrett D'Amore 	/*
3185bdb9230aSGarrett D'Amore 	 * Media is searched for in order of Precedence. This DEC SROM spec
3186bdb9230aSGarrett D'Amore 	 * tells us that the first media entry in the SROM is the lowest
3187bdb9230aSGarrett D'Amore 	 * precedence and should be checked last. This is why we go to the last
3188bdb9230aSGarrett D'Amore 	 * Media block and work back to the beginning.
3189bdb9230aSGarrett D'Amore 	 *
3190bdb9230aSGarrett D'Amore 	 * However, some older SROMs (Cogent EM110's etc.) have this the wrong
3191bdb9230aSGarrett D'Amore 	 * way around. As a result, following the SROM spec would result in a
3192bdb9230aSGarrett D'Amore 	 * 10 link being chosen over a 100 link if both media are available.
3193bdb9230aSGarrett D'Amore 	 * So we continue trying the media until we have at least tried the
3194bdb9230aSGarrett D'Amore 	 * DEFAULT media.
3195bdb9230aSGarrett D'Amore 	 */
3196bdb9230aSGarrett D'Amore 
3197bdb9230aSGarrett D'Amore 	/* Search for an active medium, and select it */
3198bdb9230aSGarrett D'Amore 	for (block = leaf->block + leaf->block_count  - 1;
3199bdb9230aSGarrett D'Amore 	    block >= leaf->block; block--) {
3200bdb9230aSGarrett D'Amore 		int media = block->media_code;
3201bdb9230aSGarrett D'Amore 
3202bdb9230aSGarrett D'Amore 		/* User settings disallow selection of this block */
3203bdb9230aSGarrett D'Amore 		if (dnetp->disallowed_media & (1UL<<media))
3204bdb9230aSGarrett D'Amore 			continue;
3205bdb9230aSGarrett D'Amore 
3206bdb9230aSGarrett D'Amore 		/* We may not be able to pick the default */
3207bdb9230aSGarrett D'Amore 		if (best_allowed == NULL || block == leaf->default_block)
3208bdb9230aSGarrett D'Amore 			best_allowed = block;
3209bdb9230aSGarrett D'Amore #ifdef DEBUG
3210bdb9230aSGarrett D'Amore 		if (dnetdebug & DNETSENSE)
3211bdb9230aSGarrett D'Amore 			cmn_err(CE_NOTE, "Testing %s medium (block type %d)",
3212bdb9230aSGarrett D'Amore 			    media_str[media], block->type);
3213bdb9230aSGarrett D'Amore #endif
3214bdb9230aSGarrett D'Amore 
3215bdb9230aSGarrett D'Amore 		dnetp->selected_media_block = block;
3216bdb9230aSGarrett D'Amore 		switch (block->type) {
3217bdb9230aSGarrett D'Amore 
3218bdb9230aSGarrett D'Amore 		case 2: /* SIA Media block: Best we can do is send a packet */
321998e8d175SSteven Stallion 			setup_block(dnetp);
322098e8d175SSteven Stallion 			if (send_test_packet(dnetp)) {
3221bdb9230aSGarrett D'Amore 				if (!is_fdmedia(media))
3222bdb9230aSGarrett D'Amore 					return;
3223bdb9230aSGarrett D'Amore 				if (!fd_found)
3224bdb9230aSGarrett D'Amore 					fd_found = block;
3225bdb9230aSGarrett D'Amore 			}
3226bdb9230aSGarrett D'Amore 			break;
3227bdb9230aSGarrett D'Amore 
3228bdb9230aSGarrett D'Amore 		/* SYM/SCR or TP block: Use the link-sense bits */
3229bdb9230aSGarrett D'Amore 		case 0:
3230bdb9230aSGarrett D'Amore 			if (!linkset_isset(checked, media)) {
3231bdb9230aSGarrett D'Amore 				linkset_add(&checked, media);
3232bdb9230aSGarrett D'Amore 				if (((media == MEDIA_BNC ||
3233bdb9230aSGarrett D'Amore 				    media == MEDIA_AUI) &&
323498e8d175SSteven Stallion 				    send_test_packet(dnetp)) ||
323598e8d175SSteven Stallion 				    dnet_link_sense(dnetp))
3236bdb9230aSGarrett D'Amore 					linkset_add(&links_up, media);
3237bdb9230aSGarrett D'Amore 			}
3238bdb9230aSGarrett D'Amore 
3239bdb9230aSGarrett D'Amore 			if (linkset_isset(links_up, media)) {
3240bdb9230aSGarrett D'Amore 				/*
3241bdb9230aSGarrett D'Amore 				 * Half Duplex is *always* the favoured media.
3242bdb9230aSGarrett D'Amore 				 * Full Duplex can be set and forced via the
3243bdb9230aSGarrett D'Amore 				 * conf file.
3244bdb9230aSGarrett D'Amore 				 */
3245bdb9230aSGarrett D'Amore 				if (!is_fdmedia(media) &&
3246bdb9230aSGarrett D'Amore 				    dnetp->selected_media_block ==
3247bdb9230aSGarrett D'Amore 				    leaf->default_block) {
3248bdb9230aSGarrett D'Amore 					/*
3249bdb9230aSGarrett D'Amore 					 * Cogent cards have the media in
3250bdb9230aSGarrett D'Amore 					 * opposite order to the spec.,
3251bdb9230aSGarrett D'Amore 					 * this code forces the media test to
3252bdb9230aSGarrett D'Amore 					 * keep going until the default media
3253bdb9230aSGarrett D'Amore 					 * is tested.
3254bdb9230aSGarrett D'Amore 					 *
3255bdb9230aSGarrett D'Amore 					 * In Cogent case, 10, 10FD, 100FD, 100
3256bdb9230aSGarrett D'Amore 					 * 100 is the default but 10 could have
3257bdb9230aSGarrett D'Amore 					 * been detected and would have been
3258bdb9230aSGarrett D'Amore 					 * chosen but now we force it through to
3259bdb9230aSGarrett D'Amore 					 * 100.
3260bdb9230aSGarrett D'Amore 					 */
326198e8d175SSteven Stallion 					setup_block(dnetp);
3262bdb9230aSGarrett D'Amore 					return;
3263bdb9230aSGarrett D'Amore 				} else if (!is_fdmedia(media)) {
3264bdb9230aSGarrett D'Amore 					/*
3265bdb9230aSGarrett D'Amore 					 * This allows all the others to work
3266bdb9230aSGarrett D'Amore 					 * properly by remembering the media
3267bdb9230aSGarrett D'Amore 					 * that works and not defaulting to
3268bdb9230aSGarrett D'Amore 					 * a FD link.
3269bdb9230aSGarrett D'Amore 					 */
3270bdb9230aSGarrett D'Amore 						if (hd_found == NULL)
3271bdb9230aSGarrett D'Amore 							hd_found = block;
3272bdb9230aSGarrett D'Amore 				} else if (fd_found == NULL) {
3273bdb9230aSGarrett D'Amore 					/*
3274bdb9230aSGarrett D'Amore 					 * No media have already been found
3275bdb9230aSGarrett D'Amore 					 * so far, this is FD, it works so
3276bdb9230aSGarrett D'Amore 					 * remember it and if no others are
3277bdb9230aSGarrett D'Amore 					 * detected, use it.
3278bdb9230aSGarrett D'Amore 					 */
3279bdb9230aSGarrett D'Amore 					fd_found = block;
3280bdb9230aSGarrett D'Amore 				}
3281bdb9230aSGarrett D'Amore 			}
3282bdb9230aSGarrett D'Amore 			break;
3283bdb9230aSGarrett D'Amore 
3284bdb9230aSGarrett D'Amore 		/*
3285bdb9230aSGarrett D'Amore 		 * MII block: May take up to a second or so to settle if
3286bdb9230aSGarrett D'Amore 		 * setup causes a PHY reset
3287bdb9230aSGarrett D'Amore 		 */
3288bdb9230aSGarrett D'Amore 		case 1: case 3:
328998e8d175SSteven Stallion 			setup_block(dnetp);
3290bdb9230aSGarrett D'Amore 			for (i = 0; ; i++) {
3291bdb9230aSGarrett D'Amore 				if (mii_linkup(dnetp->mii, dnetp->phyaddr)) {
3292bdb9230aSGarrett D'Amore 					/* XXX function return value ignored */
3293bdb9230aSGarrett D'Amore 					(void) mii_getspeed(dnetp->mii,
3294bdb9230aSGarrett D'Amore 					    dnetp->phyaddr,
3295bdb9230aSGarrett D'Amore 					    &dnetp->mii_speed,
3296bdb9230aSGarrett D'Amore 					    &dnetp->mii_duplex);
3297bdb9230aSGarrett D'Amore 					dnetp->mii_up = 1;
3298bdb9230aSGarrett D'Amore 					leaf->mii_block = block;
3299bdb9230aSGarrett D'Amore 					return;
3300bdb9230aSGarrett D'Amore 				}
3301bdb9230aSGarrett D'Amore 				if (i == 10)
3302bdb9230aSGarrett D'Amore 					break;
3303bdb9230aSGarrett D'Amore 				delay(drv_usectohz(150000));
3304bdb9230aSGarrett D'Amore 			}
3305bdb9230aSGarrett D'Amore 			dnetp->mii_up = 0;
3306bdb9230aSGarrett D'Amore 			break;
3307bdb9230aSGarrett D'Amore 		}
3308bdb9230aSGarrett D'Amore 	} /* for loop */
3309bdb9230aSGarrett D'Amore 	if (hd_found) {
3310bdb9230aSGarrett D'Amore 		dnetp->selected_media_block = hd_found;
3311bdb9230aSGarrett D'Amore 	} else if (fd_found) {
3312bdb9230aSGarrett D'Amore 		dnetp->selected_media_block = fd_found;
3313bdb9230aSGarrett D'Amore 	} else {
3314bdb9230aSGarrett D'Amore 		if (best_allowed == NULL)
3315bdb9230aSGarrett D'Amore 			best_allowed = leaf->default_block;
3316bdb9230aSGarrett D'Amore 		dnetp->selected_media_block = best_allowed;
3317bdb9230aSGarrett D'Amore 		cmn_err(CE_WARN, "!dnet: Default media selected\n");
3318bdb9230aSGarrett D'Amore 	}
331998e8d175SSteven Stallion 	setup_block(dnetp);
3320bdb9230aSGarrett D'Amore }
3321bdb9230aSGarrett D'Amore 
3322bdb9230aSGarrett D'Amore /*
3323bdb9230aSGarrett D'Amore  * Do anything neccessary to select the selected_media_block.
3324bdb9230aSGarrett D'Amore  * setup_block() - called with intrlock held.
3325bdb9230aSGarrett D'Amore  */
3326bdb9230aSGarrett D'Amore static void
setup_block(struct dnetinstance * dnetp)332798e8d175SSteven Stallion setup_block(struct dnetinstance *dnetp)
3328bdb9230aSGarrett D'Amore {
332998e8d175SSteven Stallion 	dnet_reset_board(dnetp);
333098e8d175SSteven Stallion 	dnet_init_board(dnetp);
3331bdb9230aSGarrett D'Amore 	/* XXX function return value ignored */
333298e8d175SSteven Stallion 	(void) dnet_start(dnetp);
3333bdb9230aSGarrett D'Amore }
3334bdb9230aSGarrett D'Amore 
3335bdb9230aSGarrett D'Amore /* dnet_link_sense() - called with intrlock held */
3336bdb9230aSGarrett D'Amore static int
dnet_link_sense(struct dnetinstance * dnetp)333798e8d175SSteven Stallion dnet_link_sense(struct dnetinstance *dnetp)
3338bdb9230aSGarrett D'Amore {
3339bdb9230aSGarrett D'Amore 	/*
3340bdb9230aSGarrett D'Amore 	 * This routine makes use of the command word from the srom config.
3341bdb9230aSGarrett D'Amore 	 * Details of the auto-sensing information contained in this can
3342bdb9230aSGarrett D'Amore 	 * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03"
3343bdb9230aSGarrett D'Amore 	 * spec. Section 4.3.2.1, and 4.5.2.1.3
3344bdb9230aSGarrett D'Amore 	 */
3345bdb9230aSGarrett D'Amore 	media_block_t *block = dnetp->selected_media_block;
3346bdb9230aSGarrett D'Amore 	uint32_t link, status, mask, polarity;
3347bdb9230aSGarrett D'Amore 	int settletime, stabletime, waittime, upsamples;
3348bdb9230aSGarrett D'Amore 	int delay_100, delay_10;
3349bdb9230aSGarrett D'Amore 
3350bdb9230aSGarrett D'Amore 
3351bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3352bdb9230aSGarrett D'Amore 	/* Don't autosense if the medium does not support it */
3353bdb9230aSGarrett D'Amore 	if (block->command & (1 << 15)) {
3354bdb9230aSGarrett D'Amore 		/* This should be the default block */
3355bdb9230aSGarrett D'Amore 		if (block->command & (1UL<<14))
3356bdb9230aSGarrett D'Amore 			dnetp->sr.leaf[dnetp->leaf].default_block = block;
3357bdb9230aSGarrett D'Amore 		return (0);
3358bdb9230aSGarrett D'Amore 	}
3359bdb9230aSGarrett D'Amore 
3360bdb9230aSGarrett D'Amore 	delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3361bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, "autosense-delay-100", 2000);
3362bdb9230aSGarrett D'Amore 
3363bdb9230aSGarrett D'Amore 	delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3364bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, "autosense-delay-10", 400);
3365bdb9230aSGarrett D'Amore 
3366bdb9230aSGarrett D'Amore 	/*
3367bdb9230aSGarrett D'Amore 	 * Scrambler may need to be disabled for link sensing
3368bdb9230aSGarrett D'Amore 	 * to work
3369bdb9230aSGarrett D'Amore 	 */
3370bdb9230aSGarrett D'Amore 	dnetp->disable_scrambler = 1;
337198e8d175SSteven Stallion 	setup_block(dnetp);
3372bdb9230aSGarrett D'Amore 	dnetp->disable_scrambler = 0;
3373bdb9230aSGarrett D'Amore 
3374bdb9230aSGarrett D'Amore 	if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD)
3375bdb9230aSGarrett D'Amore 		settletime = delay_10;
3376bdb9230aSGarrett D'Amore 	else
3377bdb9230aSGarrett D'Amore 		settletime = delay_100;
3378bdb9230aSGarrett D'Amore 	stabletime = settletime / 4;
3379bdb9230aSGarrett D'Amore 
3380bdb9230aSGarrett D'Amore 	mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1);
3381bdb9230aSGarrett D'Amore 	polarity = block->command & CMD_POL ? 0xffffffff : 0;
3382bdb9230aSGarrett D'Amore 
3383bdb9230aSGarrett D'Amore 	for (waittime = 0, upsamples = 0;
3384bdb9230aSGarrett D'Amore 	    waittime <= settletime + stabletime && upsamples < 8;
3385bdb9230aSGarrett D'Amore 	    waittime += stabletime/8) {
3386bdb9230aSGarrett D'Amore 		delay(drv_usectohz(stabletime*1000 / 8));
3387bdb9230aSGarrett D'Amore 		status = read_gpr(dnetp);
3388bdb9230aSGarrett D'Amore 		link = (status^polarity) & mask;
3389bdb9230aSGarrett D'Amore 		if (link)
3390bdb9230aSGarrett D'Amore 			upsamples++;
3391bdb9230aSGarrett D'Amore 		else
3392bdb9230aSGarrett D'Amore 			upsamples = 0;
3393bdb9230aSGarrett D'Amore 	}
3394bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3395bdb9230aSGarrett D'Amore 	if (dnetdebug & DNETSENSE)
3396bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x "
3397bdb9230aSGarrett D'Amore 		    "mask:%x link:%x",
3398bdb9230aSGarrett D'Amore 		    upsamples == 8 ? "UP":"DOWN",
3399bdb9230aSGarrett D'Amore 		    upsamples, status, polarity, mask, link);
3400bdb9230aSGarrett D'Amore #endif
3401bdb9230aSGarrett D'Amore 	if (upsamples == 8)
3402bdb9230aSGarrett D'Amore 		return (1);
3403bdb9230aSGarrett D'Amore 	return (0);
3404bdb9230aSGarrett D'Amore }
3405bdb9230aSGarrett D'Amore 
3406bdb9230aSGarrett D'Amore static int
send_test_packet(struct dnetinstance * dnetp)340798e8d175SSteven Stallion send_test_packet(struct dnetinstance *dnetp)
3408bdb9230aSGarrett D'Amore {
3409bdb9230aSGarrett D'Amore 	int packet_delay;
3410bdb9230aSGarrett D'Amore 	struct tx_desc_type *desc;
3411bdb9230aSGarrett D'Amore 	int bufindex;
3412bdb9230aSGarrett D'Amore 	int media_code = dnetp->selected_media_block->media_code;
3413bdb9230aSGarrett D'Amore 	uint32_t del;
3414bdb9230aSGarrett D'Amore 
3415bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3416bdb9230aSGarrett D'Amore 	/*
3417bdb9230aSGarrett D'Amore 	 * For a successful test packet, the card must have settled into
3418bdb9230aSGarrett D'Amore 	 * its current setting.  Almost all cards we've tested manage to
3419bdb9230aSGarrett D'Amore 	 * do this with all media within 50ms.  However, the SMC 8432
3420bdb9230aSGarrett D'Amore 	 * requires 300ms to settle into BNC mode.  We now only do this
3421bdb9230aSGarrett D'Amore 	 * from attach, and we do sleeping delay() instead of drv_usecwait()
3422bdb9230aSGarrett D'Amore 	 * so we hope this .2 second delay won't cause too much suffering.
3423bdb9230aSGarrett D'Amore 	 * ALSO: with an autonegotiating hub, an aditional 1 second delay is
3424bdb9230aSGarrett D'Amore 	 * required. This is done if the media type is TP
3425bdb9230aSGarrett D'Amore 	 */
3426bdb9230aSGarrett D'Amore 	if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) {
3427bdb9230aSGarrett D'Amore 		packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3428bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000);
3429bdb9230aSGarrett D'Amore 	} else {
3430bdb9230aSGarrett D'Amore 		packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3431bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, "test_packet_delay", 300000);
3432bdb9230aSGarrett D'Amore 	}
3433bdb9230aSGarrett D'Amore 	delay(drv_usectohz(packet_delay));
3434bdb9230aSGarrett D'Amore 
3435bdb9230aSGarrett D'Amore 	desc = dnetp->tx_desc;
3436bdb9230aSGarrett D'Amore 
3437bdb9230aSGarrett D'Amore 	bufindex = dnetp->tx_current_desc;
343898e8d175SSteven Stallion 	if (alloc_descriptor(dnetp) == FAILURE) {
3439bdb9230aSGarrett D'Amore 		cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor"
3440bdb9230aSGarrett D'Amore 		    "failed");
3441bdb9230aSGarrett D'Amore 		return (0);
3442bdb9230aSGarrett D'Amore 	}
3443bdb9230aSGarrett D'Amore 
3444bdb9230aSGarrett D'Amore 	/*
3445bdb9230aSGarrett D'Amore 	 * use setup buffer as the buffer for the test packet
3446bdb9230aSGarrett D'Amore 	 * instead of allocating one.
3447bdb9230aSGarrett D'Amore 	 */
3448bdb9230aSGarrett D'Amore 
3449bdb9230aSGarrett D'Amore 	ASSERT(dnetp->setup_buf_vaddr != NULL);
3450bdb9230aSGarrett D'Amore 	/* Put something decent in dest address so we don't annoy other cards */
3451bdb9230aSGarrett D'Amore 	BCOPY((caddr_t)dnetp->curr_macaddr,
3452bdb9230aSGarrett D'Amore 	    (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL);
3453bdb9230aSGarrett D'Amore 	BCOPY((caddr_t)dnetp->curr_macaddr,
3454bdb9230aSGarrett D'Amore 	    (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL);
3455bdb9230aSGarrett D'Amore 
3456bdb9230aSGarrett D'Amore 	desc[bufindex].buffer1 = dnetp->setup_buf_paddr;
3457bdb9230aSGarrett D'Amore 	desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE;
3458bdb9230aSGarrett D'Amore 	desc[bufindex].buffer2 = (uint32_t)(0);
3459bdb9230aSGarrett D'Amore 	desc[bufindex].desc1.first_desc = 1;
3460bdb9230aSGarrett D'Amore 	desc[bufindex].desc1.last_desc = 1;
3461bdb9230aSGarrett D'Amore 	desc[bufindex].desc1.int_on_comp = 1;
3462bdb9230aSGarrett D'Amore 	desc[bufindex].desc0.own = 1;
3463bdb9230aSGarrett D'Amore 
3464bdb9230aSGarrett D'Amore 	ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
3465bdb9230aSGarrett D'Amore 	    TX_POLL_DEMAND);
3466bdb9230aSGarrett D'Amore 
3467bdb9230aSGarrett D'Amore 	/*
3468bdb9230aSGarrett D'Amore 	 * Give enough time for the chip to transmit the packet
3469bdb9230aSGarrett D'Amore 	 */
3470bdb9230aSGarrett D'Amore #if 1
3471bdb9230aSGarrett D'Amore 	del = 1000;
3472bdb9230aSGarrett D'Amore 	while (desc[bufindex].desc0.own && --del)
3473bdb9230aSGarrett D'Amore 		drv_usecwait(10);	/* quickly wait up to 10ms */
3474bdb9230aSGarrett D'Amore 	if (desc[bufindex].desc0.own)
3475bdb9230aSGarrett D'Amore 		delay(drv_usectohz(200000));	/* nicely wait a longer time */
3476bdb9230aSGarrett D'Amore #else
3477bdb9230aSGarrett D'Amore 	del = 0x10000;
3478bdb9230aSGarrett D'Amore 	while (desc[bufindex].desc0.own && --del)
3479bdb9230aSGarrett D'Amore 		drv_usecwait(10);
3480bdb9230aSGarrett D'Amore #endif
3481bdb9230aSGarrett D'Amore 
3482bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3483bdb9230aSGarrett D'Amore 	if (dnetdebug & DNETSENSE)
3484bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u",
3485bdb9230aSGarrett D'Amore 		    desc[bufindex].desc0.own,
3486bdb9230aSGarrett D'Amore 		    desc[bufindex].desc0.err_summary,
3487bdb9230aSGarrett D'Amore 		    desc[bufindex].desc0.carrier_loss,
3488bdb9230aSGarrett D'Amore 		    desc[bufindex].desc0.no_carrier,
3489bdb9230aSGarrett D'Amore 		    desc[bufindex].desc0.late_collision,
3490bdb9230aSGarrett D'Amore 		    desc[bufindex].desc0.link_fail);
3491bdb9230aSGarrett D'Amore #endif
3492bdb9230aSGarrett D'Amore 	if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */
3493bdb9230aSGarrett D'Amore 		return (0);
3494bdb9230aSGarrett D'Amore 
3495bdb9230aSGarrett D'Amore 	return (!desc[bufindex].desc0.err_summary);
3496bdb9230aSGarrett D'Amore }
3497bdb9230aSGarrett D'Amore 
3498bdb9230aSGarrett D'Amore /* enable_interrupts - called with intrlock held */
3499bdb9230aSGarrett D'Amore static void
enable_interrupts(struct dnetinstance * dnetp)350098e8d175SSteven Stallion enable_interrupts(struct dnetinstance *dnetp)
3501bdb9230aSGarrett D'Amore {
3502bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3503bdb9230aSGarrett D'Amore 	/* Don't enable interrupts if they have been forced off */
3504bdb9230aSGarrett D'Amore 	if (dnetp->interrupts_disabled)
3505bdb9230aSGarrett D'Amore 		return;
3506bdb9230aSGarrett D'Amore 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG),
350798e8d175SSteven Stallion 	    ABNORMAL_INTR_MASK | NORMAL_INTR_MASK | SYSTEM_ERROR_MASK |
3508bdb9230aSGarrett D'Amore 	    (dnetp->timer.cb ? GPTIMER_INTR : 0) |
350998e8d175SSteven Stallion 	    RX_INTERRUPT_MASK |
351098e8d175SSteven Stallion 	    TX_INTERRUPT_MASK | TX_JABBER_MASK | TX_UNDERFLOW_MASK);
3511bdb9230aSGarrett D'Amore }
3512bdb9230aSGarrett D'Amore 
3513bdb9230aSGarrett D'Amore /*
3514bdb9230aSGarrett D'Amore  * Some older multiport cards are non-PCI compliant in their interrupt routing.
3515bdb9230aSGarrett D'Amore  * Second and subsequent devices are incorrectly configured by the BIOS
3516bdb9230aSGarrett D'Amore  * (either in their ILINE configuration or the MP Configuration Table for PC+MP
3517bdb9230aSGarrett D'Amore  * systems).
351898e8d175SSteven Stallion  * The hack stops registering the interrupt routine for the FIRST
351998e8d175SSteven Stallion  * device on the adapter, and registers its own. It builds up a table
352098e8d175SSteven Stallion  * of dnetp structures for each device, and the new interrupt routine
352198e8d175SSteven Stallion  * calls dnet_intr for each of them.
3522bdb9230aSGarrett D'Amore  * Known cards that suffer from this problem are:
3523bdb9230aSGarrett D'Amore  *	All Cogent multiport cards;
3524bdb9230aSGarrett D'Amore  *	Znyx 314;
3525bdb9230aSGarrett D'Amore  *	Znyx 315.
3526bdb9230aSGarrett D'Amore  *
3527bdb9230aSGarrett D'Amore  * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This
3528bdb9230aSGarrett D'Amore  * hack relies on the fact that the offending cards will have only one SROM.
3529bdb9230aSGarrett D'Amore  * It uses this fact to identify devices that are on the same multiport
3530bdb9230aSGarrett D'Amore  * adapter, as opposed to multiple devices from the same vendor (as
3531bdb9230aSGarrett D'Amore  * indicated by "secondary")
3532bdb9230aSGarrett D'Amore  */
3533bdb9230aSGarrett D'Amore static int
dnet_hack_interrupts(struct dnetinstance * dnetp,int secondary)353498e8d175SSteven Stallion dnet_hack_interrupts(struct dnetinstance *dnetp, int secondary)
3535bdb9230aSGarrett D'Amore {
3536bdb9230aSGarrett D'Amore 	int i;
3537bdb9230aSGarrett D'Amore 	struct hackintr_inf *hackintr_inf;
3538bdb9230aSGarrett D'Amore 	dev_info_t *devinfo = dnetp->devinfo;
3539bdb9230aSGarrett D'Amore 	uint32_t oui = 0;	/* Organizationally Unique ID */
3540bdb9230aSGarrett D'Amore 
3541bdb9230aSGarrett D'Amore 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3542bdb9230aSGarrett D'Amore 	    "no_INTA_workaround", 0) != 0)
3543bdb9230aSGarrett D'Amore 		return (0);
3544bdb9230aSGarrett D'Amore 
3545bdb9230aSGarrett D'Amore 	for (i = 0; i < 3; i++)
3546bdb9230aSGarrett D'Amore 		oui = (oui << 8) | dnetp->vendor_addr[i];
3547bdb9230aSGarrett D'Amore 
3548bdb9230aSGarrett D'Amore 	/* Check wheather or not we need to implement the hack */
3549bdb9230aSGarrett D'Amore 
3550bdb9230aSGarrett D'Amore 	switch (oui) {
3551bdb9230aSGarrett D'Amore 	case ZNYX_ETHER:
3552bdb9230aSGarrett D'Amore 		/* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */
3553bdb9230aSGarrett D'Amore 		if (dnetp->board_type != DEVICE_ID_21040)
3554bdb9230aSGarrett D'Amore 			return (0);
3555bdb9230aSGarrett D'Amore 		break;
3556bdb9230aSGarrett D'Amore 
3557bdb9230aSGarrett D'Amore 	case COGENT_ETHER:
3558bdb9230aSGarrett D'Amore 		/* All known Cogent multiport cards */
3559bdb9230aSGarrett D'Amore 		break;
3560bdb9230aSGarrett D'Amore 
3561bdb9230aSGarrett D'Amore 	case ADAPTEC_ETHER:
3562bdb9230aSGarrett D'Amore 		/* Adaptec multiport cards */
3563bdb9230aSGarrett D'Amore 		break;
3564bdb9230aSGarrett D'Amore 
3565bdb9230aSGarrett D'Amore 	default:
3566bdb9230aSGarrett D'Amore 		/* Other cards work correctly */
3567bdb9230aSGarrett D'Amore 		return (0);
3568bdb9230aSGarrett D'Amore 	}
3569bdb9230aSGarrett D'Amore 
3570bdb9230aSGarrett D'Amore 	/* card is (probably) non-PCI compliant in its interrupt routing */
3571bdb9230aSGarrett D'Amore 
3572bdb9230aSGarrett D'Amore 
3573bdb9230aSGarrett D'Amore 	if (!secondary) {
3574bdb9230aSGarrett D'Amore 
3575bdb9230aSGarrett D'Amore 		/*
3576bdb9230aSGarrett D'Amore 		 * If we have already registered a hacked interrupt, and
3577bdb9230aSGarrett D'Amore 		 * this is also a 'primary' adapter, then this is NOT part of
3578bdb9230aSGarrett D'Amore 		 * a multiport card, but a second card on the same PCI bus.
3579bdb9230aSGarrett D'Amore 		 * BUGID: 4057747
3580bdb9230aSGarrett D'Amore 		 */
3581bdb9230aSGarrett D'Amore 		if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3582bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, hackintr_propname, 0) != 0)
3583bdb9230aSGarrett D'Amore 			return (0);
3584bdb9230aSGarrett D'Amore 				/* ... Primary not part of a multiport device */
3585bdb9230aSGarrett D'Amore 
3586bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3587bdb9230aSGarrett D'Amore 		if (dnetdebug & DNETTRACE)
3588bdb9230aSGarrett D'Amore 			cmn_err(CE_NOTE, "dnet: Implementing hardware "
3589bdb9230aSGarrett D'Amore 			    "interrupt flaw workaround");
3590bdb9230aSGarrett D'Amore #endif
3591bdb9230aSGarrett D'Amore 		dnetp->hackintr_inf = hackintr_inf =
3592bdb9230aSGarrett D'Amore 		    kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP);
3593bdb9230aSGarrett D'Amore 		if (hackintr_inf == NULL)
3594bdb9230aSGarrett D'Amore 			goto fail;
3595bdb9230aSGarrett D'Amore 
359698e8d175SSteven Stallion 		hackintr_inf->dnetps[0] = dnetp;
3597bdb9230aSGarrett D'Amore 		hackintr_inf->devinfo = devinfo;
3598bdb9230aSGarrett D'Amore 
3599bdb9230aSGarrett D'Amore 		/*
3600bdb9230aSGarrett D'Amore 		 * Add a property to allow successive attaches to find the
3601bdb9230aSGarrett D'Amore 		 * table
3602bdb9230aSGarrett D'Amore 		 */
3603bdb9230aSGarrett D'Amore 
3604bdb9230aSGarrett D'Amore 		if (ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3605bdb9230aSGarrett D'Amore 		    ddi_get_parent(devinfo), hackintr_propname,
3606bdb9230aSGarrett D'Amore 		    (uchar_t *)&dnetp->hackintr_inf,
3607bdb9230aSGarrett D'Amore 		    sizeof (void *)) != DDI_PROP_SUCCESS)
3608bdb9230aSGarrett D'Amore 			goto fail;
3609bdb9230aSGarrett D'Amore 
3610bdb9230aSGarrett D'Amore 
3611bdb9230aSGarrett D'Amore 		/* Register our hacked interrupt routine */
361298e8d175SSteven Stallion 		if (ddi_add_intr(devinfo, 0, &dnetp->icookie, NULL,
3613bdb9230aSGarrett D'Amore 		    (uint_t (*)(char *))dnet_hack_intr,
3614bdb9230aSGarrett D'Amore 		    (caddr_t)hackintr_inf) != DDI_SUCCESS) {
3615bdb9230aSGarrett D'Amore 			/* XXX function return value ignored */
3616bdb9230aSGarrett D'Amore 			(void) ddi_prop_remove(DDI_DEV_T_NONE,
3617bdb9230aSGarrett D'Amore 			    ddi_get_parent(devinfo),
3618bdb9230aSGarrett D'Amore 			    hackintr_propname);
3619bdb9230aSGarrett D'Amore 			goto fail;
3620bdb9230aSGarrett D'Amore 		}
3621bdb9230aSGarrett D'Amore 
3622bdb9230aSGarrett D'Amore 		/*
3623bdb9230aSGarrett D'Amore 		 * Mutex required to ensure interrupt routine has completed
3624bdb9230aSGarrett D'Amore 		 * when detaching devices
3625bdb9230aSGarrett D'Amore 		 */
3626bdb9230aSGarrett D'Amore 		mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER,
362798e8d175SSteven Stallion 		    dnetp->icookie);
3628bdb9230aSGarrett D'Amore 
3629bdb9230aSGarrett D'Amore 		/* Stop GLD registering an interrupt */
3630bdb9230aSGarrett D'Amore 		return (-1);
3631bdb9230aSGarrett D'Amore 	} else {
3632bdb9230aSGarrett D'Amore 
363398e8d175SSteven Stallion 		/* Add the dnetp for this secondary device to the table */
3634bdb9230aSGarrett D'Amore 
3635bdb9230aSGarrett D'Amore 		hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3636bdb9230aSGarrett D'Amore 		    ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3637bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, hackintr_propname, 0);
3638bdb9230aSGarrett D'Amore 
3639bdb9230aSGarrett D'Amore 		if (hackintr_inf == NULL)
3640bdb9230aSGarrett D'Amore 			goto fail;
3641bdb9230aSGarrett D'Amore 
3642bdb9230aSGarrett D'Amore 		/* Find an empty slot */
3643bdb9230aSGarrett D'Amore 		for (i = 0; i < MAX_INST; i++)
364498e8d175SSteven Stallion 			if (hackintr_inf->dnetps[i] == NULL)
3645bdb9230aSGarrett D'Amore 				break;
3646bdb9230aSGarrett D'Amore 
3647bdb9230aSGarrett D'Amore 		/* More than 8 ports on adapter ?! */
3648bdb9230aSGarrett D'Amore 		if (i == MAX_INST)
3649bdb9230aSGarrett D'Amore 			goto fail;
3650bdb9230aSGarrett D'Amore 
365198e8d175SSteven Stallion 		hackintr_inf->dnetps[i] = dnetp;
3652bdb9230aSGarrett D'Amore 
3653bdb9230aSGarrett D'Amore 		/*
3654bdb9230aSGarrett D'Amore 		 * Allow GLD to register a handler for this
3655bdb9230aSGarrett D'Amore 		 * device. If the card is actually broken, as we suspect, this
3656bdb9230aSGarrett D'Amore 		 * handler will never get called. However, by registering the
3657bdb9230aSGarrett D'Amore 		 * interrupt handler, we can copy gracefully with new multiport
3658bdb9230aSGarrett D'Amore 		 * Cogent cards that decide to fix the hardware problem
3659bdb9230aSGarrett D'Amore 		 */
3660bdb9230aSGarrett D'Amore 		return (0);
3661bdb9230aSGarrett D'Amore 	}
3662bdb9230aSGarrett D'Amore 
3663bdb9230aSGarrett D'Amore fail:
3664bdb9230aSGarrett D'Amore 	cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt"
3665bdb9230aSGarrett D'Amore 	    " routing problem");
3666bdb9230aSGarrett D'Amore 	return (0);
3667bdb9230aSGarrett D'Amore }
3668bdb9230aSGarrett D'Amore 
3669bdb9230aSGarrett D'Amore /*
367098e8d175SSteven Stallion  * Call dnet_intr for all adapters on a multiport card
3671bdb9230aSGarrett D'Amore  */
3672bdb9230aSGarrett D'Amore static uint_t
dnet_hack_intr(struct hackintr_inf * hackintr_inf)3673bdb9230aSGarrett D'Amore dnet_hack_intr(struct hackintr_inf *hackintr_inf)
3674bdb9230aSGarrett D'Amore {
3675bdb9230aSGarrett D'Amore 	int i;
3676bdb9230aSGarrett D'Amore 	int claimed = DDI_INTR_UNCLAIMED;
3677bdb9230aSGarrett D'Amore 
3678bdb9230aSGarrett D'Amore 	/* Stop detaches while processing interrupts */
3679bdb9230aSGarrett D'Amore 	mutex_enter(&hackintr_inf->lock);
3680bdb9230aSGarrett D'Amore 
3681bdb9230aSGarrett D'Amore 	for (i = 0; i < MAX_INST; i++) {
368298e8d175SSteven Stallion 		if (hackintr_inf->dnetps[i] &&
368398e8d175SSteven Stallion 		    dnet_intr((caddr_t)hackintr_inf->dnetps[i]) ==
368498e8d175SSteven Stallion 		    DDI_INTR_CLAIMED) {
3685bdb9230aSGarrett D'Amore 			claimed = DDI_INTR_CLAIMED;
3686bdb9230aSGarrett D'Amore 		}
368798e8d175SSteven Stallion 	}
3688bdb9230aSGarrett D'Amore 	mutex_exit(&hackintr_inf->lock);
3689bdb9230aSGarrett D'Amore 	return (claimed);
3690bdb9230aSGarrett D'Amore }
3691bdb9230aSGarrett D'Amore 
3692bdb9230aSGarrett D'Amore /*
3693bdb9230aSGarrett D'Amore  * This removes the detaching device from the table procesed by the hacked
3694bdb9230aSGarrett D'Amore  * interrupt routine. Because the interrupts from all devices come in to the
3695bdb9230aSGarrett D'Amore  * same interrupt handler, ALL devices must stop interrupting once the
3696bdb9230aSGarrett D'Amore  * primary device detaches. This isn't a problem at present, because all
3697bdb9230aSGarrett D'Amore  * instances of a device are detached when the driver is unloaded.
3698bdb9230aSGarrett D'Amore  */
3699bdb9230aSGarrett D'Amore static int
dnet_detach_hacked_interrupt(dev_info_t * devinfo)3700bdb9230aSGarrett D'Amore dnet_detach_hacked_interrupt(dev_info_t *devinfo)
3701bdb9230aSGarrett D'Amore {
3702bdb9230aSGarrett D'Amore 	int i;
3703bdb9230aSGarrett D'Amore 	struct hackintr_inf *hackintr_inf;
370498e8d175SSteven Stallion 	struct dnetinstance *altdnetp, *dnetp =
370598e8d175SSteven Stallion 	    ddi_get_driver_private(devinfo);
3706bdb9230aSGarrett D'Amore 
3707bdb9230aSGarrett D'Amore 	hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3708bdb9230aSGarrett D'Amore 	    ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3709bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, hackintr_propname, 0);
3710bdb9230aSGarrett D'Amore 
3711bdb9230aSGarrett D'Amore 	/*
3712bdb9230aSGarrett D'Amore 	 * No hackintr_inf implies hack was not required or the primary has
3713bdb9230aSGarrett D'Amore 	 * detached, and our interrupts are already disabled
3714bdb9230aSGarrett D'Amore 	 */
3715bdb9230aSGarrett D'Amore 	if (!hackintr_inf) {
3716bdb9230aSGarrett D'Amore 		/* remove the interrupt for the non-hacked case */
371798e8d175SSteven Stallion 		ddi_remove_intr(devinfo, 0, dnetp->icookie);
3718bdb9230aSGarrett D'Amore 		return (DDI_SUCCESS);
3719bdb9230aSGarrett D'Amore 	}
3720bdb9230aSGarrett D'Amore 
3721bdb9230aSGarrett D'Amore 	/* Remove this device from the handled table */
3722bdb9230aSGarrett D'Amore 	mutex_enter(&hackintr_inf->lock);
3723bdb9230aSGarrett D'Amore 	for (i = 0; i < MAX_INST; i++) {
372498e8d175SSteven Stallion 		if (hackintr_inf->dnetps[i] == dnetp) {
372598e8d175SSteven Stallion 			hackintr_inf->dnetps[i] = NULL;
3726bdb9230aSGarrett D'Amore 			break;
3727bdb9230aSGarrett D'Amore 		}
3728bdb9230aSGarrett D'Amore 	}
3729bdb9230aSGarrett D'Amore 
3730bdb9230aSGarrett D'Amore 	mutex_exit(&hackintr_inf->lock);
3731bdb9230aSGarrett D'Amore 
3732bdb9230aSGarrett D'Amore 	/* Not the primary card, we are done */
3733bdb9230aSGarrett D'Amore 	if (devinfo != hackintr_inf->devinfo)
3734bdb9230aSGarrett D'Amore 		return (DDI_SUCCESS);
3735bdb9230aSGarrett D'Amore 
3736bdb9230aSGarrett D'Amore 	/*
3737bdb9230aSGarrett D'Amore 	 * This is the primary card. All remaining adapters on this device
3738bdb9230aSGarrett D'Amore 	 * must have their interrupts disabled before we remove the handler
3739bdb9230aSGarrett D'Amore 	 */
3740bdb9230aSGarrett D'Amore 	for (i = 0; i < MAX_INST; i++) {
374198e8d175SSteven Stallion 		if ((altdnetp = hackintr_inf->dnetps[i]) != NULL) {
3742bdb9230aSGarrett D'Amore 			altdnetp->interrupts_disabled = 1;
3743bdb9230aSGarrett D'Amore 			ddi_put32(altdnetp->io_handle,
3744bdb9230aSGarrett D'Amore 			    REG32(altdnetp->io_reg, INT_MASK_REG), 0);
3745bdb9230aSGarrett D'Amore 		}
3746bdb9230aSGarrett D'Amore 	}
3747bdb9230aSGarrett D'Amore 
3748bdb9230aSGarrett D'Amore 	/* It should now be safe to remove the interrupt handler */
3749bdb9230aSGarrett D'Amore 
375098e8d175SSteven Stallion 	ddi_remove_intr(devinfo, 0, dnetp->icookie);
3751bdb9230aSGarrett D'Amore 	mutex_destroy(&hackintr_inf->lock);
3752bdb9230aSGarrett D'Amore 	/* XXX function return value ignored */
3753bdb9230aSGarrett D'Amore 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
3754bdb9230aSGarrett D'Amore 	    hackintr_propname);
3755bdb9230aSGarrett D'Amore 	kmem_free(hackintr_inf, sizeof (struct hackintr_inf));
3756bdb9230aSGarrett D'Amore 	return (DDI_SUCCESS);
3757bdb9230aSGarrett D'Amore }
3758bdb9230aSGarrett D'Amore 
3759bdb9230aSGarrett D'Amore /* do_phy() - called with intrlock held */
3760bdb9230aSGarrett D'Amore static void
do_phy(struct dnetinstance * dnetp)376198e8d175SSteven Stallion do_phy(struct dnetinstance *dnetp)
3762bdb9230aSGarrett D'Amore {
3763bdb9230aSGarrett D'Amore 	dev_info_t *dip;
3764bdb9230aSGarrett D'Amore 	LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf;
3765bdb9230aSGarrett D'Amore 	media_block_t *block;
3766bdb9230aSGarrett D'Amore 	int phy;
3767bdb9230aSGarrett D'Amore 
3768bdb9230aSGarrett D'Amore 	dip = dnetp->devinfo;
3769bdb9230aSGarrett D'Amore 
3770bdb9230aSGarrett D'Amore 	/*
3771bdb9230aSGarrett D'Amore 	 * Find and configure the PHY media block. If NO PHY blocks are
3772bdb9230aSGarrett D'Amore 	 * found on the SROM, but a PHY device is present, we assume the card
3773bdb9230aSGarrett D'Amore 	 * is a legacy device, and that there is ONLY a PHY interface on the
3774bdb9230aSGarrett D'Amore 	 * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY
3775bdb9230aSGarrett D'Amore 	 */
3776bdb9230aSGarrett D'Amore 
3777bdb9230aSGarrett D'Amore 	for (block = leaf->block + leaf->block_count -1;
3778bdb9230aSGarrett D'Amore 	    block >= leaf->block; block --) {
3779bdb9230aSGarrett D'Amore 		if (block->type == 3 || block->type == 1) {
3780bdb9230aSGarrett D'Amore 			leaf->mii_block = block;
3781bdb9230aSGarrett D'Amore 			break;
3782bdb9230aSGarrett D'Amore 		}
3783bdb9230aSGarrett D'Amore 	}
3784bdb9230aSGarrett D'Amore 
3785bdb9230aSGarrett D'Amore 	/*
3786bdb9230aSGarrett D'Amore 	 * If no MII block, select default, and hope this configuration will
3787bdb9230aSGarrett D'Amore 	 * allow the phy to be read/written if it is present
3788bdb9230aSGarrett D'Amore 	 */
3789bdb9230aSGarrett D'Amore 	dnetp->selected_media_block = leaf->mii_block ?
3790bdb9230aSGarrett D'Amore 	    leaf->mii_block : leaf->default_block;
3791bdb9230aSGarrett D'Amore 
379298e8d175SSteven Stallion 	setup_block(dnetp);
3793bdb9230aSGarrett D'Amore 	/* XXX function return value ignored */
3794bdb9230aSGarrett D'Amore 	(void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii);
3795bdb9230aSGarrett D'Amore 
3796bdb9230aSGarrett D'Amore 	/*
3797bdb9230aSGarrett D'Amore 	 * We try PHY 0 LAST because it is less likely to be connected
3798bdb9230aSGarrett D'Amore 	 */
3799bdb9230aSGarrett D'Amore 	for (phy = 1; phy < 33; phy++)
3800bdb9230aSGarrett D'Amore 		if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS &&
3801bdb9230aSGarrett D'Amore 		    mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) {
3802bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3803bdb9230aSGarrett D'Amore 			if (dnetdebug & DNETSENSE)
3804bdb9230aSGarrett D'Amore 				cmn_err(CE_NOTE, "dnet: "
3805bdb9230aSGarrett D'Amore 				    "PHY at address %d", phy % 32);
3806bdb9230aSGarrett D'Amore #endif
3807bdb9230aSGarrett D'Amore 			dnetp->phyaddr = phy % 32;
3808bdb9230aSGarrett D'Amore 			if (!leaf->mii_block) {
3809bdb9230aSGarrett D'Amore 				/* Legacy card, change the leaf node */
3810bdb9230aSGarrett D'Amore 				set_leaf(&dnetp->sr, &leaf_phylegacy);
3811bdb9230aSGarrett D'Amore 			}
3812bdb9230aSGarrett D'Amore 			return;
3813bdb9230aSGarrett D'Amore 		}
3814bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3815bdb9230aSGarrett D'Amore 	if (dnetdebug & DNETSENSE)
3816bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "dnet: No PHY found");
3817bdb9230aSGarrett D'Amore #endif
3818bdb9230aSGarrett D'Amore }
3819bdb9230aSGarrett D'Amore 
3820bdb9230aSGarrett D'Amore static ushort_t
dnet_mii_read(dev_info_t * dip,int phy_addr,int reg_num)3821bdb9230aSGarrett D'Amore dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num)
3822bdb9230aSGarrett D'Amore {
3823bdb9230aSGarrett D'Amore 	struct dnetinstance *dnetp;
3824bdb9230aSGarrett D'Amore 
3825bdb9230aSGarrett D'Amore 	uint32_t command_word;
3826bdb9230aSGarrett D'Amore 	uint32_t tmp;
3827bdb9230aSGarrett D'Amore 	uint32_t data = 0;
3828bdb9230aSGarrett D'Amore 	int i;
3829bdb9230aSGarrett D'Amore 	int bits_in_ushort = ((sizeof (ushort_t))*8);
3830bdb9230aSGarrett D'Amore 	int turned_around = 0;
3831bdb9230aSGarrett D'Amore 
383298e8d175SSteven Stallion 	dnetp = ddi_get_driver_private(dip);
3833bdb9230aSGarrett D'Amore 
3834bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3835bdb9230aSGarrett D'Amore 	/* Write Preamble */
3836bdb9230aSGarrett D'Amore 	write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
3837bdb9230aSGarrett D'Amore 
3838bdb9230aSGarrett D'Amore 	/* Prepare command word */
3839bdb9230aSGarrett D'Amore 	command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN;
3840bdb9230aSGarrett D'Amore 	command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN;
3841bdb9230aSGarrett D'Amore 	command_word |= MII_READ_FRAME;
3842bdb9230aSGarrett D'Amore 
3843bdb9230aSGarrett D'Amore 	write_mii(dnetp, command_word, bits_in_ushort-2);
3844bdb9230aSGarrett D'Amore 
3845bdb9230aSGarrett D'Amore 	mii_tristate(dnetp);
3846bdb9230aSGarrett D'Amore 
3847bdb9230aSGarrett D'Amore 	/* Check that the PHY generated a zero bit the 2nd clock */
3848bdb9230aSGarrett D'Amore 	tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG));
3849bdb9230aSGarrett D'Amore 
3850bdb9230aSGarrett D'Amore 	turned_around = (tmp & MII_DATA_IN) ? 0 : 1;
3851bdb9230aSGarrett D'Amore 
3852bdb9230aSGarrett D'Amore 	/* read data WORD */
3853bdb9230aSGarrett D'Amore 	for (i = 0; i < bits_in_ushort; i++) {
3854bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
3855bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ);
3856bdb9230aSGarrett D'Amore 		drv_usecwait(MII_DELAY);
3857bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
3858bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK);
3859bdb9230aSGarrett D'Amore 		drv_usecwait(MII_DELAY);
3860bdb9230aSGarrett D'Amore 		tmp = ddi_get32(dnetp->io_handle,
3861bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, ETHER_ROM_REG));
3862bdb9230aSGarrett D'Amore 		drv_usecwait(MII_DELAY);
3863bdb9230aSGarrett D'Amore 		data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001;
3864bdb9230aSGarrett D'Amore 	}
3865bdb9230aSGarrett D'Amore 
3866bdb9230aSGarrett D'Amore 	mii_tristate(dnetp);
3867bdb9230aSGarrett D'Amore 	return (turned_around ? data: -1);
3868bdb9230aSGarrett D'Amore }
3869bdb9230aSGarrett D'Amore 
3870bdb9230aSGarrett D'Amore static void
dnet_mii_write(dev_info_t * dip,int phy_addr,int reg_num,int reg_dat)3871bdb9230aSGarrett D'Amore dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat)
3872bdb9230aSGarrett D'Amore {
3873bdb9230aSGarrett D'Amore 	struct dnetinstance *dnetp;
3874bdb9230aSGarrett D'Amore 	uint32_t command_word;
3875bdb9230aSGarrett D'Amore 	int bits_in_ushort = ((sizeof (ushort_t))*8);
3876bdb9230aSGarrett D'Amore 
387798e8d175SSteven Stallion 	dnetp = ddi_get_driver_private(dip);
3878bdb9230aSGarrett D'Amore 
3879bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3880bdb9230aSGarrett D'Amore 	write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
3881bdb9230aSGarrett D'Amore 
3882bdb9230aSGarrett D'Amore 	/* Prepare command word */
3883bdb9230aSGarrett D'Amore 	command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN);
3884bdb9230aSGarrett D'Amore 	command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN);
3885bdb9230aSGarrett D'Amore 	command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat);
3886bdb9230aSGarrett D'Amore 
3887bdb9230aSGarrett D'Amore 	write_mii(dnetp, command_word, 2*bits_in_ushort);
3888bdb9230aSGarrett D'Amore 	mii_tristate(dnetp);
3889bdb9230aSGarrett D'Amore }
3890bdb9230aSGarrett D'Amore 
3891bdb9230aSGarrett D'Amore /*
3892bdb9230aSGarrett D'Amore  * Write data size bits from mii_data to the MII control lines.
3893bdb9230aSGarrett D'Amore  */
3894bdb9230aSGarrett D'Amore static void
write_mii(struct dnetinstance * dnetp,uint32_t mii_data,int data_size)3895bdb9230aSGarrett D'Amore write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size)
3896bdb9230aSGarrett D'Amore {
3897bdb9230aSGarrett D'Amore 	int i;
3898bdb9230aSGarrett D'Amore 	uint32_t dbit;
3899bdb9230aSGarrett D'Amore 
3900bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3901bdb9230aSGarrett D'Amore 	for (i = data_size; i > 0; i--) {
3902bdb9230aSGarrett D'Amore 		dbit = ((mii_data >>
3903bdb9230aSGarrett D'Amore 		    (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA);
3904bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
3905bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, ETHER_ROM_REG),
3906bdb9230aSGarrett D'Amore 		    MII_WRITE | dbit);
3907bdb9230aSGarrett D'Amore 		drv_usecwait(MII_DELAY);
3908bdb9230aSGarrett D'Amore 		ddi_put32(dnetp->io_handle,
3909bdb9230aSGarrett D'Amore 		    REG32(dnetp->io_reg, ETHER_ROM_REG),
3910bdb9230aSGarrett D'Amore 		    MII_WRITE | MII_CLOCK | dbit);
3911bdb9230aSGarrett D'Amore 		drv_usecwait(MII_DELAY);
3912bdb9230aSGarrett D'Amore 		mii_data <<= 1;
3913bdb9230aSGarrett D'Amore 	}
3914bdb9230aSGarrett D'Amore }
3915bdb9230aSGarrett D'Amore 
3916bdb9230aSGarrett D'Amore /*
3917bdb9230aSGarrett D'Amore  * Put the MDIO port in tri-state for the turn around bits
3918bdb9230aSGarrett D'Amore  * in MII read and at end of MII management sequence.
3919bdb9230aSGarrett D'Amore  */
3920bdb9230aSGarrett D'Amore static void
mii_tristate(struct dnetinstance * dnetp)3921bdb9230aSGarrett D'Amore mii_tristate(struct dnetinstance *dnetp)
3922bdb9230aSGarrett D'Amore {
3923bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
3924bdb9230aSGarrett D'Amore 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
3925bdb9230aSGarrett D'Amore 	    MII_WRITE_TS);
3926bdb9230aSGarrett D'Amore 	drv_usecwait(MII_DELAY);
3927bdb9230aSGarrett D'Amore 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
3928bdb9230aSGarrett D'Amore 	    MII_WRITE_TS | MII_CLOCK);
3929bdb9230aSGarrett D'Amore 	drv_usecwait(MII_DELAY);
3930bdb9230aSGarrett D'Amore }
3931bdb9230aSGarrett D'Amore 
3932bdb9230aSGarrett D'Amore 
3933bdb9230aSGarrett D'Amore static void
set_leaf(SROM_FORMAT * sr,LEAF_FORMAT * leaf)3934bdb9230aSGarrett D'Amore set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf)
3935bdb9230aSGarrett D'Amore {
3936bdb9230aSGarrett D'Amore 	if (sr->leaf && !sr->leaf->is_static)
3937bdb9230aSGarrett D'Amore 		kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT));
3938bdb9230aSGarrett D'Amore 	sr->leaf = leaf;
3939bdb9230aSGarrett D'Amore }
3940bdb9230aSGarrett D'Amore 
3941bdb9230aSGarrett D'Amore /*
3942bdb9230aSGarrett D'Amore  * Callback from MII module. Makes sure that the CSR registers are
3943bdb9230aSGarrett D'Amore  * configured properly if the PHY changes mode.
3944bdb9230aSGarrett D'Amore  */
3945bdb9230aSGarrett D'Amore /* ARGSUSED */
3946bdb9230aSGarrett D'Amore /* dnet_mii_link_cb - called with intrlock held */
3947bdb9230aSGarrett D'Amore static void
dnet_mii_link_cb(dev_info_t * dip,int phy,enum mii_phy_state state)3948bdb9230aSGarrett D'Amore dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state)
3949bdb9230aSGarrett D'Amore {
395098e8d175SSteven Stallion 	struct dnetinstance *dnetp = ddi_get_driver_private(dip);
3951bdb9230aSGarrett D'Amore 	LEAF_FORMAT *leaf;
3952bdb9230aSGarrett D'Amore 
3953bdb9230aSGarrett D'Amore 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
395498e8d175SSteven Stallion 
3955bdb9230aSGarrett D'Amore 	leaf = dnetp->sr.leaf + dnetp->leaf;
3956bdb9230aSGarrett D'Amore 	if (state == phy_state_linkup) {
3957bdb9230aSGarrett D'Amore 		dnetp->mii_up = 1;
395898e8d175SSteven Stallion 
395998e8d175SSteven Stallion 		(void) mii_getspeed(dnetp->mii, dnetp->phyaddr,
396098e8d175SSteven Stallion 		    &dnetp->mii_speed, &dnetp->mii_duplex);
396198e8d175SSteven Stallion 
3962bdb9230aSGarrett D'Amore 		dnetp->selected_media_block = leaf->mii_block;
396398e8d175SSteven Stallion 		setup_block(dnetp);
3964bdb9230aSGarrett D'Amore 	} else {
3965bdb9230aSGarrett D'Amore 		/* NEEDSWORK: Probably can call find_active_media here */
3966bdb9230aSGarrett D'Amore 		dnetp->mii_up = 0;
396798e8d175SSteven Stallion 
3968bdb9230aSGarrett D'Amore 		if (leaf->default_block->media_code == MEDIA_MII)
3969bdb9230aSGarrett D'Amore 			dnetp->selected_media_block = leaf->default_block;
397098e8d175SSteven Stallion 		setup_block(dnetp);
397198e8d175SSteven Stallion 	}
397298e8d175SSteven Stallion 
397332607e28SSteven Stallion 	if (dnetp->running) {
397432607e28SSteven Stallion 		mac_link_update(dnetp->mac_handle,
397532607e28SSteven Stallion 		    (dnetp->mii_up ? LINK_STATE_UP : LINK_STATE_DOWN));
3976bdb9230aSGarrett D'Amore 	}
3977bdb9230aSGarrett D'Amore }
3978bdb9230aSGarrett D'Amore 
3979bdb9230aSGarrett D'Amore /*
3980bdb9230aSGarrett D'Amore  * SROM parsing routines.
3981bdb9230aSGarrett D'Amore  * Refer to the Digital 3.03 SROM spec while reading this! (references refer
3982bdb9230aSGarrett D'Amore  * to this document)
3983bdb9230aSGarrett D'Amore  * Where possible ALL vendor specific changes should be localised here. The
3984bdb9230aSGarrett D'Amore  * SROM data should be capable of describing any programmatic irregularities
3985bdb9230aSGarrett D'Amore  * of DNET cards (via SIA or GP registers, in particular), so vendor specific
3986bdb9230aSGarrett D'Amore  * code elsewhere should not be required
3987bdb9230aSGarrett D'Amore  */
3988bdb9230aSGarrett D'Amore static void
dnet_parse_srom(struct dnetinstance * dnetp,SROM_FORMAT * sr,uchar_t * vi)3989bdb9230aSGarrett D'Amore dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi)
3990bdb9230aSGarrett D'Amore {
3991bdb9230aSGarrett D'Amore 	uint32_t ether_mfg = 0;
3992bdb9230aSGarrett D'Amore 	int i;
3993bdb9230aSGarrett D'Amore 	uchar_t *p;
3994bdb9230aSGarrett D'Amore 
3995bdb9230aSGarrett D'Amore 	if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3996bdb9230aSGarrett D'Amore 	    DDI_PROP_DONTPASS, "no_sromconfig", 0))
3997bdb9230aSGarrett D'Amore 		dnetp->sr.init_from_srom = check_srom_valid(vi);
3998bdb9230aSGarrett D'Amore 
3999bdb9230aSGarrett D'Amore 	if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) {
4000bdb9230aSGarrett D'Amore 		/* Section 2/3: General SROM Format/ ID Block */
4001bdb9230aSGarrett D'Amore 		p = vi+18;
4002bdb9230aSGarrett D'Amore 		sr->version = *p++;
4003bdb9230aSGarrett D'Amore 		sr->adapters = *p++;
4004bdb9230aSGarrett D'Amore 
4005bdb9230aSGarrett D'Amore 		sr->leaf =
4006bdb9230aSGarrett D'Amore 		    kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP);
4007bdb9230aSGarrett D'Amore 		for (i = 0; i < 6; i++)
4008bdb9230aSGarrett D'Amore 			sr->netaddr[i] = *p++;
4009bdb9230aSGarrett D'Amore 
4010bdb9230aSGarrett D'Amore 		for (i = 0; i < sr->adapters; i++) {
4011bdb9230aSGarrett D'Amore 			uchar_t devno = *p++;
4012bdb9230aSGarrett D'Amore 			uint16_t offset = *p++;
4013bdb9230aSGarrett D'Amore 			offset |= *p++ << 8;
4014bdb9230aSGarrett D'Amore 			sr->leaf[i].device_number = devno;
4015bdb9230aSGarrett D'Amore 			parse_controller_leaf(dnetp, sr->leaf+i, vi+offset);
4016bdb9230aSGarrett D'Amore 		}
4017bdb9230aSGarrett D'Amore 		/*
4018bdb9230aSGarrett D'Amore 		 * 'Orrible hack for cogent cards. The 6911A board seems to
4019bdb9230aSGarrett D'Amore 		 * have an incorrect SROM. (From the OEMDEMO program
4020bdb9230aSGarrett D'Amore 		 * supplied by cogent, it seems that the ROM matches a setup
4021bdb9230aSGarrett D'Amore 		 * or a board with a QSI or ICS PHY.
4022bdb9230aSGarrett D'Amore 		 */
4023bdb9230aSGarrett D'Amore 		for (i = 0; i < 3; i++)
4024bdb9230aSGarrett D'Amore 			ether_mfg = (ether_mfg << 8) | sr->netaddr[i];
4025bdb9230aSGarrett D'Amore 
4026bdb9230aSGarrett D'Amore 		if (ether_mfg == ADAPTEC_ETHER) {
4027bdb9230aSGarrett D'Amore 			static uint16_t cogent_gprseq[] = {0x821, 0};
4028bdb9230aSGarrett D'Amore 			switch (vi[COGENT_SROM_ID]) {
4029bdb9230aSGarrett D'Amore 			case COGENT_ANA6911A_C:
4030bdb9230aSGarrett D'Amore 			case COGENT_ANA6911AC_C:
4031bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
4032bdb9230aSGarrett D'Amore 				if (dnetdebug & DNETTRACE)
4033bdb9230aSGarrett D'Amore 					cmn_err(CE_WARN,
4034bdb9230aSGarrett D'Amore 					    "Suspected bad GPR sequence."
4035bdb9230aSGarrett D'Amore 					    " Making a guess (821,0)");
4036bdb9230aSGarrett D'Amore #endif
4037bdb9230aSGarrett D'Amore 
4038bdb9230aSGarrett D'Amore 				/* XXX function return value ignored */
4039bdb9230aSGarrett D'Amore 				(void) ddi_prop_update_byte_array(
4040bdb9230aSGarrett D'Amore 				    DDI_DEV_T_NONE, dnetp->devinfo,
4041bdb9230aSGarrett D'Amore 				    "gpr-sequence", (uchar_t *)cogent_gprseq,
4042bdb9230aSGarrett D'Amore 				    sizeof (cogent_gprseq));
4043bdb9230aSGarrett D'Amore 				break;
4044bdb9230aSGarrett D'Amore 			}
4045bdb9230aSGarrett D'Amore 		}
4046bdb9230aSGarrett D'Amore 	} else {
4047bdb9230aSGarrett D'Amore 		/*
4048bdb9230aSGarrett D'Amore 		 * Adhoc SROM, check for some cards which need special handling
4049bdb9230aSGarrett D'Amore 		 * Assume vendor info contains ether address in first six bytes
4050bdb9230aSGarrett D'Amore 		 */
4051bdb9230aSGarrett D'Amore 
4052bdb9230aSGarrett D'Amore 		uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
4053bdb9230aSGarrett D'Amore 		    DDI_PROP_DONTPASS, macoffset_propname, 0);
4054bdb9230aSGarrett D'Amore 
4055bdb9230aSGarrett D'Amore 		for (i = 0; i < 6; i++)
4056bdb9230aSGarrett D'Amore 			sr->netaddr[i] = mac[i];
4057bdb9230aSGarrett D'Amore 
4058bdb9230aSGarrett D'Amore 		if (dnetp->board_type == DEVICE_ID_21140) {
4059bdb9230aSGarrett D'Amore 			for (i = 0; i < 3; i++)
4060bdb9230aSGarrett D'Amore 				ether_mfg = (ether_mfg << 8) | mac[i];
4061bdb9230aSGarrett D'Amore 
4062bdb9230aSGarrett D'Amore 			switch (ether_mfg) {
4063bdb9230aSGarrett D'Amore 			case ASANTE_ETHER:
4064bdb9230aSGarrett D'Amore 				dnetp->vendor_21140 = ASANTE_TYPE;
4065bdb9230aSGarrett D'Amore 				dnetp->vendor_revision = 0;
4066bdb9230aSGarrett D'Amore 				set_leaf(sr, &leaf_asante);
4067bdb9230aSGarrett D'Amore 				sr->adapters = 1;
4068bdb9230aSGarrett D'Amore 				break;
4069bdb9230aSGarrett D'Amore 
4070bdb9230aSGarrett D'Amore 			case COGENT_ETHER:
4071bdb9230aSGarrett D'Amore 			case ADAPTEC_ETHER:
4072bdb9230aSGarrett D'Amore 				dnetp->vendor_21140 = COGENT_EM_TYPE;
4073bdb9230aSGarrett D'Amore 				dnetp->vendor_revision =
4074bdb9230aSGarrett D'Amore 				    vi[VENDOR_REVISION_OFFSET];
4075bdb9230aSGarrett D'Amore 				set_leaf(sr, &leaf_cogent_100);
4076bdb9230aSGarrett D'Amore 				sr->adapters = 1;
4077bdb9230aSGarrett D'Amore 				break;
4078bdb9230aSGarrett D'Amore 
4079bdb9230aSGarrett D'Amore 			default:
4080bdb9230aSGarrett D'Amore 				dnetp->vendor_21140 = DEFAULT_TYPE;
4081bdb9230aSGarrett D'Amore 				dnetp->vendor_revision = 0;
4082bdb9230aSGarrett D'Amore 				set_leaf(sr, &leaf_default_100);
4083bdb9230aSGarrett D'Amore 				sr->adapters = 1;
4084bdb9230aSGarrett D'Amore 				break;
4085bdb9230aSGarrett D'Amore 			}
4086bdb9230aSGarrett D'Amore 		} else if (dnetp->board_type == DEVICE_ID_21041) {
4087bdb9230aSGarrett D'Amore 			set_leaf(sr, &leaf_21041);
4088bdb9230aSGarrett D'Amore 		} else if (dnetp->board_type == DEVICE_ID_21040) {
4089bdb9230aSGarrett D'Amore 			set_leaf(sr, &leaf_21040);
4090bdb9230aSGarrett D'Amore 		}
4091bdb9230aSGarrett D'Amore 	}
4092bdb9230aSGarrett D'Amore }
4093bdb9230aSGarrett D'Amore 
4094bdb9230aSGarrett D'Amore /* Section 4.2, 4.3, 4.4, 4.5 */
4095bdb9230aSGarrett D'Amore static void
parse_controller_leaf(struct dnetinstance * dnetp,LEAF_FORMAT * leaf,uchar_t * vi)4096bdb9230aSGarrett D'Amore parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
4097bdb9230aSGarrett D'Amore     uchar_t *vi)
4098bdb9230aSGarrett D'Amore {
4099bdb9230aSGarrett D'Amore 	int i;
4100bdb9230aSGarrett D'Amore 
4101bdb9230aSGarrett D'Amore 	leaf->selected_contype = *vi++;
4102bdb9230aSGarrett D'Amore 	leaf->selected_contype |= *vi++ << 8;
4103bdb9230aSGarrett D'Amore 
4104bdb9230aSGarrett D'Amore 	if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */
4105bdb9230aSGarrett D'Amore 		leaf->gpr = *vi++;
4106bdb9230aSGarrett D'Amore 
4107bdb9230aSGarrett D'Amore 	leaf->block_count = *vi++;
4108bdb9230aSGarrett D'Amore 
4109bdb9230aSGarrett D'Amore 	if (leaf->block_count > MAX_MEDIA) {
4110bdb9230aSGarrett D'Amore 		cmn_err(CE_WARN, "dnet: Too many media in SROM!");
4111bdb9230aSGarrett D'Amore 		leaf->block_count = 1;
4112bdb9230aSGarrett D'Amore 	}
4113bdb9230aSGarrett D'Amore 	for (i = 0; i <= leaf->block_count; i++) {
4114bdb9230aSGarrett D'Amore 		vi = parse_media_block(dnetp, leaf->block + i, vi);
4115bdb9230aSGarrett D'Amore 		if (leaf->block[i].command & CMD_DEFAULT_MEDIUM)
4116bdb9230aSGarrett D'Amore 			leaf->default_block = leaf->block+i;
4117bdb9230aSGarrett D'Amore 	}
4118bdb9230aSGarrett D'Amore 	/* No explicit default block: use last in the ROM */
4119bdb9230aSGarrett D'Amore 	if (leaf->default_block == NULL)
4120bdb9230aSGarrett D'Amore 		leaf->default_block = leaf->block + leaf->block_count -1;
4121bdb9230aSGarrett D'Amore 
4122bdb9230aSGarrett D'Amore }
4123bdb9230aSGarrett D'Amore 
4124bdb9230aSGarrett D'Amore static uchar_t *
parse_media_block(struct dnetinstance * dnetp,media_block_t * block,uchar_t * vi)4125bdb9230aSGarrett D'Amore parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi)
4126bdb9230aSGarrett D'Amore {
4127bdb9230aSGarrett D'Amore 	int i;
4128bdb9230aSGarrett D'Amore 
4129bdb9230aSGarrett D'Amore 	/*
4130bdb9230aSGarrett D'Amore 	 * There are three kinds of media block we need to worry about:
4131bdb9230aSGarrett D'Amore 	 * The 21041 blocks.
4132bdb9230aSGarrett D'Amore 	 * 21140 blocks from a version 1 SROM
4133bdb9230aSGarrett D'Amore 	 * 2114[023] block from a version 3 SROM
4134bdb9230aSGarrett D'Amore 	 */
4135bdb9230aSGarrett D'Amore 
4136bdb9230aSGarrett D'Amore 	if (dnetp->board_type == DEVICE_ID_21041) {
4137bdb9230aSGarrett D'Amore 		/* Section 4.2 */
4138bdb9230aSGarrett D'Amore 		block->media_code = *vi & 0x3f;
4139bdb9230aSGarrett D'Amore 		block->type = 2;
4140bdb9230aSGarrett D'Amore 		if (*vi++ & 0x40) {
4141bdb9230aSGarrett D'Amore 			block->un.sia.csr13 = *vi++;
4142bdb9230aSGarrett D'Amore 			block->un.sia.csr13 |= *vi++ << 8;
4143bdb9230aSGarrett D'Amore 			block->un.sia.csr14 = *vi++;
4144bdb9230aSGarrett D'Amore 			block->un.sia.csr14 |= *vi++ << 8;
4145bdb9230aSGarrett D'Amore 			block->un.sia.csr15 = *vi++;
4146bdb9230aSGarrett D'Amore 			block->un.sia.csr15 |= *vi++ << 8;
4147bdb9230aSGarrett D'Amore 		} else {
4148bdb9230aSGarrett D'Amore 			/* No media data (csrs 13,14,15). Insert defaults */
4149bdb9230aSGarrett D'Amore 			switch (block->media_code) {
4150bdb9230aSGarrett D'Amore 			case MEDIA_TP:
4151bdb9230aSGarrett D'Amore 				block->un.sia.csr13 = 0xef01;
4152bdb9230aSGarrett D'Amore 				block->un.sia.csr14 = 0x7f3f;
4153bdb9230aSGarrett D'Amore 				block->un.sia.csr15 = 0x0008;
4154bdb9230aSGarrett D'Amore 				break;
4155bdb9230aSGarrett D'Amore 			case MEDIA_TP_FD:
4156bdb9230aSGarrett D'Amore 				block->un.sia.csr13 = 0xef01;
4157bdb9230aSGarrett D'Amore 				block->un.sia.csr14 = 0x7f3d;
4158bdb9230aSGarrett D'Amore 				block->un.sia.csr15 = 0x0008;
4159bdb9230aSGarrett D'Amore 				break;
4160bdb9230aSGarrett D'Amore 			case MEDIA_BNC:
4161bdb9230aSGarrett D'Amore 				block->un.sia.csr13 = 0xef09;
4162bdb9230aSGarrett D'Amore 				block->un.sia.csr14 = 0x0705;
4163bdb9230aSGarrett D'Amore 				block->un.sia.csr15 = 0x0006;
4164bdb9230aSGarrett D'Amore 				break;
4165bdb9230aSGarrett D'Amore 			case MEDIA_AUI:
4166bdb9230aSGarrett D'Amore 				block->un.sia.csr13 = 0xef09;
4167bdb9230aSGarrett D'Amore 				block->un.sia.csr14 = 0x0705;
4168bdb9230aSGarrett D'Amore 				block->un.sia.csr15 = 0x000e;
4169bdb9230aSGarrett D'Amore 				break;
4170bdb9230aSGarrett D'Amore 			}
4171bdb9230aSGarrett D'Amore 		}
4172bdb9230aSGarrett D'Amore 	} else  if (*vi & 0x80) {  /* Extended format: Section 4.3.2.2 */
4173bdb9230aSGarrett D'Amore 		int blocklen = *vi++ & 0x7f;
4174bdb9230aSGarrett D'Amore 		block->type = *vi++;
4175bdb9230aSGarrett D'Amore 		switch (block->type) {
4176bdb9230aSGarrett D'Amore 		case 0: /* "non-MII": Section 4.3.2.2.1 */
4177bdb9230aSGarrett D'Amore 			block->media_code = (*vi++) & 0x3f;
4178bdb9230aSGarrett D'Amore 			block->gprseqlen = 1;
4179bdb9230aSGarrett D'Amore 			block->gprseq[0] = *vi++;
4180bdb9230aSGarrett D'Amore 			block->command = *vi++;
4181bdb9230aSGarrett D'Amore 			block->command |= *vi++ << 8;
4182bdb9230aSGarrett D'Amore 			break;
4183bdb9230aSGarrett D'Amore 
4184bdb9230aSGarrett D'Amore 		case 1: /* MII/PHY: Section 4.3.2.2.2 */
4185bdb9230aSGarrett D'Amore 			block->command = CMD_PS;
4186bdb9230aSGarrett D'Amore 			block->media_code = MEDIA_MII;
4187bdb9230aSGarrett D'Amore 				/* This is whats needed in CSR6 */
4188bdb9230aSGarrett D'Amore 
4189bdb9230aSGarrett D'Amore 			block->un.mii.phy_num = *vi++;
4190bdb9230aSGarrett D'Amore 			block->gprseqlen = *vi++;
4191bdb9230aSGarrett D'Amore 
4192bdb9230aSGarrett D'Amore 			for (i = 0; i < block->gprseqlen; i++)
4193bdb9230aSGarrett D'Amore 				block->gprseq[i] = *vi++;
4194bdb9230aSGarrett D'Amore 			block->rstseqlen = *vi++;
4195bdb9230aSGarrett D'Amore 			for (i = 0; i < block->rstseqlen; i++)
4196bdb9230aSGarrett D'Amore 				block->rstseq[i] = *vi++;
4197bdb9230aSGarrett D'Amore 
4198bdb9230aSGarrett D'Amore 			block->un.mii.mediacaps = *vi++;
4199bdb9230aSGarrett D'Amore 			block->un.mii.mediacaps |= *vi++ << 8;
4200bdb9230aSGarrett D'Amore 			block->un.mii.nwayadvert = *vi++;
4201bdb9230aSGarrett D'Amore 			block->un.mii.nwayadvert |= *vi++ << 8;
4202bdb9230aSGarrett D'Amore 			block->un.mii.fdxmask = *vi++;
4203bdb9230aSGarrett D'Amore 			block->un.mii.fdxmask |= *vi++ << 8;
4204bdb9230aSGarrett D'Amore 			block->un.mii.ttmmask = *vi++;
4205bdb9230aSGarrett D'Amore 			block->un.mii.ttmmask |= *vi++ << 8;
4206bdb9230aSGarrett D'Amore 			break;
4207bdb9230aSGarrett D'Amore 
4208bdb9230aSGarrett D'Amore 		case 2: /* SIA Media: Section 4.4.2.1.1 */
4209bdb9230aSGarrett D'Amore 			block->media_code = *vi & 0x3f;
4210bdb9230aSGarrett D'Amore 			if (*vi++ & 0x40) {
4211bdb9230aSGarrett D'Amore 				block->un.sia.csr13 = *vi++;
4212bdb9230aSGarrett D'Amore 				block->un.sia.csr13 |= *vi++ << 8;
4213bdb9230aSGarrett D'Amore 				block->un.sia.csr14 = *vi++;
4214bdb9230aSGarrett D'Amore 				block->un.sia.csr14 |= *vi++ << 8;
4215bdb9230aSGarrett D'Amore 				block->un.sia.csr15 = *vi++;
4216bdb9230aSGarrett D'Amore 				block->un.sia.csr15 |= *vi++ << 8;
4217bdb9230aSGarrett D'Amore 			} else {
4218bdb9230aSGarrett D'Amore 				/*
4219bdb9230aSGarrett D'Amore 				 * SIA values not provided by SROM; provide
4220bdb9230aSGarrett D'Amore 				 * defaults. See appendix D of 2114[23] manuals.
4221bdb9230aSGarrett D'Amore 				 */
4222bdb9230aSGarrett D'Amore 				switch (block->media_code) {
4223bdb9230aSGarrett D'Amore 				case MEDIA_BNC:
4224bdb9230aSGarrett D'Amore 					block->un.sia.csr13 = 0x0009;
4225bdb9230aSGarrett D'Amore 					block->un.sia.csr14 = 0x0705;
4226bdb9230aSGarrett D'Amore 					block->un.sia.csr15 = 0x0000;
4227bdb9230aSGarrett D'Amore 					break;
4228bdb9230aSGarrett D'Amore 				case MEDIA_AUI:
4229bdb9230aSGarrett D'Amore 					block->un.sia.csr13 = 0x0009;
4230bdb9230aSGarrett D'Amore 					block->un.sia.csr14 = 0x0705;
4231bdb9230aSGarrett D'Amore 					block->un.sia.csr15 = 0x0008;
4232bdb9230aSGarrett D'Amore 					break;
4233bdb9230aSGarrett D'Amore 				case MEDIA_TP:
4234bdb9230aSGarrett D'Amore 					block->un.sia.csr13 = 0x0001;
4235bdb9230aSGarrett D'Amore 					block->un.sia.csr14 = 0x7f3f;
4236bdb9230aSGarrett D'Amore 					block->un.sia.csr15 = 0x0000;
4237bdb9230aSGarrett D'Amore 					break;
4238bdb9230aSGarrett D'Amore 				case MEDIA_TP_FD:
4239bdb9230aSGarrett D'Amore 					block->un.sia.csr13 = 0x0001;
4240bdb9230aSGarrett D'Amore 					block->un.sia.csr14 = 0x7f3d;
4241bdb9230aSGarrett D'Amore 					block->un.sia.csr15 = 0x0000;
4242bdb9230aSGarrett D'Amore 					break;
4243bdb9230aSGarrett D'Amore 				default:
4244bdb9230aSGarrett D'Amore 					block->un.sia.csr13 = 0x0000;
4245bdb9230aSGarrett D'Amore 					block->un.sia.csr14 = 0x0000;
4246bdb9230aSGarrett D'Amore 					block->un.sia.csr15 = 0x0000;
4247bdb9230aSGarrett D'Amore 				}
4248bdb9230aSGarrett D'Amore 			}
4249bdb9230aSGarrett D'Amore 
4250bdb9230aSGarrett D'Amore 			/* Treat GP control/data as a GPR sequence */
4251bdb9230aSGarrett D'Amore 			block->gprseqlen = 2;
4252bdb9230aSGarrett D'Amore 			block->gprseq[0] = *vi++;
4253bdb9230aSGarrett D'Amore 			block->gprseq[0] |= *vi++ << 8;
4254bdb9230aSGarrett D'Amore 			block->gprseq[0] |= GPR_CONTROL_WRITE;
4255bdb9230aSGarrett D'Amore 			block->gprseq[1] = *vi++;
4256bdb9230aSGarrett D'Amore 			block->gprseq[1] |= *vi++ << 8;
4257bdb9230aSGarrett D'Amore 			break;
4258bdb9230aSGarrett D'Amore 
4259bdb9230aSGarrett D'Amore 		case 3: /* MII/PHY : Section 4.4.2.1.2 */
4260bdb9230aSGarrett D'Amore 			block->command = CMD_PS;
4261bdb9230aSGarrett D'Amore 			block->media_code = MEDIA_MII;
4262bdb9230aSGarrett D'Amore 			block->un.mii.phy_num = *vi++;
4263bdb9230aSGarrett D'Amore 
4264bdb9230aSGarrett D'Amore 			block->gprseqlen = *vi++;
4265bdb9230aSGarrett D'Amore 			for (i = 0; i < block->gprseqlen; i++) {
4266bdb9230aSGarrett D'Amore 				block->gprseq[i] = *vi++;
4267bdb9230aSGarrett D'Amore 				block->gprseq[i] |= *vi++ << 8;
4268bdb9230aSGarrett D'Amore 			}
4269bdb9230aSGarrett D'Amore 
4270bdb9230aSGarrett D'Amore 			block->rstseqlen = *vi++;
4271bdb9230aSGarrett D'Amore 			for (i = 0; i < block->rstseqlen; i++) {
4272bdb9230aSGarrett D'Amore 				block->rstseq[i] = *vi++;
4273bdb9230aSGarrett D'Amore 				block->rstseq[i] |= *vi++ << 8;
4274bdb9230aSGarrett D'Amore 			}
4275bdb9230aSGarrett D'Amore 			block->un.mii.mediacaps = *vi++;
4276bdb9230aSGarrett D'Amore 			block->un.mii.mediacaps |= *vi++ << 8;
4277bdb9230aSGarrett D'Amore 			block->un.mii.nwayadvert = *vi++;
4278bdb9230aSGarrett D'Amore 			block->un.mii.nwayadvert |= *vi++ << 8;
4279bdb9230aSGarrett D'Amore 			block->un.mii.fdxmask = *vi++;
4280bdb9230aSGarrett D'Amore 			block->un.mii.fdxmask |= *vi++ << 8;
4281bdb9230aSGarrett D'Amore 			block->un.mii.ttmmask = *vi++;
4282bdb9230aSGarrett D'Amore 			block->un.mii.ttmmask |= *vi++ << 8;
4283bdb9230aSGarrett D'Amore 			block->un.mii.miiintr |= *vi++;
4284bdb9230aSGarrett D'Amore 			break;
4285bdb9230aSGarrett D'Amore 
4286bdb9230aSGarrett D'Amore 		case 4: /* SYM Media: 4.5.2.1.3 */
4287bdb9230aSGarrett D'Amore 			block->media_code = *vi++ & 0x3f;
4288bdb9230aSGarrett D'Amore 			/* Treat GP control and data as a GPR sequence */
4289bdb9230aSGarrett D'Amore 			block->gprseqlen = 2;
4290bdb9230aSGarrett D'Amore 			block->gprseq[0] = *vi++;
4291bdb9230aSGarrett D'Amore 			block->gprseq[0] |= *vi++ << 8;
4292bdb9230aSGarrett D'Amore 			block->gprseq[0] |= GPR_CONTROL_WRITE;
4293bdb9230aSGarrett D'Amore 			block->gprseq[1]  = *vi++;
4294bdb9230aSGarrett D'Amore 			block->gprseq[1] |= *vi++ << 8;
4295bdb9230aSGarrett D'Amore 			block->command = *vi++;
4296bdb9230aSGarrett D'Amore 			block->command |= *vi++ << 8;
4297bdb9230aSGarrett D'Amore 			break;
4298bdb9230aSGarrett D'Amore 
4299bdb9230aSGarrett D'Amore 		case 5: /* GPR reset sequence:  Section 4.5.2.1.4 */
4300bdb9230aSGarrett D'Amore 			block->rstseqlen = *vi++;
4301bdb9230aSGarrett D'Amore 			for (i = 0; i < block->rstseqlen; i++)
4302bdb9230aSGarrett D'Amore 				block->rstseq[i] = *vi++;
4303bdb9230aSGarrett D'Amore 			break;
4304bdb9230aSGarrett D'Amore 
4305bdb9230aSGarrett D'Amore 		default: /* Unknown media block. Skip it. */
4306bdb9230aSGarrett D'Amore 			cmn_err(CE_WARN, "dnet: Unsupported SROM block.");
4307bdb9230aSGarrett D'Amore 			vi += blocklen;
4308bdb9230aSGarrett D'Amore 			break;
4309bdb9230aSGarrett D'Amore 		}
4310bdb9230aSGarrett D'Amore 	} else { /* Compact format (or V1 SROM): Section 4.3.2.1 */
4311bdb9230aSGarrett D'Amore 		block->type = 0;
4312bdb9230aSGarrett D'Amore 		block->media_code = *vi++ & 0x3f;
4313bdb9230aSGarrett D'Amore 		block->gprseqlen = 1;
4314bdb9230aSGarrett D'Amore 		block->gprseq[0] = *vi++;
4315bdb9230aSGarrett D'Amore 		block->command = *vi++;
4316bdb9230aSGarrett D'Amore 		block->command |= (*vi++) << 8;
4317bdb9230aSGarrett D'Amore 	}
4318bdb9230aSGarrett D'Amore 	return (vi);
4319bdb9230aSGarrett D'Amore }
4320bdb9230aSGarrett D'Amore 
4321bdb9230aSGarrett D'Amore 
4322bdb9230aSGarrett D'Amore /*
4323bdb9230aSGarrett D'Amore  * An alternative to doing this would be to store the legacy ROMs in binary
4324bdb9230aSGarrett D'Amore  * format in the conf file, and in read_srom, pick out the data. This would
4325bdb9230aSGarrett D'Amore  * then allow the parser to continue on as normal. This makes it a little
4326bdb9230aSGarrett D'Amore  * easier to read.
4327bdb9230aSGarrett D'Amore  */
4328bdb9230aSGarrett D'Amore static void
setup_legacy_blocks()4329bdb9230aSGarrett D'Amore setup_legacy_blocks()
4330bdb9230aSGarrett D'Amore {
4331bdb9230aSGarrett D'Amore 	LEAF_FORMAT *leaf;
4332bdb9230aSGarrett D'Amore 	media_block_t *block;
4333bdb9230aSGarrett D'Amore 
4334bdb9230aSGarrett D'Amore 	/* Default FAKE SROM */
4335bdb9230aSGarrett D'Amore 	leaf = &leaf_default_100;
4336bdb9230aSGarrett D'Amore 	leaf->is_static = 1;
4337bdb9230aSGarrett D'Amore 	leaf->default_block = &leaf->block[3];
4338bdb9230aSGarrett D'Amore 	leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */
4339bdb9230aSGarrett D'Amore 	block = leaf->block;
4340bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP_FD;
4341bdb9230aSGarrett D'Amore 	block->type = 0;
4342bdb9230aSGarrett D'Amore 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4343bdb9230aSGarrett D'Amore 	block++;
4344bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP;
4345bdb9230aSGarrett D'Amore 	block->type = 0;
4346bdb9230aSGarrett D'Amore 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4347bdb9230aSGarrett D'Amore 	block++;
4348bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_SYM_SCR_FD;
4349bdb9230aSGarrett D'Amore 	block->type = 0;
4350bdb9230aSGarrett D'Amore 	block->command = 0x6d;  /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4351bdb9230aSGarrett D'Amore 	block++;
4352bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_SYM_SCR;
4353bdb9230aSGarrett D'Amore 	block->type = 0;
4354bdb9230aSGarrett D'Amore 	block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4355bdb9230aSGarrett D'Amore 
4356bdb9230aSGarrett D'Amore 	/* COGENT FAKE SROM */
4357bdb9230aSGarrett D'Amore 	leaf = &leaf_cogent_100;
4358bdb9230aSGarrett D'Amore 	leaf->is_static = 1;
4359bdb9230aSGarrett D'Amore 	leaf->default_block = &leaf->block[4];
4360bdb9230aSGarrett D'Amore 	leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */
4361bdb9230aSGarrett D'Amore 	block = leaf->block; /* BNC */
4362bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_BNC;
4363bdb9230aSGarrett D'Amore 	block->type = 0;
4364bdb9230aSGarrett D'Amore 	block->command =  0x8000; /* No media sense, PCS, SCR, PS all off */
4365bdb9230aSGarrett D'Amore 	block->gprseqlen = 2;
4366bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4367bdb9230aSGarrett D'Amore 	block->gprseq[0] = 0x13f;
4368bdb9230aSGarrett D'Amore 	block->gprseq[1] = 1;
4369bdb9230aSGarrett D'Amore 
4370bdb9230aSGarrett D'Amore 	block++;
4371bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP_FD;
4372bdb9230aSGarrett D'Amore 	block->type = 0;
4373bdb9230aSGarrett D'Amore 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4374bdb9230aSGarrett D'Amore 	block->gprseqlen = 2;
4375bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4376bdb9230aSGarrett D'Amore 	block->gprseq[0] = 0x13f;
4377bdb9230aSGarrett D'Amore 	block->gprseq[1] = 0x26;
4378bdb9230aSGarrett D'Amore 
4379bdb9230aSGarrett D'Amore 	block++; /* 10BaseT */
4380bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP;
4381bdb9230aSGarrett D'Amore 	block->type = 0;
4382bdb9230aSGarrett D'Amore 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
4383bdb9230aSGarrett D'Amore 	block->gprseqlen = 2;
4384bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4385bdb9230aSGarrett D'Amore 	block->gprseq[0] = 0x13f;
4386bdb9230aSGarrett D'Amore 	block->gprseq[1] = 0x3e;
4387bdb9230aSGarrett D'Amore 
4388bdb9230aSGarrett D'Amore 	block++; /* 100BaseTX-FD */
4389bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_SYM_SCR_FD;
4390bdb9230aSGarrett D'Amore 	block->type = 0;
4391bdb9230aSGarrett D'Amore 	block->command = 0x6d;  /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4392bdb9230aSGarrett D'Amore 	block->gprseqlen = 2;
4393bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4394bdb9230aSGarrett D'Amore 	block->gprseq[0] = 0x13f;
4395bdb9230aSGarrett D'Amore 	block->gprseq[1] = 1;
4396bdb9230aSGarrett D'Amore 
4397bdb9230aSGarrett D'Amore 	block++; /* 100BaseTX */
4398bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_SYM_SCR;
4399bdb9230aSGarrett D'Amore 	block->type = 0;
4400bdb9230aSGarrett D'Amore 	block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4401bdb9230aSGarrett D'Amore 	block->gprseqlen = 2;
4402bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4403bdb9230aSGarrett D'Amore 	block->gprseq[0] = 0x13f;
4404bdb9230aSGarrett D'Amore 	block->gprseq[1] = 1;
4405bdb9230aSGarrett D'Amore 
4406bdb9230aSGarrett D'Amore 	/* Generic legacy card with a PHY. */
4407bdb9230aSGarrett D'Amore 	leaf = &leaf_phylegacy;
4408bdb9230aSGarrett D'Amore 	leaf->block_count = 1;
4409bdb9230aSGarrett D'Amore 	leaf->mii_block = leaf->block;
4410bdb9230aSGarrett D'Amore 	leaf->default_block = &leaf->block[0];
4411bdb9230aSGarrett D'Amore 	leaf->is_static = 1;
4412bdb9230aSGarrett D'Amore 	block = leaf->block;
4413bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_MII;
4414bdb9230aSGarrett D'Amore 	block->type = 1; /* MII Block type 1 */
4415bdb9230aSGarrett D'Amore 	block->command = 1; /* Port select */
4416bdb9230aSGarrett D'Amore 	block->gprseqlen = 0;
4417bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4418bdb9230aSGarrett D'Amore 
4419bdb9230aSGarrett D'Amore 	/* ASANTE FAKE SROM */
4420bdb9230aSGarrett D'Amore 	leaf = &leaf_asante;
4421bdb9230aSGarrett D'Amore 	leaf->is_static = 1;
4422bdb9230aSGarrett D'Amore 	leaf->default_block = &leaf->block[0];
4423bdb9230aSGarrett D'Amore 	leaf->block_count = 1;
4424bdb9230aSGarrett D'Amore 	block = leaf->block;
4425bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_MII;
4426bdb9230aSGarrett D'Amore 	block->type = 1; /* MII Block type 1 */
4427bdb9230aSGarrett D'Amore 	block->command = 1; /* Port select */
4428bdb9230aSGarrett D'Amore 	block->gprseqlen = 3;
4429bdb9230aSGarrett D'Amore 	block->rstseqlen = 0;
4430bdb9230aSGarrett D'Amore 	block->gprseq[0] = 0x180;
4431bdb9230aSGarrett D'Amore 	block->gprseq[1] = 0x80;
4432bdb9230aSGarrett D'Amore 	block->gprseq[2] = 0x0;
4433bdb9230aSGarrett D'Amore 
4434bdb9230aSGarrett D'Amore 	/* LEGACY 21041 card FAKE SROM */
4435bdb9230aSGarrett D'Amore 	leaf = &leaf_21041;
4436bdb9230aSGarrett D'Amore 	leaf->is_static = 1;
4437bdb9230aSGarrett D'Amore 	leaf->block_count = 4;  /* SIA Blocks for TP, TPfd, BNC, AUI */
4438bdb9230aSGarrett D'Amore 	leaf->default_block = &leaf->block[3];
4439bdb9230aSGarrett D'Amore 
4440bdb9230aSGarrett D'Amore 	block = leaf->block;
4441bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_AUI;
4442bdb9230aSGarrett D'Amore 	block->type = 2;
4443bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0xef09;
4444bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x0705;
4445bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x000e;
4446bdb9230aSGarrett D'Amore 
4447bdb9230aSGarrett D'Amore 	block++;
4448bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP_FD;
4449bdb9230aSGarrett D'Amore 	block->type = 2;
4450bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0xef01;
4451bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x7f3d;
4452bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x0008;
4453bdb9230aSGarrett D'Amore 
4454bdb9230aSGarrett D'Amore 	block++;
4455bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_BNC;
4456bdb9230aSGarrett D'Amore 	block->type = 2;
4457bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0xef09;
4458bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x0705;
4459bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x0006;
4460bdb9230aSGarrett D'Amore 
4461bdb9230aSGarrett D'Amore 	block++;
4462bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP;
4463bdb9230aSGarrett D'Amore 	block->type = 2;
4464bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0xef01;
4465bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x7f3f;
4466bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x0008;
4467bdb9230aSGarrett D'Amore 
4468bdb9230aSGarrett D'Amore 	/* LEGACY 21040 card FAKE SROM */
4469bdb9230aSGarrett D'Amore 	leaf = &leaf_21040;
4470bdb9230aSGarrett D'Amore 	leaf->is_static = 1;
4471bdb9230aSGarrett D'Amore 	leaf->block_count = 4;  /* SIA Blocks for TP, TPfd, BNC, AUI */
4472bdb9230aSGarrett D'Amore 	block = leaf->block;
4473bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_AUI;
4474bdb9230aSGarrett D'Amore 	block->type = 2;
4475bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0x8f09;
4476bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x0705;
4477bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x000e;
4478bdb9230aSGarrett D'Amore 	block++;
4479bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP_FD;
4480bdb9230aSGarrett D'Amore 	block->type = 2;
4481bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0x0f01;
4482bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x7f3d;
4483bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x0008;
4484bdb9230aSGarrett D'Amore 	block++;
4485bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_BNC;
4486bdb9230aSGarrett D'Amore 	block->type = 2;
4487bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0xef09;
4488bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x0705;
4489bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x0006;
4490bdb9230aSGarrett D'Amore 	block++;
4491bdb9230aSGarrett D'Amore 	block->media_code = MEDIA_TP;
4492bdb9230aSGarrett D'Amore 	block->type = 2;
4493bdb9230aSGarrett D'Amore 	block->un.sia.csr13 = 0x8f01;
4494bdb9230aSGarrett D'Amore 	block->un.sia.csr14 = 0x7f3f;
4495bdb9230aSGarrett D'Amore 	block->un.sia.csr15 = 0x0008;
4496bdb9230aSGarrett D'Amore }
4497bdb9230aSGarrett D'Amore 
4498bdb9230aSGarrett D'Amore static void
dnet_print_srom(SROM_FORMAT * sr)4499bdb9230aSGarrett D'Amore dnet_print_srom(SROM_FORMAT *sr)
4500bdb9230aSGarrett D'Amore {
4501bdb9230aSGarrett D'Amore 	int i;
4502bdb9230aSGarrett D'Amore 	uchar_t *a = sr->netaddr;
4503bdb9230aSGarrett D'Amore 	cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d,"
4504bdb9230aSGarrett D'Amore 	    "Addr:%x:%x:%x:%x:%x:%x",
4505bdb9230aSGarrett D'Amore 	    sr->init_from_srom, sr->version, sr->adapters,
4506bdb9230aSGarrett D'Amore 	    a[0], a[1], a[2], a[3], a[4], a[5]);
4507bdb9230aSGarrett D'Amore 
4508bdb9230aSGarrett D'Amore 	for (i = 0; i < sr->adapters; i++)
4509bdb9230aSGarrett D'Amore 		dnet_dump_leaf(sr->leaf+i);
4510bdb9230aSGarrett D'Amore }
4511bdb9230aSGarrett D'Amore 
4512bdb9230aSGarrett D'Amore static void
dnet_dump_leaf(LEAF_FORMAT * leaf)4513bdb9230aSGarrett D'Amore dnet_dump_leaf(LEAF_FORMAT *leaf)
4514bdb9230aSGarrett D'Amore {
4515bdb9230aSGarrett D'Amore 	int i;
4516bdb9230aSGarrett D'Amore 	cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x",
4517bdb9230aSGarrett D'Amore 	    leaf->device_number, leaf->block_count, leaf->gpr);
4518bdb9230aSGarrett D'Amore 	for (i = 0; i < leaf->block_count; i++)
4519bdb9230aSGarrett D'Amore 		dnet_dump_block(leaf->block+i);
4520bdb9230aSGarrett D'Amore }
4521bdb9230aSGarrett D'Amore 
4522bdb9230aSGarrett D'Amore static void
dnet_dump_block(media_block_t * block)4523bdb9230aSGarrett D'Amore dnet_dump_block(media_block_t *block)
4524bdb9230aSGarrett D'Amore {
4525bdb9230aSGarrett D'Amore 	cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ",
4526bdb9230aSGarrett D'Amore 	    (void *)block,
4527bdb9230aSGarrett D'Amore 	    block->type, media_str[block->media_code], block->command);
4528bdb9230aSGarrett D'Amore 	dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2,
4529bdb9230aSGarrett D'Amore 	    block->gprseqlen *2);
4530bdb9230aSGarrett D'Amore 	dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2,
4531bdb9230aSGarrett D'Amore 	    block->rstseqlen *2);
4532bdb9230aSGarrett D'Amore 	switch (block->type) {
4533bdb9230aSGarrett D'Amore 	case 1: case 3:
4534bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx"
4535bdb9230aSGarrett D'Amore 		    "%x, ttm %x, mediacap %x",
4536bdb9230aSGarrett D'Amore 		    block->un.mii.phy_num, block->un.mii.nwayadvert,
4537bdb9230aSGarrett D'Amore 		    block->un.mii.fdxmask, block->un.mii.ttmmask,
4538bdb9230aSGarrett D'Amore 		    block->un.mii.mediacaps);
4539bdb9230aSGarrett D'Amore 		break;
4540bdb9230aSGarrett D'Amore 	case 2:
4541bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x",
4542bdb9230aSGarrett D'Amore 		    block->un.sia.csr13, block->un.sia.csr14,
4543bdb9230aSGarrett D'Amore 		    block->un.sia.csr15);
4544bdb9230aSGarrett D'Amore 		break;
4545bdb9230aSGarrett D'Amore 	}
4546bdb9230aSGarrett D'Amore }
4547bdb9230aSGarrett D'Amore 
4548bdb9230aSGarrett D'Amore 
4549bdb9230aSGarrett D'Amore /* Utility to print out binary info dumps. Handy for SROMs, etc */
4550bdb9230aSGarrett D'Amore 
4551bdb9230aSGarrett D'Amore static int
hexcode(unsigned val)4552bdb9230aSGarrett D'Amore hexcode(unsigned val)
4553bdb9230aSGarrett D'Amore {
4554bdb9230aSGarrett D'Amore 	if (val <= 9)
4555bdb9230aSGarrett D'Amore 		return (val +'0');
4556bdb9230aSGarrett D'Amore 	if (val <= 15)
4557bdb9230aSGarrett D'Amore 		return (val + 'a' - 10);
4558bdb9230aSGarrett D'Amore 	return (-1);
4559bdb9230aSGarrett D'Amore }
4560bdb9230aSGarrett D'Amore 
4561bdb9230aSGarrett D'Amore static void
dnet_dumpbin(char * msg,unsigned char * data,int size,int len)4562bdb9230aSGarrett D'Amore dnet_dumpbin(char *msg, unsigned char *data, int size, int len)
4563bdb9230aSGarrett D'Amore {
4564bdb9230aSGarrett D'Amore 	char hex[128], *p = hex;
4565bdb9230aSGarrett D'Amore 	char ascii[128], *q = ascii;
4566bdb9230aSGarrett D'Amore 	int i, j;
4567bdb9230aSGarrett D'Amore 
4568bdb9230aSGarrett D'Amore 	if (!len)
4569bdb9230aSGarrett D'Amore 		return;
4570bdb9230aSGarrett D'Amore 
4571bdb9230aSGarrett D'Amore 	for (i = 0; i < len; i += size) {
4572bdb9230aSGarrett D'Amore 		for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */
4573bdb9230aSGarrett D'Amore 			*p++ = hexcode(data[i+j] >> 4);
4574bdb9230aSGarrett D'Amore 			*p++ = hexcode(data[i+j] & 0xf);
4575bdb9230aSGarrett D'Amore 			*q++ = (data[i+j] < 32 || data[i+j] > 127) ?
4576bdb9230aSGarrett D'Amore 			    '.' : data[i];
4577bdb9230aSGarrett D'Amore 		}
4578bdb9230aSGarrett D'Amore 		*p++ = ' ';
4579bdb9230aSGarrett D'Amore 		if (q-ascii >= 8) {
4580bdb9230aSGarrett D'Amore 			*p = *q = 0;
4581bdb9230aSGarrett D'Amore 			cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4582bdb9230aSGarrett D'Amore 			p = hex;
4583bdb9230aSGarrett D'Amore 			q = ascii;
4584bdb9230aSGarrett D'Amore 		}
4585bdb9230aSGarrett D'Amore 	}
4586bdb9230aSGarrett D'Amore 	if (p != hex) {
4587bdb9230aSGarrett D'Amore 		while ((p - hex) < 8*3)
4588bdb9230aSGarrett D'Amore 			*p++ = ' ';
4589bdb9230aSGarrett D'Amore 		*p = *q = 0;
4590bdb9230aSGarrett D'Amore 		cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4591bdb9230aSGarrett D'Amore 	}
4592bdb9230aSGarrett D'Amore }
4593bdb9230aSGarrett D'Amore 
4594bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
4595bdb9230aSGarrett D'Amore void
dnet_usectimeout(struct dnetinstance * dnetp,uint32_t usecs,int contin,timercb_t cback)4596bdb9230aSGarrett D'Amore dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin,
4597bdb9230aSGarrett D'Amore     timercb_t cback)
4598bdb9230aSGarrett D'Amore {
4599bdb9230aSGarrett D'Amore 	mutex_enter(&dnetp->intrlock);
4600bdb9230aSGarrett D'Amore 	dnetp->timer.start_ticks = (usecs * 100) / 8192;
4601bdb9230aSGarrett D'Amore 	dnetp->timer.cb = cback;
4602bdb9230aSGarrett D'Amore 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG),
4603bdb9230aSGarrett D'Amore 	    dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0));
4604bdb9230aSGarrett D'Amore 	if (dnetp->timer.cb)
460598e8d175SSteven Stallion 		enable_interrupts(dnetp);
4606bdb9230aSGarrett D'Amore 	mutex_exit(&dnetp->intrlock);
4607bdb9230aSGarrett D'Amore }
4608bdb9230aSGarrett D'Amore 
4609bdb9230aSGarrett D'Amore uint32_t
dnet_usecelapsed(struct dnetinstance * dnetp)4610bdb9230aSGarrett D'Amore dnet_usecelapsed(struct dnetinstance *dnetp)
4611bdb9230aSGarrett D'Amore {
4612bdb9230aSGarrett D'Amore 	uint32_t ticks = dnetp->timer.start_ticks -
4613bdb9230aSGarrett D'Amore 	    (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) &
4614bdb9230aSGarrett D'Amore 	    0xffff);
4615bdb9230aSGarrett D'Amore 	return ((ticks * 8192) / 100);
4616bdb9230aSGarrett D'Amore }
4617bdb9230aSGarrett D'Amore 
4618bdb9230aSGarrett D'Amore /* ARGSUSED */
4619bdb9230aSGarrett D'Amore void
dnet_timestamp(struct dnetinstance * dnetp,char * buf)4620bdb9230aSGarrett D'Amore dnet_timestamp(struct dnetinstance *dnetp,  char *buf)
4621bdb9230aSGarrett D'Amore {
4622bdb9230aSGarrett D'Amore 	uint32_t elapsed = dnet_usecelapsed(dnetp);
4623bdb9230aSGarrett D'Amore 	char loc[32], *p = loc;
4624bdb9230aSGarrett D'Amore 	int firstdigit = 1;
4625bdb9230aSGarrett D'Amore 	uint32_t divisor;
4626bdb9230aSGarrett D'Amore 
4627bdb9230aSGarrett D'Amore 	while (*p++ = *buf++)
4628bdb9230aSGarrett D'Amore 		;
4629bdb9230aSGarrett D'Amore 	p--;
4630bdb9230aSGarrett D'Amore 
4631bdb9230aSGarrett D'Amore 	for (divisor = 1000000000; divisor /= 10; ) {
4632bdb9230aSGarrett D'Amore 		int digit = (elapsed / divisor);
4633bdb9230aSGarrett D'Amore 		elapsed -= digit * divisor;
4634bdb9230aSGarrett D'Amore 		if (!firstdigit || digit) {
4635bdb9230aSGarrett D'Amore 			*p++ = digit + '0';
4636bdb9230aSGarrett D'Amore 			firstdigit = 0;
4637bdb9230aSGarrett D'Amore 		}
4638bdb9230aSGarrett D'Amore 
4639bdb9230aSGarrett D'Amore 	}
4640bdb9230aSGarrett D'Amore 
4641bdb9230aSGarrett D'Amore 	/* Actual zero, output it */
4642bdb9230aSGarrett D'Amore 	if (firstdigit)
4643bdb9230aSGarrett D'Amore 		*p++ = '0';
4644bdb9230aSGarrett D'Amore 
4645bdb9230aSGarrett D'Amore 	*p++ = '-';
4646bdb9230aSGarrett D'Amore 	*p++ = '>';
4647bdb9230aSGarrett D'Amore 	*p++ = 0;
4648bdb9230aSGarrett D'Amore 
4649bdb9230aSGarrett D'Amore 	printf(loc);
4650bdb9230aSGarrett D'Amore 	dnet_usectimeout(dnetp, 1000000, 0, 0);
4651bdb9230aSGarrett D'Amore }
4652bdb9230aSGarrett D'Amore 
4653bdb9230aSGarrett D'Amore #endif
4654