xref: /titanic_52/usr/src/uts/common/io/efe/efe.c (revision e65fcc69bb33b3f4525b0c2c9732ece17c90b196)
1b3697b90SSteven Stallion /*
2b3697b90SSteven Stallion  * Copyright (c) 2010 Steven Stallion.  All rights reserved.
3b3697b90SSteven Stallion  *
4b3697b90SSteven Stallion  * Redistribution and use in source and binary forms, with or without
5b3697b90SSteven Stallion  * modification, are permitted provided that the following conditions are
6b3697b90SSteven Stallion  * met:
7b3697b90SSteven Stallion  *
8b3697b90SSteven Stallion  *     1. Redistributions of source code must retain the above copyright
9b3697b90SSteven Stallion  *        notice, this list of conditions and the following disclaimer.
10b3697b90SSteven Stallion  *     2. Redistributions in binary form must reproduce the above
11b3697b90SSteven Stallion  *        copyright notice, this list of conditions and the following
12b3697b90SSteven Stallion  *        disclaimer in the documentation and/or other materials provided
13b3697b90SSteven Stallion  *        with the distribution.
14b3697b90SSteven Stallion  *     3. Neither the name of the copyright owner nor the names of any
15b3697b90SSteven Stallion  *        contributors may be used to endorse or promote products derived
16b3697b90SSteven Stallion  *        from this software without specific prior written permission.
17b3697b90SSteven Stallion  *
18b3697b90SSteven Stallion  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
19b3697b90SSteven Stallion  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20b3697b90SSteven Stallion  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21b3697b90SSteven Stallion  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22b3697b90SSteven Stallion  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23b3697b90SSteven Stallion  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24b3697b90SSteven Stallion  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25b3697b90SSteven Stallion  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26b3697b90SSteven Stallion  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27b3697b90SSteven Stallion  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28b3697b90SSteven Stallion  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29b3697b90SSteven Stallion  */
30b3697b90SSteven Stallion 
31b3697b90SSteven Stallion #include <sys/byteorder.h>
32b3697b90SSteven Stallion #include <sys/types.h>
33b3697b90SSteven Stallion #include <sys/errno.h>
34b3697b90SSteven Stallion #include <sys/varargs.h>
35b3697b90SSteven Stallion #include <sys/cmn_err.h>
36b3697b90SSteven Stallion #include <sys/note.h>
37b3697b90SSteven Stallion #include <sys/kmem.h>
38b3697b90SSteven Stallion #include <sys/conf.h>
39b3697b90SSteven Stallion #include <sys/devops.h>
40b3697b90SSteven Stallion #include <sys/modctl.h>
41b3697b90SSteven Stallion #include <sys/sysmacros.h>
42b3697b90SSteven Stallion #include <sys/ddi.h>
43b3697b90SSteven Stallion #include <sys/ddi_intr.h>
44b3697b90SSteven Stallion #include <sys/sunddi.h>
45b3697b90SSteven Stallion #include <sys/stream.h>
46b3697b90SSteven Stallion #include <sys/strsun.h>
47b3697b90SSteven Stallion #include <sys/pci.h>
48b3697b90SSteven Stallion #include <sys/ethernet.h>
49b3697b90SSteven Stallion #include <sys/vlan.h>
50b3697b90SSteven Stallion #include <sys/crc32.h>
51b3697b90SSteven Stallion #include <sys/mii.h>
52b3697b90SSteven Stallion #include <sys/mac.h>
53b3697b90SSteven Stallion #include <sys/mac_ether.h>
54b3697b90SSteven Stallion #include <sys/mac_provider.h>
55b3697b90SSteven Stallion 
56b3697b90SSteven Stallion #include "efe.h"
57b3697b90SSteven Stallion 
58b3697b90SSteven Stallion /* Autoconfiguration entry points */
59b3697b90SSteven Stallion static int	efe_attach(dev_info_t *, ddi_attach_cmd_t);
60b3697b90SSteven Stallion static int	efe_detach(dev_info_t *, ddi_detach_cmd_t);
61b3697b90SSteven Stallion static int	efe_quiesce(dev_info_t *);
62b3697b90SSteven Stallion 
63b3697b90SSteven Stallion /* MII entry points */
64b3697b90SSteven Stallion static uint16_t	efe_mii_read(void *, uint8_t, uint8_t);
65b3697b90SSteven Stallion static void	efe_mii_write(void *, uint8_t, uint8_t, uint16_t);
66b3697b90SSteven Stallion static void	efe_mii_notify(void *, link_state_t);
67b3697b90SSteven Stallion 
68b3697b90SSteven Stallion /* MAC entry points */
69b3697b90SSteven Stallion static int	efe_m_getstat(void *, uint_t, uint64_t *);
70b3697b90SSteven Stallion static int	efe_m_start(void *);
71b3697b90SSteven Stallion static void	efe_m_stop(void *);
72b3697b90SSteven Stallion static int	efe_m_setpromisc(void *, boolean_t);
73b3697b90SSteven Stallion static int	efe_m_multicst(void *, boolean_t, const uint8_t *);
74b3697b90SSteven Stallion static int	efe_m_unicst(void *, const uint8_t *);
75b3697b90SSteven Stallion static mblk_t	*efe_m_tx(void *, mblk_t *);
76b3697b90SSteven Stallion static int	efe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
77b3697b90SSteven Stallion     const void *);
78b3697b90SSteven Stallion static int	efe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
79b3697b90SSteven Stallion     void *);
80b3697b90SSteven Stallion static void	efe_m_propinfo(void *, const char *, mac_prop_id_t,
81b3697b90SSteven Stallion     mac_prop_info_handle_t);
82b3697b90SSteven Stallion 
83b3697b90SSteven Stallion /* ISR/periodic callbacks */
84b3697b90SSteven Stallion static uint_t	efe_intr(caddr_t, caddr_t);
85b3697b90SSteven Stallion 
86b3697b90SSteven Stallion /* Support functions */
87b3697b90SSteven Stallion static void		efe_init(efe_t *);
88b3697b90SSteven Stallion static void		efe_init_rx_ring(efe_t *);
89b3697b90SSteven Stallion static void		efe_init_tx_ring(efe_t *);
90b3697b90SSteven Stallion static void		efe_reset(efe_t *);
91b3697b90SSteven Stallion static void		efe_start(efe_t *);
92b3697b90SSteven Stallion static void		efe_stop(efe_t *);
93b3697b90SSteven Stallion static void		efe_stop_dma(efe_t *);
94b3697b90SSteven Stallion static inline void	efe_restart(efe_t *);
95b3697b90SSteven Stallion static int		efe_suspend(efe_t *);
96b3697b90SSteven Stallion static int		efe_resume(efe_t *);
97b3697b90SSteven Stallion 
98b3697b90SSteven Stallion static efe_ring_t	*efe_ring_alloc(dev_info_t *, size_t);
99b3697b90SSteven Stallion static void		efe_ring_free(efe_ring_t **);
100b3697b90SSteven Stallion static efe_buf_t	*efe_buf_alloc(dev_info_t *, size_t);
101b3697b90SSteven Stallion static void		efe_buf_free(efe_buf_t **);
102b3697b90SSteven Stallion 
103b3697b90SSteven Stallion static void		efe_intr_enable(efe_t *);
104b3697b90SSteven Stallion static void		efe_intr_disable(efe_t *);
105b3697b90SSteven Stallion 
106b3697b90SSteven Stallion static mblk_t		*efe_recv(efe_t *);
107b3697b90SSteven Stallion static mblk_t		*efe_recv_pkt(efe_t *, efe_desc_t *);
108b3697b90SSteven Stallion 
109b3697b90SSteven Stallion static int		efe_send(efe_t *, mblk_t *);
110b3697b90SSteven Stallion static void		efe_send_done(efe_t *);
111b3697b90SSteven Stallion 
112b3697b90SSteven Stallion static void		efe_getaddr(efe_t *, uint8_t *);
113b3697b90SSteven Stallion static void		efe_setaddr(efe_t *, uint8_t *);
114b3697b90SSteven Stallion static void		efe_setmchash(efe_t *, uint16_t *);
115b3697b90SSteven Stallion 
116b3697b90SSteven Stallion static void		efe_eeprom_read(efe_t *, uint8_t *, size_t, uint8_t);
117b3697b90SSteven Stallion static uint16_t		efe_eeprom_readw(efe_t *, int, uint8_t);
118b3697b90SSteven Stallion static inline int	efe_eeprom_readbit(efe_t *);
119b3697b90SSteven Stallion static inline void	efe_eeprom_writebit(efe_t *, int);
120b3697b90SSteven Stallion 
121b3697b90SSteven Stallion static void		efe_dprintf(dev_info_t *, int, const char *, ...);
122b3697b90SSteven Stallion 
123b3697b90SSteven Stallion #ifdef DEBUG
124b3697b90SSteven Stallion #define	efe_debug(dip, ...) \
125b3697b90SSteven Stallion 	efe_dprintf((dip), CE_CONT, __VA_ARGS__)
126b3697b90SSteven Stallion #else
127b3697b90SSteven Stallion #define	efe_debug(dip, ...)	/*EMPTY*/
128b3697b90SSteven Stallion #endif
129b3697b90SSteven Stallion 
130b3697b90SSteven Stallion #define	efe_error(dip, ...) \
131b3697b90SSteven Stallion 	efe_dprintf((dip), CE_WARN, __VA_ARGS__)
132b3697b90SSteven Stallion 
133b3697b90SSteven Stallion extern struct mod_ops mod_driverops;
134b3697b90SSteven Stallion 
135b3697b90SSteven Stallion DDI_DEFINE_STREAM_OPS(efe_dev_ops, nulldev, nulldev, efe_attach, efe_detach,
136b3697b90SSteven Stallion     nodev, NULL, D_MP, NULL, efe_quiesce);
137b3697b90SSteven Stallion 
138b3697b90SSteven Stallion static struct modldrv modldrv = {
139b3697b90SSteven Stallion 	&mod_driverops,			/* drv_modops */
140b3697b90SSteven Stallion 	"EPIC/100 Fast Ethernet",	/* drv_linkinfo */
141b3697b90SSteven Stallion 	&efe_dev_ops			/* drv_dev_ops */
142b3697b90SSteven Stallion };
143b3697b90SSteven Stallion 
144b3697b90SSteven Stallion static struct modlinkage modlinkage = {
145b3697b90SSteven Stallion 	MODREV_1,		/* ml_rev */
146b3697b90SSteven Stallion 	{ &modldrv, NULL }	/* ml_linkage */
147b3697b90SSteven Stallion };
148b3697b90SSteven Stallion 
149b3697b90SSteven Stallion static ddi_device_acc_attr_t efe_regs_acc_attr = {
150b3697b90SSteven Stallion 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
151b3697b90SSteven Stallion 	DDI_STRUCTURE_LE_ACC,	/* devacc_attr_endian_flags */
152b3697b90SSteven Stallion 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
153b3697b90SSteven Stallion };
154b3697b90SSteven Stallion 
155b3697b90SSteven Stallion static ddi_device_acc_attr_t efe_buf_acc_attr = {
156b3697b90SSteven Stallion 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
157b3697b90SSteven Stallion 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
158b3697b90SSteven Stallion 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
159b3697b90SSteven Stallion };
160b3697b90SSteven Stallion 
161b3697b90SSteven Stallion static ddi_dma_attr_t efe_dma_attr = {
162b3697b90SSteven Stallion 	DMA_ATTR_V0,		/* dma_attr_version */
163b3697b90SSteven Stallion 	0,			/* dma_attr_addr_lo */
164b3697b90SSteven Stallion 	0xFFFFFFFFUL,		/* dma_attr_addr_hi */
165b3697b90SSteven Stallion 	0x7FFFFFFFUL,		/* dma_attr_count_max */
166b3697b90SSteven Stallion 	4,			/* dma_attr_align */
167b3697b90SSteven Stallion 	0x7F,			/* dma_attr_burstsizes */
168b3697b90SSteven Stallion 	1,			/* dma_attr_minxfer */
169b3697b90SSteven Stallion 	0xFFFFFFFFUL,		/* dma_attr_maxxfer */
170b3697b90SSteven Stallion 	0xFFFFFFFFUL,		/* dma_attr_seg */
171b3697b90SSteven Stallion 	1,			/* dma_attr_sgllen */
172b3697b90SSteven Stallion 	1,			/* dma_attr_granular */
173b3697b90SSteven Stallion 	0			/* dma_attr_flags */
174b3697b90SSteven Stallion };
175b3697b90SSteven Stallion 
176b3697b90SSteven Stallion static mii_ops_t efe_mii_ops = {
177b3697b90SSteven Stallion 	MII_OPS_VERSION,	/* mii_version */
178b3697b90SSteven Stallion 	efe_mii_read,		/* mii_read */
179b3697b90SSteven Stallion 	efe_mii_write,		/* mii_write */
180b3697b90SSteven Stallion 	efe_mii_notify		/* mii_notify */
181b3697b90SSteven Stallion };
182b3697b90SSteven Stallion 
183b3697b90SSteven Stallion static mac_callbacks_t efe_m_callbacks = {
184b3697b90SSteven Stallion 	MC_SETPROP | MC_GETPROP,	/* mc_callbacks */
185b3697b90SSteven Stallion 	efe_m_getstat,			/* mc_getstat */
186b3697b90SSteven Stallion 	efe_m_start,			/* mc_start */
187b3697b90SSteven Stallion 	efe_m_stop,			/* mc_stop */
188b3697b90SSteven Stallion 	efe_m_setpromisc,		/* mc_setpromisc */
189b3697b90SSteven Stallion 	efe_m_multicst,			/* mc_multicst */
190b3697b90SSteven Stallion 	efe_m_unicst,			/* mc_unicst */
191b3697b90SSteven Stallion 	efe_m_tx,			/* mc_tx */
192b3697b90SSteven Stallion 	NULL,				/* mc_reserved */
193b3697b90SSteven Stallion 	NULL,				/* mc_ioctl */
194b3697b90SSteven Stallion 	NULL,				/* mc_getcapab */
195b3697b90SSteven Stallion 	NULL,				/* mc_open */
196b3697b90SSteven Stallion 	NULL,				/* mc_close */
197b3697b90SSteven Stallion 	efe_m_setprop,			/* mc_setprop */
198b3697b90SSteven Stallion 	efe_m_getprop,			/* mc_getprop */
199b3697b90SSteven Stallion 	efe_m_propinfo			/* mc_propinfo */
200b3697b90SSteven Stallion };
201b3697b90SSteven Stallion 
202b3697b90SSteven Stallion static uint8_t efe_broadcast[] = {
203b3697b90SSteven Stallion 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
204b3697b90SSteven Stallion };
205b3697b90SSteven Stallion 
206b3697b90SSteven Stallion static uint16_t efe_mchash_promisc[] = {
207b3697b90SSteven Stallion 	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
208b3697b90SSteven Stallion };
209b3697b90SSteven Stallion 
210b3697b90SSteven Stallion /*
211b3697b90SSteven Stallion  * Loadable module entry points.
212b3697b90SSteven Stallion  */
213b3697b90SSteven Stallion int
214b3697b90SSteven Stallion _init(void)
215b3697b90SSteven Stallion {
216b3697b90SSteven Stallion 	int error;
217b3697b90SSteven Stallion 
218b3697b90SSteven Stallion 	mac_init_ops(&efe_dev_ops, "efe");
219b3697b90SSteven Stallion 	if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) {
220b3697b90SSteven Stallion 		mac_fini_ops(&efe_dev_ops);
221b3697b90SSteven Stallion 	}
222b3697b90SSteven Stallion 
223b3697b90SSteven Stallion 	return (error);
224b3697b90SSteven Stallion }
225b3697b90SSteven Stallion 
226b3697b90SSteven Stallion int
227b3697b90SSteven Stallion _fini(void)
228b3697b90SSteven Stallion {
229b3697b90SSteven Stallion 	int error;
230b3697b90SSteven Stallion 
231b3697b90SSteven Stallion 	if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) {
232b3697b90SSteven Stallion 		mac_fini_ops(&efe_dev_ops);
233b3697b90SSteven Stallion 	}
234b3697b90SSteven Stallion 
235b3697b90SSteven Stallion 	return (error);
236b3697b90SSteven Stallion }
237b3697b90SSteven Stallion 
238b3697b90SSteven Stallion int
239b3697b90SSteven Stallion _info(struct modinfo *modinfop)
240b3697b90SSteven Stallion {
241b3697b90SSteven Stallion 	return (mod_info(&modlinkage, modinfop));
242b3697b90SSteven Stallion }
243b3697b90SSteven Stallion 
244b3697b90SSteven Stallion /*
245b3697b90SSteven Stallion  * Autoconfiguration entry points.
246b3697b90SSteven Stallion  */
247b3697b90SSteven Stallion int
248b3697b90SSteven Stallion efe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
249b3697b90SSteven Stallion {
250b3697b90SSteven Stallion 	ddi_acc_handle_t pci;
251b3697b90SSteven Stallion 	int types;
252b3697b90SSteven Stallion 	int count;
253b3697b90SSteven Stallion 	int actual;
254b3697b90SSteven Stallion 	uint_t pri;
255b3697b90SSteven Stallion 	efe_t *efep;
256b3697b90SSteven Stallion 	mac_register_t *macp;
257b3697b90SSteven Stallion 
258b3697b90SSteven Stallion 	switch (cmd) {
259b3697b90SSteven Stallion 	case DDI_ATTACH:
260b3697b90SSteven Stallion 		break;
261b3697b90SSteven Stallion 
262b3697b90SSteven Stallion 	case DDI_RESUME:
263b3697b90SSteven Stallion 		efep = ddi_get_driver_private(dip);
264b3697b90SSteven Stallion 		return (efe_resume(efep));
265b3697b90SSteven Stallion 
266b3697b90SSteven Stallion 	default:
267b3697b90SSteven Stallion 		return (DDI_FAILURE);
268b3697b90SSteven Stallion 	}
269b3697b90SSteven Stallion 
270b3697b90SSteven Stallion 	/*
271b3697b90SSteven Stallion 	 * PCI configuration.
272b3697b90SSteven Stallion 	 */
273b3697b90SSteven Stallion 	if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
274b3697b90SSteven Stallion 		efe_error(dip, "unable to setup PCI configuration!");
275b3697b90SSteven Stallion 		return (DDI_FAILURE);
276b3697b90SSteven Stallion 	}
277b3697b90SSteven Stallion 
278b3697b90SSteven Stallion 	pci_config_put16(pci, PCI_CONF_COMM,
279b3697b90SSteven Stallion 	    pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_MAE | PCI_COMM_ME);
280b3697b90SSteven Stallion 
281b3697b90SSteven Stallion 	pci_config_teardown(&pci);
282b3697b90SSteven Stallion 
283b3697b90SSteven Stallion 	if (ddi_intr_get_supported_types(dip, &types)
284b3697b90SSteven Stallion 	    != DDI_SUCCESS || !(types & DDI_INTR_TYPE_FIXED)) {
285b3697b90SSteven Stallion 		efe_error(dip, "fixed interrupts not supported!");
286b3697b90SSteven Stallion 		return (DDI_FAILURE);
287b3697b90SSteven Stallion 	}
288b3697b90SSteven Stallion 
289b3697b90SSteven Stallion 	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count)
290b3697b90SSteven Stallion 	    != DDI_SUCCESS || count != 1) {
291b3697b90SSteven Stallion 		efe_error(dip, "no fixed interrupts available!");
292b3697b90SSteven Stallion 		return (DDI_FAILURE);
293b3697b90SSteven Stallion 	}
294b3697b90SSteven Stallion 
295b3697b90SSteven Stallion 	/*
296b3697b90SSteven Stallion 	 * Initialize soft state.
297b3697b90SSteven Stallion 	 */
298b3697b90SSteven Stallion 	efep = kmem_zalloc(sizeof (efe_t), KM_SLEEP);
299b3697b90SSteven Stallion 	ddi_set_driver_private(dip, efep);
300b3697b90SSteven Stallion 
301b3697b90SSteven Stallion 	efep->efe_dip = dip;
302b3697b90SSteven Stallion 
303b3697b90SSteven Stallion 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&efep->efe_regs, 0, 0,
304b3697b90SSteven Stallion 	    &efe_regs_acc_attr, &efep->efe_regs_acch) != DDI_SUCCESS) {
305b3697b90SSteven Stallion 		efe_error(dip, "unable to setup register mapping!");
306b3697b90SSteven Stallion 		goto failure;
307b3697b90SSteven Stallion 	}
308b3697b90SSteven Stallion 
309b3697b90SSteven Stallion 	efep->efe_rx_ring = efe_ring_alloc(efep->efe_dip, RXDESCL);
310b3697b90SSteven Stallion 	if (efep->efe_rx_ring == NULL) {
311b3697b90SSteven Stallion 		efe_error(efep->efe_dip, "unable to allocate rx ring!");
312b3697b90SSteven Stallion 		goto failure;
313b3697b90SSteven Stallion 	}
314b3697b90SSteven Stallion 
315b3697b90SSteven Stallion 	efep->efe_tx_ring = efe_ring_alloc(efep->efe_dip, TXDESCL);
316b3697b90SSteven Stallion 	if (efep->efe_tx_ring == NULL) {
317b3697b90SSteven Stallion 		efe_error(efep->efe_dip, "unable to allocate tx ring!");
318b3697b90SSteven Stallion 		goto failure;
319b3697b90SSteven Stallion 	}
320b3697b90SSteven Stallion 
321b3697b90SSteven Stallion 	if (ddi_intr_alloc(dip, &efep->efe_intrh, DDI_INTR_TYPE_FIXED, 0,
322b3697b90SSteven Stallion 	    count, &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS ||
323b3697b90SSteven Stallion 	    actual != count) {
324b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate fixed interrupt!");
325b3697b90SSteven Stallion 		goto failure;
326b3697b90SSteven Stallion 	}
327b3697b90SSteven Stallion 
328b3697b90SSteven Stallion 	if (ddi_intr_get_pri(efep->efe_intrh, &pri) != DDI_SUCCESS ||
329b3697b90SSteven Stallion 	    pri >= ddi_intr_get_hilevel_pri()) {
330b3697b90SSteven Stallion 		efe_error(dip, "unable to get valid interrupt priority!");
331b3697b90SSteven Stallion 		goto failure;
332b3697b90SSteven Stallion 	}
333b3697b90SSteven Stallion 
334b3697b90SSteven Stallion 	mutex_init(&efep->efe_intrlock, NULL, MUTEX_DRIVER,
335b3697b90SSteven Stallion 	    DDI_INTR_PRI(pri));
336b3697b90SSteven Stallion 
337b3697b90SSteven Stallion 	mutex_init(&efep->efe_txlock, NULL, MUTEX_DRIVER,
338b3697b90SSteven Stallion 	    DDI_INTR_PRI(pri));
339b3697b90SSteven Stallion 
340b3697b90SSteven Stallion 	/*
341b3697b90SSteven Stallion 	 * Initialize device.
342b3697b90SSteven Stallion 	 */
343b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
344b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
345b3697b90SSteven Stallion 
346b3697b90SSteven Stallion 	efe_reset(efep);
347b3697b90SSteven Stallion 
348b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
349b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
350b3697b90SSteven Stallion 
351b3697b90SSteven Stallion 	/* Use factory address as default */
352b3697b90SSteven Stallion 	efe_getaddr(efep, efep->efe_macaddr);
353b3697b90SSteven Stallion 
354b3697b90SSteven Stallion 	/*
355b3697b90SSteven Stallion 	 * Enable the ISR.
356b3697b90SSteven Stallion 	 */
357b3697b90SSteven Stallion 	if (ddi_intr_add_handler(efep->efe_intrh, efe_intr, efep, NULL)
358b3697b90SSteven Stallion 	    != DDI_SUCCESS) {
359b3697b90SSteven Stallion 		efe_error(dip, "unable to add interrupt handler!");
360b3697b90SSteven Stallion 		goto failure;
361b3697b90SSteven Stallion 	}
362b3697b90SSteven Stallion 
363b3697b90SSteven Stallion 	if (ddi_intr_enable(efep->efe_intrh) != DDI_SUCCESS) {
364b3697b90SSteven Stallion 		efe_error(dip, "unable to enable interrupt!");
365b3697b90SSteven Stallion 		goto failure;
366b3697b90SSteven Stallion 	}
367b3697b90SSteven Stallion 
368b3697b90SSteven Stallion 	/*
369b3697b90SSteven Stallion 	 * Allocate MII resources.
370b3697b90SSteven Stallion 	 */
371b3697b90SSteven Stallion 	if ((efep->efe_miih = mii_alloc(efep, dip, &efe_mii_ops)) == NULL) {
372b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate mii resources!");
373b3697b90SSteven Stallion 		goto failure;
374b3697b90SSteven Stallion 	}
375b3697b90SSteven Stallion 
376b3697b90SSteven Stallion 	/*
377b3697b90SSteven Stallion 	 * Allocate MAC resources.
378b3697b90SSteven Stallion 	 */
379b3697b90SSteven Stallion 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
380b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate mac resources!");
381b3697b90SSteven Stallion 		goto failure;
382b3697b90SSteven Stallion 	}
383b3697b90SSteven Stallion 
384b3697b90SSteven Stallion 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
385b3697b90SSteven Stallion 	macp->m_driver = efep;
386b3697b90SSteven Stallion 	macp->m_dip = dip;
387b3697b90SSteven Stallion 	macp->m_src_addr = efep->efe_macaddr;
388b3697b90SSteven Stallion 	macp->m_callbacks = &efe_m_callbacks;
389b3697b90SSteven Stallion 	macp->m_min_sdu = 0;
390b3697b90SSteven Stallion 	macp->m_max_sdu = ETHERMTU;
391b3697b90SSteven Stallion 	macp->m_margin = VLAN_TAGSZ;
392b3697b90SSteven Stallion 
393b3697b90SSteven Stallion 	if (mac_register(macp, &efep->efe_mh) != 0) {
394b3697b90SSteven Stallion 		efe_error(dip, "unable to register with mac!");
395b3697b90SSteven Stallion 		goto failure;
396b3697b90SSteven Stallion 	}
397b3697b90SSteven Stallion 	mac_free(macp);
398b3697b90SSteven Stallion 
399b3697b90SSteven Stallion 	ddi_report_dev(dip);
400b3697b90SSteven Stallion 
401b3697b90SSteven Stallion 	return (DDI_SUCCESS);
402b3697b90SSteven Stallion 
403b3697b90SSteven Stallion failure:
404b3697b90SSteven Stallion 	if (macp != NULL) {
405b3697b90SSteven Stallion 		mac_free(macp);
406b3697b90SSteven Stallion 	}
407b3697b90SSteven Stallion 
408b3697b90SSteven Stallion 	if (efep->efe_miih != NULL) {
409b3697b90SSteven Stallion 		mii_free(efep->efe_miih);
410b3697b90SSteven Stallion 	}
411b3697b90SSteven Stallion 
412b3697b90SSteven Stallion 	if (efep->efe_intrh != NULL) {
413b3697b90SSteven Stallion 		(void) ddi_intr_disable(efep->efe_intrh);
414b3697b90SSteven Stallion 		(void) ddi_intr_remove_handler(efep->efe_intrh);
415b3697b90SSteven Stallion 		(void) ddi_intr_free(efep->efe_intrh);
416b3697b90SSteven Stallion 	}
417b3697b90SSteven Stallion 
418b3697b90SSteven Stallion 	mutex_destroy(&efep->efe_txlock);
419b3697b90SSteven Stallion 	mutex_destroy(&efep->efe_intrlock);
420b3697b90SSteven Stallion 
421b3697b90SSteven Stallion 	if (efep->efe_tx_ring != NULL) {
422b3697b90SSteven Stallion 		efe_ring_free(&efep->efe_tx_ring);
423b3697b90SSteven Stallion 	}
424b3697b90SSteven Stallion 	if (efep->efe_rx_ring != NULL) {
425b3697b90SSteven Stallion 		efe_ring_free(&efep->efe_rx_ring);
426b3697b90SSteven Stallion 	}
427b3697b90SSteven Stallion 
428b3697b90SSteven Stallion 	if (efep->efe_regs_acch != NULL) {
429b3697b90SSteven Stallion 		ddi_regs_map_free(&efep->efe_regs_acch);
430b3697b90SSteven Stallion 	}
431b3697b90SSteven Stallion 
432b3697b90SSteven Stallion 	kmem_free(efep, sizeof (efe_t));
433b3697b90SSteven Stallion 
434b3697b90SSteven Stallion 	return (DDI_FAILURE);
435b3697b90SSteven Stallion }
436b3697b90SSteven Stallion 
437b3697b90SSteven Stallion int
438b3697b90SSteven Stallion efe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
439b3697b90SSteven Stallion {
440b3697b90SSteven Stallion 	efe_t *efep = ddi_get_driver_private(dip);
441b3697b90SSteven Stallion 
442b3697b90SSteven Stallion 	switch (cmd) {
443b3697b90SSteven Stallion 	case DDI_DETACH:
444b3697b90SSteven Stallion 		break;
445b3697b90SSteven Stallion 
446b3697b90SSteven Stallion 	case DDI_SUSPEND:
447b3697b90SSteven Stallion 		return (efe_suspend(efep));
448b3697b90SSteven Stallion 
449b3697b90SSteven Stallion 	default:
450b3697b90SSteven Stallion 		return (DDI_FAILURE);
451b3697b90SSteven Stallion 	}
452b3697b90SSteven Stallion 
453b3697b90SSteven Stallion 	if (mac_unregister(efep->efe_mh) != 0) {
454b3697b90SSteven Stallion 		efe_error(dip, "unable to unregister from mac!");
455b3697b90SSteven Stallion 		return (DDI_FAILURE);
456b3697b90SSteven Stallion 	}
457b3697b90SSteven Stallion 
458b3697b90SSteven Stallion 	mii_free(efep->efe_miih);
459b3697b90SSteven Stallion 
460b3697b90SSteven Stallion 	(void) ddi_intr_disable(efep->efe_intrh);
461b3697b90SSteven Stallion 	(void) ddi_intr_remove_handler(efep->efe_intrh);
462b3697b90SSteven Stallion 	(void) ddi_intr_free(efep->efe_intrh);
463b3697b90SSteven Stallion 
464b3697b90SSteven Stallion 	mutex_destroy(&efep->efe_txlock);
465b3697b90SSteven Stallion 	mutex_destroy(&efep->efe_intrlock);
466b3697b90SSteven Stallion 
467b3697b90SSteven Stallion 	if (efep->efe_tx_ring != NULL) {
468b3697b90SSteven Stallion 		efe_ring_free(&efep->efe_tx_ring);
469b3697b90SSteven Stallion 	}
470b3697b90SSteven Stallion 	if (efep->efe_rx_ring != NULL) {
471b3697b90SSteven Stallion 		efe_ring_free(&efep->efe_rx_ring);
472b3697b90SSteven Stallion 	}
473b3697b90SSteven Stallion 
474b3697b90SSteven Stallion 	ddi_regs_map_free(&efep->efe_regs_acch);
475b3697b90SSteven Stallion 
476b3697b90SSteven Stallion 	kmem_free(efep, sizeof (efe_t));
477b3697b90SSteven Stallion 
478b3697b90SSteven Stallion 	return (DDI_SUCCESS);
479b3697b90SSteven Stallion }
480b3697b90SSteven Stallion 
481b3697b90SSteven Stallion int
482b3697b90SSteven Stallion efe_quiesce(dev_info_t *dip)
483b3697b90SSteven Stallion {
484b3697b90SSteven Stallion 	efe_t *efep = ddi_get_driver_private(dip);
485b3697b90SSteven Stallion 
486b3697b90SSteven Stallion 	PUTCSR(efep, CSR_GENCTL, GENCTL_RESET);
487b3697b90SSteven Stallion 	drv_usecwait(RESET_DELAY);
488b3697b90SSteven Stallion 
489b3697b90SSteven Stallion 	PUTCSR(efep, CSR_GENCTL, GENCTL_PWRDWN);
490b3697b90SSteven Stallion 
491b3697b90SSteven Stallion 	return (DDI_SUCCESS);
492b3697b90SSteven Stallion }
493b3697b90SSteven Stallion 
494b3697b90SSteven Stallion /*
495b3697b90SSteven Stallion  * MII entry points.
496b3697b90SSteven Stallion  */
497b3697b90SSteven Stallion uint16_t
498b3697b90SSteven Stallion efe_mii_read(void *arg, uint8_t phy, uint8_t reg)
499b3697b90SSteven Stallion {
500b3697b90SSteven Stallion 	efe_t *efep = arg;
501b3697b90SSteven Stallion 
502b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MMCTL, MMCTL_READ |
503b3697b90SSteven Stallion 	    reg << MMCTL_PHYREG | phy << MMCTL_PHYADDR);
504b3697b90SSteven Stallion 
505b3697b90SSteven Stallion 	for (int i = 0; i < MII_DELAY_CYCLES; ++i) {
506b3697b90SSteven Stallion 		if (!(GETCSR(efep, CSR_MMCTL) & MMCTL_READ)) {
507b3697b90SSteven Stallion 			return ((uint16_t)GETCSR(efep, CSR_MMDATA));
508b3697b90SSteven Stallion 		}
509b3697b90SSteven Stallion 		drv_usecwait(MII_DELAY);
510b3697b90SSteven Stallion 	}
511b3697b90SSteven Stallion 	efe_error(efep->efe_dip, "timed out reading from MII!");
512b3697b90SSteven Stallion 
513b3697b90SSteven Stallion 	return (0);
514b3697b90SSteven Stallion }
515b3697b90SSteven Stallion 
516b3697b90SSteven Stallion void
517b3697b90SSteven Stallion efe_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t data)
518b3697b90SSteven Stallion {
519b3697b90SSteven Stallion 	efe_t *efep = arg;
520b3697b90SSteven Stallion 
521b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MMDATA, data);
522b3697b90SSteven Stallion 
523b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MMCTL, MMCTL_WRITE |
524b3697b90SSteven Stallion 	    reg << MMCTL_PHYREG | phy << MMCTL_PHYADDR);
525b3697b90SSteven Stallion 
526b3697b90SSteven Stallion 	for (int i = 0; i < MII_DELAY_CYCLES; ++i) {
527b3697b90SSteven Stallion 		if (!(GETCSR(efep, CSR_MMCTL) & MMCTL_WRITE)) {
528b3697b90SSteven Stallion 			return;
529b3697b90SSteven Stallion 		}
530b3697b90SSteven Stallion 		drv_usecwait(MII_DELAY);
531b3697b90SSteven Stallion 	}
532b3697b90SSteven Stallion 	efe_error(efep->efe_dip, "timed out writing to MII!");
533b3697b90SSteven Stallion }
534b3697b90SSteven Stallion 
535b3697b90SSteven Stallion void
536b3697b90SSteven Stallion efe_mii_notify(void *arg, link_state_t link)
537b3697b90SSteven Stallion {
538b3697b90SSteven Stallion 	efe_t *efep = arg;
539b3697b90SSteven Stallion 
540b3697b90SSteven Stallion 	mac_link_update(efep->efe_mh, link);
541b3697b90SSteven Stallion }
542b3697b90SSteven Stallion 
543b3697b90SSteven Stallion /*
544b3697b90SSteven Stallion  * MAC entry points.
545b3697b90SSteven Stallion  */
546b3697b90SSteven Stallion int
547b3697b90SSteven Stallion efe_m_getstat(void *arg, uint_t stat, uint64_t *val)
548b3697b90SSteven Stallion {
549b3697b90SSteven Stallion 	efe_t *efep = arg;
550b3697b90SSteven Stallion 
551b3697b90SSteven Stallion 	if (mii_m_getstat(efep->efe_miih, stat, val) == 0) {
552b3697b90SSteven Stallion 		return (0);
553b3697b90SSteven Stallion 	}
554b3697b90SSteven Stallion 
555b3697b90SSteven Stallion 	switch (stat) {
556b3697b90SSteven Stallion 	case MAC_STAT_MULTIRCV:
557b3697b90SSteven Stallion 		*val = efep->efe_multircv;
558b3697b90SSteven Stallion 		break;
559b3697b90SSteven Stallion 
560b3697b90SSteven Stallion 	case MAC_STAT_BRDCSTRCV:
561b3697b90SSteven Stallion 		*val = efep->efe_brdcstrcv;
562b3697b90SSteven Stallion 		break;
563b3697b90SSteven Stallion 
564b3697b90SSteven Stallion 	case MAC_STAT_MULTIXMT:
565b3697b90SSteven Stallion 		*val = efep->efe_multixmt;
566b3697b90SSteven Stallion 		break;
567b3697b90SSteven Stallion 
568b3697b90SSteven Stallion 	case MAC_STAT_BRDCSTXMT:
569b3697b90SSteven Stallion 		*val = efep->efe_brdcstxmt;
570b3697b90SSteven Stallion 		break;
571b3697b90SSteven Stallion 
572b3697b90SSteven Stallion 	case MAC_STAT_NORCVBUF:
573b3697b90SSteven Stallion 		*val = efep->efe_norcvbuf;
574b3697b90SSteven Stallion 		break;
575b3697b90SSteven Stallion 
576b3697b90SSteven Stallion 	case MAC_STAT_IERRORS:
577b3697b90SSteven Stallion 		*val = efep->efe_ierrors;
578b3697b90SSteven Stallion 		break;
579b3697b90SSteven Stallion 
580b3697b90SSteven Stallion 	case MAC_STAT_NOXMTBUF:
581b3697b90SSteven Stallion 		*val = efep->efe_noxmtbuf;
582b3697b90SSteven Stallion 		break;
583b3697b90SSteven Stallion 
584b3697b90SSteven Stallion 	case MAC_STAT_OERRORS:
585b3697b90SSteven Stallion 		*val = efep->efe_oerrors;
586b3697b90SSteven Stallion 		break;
587b3697b90SSteven Stallion 
588b3697b90SSteven Stallion 	case MAC_STAT_COLLISIONS:
589b3697b90SSteven Stallion 		*val = efep->efe_collisions;
590b3697b90SSteven Stallion 		break;
591b3697b90SSteven Stallion 
592b3697b90SSteven Stallion 	case MAC_STAT_RBYTES:
593b3697b90SSteven Stallion 		*val = efep->efe_rbytes;
594b3697b90SSteven Stallion 		break;
595b3697b90SSteven Stallion 
596b3697b90SSteven Stallion 	case MAC_STAT_IPACKETS:
597b3697b90SSteven Stallion 		*val = efep->efe_ipackets;
598b3697b90SSteven Stallion 		break;
599b3697b90SSteven Stallion 
600b3697b90SSteven Stallion 	case MAC_STAT_OBYTES:
601b3697b90SSteven Stallion 		*val = efep->efe_obytes;
602b3697b90SSteven Stallion 		break;
603b3697b90SSteven Stallion 
604b3697b90SSteven Stallion 	case MAC_STAT_OPACKETS:
605b3697b90SSteven Stallion 		*val = efep->efe_opackets;
606b3697b90SSteven Stallion 		break;
607b3697b90SSteven Stallion 
608b3697b90SSteven Stallion 	case MAC_STAT_UNDERFLOWS:
609b3697b90SSteven Stallion 		*val = efep->efe_uflo;
610b3697b90SSteven Stallion 		break;
611b3697b90SSteven Stallion 
612b3697b90SSteven Stallion 	case MAC_STAT_OVERFLOWS:
613b3697b90SSteven Stallion 		*val = efep->efe_oflo;
614b3697b90SSteven Stallion 		break;
615b3697b90SSteven Stallion 
616b3697b90SSteven Stallion 	case ETHER_STAT_ALIGN_ERRORS:
617b3697b90SSteven Stallion 		*val = efep->efe_align_errors;
618b3697b90SSteven Stallion 		break;
619b3697b90SSteven Stallion 
620b3697b90SSteven Stallion 	case ETHER_STAT_FCS_ERRORS:
621b3697b90SSteven Stallion 		*val = efep->efe_fcs_errors;
622b3697b90SSteven Stallion 		break;
623b3697b90SSteven Stallion 
624b3697b90SSteven Stallion 	case ETHER_STAT_FIRST_COLLISIONS:
625b3697b90SSteven Stallion 		*val = efep->efe_first_collisions;
626b3697b90SSteven Stallion 		break;
627b3697b90SSteven Stallion 
628b3697b90SSteven Stallion 	case ETHER_STAT_TX_LATE_COLLISIONS:
629b3697b90SSteven Stallion 		*val = efep->efe_tx_late_collisions;
630b3697b90SSteven Stallion 		break;
631b3697b90SSteven Stallion 
632b3697b90SSteven Stallion 	case ETHER_STAT_DEFER_XMTS:
633b3697b90SSteven Stallion 		*val = efep->efe_defer_xmts;
634b3697b90SSteven Stallion 		break;
635b3697b90SSteven Stallion 
636b3697b90SSteven Stallion 	case ETHER_STAT_EX_COLLISIONS:
637b3697b90SSteven Stallion 		*val = efep->efe_ex_collisions;
638b3697b90SSteven Stallion 		break;
639b3697b90SSteven Stallion 
640b3697b90SSteven Stallion 	case ETHER_STAT_MACXMT_ERRORS:
641b3697b90SSteven Stallion 		*val = efep->efe_macxmt_errors;
642b3697b90SSteven Stallion 		break;
643b3697b90SSteven Stallion 
644b3697b90SSteven Stallion 	case ETHER_STAT_CARRIER_ERRORS:
645b3697b90SSteven Stallion 		*val = efep->efe_carrier_errors;
646b3697b90SSteven Stallion 		break;
647b3697b90SSteven Stallion 
648b3697b90SSteven Stallion 	case ETHER_STAT_TOOLONG_ERRORS:
649b3697b90SSteven Stallion 		*val = efep->efe_toolong_errors;
650b3697b90SSteven Stallion 		break;
651b3697b90SSteven Stallion 
652b3697b90SSteven Stallion 	case ETHER_STAT_MACRCV_ERRORS:
653b3697b90SSteven Stallion 		*val = efep->efe_macrcv_errors;
654b3697b90SSteven Stallion 		break;
655b3697b90SSteven Stallion 
656b3697b90SSteven Stallion 	case ETHER_STAT_TOOSHORT_ERRORS:
657b3697b90SSteven Stallion 		*val = efep->efe_runt_errors;
658b3697b90SSteven Stallion 		break;
659b3697b90SSteven Stallion 
660b3697b90SSteven Stallion 	case ETHER_STAT_JABBER_ERRORS:
661b3697b90SSteven Stallion 		*val = efep->efe_jabber_errors;
662b3697b90SSteven Stallion 		break;
663b3697b90SSteven Stallion 
664b3697b90SSteven Stallion 	default:
665b3697b90SSteven Stallion 		return (ENOTSUP);
666b3697b90SSteven Stallion 	}
667b3697b90SSteven Stallion 
668b3697b90SSteven Stallion 	return (0);
669b3697b90SSteven Stallion }
670b3697b90SSteven Stallion 
671b3697b90SSteven Stallion int
672b3697b90SSteven Stallion efe_m_start(void *arg)
673b3697b90SSteven Stallion {
674b3697b90SSteven Stallion 	efe_t *efep = arg;
675b3697b90SSteven Stallion 
676b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
677b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
678b3697b90SSteven Stallion 
679b3697b90SSteven Stallion 	efe_start(efep);
680b3697b90SSteven Stallion 	efep->efe_flags |= FLAG_RUNNING;
681b3697b90SSteven Stallion 
682b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
683b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
684b3697b90SSteven Stallion 
685b3697b90SSteven Stallion 	mii_start(efep->efe_miih);
686b3697b90SSteven Stallion 
687b3697b90SSteven Stallion 	return (0);
688b3697b90SSteven Stallion }
689b3697b90SSteven Stallion 
690b3697b90SSteven Stallion void
691b3697b90SSteven Stallion efe_m_stop(void *arg)
692b3697b90SSteven Stallion {
693b3697b90SSteven Stallion 	efe_t *efep = arg;
694b3697b90SSteven Stallion 
695b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
696b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
697b3697b90SSteven Stallion 
698b3697b90SSteven Stallion 	efe_stop(efep);
699b3697b90SSteven Stallion 	efep->efe_flags &= ~FLAG_RUNNING;
700b3697b90SSteven Stallion 
701b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
702b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
703b3697b90SSteven Stallion 
704b3697b90SSteven Stallion 	mii_stop(efep->efe_miih);
705b3697b90SSteven Stallion }
706b3697b90SSteven Stallion 
707b3697b90SSteven Stallion int
708b3697b90SSteven Stallion efe_m_setpromisc(void *arg, boolean_t on)
709b3697b90SSteven Stallion {
710b3697b90SSteven Stallion 	efe_t *efep = arg;
711b3697b90SSteven Stallion 
712b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
713b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
714b3697b90SSteven Stallion 
715b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_SUSPENDED) {
716b3697b90SSteven Stallion 		mutex_exit(&efep->efe_txlock);
717b3697b90SSteven Stallion 		mutex_exit(&efep->efe_intrlock);
718b3697b90SSteven Stallion 		return (0);
719b3697b90SSteven Stallion 	}
720b3697b90SSteven Stallion 
721b3697b90SSteven Stallion 	efep->efe_promisc = on;
722b3697b90SSteven Stallion 
723b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_RUNNING) {
724b3697b90SSteven Stallion 		efe_restart(efep);
725b3697b90SSteven Stallion 	}
726b3697b90SSteven Stallion 
727b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
728b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
729b3697b90SSteven Stallion 
730b3697b90SSteven Stallion 	return (0);
731b3697b90SSteven Stallion }
732b3697b90SSteven Stallion 
733b3697b90SSteven Stallion int
734b3697b90SSteven Stallion efe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
735b3697b90SSteven Stallion {
736b3697b90SSteven Stallion 	efe_t *efep = arg;
737b3697b90SSteven Stallion 	uint32_t val;
738b3697b90SSteven Stallion 	int index;
739b3697b90SSteven Stallion 	int bit;
740b3697b90SSteven Stallion 	boolean_t restart = B_FALSE;
741b3697b90SSteven Stallion 
742b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
743b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
744b3697b90SSteven Stallion 
745b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_SUSPENDED) {
746b3697b90SSteven Stallion 		mutex_exit(&efep->efe_txlock);
747b3697b90SSteven Stallion 		mutex_exit(&efep->efe_intrlock);
748b3697b90SSteven Stallion 		return (0);
749b3697b90SSteven Stallion 	}
750b3697b90SSteven Stallion 
751b3697b90SSteven Stallion 	CRC32(val, macaddr, ETHERADDRL, -1U, crc32_table);
752b3697b90SSteven Stallion 	val %= MCHASHL;
753b3697b90SSteven Stallion 
754b3697b90SSteven Stallion 	index = val / MCHASHSZ;
755b3697b90SSteven Stallion 	bit = 1U << (val % MCHASHSZ);
756b3697b90SSteven Stallion 
757b3697b90SSteven Stallion 	if (add) {
758b3697b90SSteven Stallion 		efep->efe_mccount[val]++;
759b3697b90SSteven Stallion 		if (efep->efe_mccount[val] == 1) {
760b3697b90SSteven Stallion 			efep->efe_mchash[index] |= bit;
761b3697b90SSteven Stallion 			restart = B_TRUE;
762b3697b90SSteven Stallion 		}
763b3697b90SSteven Stallion 
764b3697b90SSteven Stallion 	} else {
765b3697b90SSteven Stallion 		efep->efe_mccount[val]--;
766b3697b90SSteven Stallion 		if (efep->efe_mccount[val] == 0) {
767b3697b90SSteven Stallion 			efep->efe_mchash[index] &= ~bit;
768b3697b90SSteven Stallion 			restart = B_TRUE;
769b3697b90SSteven Stallion 		}
770b3697b90SSteven Stallion 	}
771b3697b90SSteven Stallion 
772b3697b90SSteven Stallion 	if (restart && efep->efe_flags & FLAG_RUNNING) {
773b3697b90SSteven Stallion 		efe_restart(efep);
774b3697b90SSteven Stallion 	}
775b3697b90SSteven Stallion 
776b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
777b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
778b3697b90SSteven Stallion 
779b3697b90SSteven Stallion 	return (0);
780b3697b90SSteven Stallion }
781b3697b90SSteven Stallion 
782b3697b90SSteven Stallion int
783b3697b90SSteven Stallion efe_m_unicst(void *arg, const uint8_t *macaddr)
784b3697b90SSteven Stallion {
785b3697b90SSteven Stallion 	efe_t *efep = arg;
786b3697b90SSteven Stallion 
787b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
788b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
789b3697b90SSteven Stallion 
790b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_SUSPENDED) {
791b3697b90SSteven Stallion 		mutex_exit(&efep->efe_txlock);
792b3697b90SSteven Stallion 		mutex_exit(&efep->efe_intrlock);
793b3697b90SSteven Stallion 		return (0);
794b3697b90SSteven Stallion 	}
795b3697b90SSteven Stallion 
796b3697b90SSteven Stallion 	bcopy(macaddr, efep->efe_macaddr, ETHERADDRL);
797b3697b90SSteven Stallion 
798b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_RUNNING) {
799b3697b90SSteven Stallion 		efe_restart(efep);
800b3697b90SSteven Stallion 	}
801b3697b90SSteven Stallion 
802b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
803b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
804b3697b90SSteven Stallion 
805b3697b90SSteven Stallion 	return (0);
806b3697b90SSteven Stallion }
807b3697b90SSteven Stallion 
808b3697b90SSteven Stallion mblk_t *
809b3697b90SSteven Stallion efe_m_tx(void *arg, mblk_t *mp)
810b3697b90SSteven Stallion {
811b3697b90SSteven Stallion 	efe_t *efep = arg;
812b3697b90SSteven Stallion 
813b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
814b3697b90SSteven Stallion 
815b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_SUSPENDED) {
816b3697b90SSteven Stallion 		mutex_exit(&efep->efe_txlock);
817b3697b90SSteven Stallion 		return (mp);
818b3697b90SSteven Stallion 	}
819b3697b90SSteven Stallion 
820b3697b90SSteven Stallion 	while (mp != NULL) {
821b3697b90SSteven Stallion 		mblk_t *tmp = mp->b_next;
822b3697b90SSteven Stallion 		mp->b_next = NULL;
823b3697b90SSteven Stallion 
824b3697b90SSteven Stallion 		if (efe_send(efep, mp) != DDI_SUCCESS) {
825b3697b90SSteven Stallion 			mp->b_next = tmp;
826b3697b90SSteven Stallion 			break;
827b3697b90SSteven Stallion 		}
828b3697b90SSteven Stallion 		mp = tmp;
829b3697b90SSteven Stallion 	}
830b3697b90SSteven Stallion 
831b3697b90SSteven Stallion 	/* Kick the transmitter */
832b3697b90SSteven Stallion 	PUTCSR(efep, CSR_COMMAND, COMMAND_TXQUEUED);
833b3697b90SSteven Stallion 
834b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
835b3697b90SSteven Stallion 
836b3697b90SSteven Stallion 	return (mp);
837b3697b90SSteven Stallion }
838b3697b90SSteven Stallion 
839b3697b90SSteven Stallion int
840b3697b90SSteven Stallion efe_m_setprop(void *arg, const char *name, mac_prop_id_t id,
841b3697b90SSteven Stallion     uint_t valsize, const void *val)
842b3697b90SSteven Stallion {
843b3697b90SSteven Stallion 	efe_t *efep = arg;
844b3697b90SSteven Stallion 
845b3697b90SSteven Stallion 	return (mii_m_setprop(efep->efe_miih, name, id, valsize, val));
846b3697b90SSteven Stallion }
847b3697b90SSteven Stallion 
848b3697b90SSteven Stallion int
849b3697b90SSteven Stallion efe_m_getprop(void *arg, const char *name, mac_prop_id_t id,
850b3697b90SSteven Stallion     uint_t valsize, void *val)
851b3697b90SSteven Stallion {
852b3697b90SSteven Stallion 	efe_t *efep = arg;
853b3697b90SSteven Stallion 
854b3697b90SSteven Stallion 	return (mii_m_getprop(efep->efe_miih, name, id, valsize, val));
855b3697b90SSteven Stallion }
856b3697b90SSteven Stallion 
857b3697b90SSteven Stallion void
858b3697b90SSteven Stallion efe_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
859b3697b90SSteven Stallion     mac_prop_info_handle_t state)
860b3697b90SSteven Stallion {
861b3697b90SSteven Stallion 	efe_t *efep = arg;
862b3697b90SSteven Stallion 
863b3697b90SSteven Stallion 	mii_m_propinfo(efep->efe_miih, name, id, state);
864b3697b90SSteven Stallion }
865b3697b90SSteven Stallion 
866b3697b90SSteven Stallion /*
867b3697b90SSteven Stallion  * ISR/periodic callbacks.
868b3697b90SSteven Stallion  */
869b3697b90SSteven Stallion uint_t
870b3697b90SSteven Stallion efe_intr(caddr_t arg1, caddr_t arg2)
871b3697b90SSteven Stallion {
872b3697b90SSteven Stallion 	efe_t *efep = (void *)arg1;
873b3697b90SSteven Stallion 	uint32_t status;
874b3697b90SSteven Stallion 	mblk_t *mp = NULL;
875b3697b90SSteven Stallion 
876b3697b90SSteven Stallion 	_NOTE(ARGUNUSED(arg2));
877b3697b90SSteven Stallion 
878b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
879b3697b90SSteven Stallion 
880b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_SUSPENDED) {
881b3697b90SSteven Stallion 		mutex_exit(&efep->efe_intrlock);
882b3697b90SSteven Stallion 		return (DDI_INTR_UNCLAIMED);
883b3697b90SSteven Stallion 	}
884b3697b90SSteven Stallion 
885b3697b90SSteven Stallion 	status = GETCSR(efep, CSR_INTSTAT);
886b3697b90SSteven Stallion 	if (!(status & INTSTAT_ACTV)) {
887b3697b90SSteven Stallion 		mutex_exit(&efep->efe_intrlock);
888b3697b90SSteven Stallion 		return (DDI_INTR_UNCLAIMED);
889b3697b90SSteven Stallion 	}
890b3697b90SSteven Stallion 	PUTCSR(efep, CSR_INTSTAT, status);
891b3697b90SSteven Stallion 
892b3697b90SSteven Stallion 	if (status & INTSTAT_RCC) {
893b3697b90SSteven Stallion 		mp = efe_recv(efep);
894b3697b90SSteven Stallion 	}
895b3697b90SSteven Stallion 
896b3697b90SSteven Stallion 	if (status & INTSTAT_RQE) {
897b3697b90SSteven Stallion 		efep->efe_ierrors++;
898b3697b90SSteven Stallion 		efep->efe_macrcv_errors++;
899b3697b90SSteven Stallion 
900b3697b90SSteven Stallion 		/* Kick the receiver */
901b3697b90SSteven Stallion 		PUTCSR(efep, CSR_COMMAND, COMMAND_RXQUEUED);
902b3697b90SSteven Stallion 	}
903b3697b90SSteven Stallion 
904b3697b90SSteven Stallion 	if (status & INTSTAT_TXC) {
905b3697b90SSteven Stallion 		mutex_enter(&efep->efe_txlock);
906b3697b90SSteven Stallion 
907b3697b90SSteven Stallion 		efe_send_done(efep);
908b3697b90SSteven Stallion 
909b3697b90SSteven Stallion 		mutex_exit(&efep->efe_txlock);
910b3697b90SSteven Stallion 	}
911b3697b90SSteven Stallion 
912b3697b90SSteven Stallion 	if (status & INTSTAT_FATAL) {
913b3697b90SSteven Stallion 		mutex_enter(&efep->efe_txlock);
914b3697b90SSteven Stallion 
915b3697b90SSteven Stallion 		efe_error(efep->efe_dip, "bus error; resetting!");
916b3697b90SSteven Stallion 		efe_restart(efep);
917b3697b90SSteven Stallion 
918b3697b90SSteven Stallion 		mutex_exit(&efep->efe_txlock);
919b3697b90SSteven Stallion 	}
920b3697b90SSteven Stallion 
921b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
922b3697b90SSteven Stallion 
923b3697b90SSteven Stallion 	if (mp != NULL) {
924b3697b90SSteven Stallion 		mac_rx(efep->efe_mh, NULL, mp);
925b3697b90SSteven Stallion 	}
926b3697b90SSteven Stallion 
927b3697b90SSteven Stallion 	if (status & INTSTAT_TXC) {
928b3697b90SSteven Stallion 		mac_tx_update(efep->efe_mh);
929b3697b90SSteven Stallion 	}
930b3697b90SSteven Stallion 
931b3697b90SSteven Stallion 	if (status & INTSTAT_FATAL) {
932b3697b90SSteven Stallion 		mii_reset(efep->efe_miih);
933b3697b90SSteven Stallion 	}
934b3697b90SSteven Stallion 
935b3697b90SSteven Stallion 	return (DDI_INTR_CLAIMED);
936b3697b90SSteven Stallion }
937b3697b90SSteven Stallion 
938b3697b90SSteven Stallion /*
939b3697b90SSteven Stallion  * Support functions.
940b3697b90SSteven Stallion  */
941b3697b90SSteven Stallion void
942b3697b90SSteven Stallion efe_init(efe_t *efep)
943b3697b90SSteven Stallion {
944b3697b90SSteven Stallion 	uint32_t val;
945b3697b90SSteven Stallion 
946b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
947b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
948b3697b90SSteven Stallion 
949b3697b90SSteven Stallion 	efe_reset(efep);
950b3697b90SSteven Stallion 
951b3697b90SSteven Stallion 	val = GENCTL_ONECOPY | GENCTL_RFT_128 | GENCTL_MRM;
952b3697b90SSteven Stallion #ifdef _BIG_ENDIAN
953b3697b90SSteven Stallion 	val |= GENCTL_BE;
954b3697b90SSteven Stallion #endif	/* _BIG_ENDIAN */
955b3697b90SSteven Stallion 
956b3697b90SSteven Stallion 	PUTCSR(efep, CSR_GENCTL, val);
957b3697b90SSteven Stallion 	PUTCSR(efep, CSR_PBLCNT, BURSTLEN);
958b3697b90SSteven Stallion 
959b3697b90SSteven Stallion 	efe_init_rx_ring(efep);
960b3697b90SSteven Stallion 	efe_init_tx_ring(efep);
961b3697b90SSteven Stallion 
962b3697b90SSteven Stallion 	efe_setaddr(efep, efep->efe_macaddr);
963b3697b90SSteven Stallion 
964b3697b90SSteven Stallion 	if (efep->efe_promisc) {
965b3697b90SSteven Stallion 		efe_setmchash(efep, efe_mchash_promisc);
966b3697b90SSteven Stallion 	} else {
967b3697b90SSteven Stallion 		efe_setmchash(efep, efep->efe_mchash);
968b3697b90SSteven Stallion 	}
969b3697b90SSteven Stallion }
970b3697b90SSteven Stallion 
971b3697b90SSteven Stallion void
972b3697b90SSteven Stallion efe_init_rx_ring(efe_t *efep)
973b3697b90SSteven Stallion {
974b3697b90SSteven Stallion 	efe_ring_t *rp;
975b3697b90SSteven Stallion 
976b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
977b3697b90SSteven Stallion 
978b3697b90SSteven Stallion 	rp = efep->efe_rx_ring;
979b3697b90SSteven Stallion 
980b3697b90SSteven Stallion 	for (int i = 0; i < DESCLEN(rp); ++i) {
981b3697b90SSteven Stallion 		efe_desc_t *dp = GETDESC(rp, i);
982b3697b90SSteven Stallion 		efe_buf_t *bp = GETBUF(rp, i);
983b3697b90SSteven Stallion 
984b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_status, RXSTAT_OWNER);
985b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_len, 0);
986b3697b90SSteven Stallion 		PUTDESC32(rp, &dp->d_bufaddr, BUFADDR(bp));
987b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_buflen, BUFLEN(bp));
988b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_control, 0);
989b3697b90SSteven Stallion 		PUTDESC32(rp, &dp->d_next, NEXTDESCADDR(rp, i));
990b3697b90SSteven Stallion 
991b3697b90SSteven Stallion 		SYNCDESC(rp, i, DDI_DMA_SYNC_FORDEV);
992b3697b90SSteven Stallion 	}
993b3697b90SSteven Stallion 
994b3697b90SSteven Stallion 	efep->efe_rx_desc = 0;
995b3697b90SSteven Stallion 
996b3697b90SSteven Stallion 	PUTCSR(efep, CSR_PRCDAR, DESCADDR(rp, 0));
997b3697b90SSteven Stallion }
998b3697b90SSteven Stallion 
999b3697b90SSteven Stallion void
1000b3697b90SSteven Stallion efe_init_tx_ring(efe_t *efep)
1001b3697b90SSteven Stallion {
1002b3697b90SSteven Stallion 	efe_ring_t *rp;
1003b3697b90SSteven Stallion 
1004b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1005b3697b90SSteven Stallion 
1006b3697b90SSteven Stallion 	rp = efep->efe_tx_ring;
1007b3697b90SSteven Stallion 
1008b3697b90SSteven Stallion 	for (int i = 0; i < DESCLEN(rp); ++i) {
1009b3697b90SSteven Stallion 		efe_desc_t *dp = GETDESC(rp, i);
1010b3697b90SSteven Stallion 		efe_buf_t *bp = GETBUF(rp, i);
1011b3697b90SSteven Stallion 
1012b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_status, 0);
1013b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_len, 0);
1014b3697b90SSteven Stallion 		PUTDESC32(rp, &dp->d_bufaddr, BUFADDR(bp));
1015b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_buflen, BUFLEN(bp));
1016b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_control, 0);
1017b3697b90SSteven Stallion 		PUTDESC32(rp, &dp->d_next, NEXTDESCADDR(rp, i));
1018b3697b90SSteven Stallion 
1019b3697b90SSteven Stallion 		SYNCDESC(rp, i, DDI_DMA_SYNC_FORDEV);
1020b3697b90SSteven Stallion 	}
1021b3697b90SSteven Stallion 
1022b3697b90SSteven Stallion 	efep->efe_tx_desc = 0;
1023b3697b90SSteven Stallion 	efep->efe_tx_sent = 0;
1024b3697b90SSteven Stallion 
1025b3697b90SSteven Stallion 	PUTCSR(efep, CSR_PTCDAR, DESCADDR(rp, 0));
1026b3697b90SSteven Stallion }
1027b3697b90SSteven Stallion 
1028b3697b90SSteven Stallion void
1029b3697b90SSteven Stallion efe_reset(efe_t *efep)
1030b3697b90SSteven Stallion {
1031b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
1032b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1033b3697b90SSteven Stallion 
1034b3697b90SSteven Stallion 	PUTCSR(efep, CSR_GENCTL, GENCTL_RESET);
1035b3697b90SSteven Stallion 	drv_usecwait(RESET_DELAY);
1036b3697b90SSteven Stallion 
1037b3697b90SSteven Stallion 	/* Assert internal clock source (AN 7.15) */
1038b3697b90SSteven Stallion 	for (int i = 0; i < RESET_TEST_CYCLES; ++i) {
1039b3697b90SSteven Stallion 		PUTCSR(efep, CSR_TEST, TEST_CLOCK);
1040b3697b90SSteven Stallion 	}
1041b3697b90SSteven Stallion }
1042b3697b90SSteven Stallion 
1043b3697b90SSteven Stallion void
1044b3697b90SSteven Stallion efe_start(efe_t *efep)
1045b3697b90SSteven Stallion {
1046b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
1047b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1048b3697b90SSteven Stallion 
1049b3697b90SSteven Stallion 	efe_init(efep);
1050b3697b90SSteven Stallion 
1051b3697b90SSteven Stallion 	PUTCSR(efep, CSR_RXCON,
1052b3697b90SSteven Stallion 	    RXCON_SEP | RXCON_RRF | RXCON_RBF | RXCON_RMF |
1053b3697b90SSteven Stallion 	    (efep->efe_promisc ? RXCON_PROMISC : 0));
1054b3697b90SSteven Stallion 
1055b3697b90SSteven Stallion 	PUTCSR(efep, CSR_TXCON, TXCON_LB_3);
1056b3697b90SSteven Stallion 
1057b3697b90SSteven Stallion 	efe_intr_enable(efep);
1058b3697b90SSteven Stallion 
1059b3697b90SSteven Stallion 	SETBIT(efep, CSR_COMMAND,
1060b3697b90SSteven Stallion 	    COMMAND_START_RX | COMMAND_RXQUEUED);
1061b3697b90SSteven Stallion }
1062b3697b90SSteven Stallion 
1063b3697b90SSteven Stallion void
1064b3697b90SSteven Stallion efe_stop(efe_t *efep)
1065b3697b90SSteven Stallion {
1066b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
1067b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1068b3697b90SSteven Stallion 
1069b3697b90SSteven Stallion 	efe_intr_disable(efep);
1070b3697b90SSteven Stallion 
1071b3697b90SSteven Stallion 	PUTCSR(efep, CSR_COMMAND, COMMAND_STOP_RX);
1072b3697b90SSteven Stallion 
1073b3697b90SSteven Stallion 	efe_stop_dma(efep);
1074b3697b90SSteven Stallion 
1075b3697b90SSteven Stallion 	PUTCSR(efep, CSR_GENCTL, GENCTL_RESET);
1076b3697b90SSteven Stallion 	drv_usecwait(RESET_DELAY);
1077b3697b90SSteven Stallion 
1078b3697b90SSteven Stallion 	PUTCSR(efep, CSR_GENCTL, GENCTL_PWRDWN);
1079b3697b90SSteven Stallion }
1080b3697b90SSteven Stallion 
1081b3697b90SSteven Stallion void
1082b3697b90SSteven Stallion efe_stop_dma(efe_t *efep)
1083b3697b90SSteven Stallion {
1084b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
1085b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1086b3697b90SSteven Stallion 
1087b3697b90SSteven Stallion 	PUTCSR(efep, CSR_COMMAND,
1088b3697b90SSteven Stallion 	    COMMAND_STOP_RDMA | COMMAND_STOP_TDMA);
1089b3697b90SSteven Stallion 
1090b3697b90SSteven Stallion 	for (int i = 0; i < STOP_DELAY_CYCLES; ++i) {
1091b3697b90SSteven Stallion 		uint32_t status = GETCSR(efep, CSR_INTSTAT);
1092b3697b90SSteven Stallion 		if (status & INTSTAT_RXIDLE &&
1093b3697b90SSteven Stallion 		    status & INTSTAT_TXIDLE) {
1094b3697b90SSteven Stallion 			return;
1095b3697b90SSteven Stallion 		}
1096b3697b90SSteven Stallion 		drv_usecwait(STOP_DELAY);
1097b3697b90SSteven Stallion 	}
1098b3697b90SSteven Stallion 	efe_error(efep->efe_dip, "timed out stopping DMA engine!");
1099b3697b90SSteven Stallion }
1100b3697b90SSteven Stallion 
1101*e65fcc69SRichard Lowe static inline void
1102b3697b90SSteven Stallion efe_restart(efe_t *efep)
1103b3697b90SSteven Stallion {
1104b3697b90SSteven Stallion 	efe_stop(efep);
1105b3697b90SSteven Stallion 	efe_start(efep);
1106b3697b90SSteven Stallion }
1107b3697b90SSteven Stallion 
1108b3697b90SSteven Stallion int
1109b3697b90SSteven Stallion efe_suspend(efe_t *efep)
1110b3697b90SSteven Stallion {
1111b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
1112b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
1113b3697b90SSteven Stallion 
1114b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_RUNNING) {
1115b3697b90SSteven Stallion 		efe_stop(efep);
1116b3697b90SSteven Stallion 	}
1117b3697b90SSteven Stallion 	efep->efe_flags |= FLAG_SUSPENDED;
1118b3697b90SSteven Stallion 
1119b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
1120b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
1121b3697b90SSteven Stallion 
1122b3697b90SSteven Stallion 	mii_suspend(efep->efe_miih);
1123b3697b90SSteven Stallion 
1124b3697b90SSteven Stallion 	return (DDI_SUCCESS);
1125b3697b90SSteven Stallion }
1126b3697b90SSteven Stallion 
1127b3697b90SSteven Stallion int
1128b3697b90SSteven Stallion efe_resume(efe_t *efep)
1129b3697b90SSteven Stallion {
1130b3697b90SSteven Stallion 	mutex_enter(&efep->efe_intrlock);
1131b3697b90SSteven Stallion 	mutex_enter(&efep->efe_txlock);
1132b3697b90SSteven Stallion 
1133b3697b90SSteven Stallion 	if (efep->efe_flags & FLAG_RUNNING) {
1134b3697b90SSteven Stallion 		efe_start(efep);
1135b3697b90SSteven Stallion 	}
1136b3697b90SSteven Stallion 	efep->efe_flags &= ~FLAG_SUSPENDED;
1137b3697b90SSteven Stallion 
1138b3697b90SSteven Stallion 	mutex_exit(&efep->efe_txlock);
1139b3697b90SSteven Stallion 	mutex_exit(&efep->efe_intrlock);
1140b3697b90SSteven Stallion 
1141b3697b90SSteven Stallion 	mii_resume(efep->efe_miih);
1142b3697b90SSteven Stallion 
1143b3697b90SSteven Stallion 	return (DDI_SUCCESS);
1144b3697b90SSteven Stallion }
1145b3697b90SSteven Stallion 
1146b3697b90SSteven Stallion efe_ring_t *
1147b3697b90SSteven Stallion efe_ring_alloc(dev_info_t *dip, size_t len)
1148b3697b90SSteven Stallion {
1149b3697b90SSteven Stallion 	efe_ring_t *rp;
1150b3697b90SSteven Stallion 	size_t rlen;
1151b3697b90SSteven Stallion 	uint_t ccount;
1152b3697b90SSteven Stallion 
1153b3697b90SSteven Stallion 	ASSERT(len > 1);
1154b3697b90SSteven Stallion 
1155b3697b90SSteven Stallion 	rp = kmem_zalloc(sizeof (efe_ring_t), KM_SLEEP);
1156b3697b90SSteven Stallion 	rp->r_len = len;
1157b3697b90SSteven Stallion 
1158b3697b90SSteven Stallion 	if (ddi_dma_alloc_handle(dip, &efe_dma_attr, DDI_DMA_SLEEP, NULL,
1159b3697b90SSteven Stallion 	    &rp->r_dmah) != DDI_SUCCESS) {
1160b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate DMA handle!");
1161b3697b90SSteven Stallion 		goto failure;
1162b3697b90SSteven Stallion 	}
1163b3697b90SSteven Stallion 
1164b3697b90SSteven Stallion 	if (ddi_dma_mem_alloc(rp->r_dmah, DESCSZ(len), &efe_buf_acc_attr,
1165b3697b90SSteven Stallion 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, (caddr_t *)&rp->r_descp,
1166b3697b90SSteven Stallion 	    &rlen, &rp->r_acch) != DDI_SUCCESS) {
1167b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate descriptors!");
1168b3697b90SSteven Stallion 		goto failure;
1169b3697b90SSteven Stallion 	}
1170b3697b90SSteven Stallion 
1171b3697b90SSteven Stallion 	if (ddi_dma_addr_bind_handle(rp->r_dmah, NULL, (caddr_t)rp->r_descp,
1172b3697b90SSteven Stallion 	    DESCSZ(len), DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
1173b3697b90SSteven Stallion 	    NULL, &rp->r_dmac, &ccount) != DDI_DMA_MAPPED) {
1174b3697b90SSteven Stallion 		efe_error(dip, "unable to bind DMA handle to descriptors!");
1175b3697b90SSteven Stallion 		goto failure;
1176b3697b90SSteven Stallion 	}
1177b3697b90SSteven Stallion 
1178b3697b90SSteven Stallion 	rp->r_bufpp = kmem_zalloc(BUFPSZ(len), KM_SLEEP);
1179b3697b90SSteven Stallion 
1180b3697b90SSteven Stallion 	for (int i = 0; i < len; ++i) {
1181b3697b90SSteven Stallion 		efe_buf_t *bp = efe_buf_alloc(dip, BUFSZ);
1182b3697b90SSteven Stallion 		if (bp == NULL) {
1183b3697b90SSteven Stallion 			goto failure;
1184b3697b90SSteven Stallion 		}
1185b3697b90SSteven Stallion 		rp->r_bufpp[i] = bp;
1186b3697b90SSteven Stallion 	}
1187b3697b90SSteven Stallion 
1188b3697b90SSteven Stallion 	return (rp);
1189b3697b90SSteven Stallion 
1190b3697b90SSteven Stallion failure:
1191b3697b90SSteven Stallion 	efe_ring_free(&rp);
1192b3697b90SSteven Stallion 
1193b3697b90SSteven Stallion 	return (NULL);
1194b3697b90SSteven Stallion }
1195b3697b90SSteven Stallion 
1196b3697b90SSteven Stallion void
1197b3697b90SSteven Stallion efe_ring_free(efe_ring_t **rpp)
1198b3697b90SSteven Stallion {
1199b3697b90SSteven Stallion 	efe_ring_t *rp = *rpp;
1200b3697b90SSteven Stallion 
1201b3697b90SSteven Stallion 	ASSERT(rp != NULL);
1202b3697b90SSteven Stallion 
1203b3697b90SSteven Stallion 	for (int i = 0; i < DESCLEN(rp); ++i) {
1204b3697b90SSteven Stallion 		efe_buf_t *bp = GETBUF(rp, i);
1205b3697b90SSteven Stallion 		if (bp != NULL) {
1206b3697b90SSteven Stallion 			efe_buf_free(&bp);
1207b3697b90SSteven Stallion 		}
1208b3697b90SSteven Stallion 	}
1209b3697b90SSteven Stallion 	kmem_free(rp->r_bufpp, BUFPSZ(DESCLEN(rp)));
1210b3697b90SSteven Stallion 
1211b3697b90SSteven Stallion 	if (rp->r_descp != NULL) {
1212b3697b90SSteven Stallion 		(void) ddi_dma_unbind_handle(rp->r_dmah);
1213b3697b90SSteven Stallion 	}
1214b3697b90SSteven Stallion 	if (rp->r_acch != NULL) {
1215b3697b90SSteven Stallion 		ddi_dma_mem_free(&rp->r_acch);
1216b3697b90SSteven Stallion 	}
1217b3697b90SSteven Stallion 	if (rp->r_dmah != NULL) {
1218b3697b90SSteven Stallion 		ddi_dma_free_handle(&rp->r_dmah);
1219b3697b90SSteven Stallion 	}
1220b3697b90SSteven Stallion 	kmem_free(rp, sizeof (efe_ring_t));
1221b3697b90SSteven Stallion 
1222b3697b90SSteven Stallion 	*rpp = NULL;
1223b3697b90SSteven Stallion }
1224b3697b90SSteven Stallion 
1225b3697b90SSteven Stallion efe_buf_t *
1226b3697b90SSteven Stallion efe_buf_alloc(dev_info_t *dip, size_t len)
1227b3697b90SSteven Stallion {
1228b3697b90SSteven Stallion 	efe_buf_t *bp;
1229b3697b90SSteven Stallion 	size_t rlen;
1230b3697b90SSteven Stallion 	uint_t ccount;
1231b3697b90SSteven Stallion 
1232b3697b90SSteven Stallion 	bp = kmem_zalloc(sizeof (efe_buf_t), KM_SLEEP);
1233b3697b90SSteven Stallion 	bp->b_len = len;
1234b3697b90SSteven Stallion 
1235b3697b90SSteven Stallion 	if (ddi_dma_alloc_handle(dip, &efe_dma_attr, DDI_DMA_SLEEP, NULL,
1236b3697b90SSteven Stallion 	    &bp->b_dmah) != DDI_SUCCESS) {
1237b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate DMA handle!");
1238b3697b90SSteven Stallion 		goto failure;
1239b3697b90SSteven Stallion 	}
1240b3697b90SSteven Stallion 
1241b3697b90SSteven Stallion 	if (ddi_dma_mem_alloc(bp->b_dmah, len, &efe_buf_acc_attr,
1242b3697b90SSteven Stallion 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &bp->b_kaddr, &rlen,
1243b3697b90SSteven Stallion 	    &bp->b_acch) != DDI_SUCCESS) {
1244b3697b90SSteven Stallion 		efe_error(dip, "unable to allocate buffer!");
1245b3697b90SSteven Stallion 		goto failure;
1246b3697b90SSteven Stallion 	}
1247b3697b90SSteven Stallion 
1248b3697b90SSteven Stallion 	if (ddi_dma_addr_bind_handle(bp->b_dmah, NULL, bp->b_kaddr,
1249b3697b90SSteven Stallion 	    len, DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
1250b3697b90SSteven Stallion 	    &bp->b_dmac, &ccount) != DDI_DMA_MAPPED) {
1251b3697b90SSteven Stallion 		efe_error(dip, "unable to bind DMA handle to buffer!");
1252b3697b90SSteven Stallion 		goto failure;
1253b3697b90SSteven Stallion 	}
1254b3697b90SSteven Stallion 
1255b3697b90SSteven Stallion 	return (bp);
1256b3697b90SSteven Stallion 
1257b3697b90SSteven Stallion failure:
1258b3697b90SSteven Stallion 	efe_buf_free(&bp);
1259b3697b90SSteven Stallion 
1260b3697b90SSteven Stallion 	return (NULL);
1261b3697b90SSteven Stallion }
1262b3697b90SSteven Stallion 
1263b3697b90SSteven Stallion void
1264b3697b90SSteven Stallion efe_buf_free(efe_buf_t **bpp)
1265b3697b90SSteven Stallion {
1266b3697b90SSteven Stallion 	efe_buf_t *bp = *bpp;
1267b3697b90SSteven Stallion 
1268b3697b90SSteven Stallion 	ASSERT(bp != NULL);
1269b3697b90SSteven Stallion 
1270b3697b90SSteven Stallion 	if (bp->b_kaddr != NULL) {
1271b3697b90SSteven Stallion 		(void) ddi_dma_unbind_handle(bp->b_dmah);
1272b3697b90SSteven Stallion 	}
1273b3697b90SSteven Stallion 	if (bp->b_acch != NULL) {
1274b3697b90SSteven Stallion 		ddi_dma_mem_free(&bp->b_acch);
1275b3697b90SSteven Stallion 	}
1276b3697b90SSteven Stallion 	if (bp->b_dmah != NULL) {
1277b3697b90SSteven Stallion 		ddi_dma_free_handle(&bp->b_dmah);
1278b3697b90SSteven Stallion 	}
1279b3697b90SSteven Stallion 	kmem_free(bp, sizeof (efe_buf_t));
1280b3697b90SSteven Stallion 
1281b3697b90SSteven Stallion 	*bpp = NULL;
1282b3697b90SSteven Stallion }
1283b3697b90SSteven Stallion 
1284b3697b90SSteven Stallion void
1285b3697b90SSteven Stallion efe_intr_enable(efe_t *efep)
1286b3697b90SSteven Stallion {
1287b3697b90SSteven Stallion 	PUTCSR(efep, CSR_INTMASK,
1288b3697b90SSteven Stallion 	    INTMASK_RCC | INTMASK_RQE | INTMASK_TXC | INTMASK_FATAL);
1289b3697b90SSteven Stallion 
1290b3697b90SSteven Stallion 	SETBIT(efep, CSR_GENCTL, GENCTL_INT);
1291b3697b90SSteven Stallion }
1292b3697b90SSteven Stallion 
1293b3697b90SSteven Stallion void
1294b3697b90SSteven Stallion efe_intr_disable(efe_t *efep)
1295b3697b90SSteven Stallion {
1296b3697b90SSteven Stallion 	PUTCSR(efep, CSR_INTMASK, 0);
1297b3697b90SSteven Stallion 
1298b3697b90SSteven Stallion 	CLRBIT(efep, CSR_GENCTL, GENCTL_INT);
1299b3697b90SSteven Stallion }
1300b3697b90SSteven Stallion 
1301b3697b90SSteven Stallion mblk_t *
1302b3697b90SSteven Stallion efe_recv(efe_t *efep)
1303b3697b90SSteven Stallion {
1304b3697b90SSteven Stallion 	efe_ring_t *rp;
1305b3697b90SSteven Stallion 	mblk_t *mp = NULL;
1306b3697b90SSteven Stallion 	mblk_t **mpp = &mp;
1307b3697b90SSteven Stallion 
1308b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
1309b3697b90SSteven Stallion 
1310b3697b90SSteven Stallion 	rp = efep->efe_rx_ring;
1311b3697b90SSteven Stallion 
1312b3697b90SSteven Stallion 	for (;;) {
1313b3697b90SSteven Stallion 		efe_desc_t *dp;
1314b3697b90SSteven Stallion 		uint16_t status;
1315b3697b90SSteven Stallion 
1316b3697b90SSteven Stallion 		dp = GETDESC(rp, efep->efe_rx_desc);
1317b3697b90SSteven Stallion 		SYNCDESC(rp, efep->efe_rx_desc, DDI_DMA_SYNC_FORKERNEL);
1318b3697b90SSteven Stallion 
1319b3697b90SSteven Stallion 		status = GETDESC16(rp, &dp->d_status);
1320b3697b90SSteven Stallion 
1321b3697b90SSteven Stallion 		/* Stop if device owns descriptor */
1322b3697b90SSteven Stallion 		if (status & RXSTAT_OWNER) {
1323b3697b90SSteven Stallion 			break;
1324b3697b90SSteven Stallion 		}
1325b3697b90SSteven Stallion 
1326b3697b90SSteven Stallion 		if (status & RXSTAT_PRI) {
1327b3697b90SSteven Stallion 			mblk_t *tmp = efe_recv_pkt(efep, dp);
1328b3697b90SSteven Stallion 			if (tmp != NULL) {
1329b3697b90SSteven Stallion 				*mpp = tmp;
1330b3697b90SSteven Stallion 				mpp = &tmp->b_next;
1331b3697b90SSteven Stallion 			}
1332b3697b90SSteven Stallion 
1333b3697b90SSteven Stallion 		} else {
1334b3697b90SSteven Stallion 			efep->efe_ierrors++;
1335b3697b90SSteven Stallion 
1336b3697b90SSteven Stallion 			if (status & RXSTAT_FAE) {
1337b3697b90SSteven Stallion 				efep->efe_align_errors++;
1338b3697b90SSteven Stallion 			}
1339b3697b90SSteven Stallion 			if (status & RXSTAT_CRC) {
1340b3697b90SSteven Stallion 				efep->efe_fcs_errors++;
1341b3697b90SSteven Stallion 			}
1342b3697b90SSteven Stallion 			if (status & RXSTAT_MP) {
1343b3697b90SSteven Stallion 				efep->efe_oflo++;
1344b3697b90SSteven Stallion 			}
1345b3697b90SSteven Stallion 		}
1346b3697b90SSteven Stallion 
1347b3697b90SSteven Stallion 		/* Release ownership to device */
1348b3697b90SSteven Stallion 		PUTDESC16(rp, &dp->d_status, RXSTAT_OWNER);
1349b3697b90SSteven Stallion 
1350b3697b90SSteven Stallion 		SYNCDESC(rp, efep->efe_rx_desc, DDI_DMA_SYNC_FORDEV);
1351b3697b90SSteven Stallion 
1352b3697b90SSteven Stallion 		efep->efe_rx_desc = NEXTDESC(rp, efep->efe_rx_desc);
1353b3697b90SSteven Stallion 	}
1354b3697b90SSteven Stallion 
1355b3697b90SSteven Stallion 	return (mp);
1356b3697b90SSteven Stallion }
1357b3697b90SSteven Stallion 
1358b3697b90SSteven Stallion mblk_t *
1359b3697b90SSteven Stallion efe_recv_pkt(efe_t *efep, efe_desc_t *dp)
1360b3697b90SSteven Stallion {
1361b3697b90SSteven Stallion 	efe_ring_t *rp;
1362b3697b90SSteven Stallion 	efe_buf_t *bp;
1363b3697b90SSteven Stallion 	uint16_t len;
1364b3697b90SSteven Stallion 	mblk_t *mp;
1365b3697b90SSteven Stallion 	uint16_t status;
1366b3697b90SSteven Stallion 
1367b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_intrlock));
1368b3697b90SSteven Stallion 
1369b3697b90SSteven Stallion 	rp = efep->efe_rx_ring;
1370b3697b90SSteven Stallion 
1371b3697b90SSteven Stallion 	len = GETDESC16(rp, &dp->d_len) - ETHERFCSL;
1372b3697b90SSteven Stallion 
1373b3697b90SSteven Stallion 	if (len < ETHERMIN) {
1374b3697b90SSteven Stallion 		efep->efe_ierrors++;
1375b3697b90SSteven Stallion 		efep->efe_runt_errors++;
1376b3697b90SSteven Stallion 		return (NULL);
1377b3697b90SSteven Stallion 	}
1378b3697b90SSteven Stallion 
1379b3697b90SSteven Stallion 	if (len > ETHERMAX + VLAN_TAGSZ) {
1380b3697b90SSteven Stallion 		efep->efe_ierrors++;
1381b3697b90SSteven Stallion 		efep->efe_toolong_errors++;
1382b3697b90SSteven Stallion 		return (NULL);
1383b3697b90SSteven Stallion 	}
1384b3697b90SSteven Stallion 
1385b3697b90SSteven Stallion 	mp = allocb(len, 0);
1386b3697b90SSteven Stallion 	if (mp == NULL) {
1387b3697b90SSteven Stallion 		efep->efe_ierrors++;
1388b3697b90SSteven Stallion 		efep->efe_norcvbuf++;
1389b3697b90SSteven Stallion 		return (NULL);
1390b3697b90SSteven Stallion 	}
1391b3697b90SSteven Stallion 	mp->b_wptr = mp->b_rptr + len;
1392b3697b90SSteven Stallion 
1393b3697b90SSteven Stallion 	bp = GETBUF(rp, efep->efe_rx_desc);
1394b3697b90SSteven Stallion 	SYNCBUF(bp, DDI_DMA_SYNC_FORKERNEL);
1395b3697b90SSteven Stallion 
1396b3697b90SSteven Stallion 	bcopy(bp->b_kaddr, mp->b_rptr, len);
1397b3697b90SSteven Stallion 
1398b3697b90SSteven Stallion 	efep->efe_ipackets++;
1399b3697b90SSteven Stallion 	efep->efe_rbytes += len;
1400b3697b90SSteven Stallion 
1401b3697b90SSteven Stallion 	status = GETDESC16(rp, &dp->d_status);
1402b3697b90SSteven Stallion 
1403b3697b90SSteven Stallion 	if (status & RXSTAT_BAR) {
1404b3697b90SSteven Stallion 		efep->efe_brdcstrcv++;
1405b3697b90SSteven Stallion 
1406b3697b90SSteven Stallion 	} else if (status & RXSTAT_MAR) {
1407b3697b90SSteven Stallion 		efep->efe_multircv++;
1408b3697b90SSteven Stallion 	}
1409b3697b90SSteven Stallion 
1410b3697b90SSteven Stallion 	return (mp);
1411b3697b90SSteven Stallion }
1412b3697b90SSteven Stallion 
1413b3697b90SSteven Stallion int
1414b3697b90SSteven Stallion efe_send(efe_t *efep, mblk_t *mp)
1415b3697b90SSteven Stallion {
1416b3697b90SSteven Stallion 	efe_ring_t *rp;
1417b3697b90SSteven Stallion 	uint16_t len;
1418b3697b90SSteven Stallion 	efe_desc_t *dp;
1419b3697b90SSteven Stallion 	uint16_t status;
1420b3697b90SSteven Stallion 	efe_buf_t *bp;
1421b3697b90SSteven Stallion 
1422b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1423b3697b90SSteven Stallion 
1424b3697b90SSteven Stallion 	rp = efep->efe_tx_ring;
1425b3697b90SSteven Stallion 
1426b3697b90SSteven Stallion 	len = msgsize(mp);
1427b3697b90SSteven Stallion 
1428b3697b90SSteven Stallion 	if (len > ETHERMAX + VLAN_TAGSZ) {
1429b3697b90SSteven Stallion 		efep->efe_oerrors++;
1430b3697b90SSteven Stallion 		efep->efe_macxmt_errors++;
1431b3697b90SSteven Stallion 		freemsg(mp);
1432b3697b90SSteven Stallion 		return (DDI_SUCCESS);
1433b3697b90SSteven Stallion 	}
1434b3697b90SSteven Stallion 
1435b3697b90SSteven Stallion 	dp = GETDESC(rp, efep->efe_tx_desc);
1436b3697b90SSteven Stallion 	SYNCDESC(rp, efep->efe_tx_desc, DDI_DMA_SYNC_FORKERNEL);
1437b3697b90SSteven Stallion 
1438b3697b90SSteven Stallion 	status = GETDESC16(efep->efe_tx_ring, &dp->d_status);
1439b3697b90SSteven Stallion 
1440b3697b90SSteven Stallion 	/* Stop if device owns descriptor */
1441b3697b90SSteven Stallion 	if (status & TXSTAT_OWNER) {
1442b3697b90SSteven Stallion 		return (DDI_FAILURE);
1443b3697b90SSteven Stallion 	}
1444b3697b90SSteven Stallion 
1445b3697b90SSteven Stallion 	bp = GETBUF(rp, efep->efe_tx_desc);
1446b3697b90SSteven Stallion 
1447b3697b90SSteven Stallion 	mcopymsg(mp, bp->b_kaddr);
1448b3697b90SSteven Stallion 
1449b3697b90SSteven Stallion 	/*
1450b3697b90SSteven Stallion 	 * Packets must contain at least ETHERMIN octets.
1451b3697b90SSteven Stallion 	 * Padded octets are zeroed out prior to sending.
1452b3697b90SSteven Stallion 	 */
1453b3697b90SSteven Stallion 	if (len < ETHERMIN) {
1454b3697b90SSteven Stallion 		bzero(bp->b_kaddr + len, ETHERMIN - len);
1455b3697b90SSteven Stallion 		len = ETHERMIN;
1456b3697b90SSteven Stallion 	}
1457b3697b90SSteven Stallion 
1458b3697b90SSteven Stallion 	SYNCBUF(bp, DDI_DMA_SYNC_FORDEV);
1459b3697b90SSteven Stallion 
1460b3697b90SSteven Stallion 	PUTDESC16(rp, &dp->d_status, TXSTAT_OWNER);
1461b3697b90SSteven Stallion 	PUTDESC16(rp, &dp->d_len, len);
1462b3697b90SSteven Stallion 	PUTDESC16(rp, &dp->d_control, TXCTL_LASTDESCR);
1463b3697b90SSteven Stallion 
1464b3697b90SSteven Stallion 	SYNCDESC(rp, efep->efe_tx_desc, DDI_DMA_SYNC_FORDEV);
1465b3697b90SSteven Stallion 
1466b3697b90SSteven Stallion 	efep->efe_opackets++;
1467b3697b90SSteven Stallion 	efep->efe_obytes += len;
1468b3697b90SSteven Stallion 
1469b3697b90SSteven Stallion 	if (*bp->b_kaddr & 0x01) {
1470b3697b90SSteven Stallion 		if (bcmp(bp->b_kaddr, efe_broadcast, ETHERADDRL) == 0) {
1471b3697b90SSteven Stallion 			efep->efe_brdcstxmt++;
1472b3697b90SSteven Stallion 		} else {
1473b3697b90SSteven Stallion 			efep->efe_multixmt++;
1474b3697b90SSteven Stallion 		}
1475b3697b90SSteven Stallion 	}
1476b3697b90SSteven Stallion 
1477b3697b90SSteven Stallion 	efep->efe_tx_desc = NEXTDESC(rp, efep->efe_tx_desc);
1478b3697b90SSteven Stallion 
1479b3697b90SSteven Stallion 	return (DDI_SUCCESS);
1480b3697b90SSteven Stallion }
1481b3697b90SSteven Stallion 
1482b3697b90SSteven Stallion void
1483b3697b90SSteven Stallion efe_send_done(efe_t *efep)
1484b3697b90SSteven Stallion {
1485b3697b90SSteven Stallion 	efe_ring_t *rp;
1486b3697b90SSteven Stallion 
1487b3697b90SSteven Stallion 	ASSERT(mutex_owned(&efep->efe_txlock));
1488b3697b90SSteven Stallion 
1489b3697b90SSteven Stallion 	rp = efep->efe_tx_ring;
1490b3697b90SSteven Stallion 
1491b3697b90SSteven Stallion 	for (;;) {
1492b3697b90SSteven Stallion 		efe_desc_t *dp;
1493b3697b90SSteven Stallion 		uint16_t status;
1494b3697b90SSteven Stallion 
1495b3697b90SSteven Stallion 		dp = GETDESC(rp, efep->efe_tx_sent);
1496b3697b90SSteven Stallion 		SYNCDESC(rp, efep->efe_tx_sent, DDI_DMA_SYNC_FORKERNEL);
1497b3697b90SSteven Stallion 
1498b3697b90SSteven Stallion 		status = GETDESC16(rp, &dp->d_status);
1499b3697b90SSteven Stallion 
1500b3697b90SSteven Stallion 		/* Stop if device owns descriptor */
1501b3697b90SSteven Stallion 		if (status & TXSTAT_OWNER) {
1502b3697b90SSteven Stallion 			break;
1503b3697b90SSteven Stallion 		}
1504b3697b90SSteven Stallion 
1505b3697b90SSteven Stallion 		if (status & TXSTAT_PTX) {
1506b3697b90SSteven Stallion 			if (!(status & TXSTAT_ND)) {
1507b3697b90SSteven Stallion 				efep->efe_defer_xmts++;
1508b3697b90SSteven Stallion 			}
1509b3697b90SSteven Stallion 			if (status & TXSTAT_COLL) {
1510b3697b90SSteven Stallion 				efep->efe_first_collisions++;
1511b3697b90SSteven Stallion 			}
1512b3697b90SSteven Stallion 
1513b3697b90SSteven Stallion 		} else {
1514b3697b90SSteven Stallion 			efep->efe_oerrors++;
1515b3697b90SSteven Stallion 
1516b3697b90SSteven Stallion 			if (status & TXSTAT_CSL) {
1517b3697b90SSteven Stallion 				efep->efe_carrier_errors++;
1518b3697b90SSteven Stallion 			}
1519b3697b90SSteven Stallion 			if (status & TXSTAT_UFLO) {
1520b3697b90SSteven Stallion 				efep->efe_uflo++;
1521b3697b90SSteven Stallion 			}
1522b3697b90SSteven Stallion 			if (status & TXSTAT_OWC) {
1523b3697b90SSteven Stallion 				efep->efe_tx_late_collisions++;
1524b3697b90SSteven Stallion 			}
1525b3697b90SSteven Stallion 			if (status & TXSTAT_DEFER) {
1526b3697b90SSteven Stallion 				efep->efe_jabber_errors++;
1527b3697b90SSteven Stallion 			}
1528b3697b90SSteven Stallion 			if (status & TXSTAT_EXCOLL) {
1529b3697b90SSteven Stallion 				efep->efe_ex_collisions++;
1530b3697b90SSteven Stallion 			}
1531b3697b90SSteven Stallion 		}
1532b3697b90SSteven Stallion 
1533b3697b90SSteven Stallion 		efep->efe_collisions +=
1534b3697b90SSteven Stallion 		    (status >> TXSTAT_CCNT) & TXSTAT_CCNTMASK;
1535b3697b90SSteven Stallion 
1536b3697b90SSteven Stallion 		efep->efe_tx_sent = NEXTDESC(rp, efep->efe_tx_sent);
1537b3697b90SSteven Stallion 	}
1538b3697b90SSteven Stallion }
1539b3697b90SSteven Stallion 
1540b3697b90SSteven Stallion void
1541b3697b90SSteven Stallion efe_getaddr(efe_t *efep, uint8_t *macaddr)
1542b3697b90SSteven Stallion {
1543b3697b90SSteven Stallion 	efe_eeprom_read(efep, macaddr, ETHERADDRL, 0x0);
1544b3697b90SSteven Stallion 
1545b3697b90SSteven Stallion 	efe_debug(efep->efe_dip,
1546b3697b90SSteven Stallion 	    "factory address is %02x:%02x:%02x:%02x:%02x:%02x\n",
1547b3697b90SSteven Stallion 	    macaddr[0], macaddr[1], macaddr[2], macaddr[3],
1548b3697b90SSteven Stallion 	    macaddr[4], macaddr[5]);
1549b3697b90SSteven Stallion }
1550b3697b90SSteven Stallion 
1551b3697b90SSteven Stallion void
1552b3697b90SSteven Stallion efe_setaddr(efe_t *efep, uint8_t *macaddr)
1553b3697b90SSteven Stallion {
1554b3697b90SSteven Stallion 	uint16_t val;
1555b3697b90SSteven Stallion 
1556b3697b90SSteven Stallion 	bcopy(macaddr, &val, sizeof (uint16_t));
1557b3697b90SSteven Stallion 	PUTCSR(efep, CSR_LAN0, val);
1558b3697b90SSteven Stallion 	macaddr += sizeof (uint16_t);
1559b3697b90SSteven Stallion 
1560b3697b90SSteven Stallion 	bcopy(macaddr, &val, sizeof (uint16_t));
1561b3697b90SSteven Stallion 	PUTCSR(efep, CSR_LAN1, val);
1562b3697b90SSteven Stallion 	macaddr += sizeof (uint16_t);
1563b3697b90SSteven Stallion 
1564b3697b90SSteven Stallion 	bcopy(macaddr, &val, sizeof (uint16_t));
1565b3697b90SSteven Stallion 	PUTCSR(efep, CSR_LAN2, val);
1566b3697b90SSteven Stallion }
1567b3697b90SSteven Stallion 
1568b3697b90SSteven Stallion void
1569b3697b90SSteven Stallion efe_setmchash(efe_t *efep, uint16_t *mchash)
1570b3697b90SSteven Stallion {
1571b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MC0, mchash[0]);
1572b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MC1, mchash[1]);
1573b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MC2, mchash[2]);
1574b3697b90SSteven Stallion 	PUTCSR(efep, CSR_MC3, mchash[3]);
1575b3697b90SSteven Stallion }
1576b3697b90SSteven Stallion 
1577b3697b90SSteven Stallion void
1578b3697b90SSteven Stallion efe_eeprom_read(efe_t *efep, uint8_t *buf, size_t len, uint8_t addr)
1579b3697b90SSteven Stallion {
1580b3697b90SSteven Stallion 	int addrlen;
1581b3697b90SSteven Stallion 
1582b3697b90SSteven Stallion 	ASSERT(len & ~0x1);	/* non-zero; word-aligned */
1583b3697b90SSteven Stallion 
1584b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
1585b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1586b3697b90SSteven Stallion 
1587b3697b90SSteven Stallion 	addrlen = (GETCSR(efep, CSR_EECTL) & EECTL_SIZE ?
1588b3697b90SSteven Stallion 	    AT93C46_ADDRLEN : AT93C56_ADDRLEN);
1589b3697b90SSteven Stallion 
1590b3697b90SSteven Stallion 	for (int i = 0; i < len / sizeof (uint16_t); ++i) {
1591b3697b90SSteven Stallion 		uint16_t val = efe_eeprom_readw(efep, addrlen, addr + i);
1592b3697b90SSteven Stallion 		bcopy(&val, buf, sizeof (uint16_t));
1593b3697b90SSteven Stallion 		buf += sizeof (uint16_t);
1594b3697b90SSteven Stallion 	}
1595b3697b90SSteven Stallion }
1596b3697b90SSteven Stallion 
1597b3697b90SSteven Stallion uint16_t
1598b3697b90SSteven Stallion efe_eeprom_readw(efe_t *efep, int addrlen, uint8_t addr)
1599b3697b90SSteven Stallion {
1600b3697b90SSteven Stallion 	uint16_t val = 0;
1601b3697b90SSteven Stallion 
1602b3697b90SSteven Stallion 	ASSERT(addrlen > 0);
1603b3697b90SSteven Stallion 
1604b3697b90SSteven Stallion 	/* Write Start Bit (SB) */
1605b3697b90SSteven Stallion 	efe_eeprom_writebit(efep, 1);
1606b3697b90SSteven Stallion 
1607b3697b90SSteven Stallion 	/* Write READ instruction */
1608b3697b90SSteven Stallion 	efe_eeprom_writebit(efep, 1);
1609b3697b90SSteven Stallion 	efe_eeprom_writebit(efep, 0);
1610b3697b90SSteven Stallion 
1611b3697b90SSteven Stallion 	/* Write EEPROM address */
1612b3697b90SSteven Stallion 	for (int i = addrlen - 1; i >= 0; --i) {
1613b3697b90SSteven Stallion 		efe_eeprom_writebit(efep, addr & 1U << i);
1614b3697b90SSteven Stallion 	}
1615b3697b90SSteven Stallion 
1616b3697b90SSteven Stallion 	/* Read EEPROM word */
1617b3697b90SSteven Stallion 	for (int i = EEPROM_WORDSZ - 1; i >= 0; --i) {
1618b3697b90SSteven Stallion 		val |= efe_eeprom_readbit(efep) << i;
1619b3697b90SSteven Stallion 	}
1620b3697b90SSteven Stallion 
1621b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE);
1622b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1623b3697b90SSteven Stallion 
1624b3697b90SSteven Stallion 	return (val);
1625b3697b90SSteven Stallion }
1626b3697b90SSteven Stallion 
1627b3697b90SSteven Stallion inline int
1628b3697b90SSteven Stallion efe_eeprom_readbit(efe_t *efep)
1629b3697b90SSteven Stallion {
1630b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
1631b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1632b3697b90SSteven Stallion 
1633b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS |
1634b3697b90SSteven Stallion 	    EECTL_EESK);
1635b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1636b3697b90SSteven Stallion 
1637b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
1638b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1639b3697b90SSteven Stallion 
1640b3697b90SSteven Stallion 	return (!!(GETCSR(efep, CSR_EECTL) & EECTL_EEDO));
1641b3697b90SSteven Stallion }
1642b3697b90SSteven Stallion 
1643b3697b90SSteven Stallion inline void
1644b3697b90SSteven Stallion efe_eeprom_writebit(efe_t *efep, int bit)
1645b3697b90SSteven Stallion {
1646b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
1647b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1648b3697b90SSteven Stallion 
1649b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS |
1650b3697b90SSteven Stallion 	    EECTL_EESK | (bit ? EECTL_EEDI : 0));
1651b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1652b3697b90SSteven Stallion 
1653b3697b90SSteven Stallion 	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
1654b3697b90SSteven Stallion 	drv_usecwait(EEPROM_DELAY);
1655b3697b90SSteven Stallion }
1656b3697b90SSteven Stallion 
1657b3697b90SSteven Stallion void
1658b3697b90SSteven Stallion efe_dprintf(dev_info_t *dip, int level, const char *format, ...)
1659b3697b90SSteven Stallion {
1660b3697b90SSteven Stallion 	va_list ap;
1661b3697b90SSteven Stallion 	char buf[255];
1662b3697b90SSteven Stallion 
1663b3697b90SSteven Stallion 	va_start(ap, format);
1664b3697b90SSteven Stallion 
1665b3697b90SSteven Stallion 	(void) vsnprintf(buf, sizeof (buf), format, ap);
1666b3697b90SSteven Stallion 
1667b3697b90SSteven Stallion 	cmn_err(level, "?%s%d %s", ddi_driver_name(dip),
1668b3697b90SSteven Stallion 	    ddi_get_instance(dip), buf);
1669b3697b90SSteven Stallion 
1670b3697b90SSteven Stallion 	va_end(ap);
1671b3697b90SSteven Stallion }
1672