xref: /illumos-gate/usr/src/uts/common/io/afe/afe.c (revision 1959748cbddf37d4734c107dadfa449e076045e3)
1*1959748cSgd78059 /*
2*1959748cSgd78059  * Solaris driver for ethernet cards based on the ADMtek Centaur
3*1959748cSgd78059  *
4*1959748cSgd78059  * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
5*1959748cSgd78059  * All rights reserved.
6*1959748cSgd78059  *
7*1959748cSgd78059  * Redistribution and use in source and binary forms, with or without
8*1959748cSgd78059  * modification, are permitted provided that the following conditions
9*1959748cSgd78059  * are met:
10*1959748cSgd78059  * 1. Redistributions of source code must retain the above copyright
11*1959748cSgd78059  *    notice, this list of conditions and the following disclaimer.
12*1959748cSgd78059  * 2. Redistributions in binary form must reproduce the above copyright
13*1959748cSgd78059  *    notice, this list of conditions and the following disclaimer in the
14*1959748cSgd78059  *    documentation and/or other materials provided with the distribution.
15*1959748cSgd78059  * 3. Neither the name of the author nor the names of any co-contributors
16*1959748cSgd78059  *    may be used to endorse or promote products derived from this software
17*1959748cSgd78059  *    without specific prior written permission.
18*1959748cSgd78059  *
19*1959748cSgd78059  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
20*1959748cSgd78059  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*1959748cSgd78059  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*1959748cSgd78059  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23*1959748cSgd78059  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*1959748cSgd78059  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*1959748cSgd78059  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*1959748cSgd78059  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*1959748cSgd78059  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*1959748cSgd78059  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*1959748cSgd78059  * POSSIBILITY OF SUCH DAMAGE.
30*1959748cSgd78059  */
31*1959748cSgd78059 
32*1959748cSgd78059 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33*1959748cSgd78059 
34*1959748cSgd78059 #include <sys/varargs.h>
35*1959748cSgd78059 #include <sys/types.h>
36*1959748cSgd78059 #include <sys/modctl.h>
37*1959748cSgd78059 #include <sys/conf.h>
38*1959748cSgd78059 #include <sys/devops.h>
39*1959748cSgd78059 #include <sys/stream.h>
40*1959748cSgd78059 #include <sys/strsun.h>
41*1959748cSgd78059 #include <sys/priv.h>
42*1959748cSgd78059 #include <sys/policy.h>
43*1959748cSgd78059 #include <sys/cred.h>
44*1959748cSgd78059 #include <sys/cmn_err.h>
45*1959748cSgd78059 #include <sys/dlpi.h>
46*1959748cSgd78059 #include <sys/ethernet.h>
47*1959748cSgd78059 #include <sys/kmem.h>
48*1959748cSgd78059 #include <sys/time.h>
49*1959748cSgd78059 #include <sys/crc32.h>
50*1959748cSgd78059 #include <sys/miiregs.h>
51*1959748cSgd78059 #include <sys/mac.h>
52*1959748cSgd78059 #include <sys/mac_ether.h>
53*1959748cSgd78059 #include <sys/ddi.h>
54*1959748cSgd78059 #include <sys/sunddi.h>
55*1959748cSgd78059 
56*1959748cSgd78059 #include "afe.h"
57*1959748cSgd78059 #include "afeimpl.h"
58*1959748cSgd78059 
59*1959748cSgd78059 /*
60*1959748cSgd78059  * Driver globals.
61*1959748cSgd78059  */
62*1959748cSgd78059 
63*1959748cSgd78059 /* patchable debug flag ... must not be static! */
64*1959748cSgd78059 #ifdef	DEBUG
65*1959748cSgd78059 unsigned		afe_debug = DWARN;
66*1959748cSgd78059 #endif
67*1959748cSgd78059 
68*1959748cSgd78059 /* table of supported devices */
69*1959748cSgd78059 static afe_card_t afe_cards[] = {
70*1959748cSgd78059 
71*1959748cSgd78059 	/*
72*1959748cSgd78059 	 * ADMtek Centaur and Comet
73*1959748cSgd78059 	 */
74*1959748cSgd78059 	{ 0x1317, 0x0981, "ADMtek AL981", MODEL_COMET },
75*1959748cSgd78059 	{ 0x1317, 0x0985, "ADMtek AN983", MODEL_CENTAUR },
76*1959748cSgd78059 	{ 0x1317, 0x1985, "ADMtek AN985", MODEL_CENTAUR },
77*1959748cSgd78059 	{ 0x1317, 0x9511, "ADMtek ADM9511", MODEL_CENTAUR },
78*1959748cSgd78059 	{ 0x1317, 0x9513, "ADMtek ADM9513", MODEL_CENTAUR },
79*1959748cSgd78059 	/*
80*1959748cSgd78059 	 * Accton just relabels other companies' controllers
81*1959748cSgd78059 	 */
82*1959748cSgd78059 	{ 0x1113, 0x1216, "Accton EN5251", MODEL_CENTAUR },
83*1959748cSgd78059 	/*
84*1959748cSgd78059 	 * Models listed here.
85*1959748cSgd78059 	 */
86*1959748cSgd78059 	{ 0x10b7, 0x9300, "3Com 3CSOHO100B-TX", MODEL_CENTAUR },
87*1959748cSgd78059 	{ 0x1113, 0xec02, "SMC SMC1244TX", MODEL_CENTAUR },
88*1959748cSgd78059 	{ 0x10b8, 0x1255, "SMC SMC1255TX", MODEL_CENTAUR },
89*1959748cSgd78059 	{ 0x111a, 0x1020, "Siemens SpeedStream PCI 10/100", MODEL_CENTAUR },
90*1959748cSgd78059 	{ 0x1113, 0x1207, "Accton EN1207F", MODEL_CENTAUR },
91*1959748cSgd78059 	{ 0x1113, 0x2242, "Accton EN2242", MODEL_CENTAUR },
92*1959748cSgd78059 	{ 0x1113, 0x2220, "Accton EN2220", MODEL_CENTAUR },
93*1959748cSgd78059 	{ 0x1113, 0x9216, "3M VOL-N100VF+TX", MODEL_CENTAUR },
94*1959748cSgd78059 	{ 0x1317, 0x0574, "Linksys LNE100TX", MODEL_CENTAUR },
95*1959748cSgd78059 	{ 0x1317, 0x0570, "Linksys NC100", MODEL_CENTAUR },
96*1959748cSgd78059 	{ 0x1385, 0x511a, "Netgear FA511", MODEL_CENTAUR },
97*1959748cSgd78059 	{ 0x13d1, 0xab02, "AboCom FE2500", MODEL_CENTAUR },
98*1959748cSgd78059 	{ 0x13d1, 0xab03, "AboCom PCM200", MODEL_CENTAUR },
99*1959748cSgd78059 	{ 0x13d1, 0xab08, "AboCom FE2500MX", MODEL_CENTAUR },
100*1959748cSgd78059 	{ 0x1414, 0x0001, "Microsoft MN-120", MODEL_CENTAUR },
101*1959748cSgd78059 	{ 0x16ec, 0x00ed, "U.S. Robotics USR997900", MODEL_CENTAUR },
102*1959748cSgd78059 	{ 0x1734, 0x100c, "Fujitsu-Siemens D1961", MODEL_CENTAUR },
103*1959748cSgd78059 	{ 0x1737, 0xab08, "Linksys PCMPC200", MODEL_CENTAUR },
104*1959748cSgd78059 	{ 0x1737, 0xab09, "Linksys PCM200", MODEL_CENTAUR },
105*1959748cSgd78059 	{ 0x17b3, 0xab08, "Hawking PN672TX", MODEL_CENTAUR },
106*1959748cSgd78059 };
107*1959748cSgd78059 
108*1959748cSgd78059 #define	ETHERVLANMTU	(ETHERMAX + 4)
109*1959748cSgd78059 
110*1959748cSgd78059 /*
111*1959748cSgd78059  * Function prototypes
112*1959748cSgd78059  */
113*1959748cSgd78059 static int	afe_attach(dev_info_t *, ddi_attach_cmd_t);
114*1959748cSgd78059 static int	afe_detach(dev_info_t *, ddi_detach_cmd_t);
115*1959748cSgd78059 static int	afe_resume(dev_info_t *);
116*1959748cSgd78059 static int	afe_m_unicst(void *, const uint8_t *);
117*1959748cSgd78059 static int	afe_m_multicst(void *, boolean_t, const uint8_t *);
118*1959748cSgd78059 static int	afe_m_promisc(void *, boolean_t);
119*1959748cSgd78059 static mblk_t	*afe_m_tx(void *, mblk_t *);
120*1959748cSgd78059 static int	afe_m_stat(void *, uint_t, uint64_t *);
121*1959748cSgd78059 static int	afe_m_start(void *);
122*1959748cSgd78059 static void	afe_m_stop(void *);
123*1959748cSgd78059 static void	afe_m_ioctl(void *, queue_t *, mblk_t *);
124*1959748cSgd78059 static unsigned	afe_intr(caddr_t);
125*1959748cSgd78059 static void	afe_startmac(afe_t *);
126*1959748cSgd78059 static void	afe_stopmac(afe_t *);
127*1959748cSgd78059 static void	afe_resetrings(afe_t *);
128*1959748cSgd78059 static boolean_t	afe_initialize(afe_t *);
129*1959748cSgd78059 static void	afe_startall(afe_t *);
130*1959748cSgd78059 static void	afe_stopall(afe_t *);
131*1959748cSgd78059 static void	afe_resetall(afe_t *);
132*1959748cSgd78059 static afe_txbuf_t *afe_alloctxbuf(afe_t *);
133*1959748cSgd78059 static void	afe_destroytxbuf(afe_txbuf_t *);
134*1959748cSgd78059 static afe_rxbuf_t *afe_allocrxbuf(afe_t *);
135*1959748cSgd78059 static void	afe_destroyrxbuf(afe_rxbuf_t *);
136*1959748cSgd78059 static boolean_t	afe_send(afe_t *, mblk_t *);
137*1959748cSgd78059 static int	afe_allocrxring(afe_t *);
138*1959748cSgd78059 static void	afe_freerxring(afe_t *);
139*1959748cSgd78059 static int	afe_alloctxring(afe_t *);
140*1959748cSgd78059 static void	afe_freetxring(afe_t *);
141*1959748cSgd78059 static void	afe_error(dev_info_t *, char *, ...);
142*1959748cSgd78059 static void	afe_setrxfilt(afe_t *);
143*1959748cSgd78059 static uint8_t	afe_sromwidth(afe_t *);
144*1959748cSgd78059 static uint16_t	afe_readsromword(afe_t *, unsigned);
145*1959748cSgd78059 static void	afe_readsrom(afe_t *, unsigned, unsigned, char *);
146*1959748cSgd78059 static void	afe_getfactaddr(afe_t *, uchar_t *);
147*1959748cSgd78059 static int	afe_miireadbit(afe_t *);
148*1959748cSgd78059 static void	afe_miiwritebit(afe_t *, int);
149*1959748cSgd78059 static void	afe_miitristate(afe_t *);
150*1959748cSgd78059 static unsigned	afe_miiread(afe_t *, int, int);
151*1959748cSgd78059 static void	afe_miiwrite(afe_t *, int, int, uint16_t);
152*1959748cSgd78059 static unsigned	afe_miireadgeneral(afe_t *, int, int);
153*1959748cSgd78059 static void	afe_miiwritegeneral(afe_t *, int, int, uint16_t);
154*1959748cSgd78059 static unsigned	afe_miireadcomet(afe_t *, int, int);
155*1959748cSgd78059 static void	afe_miiwritecomet(afe_t *, int, int, uint16_t);
156*1959748cSgd78059 static int	afe_getmiibit(afe_t *, uint16_t, uint16_t);
157*1959748cSgd78059 static void	afe_startphy(afe_t *);
158*1959748cSgd78059 static void	afe_stopphy(afe_t *);
159*1959748cSgd78059 static void	afe_reportlink(afe_t *);
160*1959748cSgd78059 static void	afe_checklink(afe_t *);
161*1959748cSgd78059 static void	afe_checklinkcomet(afe_t *);
162*1959748cSgd78059 static void	afe_checklinkcentaur(afe_t *);
163*1959748cSgd78059 static void	afe_checklinkmii(afe_t *);
164*1959748cSgd78059 static void	afe_disableinterrupts(afe_t *);
165*1959748cSgd78059 static void	afe_enableinterrupts(afe_t *);
166*1959748cSgd78059 static void	afe_reclaim(afe_t *);
167*1959748cSgd78059 static mblk_t	*afe_receive(afe_t *);
168*1959748cSgd78059 static int	afe_ndaddbytes(mblk_t *, char *, int);
169*1959748cSgd78059 static int	afe_ndaddstr(mblk_t *, char *, int);
170*1959748cSgd78059 static void	afe_ndparsestring(mblk_t *, char *, int);
171*1959748cSgd78059 static int	afe_ndparselen(mblk_t *);
172*1959748cSgd78059 static int	afe_ndparseint(mblk_t *);
173*1959748cSgd78059 static void	afe_ndget(afe_t *, queue_t *, mblk_t *);
174*1959748cSgd78059 static void	afe_ndset(afe_t *, queue_t *, mblk_t *);
175*1959748cSgd78059 static void	afe_ndfini(afe_t *);
176*1959748cSgd78059 static void	afe_ndinit(afe_t *);
177*1959748cSgd78059 static int	afe_ndquestion(afe_t *, mblk_t *, afe_nd_t *);
178*1959748cSgd78059 static int	afe_ndgetint(afe_t *, mblk_t *, afe_nd_t *);
179*1959748cSgd78059 static int	afe_ndgetmiibit(afe_t *, mblk_t *, afe_nd_t *);
180*1959748cSgd78059 static int	afe_ndsetadv(afe_t *, mblk_t *, afe_nd_t *);
181*1959748cSgd78059 static afe_nd_t *afe_ndfind(afe_t *, char *);
182*1959748cSgd78059 static void	afe_ndempty(mblk_t *);
183*1959748cSgd78059 static void	afe_ndadd(afe_t *, char *, afe_nd_pf_t, afe_nd_pf_t,
184*1959748cSgd78059     intptr_t, intptr_t);
185*1959748cSgd78059 
186*1959748cSgd78059 #ifdef	DEBUG
187*1959748cSgd78059 static void	afe_dprintf(afe_t *, const char *, int, char *, ...);
188*1959748cSgd78059 #endif
189*1959748cSgd78059 
190*1959748cSgd78059 #define	KIOIP	KSTAT_INTR_PTR(afep->afe_intrstat)
191*1959748cSgd78059 
192*1959748cSgd78059 static mac_callbacks_t afe_m_callbacks = {
193*1959748cSgd78059 	MC_IOCTL,
194*1959748cSgd78059 	afe_m_stat,
195*1959748cSgd78059 	afe_m_start,
196*1959748cSgd78059 	afe_m_stop,
197*1959748cSgd78059 	afe_m_promisc,
198*1959748cSgd78059 	afe_m_multicst,
199*1959748cSgd78059 	afe_m_unicst,
200*1959748cSgd78059 	afe_m_tx,
201*1959748cSgd78059 	NULL,
202*1959748cSgd78059 	afe_m_ioctl,
203*1959748cSgd78059 	NULL,		/* m_getcapab */
204*1959748cSgd78059 };
205*1959748cSgd78059 
206*1959748cSgd78059 
207*1959748cSgd78059 /*
208*1959748cSgd78059  * Stream information
209*1959748cSgd78059  */
210*1959748cSgd78059 DDI_DEFINE_STREAM_OPS(afe_devops, nulldev, nulldev, afe_attach, afe_detach,
211*1959748cSgd78059     nodev, NULL, D_MP, NULL);
212*1959748cSgd78059 
213*1959748cSgd78059 /*
214*1959748cSgd78059  * Module linkage information.
215*1959748cSgd78059  */
216*1959748cSgd78059 
217*1959748cSgd78059 static struct modldrv afe_modldrv = {
218*1959748cSgd78059 	&mod_driverops,			/* drv_modops */
219*1959748cSgd78059 	"ADMtek Fast Ethernet",		/* drv_linkinfo */
220*1959748cSgd78059 	&afe_devops			/* drv_dev_ops */
221*1959748cSgd78059 };
222*1959748cSgd78059 
223*1959748cSgd78059 static struct modlinkage afe_modlinkage = {
224*1959748cSgd78059 	MODREV_1,		/* ml_rev */
225*1959748cSgd78059 	{ &afe_modldrv, NULL }	/* ml_linkage */
226*1959748cSgd78059 };
227*1959748cSgd78059 
228*1959748cSgd78059 /*
229*1959748cSgd78059  * Device attributes.
230*1959748cSgd78059  */
231*1959748cSgd78059 static ddi_device_acc_attr_t afe_devattr = {
232*1959748cSgd78059 	DDI_DEVICE_ATTR_V0,
233*1959748cSgd78059 	DDI_STRUCTURE_LE_ACC,
234*1959748cSgd78059 	DDI_STRICTORDER_ACC
235*1959748cSgd78059 };
236*1959748cSgd78059 
237*1959748cSgd78059 static ddi_device_acc_attr_t afe_bufattr = {
238*1959748cSgd78059 	DDI_DEVICE_ATTR_V0,
239*1959748cSgd78059 	DDI_NEVERSWAP_ACC,
240*1959748cSgd78059 	DDI_STRICTORDER_ACC
241*1959748cSgd78059 };
242*1959748cSgd78059 
243*1959748cSgd78059 static ddi_dma_attr_t afe_dma_attr = {
244*1959748cSgd78059 	DMA_ATTR_V0,		/* dma_attr_version */
245*1959748cSgd78059 	0,			/* dma_attr_addr_lo */
246*1959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
247*1959748cSgd78059 	0x7FFFFFFFU,		/* dma_attr_count_max */
248*1959748cSgd78059 	4,			/* dma_attr_align */
249*1959748cSgd78059 	0x3F,			/* dma_attr_burstsizes */
250*1959748cSgd78059 	1,			/* dma_attr_minxfer */
251*1959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
252*1959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_seg */
253*1959748cSgd78059 	1,			/* dma_attr_sgllen */
254*1959748cSgd78059 	1,			/* dma_attr_granular */
255*1959748cSgd78059 	0			/* dma_attr_flags */
256*1959748cSgd78059 };
257*1959748cSgd78059 
258*1959748cSgd78059 /*
259*1959748cSgd78059  * Tx buffers can be arbitrarily aligned.  Additionally, they can
260*1959748cSgd78059  * cross a page boundary, so we use the two buffer addresses of the
261*1959748cSgd78059  * chip to provide a two-entry scatter-gather list.
262*1959748cSgd78059  */
263*1959748cSgd78059 static ddi_dma_attr_t afe_dma_txattr = {
264*1959748cSgd78059 	DMA_ATTR_V0,		/* dma_attr_version */
265*1959748cSgd78059 	0,			/* dma_attr_addr_lo */
266*1959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
267*1959748cSgd78059 	0x7FFFFFFFU,		/* dma_attr_count_max */
268*1959748cSgd78059 	1,			/* dma_attr_align */
269*1959748cSgd78059 	0x3F,			/* dma_attr_burstsizes */
270*1959748cSgd78059 	1,			/* dma_attr_minxfer */
271*1959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
272*1959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_seg */
273*1959748cSgd78059 	2,			/* dma_attr_sgllen */
274*1959748cSgd78059 	1,			/* dma_attr_granular */
275*1959748cSgd78059 	0			/* dma_attr_flags */
276*1959748cSgd78059 };
277*1959748cSgd78059 
278*1959748cSgd78059 /*
279*1959748cSgd78059  * Ethernet addresses.
280*1959748cSgd78059  */
281*1959748cSgd78059 static uchar_t afe_broadcast[ETHERADDRL] = {
282*1959748cSgd78059 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
283*1959748cSgd78059 };
284*1959748cSgd78059 
285*1959748cSgd78059 /*
286*1959748cSgd78059  * DDI entry points.
287*1959748cSgd78059  */
288*1959748cSgd78059 int
289*1959748cSgd78059 _init(void)
290*1959748cSgd78059 {
291*1959748cSgd78059 	int	rv;
292*1959748cSgd78059 	mac_init_ops(&afe_devops, "afe");
293*1959748cSgd78059 	if ((rv = mod_install(&afe_modlinkage)) != DDI_SUCCESS) {
294*1959748cSgd78059 		mac_fini_ops(&afe_devops);
295*1959748cSgd78059 	}
296*1959748cSgd78059 	return (rv);
297*1959748cSgd78059 }
298*1959748cSgd78059 
299*1959748cSgd78059 int
300*1959748cSgd78059 _fini(void)
301*1959748cSgd78059 {
302*1959748cSgd78059 	int	rv;
303*1959748cSgd78059 	if ((rv = mod_remove(&afe_modlinkage)) == DDI_SUCCESS) {
304*1959748cSgd78059 		mac_fini_ops(&afe_devops);
305*1959748cSgd78059 	}
306*1959748cSgd78059 	return (rv);
307*1959748cSgd78059 }
308*1959748cSgd78059 
309*1959748cSgd78059 int
310*1959748cSgd78059 _info(struct modinfo *modinfop)
311*1959748cSgd78059 {
312*1959748cSgd78059 	return (mod_info(&afe_modlinkage, modinfop));
313*1959748cSgd78059 }
314*1959748cSgd78059 
315*1959748cSgd78059 int
316*1959748cSgd78059 afe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
317*1959748cSgd78059 {
318*1959748cSgd78059 	afe_t			*afep;
319*1959748cSgd78059 	mac_register_t		*macp;
320*1959748cSgd78059 	int			inst = ddi_get_instance(dip);
321*1959748cSgd78059 	ddi_acc_handle_t	pci;
322*1959748cSgd78059 	uint16_t		venid;
323*1959748cSgd78059 	uint16_t		devid;
324*1959748cSgd78059 	uint16_t		svid;
325*1959748cSgd78059 	uint16_t		ssid;
326*1959748cSgd78059 	uint16_t		cachesize;
327*1959748cSgd78059 	afe_card_t		*cardp;
328*1959748cSgd78059 	int			i;
329*1959748cSgd78059 
330*1959748cSgd78059 	switch (cmd) {
331*1959748cSgd78059 	case DDI_RESUME:
332*1959748cSgd78059 		return (afe_resume(dip));
333*1959748cSgd78059 
334*1959748cSgd78059 	case DDI_ATTACH:
335*1959748cSgd78059 		break;
336*1959748cSgd78059 
337*1959748cSgd78059 	default:
338*1959748cSgd78059 		return (DDI_FAILURE);
339*1959748cSgd78059 	}
340*1959748cSgd78059 
341*1959748cSgd78059 	/* this card is a bus master, reject any slave-only slot */
342*1959748cSgd78059 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
343*1959748cSgd78059 		afe_error(dip, "slot does not support PCI bus-master");
344*1959748cSgd78059 		return (DDI_FAILURE);
345*1959748cSgd78059 	}
346*1959748cSgd78059 	/* PCI devices shouldn't generate hilevel interrupts */
347*1959748cSgd78059 	if (ddi_intr_hilevel(dip, 0) != 0) {
348*1959748cSgd78059 		afe_error(dip, "hilevel interrupts not supported");
349*1959748cSgd78059 		return (DDI_FAILURE);
350*1959748cSgd78059 	}
351*1959748cSgd78059 	if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
352*1959748cSgd78059 		afe_error(dip, "unable to setup PCI config handle");
353*1959748cSgd78059 		return (DDI_FAILURE);
354*1959748cSgd78059 	}
355*1959748cSgd78059 
356*1959748cSgd78059 	venid = pci_config_get16(pci, PCI_VID);
357*1959748cSgd78059 	devid = pci_config_get16(pci, PCI_DID);
358*1959748cSgd78059 	svid = pci_config_get16(pci, PCI_SVID);
359*1959748cSgd78059 	ssid = pci_config_get16(pci, PCI_SSID);
360*1959748cSgd78059 
361*1959748cSgd78059 	/*
362*1959748cSgd78059 	 * Note: ADMtek boards seem to misprogram themselves with bogus
363*1959748cSgd78059 	 * timings, which do not seem to work properly on SPARC.  We
364*1959748cSgd78059 	 * reprogram them zero (but only if they appear to be broken),
365*1959748cSgd78059 	 * which seems to at least work.  Its unclear that this is a
366*1959748cSgd78059 	 * legal or wise practice to me, but it certainly works better
367*1959748cSgd78059 	 * than the original values.  (I would love to hear
368*1959748cSgd78059 	 * suggestions for better values, or a better strategy.)
369*1959748cSgd78059 	 */
370*1959748cSgd78059 	if ((pci_config_get8(pci, PCI_MINGNT) == 0xff) &&
371*1959748cSgd78059 	    (pci_config_get8(pci, PCI_MAXLAT) == 0xff)) {
372*1959748cSgd78059 		pci_config_put8(pci, PCI_MINGNT, 0);
373*1959748cSgd78059 		pci_config_put8(pci, PCI_MAXLAT, 0);
374*1959748cSgd78059 	}
375*1959748cSgd78059 
376*1959748cSgd78059 	/*
377*1959748cSgd78059 	 * the last entry in the card table matches every possible
378*1959748cSgd78059 	 * card, so the for-loop always terminates properly.
379*1959748cSgd78059 	 */
380*1959748cSgd78059 	cardp = NULL;
381*1959748cSgd78059 	for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) {
382*1959748cSgd78059 		if ((venid == afe_cards[i].card_venid) &&
383*1959748cSgd78059 		    (devid == afe_cards[i].card_devid)) {
384*1959748cSgd78059 			cardp = &afe_cards[i];
385*1959748cSgd78059 		}
386*1959748cSgd78059 		if ((svid == afe_cards[i].card_venid) &&
387*1959748cSgd78059 		    (ssid == afe_cards[i].card_devid)) {
388*1959748cSgd78059 			cardp = &afe_cards[i];
389*1959748cSgd78059 			break;
390*1959748cSgd78059 		}
391*1959748cSgd78059 	}
392*1959748cSgd78059 
393*1959748cSgd78059 	if (cardp == NULL) {
394*1959748cSgd78059 		pci_config_teardown(&pci);
395*1959748cSgd78059 		afe_error(dip, "Unable to identify PCI card");
396*1959748cSgd78059 		return (DDI_FAILURE);
397*1959748cSgd78059 	}
398*1959748cSgd78059 
399*1959748cSgd78059 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
400*1959748cSgd78059 	    cardp->card_cardname) != DDI_PROP_SUCCESS) {
401*1959748cSgd78059 		pci_config_teardown(&pci);
402*1959748cSgd78059 		afe_error(dip, "Unable to create model property");
403*1959748cSgd78059 		return (DDI_FAILURE);
404*1959748cSgd78059 	}
405*1959748cSgd78059 
406*1959748cSgd78059 	/*
407*1959748cSgd78059 	 * Grab the PCI cachesize -- we use this to program the
408*1959748cSgd78059 	 * cache-optimization bus access bits.
409*1959748cSgd78059 	 */
410*1959748cSgd78059 	cachesize = pci_config_get8(pci, PCI_CLS);
411*1959748cSgd78059 
412*1959748cSgd78059 	/* this cannot fail */
413*1959748cSgd78059 	afep = kmem_zalloc(sizeof (afe_t), KM_SLEEP);
414*1959748cSgd78059 	ddi_set_driver_private(dip, afep);
415*1959748cSgd78059 
416*1959748cSgd78059 	/* get the interrupt block cookie */
417*1959748cSgd78059 	if (ddi_get_iblock_cookie(dip, 0, &afep->afe_icookie) != DDI_SUCCESS) {
418*1959748cSgd78059 		afe_error(dip, "ddi_get_iblock_cookie failed");
419*1959748cSgd78059 		pci_config_teardown(&pci);
420*1959748cSgd78059 		kmem_free(afep, sizeof (afe_t));
421*1959748cSgd78059 		return (DDI_FAILURE);
422*1959748cSgd78059 	}
423*1959748cSgd78059 
424*1959748cSgd78059 	afep->afe_dip = dip;
425*1959748cSgd78059 	afep->afe_cardp = cardp;
426*1959748cSgd78059 	afep->afe_phyaddr = -1;
427*1959748cSgd78059 	afep->afe_cachesize = cachesize;
428*1959748cSgd78059 
429*1959748cSgd78059 	/* default properties */
430*1959748cSgd78059 	afep->afe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
431*1959748cSgd78059 	    "adv_autoneg_cap", 1);
432*1959748cSgd78059 	afep->afe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
433*1959748cSgd78059 	    "adv_100T4_cap", 1);
434*1959748cSgd78059 	afep->afe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
435*1959748cSgd78059 	    "adv_100fdx_cap", 1);
436*1959748cSgd78059 	afep->afe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
437*1959748cSgd78059 	    "adv_100hdx_cap", 1);
438*1959748cSgd78059 	afep->afe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
439*1959748cSgd78059 	    "adv_10fdx_cap", 1);
440*1959748cSgd78059 	afep->afe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
441*1959748cSgd78059 	    "adv_10hdx_cap", 1);
442*1959748cSgd78059 
443*1959748cSgd78059 	afep->afe_forcefiber = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
444*1959748cSgd78059 	    "fiber", 0);
445*1959748cSgd78059 
446*1959748cSgd78059 	DBG(DPCI, "PCI vendor id = %x", venid);
447*1959748cSgd78059 	DBG(DPCI, "PCI device id = %x", devid);
448*1959748cSgd78059 	DBG(DPCI, "PCI cachesize = %d", cachesize);
449*1959748cSgd78059 	DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD));
450*1959748cSgd78059 	DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT));
451*1959748cSgd78059 
452*1959748cSgd78059 	mutex_init(&afep->afe_xmtlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
453*1959748cSgd78059 	mutex_init(&afep->afe_intrlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
454*1959748cSgd78059 
455*1959748cSgd78059 	afe_ndinit(afep);
456*1959748cSgd78059 
457*1959748cSgd78059 	/*
458*1959748cSgd78059 	 * Enable bus master, IO space, and memory space accesses.
459*1959748cSgd78059 	 */
460*1959748cSgd78059 	pci_config_put16(pci, PCI_CMD,
461*1959748cSgd78059 	    pci_config_get16(pci, PCI_CMD) | PCI_CMD_BME | PCI_CMD_MAE);
462*1959748cSgd78059 
463*1959748cSgd78059 	/* we're done with this now, drop it */
464*1959748cSgd78059 	pci_config_teardown(&pci);
465*1959748cSgd78059 
466*1959748cSgd78059 	/*
467*1959748cSgd78059 	 * Initialize interrupt kstat.  This should not normally fail, since
468*1959748cSgd78059 	 * we don't use a persistent stat.  We do it this way to avoid having
469*1959748cSgd78059 	 * to test for it at run time on the hot path.
470*1959748cSgd78059 	 */
471*1959748cSgd78059 	afep->afe_intrstat = kstat_create("afe", inst, "intr", "controller",
472*1959748cSgd78059 	    KSTAT_TYPE_INTR, 1, 0);
473*1959748cSgd78059 	if (afep->afe_intrstat == NULL) {
474*1959748cSgd78059 		afe_error(dip, "kstat_create failed");
475*1959748cSgd78059 		goto failed;
476*1959748cSgd78059 	}
477*1959748cSgd78059 	kstat_install(afep->afe_intrstat);
478*1959748cSgd78059 
479*1959748cSgd78059 	/*
480*1959748cSgd78059 	 * Map in the device registers.
481*1959748cSgd78059 	 */
482*1959748cSgd78059 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&afep->afe_regs,
483*1959748cSgd78059 	    0, 0, &afe_devattr, &afep->afe_regshandle)) {
484*1959748cSgd78059 		afe_error(dip, "ddi_regs_map_setup failed");
485*1959748cSgd78059 		goto failed;
486*1959748cSgd78059 	}
487*1959748cSgd78059 
488*1959748cSgd78059 	/*
489*1959748cSgd78059 	 * Allocate DMA resources (descriptor rings and buffers).
490*1959748cSgd78059 	 */
491*1959748cSgd78059 	if ((afe_allocrxring(afep) != DDI_SUCCESS) ||
492*1959748cSgd78059 	    (afe_alloctxring(afep) != DDI_SUCCESS)) {
493*1959748cSgd78059 		afe_error(dip, "unable to allocate DMA resources");
494*1959748cSgd78059 		goto failed;
495*1959748cSgd78059 	}
496*1959748cSgd78059 
497*1959748cSgd78059 	/* Initialize the chip. */
498*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
499*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
500*1959748cSgd78059 	if (!afe_initialize(afep)) {
501*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
502*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
503*1959748cSgd78059 		goto failed;
504*1959748cSgd78059 	}
505*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
506*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
507*1959748cSgd78059 
508*1959748cSgd78059 	/* Determine the number of address bits to our EEPROM. */
509*1959748cSgd78059 	afep->afe_sromwidth = afe_sromwidth(afep);
510*1959748cSgd78059 
511*1959748cSgd78059 	/*
512*1959748cSgd78059 	 * Get the factory ethernet address.  This becomes the current
513*1959748cSgd78059 	 * ethernet address (it can be overridden later via ifconfig).
514*1959748cSgd78059 	 */
515*1959748cSgd78059 	afe_getfactaddr(afep, afep->afe_curraddr);
516*1959748cSgd78059 	afep->afe_promisc = B_FALSE;
517*1959748cSgd78059 
518*1959748cSgd78059 	/* make sure we add configure the initial filter */
519*1959748cSgd78059 	(void) afe_m_unicst(afep, afep->afe_curraddr);
520*1959748cSgd78059 	(void) afe_m_multicst(afep, B_TRUE, afe_broadcast);
521*1959748cSgd78059 
522*1959748cSgd78059 	/*
523*1959748cSgd78059 	 * Establish interrupt handler.
524*1959748cSgd78059 	 */
525*1959748cSgd78059 	if (ddi_add_intr(dip, 0, NULL, NULL, afe_intr, (caddr_t)afep) !=
526*1959748cSgd78059 	    DDI_SUCCESS) {
527*1959748cSgd78059 		afe_error(dip, "unable to add interrupt");
528*1959748cSgd78059 		goto failed;
529*1959748cSgd78059 	}
530*1959748cSgd78059 
531*1959748cSgd78059 	/* TODO: do the power management stuff */
532*1959748cSgd78059 
533*1959748cSgd78059 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
534*1959748cSgd78059 		afe_error(dip, "mac_alloc failed");
535*1959748cSgd78059 		goto failed;
536*1959748cSgd78059 	}
537*1959748cSgd78059 
538*1959748cSgd78059 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
539*1959748cSgd78059 	macp->m_driver = afep;
540*1959748cSgd78059 	macp->m_dip = dip;
541*1959748cSgd78059 	macp->m_src_addr = afep->afe_curraddr;
542*1959748cSgd78059 	macp->m_callbacks = &afe_m_callbacks;
543*1959748cSgd78059 	macp->m_min_sdu = 0;
544*1959748cSgd78059 	macp->m_max_sdu = ETHERMTU;
545*1959748cSgd78059 
546*1959748cSgd78059 	if (mac_register(macp, &afep->afe_mh) == DDI_SUCCESS) {
547*1959748cSgd78059 		mac_free(macp);
548*1959748cSgd78059 		return (DDI_SUCCESS);
549*1959748cSgd78059 	}
550*1959748cSgd78059 
551*1959748cSgd78059 	/* failed to register with MAC */
552*1959748cSgd78059 	mac_free(macp);
553*1959748cSgd78059 failed:
554*1959748cSgd78059 	if (afep->afe_icookie != NULL) {
555*1959748cSgd78059 		ddi_remove_intr(dip, 0, afep->afe_icookie);
556*1959748cSgd78059 	}
557*1959748cSgd78059 	if (afep->afe_intrstat) {
558*1959748cSgd78059 		kstat_delete(afep->afe_intrstat);
559*1959748cSgd78059 	}
560*1959748cSgd78059 	afe_ndfini(afep);
561*1959748cSgd78059 	mutex_destroy(&afep->afe_intrlock);
562*1959748cSgd78059 	mutex_destroy(&afep->afe_xmtlock);
563*1959748cSgd78059 
564*1959748cSgd78059 	afe_freerxring(afep);
565*1959748cSgd78059 	afe_freetxring(afep);
566*1959748cSgd78059 
567*1959748cSgd78059 	if (afep->afe_regshandle != NULL) {
568*1959748cSgd78059 		ddi_regs_map_free(&afep->afe_regshandle);
569*1959748cSgd78059 	}
570*1959748cSgd78059 	kmem_free(afep, sizeof (afe_t));
571*1959748cSgd78059 	return (DDI_FAILURE);
572*1959748cSgd78059 }
573*1959748cSgd78059 
574*1959748cSgd78059 int
575*1959748cSgd78059 afe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
576*1959748cSgd78059 {
577*1959748cSgd78059 	afe_t		*afep;
578*1959748cSgd78059 
579*1959748cSgd78059 	afep = ddi_get_driver_private(dip);
580*1959748cSgd78059 	if (afep == NULL) {
581*1959748cSgd78059 		afe_error(dip, "no soft state in detach!");
582*1959748cSgd78059 		return (DDI_FAILURE);
583*1959748cSgd78059 	}
584*1959748cSgd78059 
585*1959748cSgd78059 	switch (cmd) {
586*1959748cSgd78059 	case DDI_DETACH:
587*1959748cSgd78059 
588*1959748cSgd78059 		if (mac_unregister(afep->afe_mh) != 0) {
589*1959748cSgd78059 			return (DDI_FAILURE);
590*1959748cSgd78059 		}
591*1959748cSgd78059 
592*1959748cSgd78059 		/* make sure hardware is quiesced */
593*1959748cSgd78059 		mutex_enter(&afep->afe_intrlock);
594*1959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
595*1959748cSgd78059 		afep->afe_flags &= ~AFE_RUNNING;
596*1959748cSgd78059 		afe_stopall(afep);
597*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
598*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
599*1959748cSgd78059 
600*1959748cSgd78059 		/* clean up and shut down device */
601*1959748cSgd78059 		ddi_remove_intr(dip, 0, afep->afe_icookie);
602*1959748cSgd78059 
603*1959748cSgd78059 		/* clean up kstats */
604*1959748cSgd78059 		kstat_delete(afep->afe_intrstat);
605*1959748cSgd78059 
606*1959748cSgd78059 		ddi_prop_remove_all(dip);
607*1959748cSgd78059 
608*1959748cSgd78059 		/* free up any left over buffers or DMA resources */
609*1959748cSgd78059 		afe_freerxring(afep);
610*1959748cSgd78059 		afe_freetxring(afep);
611*1959748cSgd78059 
612*1959748cSgd78059 		afe_ndfini(afep);
613*1959748cSgd78059 		ddi_regs_map_free(&afep->afe_regshandle);
614*1959748cSgd78059 		mutex_destroy(&afep->afe_intrlock);
615*1959748cSgd78059 		mutex_destroy(&afep->afe_xmtlock);
616*1959748cSgd78059 
617*1959748cSgd78059 		kmem_free(afep, sizeof (afe_t));
618*1959748cSgd78059 		return (DDI_SUCCESS);
619*1959748cSgd78059 
620*1959748cSgd78059 	case DDI_SUSPEND:
621*1959748cSgd78059 		/* quiesce the hardware */
622*1959748cSgd78059 		mutex_enter(&afep->afe_intrlock);
623*1959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
624*1959748cSgd78059 		afep->afe_flags |= AFE_SUSPENDED;
625*1959748cSgd78059 		afe_stopall(afep);
626*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
627*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
628*1959748cSgd78059 		return (DDI_SUCCESS);
629*1959748cSgd78059 	default:
630*1959748cSgd78059 		return (DDI_FAILURE);
631*1959748cSgd78059 	}
632*1959748cSgd78059 }
633*1959748cSgd78059 
634*1959748cSgd78059 int
635*1959748cSgd78059 afe_resume(dev_info_t *dip)
636*1959748cSgd78059 {
637*1959748cSgd78059 	afe_t	*afep;
638*1959748cSgd78059 
639*1959748cSgd78059 	if ((afep = ddi_get_driver_private(dip)) == NULL) {
640*1959748cSgd78059 		return (DDI_FAILURE);
641*1959748cSgd78059 	}
642*1959748cSgd78059 
643*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
644*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
645*1959748cSgd78059 
646*1959748cSgd78059 	afep->afe_flags &= ~AFE_SUSPENDED;
647*1959748cSgd78059 
648*1959748cSgd78059 	/* re-initialize chip */
649*1959748cSgd78059 	if (!afe_initialize(afep)) {
650*1959748cSgd78059 		afe_error(afep->afe_dip, "unable to resume chip!");
651*1959748cSgd78059 		afep->afe_flags |= AFE_SUSPENDED;
652*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
653*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
654*1959748cSgd78059 		return (DDI_SUCCESS);
655*1959748cSgd78059 	}
656*1959748cSgd78059 
657*1959748cSgd78059 	/* start the chip */
658*1959748cSgd78059 	if (afep->afe_flags & AFE_RUNNING) {
659*1959748cSgd78059 		afe_startall(afep);
660*1959748cSgd78059 	}
661*1959748cSgd78059 
662*1959748cSgd78059 	/* drop locks */
663*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
664*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
665*1959748cSgd78059 
666*1959748cSgd78059 	return (DDI_SUCCESS);
667*1959748cSgd78059 }
668*1959748cSgd78059 
669*1959748cSgd78059 void
670*1959748cSgd78059 afe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
671*1959748cSgd78059 {
672*1959748cSgd78059 	afe_t *afep = arg;
673*1959748cSgd78059 
674*1959748cSgd78059 	switch (*(int *)(void *)(mp->b_rptr)) {
675*1959748cSgd78059 
676*1959748cSgd78059 	case NDIOC_GET:
677*1959748cSgd78059 		afe_ndget(afep, wq, mp);
678*1959748cSgd78059 		break;
679*1959748cSgd78059 
680*1959748cSgd78059 	case NDIOC_SET:
681*1959748cSgd78059 		afe_ndset(afep, wq, mp);
682*1959748cSgd78059 		break;
683*1959748cSgd78059 
684*1959748cSgd78059 	default:
685*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
686*1959748cSgd78059 		break;
687*1959748cSgd78059 	}
688*1959748cSgd78059 }
689*1959748cSgd78059 
690*1959748cSgd78059 void
691*1959748cSgd78059 afe_setrxfilt(afe_t *afep)
692*1959748cSgd78059 {
693*1959748cSgd78059 	unsigned rxen, pa0, pa1;
694*1959748cSgd78059 
695*1959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
696*1959748cSgd78059 		/* don't touch a suspended interface */
697*1959748cSgd78059 		return;
698*1959748cSgd78059 	}
699*1959748cSgd78059 
700*1959748cSgd78059 	rxen = GETCSR(afep, CSR_NAR) & NAR_RX_ENABLE;
701*1959748cSgd78059 
702*1959748cSgd78059 	/* stop receiver */
703*1959748cSgd78059 	if (rxen) {
704*1959748cSgd78059 		afe_stopmac(afep);
705*1959748cSgd78059 	}
706*1959748cSgd78059 
707*1959748cSgd78059 	/* program promiscuous mode */
708*1959748cSgd78059 	if (afep->afe_promisc)
709*1959748cSgd78059 		SETBIT(afep, CSR_NAR, NAR_RX_PROMISC);
710*1959748cSgd78059 	else
711*1959748cSgd78059 		CLRBIT(afep, CSR_NAR, NAR_RX_PROMISC);
712*1959748cSgd78059 
713*1959748cSgd78059 	/* program mac address */
714*1959748cSgd78059 	pa0 = (afep->afe_curraddr[3] << 24) | (afep->afe_curraddr[2] << 16) |
715*1959748cSgd78059 	    (afep->afe_curraddr[1] << 8) | afep->afe_curraddr[0];
716*1959748cSgd78059 	pa1 = (afep->afe_curraddr[5] << 8) | afep->afe_curraddr[4];
717*1959748cSgd78059 
718*1959748cSgd78059 	DBG(DMACID, "programming PAR0 with %x", pa0);
719*1959748cSgd78059 	DBG(DMACID, "programming PAR1 with %x", pa1);
720*1959748cSgd78059 	PUTCSR(afep, CSR_PAR0, pa0);
721*1959748cSgd78059 	PUTCSR(afep, CSR_PAR1, pa1);
722*1959748cSgd78059 	if (rxen) {
723*1959748cSgd78059 		SETBIT(afep, CSR_NAR, rxen);
724*1959748cSgd78059 	}
725*1959748cSgd78059 
726*1959748cSgd78059 	DBG(DMACID, "programming MAR0 = %x", afep->afe_mctab[0]);
727*1959748cSgd78059 	DBG(DMACID, "programming MAR1 = %x", afep->afe_mctab[1]);
728*1959748cSgd78059 
729*1959748cSgd78059 	/* program multicast filter */
730*1959748cSgd78059 	if (AFE_MODEL(afep) == MODEL_COMET) {
731*1959748cSgd78059 		if (afep->afe_mctab[0] || afep->afe_mctab[1]) {
732*1959748cSgd78059 			SETBIT(afep, CSR_NAR, NAR_RX_MULTI);
733*1959748cSgd78059 		} else {
734*1959748cSgd78059 			CLRBIT(afep, CSR_NAR, NAR_RX_MULTI);
735*1959748cSgd78059 		}
736*1959748cSgd78059 	} else {
737*1959748cSgd78059 		CLRBIT(afep, CSR_NAR, NAR_RX_MULTI);
738*1959748cSgd78059 		PUTCSR(afep, CSR_MAR0, afep->afe_mctab[0]);
739*1959748cSgd78059 		PUTCSR(afep, CSR_MAR1, afep->afe_mctab[1]);
740*1959748cSgd78059 	}
741*1959748cSgd78059 
742*1959748cSgd78059 	/* restart receiver */
743*1959748cSgd78059 	if (rxen) {
744*1959748cSgd78059 		afe_startmac(afep);
745*1959748cSgd78059 	}
746*1959748cSgd78059 }
747*1959748cSgd78059 
748*1959748cSgd78059 int
749*1959748cSgd78059 afe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
750*1959748cSgd78059 {
751*1959748cSgd78059 	afe_t		*afep = arg;
752*1959748cSgd78059 	int		index;
753*1959748cSgd78059 	uint32_t	crc;
754*1959748cSgd78059 	uint32_t	bit;
755*1959748cSgd78059 	uint32_t	newval, oldval;
756*1959748cSgd78059 
757*1959748cSgd78059 	CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table);
758*1959748cSgd78059 	crc %= AFE_MCHASH;
759*1959748cSgd78059 
760*1959748cSgd78059 	/* bit within a 32-bit word */
761*1959748cSgd78059 	index = crc / 32;
762*1959748cSgd78059 	bit = (1 << (crc % 32));
763*1959748cSgd78059 
764*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
765*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
766*1959748cSgd78059 	newval = oldval = afep->afe_mctab[index];
767*1959748cSgd78059 
768*1959748cSgd78059 	if (add) {
769*1959748cSgd78059 		afep->afe_mccount[crc]++;
770*1959748cSgd78059 		if (afep->afe_mccount[crc] == 1)
771*1959748cSgd78059 			newval |= bit;
772*1959748cSgd78059 	} else {
773*1959748cSgd78059 		afep->afe_mccount[crc]--;
774*1959748cSgd78059 		if (afep->afe_mccount[crc] == 0)
775*1959748cSgd78059 			newval &= ~bit;
776*1959748cSgd78059 	}
777*1959748cSgd78059 	if (newval != oldval) {
778*1959748cSgd78059 		afep->afe_mctab[index] = newval;
779*1959748cSgd78059 		afe_setrxfilt(afep);
780*1959748cSgd78059 	}
781*1959748cSgd78059 
782*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
783*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
784*1959748cSgd78059 
785*1959748cSgd78059 	return (0);
786*1959748cSgd78059 }
787*1959748cSgd78059 
788*1959748cSgd78059 int
789*1959748cSgd78059 afe_m_promisc(void *arg, boolean_t on)
790*1959748cSgd78059 {
791*1959748cSgd78059 	afe_t		*afep = arg;
792*1959748cSgd78059 
793*1959748cSgd78059 	/* exclusive access to the card while we reprogram it */
794*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
795*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
796*1959748cSgd78059 	/* save current promiscuous mode state for replay in resume */
797*1959748cSgd78059 	afep->afe_promisc = on;
798*1959748cSgd78059 
799*1959748cSgd78059 	afe_setrxfilt(afep);
800*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
801*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
802*1959748cSgd78059 
803*1959748cSgd78059 	return (0);
804*1959748cSgd78059 }
805*1959748cSgd78059 
806*1959748cSgd78059 int
807*1959748cSgd78059 afe_m_unicst(void *arg, const uint8_t *macaddr)
808*1959748cSgd78059 {
809*1959748cSgd78059 	afe_t		*afep = arg;
810*1959748cSgd78059 
811*1959748cSgd78059 	/* exclusive access to the card while we reprogram it */
812*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
813*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
814*1959748cSgd78059 
815*1959748cSgd78059 	bcopy(macaddr, afep->afe_curraddr, ETHERADDRL);
816*1959748cSgd78059 	afe_setrxfilt(afep);
817*1959748cSgd78059 
818*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
819*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
820*1959748cSgd78059 
821*1959748cSgd78059 	return (0);
822*1959748cSgd78059 }
823*1959748cSgd78059 
824*1959748cSgd78059 mblk_t *
825*1959748cSgd78059 afe_m_tx(void *arg, mblk_t *mp)
826*1959748cSgd78059 {
827*1959748cSgd78059 	afe_t	*afep = arg;
828*1959748cSgd78059 	mblk_t	*nmp;
829*1959748cSgd78059 
830*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
831*1959748cSgd78059 
832*1959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
833*1959748cSgd78059 		while ((nmp = mp) != NULL) {
834*1959748cSgd78059 			afep->afe_carrier_errors++;
835*1959748cSgd78059 			mp = mp->b_next;
836*1959748cSgd78059 			freemsg(nmp);
837*1959748cSgd78059 		}
838*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
839*1959748cSgd78059 		return (NULL);
840*1959748cSgd78059 	}
841*1959748cSgd78059 
842*1959748cSgd78059 	while (mp != NULL) {
843*1959748cSgd78059 		nmp = mp->b_next;
844*1959748cSgd78059 		mp->b_next = NULL;
845*1959748cSgd78059 
846*1959748cSgd78059 		if (!afe_send(afep, mp)) {
847*1959748cSgd78059 			mp->b_next = nmp;
848*1959748cSgd78059 			break;
849*1959748cSgd78059 		}
850*1959748cSgd78059 		mp = nmp;
851*1959748cSgd78059 	}
852*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
853*1959748cSgd78059 
854*1959748cSgd78059 	return (mp);
855*1959748cSgd78059 }
856*1959748cSgd78059 
857*1959748cSgd78059 /*
858*1959748cSgd78059  * Hardware management.
859*1959748cSgd78059  */
860*1959748cSgd78059 static boolean_t
861*1959748cSgd78059 afe_initialize(afe_t *afep)
862*1959748cSgd78059 {
863*1959748cSgd78059 	int		i;
864*1959748cSgd78059 	unsigned	val;
865*1959748cSgd78059 	uint32_t	par, nar;
866*1959748cSgd78059 
867*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
868*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
869*1959748cSgd78059 
870*1959748cSgd78059 	DBG(DCHATTY, "resetting!");
871*1959748cSgd78059 	SETBIT(afep, CSR_PAR, PAR_RESET);
872*1959748cSgd78059 	for (i = 1; i < 10; i++) {
873*1959748cSgd78059 		drv_usecwait(5);
874*1959748cSgd78059 		val = GETCSR(afep, CSR_PAR);
875*1959748cSgd78059 		if (!(val & PAR_RESET)) {
876*1959748cSgd78059 			break;
877*1959748cSgd78059 		}
878*1959748cSgd78059 	}
879*1959748cSgd78059 	if (i == 10) {
880*1959748cSgd78059 		afe_error(afep->afe_dip, "timed out waiting for reset!");
881*1959748cSgd78059 		return (B_FALSE);
882*1959748cSgd78059 	}
883*1959748cSgd78059 
884*1959748cSgd78059 	/*
885*1959748cSgd78059 	 * Updated Centaur data sheets show that the Comet and Centaur are
886*1959748cSgd78059 	 * alike here (contrary to earlier versions of the data sheet).
887*1959748cSgd78059 	 */
888*1959748cSgd78059 	/* XXX:? chip problems */
889*1959748cSgd78059 	/* par = PAR_MRLE | PAR_MRME | PAR_MWIE; */
890*1959748cSgd78059 	par = 0;
891*1959748cSgd78059 	switch (afep->afe_cachesize) {
892*1959748cSgd78059 	case 8:
893*1959748cSgd78059 		par |= PAR_CALIGN_8 | PAR_BURST_8;
894*1959748cSgd78059 		break;
895*1959748cSgd78059 	case 16:
896*1959748cSgd78059 		par |= PAR_CALIGN_16 | PAR_BURST_16;
897*1959748cSgd78059 		break;
898*1959748cSgd78059 	case 32:
899*1959748cSgd78059 		par |= PAR_CALIGN_32 | PAR_BURST_32;
900*1959748cSgd78059 		break;
901*1959748cSgd78059 	default:
902*1959748cSgd78059 		par |= PAR_BURST_32;
903*1959748cSgd78059 		par &= ~(PAR_MWIE | PAR_MRLE | PAR_MRME);
904*1959748cSgd78059 		break;
905*1959748cSgd78059 
906*1959748cSgd78059 	}
907*1959748cSgd78059 
908*1959748cSgd78059 	PUTCSR(afep, CSR_PAR, par);
909*1959748cSgd78059 
910*1959748cSgd78059 	/* enable transmit underrun auto-recovery */
911*1959748cSgd78059 	SETBIT(afep, CSR_CR, CR_TXURAUTOR);
912*1959748cSgd78059 
913*1959748cSgd78059 	afe_resetrings(afep);
914*1959748cSgd78059 
915*1959748cSgd78059 	/* clear the lost packet counter (cleared on read) */
916*1959748cSgd78059 	(void) GETCSR(afep, CSR_LPC);
917*1959748cSgd78059 
918*1959748cSgd78059 	nar = GETCSR(afep, CSR_NAR);
919*1959748cSgd78059 	nar &= ~NAR_TR;		/* clear tx threshold */
920*1959748cSgd78059 	nar |= NAR_SF;		/* store-and-forward */
921*1959748cSgd78059 	nar |= NAR_HBD;		/* disable SQE test */
922*1959748cSgd78059 	PUTCSR(afep, CSR_NAR, nar);
923*1959748cSgd78059 
924*1959748cSgd78059 	afe_setrxfilt(afep);
925*1959748cSgd78059 
926*1959748cSgd78059 	return (B_TRUE);
927*1959748cSgd78059 }
928*1959748cSgd78059 
929*1959748cSgd78059 /*
930*1959748cSgd78059  * Serial EEPROM access - inspired by the FreeBSD implementation.
931*1959748cSgd78059  */
932*1959748cSgd78059 
933*1959748cSgd78059 uint8_t
934*1959748cSgd78059 afe_sromwidth(afe_t *afep)
935*1959748cSgd78059 {
936*1959748cSgd78059 	int		i;
937*1959748cSgd78059 	uint32_t	eeread;
938*1959748cSgd78059 	uint8_t		addrlen = 8;
939*1959748cSgd78059 
940*1959748cSgd78059 	eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
941*1959748cSgd78059 
942*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
943*1959748cSgd78059 	drv_usecwait(1);
944*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
945*1959748cSgd78059 
946*1959748cSgd78059 	/* command bits first */
947*1959748cSgd78059 	for (i = 4; i != 0; i >>= 1) {
948*1959748cSgd78059 		unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0;
949*1959748cSgd78059 
950*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val);
951*1959748cSgd78059 		drv_usecwait(1);
952*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
953*1959748cSgd78059 		drv_usecwait(1);
954*1959748cSgd78059 	}
955*1959748cSgd78059 
956*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
957*1959748cSgd78059 
958*1959748cSgd78059 	for (addrlen = 1; addrlen <= 12; addrlen++) {
959*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK);
960*1959748cSgd78059 		drv_usecwait(1);
961*1959748cSgd78059 		if (!(GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT)) {
962*1959748cSgd78059 			PUTCSR(afep, CSR_SPR, eeread);
963*1959748cSgd78059 			drv_usecwait(1);
964*1959748cSgd78059 			break;
965*1959748cSgd78059 		}
966*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread);
967*1959748cSgd78059 		drv_usecwait(1);
968*1959748cSgd78059 	}
969*1959748cSgd78059 
970*1959748cSgd78059 	/* turn off accesses to the EEPROM */
971*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
972*1959748cSgd78059 
973*1959748cSgd78059 	DBG(DSROM, "detected srom width = %d bits", addrlen);
974*1959748cSgd78059 
975*1959748cSgd78059 	return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen);
976*1959748cSgd78059 }
977*1959748cSgd78059 
978*1959748cSgd78059 /*
979*1959748cSgd78059  * The words in EEPROM are stored in little endian order.  We
980*1959748cSgd78059  * shift bits out in big endian order, though.  This requires
981*1959748cSgd78059  * a byte swap on some platforms.
982*1959748cSgd78059  */
983*1959748cSgd78059 uint16_t
984*1959748cSgd78059 afe_readsromword(afe_t *afep, unsigned romaddr)
985*1959748cSgd78059 {
986*1959748cSgd78059 	int		i;
987*1959748cSgd78059 	uint16_t	word = 0;
988*1959748cSgd78059 	uint16_t	retval;
989*1959748cSgd78059 	int		eeread;
990*1959748cSgd78059 	uint8_t		addrlen;
991*1959748cSgd78059 	int		readcmd;
992*1959748cSgd78059 	uchar_t		*ptr;
993*1959748cSgd78059 
994*1959748cSgd78059 	eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
995*1959748cSgd78059 	addrlen = afep->afe_sromwidth;
996*1959748cSgd78059 	readcmd = (SROM_READCMD << addrlen) | romaddr;
997*1959748cSgd78059 
998*1959748cSgd78059 	if (romaddr >= (1 << addrlen)) {
999*1959748cSgd78059 		/* too big to fit! */
1000*1959748cSgd78059 		return (0);
1001*1959748cSgd78059 	}
1002*1959748cSgd78059 
1003*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
1004*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
1005*1959748cSgd78059 
1006*1959748cSgd78059 	/* command and address bits */
1007*1959748cSgd78059 	for (i = 4 + addrlen; i >= 0; i--) {
1008*1959748cSgd78059 		short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0;
1009*1959748cSgd78059 
1010*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val);
1011*1959748cSgd78059 		drv_usecwait(1);
1012*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
1013*1959748cSgd78059 		drv_usecwait(1);
1014*1959748cSgd78059 	}
1015*1959748cSgd78059 
1016*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
1017*1959748cSgd78059 
1018*1959748cSgd78059 	for (i = 0; i < 16; i++) {
1019*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK);
1020*1959748cSgd78059 		drv_usecwait(1);
1021*1959748cSgd78059 		word <<= 1;
1022*1959748cSgd78059 		if (GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT) {
1023*1959748cSgd78059 			word |= 1;
1024*1959748cSgd78059 		}
1025*1959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread);
1026*1959748cSgd78059 		drv_usecwait(1);
1027*1959748cSgd78059 	}
1028*1959748cSgd78059 
1029*1959748cSgd78059 	/* turn off accesses to the EEPROM */
1030*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
1031*1959748cSgd78059 
1032*1959748cSgd78059 	/*
1033*1959748cSgd78059 	 * Fix up the endianness thing.  Note that the values
1034*1959748cSgd78059 	 * are stored in little endian format on the SROM.
1035*1959748cSgd78059 	 */
1036*1959748cSgd78059 	ptr = (uchar_t *)&word;
1037*1959748cSgd78059 	retval = (ptr[1] << 8) | ptr[0];
1038*1959748cSgd78059 	return (retval);
1039*1959748cSgd78059 }
1040*1959748cSgd78059 
1041*1959748cSgd78059 void
1042*1959748cSgd78059 afe_readsrom(afe_t *afep, unsigned romaddr, unsigned len, char *dest)
1043*1959748cSgd78059 {
1044*1959748cSgd78059 	int	i;
1045*1959748cSgd78059 	uint16_t	word;
1046*1959748cSgd78059 	uint16_t	*ptr = (uint16_t *)((void *)dest);
1047*1959748cSgd78059 	for (i = 0; i < len; i++) {
1048*1959748cSgd78059 		word = afe_readsromword(afep, romaddr + i);
1049*1959748cSgd78059 		*ptr = word;
1050*1959748cSgd78059 		ptr++;
1051*1959748cSgd78059 	}
1052*1959748cSgd78059 }
1053*1959748cSgd78059 
1054*1959748cSgd78059 void
1055*1959748cSgd78059 afe_getfactaddr(afe_t *afep, uchar_t *eaddr)
1056*1959748cSgd78059 {
1057*1959748cSgd78059 	afe_readsrom(afep, SROM_ENADDR, ETHERADDRL / 2, (char *)eaddr);
1058*1959748cSgd78059 
1059*1959748cSgd78059 	DBG(DMACID,
1060*1959748cSgd78059 	    "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x",
1061*1959748cSgd78059 	    eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
1062*1959748cSgd78059 }
1063*1959748cSgd78059 
1064*1959748cSgd78059 /*
1065*1959748cSgd78059  * MII management.
1066*1959748cSgd78059  */
1067*1959748cSgd78059 void
1068*1959748cSgd78059 afe_startphy(afe_t *afep)
1069*1959748cSgd78059 {
1070*1959748cSgd78059 	unsigned	phyaddr;
1071*1959748cSgd78059 	unsigned	bmcr;
1072*1959748cSgd78059 	unsigned	bmsr;
1073*1959748cSgd78059 	unsigned	anar;
1074*1959748cSgd78059 	unsigned	phyidr1;
1075*1959748cSgd78059 	unsigned	phyidr2;
1076*1959748cSgd78059 	unsigned	nosqe = 0;
1077*1959748cSgd78059 	int		retries;
1078*1959748cSgd78059 	int		force;
1079*1959748cSgd78059 	int		fiber;
1080*1959748cSgd78059 	int		cnt;
1081*1959748cSgd78059 
1082*1959748cSgd78059 	/* ADMtek devices just use the PHY at address 1 */
1083*1959748cSgd78059 	afep->afe_phyaddr = phyaddr = 1;
1084*1959748cSgd78059 
1085*1959748cSgd78059 	phyidr1 = afe_miiread(afep, phyaddr, MII_PHYIDH);
1086*1959748cSgd78059 	phyidr2 = afe_miiread(afep, phyaddr, MII_PHYIDL);
1087*1959748cSgd78059 	if ((phyidr1 == 0x0022) &&
1088*1959748cSgd78059 	    ((phyidr2 & 0xfff0) ==  0x5410)) {
1089*1959748cSgd78059 		nosqe = 1;
1090*1959748cSgd78059 		/* only 983B has fiber support */
1091*1959748cSgd78059 		afep->afe_flags |= AFE_HASFIBER;
1092*1959748cSgd78059 	}
1093*1959748cSgd78059 	afep->afe_phyid = (phyidr1 << 16) | phyidr2;
1094*1959748cSgd78059 
1095*1959748cSgd78059 	DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2);
1096*1959748cSgd78059 	DBG(DPHY, "bmsr = %x", afe_miiread(afep,
1097*1959748cSgd78059 	    afep->afe_phyaddr, MII_STATUS));
1098*1959748cSgd78059 	DBG(DPHY, "anar = %x", afe_miiread(afep,
1099*1959748cSgd78059 	    afep->afe_phyaddr, MII_AN_ADVERT));
1100*1959748cSgd78059 	DBG(DPHY, "anlpar = %x", afe_miiread(afep,
1101*1959748cSgd78059 	    afep->afe_phyaddr, MII_AN_LPABLE));
1102*1959748cSgd78059 	DBG(DPHY, "aner = %x", afe_miiread(afep,
1103*1959748cSgd78059 	    afep->afe_phyaddr, MII_AN_EXPANSION));
1104*1959748cSgd78059 
1105*1959748cSgd78059 	DBG(DPHY, "resetting phy");
1106*1959748cSgd78059 
1107*1959748cSgd78059 	/* we reset the phy block */
1108*1959748cSgd78059 	afe_miiwrite(afep, phyaddr, MII_CONTROL, MII_CONTROL_RESET);
1109*1959748cSgd78059 	/*
1110*1959748cSgd78059 	 * wait for it to complete -- 500usec is still to short to
1111*1959748cSgd78059 	 * bother getting the system clock involved.
1112*1959748cSgd78059 	 */
1113*1959748cSgd78059 	drv_usecwait(500);
1114*1959748cSgd78059 	for (retries = 0; retries < 10; retries++) {
1115*1959748cSgd78059 		if (afe_miiread(afep, phyaddr, MII_CONTROL) &
1116*1959748cSgd78059 		    MII_CONTROL_RESET) {
1117*1959748cSgd78059 			drv_usecwait(500);
1118*1959748cSgd78059 			continue;
1119*1959748cSgd78059 		}
1120*1959748cSgd78059 		break;
1121*1959748cSgd78059 	}
1122*1959748cSgd78059 	if (retries == 100) {
1123*1959748cSgd78059 		afe_error(afep->afe_dip, "timeout waiting on phy to reset");
1124*1959748cSgd78059 		return;
1125*1959748cSgd78059 	}
1126*1959748cSgd78059 
1127*1959748cSgd78059 	DBG(DPHY, "phy reset complete");
1128*1959748cSgd78059 
1129*1959748cSgd78059 	bmsr = afe_miiread(afep, phyaddr, MII_STATUS);
1130*1959748cSgd78059 	anar = afe_miiread(afep, phyaddr, MII_AN_ADVERT);
1131*1959748cSgd78059 
1132*1959748cSgd78059 	anar &= ~(MII_ABILITY_100BASE_T4 |
1133*1959748cSgd78059 	    MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
1134*1959748cSgd78059 	    MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
1135*1959748cSgd78059 
1136*1959748cSgd78059 	force = 0;
1137*1959748cSgd78059 	fiber = 0;
1138*1959748cSgd78059 
1139*1959748cSgd78059 	/* if fiber is being forced, and device supports fiber... */
1140*1959748cSgd78059 	if (afep->afe_flags & AFE_HASFIBER) {
1141*1959748cSgd78059 
1142*1959748cSgd78059 		uint16_t	mcr;
1143*1959748cSgd78059 
1144*1959748cSgd78059 		DBG(DPHY, "device supports 100BaseFX");
1145*1959748cSgd78059 		mcr = afe_miiread(afep, phyaddr, PHY_MCR);
1146*1959748cSgd78059 		switch (afep->afe_forcefiber) {
1147*1959748cSgd78059 		case 0:
1148*1959748cSgd78059 			/* UTP Port */
1149*1959748cSgd78059 			DBG(DPHY, "forcing twpair");
1150*1959748cSgd78059 			mcr &= ~MCR_FIBER;
1151*1959748cSgd78059 			fiber = 0;
1152*1959748cSgd78059 			break;
1153*1959748cSgd78059 		case 1:
1154*1959748cSgd78059 			/* Fiber Port */
1155*1959748cSgd78059 			force = 1;
1156*1959748cSgd78059 			DBG(DPHY, "forcing 100BaseFX");
1157*1959748cSgd78059 			mcr |= MCR_FIBER;
1158*1959748cSgd78059 			bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
1159*1959748cSgd78059 			fiber = 1;
1160*1959748cSgd78059 			break;
1161*1959748cSgd78059 		default:
1162*1959748cSgd78059 			DBG(DPHY, "checking for 100BaseFX link");
1163*1959748cSgd78059 			/* fiber is 100 Mb FDX */
1164*1959748cSgd78059 			afe_miiwrite(afep, phyaddr, MII_CONTROL,
1165*1959748cSgd78059 			    MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
1166*1959748cSgd78059 			drv_usecwait(50);
1167*1959748cSgd78059 
1168*1959748cSgd78059 			mcr = afe_miiread(afep, phyaddr, PHY_MCR);
1169*1959748cSgd78059 			mcr |= MCR_FIBER;
1170*1959748cSgd78059 			afe_miiwrite(afep, phyaddr, PHY_MCR, mcr);
1171*1959748cSgd78059 			drv_usecwait(500);
1172*1959748cSgd78059 
1173*1959748cSgd78059 			/* if fiber is active, use it */
1174*1959748cSgd78059 			if ((afe_miiread(afep, phyaddr, MII_STATUS) &
1175*1959748cSgd78059 			    MII_STATUS_LINKUP)) {
1176*1959748cSgd78059 				bmcr = MII_CONTROL_100MB | MII_CONTROL_FDUPLEX;
1177*1959748cSgd78059 				fiber = 1;
1178*1959748cSgd78059 			} else {
1179*1959748cSgd78059 				mcr &= ~MCR_FIBER;
1180*1959748cSgd78059 				fiber = 0;
1181*1959748cSgd78059 			}
1182*1959748cSgd78059 			break;
1183*1959748cSgd78059 		}
1184*1959748cSgd78059 		afe_miiwrite(afep, phyaddr, PHY_MCR, mcr);
1185*1959748cSgd78059 		drv_usecwait(500);
1186*1959748cSgd78059 	}
1187*1959748cSgd78059 
1188*1959748cSgd78059 	if (fiber) {
1189*1959748cSgd78059 		/* fiber only supports 100FDX(?) */
1190*1959748cSgd78059 		bmsr &= ~(MII_STATUS_100_BASE_T4 |
1191*1959748cSgd78059 		    MII_STATUS_100_BASEX | MII_STATUS_10_FD | MII_STATUS_10);
1192*1959748cSgd78059 		bmsr |= MII_STATUS_100_BASEX_FD;
1193*1959748cSgd78059 	}
1194*1959748cSgd78059 
1195*1959748cSgd78059 	/* disable modes not supported in hardware */
1196*1959748cSgd78059 	if (!(bmsr & MII_STATUS_100_BASEX_FD)) {
1197*1959748cSgd78059 		afep->afe_adv_100fdx = 0;
1198*1959748cSgd78059 	}
1199*1959748cSgd78059 	if (!(bmsr & MII_STATUS_100_BASE_T4)) {
1200*1959748cSgd78059 		afep->afe_adv_100T4 = 0;
1201*1959748cSgd78059 	}
1202*1959748cSgd78059 	if (!(bmsr & MII_STATUS_100_BASEX)) {
1203*1959748cSgd78059 		afep->afe_adv_100hdx = 0;
1204*1959748cSgd78059 	}
1205*1959748cSgd78059 	if (!(bmsr & MII_STATUS_10_FD)) {
1206*1959748cSgd78059 		afep->afe_adv_10fdx = 0;
1207*1959748cSgd78059 	}
1208*1959748cSgd78059 	if (!(bmsr & MII_STATUS_10)) {
1209*1959748cSgd78059 		afep->afe_adv_10hdx = 0;
1210*1959748cSgd78059 	}
1211*1959748cSgd78059 	if (!(bmsr & MII_STATUS_CANAUTONEG)) {
1212*1959748cSgd78059 		afep->afe_adv_aneg = 0;
1213*1959748cSgd78059 		force = 1;
1214*1959748cSgd78059 	}
1215*1959748cSgd78059 
1216*1959748cSgd78059 	cnt = 0;
1217*1959748cSgd78059 	if (afep->afe_adv_100fdx) {
1218*1959748cSgd78059 		anar |= MII_ABILITY_100BASE_TX_FD;
1219*1959748cSgd78059 		cnt++;
1220*1959748cSgd78059 	}
1221*1959748cSgd78059 	if (afep->afe_adv_100T4) {
1222*1959748cSgd78059 		anar |= MII_ABILITY_100BASE_T4;
1223*1959748cSgd78059 		cnt++;
1224*1959748cSgd78059 	}
1225*1959748cSgd78059 	if (afep->afe_adv_100hdx) {
1226*1959748cSgd78059 		anar |= MII_ABILITY_100BASE_TX;
1227*1959748cSgd78059 		cnt++;
1228*1959748cSgd78059 	}
1229*1959748cSgd78059 	if (afep->afe_adv_10fdx) {
1230*1959748cSgd78059 		anar |= MII_ABILITY_10BASE_T_FD;
1231*1959748cSgd78059 		cnt++;
1232*1959748cSgd78059 	}
1233*1959748cSgd78059 	if (afep->afe_adv_10hdx) {
1234*1959748cSgd78059 		anar |= MII_ABILITY_10BASE_T;
1235*1959748cSgd78059 		cnt++;
1236*1959748cSgd78059 	}
1237*1959748cSgd78059 
1238*1959748cSgd78059 	/*
1239*1959748cSgd78059 	 * Make certain at least one valid link mode is selected.
1240*1959748cSgd78059 	 */
1241*1959748cSgd78059 	if (!cnt) {
1242*1959748cSgd78059 		afe_error(afep->afe_dip, "No valid link mode selected.");
1243*1959748cSgd78059 		afe_error(afep->afe_dip, "Powering down PHY.");
1244*1959748cSgd78059 		afe_stopphy(afep);
1245*1959748cSgd78059 		afep->afe_linkup = LINK_STATE_DOWN;
1246*1959748cSgd78059 		if (afep->afe_flags & AFE_RUNNING)
1247*1959748cSgd78059 			afe_reportlink(afep);
1248*1959748cSgd78059 		return;
1249*1959748cSgd78059 	}
1250*1959748cSgd78059 
1251*1959748cSgd78059 	if (fiber) {
1252*1959748cSgd78059 		bmcr = MII_CONTROL_100MB | MII_CONTROL_FDUPLEX;
1253*1959748cSgd78059 	} else if ((afep->afe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) {
1254*1959748cSgd78059 		DBG(DPHY, "using autoneg mode");
1255*1959748cSgd78059 		bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
1256*1959748cSgd78059 	} else {
1257*1959748cSgd78059 		DBG(DPHY, "using forced mode");
1258*1959748cSgd78059 		force = 1;
1259*1959748cSgd78059 		if (afep->afe_adv_100fdx) {
1260*1959748cSgd78059 			bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
1261*1959748cSgd78059 		} else if (afep->afe_adv_100hdx) {
1262*1959748cSgd78059 			bmcr = MII_CONTROL_100MB;
1263*1959748cSgd78059 		} else if (afep->afe_adv_10fdx) {
1264*1959748cSgd78059 			bmcr = MII_CONTROL_FDUPLEX;
1265*1959748cSgd78059 		} else {
1266*1959748cSgd78059 			/* 10HDX */
1267*1959748cSgd78059 			bmcr = 0;
1268*1959748cSgd78059 		}
1269*1959748cSgd78059 	}
1270*1959748cSgd78059 
1271*1959748cSgd78059 	afep->afe_forcephy = force;
1272*1959748cSgd78059 
1273*1959748cSgd78059 	DBG(DPHY, "programming anar to 0x%x", anar);
1274*1959748cSgd78059 	afe_miiwrite(afep, phyaddr, MII_AN_ADVERT, anar);
1275*1959748cSgd78059 	DBG(DPHY, "programming bmcr to 0x%x", bmcr);
1276*1959748cSgd78059 	afe_miiwrite(afep, phyaddr, MII_CONTROL, bmcr);
1277*1959748cSgd78059 
1278*1959748cSgd78059 	if (nosqe) {
1279*1959748cSgd78059 		uint16_t	pilr;
1280*1959748cSgd78059 		/*
1281*1959748cSgd78059 		 * work around for errata 983B_0416 -- duplex light flashes
1282*1959748cSgd78059 		 * in 10 HDX.  we just disable SQE testing on the device.
1283*1959748cSgd78059 		 */
1284*1959748cSgd78059 		pilr = afe_miiread(afep, phyaddr, PHY_PILR);
1285*1959748cSgd78059 		pilr |= PILR_NOSQE;
1286*1959748cSgd78059 		afe_miiwrite(afep, phyaddr, PHY_PILR, pilr);
1287*1959748cSgd78059 	}
1288*1959748cSgd78059 
1289*1959748cSgd78059 	/*
1290*1959748cSgd78059 	 * schedule a query of the link status
1291*1959748cSgd78059 	 */
1292*1959748cSgd78059 	PUTCSR(afep, CSR_TIMER, TIMER_LOOP |
1293*1959748cSgd78059 	    (AFE_LINKTIMER * 1000 / TIMER_USEC));
1294*1959748cSgd78059 }
1295*1959748cSgd78059 
1296*1959748cSgd78059 void
1297*1959748cSgd78059 afe_stopphy(afe_t *afep)
1298*1959748cSgd78059 {
1299*1959748cSgd78059 	/* stop the phy timer */
1300*1959748cSgd78059 	PUTCSR(afep, CSR_TIMER, 0);
1301*1959748cSgd78059 
1302*1959748cSgd78059 	/*
1303*1959748cSgd78059 	 * phy in isolate & powerdown mode...
1304*1959748cSgd78059 	 */
1305*1959748cSgd78059 	afe_miiwrite(afep, afep->afe_phyaddr, MII_CONTROL,
1306*1959748cSgd78059 	    MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
1307*1959748cSgd78059 
1308*1959748cSgd78059 	/*
1309*1959748cSgd78059 	 * mark the link state unknown
1310*1959748cSgd78059 	 */
1311*1959748cSgd78059 	if (!afep->afe_resetting) {
1312*1959748cSgd78059 		afep->afe_linkup = LINK_STATE_UNKNOWN;
1313*1959748cSgd78059 		afep->afe_ifspeed = 0;
1314*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_UNKNOWN;
1315*1959748cSgd78059 		if (afep->afe_flags & AFE_RUNNING)
1316*1959748cSgd78059 			afe_reportlink(afep);
1317*1959748cSgd78059 	}
1318*1959748cSgd78059 }
1319*1959748cSgd78059 
1320*1959748cSgd78059 void
1321*1959748cSgd78059 afe_reportlink(afe_t *afep)
1322*1959748cSgd78059 {
1323*1959748cSgd78059 	int changed = 0;
1324*1959748cSgd78059 
1325*1959748cSgd78059 	if (afep->afe_ifspeed != afep->afe_lastifspeed) {
1326*1959748cSgd78059 		afep->afe_lastifspeed = afep->afe_ifspeed;
1327*1959748cSgd78059 		changed++;
1328*1959748cSgd78059 	}
1329*1959748cSgd78059 	if (afep->afe_duplex != afep->afe_lastduplex) {
1330*1959748cSgd78059 		afep->afe_lastduplex = afep->afe_duplex;
1331*1959748cSgd78059 		changed++;
1332*1959748cSgd78059 	}
1333*1959748cSgd78059 	if (changed)
1334*1959748cSgd78059 		mac_link_update(afep->afe_mh, afep->afe_linkup);
1335*1959748cSgd78059 }
1336*1959748cSgd78059 
1337*1959748cSgd78059 void
1338*1959748cSgd78059 afe_checklink(afe_t *afep)
1339*1959748cSgd78059 {
1340*1959748cSgd78059 	if ((afep->afe_flags & AFE_RUNNING) == 0)
1341*1959748cSgd78059 		return;
1342*1959748cSgd78059 
1343*1959748cSgd78059 	if ((afep->afe_txstall_time != 0) &&
1344*1959748cSgd78059 	    (gethrtime() > afep->afe_txstall_time) &&
1345*1959748cSgd78059 	    (afep->afe_txavail != AFE_TXRING)) {
1346*1959748cSgd78059 		afep->afe_txstall_time = 0;
1347*1959748cSgd78059 		afe_error(afep->afe_dip, "TX stall detected!");
1348*1959748cSgd78059 		afe_resetall(afep);
1349*1959748cSgd78059 		return;
1350*1959748cSgd78059 	}
1351*1959748cSgd78059 
1352*1959748cSgd78059 	switch (AFE_MODEL(afep)) {
1353*1959748cSgd78059 	case MODEL_COMET:
1354*1959748cSgd78059 		afe_checklinkcomet(afep);
1355*1959748cSgd78059 		break;
1356*1959748cSgd78059 	case MODEL_CENTAUR:
1357*1959748cSgd78059 		afe_checklinkcentaur(afep);
1358*1959748cSgd78059 		break;
1359*1959748cSgd78059 	}
1360*1959748cSgd78059 }
1361*1959748cSgd78059 
1362*1959748cSgd78059 void
1363*1959748cSgd78059 afe_checklinkcomet(afe_t *afep)
1364*1959748cSgd78059 {
1365*1959748cSgd78059 	uint16_t	xciis;
1366*1959748cSgd78059 	int		reinit = 0;
1367*1959748cSgd78059 
1368*1959748cSgd78059 	xciis = GETCSR16(afep, CSR_XCIIS);
1369*1959748cSgd78059 	if (xciis & XCIIS_PDF) {
1370*1959748cSgd78059 		afe_error(afep->afe_dip, "Parallel detection fault detected!");
1371*1959748cSgd78059 	}
1372*1959748cSgd78059 	if (xciis & XCIIS_RF) {
1373*1959748cSgd78059 		afe_error(afep->afe_dip, "Remote fault detected.");
1374*1959748cSgd78059 	}
1375*1959748cSgd78059 	if (xciis & XCIIS_LFAIL) {
1376*1959748cSgd78059 		if (afep->afe_linkup == LINK_STATE_UP) {
1377*1959748cSgd78059 			reinit++;
1378*1959748cSgd78059 		}
1379*1959748cSgd78059 		afep->afe_ifspeed = 0;
1380*1959748cSgd78059 		afep->afe_linkup = LINK_STATE_DOWN;
1381*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_UNKNOWN;
1382*1959748cSgd78059 		afe_reportlink(afep);
1383*1959748cSgd78059 		if (reinit) {
1384*1959748cSgd78059 			afe_startphy(afep);
1385*1959748cSgd78059 		}
1386*1959748cSgd78059 		return;
1387*1959748cSgd78059 	}
1388*1959748cSgd78059 
1389*1959748cSgd78059 	afep->afe_linkup = LINK_STATE_UP;
1390*1959748cSgd78059 	afep->afe_ifspeed = (xciis & XCIIS_SPEED) ? 100000000 : 10000000;
1391*1959748cSgd78059 	if (xciis & XCIIS_DUPLEX) {
1392*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_FULL;
1393*1959748cSgd78059 	} else {
1394*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_HALF;
1395*1959748cSgd78059 	}
1396*1959748cSgd78059 
1397*1959748cSgd78059 	afe_reportlink(afep);
1398*1959748cSgd78059 }
1399*1959748cSgd78059 
1400*1959748cSgd78059 void
1401*1959748cSgd78059 afe_checklinkcentaur(afe_t *afep)
1402*1959748cSgd78059 {
1403*1959748cSgd78059 	unsigned	opmode;
1404*1959748cSgd78059 	int		reinit = 0;
1405*1959748cSgd78059 
1406*1959748cSgd78059 	opmode = GETCSR(afep, CSR_OPM);
1407*1959748cSgd78059 	if ((opmode & OPM_MODE) == OPM_MACONLY) {
1408*1959748cSgd78059 		DBG(DPHY, "Centaur running in MAC-only mode");
1409*1959748cSgd78059 		afe_checklinkmii(afep);
1410*1959748cSgd78059 		return;
1411*1959748cSgd78059 	}
1412*1959748cSgd78059 	DBG(DPHY, "Centaur running in single chip mode");
1413*1959748cSgd78059 	if ((opmode & OPM_LINK) == 0) {
1414*1959748cSgd78059 		if (afep->afe_linkup == LINK_STATE_UP) {
1415*1959748cSgd78059 			reinit++;
1416*1959748cSgd78059 		}
1417*1959748cSgd78059 		afep->afe_ifspeed = 0;
1418*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_UNKNOWN;
1419*1959748cSgd78059 		afep->afe_linkup = LINK_STATE_DOWN;
1420*1959748cSgd78059 		afe_reportlink(afep);
1421*1959748cSgd78059 		if (reinit) {
1422*1959748cSgd78059 			afe_startphy(afep);
1423*1959748cSgd78059 		}
1424*1959748cSgd78059 		return;
1425*1959748cSgd78059 	}
1426*1959748cSgd78059 
1427*1959748cSgd78059 	afep->afe_linkup = LINK_STATE_UP;
1428*1959748cSgd78059 	afep->afe_ifspeed = (opmode & OPM_SPEED) ? 100000000 : 10000000;
1429*1959748cSgd78059 	if (opmode & OPM_DUPLEX) {
1430*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_FULL;
1431*1959748cSgd78059 	} else {
1432*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_HALF;
1433*1959748cSgd78059 	}
1434*1959748cSgd78059 	afe_reportlink(afep);
1435*1959748cSgd78059 }
1436*1959748cSgd78059 
1437*1959748cSgd78059 void
1438*1959748cSgd78059 afe_checklinkmii(afe_t *afep)
1439*1959748cSgd78059 {
1440*1959748cSgd78059 	/* read MII state registers */
1441*1959748cSgd78059 	uint16_t	bmsr;
1442*1959748cSgd78059 	uint16_t	bmcr;
1443*1959748cSgd78059 	uint16_t	anar;
1444*1959748cSgd78059 	uint16_t	anlpar;
1445*1959748cSgd78059 	int			reinit = 0;
1446*1959748cSgd78059 
1447*1959748cSgd78059 	/* read this twice, to clear latched link state */
1448*1959748cSgd78059 	bmsr = afe_miiread(afep, afep->afe_phyaddr, MII_STATUS);
1449*1959748cSgd78059 	bmsr = afe_miiread(afep, afep->afe_phyaddr, MII_STATUS);
1450*1959748cSgd78059 	bmcr = afe_miiread(afep, afep->afe_phyaddr, MII_CONTROL);
1451*1959748cSgd78059 	anar = afe_miiread(afep, afep->afe_phyaddr, MII_AN_ADVERT);
1452*1959748cSgd78059 	anlpar = afe_miiread(afep, afep->afe_phyaddr, MII_AN_LPABLE);
1453*1959748cSgd78059 
1454*1959748cSgd78059 	if (bmsr & MII_STATUS_REMFAULT) {
1455*1959748cSgd78059 		afe_error(afep->afe_dip, "Remote fault detected.");
1456*1959748cSgd78059 	}
1457*1959748cSgd78059 	if (bmsr & MII_STATUS_JABBERING) {
1458*1959748cSgd78059 		afe_error(afep->afe_dip, "Jabber condition detected.");
1459*1959748cSgd78059 	}
1460*1959748cSgd78059 	if ((bmsr & MII_STATUS_LINKUP) == 0) {
1461*1959748cSgd78059 		/* no link */
1462*1959748cSgd78059 		if (afep->afe_linkup) {
1463*1959748cSgd78059 			reinit = 1;
1464*1959748cSgd78059 		}
1465*1959748cSgd78059 		afep->afe_ifspeed = 0;
1466*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_UNKNOWN;
1467*1959748cSgd78059 		afep->afe_linkup = LINK_STATE_DOWN;
1468*1959748cSgd78059 		afe_reportlink(afep);
1469*1959748cSgd78059 		if (reinit) {
1470*1959748cSgd78059 			afe_startphy(afep);
1471*1959748cSgd78059 		}
1472*1959748cSgd78059 		return;
1473*1959748cSgd78059 	}
1474*1959748cSgd78059 
1475*1959748cSgd78059 	DBG(DCHATTY, "link up!");
1476*1959748cSgd78059 	afep->afe_linkup = LINK_STATE_UP;
1477*1959748cSgd78059 
1478*1959748cSgd78059 	if (!(bmcr & MII_CONTROL_ANE)) {
1479*1959748cSgd78059 		/* forced mode */
1480*1959748cSgd78059 		if (bmcr & MII_CONTROL_100MB) {
1481*1959748cSgd78059 			afep->afe_ifspeed = 100000000;
1482*1959748cSgd78059 		} else {
1483*1959748cSgd78059 			afep->afe_ifspeed = 10000000;
1484*1959748cSgd78059 		}
1485*1959748cSgd78059 		if (bmcr & MII_CONTROL_FDUPLEX) {
1486*1959748cSgd78059 			afep->afe_duplex = LINK_DUPLEX_FULL;
1487*1959748cSgd78059 		} else {
1488*1959748cSgd78059 			afep->afe_duplex = LINK_DUPLEX_HALF;
1489*1959748cSgd78059 		}
1490*1959748cSgd78059 	} else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
1491*1959748cSgd78059 	    (!(bmsr & MII_STATUS_ANDONE))) {
1492*1959748cSgd78059 		afep->afe_ifspeed = 0;
1493*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_UNKNOWN;
1494*1959748cSgd78059 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
1495*1959748cSgd78059 		afep->afe_ifspeed = 100000000;
1496*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_FULL;
1497*1959748cSgd78059 	} else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
1498*1959748cSgd78059 		afep->afe_ifspeed = 100000000;
1499*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_HALF;
1500*1959748cSgd78059 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
1501*1959748cSgd78059 		afep->afe_ifspeed = 100000000;
1502*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_HALF;
1503*1959748cSgd78059 	} else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
1504*1959748cSgd78059 		afep->afe_ifspeed = 10000000;
1505*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_FULL;
1506*1959748cSgd78059 	} else if (anar & anlpar & MII_ABILITY_10BASE_T) {
1507*1959748cSgd78059 		afep->afe_ifspeed = 10000000;
1508*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_HALF;
1509*1959748cSgd78059 	} else {
1510*1959748cSgd78059 		afep->afe_ifspeed = 0;
1511*1959748cSgd78059 		afep->afe_duplex = LINK_DUPLEX_UNKNOWN;
1512*1959748cSgd78059 	}
1513*1959748cSgd78059 
1514*1959748cSgd78059 	afe_reportlink(afep);
1515*1959748cSgd78059 }
1516*1959748cSgd78059 
1517*1959748cSgd78059 void
1518*1959748cSgd78059 afe_miitristate(afe_t *afep)
1519*1959748cSgd78059 {
1520*1959748cSgd78059 	unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL;
1521*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, val);
1522*1959748cSgd78059 	drv_usecwait(1);
1523*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK);
1524*1959748cSgd78059 	drv_usecwait(1);
1525*1959748cSgd78059 }
1526*1959748cSgd78059 
1527*1959748cSgd78059 void
1528*1959748cSgd78059 afe_miiwritebit(afe_t *afep, int bit)
1529*1959748cSgd78059 {
1530*1959748cSgd78059 	unsigned val = bit ? SPR_MII_DOUT : 0;
1531*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, val);
1532*1959748cSgd78059 	drv_usecwait(1);
1533*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK);
1534*1959748cSgd78059 	drv_usecwait(1);
1535*1959748cSgd78059 }
1536*1959748cSgd78059 
1537*1959748cSgd78059 int
1538*1959748cSgd78059 afe_miireadbit(afe_t *afep)
1539*1959748cSgd78059 {
1540*1959748cSgd78059 	unsigned val = SPR_MII_CTRL | SPR_SROM_READ;
1541*1959748cSgd78059 	int bit;
1542*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, val);
1543*1959748cSgd78059 	drv_usecwait(1);
1544*1959748cSgd78059 	bit = (GETCSR(afep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0;
1545*1959748cSgd78059 	PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK);
1546*1959748cSgd78059 	drv_usecwait(1);
1547*1959748cSgd78059 	return (bit);
1548*1959748cSgd78059 }
1549*1959748cSgd78059 
1550*1959748cSgd78059 unsigned
1551*1959748cSgd78059 afe_miiread(afe_t *afep, int phy, int reg)
1552*1959748cSgd78059 {
1553*1959748cSgd78059 	/*
1554*1959748cSgd78059 	 * ADMtek bugs ignore address decode bits -- they only
1555*1959748cSgd78059 	 * support PHY at 1.
1556*1959748cSgd78059 	 */
1557*1959748cSgd78059 	if (phy != 1) {
1558*1959748cSgd78059 		return (0xffff);
1559*1959748cSgd78059 	}
1560*1959748cSgd78059 	switch (AFE_MODEL(afep)) {
1561*1959748cSgd78059 	case MODEL_COMET:
1562*1959748cSgd78059 		return (afe_miireadcomet(afep, phy, reg));
1563*1959748cSgd78059 	case MODEL_CENTAUR:
1564*1959748cSgd78059 		return (afe_miireadgeneral(afep, phy, reg));
1565*1959748cSgd78059 	}
1566*1959748cSgd78059 	return (0xffff);
1567*1959748cSgd78059 }
1568*1959748cSgd78059 
1569*1959748cSgd78059 unsigned
1570*1959748cSgd78059 afe_miireadgeneral(afe_t *afep, int phy, int reg)
1571*1959748cSgd78059 {
1572*1959748cSgd78059 	unsigned	value = 0;
1573*1959748cSgd78059 	int		i;
1574*1959748cSgd78059 
1575*1959748cSgd78059 	/* send the 32 bit preamble */
1576*1959748cSgd78059 	for (i = 0; i < 32; i++) {
1577*1959748cSgd78059 		afe_miiwritebit(afep, 1);
1578*1959748cSgd78059 	}
1579*1959748cSgd78059 
1580*1959748cSgd78059 	/* send the start code - 01b */
1581*1959748cSgd78059 	afe_miiwritebit(afep, 0);
1582*1959748cSgd78059 	afe_miiwritebit(afep, 1);
1583*1959748cSgd78059 
1584*1959748cSgd78059 	/* send the opcode for read, - 10b */
1585*1959748cSgd78059 	afe_miiwritebit(afep, 1);
1586*1959748cSgd78059 	afe_miiwritebit(afep, 0);
1587*1959748cSgd78059 
1588*1959748cSgd78059 	/* next we send the 5 bit phy address */
1589*1959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
1590*1959748cSgd78059 		afe_miiwritebit(afep, (phy & i) ? 1 : 0);
1591*1959748cSgd78059 	}
1592*1959748cSgd78059 
1593*1959748cSgd78059 	/* the 5 bit register address goes next */
1594*1959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
1595*1959748cSgd78059 		afe_miiwritebit(afep, (reg & i) ? 1 : 0);
1596*1959748cSgd78059 	}
1597*1959748cSgd78059 
1598*1959748cSgd78059 	/* turnaround - tristate followed by logic 0 */
1599*1959748cSgd78059 	afe_miitristate(afep);
1600*1959748cSgd78059 	afe_miiwritebit(afep, 0);
1601*1959748cSgd78059 
1602*1959748cSgd78059 	/* read the 16 bit register value */
1603*1959748cSgd78059 	for (i = 0x8000; i > 0; i >>= 1) {
1604*1959748cSgd78059 		value <<= 1;
1605*1959748cSgd78059 		value |= afe_miireadbit(afep);
1606*1959748cSgd78059 	}
1607*1959748cSgd78059 	afe_miitristate(afep);
1608*1959748cSgd78059 	return (value);
1609*1959748cSgd78059 }
1610*1959748cSgd78059 
1611*1959748cSgd78059 unsigned
1612*1959748cSgd78059 afe_miireadcomet(afe_t *afep, int phy, int reg)
1613*1959748cSgd78059 {
1614*1959748cSgd78059 	if (phy != 1) {
1615*1959748cSgd78059 		return (0xffff);
1616*1959748cSgd78059 	}
1617*1959748cSgd78059 	switch (reg) {
1618*1959748cSgd78059 	case MII_CONTROL:
1619*1959748cSgd78059 		reg = CSR_BMCR;
1620*1959748cSgd78059 		break;
1621*1959748cSgd78059 	case MII_STATUS:
1622*1959748cSgd78059 		reg = CSR_BMSR;
1623*1959748cSgd78059 		break;
1624*1959748cSgd78059 	case MII_PHYIDH:
1625*1959748cSgd78059 		reg = CSR_PHYIDR1;
1626*1959748cSgd78059 		break;
1627*1959748cSgd78059 	case MII_PHYIDL:
1628*1959748cSgd78059 		reg = CSR_PHYIDR2;
1629*1959748cSgd78059 		break;
1630*1959748cSgd78059 	case MII_AN_ADVERT:
1631*1959748cSgd78059 		reg = CSR_ANAR;
1632*1959748cSgd78059 		break;
1633*1959748cSgd78059 	case MII_AN_LPABLE:
1634*1959748cSgd78059 		reg = CSR_ANLPAR;
1635*1959748cSgd78059 		break;
1636*1959748cSgd78059 	case MII_AN_EXPANSION:
1637*1959748cSgd78059 		reg = CSR_ANER;
1638*1959748cSgd78059 		break;
1639*1959748cSgd78059 	default:
1640*1959748cSgd78059 		return (0);
1641*1959748cSgd78059 	}
1642*1959748cSgd78059 	return (GETCSR16(afep, reg) & 0xFFFF);
1643*1959748cSgd78059 }
1644*1959748cSgd78059 
1645*1959748cSgd78059 void
1646*1959748cSgd78059 afe_miiwrite(afe_t *afep, int phy, int reg, uint16_t val)
1647*1959748cSgd78059 {
1648*1959748cSgd78059 	/*
1649*1959748cSgd78059 	 * ADMtek bugs ignore address decode bits -- they only
1650*1959748cSgd78059 	 * support PHY at 1.
1651*1959748cSgd78059 	 */
1652*1959748cSgd78059 	if (phy != 1) {
1653*1959748cSgd78059 		return;
1654*1959748cSgd78059 	}
1655*1959748cSgd78059 	switch (AFE_MODEL(afep)) {
1656*1959748cSgd78059 	case MODEL_COMET:
1657*1959748cSgd78059 		afe_miiwritecomet(afep, phy, reg, val);
1658*1959748cSgd78059 		break;
1659*1959748cSgd78059 	case MODEL_CENTAUR:
1660*1959748cSgd78059 		afe_miiwritegeneral(afep, phy, reg, val);
1661*1959748cSgd78059 		break;
1662*1959748cSgd78059 	}
1663*1959748cSgd78059 }
1664*1959748cSgd78059 
1665*1959748cSgd78059 void
1666*1959748cSgd78059 afe_miiwritegeneral(afe_t *afep, int phy, int reg, uint16_t val)
1667*1959748cSgd78059 {
1668*1959748cSgd78059 	int i;
1669*1959748cSgd78059 
1670*1959748cSgd78059 	/* send the 32 bit preamble */
1671*1959748cSgd78059 	for (i = 0; i < 32; i++) {
1672*1959748cSgd78059 		afe_miiwritebit(afep, 1);
1673*1959748cSgd78059 	}
1674*1959748cSgd78059 
1675*1959748cSgd78059 	/* send the start code - 01b */
1676*1959748cSgd78059 	afe_miiwritebit(afep, 0);
1677*1959748cSgd78059 	afe_miiwritebit(afep, 1);
1678*1959748cSgd78059 
1679*1959748cSgd78059 	/* send the opcode for write, - 01b */
1680*1959748cSgd78059 	afe_miiwritebit(afep, 0);
1681*1959748cSgd78059 	afe_miiwritebit(afep, 1);
1682*1959748cSgd78059 
1683*1959748cSgd78059 	/* next we send the 5 bit phy address */
1684*1959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
1685*1959748cSgd78059 		afe_miiwritebit(afep, (phy & i) ? 1 : 0);
1686*1959748cSgd78059 	}
1687*1959748cSgd78059 
1688*1959748cSgd78059 	/* the 5 bit register address goes next */
1689*1959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
1690*1959748cSgd78059 		afe_miiwritebit(afep, (reg & i) ? 1 : 0);
1691*1959748cSgd78059 	}
1692*1959748cSgd78059 
1693*1959748cSgd78059 	/* turnaround - tristate followed by logic 0 */
1694*1959748cSgd78059 	afe_miitristate(afep);
1695*1959748cSgd78059 	afe_miiwritebit(afep, 0);
1696*1959748cSgd78059 
1697*1959748cSgd78059 	/* now write out our data (16 bits) */
1698*1959748cSgd78059 	for (i = 0x8000; i > 0; i >>= 1) {
1699*1959748cSgd78059 		afe_miiwritebit(afep, (val & i) ? 1 : 0);
1700*1959748cSgd78059 	}
1701*1959748cSgd78059 
1702*1959748cSgd78059 	/* idle mode */
1703*1959748cSgd78059 	afe_miitristate(afep);
1704*1959748cSgd78059 }
1705*1959748cSgd78059 
1706*1959748cSgd78059 void
1707*1959748cSgd78059 afe_miiwritecomet(afe_t *afep, int phy, int reg, uint16_t val)
1708*1959748cSgd78059 {
1709*1959748cSgd78059 	if (phy != 1) {
1710*1959748cSgd78059 		return;
1711*1959748cSgd78059 	}
1712*1959748cSgd78059 	switch (reg) {
1713*1959748cSgd78059 	case MII_CONTROL:
1714*1959748cSgd78059 		reg = CSR_BMCR;
1715*1959748cSgd78059 		break;
1716*1959748cSgd78059 	case MII_STATUS:
1717*1959748cSgd78059 		reg = CSR_BMSR;
1718*1959748cSgd78059 		break;
1719*1959748cSgd78059 	case MII_PHYIDH:
1720*1959748cSgd78059 		reg = CSR_PHYIDR1;
1721*1959748cSgd78059 		break;
1722*1959748cSgd78059 	case MII_PHYIDL:
1723*1959748cSgd78059 		reg = CSR_PHYIDR2;
1724*1959748cSgd78059 		break;
1725*1959748cSgd78059 	case MII_AN_ADVERT:
1726*1959748cSgd78059 		reg = CSR_ANAR;
1727*1959748cSgd78059 		break;
1728*1959748cSgd78059 	case MII_AN_LPABLE:
1729*1959748cSgd78059 		reg = CSR_ANLPAR;
1730*1959748cSgd78059 		break;
1731*1959748cSgd78059 	case MII_AN_EXPANSION:
1732*1959748cSgd78059 		reg = CSR_ANER;
1733*1959748cSgd78059 		break;
1734*1959748cSgd78059 	default:
1735*1959748cSgd78059 		return;
1736*1959748cSgd78059 	}
1737*1959748cSgd78059 	PUTCSR16(afep, reg, val);
1738*1959748cSgd78059 }
1739*1959748cSgd78059 
1740*1959748cSgd78059 int
1741*1959748cSgd78059 afe_m_start(void *arg)
1742*1959748cSgd78059 {
1743*1959748cSgd78059 	afe_t	*afep = arg;
1744*1959748cSgd78059 
1745*1959748cSgd78059 	/* grab exclusive access to the card */
1746*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
1747*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
1748*1959748cSgd78059 
1749*1959748cSgd78059 	afe_startall(afep);
1750*1959748cSgd78059 	afep->afe_flags |= AFE_RUNNING;
1751*1959748cSgd78059 
1752*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
1753*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
1754*1959748cSgd78059 	return (0);
1755*1959748cSgd78059 }
1756*1959748cSgd78059 
1757*1959748cSgd78059 void
1758*1959748cSgd78059 afe_m_stop(void *arg)
1759*1959748cSgd78059 {
1760*1959748cSgd78059 	afe_t	*afep = arg;
1761*1959748cSgd78059 
1762*1959748cSgd78059 	/* exclusive access to the hardware! */
1763*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
1764*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
1765*1959748cSgd78059 
1766*1959748cSgd78059 	afe_stopall(afep);
1767*1959748cSgd78059 	afep->afe_flags &= ~AFE_RUNNING;
1768*1959748cSgd78059 
1769*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
1770*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
1771*1959748cSgd78059 }
1772*1959748cSgd78059 
1773*1959748cSgd78059 void
1774*1959748cSgd78059 afe_startmac(afe_t *afep)
1775*1959748cSgd78059 {
1776*1959748cSgd78059 	/* verify exclusive access to the card */
1777*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
1778*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
1779*1959748cSgd78059 
1780*1959748cSgd78059 	/* start the card */
1781*1959748cSgd78059 	SETBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
1782*1959748cSgd78059 
1783*1959748cSgd78059 	if (afep->afe_txavail != AFE_TXRING)
1784*1959748cSgd78059 		PUTCSR(afep, CSR_TDR, 0);
1785*1959748cSgd78059 
1786*1959748cSgd78059 	/* tell the mac that we are ready to go! */
1787*1959748cSgd78059 	if (afep->afe_flags & AFE_RUNNING)
1788*1959748cSgd78059 		mac_tx_update(afep->afe_mh);
1789*1959748cSgd78059 }
1790*1959748cSgd78059 
1791*1959748cSgd78059 void
1792*1959748cSgd78059 afe_stopmac(afe_t *afep)
1793*1959748cSgd78059 {
1794*1959748cSgd78059 	int		i;
1795*1959748cSgd78059 
1796*1959748cSgd78059 	/* exclusive access to the hardware! */
1797*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
1798*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
1799*1959748cSgd78059 
1800*1959748cSgd78059 	CLRBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
1801*1959748cSgd78059 
1802*1959748cSgd78059 	/*
1803*1959748cSgd78059 	 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
1804*1959748cSgd78059 	 * We just add up to the nearest msec (2), which should be
1805*1959748cSgd78059 	 * plenty to complete.
1806*1959748cSgd78059 	 *
1807*1959748cSgd78059 	 * Note that some chips never seem to indicate the transition to
1808*1959748cSgd78059 	 * the stopped state properly.  Experience shows that we can safely
1809*1959748cSgd78059 	 * proceed anyway, after waiting the requisite timeout.
1810*1959748cSgd78059 	 */
1811*1959748cSgd78059 	for (i = 2000; i != 0; i -= 10) {
1812*1959748cSgd78059 		if ((GETCSR(afep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0)
1813*1959748cSgd78059 			break;
1814*1959748cSgd78059 		drv_usecwait(10);
1815*1959748cSgd78059 	}
1816*1959748cSgd78059 
1817*1959748cSgd78059 	/* prevent an interrupt */
1818*1959748cSgd78059 	PUTCSR(afep, CSR_SR2, INT_RXSTOPPED | INT_TXSTOPPED);
1819*1959748cSgd78059 }
1820*1959748cSgd78059 
1821*1959748cSgd78059 void
1822*1959748cSgd78059 afe_resetrings(afe_t *afep)
1823*1959748cSgd78059 {
1824*1959748cSgd78059 	int	i;
1825*1959748cSgd78059 
1826*1959748cSgd78059 	/* now we need to reset the pointers... */
1827*1959748cSgd78059 	PUTCSR(afep, CSR_RDB, 0);
1828*1959748cSgd78059 	PUTCSR(afep, CSR_TDB, 0);
1829*1959748cSgd78059 
1830*1959748cSgd78059 	/* reset the descriptor ring pointers */
1831*1959748cSgd78059 	afep->afe_rxhead = 0;
1832*1959748cSgd78059 	afep->afe_txreclaim = 0;
1833*1959748cSgd78059 	afep->afe_txsend = 0;
1834*1959748cSgd78059 	afep->afe_txavail = AFE_TXRING;
1835*1959748cSgd78059 
1836*1959748cSgd78059 	/* set up transmit descriptor ring */
1837*1959748cSgd78059 	for (i = 0; i < AFE_TXRING; i++) {
1838*1959748cSgd78059 		afe_desc_t	*tmdp = &afep->afe_txdescp[i];
1839*1959748cSgd78059 		unsigned	control = 0;
1840*1959748cSgd78059 		if (i == (AFE_TXRING - 1)) {
1841*1959748cSgd78059 			control |= TXCTL_ENDRING;
1842*1959748cSgd78059 		}
1843*1959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_status, 0);
1844*1959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_control, control);
1845*1959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_buffer1, 0);
1846*1959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_buffer2, 0);
1847*1959748cSgd78059 		SYNCTXDESC(afep, i, DDI_DMA_SYNC_FORDEV);
1848*1959748cSgd78059 	}
1849*1959748cSgd78059 	PUTCSR(afep, CSR_TDB, afep->afe_txdesc_paddr);
1850*1959748cSgd78059 
1851*1959748cSgd78059 	/* make the receive buffers available */
1852*1959748cSgd78059 	for (i = 0; i < AFE_RXRING; i++) {
1853*1959748cSgd78059 		afe_rxbuf_t	*rxb = afep->afe_rxbufs[i];
1854*1959748cSgd78059 		afe_desc_t	*rmdp = &afep->afe_rxdescp[i];
1855*1959748cSgd78059 		unsigned	control;
1856*1959748cSgd78059 
1857*1959748cSgd78059 		control = AFE_BUFSZ & RXCTL_BUFLEN1;
1858*1959748cSgd78059 		if (i == (AFE_RXRING - 1)) {
1859*1959748cSgd78059 			control |= RXCTL_ENDRING;
1860*1959748cSgd78059 		}
1861*1959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_buffer1, rxb->rxb_paddr);
1862*1959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_buffer2, 0);
1863*1959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_control, control);
1864*1959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_status, RXSTAT_OWN);
1865*1959748cSgd78059 		SYNCRXDESC(afep, i, DDI_DMA_SYNC_FORDEV);
1866*1959748cSgd78059 	}
1867*1959748cSgd78059 	PUTCSR(afep, CSR_RDB, afep->afe_rxdesc_paddr);
1868*1959748cSgd78059 }
1869*1959748cSgd78059 
1870*1959748cSgd78059 void
1871*1959748cSgd78059 afe_stopall(afe_t *afep)
1872*1959748cSgd78059 {
1873*1959748cSgd78059 	afe_disableinterrupts(afep);
1874*1959748cSgd78059 
1875*1959748cSgd78059 	afe_stopmac(afep);
1876*1959748cSgd78059 
1877*1959748cSgd78059 	/* stop the phy */
1878*1959748cSgd78059 	afe_stopphy(afep);
1879*1959748cSgd78059 }
1880*1959748cSgd78059 
1881*1959748cSgd78059 void
1882*1959748cSgd78059 afe_startall(afe_t *afep)
1883*1959748cSgd78059 {
1884*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
1885*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
1886*1959748cSgd78059 
1887*1959748cSgd78059 	/* make sure interrupts are disabled to begin */
1888*1959748cSgd78059 	afe_disableinterrupts(afep);
1889*1959748cSgd78059 
1890*1959748cSgd78059 	/* initialize the chip */
1891*1959748cSgd78059 	(void) afe_initialize(afep);
1892*1959748cSgd78059 
1893*1959748cSgd78059 	/* now we can enable interrupts */
1894*1959748cSgd78059 	afe_enableinterrupts(afep);
1895*1959748cSgd78059 
1896*1959748cSgd78059 	/* start up the phy */
1897*1959748cSgd78059 	afe_startphy(afep);
1898*1959748cSgd78059 
1899*1959748cSgd78059 	/* start up the mac */
1900*1959748cSgd78059 	afe_startmac(afep);
1901*1959748cSgd78059 }
1902*1959748cSgd78059 
1903*1959748cSgd78059 void
1904*1959748cSgd78059 afe_resetall(afe_t *afep)
1905*1959748cSgd78059 {
1906*1959748cSgd78059 	afep->afe_resetting = B_TRUE;
1907*1959748cSgd78059 	afe_stopall(afep);
1908*1959748cSgd78059 	afep->afe_resetting = B_FALSE;
1909*1959748cSgd78059 	afe_startall(afep);
1910*1959748cSgd78059 }
1911*1959748cSgd78059 
1912*1959748cSgd78059 afe_txbuf_t *
1913*1959748cSgd78059 afe_alloctxbuf(afe_t *afep)
1914*1959748cSgd78059 {
1915*1959748cSgd78059 	ddi_dma_cookie_t	dmac;
1916*1959748cSgd78059 	unsigned		ncookies;
1917*1959748cSgd78059 	afe_txbuf_t		*txb;
1918*1959748cSgd78059 	size_t			len;
1919*1959748cSgd78059 
1920*1959748cSgd78059 	txb = kmem_zalloc(sizeof (*txb), KM_SLEEP);
1921*1959748cSgd78059 
1922*1959748cSgd78059 	if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_txattr,
1923*1959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) {
1924*1959748cSgd78059 		return (NULL);
1925*1959748cSgd78059 	}
1926*1959748cSgd78059 
1927*1959748cSgd78059 	if (ddi_dma_mem_alloc(txb->txb_dmah, AFE_BUFSZ, &afe_bufattr,
1928*1959748cSgd78059 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, &len,
1929*1959748cSgd78059 	    &txb->txb_acch) != DDI_SUCCESS) {
1930*1959748cSgd78059 		return (NULL);
1931*1959748cSgd78059 	}
1932*1959748cSgd78059 	if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf,
1933*1959748cSgd78059 	    len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
1934*1959748cSgd78059 	    &dmac, &ncookies) != DDI_DMA_MAPPED) {
1935*1959748cSgd78059 		return (NULL);
1936*1959748cSgd78059 	}
1937*1959748cSgd78059 	txb->txb_paddr = dmac.dmac_address;
1938*1959748cSgd78059 
1939*1959748cSgd78059 	return (txb);
1940*1959748cSgd78059 }
1941*1959748cSgd78059 
1942*1959748cSgd78059 void
1943*1959748cSgd78059 afe_destroytxbuf(afe_txbuf_t *txb)
1944*1959748cSgd78059 {
1945*1959748cSgd78059 	if (txb != NULL) {
1946*1959748cSgd78059 		if (txb->txb_paddr)
1947*1959748cSgd78059 			(void) ddi_dma_unbind_handle(txb->txb_dmah);
1948*1959748cSgd78059 		if (txb->txb_acch)
1949*1959748cSgd78059 			ddi_dma_mem_free(&txb->txb_acch);
1950*1959748cSgd78059 		if (txb->txb_dmah)
1951*1959748cSgd78059 			ddi_dma_free_handle(&txb->txb_dmah);
1952*1959748cSgd78059 		kmem_free(txb, sizeof (*txb));
1953*1959748cSgd78059 	}
1954*1959748cSgd78059 }
1955*1959748cSgd78059 
1956*1959748cSgd78059 afe_rxbuf_t *
1957*1959748cSgd78059 afe_allocrxbuf(afe_t *afep)
1958*1959748cSgd78059 {
1959*1959748cSgd78059 	afe_rxbuf_t		*rxb;
1960*1959748cSgd78059 	size_t			len;
1961*1959748cSgd78059 	unsigned		ccnt;
1962*1959748cSgd78059 	ddi_dma_cookie_t	dmac;
1963*1959748cSgd78059 
1964*1959748cSgd78059 	rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP);
1965*1959748cSgd78059 
1966*1959748cSgd78059 	if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
1967*1959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) {
1968*1959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
1969*1959748cSgd78059 		return (NULL);
1970*1959748cSgd78059 	}
1971*1959748cSgd78059 	if (ddi_dma_mem_alloc(rxb->rxb_dmah, AFE_BUFSZ, &afe_bufattr,
1972*1959748cSgd78059 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &rxb->rxb_buf, &len,
1973*1959748cSgd78059 	    &rxb->rxb_acch) != DDI_SUCCESS) {
1974*1959748cSgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
1975*1959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
1976*1959748cSgd78059 		return (NULL);
1977*1959748cSgd78059 	}
1978*1959748cSgd78059 	if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len,
1979*1959748cSgd78059 	    DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
1980*1959748cSgd78059 	    &ccnt) != DDI_DMA_MAPPED) {
1981*1959748cSgd78059 		ddi_dma_mem_free(&rxb->rxb_acch);
1982*1959748cSgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
1983*1959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
1984*1959748cSgd78059 		return (NULL);
1985*1959748cSgd78059 	}
1986*1959748cSgd78059 	rxb->rxb_paddr = dmac.dmac_address;
1987*1959748cSgd78059 
1988*1959748cSgd78059 	return (rxb);
1989*1959748cSgd78059 }
1990*1959748cSgd78059 
1991*1959748cSgd78059 void
1992*1959748cSgd78059 afe_destroyrxbuf(afe_rxbuf_t *rxb)
1993*1959748cSgd78059 {
1994*1959748cSgd78059 	if (rxb) {
1995*1959748cSgd78059 		(void) ddi_dma_unbind_handle(rxb->rxb_dmah);
1996*1959748cSgd78059 		ddi_dma_mem_free(&rxb->rxb_acch);
1997*1959748cSgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
1998*1959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
1999*1959748cSgd78059 	}
2000*1959748cSgd78059 }
2001*1959748cSgd78059 
2002*1959748cSgd78059 /*
2003*1959748cSgd78059  * Allocate receive resources.
2004*1959748cSgd78059  */
2005*1959748cSgd78059 int
2006*1959748cSgd78059 afe_allocrxring(afe_t *afep)
2007*1959748cSgd78059 {
2008*1959748cSgd78059 	int			rval;
2009*1959748cSgd78059 	int			i;
2010*1959748cSgd78059 	size_t			size;
2011*1959748cSgd78059 	size_t			len;
2012*1959748cSgd78059 	ddi_dma_cookie_t	dmac;
2013*1959748cSgd78059 	unsigned		ncookies;
2014*1959748cSgd78059 	caddr_t			kaddr;
2015*1959748cSgd78059 
2016*1959748cSgd78059 	size = AFE_RXRING * sizeof (afe_desc_t);
2017*1959748cSgd78059 
2018*1959748cSgd78059 	rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
2019*1959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &afep->afe_rxdesc_dmah);
2020*1959748cSgd78059 	if (rval != DDI_SUCCESS) {
2021*1959748cSgd78059 		afe_error(afep->afe_dip,
2022*1959748cSgd78059 		    "unable to allocate DMA handle for rx descriptors");
2023*1959748cSgd78059 		return (DDI_FAILURE);
2024*1959748cSgd78059 	}
2025*1959748cSgd78059 
2026*1959748cSgd78059 	rval = ddi_dma_mem_alloc(afep->afe_rxdesc_dmah, size, &afe_devattr,
2027*1959748cSgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
2028*1959748cSgd78059 	    &afep->afe_rxdesc_acch);
2029*1959748cSgd78059 	if (rval != DDI_SUCCESS) {
2030*1959748cSgd78059 		afe_error(afep->afe_dip,
2031*1959748cSgd78059 		    "unable to allocate DMA memory for rx descriptors");
2032*1959748cSgd78059 		return (DDI_FAILURE);
2033*1959748cSgd78059 	}
2034*1959748cSgd78059 
2035*1959748cSgd78059 	rval = ddi_dma_addr_bind_handle(afep->afe_rxdesc_dmah, NULL, kaddr,
2036*1959748cSgd78059 	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
2037*1959748cSgd78059 	    &dmac, &ncookies);
2038*1959748cSgd78059 	if (rval != DDI_DMA_MAPPED) {
2039*1959748cSgd78059 		afe_error(afep->afe_dip,
2040*1959748cSgd78059 		    "unable to bind DMA for rx descriptors");
2041*1959748cSgd78059 		return (DDI_FAILURE);
2042*1959748cSgd78059 	}
2043*1959748cSgd78059 
2044*1959748cSgd78059 	/* because of afe_dma_attr */
2045*1959748cSgd78059 	ASSERT(ncookies == 1);
2046*1959748cSgd78059 
2047*1959748cSgd78059 	/* we take the 32-bit physical address out of the cookie */
2048*1959748cSgd78059 	afep->afe_rxdesc_paddr = dmac.dmac_address;
2049*1959748cSgd78059 	afep->afe_rxdescp = (void *)kaddr;
2050*1959748cSgd78059 
2051*1959748cSgd78059 	/* allocate buffer pointers (not the buffers themselves, yet) */
2052*1959748cSgd78059 	afep->afe_rxbufs = kmem_zalloc(AFE_RXRING * sizeof (afe_rxbuf_t *),
2053*1959748cSgd78059 	    KM_SLEEP);
2054*1959748cSgd78059 
2055*1959748cSgd78059 	/* now allocate rx buffers */
2056*1959748cSgd78059 	for (i = 0; i < AFE_RXRING; i++) {
2057*1959748cSgd78059 		afe_rxbuf_t *rxb = afe_allocrxbuf(afep);
2058*1959748cSgd78059 		if (rxb == NULL)
2059*1959748cSgd78059 			return (DDI_FAILURE);
2060*1959748cSgd78059 		afep->afe_rxbufs[i] = rxb;
2061*1959748cSgd78059 	}
2062*1959748cSgd78059 
2063*1959748cSgd78059 	return (DDI_SUCCESS);
2064*1959748cSgd78059 }
2065*1959748cSgd78059 
2066*1959748cSgd78059 /*
2067*1959748cSgd78059  * Allocate transmit resources.
2068*1959748cSgd78059  */
2069*1959748cSgd78059 int
2070*1959748cSgd78059 afe_alloctxring(afe_t *afep)
2071*1959748cSgd78059 {
2072*1959748cSgd78059 	int			rval;
2073*1959748cSgd78059 	int			i;
2074*1959748cSgd78059 	size_t			size;
2075*1959748cSgd78059 	size_t			len;
2076*1959748cSgd78059 	ddi_dma_cookie_t	dmac;
2077*1959748cSgd78059 	unsigned		ncookies;
2078*1959748cSgd78059 	caddr_t			kaddr;
2079*1959748cSgd78059 
2080*1959748cSgd78059 	size = AFE_TXRING * sizeof (afe_desc_t);
2081*1959748cSgd78059 
2082*1959748cSgd78059 	rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
2083*1959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &afep->afe_txdesc_dmah);
2084*1959748cSgd78059 	if (rval != DDI_SUCCESS) {
2085*1959748cSgd78059 		afe_error(afep->afe_dip,
2086*1959748cSgd78059 		    "unable to allocate DMA handle for tx descriptors");
2087*1959748cSgd78059 		return (DDI_FAILURE);
2088*1959748cSgd78059 	}
2089*1959748cSgd78059 
2090*1959748cSgd78059 	rval = ddi_dma_mem_alloc(afep->afe_txdesc_dmah, size, &afe_devattr,
2091*1959748cSgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
2092*1959748cSgd78059 	    &afep->afe_txdesc_acch);
2093*1959748cSgd78059 	if (rval != DDI_SUCCESS) {
2094*1959748cSgd78059 		afe_error(afep->afe_dip,
2095*1959748cSgd78059 		    "unable to allocate DMA memory for tx descriptors");
2096*1959748cSgd78059 		return (DDI_FAILURE);
2097*1959748cSgd78059 	}
2098*1959748cSgd78059 
2099*1959748cSgd78059 	rval = ddi_dma_addr_bind_handle(afep->afe_txdesc_dmah, NULL, kaddr,
2100*1959748cSgd78059 	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
2101*1959748cSgd78059 	    &dmac, &ncookies);
2102*1959748cSgd78059 	if (rval != DDI_DMA_MAPPED) {
2103*1959748cSgd78059 		afe_error(afep->afe_dip,
2104*1959748cSgd78059 		    "unable to bind DMA for tx descriptors");
2105*1959748cSgd78059 		return (DDI_FAILURE);
2106*1959748cSgd78059 	}
2107*1959748cSgd78059 
2108*1959748cSgd78059 	/* because of afe_dma_attr */
2109*1959748cSgd78059 	ASSERT(ncookies == 1);
2110*1959748cSgd78059 
2111*1959748cSgd78059 	/* we take the 32-bit physical address out of the cookie */
2112*1959748cSgd78059 	afep->afe_txdesc_paddr = dmac.dmac_address;
2113*1959748cSgd78059 	afep->afe_txdescp = (void *)kaddr;
2114*1959748cSgd78059 
2115*1959748cSgd78059 	/* allocate buffer pointers (not the buffers themselves, yet) */
2116*1959748cSgd78059 	afep->afe_txbufs = kmem_zalloc(AFE_TXRING * sizeof (afe_txbuf_t *),
2117*1959748cSgd78059 	    KM_SLEEP);
2118*1959748cSgd78059 
2119*1959748cSgd78059 	/* now allocate tx buffers */
2120*1959748cSgd78059 	for (i = 0; i < AFE_TXRING; i++) {
2121*1959748cSgd78059 		afe_txbuf_t *txb = afe_alloctxbuf(afep);
2122*1959748cSgd78059 		if (txb == NULL)
2123*1959748cSgd78059 			return (DDI_FAILURE);
2124*1959748cSgd78059 		afep->afe_txbufs[i] = txb;
2125*1959748cSgd78059 	}
2126*1959748cSgd78059 
2127*1959748cSgd78059 	return (DDI_SUCCESS);
2128*1959748cSgd78059 }
2129*1959748cSgd78059 
2130*1959748cSgd78059 void
2131*1959748cSgd78059 afe_freerxring(afe_t *afep)
2132*1959748cSgd78059 {
2133*1959748cSgd78059 	int		i;
2134*1959748cSgd78059 
2135*1959748cSgd78059 	for (i = 0; i < AFE_RXRING; i++) {
2136*1959748cSgd78059 		afe_destroyrxbuf(afep->afe_rxbufs[i]);
2137*1959748cSgd78059 	}
2138*1959748cSgd78059 
2139*1959748cSgd78059 	if (afep->afe_rxbufs) {
2140*1959748cSgd78059 		kmem_free(afep->afe_rxbufs,
2141*1959748cSgd78059 		    AFE_RXRING * sizeof (afe_rxbuf_t *));
2142*1959748cSgd78059 	}
2143*1959748cSgd78059 
2144*1959748cSgd78059 	if (afep->afe_rxdesc_paddr)
2145*1959748cSgd78059 		(void) ddi_dma_unbind_handle(afep->afe_rxdesc_dmah);
2146*1959748cSgd78059 	if (afep->afe_rxdesc_acch)
2147*1959748cSgd78059 		ddi_dma_mem_free(&afep->afe_rxdesc_acch);
2148*1959748cSgd78059 	if (afep->afe_rxdesc_dmah)
2149*1959748cSgd78059 		ddi_dma_free_handle(&afep->afe_rxdesc_dmah);
2150*1959748cSgd78059 }
2151*1959748cSgd78059 
2152*1959748cSgd78059 void
2153*1959748cSgd78059 afe_freetxring(afe_t *afep)
2154*1959748cSgd78059 {
2155*1959748cSgd78059 	int			i;
2156*1959748cSgd78059 
2157*1959748cSgd78059 	for (i = 0; i < AFE_TXRING; i++) {
2158*1959748cSgd78059 		afe_destroytxbuf(afep->afe_txbufs[i]);
2159*1959748cSgd78059 	}
2160*1959748cSgd78059 
2161*1959748cSgd78059 	if (afep->afe_txbufs) {
2162*1959748cSgd78059 		kmem_free(afep->afe_txbufs,
2163*1959748cSgd78059 		    AFE_TXRING * sizeof (afe_txbuf_t *));
2164*1959748cSgd78059 	}
2165*1959748cSgd78059 	if (afep->afe_txdesc_paddr)
2166*1959748cSgd78059 		(void) ddi_dma_unbind_handle(afep->afe_txdesc_dmah);
2167*1959748cSgd78059 	if (afep->afe_txdesc_acch)
2168*1959748cSgd78059 		ddi_dma_mem_free(&afep->afe_txdesc_acch);
2169*1959748cSgd78059 	if (afep->afe_txdesc_dmah)
2170*1959748cSgd78059 		ddi_dma_free_handle(&afep->afe_txdesc_dmah);
2171*1959748cSgd78059 }
2172*1959748cSgd78059 
2173*1959748cSgd78059 /*
2174*1959748cSgd78059  * Interrupt service routine.
2175*1959748cSgd78059  */
2176*1959748cSgd78059 unsigned
2177*1959748cSgd78059 afe_intr(caddr_t arg)
2178*1959748cSgd78059 {
2179*1959748cSgd78059 	afe_t		*afep = (void *)arg;
2180*1959748cSgd78059 	uint32_t	status;
2181*1959748cSgd78059 	mblk_t		*mp = NULL;
2182*1959748cSgd78059 
2183*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
2184*1959748cSgd78059 
2185*1959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
2186*1959748cSgd78059 		/* we cannot receive interrupts! */
2187*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
2188*1959748cSgd78059 		return (DDI_INTR_UNCLAIMED);
2189*1959748cSgd78059 	}
2190*1959748cSgd78059 
2191*1959748cSgd78059 	/* check interrupt status bits, did we interrupt? */
2192*1959748cSgd78059 	status = GETCSR(afep, CSR_SR2) & INT_ALL;
2193*1959748cSgd78059 
2194*1959748cSgd78059 	if (status == 0) {
2195*1959748cSgd78059 		KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
2196*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
2197*1959748cSgd78059 		return (DDI_INTR_UNCLAIMED);
2198*1959748cSgd78059 	}
2199*1959748cSgd78059 	/* ack the interrupt */
2200*1959748cSgd78059 	PUTCSR(afep, CSR_SR2, status);
2201*1959748cSgd78059 	KIOIP->intrs[KSTAT_INTR_HARD]++;
2202*1959748cSgd78059 
2203*1959748cSgd78059 	if (!(afep->afe_flags & AFE_RUNNING)) {
2204*1959748cSgd78059 		/* not running, don't touch anything */
2205*1959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
2206*1959748cSgd78059 		return (DDI_INTR_CLAIMED);
2207*1959748cSgd78059 	}
2208*1959748cSgd78059 
2209*1959748cSgd78059 	if (status & (INT_RXOK|INT_RXNOBUF)) {
2210*1959748cSgd78059 		/* receive packets */
2211*1959748cSgd78059 		mp = afe_receive(afep);
2212*1959748cSgd78059 		if (status & INT_RXNOBUF)
2213*1959748cSgd78059 			PUTCSR(afep, CSR_RDR, 0);	/* wake up chip */
2214*1959748cSgd78059 	}
2215*1959748cSgd78059 
2216*1959748cSgd78059 	if (status & INT_TXOK) {
2217*1959748cSgd78059 		/* transmit completed */
2218*1959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
2219*1959748cSgd78059 		afe_reclaim(afep);
2220*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
2221*1959748cSgd78059 	}
2222*1959748cSgd78059 
2223*1959748cSgd78059 	if (status & (INT_LINKCHG|INT_TIMER)) {
2224*1959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
2225*1959748cSgd78059 		afe_checklink(afep);
2226*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
2227*1959748cSgd78059 	}
2228*1959748cSgd78059 
2229*1959748cSgd78059 	if (status & (INT_RXSTOPPED|INT_TXSTOPPED|
2230*1959748cSgd78059 	    INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) {
2231*1959748cSgd78059 
2232*1959748cSgd78059 		if (status & (INT_RXJABBER | INT_TXJABBER)) {
2233*1959748cSgd78059 			afep->afe_jabber++;
2234*1959748cSgd78059 		}
2235*1959748cSgd78059 		DBG(DWARN, "resetting mac, status %x", status);
2236*1959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
2237*1959748cSgd78059 		afe_resetall(afep);
2238*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
2239*1959748cSgd78059 	}
2240*1959748cSgd78059 
2241*1959748cSgd78059 	if (status & INT_BUSERR) {
2242*1959748cSgd78059 		switch (GETCSR(afep, CSR_SR) & SR_BERR_TYPE) {
2243*1959748cSgd78059 		case SR_BERR_PARITY:
2244*1959748cSgd78059 			afe_error(afep->afe_dip, "PCI parity error");
2245*1959748cSgd78059 			break;
2246*1959748cSgd78059 		case SR_BERR_TARGET_ABORT:
2247*1959748cSgd78059 			afe_error(afep->afe_dip, "PCI target abort");
2248*1959748cSgd78059 			break;
2249*1959748cSgd78059 		case SR_BERR_MASTER_ABORT:
2250*1959748cSgd78059 			afe_error(afep->afe_dip, "PCI master abort");
2251*1959748cSgd78059 			break;
2252*1959748cSgd78059 		default:
2253*1959748cSgd78059 			afe_error(afep->afe_dip, "Unknown PCI error");
2254*1959748cSgd78059 			break;
2255*1959748cSgd78059 		}
2256*1959748cSgd78059 
2257*1959748cSgd78059 		/* reset the chip in an attempt to fix things */
2258*1959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
2259*1959748cSgd78059 		afe_resetall(afep);
2260*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
2261*1959748cSgd78059 	}
2262*1959748cSgd78059 
2263*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
2264*1959748cSgd78059 
2265*1959748cSgd78059 	/*
2266*1959748cSgd78059 	 * Send up packets.  We do this outside of the intrlock.
2267*1959748cSgd78059 	 */
2268*1959748cSgd78059 	if (mp) {
2269*1959748cSgd78059 		mac_rx(afep->afe_mh, NULL, mp);
2270*1959748cSgd78059 	}
2271*1959748cSgd78059 
2272*1959748cSgd78059 	return (DDI_INTR_CLAIMED);
2273*1959748cSgd78059 }
2274*1959748cSgd78059 
2275*1959748cSgd78059 void
2276*1959748cSgd78059 afe_enableinterrupts(afe_t *afep)
2277*1959748cSgd78059 {
2278*1959748cSgd78059 	unsigned mask = INT_WANTED;
2279*1959748cSgd78059 
2280*1959748cSgd78059 	if (afep->afe_wantw)
2281*1959748cSgd78059 		mask |= INT_TXOK;
2282*1959748cSgd78059 
2283*1959748cSgd78059 	PUTCSR(afep, CSR_IER2, mask);
2284*1959748cSgd78059 
2285*1959748cSgd78059 	if (AFE_MODEL(afep) == MODEL_COMET) {
2286*1959748cSgd78059 		/*
2287*1959748cSgd78059 		 * On the Comet, this is the internal transceiver
2288*1959748cSgd78059 		 * interrupt.  We program the Comet's built-in PHY to
2289*1959748cSgd78059 		 * enable certain interrupts.
2290*1959748cSgd78059 		 */
2291*1959748cSgd78059 		PUTCSR16(afep, CSR_XIE, XIE_LDE | XIE_ANCE);
2292*1959748cSgd78059 	}
2293*1959748cSgd78059 }
2294*1959748cSgd78059 
2295*1959748cSgd78059 void
2296*1959748cSgd78059 afe_disableinterrupts(afe_t *afep)
2297*1959748cSgd78059 {
2298*1959748cSgd78059 	/* disable further interrupts */
2299*1959748cSgd78059 	PUTCSR(afep, CSR_IER2, INT_NONE);
2300*1959748cSgd78059 
2301*1959748cSgd78059 	/* clear any pending interrupts */
2302*1959748cSgd78059 	PUTCSR(afep, CSR_SR2, INT_ALL);
2303*1959748cSgd78059 }
2304*1959748cSgd78059 
2305*1959748cSgd78059 boolean_t
2306*1959748cSgd78059 afe_send(afe_t *afep, mblk_t *mp)
2307*1959748cSgd78059 {
2308*1959748cSgd78059 	size_t			len;
2309*1959748cSgd78059 	afe_txbuf_t		*txb;
2310*1959748cSgd78059 	afe_desc_t		*tmd;
2311*1959748cSgd78059 	uint32_t		control;
2312*1959748cSgd78059 	int			txsend;
2313*1959748cSgd78059 
2314*1959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
2315*1959748cSgd78059 	ASSERT(mp != NULL);
2316*1959748cSgd78059 
2317*1959748cSgd78059 	len = msgsize(mp);
2318*1959748cSgd78059 	if (len > ETHERVLANMTU) {
2319*1959748cSgd78059 		DBG(DXMIT, "frame too long: %d", len);
2320*1959748cSgd78059 		afep->afe_macxmt_errors++;
2321*1959748cSgd78059 		freemsg(mp);
2322*1959748cSgd78059 		return (B_TRUE);
2323*1959748cSgd78059 	}
2324*1959748cSgd78059 
2325*1959748cSgd78059 	if (afep->afe_txavail < AFE_TXRECLAIM)
2326*1959748cSgd78059 		afe_reclaim(afep);
2327*1959748cSgd78059 
2328*1959748cSgd78059 	if (afep->afe_txavail == 0) {
2329*1959748cSgd78059 		/* no more tmds */
2330*1959748cSgd78059 		afep->afe_wantw = B_TRUE;
2331*1959748cSgd78059 		/* enable TX interrupt */
2332*1959748cSgd78059 		afe_enableinterrupts(afep);
2333*1959748cSgd78059 		return (B_FALSE);
2334*1959748cSgd78059 	}
2335*1959748cSgd78059 
2336*1959748cSgd78059 	txsend = afep->afe_txsend;
2337*1959748cSgd78059 
2338*1959748cSgd78059 	/*
2339*1959748cSgd78059 	 * For simplicity, we just do a copy into a preallocated
2340*1959748cSgd78059 	 * DMA buffer.
2341*1959748cSgd78059 	 */
2342*1959748cSgd78059 
2343*1959748cSgd78059 	txb = afep->afe_txbufs[txsend];
2344*1959748cSgd78059 	mcopymsg(mp, txb->txb_buf);	/* frees mp! */
2345*1959748cSgd78059 
2346*1959748cSgd78059 	/*
2347*1959748cSgd78059 	 * Statistics.
2348*1959748cSgd78059 	 */
2349*1959748cSgd78059 	afep->afe_opackets++;
2350*1959748cSgd78059 	afep->afe_obytes += len;
2351*1959748cSgd78059 	if (txb->txb_buf[0] & 0x1) {
2352*1959748cSgd78059 		if (bcmp(txb->txb_buf, afe_broadcast, ETHERADDRL) != 0)
2353*1959748cSgd78059 			afep->afe_multixmt++;
2354*1959748cSgd78059 		else
2355*1959748cSgd78059 			afep->afe_brdcstxmt++;
2356*1959748cSgd78059 	}
2357*1959748cSgd78059 
2358*1959748cSgd78059 	/* note len is already known to be a small unsigned */
2359*1959748cSgd78059 	control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE;
2360*1959748cSgd78059 
2361*1959748cSgd78059 	if (txsend == (AFE_TXRING - 1))
2362*1959748cSgd78059 		control |= TXCTL_ENDRING;
2363*1959748cSgd78059 
2364*1959748cSgd78059 	tmd = &afep->afe_txdescp[txsend];
2365*1959748cSgd78059 
2366*1959748cSgd78059 	SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV);
2367*1959748cSgd78059 	PUTTXDESC(afep, tmd->desc_control, control);
2368*1959748cSgd78059 	PUTTXDESC(afep, tmd->desc_buffer1, txb->txb_paddr);
2369*1959748cSgd78059 	PUTTXDESC(afep, tmd->desc_buffer2, 0);
2370*1959748cSgd78059 	PUTTXDESC(afep, tmd->desc_status, TXSTAT_OWN);
2371*1959748cSgd78059 	/* sync the descriptor out to the device */
2372*1959748cSgd78059 	SYNCTXDESC(afep, txsend, DDI_DMA_SYNC_FORDEV);
2373*1959748cSgd78059 
2374*1959748cSgd78059 	/*
2375*1959748cSgd78059 	 * Note the new values of txavail and txsend.
2376*1959748cSgd78059 	 */
2377*1959748cSgd78059 	afep->afe_txavail--;
2378*1959748cSgd78059 	afep->afe_txsend = (txsend + 1) % AFE_TXRING;
2379*1959748cSgd78059 
2380*1959748cSgd78059 	/*
2381*1959748cSgd78059 	 * It should never, ever take more than 5 seconds to drain
2382*1959748cSgd78059 	 * the ring.  If it happens, then we are stuck!
2383*1959748cSgd78059 	 */
2384*1959748cSgd78059 	afep->afe_txstall_time = gethrtime() + (5 * 1000000000ULL);
2385*1959748cSgd78059 
2386*1959748cSgd78059 	/*
2387*1959748cSgd78059 	 * wake up the chip ... inside the lock to protect against DR suspend,
2388*1959748cSgd78059 	 * etc.
2389*1959748cSgd78059 	 */
2390*1959748cSgd78059 	PUTCSR(afep, CSR_TDR, 0);
2391*1959748cSgd78059 
2392*1959748cSgd78059 	return (B_TRUE);
2393*1959748cSgd78059 }
2394*1959748cSgd78059 
2395*1959748cSgd78059 /*
2396*1959748cSgd78059  * Reclaim buffers that have completed transmission.
2397*1959748cSgd78059  */
2398*1959748cSgd78059 void
2399*1959748cSgd78059 afe_reclaim(afe_t *afep)
2400*1959748cSgd78059 {
2401*1959748cSgd78059 	afe_desc_t	*tmdp;
2402*1959748cSgd78059 
2403*1959748cSgd78059 	while (afep->afe_txavail != AFE_TXRING) {
2404*1959748cSgd78059 		uint32_t	status;
2405*1959748cSgd78059 		uint32_t	control;
2406*1959748cSgd78059 		int		index = afep->afe_txreclaim;
2407*1959748cSgd78059 
2408*1959748cSgd78059 		tmdp = &afep->afe_txdescp[index];
2409*1959748cSgd78059 
2410*1959748cSgd78059 		/* sync it before we read it */
2411*1959748cSgd78059 		SYNCTXDESC(afep, index, DDI_DMA_SYNC_FORKERNEL);
2412*1959748cSgd78059 
2413*1959748cSgd78059 		control = GETTXDESC(afep, tmdp->desc_control);
2414*1959748cSgd78059 		status = GETTXDESC(afep, tmdp->desc_status);
2415*1959748cSgd78059 
2416*1959748cSgd78059 		if (status & TXSTAT_OWN) {
2417*1959748cSgd78059 			/* chip is still working on it, we're done */
2418*1959748cSgd78059 			break;
2419*1959748cSgd78059 		}
2420*1959748cSgd78059 
2421*1959748cSgd78059 		afep->afe_txavail++;
2422*1959748cSgd78059 		afep->afe_txreclaim = (index + 1) % AFE_TXRING;
2423*1959748cSgd78059 
2424*1959748cSgd78059 		/* in the most common successful case, all bits are clear */
2425*1959748cSgd78059 		if (status == 0)
2426*1959748cSgd78059 			continue;
2427*1959748cSgd78059 
2428*1959748cSgd78059 		if ((control & TXCTL_LAST) == 0)
2429*1959748cSgd78059 			continue;
2430*1959748cSgd78059 
2431*1959748cSgd78059 		if (status & TXSTAT_TXERR) {
2432*1959748cSgd78059 			afep->afe_errxmt++;
2433*1959748cSgd78059 
2434*1959748cSgd78059 			if (status & TXSTAT_JABBER) {
2435*1959748cSgd78059 				/* transmit jabber timeout */
2436*1959748cSgd78059 				afep->afe_macxmt_errors++;
2437*1959748cSgd78059 			}
2438*1959748cSgd78059 			if (status &
2439*1959748cSgd78059 			    (TXSTAT_CARRLOST | TXSTAT_NOCARR)) {
2440*1959748cSgd78059 				afep->afe_carrier_errors++;
2441*1959748cSgd78059 			}
2442*1959748cSgd78059 			if (status & TXSTAT_UFLOW) {
2443*1959748cSgd78059 				afep->afe_underflow++;
2444*1959748cSgd78059 			}
2445*1959748cSgd78059 			if (status & TXSTAT_LATECOL) {
2446*1959748cSgd78059 				afep->afe_tx_late_collisions++;
2447*1959748cSgd78059 			}
2448*1959748cSgd78059 			if (status & TXSTAT_EXCOLL) {
2449*1959748cSgd78059 				afep->afe_ex_collisions++;
2450*1959748cSgd78059 				afep->afe_collisions += 16;
2451*1959748cSgd78059 			}
2452*1959748cSgd78059 		}
2453*1959748cSgd78059 
2454*1959748cSgd78059 		if (status & TXSTAT_DEFER) {
2455*1959748cSgd78059 			afep->afe_defer_xmts++;
2456*1959748cSgd78059 		}
2457*1959748cSgd78059 
2458*1959748cSgd78059 		/* collision counting */
2459*1959748cSgd78059 		if (TXCOLLCNT(status) == 1) {
2460*1959748cSgd78059 			afep->afe_collisions++;
2461*1959748cSgd78059 			afep->afe_first_collisions++;
2462*1959748cSgd78059 		} else if (TXCOLLCNT(status)) {
2463*1959748cSgd78059 			afep->afe_collisions += TXCOLLCNT(status);
2464*1959748cSgd78059 			afep->afe_multi_collisions += TXCOLLCNT(status);
2465*1959748cSgd78059 		}
2466*1959748cSgd78059 	}
2467*1959748cSgd78059 
2468*1959748cSgd78059 	if (afep->afe_txavail >= AFE_TXRESCHED) {
2469*1959748cSgd78059 		if (afep->afe_wantw) {
2470*1959748cSgd78059 			/*
2471*1959748cSgd78059 			 * we were able to reclaim some packets, so
2472*1959748cSgd78059 			 * disable tx interrupts
2473*1959748cSgd78059 			 */
2474*1959748cSgd78059 			afep->afe_wantw = B_FALSE;
2475*1959748cSgd78059 			afe_enableinterrupts(afep);
2476*1959748cSgd78059 			mac_tx_update(afep->afe_mh);
2477*1959748cSgd78059 		}
2478*1959748cSgd78059 	}
2479*1959748cSgd78059 }
2480*1959748cSgd78059 
2481*1959748cSgd78059 mblk_t *
2482*1959748cSgd78059 afe_receive(afe_t *afep)
2483*1959748cSgd78059 {
2484*1959748cSgd78059 	unsigned		len;
2485*1959748cSgd78059 	afe_rxbuf_t		*rxb;
2486*1959748cSgd78059 	afe_desc_t		*rmd;
2487*1959748cSgd78059 	uint32_t		status;
2488*1959748cSgd78059 	mblk_t			*mpchain, **mpp, *mp;
2489*1959748cSgd78059 	int			head, cnt;
2490*1959748cSgd78059 
2491*1959748cSgd78059 	mpchain = NULL;
2492*1959748cSgd78059 	mpp = &mpchain;
2493*1959748cSgd78059 	head = afep->afe_rxhead;
2494*1959748cSgd78059 
2495*1959748cSgd78059 	/* limit the number of packets we process to a half ring size */
2496*1959748cSgd78059 	for (cnt = 0; cnt < AFE_RXRING / 2; cnt++) {
2497*1959748cSgd78059 
2498*1959748cSgd78059 		DBG(DRECV, "receive at index %d", head);
2499*1959748cSgd78059 
2500*1959748cSgd78059 		rmd = &afep->afe_rxdescp[head];
2501*1959748cSgd78059 		rxb = afep->afe_rxbufs[head];
2502*1959748cSgd78059 
2503*1959748cSgd78059 		SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORKERNEL);
2504*1959748cSgd78059 		status = GETRXDESC(afep, rmd->desc_status);
2505*1959748cSgd78059 		if (status & RXSTAT_OWN) {
2506*1959748cSgd78059 			/* chip is still chewing on it */
2507*1959748cSgd78059 			break;
2508*1959748cSgd78059 		}
2509*1959748cSgd78059 
2510*1959748cSgd78059 		/* discard the ethernet frame checksum */
2511*1959748cSgd78059 		len = RXLENGTH(status) - ETHERFCSL;
2512*1959748cSgd78059 
2513*1959748cSgd78059 		DBG(DRECV, "recv length %d, status %x", len, status);
2514*1959748cSgd78059 
2515*1959748cSgd78059 		if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) !=
2516*1959748cSgd78059 		    (RXSTAT_FIRST | RXSTAT_LAST)) {
2517*1959748cSgd78059 
2518*1959748cSgd78059 			afep->afe_errrcv++;
2519*1959748cSgd78059 
2520*1959748cSgd78059 			/*
2521*1959748cSgd78059 			 * Abnormal status bits detected, analyze further.
2522*1959748cSgd78059 			 */
2523*1959748cSgd78059 			if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) !=
2524*1959748cSgd78059 			    (RXSTAT_LAST|RXSTAT_FIRST)) {
2525*1959748cSgd78059 				DBG(DRECV, "rx packet overspill");
2526*1959748cSgd78059 				if (status & RXSTAT_FIRST) {
2527*1959748cSgd78059 					afep->afe_toolong_errors++;
2528*1959748cSgd78059 				}
2529*1959748cSgd78059 			} else if (status & RXSTAT_DESCERR) {
2530*1959748cSgd78059 				afep->afe_macrcv_errors++;
2531*1959748cSgd78059 
2532*1959748cSgd78059 			} else if (status & RXSTAT_RUNT) {
2533*1959748cSgd78059 				afep->afe_runt++;
2534*1959748cSgd78059 
2535*1959748cSgd78059 			} else if (status & RXSTAT_COLLSEEN) {
2536*1959748cSgd78059 				/* this should really be rx_late_collisions */
2537*1959748cSgd78059 				afep->afe_macrcv_errors++;
2538*1959748cSgd78059 
2539*1959748cSgd78059 			} else if (status & RXSTAT_DRIBBLE) {
2540*1959748cSgd78059 				afep->afe_align_errors++;
2541*1959748cSgd78059 
2542*1959748cSgd78059 			} else if (status & RXSTAT_CRCERR) {
2543*1959748cSgd78059 				afep->afe_fcs_errors++;
2544*1959748cSgd78059 
2545*1959748cSgd78059 			} else if (status & RXSTAT_OFLOW) {
2546*1959748cSgd78059 				afep->afe_overflow++;
2547*1959748cSgd78059 			}
2548*1959748cSgd78059 		}
2549*1959748cSgd78059 
2550*1959748cSgd78059 		else if (len > ETHERVLANMTU) {
2551*1959748cSgd78059 			afep->afe_errrcv++;
2552*1959748cSgd78059 			afep->afe_toolong_errors++;
2553*1959748cSgd78059 		}
2554*1959748cSgd78059 
2555*1959748cSgd78059 		/*
2556*1959748cSgd78059 		 * At this point, the chip thinks the packet is OK.
2557*1959748cSgd78059 		 */
2558*1959748cSgd78059 		else {
2559*1959748cSgd78059 			mp = allocb(len + AFE_HEADROOM, 0);
2560*1959748cSgd78059 			if (mp == NULL) {
2561*1959748cSgd78059 				afep->afe_errrcv++;
2562*1959748cSgd78059 				afep->afe_norcvbuf++;
2563*1959748cSgd78059 				goto skip;
2564*1959748cSgd78059 			}
2565*1959748cSgd78059 
2566*1959748cSgd78059 			/* sync the buffer before we look at it */
2567*1959748cSgd78059 			SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
2568*1959748cSgd78059 			mp->b_rptr += AFE_HEADROOM;
2569*1959748cSgd78059 			mp->b_wptr = mp->b_rptr + len;
2570*1959748cSgd78059 			bcopy((char *)rxb->rxb_buf, mp->b_rptr, len);
2571*1959748cSgd78059 
2572*1959748cSgd78059 			afep->afe_ipackets++;
2573*1959748cSgd78059 			afep->afe_rbytes += len;
2574*1959748cSgd78059 			if (status & RXSTAT_GROUP) {
2575*1959748cSgd78059 				if (bcmp(mp->b_rptr, afe_broadcast,
2576*1959748cSgd78059 				    ETHERADDRL) == 0)
2577*1959748cSgd78059 					afep->afe_brdcstrcv++;
2578*1959748cSgd78059 				else
2579*1959748cSgd78059 					afep->afe_multircv++;
2580*1959748cSgd78059 			}
2581*1959748cSgd78059 			*mpp = mp;
2582*1959748cSgd78059 			mpp = &mp->b_next;
2583*1959748cSgd78059 		}
2584*1959748cSgd78059 
2585*1959748cSgd78059 skip:
2586*1959748cSgd78059 		/* return ring entry to the hardware */
2587*1959748cSgd78059 		PUTRXDESC(afep, rmd->desc_status, RXSTAT_OWN);
2588*1959748cSgd78059 		SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORDEV);
2589*1959748cSgd78059 
2590*1959748cSgd78059 		/* advance to next RMD */
2591*1959748cSgd78059 		head = (head + 1) % AFE_RXRING;
2592*1959748cSgd78059 	}
2593*1959748cSgd78059 
2594*1959748cSgd78059 	afep->afe_rxhead = head;
2595*1959748cSgd78059 
2596*1959748cSgd78059 	return (mpchain);
2597*1959748cSgd78059 }
2598*1959748cSgd78059 
2599*1959748cSgd78059 int
2600*1959748cSgd78059 afe_getmiibit(afe_t *afep, uint16_t reg, uint16_t bit)
2601*1959748cSgd78059 {
2602*1959748cSgd78059 	unsigned	val;
2603*1959748cSgd78059 
2604*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
2605*1959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
2606*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
2607*1959748cSgd78059 		/* device is suspended */
2608*1959748cSgd78059 		return (0);
2609*1959748cSgd78059 	}
2610*1959748cSgd78059 	val = afe_miiread(afep, afep->afe_phyaddr, reg);
2611*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
2612*1959748cSgd78059 
2613*1959748cSgd78059 	return (val & bit ? 1 : 0);
2614*1959748cSgd78059 }
2615*1959748cSgd78059 #define	GETMIIBIT(reg, bit) afe_getmiibit(afep, reg, bit)
2616*1959748cSgd78059 
2617*1959748cSgd78059 int
2618*1959748cSgd78059 afe_m_stat(void *arg, uint_t stat, uint64_t *val)
2619*1959748cSgd78059 {
2620*1959748cSgd78059 	afe_t	*afep = arg;
2621*1959748cSgd78059 
2622*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
2623*1959748cSgd78059 	if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) == AFE_RUNNING)
2624*1959748cSgd78059 		afe_reclaim(afep);
2625*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
2626*1959748cSgd78059 
2627*1959748cSgd78059 	switch (stat) {
2628*1959748cSgd78059 	case MAC_STAT_IFSPEED:
2629*1959748cSgd78059 		*val = afep->afe_ifspeed;
2630*1959748cSgd78059 		break;
2631*1959748cSgd78059 
2632*1959748cSgd78059 	case MAC_STAT_MULTIRCV:
2633*1959748cSgd78059 		*val = afep->afe_multircv;
2634*1959748cSgd78059 		break;
2635*1959748cSgd78059 
2636*1959748cSgd78059 	case MAC_STAT_BRDCSTRCV:
2637*1959748cSgd78059 		*val = afep->afe_brdcstrcv;
2638*1959748cSgd78059 		break;
2639*1959748cSgd78059 
2640*1959748cSgd78059 	case MAC_STAT_MULTIXMT:
2641*1959748cSgd78059 		*val = afep->afe_multixmt;
2642*1959748cSgd78059 		break;
2643*1959748cSgd78059 
2644*1959748cSgd78059 	case MAC_STAT_BRDCSTXMT:
2645*1959748cSgd78059 		*val = afep->afe_brdcstxmt;
2646*1959748cSgd78059 		break;
2647*1959748cSgd78059 
2648*1959748cSgd78059 	case MAC_STAT_IPACKETS:
2649*1959748cSgd78059 		*val = afep->afe_ipackets;
2650*1959748cSgd78059 		break;
2651*1959748cSgd78059 
2652*1959748cSgd78059 	case MAC_STAT_RBYTES:
2653*1959748cSgd78059 		*val = afep->afe_rbytes;
2654*1959748cSgd78059 		break;
2655*1959748cSgd78059 
2656*1959748cSgd78059 	case MAC_STAT_OPACKETS:
2657*1959748cSgd78059 		*val = afep->afe_opackets;
2658*1959748cSgd78059 		break;
2659*1959748cSgd78059 
2660*1959748cSgd78059 	case MAC_STAT_OBYTES:
2661*1959748cSgd78059 		*val = afep->afe_obytes;
2662*1959748cSgd78059 		break;
2663*1959748cSgd78059 
2664*1959748cSgd78059 	case MAC_STAT_NORCVBUF:
2665*1959748cSgd78059 		*val = afep->afe_norcvbuf;
2666*1959748cSgd78059 		break;
2667*1959748cSgd78059 
2668*1959748cSgd78059 	case MAC_STAT_NOXMTBUF:
2669*1959748cSgd78059 		*val = 0;
2670*1959748cSgd78059 		break;
2671*1959748cSgd78059 
2672*1959748cSgd78059 	case MAC_STAT_COLLISIONS:
2673*1959748cSgd78059 		*val = afep->afe_collisions;
2674*1959748cSgd78059 		break;
2675*1959748cSgd78059 
2676*1959748cSgd78059 	case MAC_STAT_IERRORS:
2677*1959748cSgd78059 		*val = afep->afe_errrcv;
2678*1959748cSgd78059 		break;
2679*1959748cSgd78059 
2680*1959748cSgd78059 	case MAC_STAT_OERRORS:
2681*1959748cSgd78059 		*val = afep->afe_errxmt;
2682*1959748cSgd78059 		break;
2683*1959748cSgd78059 
2684*1959748cSgd78059 	case ETHER_STAT_LINK_DUPLEX:
2685*1959748cSgd78059 		*val = afep->afe_duplex;
2686*1959748cSgd78059 		break;
2687*1959748cSgd78059 
2688*1959748cSgd78059 	case ETHER_STAT_ALIGN_ERRORS:
2689*1959748cSgd78059 		*val = afep->afe_align_errors;
2690*1959748cSgd78059 		break;
2691*1959748cSgd78059 
2692*1959748cSgd78059 	case ETHER_STAT_FCS_ERRORS:
2693*1959748cSgd78059 		*val = afep->afe_fcs_errors;
2694*1959748cSgd78059 		break;
2695*1959748cSgd78059 
2696*1959748cSgd78059 	case ETHER_STAT_SQE_ERRORS:
2697*1959748cSgd78059 		*val = afep->afe_sqe_errors;
2698*1959748cSgd78059 		break;
2699*1959748cSgd78059 
2700*1959748cSgd78059 	case ETHER_STAT_DEFER_XMTS:
2701*1959748cSgd78059 		*val = afep->afe_defer_xmts;
2702*1959748cSgd78059 		break;
2703*1959748cSgd78059 
2704*1959748cSgd78059 	case ETHER_STAT_FIRST_COLLISIONS:
2705*1959748cSgd78059 		*val = afep->afe_first_collisions;
2706*1959748cSgd78059 		break;
2707*1959748cSgd78059 
2708*1959748cSgd78059 	case ETHER_STAT_MULTI_COLLISIONS:
2709*1959748cSgd78059 		*val = afep->afe_multi_collisions;
2710*1959748cSgd78059 		break;
2711*1959748cSgd78059 
2712*1959748cSgd78059 	case ETHER_STAT_TX_LATE_COLLISIONS:
2713*1959748cSgd78059 		*val = afep->afe_tx_late_collisions;
2714*1959748cSgd78059 		break;
2715*1959748cSgd78059 
2716*1959748cSgd78059 	case ETHER_STAT_EX_COLLISIONS:
2717*1959748cSgd78059 		*val = afep->afe_ex_collisions;
2718*1959748cSgd78059 		break;
2719*1959748cSgd78059 
2720*1959748cSgd78059 	case ETHER_STAT_MACXMT_ERRORS:
2721*1959748cSgd78059 		*val = afep->afe_macxmt_errors;
2722*1959748cSgd78059 		break;
2723*1959748cSgd78059 
2724*1959748cSgd78059 	case ETHER_STAT_CARRIER_ERRORS:
2725*1959748cSgd78059 		*val = afep->afe_carrier_errors;
2726*1959748cSgd78059 		break;
2727*1959748cSgd78059 
2728*1959748cSgd78059 	case ETHER_STAT_TOOLONG_ERRORS:
2729*1959748cSgd78059 		*val = afep->afe_toolong_errors;
2730*1959748cSgd78059 		break;
2731*1959748cSgd78059 
2732*1959748cSgd78059 	case ETHER_STAT_MACRCV_ERRORS:
2733*1959748cSgd78059 		*val = afep->afe_macrcv_errors;
2734*1959748cSgd78059 		break;
2735*1959748cSgd78059 
2736*1959748cSgd78059 	case MAC_STAT_OVERFLOWS:
2737*1959748cSgd78059 		*val = afep->afe_overflow;
2738*1959748cSgd78059 		break;
2739*1959748cSgd78059 
2740*1959748cSgd78059 	case MAC_STAT_UNDERFLOWS:
2741*1959748cSgd78059 		*val = afep->afe_underflow;
2742*1959748cSgd78059 		break;
2743*1959748cSgd78059 
2744*1959748cSgd78059 	case ETHER_STAT_TOOSHORT_ERRORS:
2745*1959748cSgd78059 		*val = afep->afe_runt;
2746*1959748cSgd78059 		break;
2747*1959748cSgd78059 
2748*1959748cSgd78059 	case ETHER_STAT_JABBER_ERRORS:
2749*1959748cSgd78059 		*val = afep->afe_jabber;
2750*1959748cSgd78059 		break;
2751*1959748cSgd78059 
2752*1959748cSgd78059 	case ETHER_STAT_CAP_100T4:
2753*1959748cSgd78059 		*val = GETMIIBIT(MII_STATUS, MII_STATUS_100_BASE_T4);
2754*1959748cSgd78059 		break;
2755*1959748cSgd78059 
2756*1959748cSgd78059 	case ETHER_STAT_CAP_100FDX:
2757*1959748cSgd78059 		*val = GETMIIBIT(MII_STATUS, MII_STATUS_100_BASEX_FD);
2758*1959748cSgd78059 		break;
2759*1959748cSgd78059 
2760*1959748cSgd78059 	case ETHER_STAT_CAP_100HDX:
2761*1959748cSgd78059 		*val = GETMIIBIT(MII_STATUS, MII_STATUS_100_BASEX);
2762*1959748cSgd78059 		break;
2763*1959748cSgd78059 
2764*1959748cSgd78059 	case ETHER_STAT_CAP_10FDX:
2765*1959748cSgd78059 		*val = GETMIIBIT(MII_STATUS, MII_STATUS_10_FD);
2766*1959748cSgd78059 		break;
2767*1959748cSgd78059 
2768*1959748cSgd78059 	case ETHER_STAT_CAP_10HDX:
2769*1959748cSgd78059 		*val = GETMIIBIT(MII_STATUS, MII_STATUS_10);
2770*1959748cSgd78059 		break;
2771*1959748cSgd78059 
2772*1959748cSgd78059 	case ETHER_STAT_CAP_AUTONEG:
2773*1959748cSgd78059 		*val = GETMIIBIT(MII_STATUS, MII_STATUS_CANAUTONEG);
2774*1959748cSgd78059 		break;
2775*1959748cSgd78059 
2776*1959748cSgd78059 	case ETHER_STAT_LINK_AUTONEG:
2777*1959748cSgd78059 		*val = ((afep->afe_adv_aneg != 0) &&
2778*1959748cSgd78059 		    (GETMIIBIT(MII_AN_LPABLE, MII_AN_EXP_LPCANAN) != 0));
2779*1959748cSgd78059 		break;
2780*1959748cSgd78059 
2781*1959748cSgd78059 	case ETHER_STAT_ADV_CAP_100T4:
2782*1959748cSgd78059 		*val = afep->afe_adv_100T4;
2783*1959748cSgd78059 		break;
2784*1959748cSgd78059 
2785*1959748cSgd78059 	case ETHER_STAT_ADV_CAP_100FDX:
2786*1959748cSgd78059 		*val = afep->afe_adv_100fdx;
2787*1959748cSgd78059 		break;
2788*1959748cSgd78059 
2789*1959748cSgd78059 	case ETHER_STAT_ADV_CAP_100HDX:
2790*1959748cSgd78059 		*val = afep->afe_adv_100hdx;
2791*1959748cSgd78059 		break;
2792*1959748cSgd78059 
2793*1959748cSgd78059 	case ETHER_STAT_ADV_CAP_10FDX:
2794*1959748cSgd78059 		*val = afep->afe_adv_10fdx;
2795*1959748cSgd78059 		break;
2796*1959748cSgd78059 
2797*1959748cSgd78059 	case ETHER_STAT_ADV_CAP_10HDX:
2798*1959748cSgd78059 		*val = afep->afe_adv_10hdx;
2799*1959748cSgd78059 		break;
2800*1959748cSgd78059 
2801*1959748cSgd78059 	case ETHER_STAT_ADV_CAP_AUTONEG:
2802*1959748cSgd78059 		*val = afep->afe_adv_aneg;
2803*1959748cSgd78059 		break;
2804*1959748cSgd78059 
2805*1959748cSgd78059 	case ETHER_STAT_LP_CAP_100T4:
2806*1959748cSgd78059 		*val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_100BASE_T4);
2807*1959748cSgd78059 		break;
2808*1959748cSgd78059 
2809*1959748cSgd78059 	case ETHER_STAT_LP_CAP_100FDX:
2810*1959748cSgd78059 		*val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_100BASE_TX_FD);
2811*1959748cSgd78059 		break;
2812*1959748cSgd78059 
2813*1959748cSgd78059 	case ETHER_STAT_LP_CAP_100HDX:
2814*1959748cSgd78059 		*val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_100BASE_TX);
2815*1959748cSgd78059 		break;
2816*1959748cSgd78059 
2817*1959748cSgd78059 	case ETHER_STAT_LP_CAP_10FDX:
2818*1959748cSgd78059 		*val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_10BASE_T_FD);
2819*1959748cSgd78059 		break;
2820*1959748cSgd78059 
2821*1959748cSgd78059 	case ETHER_STAT_LP_CAP_10HDX:
2822*1959748cSgd78059 		*val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_10BASE_T);
2823*1959748cSgd78059 		break;
2824*1959748cSgd78059 
2825*1959748cSgd78059 	case ETHER_STAT_LP_CAP_AUTONEG:
2826*1959748cSgd78059 		*val = GETMIIBIT(MII_AN_EXPANSION, MII_AN_EXP_LPCANAN);
2827*1959748cSgd78059 		break;
2828*1959748cSgd78059 
2829*1959748cSgd78059 	case ETHER_STAT_XCVR_ADDR:
2830*1959748cSgd78059 		*val = afep->afe_phyaddr;
2831*1959748cSgd78059 		break;
2832*1959748cSgd78059 
2833*1959748cSgd78059 	case ETHER_STAT_XCVR_ID:
2834*1959748cSgd78059 		*val = afep->afe_phyid;
2835*1959748cSgd78059 		break;
2836*1959748cSgd78059 
2837*1959748cSgd78059 	default:
2838*1959748cSgd78059 		return (ENOTSUP);
2839*1959748cSgd78059 	}
2840*1959748cSgd78059 	return (0);
2841*1959748cSgd78059 }
2842*1959748cSgd78059 
2843*1959748cSgd78059 /*
2844*1959748cSgd78059  * NDD support.
2845*1959748cSgd78059  */
2846*1959748cSgd78059 afe_nd_t *
2847*1959748cSgd78059 afe_ndfind(afe_t *afep, char *name)
2848*1959748cSgd78059 {
2849*1959748cSgd78059 	afe_nd_t	*ndp;
2850*1959748cSgd78059 
2851*1959748cSgd78059 	for (ndp = afep->afe_ndp; ndp != NULL; ndp = ndp->nd_next) {
2852*1959748cSgd78059 		if (strcmp(name, ndp->nd_name) == 0) {
2853*1959748cSgd78059 			break;
2854*1959748cSgd78059 		}
2855*1959748cSgd78059 	}
2856*1959748cSgd78059 	return (ndp);
2857*1959748cSgd78059 }
2858*1959748cSgd78059 
2859*1959748cSgd78059 void
2860*1959748cSgd78059 afe_ndadd(afe_t *afep, char *name, afe_nd_pf_t get, afe_nd_pf_t set,
2861*1959748cSgd78059     intptr_t arg1, intptr_t arg2)
2862*1959748cSgd78059 {
2863*1959748cSgd78059 	afe_nd_t	*newndp;
2864*1959748cSgd78059 	afe_nd_t	**ndpp;
2865*1959748cSgd78059 
2866*1959748cSgd78059 	newndp = (afe_nd_t *)kmem_alloc(sizeof (afe_nd_t), KM_SLEEP);
2867*1959748cSgd78059 	newndp->nd_next = NULL;
2868*1959748cSgd78059 	newndp->nd_name = name;
2869*1959748cSgd78059 	newndp->nd_get = get;
2870*1959748cSgd78059 	newndp->nd_set = set;
2871*1959748cSgd78059 	newndp->nd_arg1 = arg1;
2872*1959748cSgd78059 	newndp->nd_arg2 = arg2;
2873*1959748cSgd78059 
2874*1959748cSgd78059 	/* seek to the end of the list */
2875*1959748cSgd78059 	for (ndpp = &afep->afe_ndp; *ndpp; ndpp = &(*ndpp)->nd_next) {
2876*1959748cSgd78059 	}
2877*1959748cSgd78059 
2878*1959748cSgd78059 	*ndpp = newndp;
2879*1959748cSgd78059 }
2880*1959748cSgd78059 
2881*1959748cSgd78059 void
2882*1959748cSgd78059 afe_ndempty(mblk_t *mp)
2883*1959748cSgd78059 {
2884*1959748cSgd78059 	while (mp != NULL) {
2885*1959748cSgd78059 		mp->b_rptr = mp->b_datap->db_base;
2886*1959748cSgd78059 		mp->b_wptr = mp->b_rptr;
2887*1959748cSgd78059 		mp = mp->b_cont;
2888*1959748cSgd78059 	}
2889*1959748cSgd78059 }
2890*1959748cSgd78059 
2891*1959748cSgd78059 void
2892*1959748cSgd78059 afe_ndget(afe_t *afep, queue_t *wq, mblk_t *mp)
2893*1959748cSgd78059 {
2894*1959748cSgd78059 	mblk_t		*nmp = mp->b_cont;
2895*1959748cSgd78059 	afe_nd_t	*ndp;
2896*1959748cSgd78059 	int		rv;
2897*1959748cSgd78059 	char		name[128];
2898*1959748cSgd78059 
2899*1959748cSgd78059 	/* assumption, name will fit in first mblk of chain */
2900*1959748cSgd78059 	if ((nmp == NULL) || (nmp->b_wptr <= nmp->b_rptr)) {
2901*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
2902*1959748cSgd78059 		return;
2903*1959748cSgd78059 	}
2904*1959748cSgd78059 
2905*1959748cSgd78059 	if (afe_ndparselen(nmp) >= sizeof (name)) {
2906*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
2907*1959748cSgd78059 		return;
2908*1959748cSgd78059 	}
2909*1959748cSgd78059 	afe_ndparsestring(nmp, name, sizeof (name));
2910*1959748cSgd78059 
2911*1959748cSgd78059 	/* locate variable */
2912*1959748cSgd78059 	if ((ndp = afe_ndfind(afep, name)) == NULL) {
2913*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
2914*1959748cSgd78059 		return;
2915*1959748cSgd78059 	}
2916*1959748cSgd78059 
2917*1959748cSgd78059 	/* locate get callback */
2918*1959748cSgd78059 	if (ndp->nd_get == NULL) {
2919*1959748cSgd78059 		miocnak(wq, mp, 0, EACCES);
2920*1959748cSgd78059 		return;
2921*1959748cSgd78059 	}
2922*1959748cSgd78059 
2923*1959748cSgd78059 	/* clear the result buffer */
2924*1959748cSgd78059 	afe_ndempty(nmp);
2925*1959748cSgd78059 
2926*1959748cSgd78059 	rv = (*ndp->nd_get)(afep, nmp, ndp);
2927*1959748cSgd78059 	if (rv == 0) {
2928*1959748cSgd78059 		/* add final null bytes */
2929*1959748cSgd78059 		rv = afe_ndaddbytes(nmp, "\0", 1);
2930*1959748cSgd78059 	}
2931*1959748cSgd78059 
2932*1959748cSgd78059 	if (rv == 0) {
2933*1959748cSgd78059 		miocack(wq, mp, msgsize(nmp), 0);
2934*1959748cSgd78059 	} else {
2935*1959748cSgd78059 		miocnak(wq, mp, 0, rv);
2936*1959748cSgd78059 	}
2937*1959748cSgd78059 }
2938*1959748cSgd78059 
2939*1959748cSgd78059 void
2940*1959748cSgd78059 afe_ndset(afe_t *afep, queue_t *wq, mblk_t *mp)
2941*1959748cSgd78059 {
2942*1959748cSgd78059 	struct iocblk	*iocp = (void *)mp->b_rptr;
2943*1959748cSgd78059 	mblk_t		*nmp = mp->b_cont;
2944*1959748cSgd78059 	afe_nd_t	*ndp;
2945*1959748cSgd78059 	int		rv;
2946*1959748cSgd78059 	char		name[128];
2947*1959748cSgd78059 
2948*1959748cSgd78059 	/* enforce policy */
2949*1959748cSgd78059 	if ((rv = priv_getbyname(PRIV_SYS_NET_CONFIG, 0)) < 0) {
2950*1959748cSgd78059 		/* priv_getbyname returns a negative errno */
2951*1959748cSgd78059 		miocnak(wq, mp, 0, -rv);
2952*1959748cSgd78059 		return;
2953*1959748cSgd78059 	}
2954*1959748cSgd78059 	if ((rv = priv_policy(iocp->ioc_cr, rv, B_FALSE, EPERM, NULL)) != 0) {
2955*1959748cSgd78059 		miocnak(wq, mp, 0, rv);
2956*1959748cSgd78059 		return;
2957*1959748cSgd78059 	}
2958*1959748cSgd78059 
2959*1959748cSgd78059 	/* assumption, name will fit in first mblk of chain */
2960*1959748cSgd78059 	if ((nmp == NULL) || (nmp->b_wptr <= nmp->b_rptr)) {
2961*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
2962*1959748cSgd78059 		return;
2963*1959748cSgd78059 	}
2964*1959748cSgd78059 
2965*1959748cSgd78059 	if (afe_ndparselen(nmp) >= sizeof (name)) {
2966*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
2967*1959748cSgd78059 		return;
2968*1959748cSgd78059 	}
2969*1959748cSgd78059 	afe_ndparsestring(nmp, name, sizeof (name));
2970*1959748cSgd78059 
2971*1959748cSgd78059 	/* locate variable */
2972*1959748cSgd78059 	if ((ndp = afe_ndfind(afep, name)) == NULL) {
2973*1959748cSgd78059 		miocnak(wq, mp, 0, EINVAL);
2974*1959748cSgd78059 		return;
2975*1959748cSgd78059 	}
2976*1959748cSgd78059 
2977*1959748cSgd78059 	/* locate set callback */
2978*1959748cSgd78059 	if (ndp->nd_set == NULL) {
2979*1959748cSgd78059 		miocnak(wq, mp, 0, EACCES);
2980*1959748cSgd78059 		return;
2981*1959748cSgd78059 	}
2982*1959748cSgd78059 
2983*1959748cSgd78059 	rv = (*ndp->nd_set)(afep, nmp, ndp);
2984*1959748cSgd78059 
2985*1959748cSgd78059 	if (rv == 0) {
2986*1959748cSgd78059 		miocack(wq, mp, 0, 0);
2987*1959748cSgd78059 	} else {
2988*1959748cSgd78059 		miocnak(wq, mp, 0, rv);
2989*1959748cSgd78059 	}
2990*1959748cSgd78059 }
2991*1959748cSgd78059 
2992*1959748cSgd78059 int
2993*1959748cSgd78059 afe_ndaddbytes(mblk_t *mp, char *bytes, int cnt)
2994*1959748cSgd78059 {
2995*1959748cSgd78059 	int index;
2996*1959748cSgd78059 
2997*1959748cSgd78059 	for (index = 0; index < cnt; index++) {
2998*1959748cSgd78059 		while (mp && (mp->b_wptr >= DB_LIM(mp))) {
2999*1959748cSgd78059 			mp = mp->b_cont;
3000*1959748cSgd78059 		}
3001*1959748cSgd78059 		if (mp == NULL) {
3002*1959748cSgd78059 			return (ENOSPC);
3003*1959748cSgd78059 		}
3004*1959748cSgd78059 		*(mp->b_wptr) = *bytes;
3005*1959748cSgd78059 		mp->b_wptr++;
3006*1959748cSgd78059 		bytes++;
3007*1959748cSgd78059 	}
3008*1959748cSgd78059 	return (0);
3009*1959748cSgd78059 }
3010*1959748cSgd78059 
3011*1959748cSgd78059 int
3012*1959748cSgd78059 afe_ndaddstr(mblk_t *mp, char *str, int addnull)
3013*1959748cSgd78059 {
3014*1959748cSgd78059 	/* store the string, plus the terminating null */
3015*1959748cSgd78059 	return (afe_ndaddbytes(mp, str, strlen(str) + (addnull ? 1 : 0)));
3016*1959748cSgd78059 }
3017*1959748cSgd78059 
3018*1959748cSgd78059 int
3019*1959748cSgd78059 afe_ndparselen(mblk_t *mp)
3020*1959748cSgd78059 {
3021*1959748cSgd78059 	int	len = 0;
3022*1959748cSgd78059 	int	done = 0;
3023*1959748cSgd78059 	uchar_t	*ptr;
3024*1959748cSgd78059 
3025*1959748cSgd78059 	while (mp && !done) {
3026*1959748cSgd78059 		for (ptr = mp->b_rptr; ptr < mp->b_wptr; ptr++) {
3027*1959748cSgd78059 			if (!(*ptr)) {
3028*1959748cSgd78059 				done = 1;
3029*1959748cSgd78059 				break;
3030*1959748cSgd78059 			}
3031*1959748cSgd78059 			len++;
3032*1959748cSgd78059 		}
3033*1959748cSgd78059 		mp = mp->b_cont;
3034*1959748cSgd78059 	}
3035*1959748cSgd78059 	return (len);
3036*1959748cSgd78059 }
3037*1959748cSgd78059 
3038*1959748cSgd78059 int
3039*1959748cSgd78059 afe_ndparseint(mblk_t *mp)
3040*1959748cSgd78059 {
3041*1959748cSgd78059 	int	done = 0;
3042*1959748cSgd78059 	int	val = 0;
3043*1959748cSgd78059 	while (mp && !done) {
3044*1959748cSgd78059 		while (mp->b_rptr < mp->b_wptr) {
3045*1959748cSgd78059 			uchar_t ch = *(mp->b_rptr);
3046*1959748cSgd78059 			mp->b_rptr++;
3047*1959748cSgd78059 			if ((ch >= '0') && (ch <= '9')) {
3048*1959748cSgd78059 				val *= 10;
3049*1959748cSgd78059 				val += ch - '0';
3050*1959748cSgd78059 			} else if (ch == 0) {
3051*1959748cSgd78059 				return (val);
3052*1959748cSgd78059 			} else {
3053*1959748cSgd78059 				/* parse error, put back rptr */
3054*1959748cSgd78059 				mp->b_rptr--;
3055*1959748cSgd78059 				return (val);
3056*1959748cSgd78059 			}
3057*1959748cSgd78059 		}
3058*1959748cSgd78059 		mp = mp->b_cont;
3059*1959748cSgd78059 	}
3060*1959748cSgd78059 	return (val);
3061*1959748cSgd78059 }
3062*1959748cSgd78059 
3063*1959748cSgd78059 void
3064*1959748cSgd78059 afe_ndparsestring(mblk_t *mp, char *buf, int maxlen)
3065*1959748cSgd78059 {
3066*1959748cSgd78059 	int	done = 0;
3067*1959748cSgd78059 	int	len = 0;
3068*1959748cSgd78059 
3069*1959748cSgd78059 	/* ensure null termination */
3070*1959748cSgd78059 	buf[maxlen - 1] = 0;
3071*1959748cSgd78059 	while (mp && !done) {
3072*1959748cSgd78059 		while (mp->b_rptr < mp->b_wptr) {
3073*1959748cSgd78059 			char ch = *((char *)mp->b_rptr);
3074*1959748cSgd78059 			mp->b_rptr++;
3075*1959748cSgd78059 			buf[len++] = ch;
3076*1959748cSgd78059 			if ((ch == 0) || (len == maxlen)) {
3077*1959748cSgd78059 				return;
3078*1959748cSgd78059 			}
3079*1959748cSgd78059 		}
3080*1959748cSgd78059 		mp = mp->b_cont;
3081*1959748cSgd78059 	}
3082*1959748cSgd78059 }
3083*1959748cSgd78059 
3084*1959748cSgd78059 int
3085*1959748cSgd78059 afe_ndquestion(afe_t *afep, mblk_t *mp, afe_nd_t *ndp)
3086*1959748cSgd78059 {
3087*1959748cSgd78059 	for (ndp = afep->afe_ndp; ndp; ndp = ndp->nd_next) {
3088*1959748cSgd78059 		int	rv;
3089*1959748cSgd78059 		char	*s;
3090*1959748cSgd78059 		if ((rv = afe_ndaddstr(mp, ndp->nd_name, 0)) != 0) {
3091*1959748cSgd78059 			return (rv);
3092*1959748cSgd78059 		}
3093*1959748cSgd78059 		if (ndp->nd_get && ndp->nd_set) {
3094*1959748cSgd78059 			s = " (read and write)";
3095*1959748cSgd78059 		} else if (ndp->nd_get) {
3096*1959748cSgd78059 			s = " (read only)";
3097*1959748cSgd78059 		} else if (ndp->nd_set) {
3098*1959748cSgd78059 			s = " (write only)";
3099*1959748cSgd78059 		} else {
3100*1959748cSgd78059 			s = " (no read or write)";
3101*1959748cSgd78059 		}
3102*1959748cSgd78059 		if ((rv = afe_ndaddstr(mp, s, 1)) != 0) {
3103*1959748cSgd78059 			return (rv);
3104*1959748cSgd78059 		}
3105*1959748cSgd78059 	}
3106*1959748cSgd78059 	return (0);
3107*1959748cSgd78059 }
3108*1959748cSgd78059 
3109*1959748cSgd78059 /*ARGSUSED*/
3110*1959748cSgd78059 int
3111*1959748cSgd78059 afe_ndgetint(afe_t *afep, mblk_t *mp, afe_nd_t *ndp)
3112*1959748cSgd78059 {
3113*1959748cSgd78059 	int		val;
3114*1959748cSgd78059 	char		buf[16];
3115*1959748cSgd78059 
3116*1959748cSgd78059 	val = *(int *)ndp->nd_arg1;
3117*1959748cSgd78059 
3118*1959748cSgd78059 	(void) snprintf(buf, sizeof (buf), "%d", val);
3119*1959748cSgd78059 	return (afe_ndaddstr(mp, buf, 1));
3120*1959748cSgd78059 }
3121*1959748cSgd78059 
3122*1959748cSgd78059 int
3123*1959748cSgd78059 afe_ndgetmiibit(afe_t *afep, mblk_t *mp, afe_nd_t *ndp)
3124*1959748cSgd78059 {
3125*1959748cSgd78059 	unsigned	val;
3126*1959748cSgd78059 	unsigned	mask;
3127*1959748cSgd78059 	int		reg;
3128*1959748cSgd78059 
3129*1959748cSgd78059 	reg = (int)ndp->nd_arg1;
3130*1959748cSgd78059 	mask = (unsigned)ndp->nd_arg2;
3131*1959748cSgd78059 
3132*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
3133*1959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
3134*1959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
3135*1959748cSgd78059 		/* device is suspended */
3136*1959748cSgd78059 		return (EIO);
3137*1959748cSgd78059 	}
3138*1959748cSgd78059 	val = afe_miiread(afep, afep->afe_phyaddr, reg);
3139*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
3140*1959748cSgd78059 
3141*1959748cSgd78059 	return (afe_ndaddstr(mp, val & mask ? "1" : "0", 1));
3142*1959748cSgd78059 }
3143*1959748cSgd78059 
3144*1959748cSgd78059 int
3145*1959748cSgd78059 afe_ndsetadv(afe_t *afep, mblk_t *mp, afe_nd_t *ndp)
3146*1959748cSgd78059 {
3147*1959748cSgd78059 	unsigned	*ptr = (unsigned *)ndp->nd_arg1;
3148*1959748cSgd78059 	unsigned	oldval, newval;
3149*1959748cSgd78059 
3150*1959748cSgd78059 	newval = afe_ndparseint(mp) ? 1 : 0;
3151*1959748cSgd78059 
3152*1959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
3153*1959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
3154*1959748cSgd78059 
3155*1959748cSgd78059 	oldval = *ptr;
3156*1959748cSgd78059 	if (oldval != newval) {
3157*1959748cSgd78059 		*ptr = newval;
3158*1959748cSgd78059 		if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) ==
3159*1959748cSgd78059 		    AFE_RUNNING) {
3160*1959748cSgd78059 			/*
3161*1959748cSgd78059 			 * This re-initializes the phy, but it also
3162*1959748cSgd78059 			 * restarts transmit and receive rings.
3163*1959748cSgd78059 			 * Needless to say, changing the link
3164*1959748cSgd78059 			 * parameters is destructive to traffic in
3165*1959748cSgd78059 			 * progress.
3166*1959748cSgd78059 			 */
3167*1959748cSgd78059 			afe_resetall(afep);
3168*1959748cSgd78059 		}
3169*1959748cSgd78059 	}
3170*1959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
3171*1959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
3172*1959748cSgd78059 
3173*1959748cSgd78059 	return (0);
3174*1959748cSgd78059 }
3175*1959748cSgd78059 
3176*1959748cSgd78059 void
3177*1959748cSgd78059 afe_ndfini(afe_t *afep)
3178*1959748cSgd78059 {
3179*1959748cSgd78059 	afe_nd_t	*ndp;
3180*1959748cSgd78059 
3181*1959748cSgd78059 	while ((ndp = afep->afe_ndp) != NULL) {
3182*1959748cSgd78059 		afep->afe_ndp = ndp->nd_next;
3183*1959748cSgd78059 		kmem_free(ndp, sizeof (afe_nd_t));
3184*1959748cSgd78059 	}
3185*1959748cSgd78059 }
3186*1959748cSgd78059 
3187*1959748cSgd78059 void
3188*1959748cSgd78059 afe_ndinit(afe_t *afep)
3189*1959748cSgd78059 {
3190*1959748cSgd78059 	afe_ndadd(afep, "?", afe_ndquestion, NULL, 0, 0);
3191*1959748cSgd78059 	afe_ndadd(afep, "link_status", afe_ndgetint, NULL,
3192*1959748cSgd78059 	    (intptr_t)&afep->afe_linkup, 0);
3193*1959748cSgd78059 	afe_ndadd(afep, "link_speed", afe_ndgetint, NULL,
3194*1959748cSgd78059 	    (intptr_t)&afep->afe_ifspeed, 0);
3195*1959748cSgd78059 	afe_ndadd(afep, "link_duplex", afe_ndgetint, NULL,
3196*1959748cSgd78059 	    (intptr_t)&afep->afe_duplex, 0);
3197*1959748cSgd78059 	afe_ndadd(afep, "adv_autoneg_cap", afe_ndgetint, afe_ndsetadv,
3198*1959748cSgd78059 	    (intptr_t)&afep->afe_adv_aneg, 0);
3199*1959748cSgd78059 	afe_ndadd(afep, "adv_100T4_cap", afe_ndgetint, afe_ndsetadv,
3200*1959748cSgd78059 	    (intptr_t)&afep->afe_adv_100T4, 0);
3201*1959748cSgd78059 	afe_ndadd(afep, "adv_100fdx_cap", afe_ndgetint, afe_ndsetadv,
3202*1959748cSgd78059 	    (intptr_t)&afep->afe_adv_100fdx, 0);
3203*1959748cSgd78059 	afe_ndadd(afep, "adv_100hdx_cap", afe_ndgetint, afe_ndsetadv,
3204*1959748cSgd78059 	    (intptr_t)&afep->afe_adv_100hdx, 0);
3205*1959748cSgd78059 	afe_ndadd(afep, "adv_10fdx_cap", afe_ndgetint, afe_ndsetadv,
3206*1959748cSgd78059 	    (intptr_t)&afep->afe_adv_10fdx, 0);
3207*1959748cSgd78059 	afe_ndadd(afep, "adv_10hdx_cap", afe_ndgetint, afe_ndsetadv,
3208*1959748cSgd78059 	    (intptr_t)&afep->afe_adv_10hdx, 0);
3209*1959748cSgd78059 	afe_ndadd(afep, "autoneg_cap", afe_ndgetmiibit, NULL,
3210*1959748cSgd78059 	    MII_STATUS, MII_STATUS_CANAUTONEG);
3211*1959748cSgd78059 	afe_ndadd(afep, "100T4_cap", afe_ndgetmiibit, NULL,
3212*1959748cSgd78059 	    MII_STATUS, MII_STATUS_100_BASE_T4);
3213*1959748cSgd78059 	afe_ndadd(afep, "100fdx_cap", afe_ndgetmiibit, NULL,
3214*1959748cSgd78059 	    MII_STATUS, MII_STATUS_100_BASEX_FD);
3215*1959748cSgd78059 	afe_ndadd(afep, "100hdx_cap", afe_ndgetmiibit, NULL,
3216*1959748cSgd78059 	    MII_STATUS, MII_STATUS_100_BASEX);
3217*1959748cSgd78059 	afe_ndadd(afep, "10fdx_cap", afe_ndgetmiibit, NULL,
3218*1959748cSgd78059 	    MII_STATUS, MII_STATUS_10_FD);
3219*1959748cSgd78059 	afe_ndadd(afep, "10hdx_cap", afe_ndgetmiibit, NULL,
3220*1959748cSgd78059 	    MII_STATUS, MII_STATUS_10);
3221*1959748cSgd78059 	afe_ndadd(afep, "lp_autoneg_cap", afe_ndgetmiibit, NULL,
3222*1959748cSgd78059 	    MII_AN_EXPANSION, MII_AN_EXP_LPCANAN);
3223*1959748cSgd78059 	afe_ndadd(afep, "lp_100T4_cap", afe_ndgetmiibit, NULL,
3224*1959748cSgd78059 	    MII_AN_LPABLE, MII_ABILITY_100BASE_T4);
3225*1959748cSgd78059 	afe_ndadd(afep, "lp_100fdx_cap", afe_ndgetmiibit, NULL,
3226*1959748cSgd78059 	    MII_AN_LPABLE, MII_ABILITY_100BASE_TX_FD);
3227*1959748cSgd78059 	afe_ndadd(afep, "lp_100hdx_cap", afe_ndgetmiibit, NULL,
3228*1959748cSgd78059 	    MII_AN_LPABLE, MII_ABILITY_100BASE_TX);
3229*1959748cSgd78059 	afe_ndadd(afep, "lp_10fdx_cap", afe_ndgetmiibit, NULL,
3230*1959748cSgd78059 	    MII_AN_LPABLE, MII_ABILITY_10BASE_T_FD);
3231*1959748cSgd78059 	afe_ndadd(afep, "lp_10hdx_cap", afe_ndgetmiibit, NULL,
3232*1959748cSgd78059 	    MII_AN_LPABLE, MII_ABILITY_10BASE_T);
3233*1959748cSgd78059 }
3234*1959748cSgd78059 
3235*1959748cSgd78059 /*
3236*1959748cSgd78059  * Debugging and error reporting.
3237*1959748cSgd78059  */
3238*1959748cSgd78059 void
3239*1959748cSgd78059 afe_error(dev_info_t *dip, char *fmt, ...)
3240*1959748cSgd78059 {
3241*1959748cSgd78059 	va_list	ap;
3242*1959748cSgd78059 	char	buf[256];
3243*1959748cSgd78059 
3244*1959748cSgd78059 	va_start(ap, fmt);
3245*1959748cSgd78059 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
3246*1959748cSgd78059 	va_end(ap);
3247*1959748cSgd78059 
3248*1959748cSgd78059 	if (dip) {
3249*1959748cSgd78059 		cmn_err(CE_WARN, "%s%d: %s",
3250*1959748cSgd78059 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
3251*1959748cSgd78059 	} else {
3252*1959748cSgd78059 		cmn_err(CE_WARN, "afe: %s", buf);
3253*1959748cSgd78059 	}
3254*1959748cSgd78059 }
3255*1959748cSgd78059 
3256*1959748cSgd78059 #ifdef	DEBUG
3257*1959748cSgd78059 
3258*1959748cSgd78059 void
3259*1959748cSgd78059 afe_dprintf(afe_t *afep, const char *func, int level, char *fmt, ...)
3260*1959748cSgd78059 {
3261*1959748cSgd78059 	va_list	ap;
3262*1959748cSgd78059 
3263*1959748cSgd78059 	va_start(ap, fmt);
3264*1959748cSgd78059 	if (afe_debug & level) {
3265*1959748cSgd78059 		char	tag[64];
3266*1959748cSgd78059 		char	buf[256];
3267*1959748cSgd78059 
3268*1959748cSgd78059 		if (afep && afep->afe_dip) {
3269*1959748cSgd78059 			(void) snprintf(tag, sizeof (tag), "%s%d",
3270*1959748cSgd78059 			    ddi_driver_name(afep->afe_dip),
3271*1959748cSgd78059 			    ddi_get_instance(afep->afe_dip));
3272*1959748cSgd78059 		} else {
3273*1959748cSgd78059 			(void) snprintf(tag, sizeof (tag), "afe");
3274*1959748cSgd78059 		}
3275*1959748cSgd78059 
3276*1959748cSgd78059 		(void) snprintf(buf, sizeof (buf), "%s: %s: %s\n",
3277*1959748cSgd78059 		    tag, func, fmt);
3278*1959748cSgd78059 
3279*1959748cSgd78059 		vcmn_err(CE_CONT, buf, ap);
3280*1959748cSgd78059 	}
3281*1959748cSgd78059 	va_end(ap);
3282*1959748cSgd78059 }
3283*1959748cSgd78059 
3284*1959748cSgd78059 #endif
3285