xref: /illumos-gate/usr/src/uts/common/io/atge/atge_main.c (revision 0eb090a7674ebcdcb1c35501097edeb5f2395459)
1015a6ef6SSaurabh Misra /*
2015a6ef6SSaurabh Misra  * CDDL HEADER START
3015a6ef6SSaurabh Misra  *
4015a6ef6SSaurabh Misra  * The contents of this file are subject to the terms of the
5015a6ef6SSaurabh Misra  * Common Development and Distribution License (the "License").
6015a6ef6SSaurabh Misra  * You may not use this file except in compliance with the License.
7015a6ef6SSaurabh Misra  *
8015a6ef6SSaurabh Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9015a6ef6SSaurabh Misra  * or http://www.opensolaris.org/os/licensing.
10015a6ef6SSaurabh Misra  * See the License for the specific language governing permissions
11015a6ef6SSaurabh Misra  * and limitations under the License.
12015a6ef6SSaurabh Misra  *
13015a6ef6SSaurabh Misra  * When distributing Covered Code, include this CDDL HEADER in each
14015a6ef6SSaurabh Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15015a6ef6SSaurabh Misra  * If applicable, add the following below this CDDL HEADER, with the
16015a6ef6SSaurabh Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17015a6ef6SSaurabh Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18015a6ef6SSaurabh Misra  *
19015a6ef6SSaurabh Misra  * CDDL HEADER END
20015a6ef6SSaurabh Misra  */
21015a6ef6SSaurabh Misra 
22015a6ef6SSaurabh Misra /*
23015a6ef6SSaurabh Misra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24015a6ef6SSaurabh Misra  * Use is subject to license terms.
25015a6ef6SSaurabh Misra  */
26015a6ef6SSaurabh Misra 
27015a6ef6SSaurabh Misra #include <sys/types.h>
28015a6ef6SSaurabh Misra #include <sys/stream.h>
29015a6ef6SSaurabh Misra #include <sys/strsun.h>
30015a6ef6SSaurabh Misra #include <sys/stat.h>
31015a6ef6SSaurabh Misra #include <sys/modctl.h>
32015a6ef6SSaurabh Misra #include <sys/kstat.h>
33015a6ef6SSaurabh Misra #include <sys/ethernet.h>
34015a6ef6SSaurabh Misra #include <sys/devops.h>
35015a6ef6SSaurabh Misra #include <sys/debug.h>
36015a6ef6SSaurabh Misra #include <sys/conf.h>
37015a6ef6SSaurabh Misra #include <sys/mii.h>
38015a6ef6SSaurabh Misra #include <sys/miiregs.h>
39015a6ef6SSaurabh Misra #include <sys/mac.h>
40015a6ef6SSaurabh Misra #include <sys/mac_provider.h>
41015a6ef6SSaurabh Misra #include <sys/mac_ether.h>
42015a6ef6SSaurabh Misra #include <sys/sysmacros.h>
43015a6ef6SSaurabh Misra #include <sys/dditypes.h>
44015a6ef6SSaurabh Misra #include <sys/ddi.h>
45015a6ef6SSaurabh Misra #include <sys/sunddi.h>
46015a6ef6SSaurabh Misra #include <sys/byteorder.h>
47015a6ef6SSaurabh Misra #include <sys/note.h>
48015a6ef6SSaurabh Misra #include <sys/vlan.h>
49015a6ef6SSaurabh Misra #include <sys/strsubr.h>
50015a6ef6SSaurabh Misra #include <sys/crc32.h>
51015a6ef6SSaurabh Misra #include <sys/sdt.h>
52015a6ef6SSaurabh Misra #include <sys/pci.h>
53015a6ef6SSaurabh Misra #include <sys/pci_cap.h>
54015a6ef6SSaurabh Misra 
55015a6ef6SSaurabh Misra #include "atge.h"
56015a6ef6SSaurabh Misra #include "atge_cmn_reg.h"
57015a6ef6SSaurabh Misra #include "atge_l1e_reg.h"
58*0eb090a7SSaurabh Misra #include "atge_l1_reg.h"
59015a6ef6SSaurabh Misra 
60015a6ef6SSaurabh Misra 
61015a6ef6SSaurabh Misra /*
62015a6ef6SSaurabh Misra  * Atheros/Attansic Ethernet chips are of three types - L1, L2 and L1E.
63*0eb090a7SSaurabh Misra  * This driver is for L1E/L1 but can be extended to support other chips.
64*0eb090a7SSaurabh Misra  * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
65*0eb090a7SSaurabh Misra  * flavors only.
66015a6ef6SSaurabh Misra  *
67015a6ef6SSaurabh Misra  * Atheros/Attansic Ethernet controllers have descriptor based TX and RX
68015a6ef6SSaurabh Misra  * with an exception of L1E. L1E's RX side is not descriptor based ring.
69015a6ef6SSaurabh Misra  * The L1E's RX uses pages (not to be confused with MMU pages) for
70015a6ef6SSaurabh Misra  * receiving pkts. The header has four fields :
71015a6ef6SSaurabh Misra  *
72015a6ef6SSaurabh Misra  *        uint32_t seqno;    Sequence number of the frame.
73015a6ef6SSaurabh Misra  *        uint32_t length;   Length of the frame.
74015a6ef6SSaurabh Misra  *        uint32_t flags;    Flags
75015a6ef6SSaurabh Misra  *        uint32_t vtag;     We don't use hardware VTAG.
76015a6ef6SSaurabh Misra  *
77015a6ef6SSaurabh Misra  * We use only one queue for RX (each queue can have two pages) and each
78015a6ef6SSaurabh Misra  * page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't
79015a6ef6SSaurabh Misra  * use zero-copy RX because we are limited to two pages and each page
80015a6ef6SSaurabh Misra  * accomodates large number of pkts.
81015a6ef6SSaurabh Misra  *
82015a6ef6SSaurabh Misra  * The TX side on all three chips is descriptor based ring; and all the
83015a6ef6SSaurabh Misra  * more reason to have one driver for these chips.
84015a6ef6SSaurabh Misra  *
85015a6ef6SSaurabh Misra  * We use two locks - atge_intr_lock and atge_tx_lock. Both the locks
86015a6ef6SSaurabh Misra  * should be held if the operation has impact on the driver instance.
87015a6ef6SSaurabh Misra  *
88015a6ef6SSaurabh Misra  * All the three chips have hash-based multicast filter.
89015a6ef6SSaurabh Misra  *
90015a6ef6SSaurabh Misra  * We use CMB (Coalescing Message Block) for RX but not for TX as there
91015a6ef6SSaurabh Misra  * are some issues with TX. RX CMB is used to get the last descriptor
92015a6ef6SSaurabh Misra  * posted by the chip. Each CMB is for a RX page (one queue can have two
93015a6ef6SSaurabh Misra  * pages) and are uint32_t (4 bytes) long.
94015a6ef6SSaurabh Misra  *
95015a6ef6SSaurabh Misra  * The descriptor table should have 32-bit physical address limit due to
96015a6ef6SSaurabh Misra  * the limitation of having same high address for TX/RX/SMB/CMB. The
97015a6ef6SSaurabh Misra  * TX/RX buffers can be 64-bit.
98015a6ef6SSaurabh Misra  *
99015a6ef6SSaurabh Misra  * Every DMA memory in atge is represented by atge_dma_t be it TX/RX Buffers
100015a6ef6SSaurabh Misra  * or TX/RX descriptor table or SMB/CMB. To keep the code simple, we have
101015a6ef6SSaurabh Misra  * kept sgl as 1 so that we get contingous pages from root complex.
102*0eb090a7SSaurabh Misra  *
103*0eb090a7SSaurabh Misra  * L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are
104*0eb090a7SSaurabh Misra  * common with L1E chip (0x1026).
105015a6ef6SSaurabh Misra  */
106015a6ef6SSaurabh Misra 
107015a6ef6SSaurabh Misra /*
108015a6ef6SSaurabh Misra  * Function Prototypes for debugging.
109015a6ef6SSaurabh Misra  */
110015a6ef6SSaurabh Misra void	atge_error(dev_info_t *, char *, ...);
111015a6ef6SSaurabh Misra void	atge_debug_func(char *, ...);
112015a6ef6SSaurabh Misra 
113015a6ef6SSaurabh Misra /*
114015a6ef6SSaurabh Misra  * Function Prototypes for driver operations.
115015a6ef6SSaurabh Misra  */
116015a6ef6SSaurabh Misra static int	atge_resume(dev_info_t *);
117015a6ef6SSaurabh Misra static int	atge_add_intr(atge_t *);
118015a6ef6SSaurabh Misra static int	atge_alloc_dma(atge_t *);
119015a6ef6SSaurabh Misra static void	atge_remove_intr(atge_t *);
120015a6ef6SSaurabh Misra static void	atge_free_dma(atge_t *);
121015a6ef6SSaurabh Misra static void	atge_device_reset(atge_t *);
122015a6ef6SSaurabh Misra static void	atge_device_init(atge_t *);
123015a6ef6SSaurabh Misra static void	atge_device_start(atge_t *);
124015a6ef6SSaurabh Misra static void	atge_disable_intrs(atge_t *);
125015a6ef6SSaurabh Misra atge_dma_t *atge_alloc_a_dma_blk(atge_t *, ddi_dma_attr_t *, int, int);
126015a6ef6SSaurabh Misra void	atge_free_a_dma_blk(atge_dma_t *);
127015a6ef6SSaurabh Misra static void	atge_rxfilter(atge_t *);
128015a6ef6SSaurabh Misra static void	atge_device_reset_l1_l1e(atge_t *);
129015a6ef6SSaurabh Misra void	atge_program_ether(atge_t *atgep);
130015a6ef6SSaurabh Misra void	atge_device_restart(atge_t *);
131*0eb090a7SSaurabh Misra void	atge_device_stop(atge_t *);
132015a6ef6SSaurabh Misra static int	atge_send_a_packet(atge_t *, mblk_t *);
133015a6ef6SSaurabh Misra static uint32_t	atge_ether_crc(const uint8_t *, int);
134015a6ef6SSaurabh Misra 
135015a6ef6SSaurabh Misra 
136015a6ef6SSaurabh Misra /*
137*0eb090a7SSaurabh Misra  * L1E/L2E specific functions.
138015a6ef6SSaurabh Misra  */
139015a6ef6SSaurabh Misra void	atge_l1e_device_reset(atge_t *);
140015a6ef6SSaurabh Misra void	atge_l1e_stop_mac(atge_t *);
141015a6ef6SSaurabh Misra int	atge_l1e_alloc_dma(atge_t *);
142015a6ef6SSaurabh Misra void	atge_l1e_free_dma(atge_t *);
143015a6ef6SSaurabh Misra void	atge_l1e_init_tx_ring(atge_t *);
144015a6ef6SSaurabh Misra void	atge_l1e_init_rx_pages(atge_t *);
145015a6ef6SSaurabh Misra void	atge_l1e_program_dma(atge_t *);
146*0eb090a7SSaurabh Misra void	atge_l1e_send_packet(atge_ring_t *);
147015a6ef6SSaurabh Misra mblk_t	*atge_l1e_receive(atge_t *);
148*0eb090a7SSaurabh Misra uint_t	atge_l1e_interrupt(caddr_t, caddr_t);
149015a6ef6SSaurabh Misra void	atge_l1e_gather_stats(atge_t *);
150015a6ef6SSaurabh Misra void	atge_l1e_clear_stats(atge_t *);
151015a6ef6SSaurabh Misra 
152015a6ef6SSaurabh Misra /*
153*0eb090a7SSaurabh Misra  * L1 specific functions.
154*0eb090a7SSaurabh Misra  */
155*0eb090a7SSaurabh Misra int	atge_l1_alloc_dma(atge_t *);
156*0eb090a7SSaurabh Misra void	atge_l1_init_tx_ring(atge_t *);
157*0eb090a7SSaurabh Misra void	atge_l1_init_rx_ring(atge_t *);
158*0eb090a7SSaurabh Misra void	atge_l1_init_rr_ring(atge_t *);
159*0eb090a7SSaurabh Misra void	atge_l1_init_cmb(atge_t *);
160*0eb090a7SSaurabh Misra void	atge_l1_init_smb(atge_t *);
161*0eb090a7SSaurabh Misra void	atge_l1_program_dma(atge_t *);
162*0eb090a7SSaurabh Misra void	atge_l1_stop_tx_mac(atge_t *);
163*0eb090a7SSaurabh Misra void	atge_l1_stop_rx_mac(atge_t *);
164*0eb090a7SSaurabh Misra uint_t	atge_l1_interrupt(caddr_t, caddr_t);
165*0eb090a7SSaurabh Misra void	atge_l1_send_packet(atge_ring_t *);
166*0eb090a7SSaurabh Misra 
167*0eb090a7SSaurabh Misra 
168*0eb090a7SSaurabh Misra /*
169015a6ef6SSaurabh Misra  * Function prototyps for MII operations.
170015a6ef6SSaurabh Misra  */
171015a6ef6SSaurabh Misra uint16_t	atge_mii_read(void *, uint8_t, uint8_t);
172015a6ef6SSaurabh Misra void	atge_mii_write(void *, uint8_t, uint8_t, uint16_t);
173015a6ef6SSaurabh Misra void	atge_l1e_mii_reset(void *);
174*0eb090a7SSaurabh Misra void	atge_l1_mii_reset(void *);
175015a6ef6SSaurabh Misra static void	atge_mii_notify(void *, link_state_t);
176*0eb090a7SSaurabh Misra void	atge_tx_reclaim(atge_t *atgep, int cons);
177015a6ef6SSaurabh Misra 
178*0eb090a7SSaurabh Misra /*
179*0eb090a7SSaurabh Misra  * L1E/L2E chip.
180*0eb090a7SSaurabh Misra  */
181015a6ef6SSaurabh Misra static	mii_ops_t atge_l1e_mii_ops = {
182015a6ef6SSaurabh Misra 	MII_OPS_VERSION,
183015a6ef6SSaurabh Misra 	atge_mii_read,
184015a6ef6SSaurabh Misra 	atge_mii_write,
185015a6ef6SSaurabh Misra 	atge_mii_notify,
186015a6ef6SSaurabh Misra 	atge_l1e_mii_reset
187015a6ef6SSaurabh Misra };
188015a6ef6SSaurabh Misra 
189015a6ef6SSaurabh Misra /*
190*0eb090a7SSaurabh Misra  * L1 chip.
191*0eb090a7SSaurabh Misra  */
192*0eb090a7SSaurabh Misra static	mii_ops_t atge_l1_mii_ops = {
193*0eb090a7SSaurabh Misra 	MII_OPS_VERSION,
194*0eb090a7SSaurabh Misra 	atge_mii_read,
195*0eb090a7SSaurabh Misra 	atge_mii_write,
196*0eb090a7SSaurabh Misra 	atge_mii_notify,
197*0eb090a7SSaurabh Misra 	atge_l1_mii_reset
198*0eb090a7SSaurabh Misra };
199*0eb090a7SSaurabh Misra 
200*0eb090a7SSaurabh Misra /*
201015a6ef6SSaurabh Misra  * Function Prototypes for MAC callbacks.
202015a6ef6SSaurabh Misra  */
203015a6ef6SSaurabh Misra static int	atge_m_stat(void *, uint_t, uint64_t *);
204015a6ef6SSaurabh Misra static int	atge_m_start(void *);
205015a6ef6SSaurabh Misra static void	atge_m_stop(void *);
206015a6ef6SSaurabh Misra static int	atge_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
207015a6ef6SSaurabh Misra     uint_t, void *, uint_t *);
208015a6ef6SSaurabh Misra static int	atge_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
209015a6ef6SSaurabh Misra     const void *);
210015a6ef6SSaurabh Misra static int	atge_m_unicst(void *, const uint8_t *);
211015a6ef6SSaurabh Misra static int	atge_m_multicst(void *, boolean_t, const uint8_t *);
212015a6ef6SSaurabh Misra static int	atge_m_promisc(void *, boolean_t);
213015a6ef6SSaurabh Misra static mblk_t	*atge_m_tx(void *, mblk_t *);
214015a6ef6SSaurabh Misra 
215015a6ef6SSaurabh Misra static	mac_callbacks_t	atge_m_callbacks = {
216015a6ef6SSaurabh Misra 	MC_SETPROP | MC_GETPROP,
217015a6ef6SSaurabh Misra 	atge_m_stat,
218015a6ef6SSaurabh Misra 	atge_m_start,
219015a6ef6SSaurabh Misra 	atge_m_stop,
220015a6ef6SSaurabh Misra 	atge_m_promisc,
221015a6ef6SSaurabh Misra 	atge_m_multicst,
222015a6ef6SSaurabh Misra 	atge_m_unicst,
223015a6ef6SSaurabh Misra 	atge_m_tx,
224015a6ef6SSaurabh Misra 	NULL,		/* mc_ioctl */
225015a6ef6SSaurabh Misra 	NULL,		/* mc_getcapab */
226015a6ef6SSaurabh Misra 	NULL,		/* mc_open */
227015a6ef6SSaurabh Misra 	NULL,		/* mc_close */
228015a6ef6SSaurabh Misra 	atge_m_setprop,
229015a6ef6SSaurabh Misra 	atge_m_getprop,
230015a6ef6SSaurabh Misra };
231015a6ef6SSaurabh Misra 
232015a6ef6SSaurabh Misra /*
233015a6ef6SSaurabh Misra  * DMA Data access requirements.
234015a6ef6SSaurabh Misra  */
235015a6ef6SSaurabh Misra static struct ddi_device_acc_attr atge_dev_attr = {
236015a6ef6SSaurabh Misra 	DDI_DEVICE_ATTR_V0,
237015a6ef6SSaurabh Misra 	DDI_STRUCTURE_LE_ACC,
238015a6ef6SSaurabh Misra 	DDI_STRICTORDER_ACC
239015a6ef6SSaurabh Misra };
240015a6ef6SSaurabh Misra 
241015a6ef6SSaurabh Misra /*
242015a6ef6SSaurabh Misra  * Buffers should be native endianness.
243015a6ef6SSaurabh Misra  */
244015a6ef6SSaurabh Misra static struct ddi_device_acc_attr atge_buf_attr = {
245015a6ef6SSaurabh Misra 	DDI_DEVICE_ATTR_V0,
246015a6ef6SSaurabh Misra 	DDI_NEVERSWAP_ACC,	/* native endianness */
247015a6ef6SSaurabh Misra 	DDI_STRICTORDER_ACC
248015a6ef6SSaurabh Misra };
249015a6ef6SSaurabh Misra 
250015a6ef6SSaurabh Misra /*
251*0eb090a7SSaurabh Misra  * DMA device attributes. Buffer can be 64-bit.
252015a6ef6SSaurabh Misra  */
253015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_dma_attr_buf = {
254015a6ef6SSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
255015a6ef6SSaurabh Misra 	0,			/* dma_attr_addr_lo */
256015a6ef6SSaurabh Misra 	0x00ffffffffffull,	/* dma_attr_addr_hi */
257015a6ef6SSaurabh Misra 	0x000000003fffull,	/* dma_attr_count_max */
258015a6ef6SSaurabh Misra 	8,			/* dma_attr_align */
259015a6ef6SSaurabh Misra 	0x00003ffc,		/* dma_attr_burstsizes */
260015a6ef6SSaurabh Misra 	1,			/* dma_attr_minxfer */
261015a6ef6SSaurabh Misra 	0x0000000027ffull,	/* dma_attr_maxxfer */
262015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_seg */
263015a6ef6SSaurabh Misra 	1,			/* dma_attr_sgllen */
264015a6ef6SSaurabh Misra 	1,			/* dma_attr_granular */
265015a6ef6SSaurabh Misra 	0			/* dma_attr_flags */
266015a6ef6SSaurabh Misra };
267015a6ef6SSaurabh Misra 
268015a6ef6SSaurabh Misra /*
269015a6ef6SSaurabh Misra  * Table of supported devices.
270015a6ef6SSaurabh Misra  */
271015a6ef6SSaurabh Misra #define	ATGE_VENDOR_ID	0x1969
272015a6ef6SSaurabh Misra #define	ATGE_L1E_STR	"Atheros AR8121/8113/8114"
273015a6ef6SSaurabh Misra 
274015a6ef6SSaurabh Misra static atge_cards_t atge_cards[] = {
275015a6ef6SSaurabh Misra 	{ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E},
276*0eb090a7SSaurabh Misra 	{ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, "Attansic L1", ATGE_CHIP_L1},
277015a6ef6SSaurabh Misra };
278015a6ef6SSaurabh Misra 
279015a6ef6SSaurabh Misra /*
280015a6ef6SSaurabh Misra  * Global Debugging flag. Developer level debugging is done only in DEBUG mode.
281015a6ef6SSaurabh Misra  */
282015a6ef6SSaurabh Misra int	atge_debug = 1;
283015a6ef6SSaurabh Misra 
284015a6ef6SSaurabh Misra /*
285015a6ef6SSaurabh Misra  * Debugging and error reporting.
286015a6ef6SSaurabh Misra  */
287015a6ef6SSaurabh Misra void
288015a6ef6SSaurabh Misra atge_debug_func(char *fmt, ...)
289015a6ef6SSaurabh Misra {
290015a6ef6SSaurabh Misra 	va_list	ap;
291015a6ef6SSaurabh Misra 	char	buf[256];
292015a6ef6SSaurabh Misra 
293015a6ef6SSaurabh Misra 	va_start(ap, fmt);
294015a6ef6SSaurabh Misra 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
295015a6ef6SSaurabh Misra 	va_end(ap);
296015a6ef6SSaurabh Misra 
297015a6ef6SSaurabh Misra 	DTRACE_PROBE1(atge__debug, char *, buf);
298015a6ef6SSaurabh Misra }
299015a6ef6SSaurabh Misra 
300015a6ef6SSaurabh Misra void
301015a6ef6SSaurabh Misra atge_error(dev_info_t *dip, char *fmt, ...)
302015a6ef6SSaurabh Misra {
303015a6ef6SSaurabh Misra 	va_list	ap;
304015a6ef6SSaurabh Misra 	char	buf[256];
305015a6ef6SSaurabh Misra 
306015a6ef6SSaurabh Misra 	va_start(ap, fmt);
307015a6ef6SSaurabh Misra 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
308015a6ef6SSaurabh Misra 	va_end(ap);
309015a6ef6SSaurabh Misra 
310015a6ef6SSaurabh Misra 	if (dip) {
311015a6ef6SSaurabh Misra 		cmn_err(CE_WARN, "%s%d: %s",
312015a6ef6SSaurabh Misra 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
313015a6ef6SSaurabh Misra 	} else {
314015a6ef6SSaurabh Misra 		cmn_err(CE_WARN, "atge: %s", buf);
315015a6ef6SSaurabh Misra 	}
316015a6ef6SSaurabh Misra }
317015a6ef6SSaurabh Misra 
318015a6ef6SSaurabh Misra void
319015a6ef6SSaurabh Misra atge_mac_config(atge_t *atgep)
320015a6ef6SSaurabh Misra {
321015a6ef6SSaurabh Misra 	uint32_t reg;
322015a6ef6SSaurabh Misra 	int speed;
323015a6ef6SSaurabh Misra 	link_duplex_t ld;
324015a6ef6SSaurabh Misra 
325015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_MAC_CFG);
326015a6ef6SSaurabh Misra 	reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC |
327015a6ef6SSaurabh Misra 	    ATGE_CFG_SPEED_MASK);
328015a6ef6SSaurabh Misra 
329015a6ef6SSaurabh Misra 	speed = mii_get_speed(atgep->atge_mii);
330015a6ef6SSaurabh Misra 	switch (speed) {
331015a6ef6SSaurabh Misra 	case 10:
332015a6ef6SSaurabh Misra 	case 100:
333015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_10_100;
334015a6ef6SSaurabh Misra 		break;
335015a6ef6SSaurabh Misra 	case 1000:
336015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_1000;
337015a6ef6SSaurabh Misra 		break;
338015a6ef6SSaurabh Misra 	}
339015a6ef6SSaurabh Misra 
340015a6ef6SSaurabh Misra 	ld = mii_get_duplex(atgep->atge_mii);
341015a6ef6SSaurabh Misra 	if (ld == LINK_DUPLEX_FULL)
342015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_FULL_DUPLEX;
343015a6ef6SSaurabh Misra 
344015a6ef6SSaurabh Misra 	/* Re-enable TX/RX MACs */
345*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
346015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC;
347*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
348*0eb090a7SSaurabh Misra 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
349*0eb090a7SSaurabh Misra 	}
350*0eb090a7SSaurabh Misra 
351015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAC_CFG, reg);
352015a6ef6SSaurabh Misra 
353015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
354015a6ef6SSaurabh Misra 		reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
355015a6ef6SSaurabh Misra 		reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) <<
356015a6ef6SSaurabh Misra 		    IM_TIMER_TX_SHIFT;
357015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_IM_TIMER, reg);
358015a6ef6SSaurabh Misra 	}
359015a6ef6SSaurabh Misra 
360015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mac_cfg is : %x",
361015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, INL(atgep, ATGE_MAC_CFG)));
362015a6ef6SSaurabh Misra }
363015a6ef6SSaurabh Misra 
364015a6ef6SSaurabh Misra static void
365015a6ef6SSaurabh Misra atge_mii_notify(void *arg, link_state_t link)
366015a6ef6SSaurabh Misra {
367015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
368015a6ef6SSaurabh Misra 
369015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x",
370015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, atgep->atge_link_state, link));
371015a6ef6SSaurabh Misra 
372015a6ef6SSaurabh Misra 	mac_link_update(atgep->atge_mh, link);
373015a6ef6SSaurabh Misra 
374015a6ef6SSaurabh Misra 	/*
375015a6ef6SSaurabh Misra 	 * Reconfigure MAC if link status is UP now.
376015a6ef6SSaurabh Misra 	 */
377015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
378015a6ef6SSaurabh Misra 	if (link == LINK_STATE_UP) {
379015a6ef6SSaurabh Misra 		atgep->atge_link_state = LINK_STATE_UP;
380*0eb090a7SSaurabh Misra 		atge_mac_config(atgep);
381015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 0;
382015a6ef6SSaurabh Misra 	} else {
383015a6ef6SSaurabh Misra 		atgep->atge_link_state = LINK_STATE_DOWN;
384*0eb090a7SSaurabh Misra 		atgep->atge_flags |= ATGE_MII_CHECK;
385015a6ef6SSaurabh Misra 	}
386015a6ef6SSaurabh Misra 
387015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
388015a6ef6SSaurabh Misra 
389015a6ef6SSaurabh Misra 	if (link == LINK_STATE_UP)
390015a6ef6SSaurabh Misra 		mac_tx_update(atgep->atge_mh);
391015a6ef6SSaurabh Misra }
392015a6ef6SSaurabh Misra 
393*0eb090a7SSaurabh Misra void
394*0eb090a7SSaurabh Misra atge_tx_reclaim(atge_t *atgep, int end)
395015a6ef6SSaurabh Misra {
396*0eb090a7SSaurabh Misra 	atge_tx_desc_t  *txd;
397*0eb090a7SSaurabh Misra 	atge_ring_t *r = atgep->atge_tx_ring;
398*0eb090a7SSaurabh Misra 	uchar_t *c;
399*0eb090a7SSaurabh Misra 	int start;
400015a6ef6SSaurabh Misra 
401*0eb090a7SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
402*0eb090a7SSaurabh Misra 	ASSERT(r != NULL);
403015a6ef6SSaurabh Misra 
404*0eb090a7SSaurabh Misra 	start = r->r_consumer;
405015a6ef6SSaurabh Misra 
406*0eb090a7SSaurabh Misra 	if (start == end)
407*0eb090a7SSaurabh Misra 		return;
408015a6ef6SSaurabh Misra 
409*0eb090a7SSaurabh Misra 	while (start != end) {
410*0eb090a7SSaurabh Misra 		r->r_avail_desc++;
411*0eb090a7SSaurabh Misra 		if (r->r_avail_desc > ATGE_TX_RING_CNT) {
412015a6ef6SSaurabh Misra 
413015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
414*0eb090a7SSaurabh Misra 			    "Reclaim : TX descriptor error");
415015a6ef6SSaurabh Misra 
416*0eb090a7SSaurabh Misra 			if (r->r_avail_desc > (ATGE_TX_RING_CNT + 5)) {
417015a6ef6SSaurabh Misra 				atge_device_stop(atgep);
418*0eb090a7SSaurabh Misra 				break;
419015a6ef6SSaurabh Misra 			}
420015a6ef6SSaurabh Misra 		}
421015a6ef6SSaurabh Misra 
422*0eb090a7SSaurabh Misra 		c = (uchar_t *)r->r_desc_ring->addr;
423*0eb090a7SSaurabh Misra 		c += (sizeof (atge_tx_desc_t) * start);
424*0eb090a7SSaurabh Misra 		txd = (atge_tx_desc_t *)c;
425015a6ef6SSaurabh Misra 
426015a6ef6SSaurabh Misra 		/*
427*0eb090a7SSaurabh Misra 		 * Clearing TX descriptor helps in debugging some strange
428*0eb090a7SSaurabh Misra 		 * problems.
429015a6ef6SSaurabh Misra 		 */
430*0eb090a7SSaurabh Misra 		txd->addr = 0;
431*0eb090a7SSaurabh Misra 		txd->len = 0;
432*0eb090a7SSaurabh Misra 		txd->flags = 0;
433015a6ef6SSaurabh Misra 
434*0eb090a7SSaurabh Misra 		ATGE_INC_SLOT(start, ATGE_TX_RING_CNT);
435015a6ef6SSaurabh Misra 	}
436015a6ef6SSaurabh Misra 
437*0eb090a7SSaurabh Misra 	atgep->atge_tx_ring->r_consumer = start;
438015a6ef6SSaurabh Misra 
439*0eb090a7SSaurabh Misra 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
440015a6ef6SSaurabh Misra }
441015a6ef6SSaurabh Misra 
442015a6ef6SSaurabh Misra /*
443015a6ef6SSaurabh Misra  * Adds interrupt handler depending upon the type of interrupt supported by
444015a6ef6SSaurabh Misra  * the chip.
445015a6ef6SSaurabh Misra  */
446015a6ef6SSaurabh Misra static int
447015a6ef6SSaurabh Misra atge_add_intr_handler(atge_t *atgep, int intr_type)
448015a6ef6SSaurabh Misra {
449015a6ef6SSaurabh Misra 	int err;
450015a6ef6SSaurabh Misra 	int count = 0;
451015a6ef6SSaurabh Misra 	int avail = 0;
452015a6ef6SSaurabh Misra 	int i;
453015a6ef6SSaurabh Misra 	int flag;
454015a6ef6SSaurabh Misra 
455015a6ef6SSaurabh Misra 	if (intr_type != DDI_INTR_TYPE_FIXED) {
456015a6ef6SSaurabh Misra 		err = ddi_intr_get_nintrs(atgep->atge_dip, intr_type, &count);
457015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
458015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
459015a6ef6SSaurabh Misra 			    "ddi_intr_get_nintrs failed : %d", err);
460*0eb090a7SSaurabh Misra 			return (DDI_FAILURE);
461015a6ef6SSaurabh Misra 		}
462015a6ef6SSaurabh Misra 
463015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() count : %d",
464015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__, count));
465015a6ef6SSaurabh Misra 
466015a6ef6SSaurabh Misra 		err = ddi_intr_get_navail(atgep->atge_dip, intr_type, &avail);
467015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
468015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
469015a6ef6SSaurabh Misra 			    "ddi_intr_get_navail failed : %d", err);
470*0eb090a7SSaurabh Misra 			return (DDI_FAILURE);
471015a6ef6SSaurabh Misra 		}
472015a6ef6SSaurabh Misra 
473015a6ef6SSaurabh Misra 		if (avail < count) {
474015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip, "count :%d,"
475015a6ef6SSaurabh Misra 			    " avail : %d", count, avail);
476015a6ef6SSaurabh Misra 		}
477015a6ef6SSaurabh Misra 
478015a6ef6SSaurabh Misra 		flag = DDI_INTR_ALLOC_STRICT;
479015a6ef6SSaurabh Misra 	} else {
480015a6ef6SSaurabh Misra 		/*
481015a6ef6SSaurabh Misra 		 * DDI_INTR_TYPE_FIXED case.
482015a6ef6SSaurabh Misra 		 */
483015a6ef6SSaurabh Misra 		count = 1;
484015a6ef6SSaurabh Misra 		avail = 1;
485015a6ef6SSaurabh Misra 		flag = DDI_INTR_ALLOC_NORMAL;
486015a6ef6SSaurabh Misra 	}
487015a6ef6SSaurabh Misra 
488015a6ef6SSaurabh Misra 	atgep->atge_intr_size = avail * sizeof (ddi_intr_handle_t);
489015a6ef6SSaurabh Misra 	atgep->atge_intr_handle = kmem_zalloc(atgep->atge_intr_size, KM_SLEEP);
490015a6ef6SSaurabh Misra 
491015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d",
492015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, avail, count,
493015a6ef6SSaurabh Misra 	    intr_type));
494015a6ef6SSaurabh Misra 
495015a6ef6SSaurabh Misra 	err = ddi_intr_alloc(atgep->atge_dip, atgep->atge_intr_handle,
496015a6ef6SSaurabh Misra 	    intr_type, 0, avail, &atgep->atge_intr_cnt, flag);
497015a6ef6SSaurabh Misra 
498015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
499015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "ddi_intr_alloc failed : %d", err);
500015a6ef6SSaurabh Misra 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
501*0eb090a7SSaurabh Misra 		return (DDI_FAILURE);
502015a6ef6SSaurabh Misra 	}
503015a6ef6SSaurabh Misra 
504015a6ef6SSaurabh Misra 	ATGE_DB(("%s: atge_add_intr_handler() after alloc count"
505015a6ef6SSaurabh Misra 	    " :%d, avail : %d", atgep->atge_name, count, avail));
506015a6ef6SSaurabh Misra 
507015a6ef6SSaurabh Misra 	err = ddi_intr_get_pri(atgep->atge_intr_handle[0],
508015a6ef6SSaurabh Misra 	    &atgep->atge_intr_pri);
509015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
510015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "ddi_intr_get_pri failed:%d", err);
511015a6ef6SSaurabh Misra 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
512015a6ef6SSaurabh Misra 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
513015a6ef6SSaurabh Misra 		}
514015a6ef6SSaurabh Misra 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
515015a6ef6SSaurabh Misra 
516*0eb090a7SSaurabh Misra 		return (DDI_FAILURE);
517015a6ef6SSaurabh Misra 	}
518015a6ef6SSaurabh Misra 
519015a6ef6SSaurabh Misra 	/*
520015a6ef6SSaurabh Misra 	 * Add interrupt handler now.
521015a6ef6SSaurabh Misra 	 */
522015a6ef6SSaurabh Misra 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
523*0eb090a7SSaurabh Misra 		if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
524015a6ef6SSaurabh Misra 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
525015a6ef6SSaurabh Misra 			    atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i);
526*0eb090a7SSaurabh Misra 		} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
527*0eb090a7SSaurabh Misra 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
528*0eb090a7SSaurabh Misra 			    atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i);
529*0eb090a7SSaurabh Misra 		}
530015a6ef6SSaurabh Misra 
531015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
532015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
533015a6ef6SSaurabh Misra 			    "ddi_intr_add_handler failed : %d", err);
534015a6ef6SSaurabh Misra 
535015a6ef6SSaurabh Misra 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
536015a6ef6SSaurabh Misra 			while (--i >= 0) {
537015a6ef6SSaurabh Misra 				(void) ddi_intr_remove_handler(
538015a6ef6SSaurabh Misra 				    atgep->atge_intr_handle[i]);
539015a6ef6SSaurabh Misra 				(void) ddi_intr_free(
540015a6ef6SSaurabh Misra 				    atgep->atge_intr_handle[i]);
541015a6ef6SSaurabh Misra 			}
542015a6ef6SSaurabh Misra 
543015a6ef6SSaurabh Misra 			kmem_free(atgep->atge_intr_handle,
544015a6ef6SSaurabh Misra 			    atgep->atge_intr_size);
545015a6ef6SSaurabh Misra 
546*0eb090a7SSaurabh Misra 			return (DDI_FAILURE);
547015a6ef6SSaurabh Misra 		}
548015a6ef6SSaurabh Misra 	}
549015a6ef6SSaurabh Misra 
550015a6ef6SSaurabh Misra 	err = ddi_intr_get_cap(atgep->atge_intr_handle[0],
551015a6ef6SSaurabh Misra 	    &atgep->atge_intr_cap);
552015a6ef6SSaurabh Misra 
553015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
554015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip,
555015a6ef6SSaurabh Misra 		    "ddi_intr_get_cap failed : %d", err);
556015a6ef6SSaurabh Misra 		atge_remove_intr(atgep);
557*0eb090a7SSaurabh Misra 		return (DDI_FAILURE);
558015a6ef6SSaurabh Misra 	}
559015a6ef6SSaurabh Misra 
560015a6ef6SSaurabh Misra 	if (intr_type == DDI_INTR_TYPE_FIXED)
561015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_FIXED_TYPE;
562015a6ef6SSaurabh Misra 	else if (intr_type == DDI_INTR_TYPE_MSI)
563015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_MSI_TYPE;
564015a6ef6SSaurabh Misra 	else if (intr_type == DDI_INTR_TYPE_MSIX)
565015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_MSIX_TYPE;
566015a6ef6SSaurabh Misra 
567*0eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
568015a6ef6SSaurabh Misra }
569015a6ef6SSaurabh Misra 
570015a6ef6SSaurabh Misra void
571015a6ef6SSaurabh Misra atge_remove_intr(atge_t *atgep)
572015a6ef6SSaurabh Misra {
573015a6ef6SSaurabh Misra 	int i;
574015a6ef6SSaurabh Misra 	int cap = 0;
575015a6ef6SSaurabh Misra 
576015a6ef6SSaurabh Misra 	if (atgep->atge_intr_handle == NULL)
577015a6ef6SSaurabh Misra 		return;
578015a6ef6SSaurabh Misra 
579015a6ef6SSaurabh Misra 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
580015a6ef6SSaurabh Misra 		(void) ddi_intr_block_disable(atgep->atge_intr_handle,
581015a6ef6SSaurabh Misra 		    atgep->atge_intr_cnt);
582015a6ef6SSaurabh Misra 
583015a6ef6SSaurabh Misra 		cap = 1;
584015a6ef6SSaurabh Misra 	}
585015a6ef6SSaurabh Misra 
586015a6ef6SSaurabh Misra 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
587015a6ef6SSaurabh Misra 		if (cap == 0)
588015a6ef6SSaurabh Misra 			(void) ddi_intr_disable(atgep->atge_intr_handle[i]);
589015a6ef6SSaurabh Misra 
590015a6ef6SSaurabh Misra 		(void) ddi_intr_remove_handler(atgep->atge_intr_handle[i]);
591015a6ef6SSaurabh Misra 		(void) ddi_intr_free(atgep->atge_intr_handle[i]);
592015a6ef6SSaurabh Misra 	}
593015a6ef6SSaurabh Misra 
594015a6ef6SSaurabh Misra 	kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
595015a6ef6SSaurabh Misra }
596015a6ef6SSaurabh Misra 
597015a6ef6SSaurabh Misra int
598015a6ef6SSaurabh Misra atge_enable_intrs(atge_t *atgep)
599015a6ef6SSaurabh Misra {
600015a6ef6SSaurabh Misra 	int err;
601015a6ef6SSaurabh Misra 	int i;
602015a6ef6SSaurabh Misra 
603015a6ef6SSaurabh Misra 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
604015a6ef6SSaurabh Misra 		/*
605015a6ef6SSaurabh Misra 		 * Do block enable.
606015a6ef6SSaurabh Misra 		 */
607015a6ef6SSaurabh Misra 		err = ddi_intr_block_enable(atgep->atge_intr_handle,
608015a6ef6SSaurabh Misra 		    atgep->atge_intr_cnt);
609015a6ef6SSaurabh Misra 
610015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
611015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
612015a6ef6SSaurabh Misra 			    "Failed to block enable intrs %d", err);
613*0eb090a7SSaurabh Misra 			err = DDI_FAILURE;
614015a6ef6SSaurabh Misra 		} else {
615*0eb090a7SSaurabh Misra 			err = DDI_SUCCESS;
616015a6ef6SSaurabh Misra 		}
617015a6ef6SSaurabh Misra 	} else {
618015a6ef6SSaurabh Misra 		/*
619015a6ef6SSaurabh Misra 		 * Call ddi_intr_enable() for MSI non-block enable.
620015a6ef6SSaurabh Misra 		 */
621015a6ef6SSaurabh Misra 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
622015a6ef6SSaurabh Misra 			err = ddi_intr_enable(atgep->atge_intr_handle[i]);
623015a6ef6SSaurabh Misra 			if (err != DDI_SUCCESS) {
624015a6ef6SSaurabh Misra 				atge_error(atgep->atge_dip,
625015a6ef6SSaurabh Misra 				    "Failed to enable intrs on %d with : %d",
626015a6ef6SSaurabh Misra 				    i, err);
627015a6ef6SSaurabh Misra 				break;
628015a6ef6SSaurabh Misra 			}
629015a6ef6SSaurabh Misra 		}
630015a6ef6SSaurabh Misra 
631015a6ef6SSaurabh Misra 		if (err == DDI_SUCCESS)
632*0eb090a7SSaurabh Misra 			err = DDI_SUCCESS;
633015a6ef6SSaurabh Misra 		else
634*0eb090a7SSaurabh Misra 			err = DDI_FAILURE;
635015a6ef6SSaurabh Misra 	}
636015a6ef6SSaurabh Misra 
637015a6ef6SSaurabh Misra 	return (err);
638015a6ef6SSaurabh Misra }
639015a6ef6SSaurabh Misra 
640015a6ef6SSaurabh Misra /*
641015a6ef6SSaurabh Misra  * Adds interrupt handler depending on the supported interrupt type by the
642015a6ef6SSaurabh Misra  * chip.
643015a6ef6SSaurabh Misra  */
644015a6ef6SSaurabh Misra static int
645015a6ef6SSaurabh Misra atge_add_intr(atge_t *atgep)
646015a6ef6SSaurabh Misra {
647015a6ef6SSaurabh Misra 	int	err;
648015a6ef6SSaurabh Misra 
649015a6ef6SSaurabh Misra 	/*
650015a6ef6SSaurabh Misra 	 * Get the supported interrupt types.
651015a6ef6SSaurabh Misra 	 */
652015a6ef6SSaurabh Misra 	err = ddi_intr_get_supported_types(atgep->atge_dip,
653015a6ef6SSaurabh Misra 	    &atgep->atge_intr_types);
654015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
655015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip,
656015a6ef6SSaurabh Misra 		    "ddi_intr_get_supported_types failed : %d", err);
657*0eb090a7SSaurabh Misra 		return (DDI_FAILURE);
658015a6ef6SSaurabh Misra 	}
659015a6ef6SSaurabh Misra 
660015a6ef6SSaurabh Misra 	ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d",
661015a6ef6SSaurabh Misra 	    atgep->atge_name, atgep->atge_intr_types));
662015a6ef6SSaurabh Misra 
663015a6ef6SSaurabh Misra 
664015a6ef6SSaurabh Misra 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSIX) {
665015a6ef6SSaurabh Misra 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSIX);
666*0eb090a7SSaurabh Misra 		if (err == DDI_SUCCESS) {
667015a6ef6SSaurabh Misra 			ATGE_DB(("%s: Using MSIx for interrupt",
668015a6ef6SSaurabh Misra 			    atgep->atge_name));
669015a6ef6SSaurabh Misra 			return (err);
670015a6ef6SSaurabh Misra 		}
671015a6ef6SSaurabh Misra 	}
672015a6ef6SSaurabh Misra 
673015a6ef6SSaurabh Misra 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSI) {
674015a6ef6SSaurabh Misra 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSI);
675*0eb090a7SSaurabh Misra 		if (err == DDI_SUCCESS) {
676015a6ef6SSaurabh Misra 			ATGE_DB(("%s: Using MSI for interrupt",
677015a6ef6SSaurabh Misra 			    atgep->atge_name));
678015a6ef6SSaurabh Misra 			return (err);
679015a6ef6SSaurabh Misra 		}
680015a6ef6SSaurabh Misra 	}
681015a6ef6SSaurabh Misra 
682*0eb090a7SSaurabh Misra 	err = DDI_FAILURE;
683015a6ef6SSaurabh Misra 	if (atgep->atge_intr_types & DDI_INTR_TYPE_FIXED) {
684015a6ef6SSaurabh Misra 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_FIXED);
685*0eb090a7SSaurabh Misra 		if (err == DDI_SUCCESS) {
686015a6ef6SSaurabh Misra 			ATGE_DB(("%s: Using FIXED type for interrupt",
687015a6ef6SSaurabh Misra 			    atgep->atge_name));
688015a6ef6SSaurabh Misra 			return (err);
689015a6ef6SSaurabh Misra 		}
690015a6ef6SSaurabh Misra 	}
691015a6ef6SSaurabh Misra 
692015a6ef6SSaurabh Misra 	return (err);
693015a6ef6SSaurabh Misra }
694015a6ef6SSaurabh Misra 
695015a6ef6SSaurabh Misra int
696015a6ef6SSaurabh Misra atge_identify_hardware(atge_t *atgep)
697015a6ef6SSaurabh Misra {
698015a6ef6SSaurabh Misra 	uint16_t vid, did;
699015a6ef6SSaurabh Misra 	int i;
700015a6ef6SSaurabh Misra 
701015a6ef6SSaurabh Misra 	vid = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_VENID);
702015a6ef6SSaurabh Misra 	did = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_DEVID);
703015a6ef6SSaurabh Misra 
704015a6ef6SSaurabh Misra 	atgep->atge_model = 0;
705015a6ef6SSaurabh Misra 	for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) {
706015a6ef6SSaurabh Misra 		if (atge_cards[i].vendor_id == vid &&
707015a6ef6SSaurabh Misra 		    atge_cards[i].device_id == did) {
708015a6ef6SSaurabh Misra 			atgep->atge_model = atge_cards[i].model;
709015a6ef6SSaurabh Misra 			atgep->atge_revid =
710015a6ef6SSaurabh Misra 			    pci_config_get8(atgep->atge_conf_handle,
711015a6ef6SSaurabh Misra 			    PCI_CONF_REVID);
712015a6ef6SSaurabh Misra 			ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
713015a6ef6SSaurabh Misra 			    atgep->atge_name, __func__, vid, did,
714015a6ef6SSaurabh Misra 			    atgep->atge_model));
715015a6ef6SSaurabh Misra 
716*0eb090a7SSaurabh Misra 			return (DDI_SUCCESS);
717015a6ef6SSaurabh Misra 		}
718015a6ef6SSaurabh Misra 	}
719015a6ef6SSaurabh Misra 
720015a6ef6SSaurabh Misra 	atge_error(atgep->atge_dip, "atge driver is attaching to unknown"
721015a6ef6SSaurabh Misra 	    " pci%d,%d vendor/device-id card", vid, did);
722015a6ef6SSaurabh Misra 
723015a6ef6SSaurabh Misra 	/*
724*0eb090a7SSaurabh Misra 	 * Assume it's L1 chip.
725015a6ef6SSaurabh Misra 	 */
726*0eb090a7SSaurabh Misra 	atgep->atge_model = ATGE_CHIP_L1;
727015a6ef6SSaurabh Misra 	atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle,
728015a6ef6SSaurabh Misra 	    PCI_CONF_REVID);
729015a6ef6SSaurabh Misra 
730015a6ef6SSaurabh Misra 	/*
731015a6ef6SSaurabh Misra 	 * We will leave the decision to caller.
732015a6ef6SSaurabh Misra 	 */
733*0eb090a7SSaurabh Misra 	return (DDI_FAILURE);
734015a6ef6SSaurabh Misra }
735015a6ef6SSaurabh Misra 
736015a6ef6SSaurabh Misra int
737015a6ef6SSaurabh Misra atge_get_macaddr(atge_t *atgep)
738015a6ef6SSaurabh Misra {
739015a6ef6SSaurabh Misra 	uint32_t reg;
740015a6ef6SSaurabh Misra 
741015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_SPI_CTRL);
742015a6ef6SSaurabh Misra 	if ((reg & SPI_VPD_ENB) != 0) {
743015a6ef6SSaurabh Misra 		/*
744015a6ef6SSaurabh Misra 		 * Get VPD stored in TWSI EEPROM.
745015a6ef6SSaurabh Misra 		 */
746015a6ef6SSaurabh Misra 		reg &= ~SPI_VPD_ENB;
747015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_SPI_CTRL, reg);
748015a6ef6SSaurabh Misra 
749015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s called Get VPD", atgep->atge_name, __func__));
750015a6ef6SSaurabh Misra 	}
751015a6ef6SSaurabh Misra 
752015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[5] = INB(atgep, ATGE_PAR0 + 0);
753015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[4] = INB(atgep, ATGE_PAR0 + 1);
754015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[3] = INB(atgep, ATGE_PAR0 + 2);
755015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[2] = INB(atgep, ATGE_PAR0 + 3);
756015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[1] = INB(atgep, ATGE_PAR1 + 0);
757015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[0] = INB(atgep, ATGE_PAR1 + 1);
758015a6ef6SSaurabh Misra 
759015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x",
760015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__,
761015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[0],
762015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[1],
763015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[2],
764015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[3],
765015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[4],
766015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[5]));
767015a6ef6SSaurabh Misra 
768015a6ef6SSaurabh Misra 	bcopy(atgep->atge_ether_addr, atgep->atge_dev_addr, ETHERADDRL);
769015a6ef6SSaurabh Misra 
770*0eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
771015a6ef6SSaurabh Misra }
772015a6ef6SSaurabh Misra 
773015a6ef6SSaurabh Misra /*
774015a6ef6SSaurabh Misra  * Reset functionality for L1 and L1E. It's same.
775015a6ef6SSaurabh Misra  */
776015a6ef6SSaurabh Misra static void
777015a6ef6SSaurabh Misra atge_device_reset(atge_t *atgep)
778015a6ef6SSaurabh Misra {
779015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E ||
780015a6ef6SSaurabh Misra 	    ATGE_MODEL(atgep) == ATGE_CHIP_L1)
781015a6ef6SSaurabh Misra 		atge_device_reset_l1_l1e(atgep);
782015a6ef6SSaurabh Misra }
783015a6ef6SSaurabh Misra 
784015a6ef6SSaurabh Misra void
785015a6ef6SSaurabh Misra atge_device_reset_l1_l1e(atge_t *atgep)
786015a6ef6SSaurabh Misra {
787015a6ef6SSaurabh Misra 	uint32_t reg;
788015a6ef6SSaurabh Misra 	int t;
789015a6ef6SSaurabh Misra 
790015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
791015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_MASTER_CFG);
792015a6ef6SSaurabh Misra 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
793015a6ef6SSaurabh Misra 		drv_usecwait(10);
794015a6ef6SSaurabh Misra 		reg = INL(atgep, ATGE_MASTER_CFG);
795015a6ef6SSaurabh Misra 		if ((reg & MASTER_RESET) == 0)
796015a6ef6SSaurabh Misra 			break;
797015a6ef6SSaurabh Misra 	}
798015a6ef6SSaurabh Misra 
799015a6ef6SSaurabh Misra 	if (t == 0) {
800015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, " master reset timeout reg : %x",
801015a6ef6SSaurabh Misra 		    reg);
802015a6ef6SSaurabh Misra 	}
803015a6ef6SSaurabh Misra 
804015a6ef6SSaurabh Misra 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
805015a6ef6SSaurabh Misra 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
806015a6ef6SSaurabh Misra 			break;
807015a6ef6SSaurabh Misra 
808015a6ef6SSaurabh Misra 		drv_usecwait(10);
809015a6ef6SSaurabh Misra 	}
810015a6ef6SSaurabh Misra 
811015a6ef6SSaurabh Misra 	if (t == 0) {
812015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "device reset timeout reg : %x",
813015a6ef6SSaurabh Misra 		    reg);
814015a6ef6SSaurabh Misra 	}
815015a6ef6SSaurabh Misra 
816015a6ef6SSaurabh Misra 	/*
817015a6ef6SSaurabh Misra 	 * Initialize PCIe module. These values came from FreeBSD and
818015a6ef6SSaurabh Misra 	 * we don't know the meaning of it.
819015a6ef6SSaurabh Misra 	 */
820015a6ef6SSaurabh Misra 	OUTL(atgep, 0x12FC, 0x6500);
821015a6ef6SSaurabh Misra 	reg = INL(atgep, 0x1008) | 0x8000;
822015a6ef6SSaurabh Misra 	OUTL(atgep, 0x1008, reg);
823015a6ef6SSaurabh Misra 
824015a6ef6SSaurabh Misra 	/*
825015a6ef6SSaurabh Misra 	 * Get chip revision.
826015a6ef6SSaurabh Misra 	 */
827015a6ef6SSaurabh Misra 	atgep->atge_chip_rev = INL(atgep, ATGE_MASTER_CFG) >>
828015a6ef6SSaurabh Misra 	    MASTER_CHIP_REV_SHIFT;
829015a6ef6SSaurabh Misra 
830015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s reset successfully rev : %x", atgep->atge_name,
831015a6ef6SSaurabh Misra 	    __func__, atgep->atge_chip_rev));
832015a6ef6SSaurabh Misra }
833015a6ef6SSaurabh Misra 
834015a6ef6SSaurabh Misra /*
835015a6ef6SSaurabh Misra  * DMA allocation for L1 and L1E is bit different since L1E uses RX pages
836015a6ef6SSaurabh Misra  * instead of descriptor based RX model.
837015a6ef6SSaurabh Misra  */
838015a6ef6SSaurabh Misra static int
839015a6ef6SSaurabh Misra atge_alloc_dma(atge_t *atgep)
840015a6ef6SSaurabh Misra {
841*0eb090a7SSaurabh Misra 	int err = DDI_FAILURE;
842015a6ef6SSaurabh Misra 
843015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
844015a6ef6SSaurabh Misra 		err = atge_l1e_alloc_dma(atgep);
845*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
846*0eb090a7SSaurabh Misra 		err = atge_l1_alloc_dma(atgep);
847015a6ef6SSaurabh Misra 	}
848015a6ef6SSaurabh Misra 
849015a6ef6SSaurabh Misra 	return (err);
850015a6ef6SSaurabh Misra }
851015a6ef6SSaurabh Misra 
852015a6ef6SSaurabh Misra static void
853015a6ef6SSaurabh Misra atge_free_dma(atge_t *atgep)
854015a6ef6SSaurabh Misra {
855015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
856015a6ef6SSaurabh Misra 		atge_l1e_free_dma(atgep);
857015a6ef6SSaurabh Misra 	}
858015a6ef6SSaurabh Misra }
859015a6ef6SSaurabh Misra 
860015a6ef6SSaurabh Misra /*
861015a6ef6SSaurabh Misra  * Attach entry point in the driver.
862015a6ef6SSaurabh Misra  */
863015a6ef6SSaurabh Misra static int
864015a6ef6SSaurabh Misra atge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
865015a6ef6SSaurabh Misra {
866015a6ef6SSaurabh Misra 	atge_t	*atgep;
867015a6ef6SSaurabh Misra 	mac_register_t	*macreg;
868015a6ef6SSaurabh Misra 	int	instance;
869015a6ef6SSaurabh Misra 	uint16_t cap_ptr;
870015a6ef6SSaurabh Misra 	uint16_t burst;
871015a6ef6SSaurabh Misra 	int err;
872015a6ef6SSaurabh Misra 	mii_ops_t *mii_ops;
873015a6ef6SSaurabh Misra 
874015a6ef6SSaurabh Misra 	instance =  ddi_get_instance(devinfo);
875015a6ef6SSaurabh Misra 
876015a6ef6SSaurabh Misra 	switch (cmd) {
877015a6ef6SSaurabh Misra 	default:
878015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
879015a6ef6SSaurabh Misra 
880015a6ef6SSaurabh Misra 	case DDI_RESUME:
881015a6ef6SSaurabh Misra 		return (atge_resume(devinfo));
882015a6ef6SSaurabh Misra 
883015a6ef6SSaurabh Misra 	case DDI_ATTACH:
884015a6ef6SSaurabh Misra 		ddi_set_driver_private(devinfo, NULL);
885015a6ef6SSaurabh Misra 		break;
886015a6ef6SSaurabh Misra 	}
887015a6ef6SSaurabh Misra 
888015a6ef6SSaurabh Misra 	atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP);
889015a6ef6SSaurabh Misra 	ddi_set_driver_private(devinfo, atgep);
890015a6ef6SSaurabh Misra 	atgep->atge_dip = devinfo;
891015a6ef6SSaurabh Misra 
892015a6ef6SSaurabh Misra 	/*
893015a6ef6SSaurabh Misra 	 * Setup name and instance number to be used for debugging and
894015a6ef6SSaurabh Misra 	 * error reporting.
895015a6ef6SSaurabh Misra 	 */
896015a6ef6SSaurabh Misra 	(void) snprintf(atgep->atge_name, sizeof (atgep->atge_name), "%s%d",
897015a6ef6SSaurabh Misra 	    "atge", instance);
898015a6ef6SSaurabh Misra 
899015a6ef6SSaurabh Misra 
900015a6ef6SSaurabh Misra 	/*
901015a6ef6SSaurabh Misra 	 * Map PCI config space.
902015a6ef6SSaurabh Misra 	 */
903015a6ef6SSaurabh Misra 	err = pci_config_setup(devinfo, &atgep->atge_conf_handle);
904015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
905015a6ef6SSaurabh Misra 		atge_error(devinfo, "pci_config_setup() failed");
906015a6ef6SSaurabh Misra 		goto fail1;
907015a6ef6SSaurabh Misra 	}
908015a6ef6SSaurabh Misra 
909015a6ef6SSaurabh Misra 	(void) atge_identify_hardware(atgep);
910015a6ef6SSaurabh Misra 
911015a6ef6SSaurabh Misra 	/*
912015a6ef6SSaurabh Misra 	 * Map Device registers.
913015a6ef6SSaurabh Misra 	 */
914015a6ef6SSaurabh Misra 	err = ddi_regs_map_setup(devinfo, ATGE_PCI_REG_NUMBER,
915015a6ef6SSaurabh Misra 	    &atgep->atge_io_regs, 0, 0, &atge_dev_attr, &atgep->atge_io_handle);
916015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
917015a6ef6SSaurabh Misra 		atge_error(devinfo, "ddi_regs_map_setup() failed");
918015a6ef6SSaurabh Misra 		goto fail2;
919015a6ef6SSaurabh Misra 	}
920015a6ef6SSaurabh Misra 
921015a6ef6SSaurabh Misra 	/*
922015a6ef6SSaurabh Misra 	 * Add interrupt and its associated handler.
923015a6ef6SSaurabh Misra 	 */
924015a6ef6SSaurabh Misra 	err = atge_add_intr(atgep);
925*0eb090a7SSaurabh Misra 	if (err != DDI_SUCCESS) {
926015a6ef6SSaurabh Misra 		atge_error(devinfo, "Failed to add interrupt handler");
927015a6ef6SSaurabh Misra 		goto fail3;
928015a6ef6SSaurabh Misra 	}
929015a6ef6SSaurabh Misra 
930015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_intr_lock, NULL, MUTEX_DRIVER,
931015a6ef6SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
932015a6ef6SSaurabh Misra 
933015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_tx_lock, NULL, MUTEX_DRIVER,
934015a6ef6SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
935015a6ef6SSaurabh Misra 
936015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_rx_lock, NULL, MUTEX_DRIVER,
937015a6ef6SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
938015a6ef6SSaurabh Misra 
939015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_mii_lock, NULL, MUTEX_DRIVER, NULL);
940015a6ef6SSaurabh Misra 
941*0eb090a7SSaurabh Misra 	/*
942*0eb090a7SSaurabh Misra 	 * Used to lock down MBOX register on L1 chip since RX consumer,
943*0eb090a7SSaurabh Misra 	 * TX producer and RX return ring consumer are shared.
944*0eb090a7SSaurabh Misra 	 */
945*0eb090a7SSaurabh Misra 	mutex_init(&atgep->atge_mbox_lock, NULL, MUTEX_DRIVER,
946*0eb090a7SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
947*0eb090a7SSaurabh Misra 
948015a6ef6SSaurabh Misra 	atgep->atge_link_state = LINK_STATE_DOWN;
949015a6ef6SSaurabh Misra 	atgep->atge_mtu = ETHERMTU;
950015a6ef6SSaurabh Misra 
951*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
952015a6ef6SSaurabh Misra 		if (atgep->atge_revid > 0xF0) {
953015a6ef6SSaurabh Misra 			/* L2E Rev. B. AR8114 */
954015a6ef6SSaurabh Misra 			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
955015a6ef6SSaurabh Misra 		} else {
956*0eb090a7SSaurabh Misra 			if ((INL(atgep, L1E_PHY_STATUS) &
957*0eb090a7SSaurabh Misra 			    PHY_STATUS_100M) != 0) {
958015a6ef6SSaurabh Misra 				/* L1E AR8121 */
959015a6ef6SSaurabh Misra 				atgep->atge_flags |= ATGE_FLAG_JUMBO;
960015a6ef6SSaurabh Misra 			} else {
961015a6ef6SSaurabh Misra 				/* L2E Rev. A. AR8113 */
962015a6ef6SSaurabh Misra 				atgep->atge_flags |= ATGE_FLAG_FASTETHER;
963015a6ef6SSaurabh Misra 			}
964015a6ef6SSaurabh Misra 		}
965*0eb090a7SSaurabh Misra 	}
966015a6ef6SSaurabh Misra 
967015a6ef6SSaurabh Misra 	/*
968015a6ef6SSaurabh Misra 	 * Get DMA parameters from PCIe device control register.
969015a6ef6SSaurabh Misra 	 */
970015a6ef6SSaurabh Misra 	err = PCI_CAP_LOCATE(atgep->atge_conf_handle, PCI_CAP_ID_PCI_E,
971015a6ef6SSaurabh Misra 	    &cap_ptr);
972015a6ef6SSaurabh Misra 
973015a6ef6SSaurabh Misra 	if (err == DDI_FAILURE) {
974015a6ef6SSaurabh Misra 		atgep->atge_dma_rd_burst = DMA_CFG_RD_BURST_128;
975015a6ef6SSaurabh Misra 		atgep->atge_dma_wr_burst = DMA_CFG_WR_BURST_128;
976015a6ef6SSaurabh Misra 	} else {
977015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_FLAG_PCIE;
978015a6ef6SSaurabh Misra 		burst = pci_config_get16(atgep->atge_conf_handle,
979015a6ef6SSaurabh Misra 		    cap_ptr + 0x08);
980015a6ef6SSaurabh Misra 
981015a6ef6SSaurabh Misra 		/*
982015a6ef6SSaurabh Misra 		 * Max read request size.
983015a6ef6SSaurabh Misra 		 */
984015a6ef6SSaurabh Misra 		atgep->atge_dma_rd_burst = ((burst >> 12) & 0x07) <<
985015a6ef6SSaurabh Misra 		    DMA_CFG_RD_BURST_SHIFT;
986015a6ef6SSaurabh Misra 
987015a6ef6SSaurabh Misra 		/*
988015a6ef6SSaurabh Misra 		 * Max Payload Size.
989015a6ef6SSaurabh Misra 		 */
990015a6ef6SSaurabh Misra 		atgep->atge_dma_wr_burst = ((burst >> 5) & 0x07) <<
991015a6ef6SSaurabh Misra 		    DMA_CFG_WR_BURST_SHIFT;
992015a6ef6SSaurabh Misra 
993015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() MRR : %d, MPS : %d",
994015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__,
995015a6ef6SSaurabh Misra 		    (128 << ((burst >> 12) & 0x07)),
996015a6ef6SSaurabh Misra 		    (128 << ((burst >> 5) & 0x07))));
997015a6ef6SSaurabh Misra 	}
998015a6ef6SSaurabh Misra 
999015a6ef6SSaurabh Misra 	/*
1000015a6ef6SSaurabh Misra 	 * Allocate DMA resources.
1001015a6ef6SSaurabh Misra 	 */
1002015a6ef6SSaurabh Misra 	err = atge_alloc_dma(atgep);
1003*0eb090a7SSaurabh Misra 	if (err != DDI_SUCCESS) {
1004015a6ef6SSaurabh Misra 		atge_error(devinfo, "Failed to allocate DMA resources");
1005015a6ef6SSaurabh Misra 		goto fail4;
1006015a6ef6SSaurabh Misra 	}
1007015a6ef6SSaurabh Misra 
1008015a6ef6SSaurabh Misra 	/*
1009015a6ef6SSaurabh Misra 	 * Get station address.
1010015a6ef6SSaurabh Misra 	 */
1011015a6ef6SSaurabh Misra 	(void) atge_get_macaddr(atgep);
1012015a6ef6SSaurabh Misra 
1013015a6ef6SSaurabh Misra 	/*
1014015a6ef6SSaurabh Misra 	 * Setup MII.
1015015a6ef6SSaurabh Misra 	 */
1016015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1017015a6ef6SSaurabh Misra 		mii_ops = &atge_l1e_mii_ops;
1018*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1019*0eb090a7SSaurabh Misra 		mii_ops = &atge_l1_mii_ops;
1020015a6ef6SSaurabh Misra 	}
1021015a6ef6SSaurabh Misra 
1022015a6ef6SSaurabh Misra 	if ((atgep->atge_mii = mii_alloc(atgep, devinfo,
1023015a6ef6SSaurabh Misra 	    mii_ops)) == NULL) {
1024015a6ef6SSaurabh Misra 		atge_error(devinfo, "mii_alloc() failed");
1025015a6ef6SSaurabh Misra 		goto fail4;
1026015a6ef6SSaurabh Misra 	}
1027015a6ef6SSaurabh Misra 
1028015a6ef6SSaurabh Misra 	/*
1029015a6ef6SSaurabh Misra 	 * Register with MAC layer.
1030015a6ef6SSaurabh Misra 	 */
1031015a6ef6SSaurabh Misra 	if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
1032015a6ef6SSaurabh Misra 		atge_error(devinfo, "mac_alloc() failed due to version");
1033015a6ef6SSaurabh Misra 		goto fail4;
1034015a6ef6SSaurabh Misra 	}
1035015a6ef6SSaurabh Misra 
1036015a6ef6SSaurabh Misra 	macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1037015a6ef6SSaurabh Misra 	macreg->m_driver = atgep;
1038015a6ef6SSaurabh Misra 	macreg->m_dip = devinfo;
1039015a6ef6SSaurabh Misra 	macreg->m_instance = instance;
1040015a6ef6SSaurabh Misra 	macreg->m_src_addr = atgep->atge_ether_addr;
1041015a6ef6SSaurabh Misra 	macreg->m_callbacks = &atge_m_callbacks;
1042015a6ef6SSaurabh Misra 	macreg->m_min_sdu = 0;
1043015a6ef6SSaurabh Misra 	macreg->m_max_sdu = atgep->atge_mtu;
1044015a6ef6SSaurabh Misra 	macreg->m_margin = VLAN_TAGSZ;
1045015a6ef6SSaurabh Misra 
1046015a6ef6SSaurabh Misra 	if ((err = mac_register(macreg, &atgep->atge_mh)) != 0) {
1047015a6ef6SSaurabh Misra 		atge_error(devinfo, "mac_register() failed with :%d", err);
1048015a6ef6SSaurabh Misra 		mac_free(macreg);
1049015a6ef6SSaurabh Misra 		goto fail4;
1050015a6ef6SSaurabh Misra 	}
1051015a6ef6SSaurabh Misra 
1052015a6ef6SSaurabh Misra 	mac_free(macreg);
1053015a6ef6SSaurabh Misra 
1054015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() driver attached successfully",
1055015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__));
1056015a6ef6SSaurabh Misra 
1057015a6ef6SSaurabh Misra 	atge_device_reset(atgep);
1058015a6ef6SSaurabh Misra 
1059015a6ef6SSaurabh Misra 	atgep->atge_chip_state = ATGE_CHIP_INITIALIZED;
1060015a6ef6SSaurabh Misra 
1061015a6ef6SSaurabh Misra 	/*
1062015a6ef6SSaurabh Misra 	 * At last - enable interrupts.
1063015a6ef6SSaurabh Misra 	 */
1064015a6ef6SSaurabh Misra 	err = atge_enable_intrs(atgep);
1065*0eb090a7SSaurabh Misra 	if (err == DDI_FAILURE) {
1066015a6ef6SSaurabh Misra 		goto fail5;
1067015a6ef6SSaurabh Misra 	}
1068015a6ef6SSaurabh Misra 
1069015a6ef6SSaurabh Misra 	/*
1070015a6ef6SSaurabh Misra 	 * Reset the PHY before starting.
1071015a6ef6SSaurabh Misra 	 */
1072015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1073015a6ef6SSaurabh Misra 		atge_l1e_mii_reset(atgep);
1074*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1075*0eb090a7SSaurabh Misra 		atge_l1_mii_reset(atgep);
1076015a6ef6SSaurabh Misra 	}
1077015a6ef6SSaurabh Misra 
1078015a6ef6SSaurabh Misra 	/*
1079015a6ef6SSaurabh Misra 	 * Let the PHY run.
1080015a6ef6SSaurabh Misra 	 */
1081015a6ef6SSaurabh Misra 	mii_start(atgep->atge_mii);
1082015a6ef6SSaurabh Misra 
1083015a6ef6SSaurabh Misra 	return (DDI_SUCCESS);
1084015a6ef6SSaurabh Misra 
1085015a6ef6SSaurabh Misra fail5:
1086015a6ef6SSaurabh Misra 	(void) mac_unregister(atgep->atge_mh);
1087015a6ef6SSaurabh Misra 	atge_device_stop(atgep);
1088015a6ef6SSaurabh Misra 	mii_stop(atgep->atge_mii);
1089015a6ef6SSaurabh Misra 	mii_free(atgep->atge_mii);
1090015a6ef6SSaurabh Misra fail4:
1091015a6ef6SSaurabh Misra 	atge_free_dma(atgep);
1092015a6ef6SSaurabh Misra 	mutex_destroy(&atgep->atge_intr_lock);
1093015a6ef6SSaurabh Misra 	mutex_destroy(&atgep->atge_tx_lock);
1094015a6ef6SSaurabh Misra 	mutex_destroy(&atgep->atge_rx_lock);
1095015a6ef6SSaurabh Misra 	atge_remove_intr(atgep);
1096015a6ef6SSaurabh Misra fail3:
1097015a6ef6SSaurabh Misra 	ddi_regs_map_free(&atgep->atge_io_handle);
1098015a6ef6SSaurabh Misra fail2:
1099015a6ef6SSaurabh Misra 	pci_config_teardown(&atgep->atge_conf_handle);
1100015a6ef6SSaurabh Misra fail1:
1101015a6ef6SSaurabh Misra 	if (atgep)
1102015a6ef6SSaurabh Misra 		kmem_free(atgep, sizeof (atge_t));
1103015a6ef6SSaurabh Misra 
1104015a6ef6SSaurabh Misra 	return (DDI_FAILURE);
1105015a6ef6SSaurabh Misra }
1106015a6ef6SSaurabh Misra 
1107015a6ef6SSaurabh Misra static int
1108015a6ef6SSaurabh Misra atge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1109015a6ef6SSaurabh Misra {
1110015a6ef6SSaurabh Misra 	atge_t	*atgep;
1111015a6ef6SSaurabh Misra 
1112015a6ef6SSaurabh Misra 	atgep = ddi_get_driver_private(dip);
1113015a6ef6SSaurabh Misra 	if (atgep == NULL) {
1114015a6ef6SSaurabh Misra 		atge_error(dip, "No soft state in detach");
1115015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1116015a6ef6SSaurabh Misra 	}
1117015a6ef6SSaurabh Misra 
1118015a6ef6SSaurabh Misra 	switch (cmd) {
1119015a6ef6SSaurabh Misra 	case DDI_DETACH:
1120015a6ef6SSaurabh Misra 		mii_stop(atgep->atge_mii);
1121015a6ef6SSaurabh Misra 
1122015a6ef6SSaurabh Misra 		/*
1123015a6ef6SSaurabh Misra 		 * First unregister with MAC layer before stopping DMA
1124015a6ef6SSaurabh Misra 		 */
1125015a6ef6SSaurabh Misra 		if (mac_unregister(atgep->atge_mh) != DDI_SUCCESS)
1126015a6ef6SSaurabh Misra 			return (DDI_FAILURE);
1127015a6ef6SSaurabh Misra 
1128015a6ef6SSaurabh Misra 		atgep->atge_mh = NULL;
1129015a6ef6SSaurabh Misra 
1130015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_intr_lock);
1131015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_tx_lock);
1132015a6ef6SSaurabh Misra 		atge_device_stop(atgep);
1133015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1134015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
1135015a6ef6SSaurabh Misra 
1136015a6ef6SSaurabh Misra 		mii_free(atgep->atge_mii);
1137015a6ef6SSaurabh Misra 		atge_free_dma(atgep);
1138015a6ef6SSaurabh Misra 
1139015a6ef6SSaurabh Misra 		ddi_regs_map_free(&atgep->atge_io_handle);
1140015a6ef6SSaurabh Misra 		atge_remove_intr(atgep);
1141015a6ef6SSaurabh Misra 		pci_config_teardown(&atgep->atge_conf_handle);
1142015a6ef6SSaurabh Misra 
1143015a6ef6SSaurabh Misra 		mutex_destroy(&atgep->atge_intr_lock);
1144015a6ef6SSaurabh Misra 		mutex_destroy(&atgep->atge_tx_lock);
1145015a6ef6SSaurabh Misra 		mutex_destroy(&atgep->atge_rx_lock);
1146015a6ef6SSaurabh Misra 		kmem_free(atgep, sizeof (atge_t));
1147015a6ef6SSaurabh Misra 		ddi_set_driver_private(dip, NULL);
1148015a6ef6SSaurabh Misra 
1149015a6ef6SSaurabh Misra 		return (DDI_SUCCESS);
1150015a6ef6SSaurabh Misra 
1151015a6ef6SSaurabh Misra 	case DDI_SUSPEND:
1152015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() is being suspended",
1153015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
1154015a6ef6SSaurabh Misra 
1155015a6ef6SSaurabh Misra 		/*
1156015a6ef6SSaurabh Misra 		 * Suspend monitoring MII.
1157015a6ef6SSaurabh Misra 		 */
1158015a6ef6SSaurabh Misra 		mii_suspend(atgep->atge_mii);
1159015a6ef6SSaurabh Misra 
1160015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_intr_lock);
1161015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_tx_lock);
1162015a6ef6SSaurabh Misra 		atgep->atge_chip_state |= ATGE_CHIP_SUSPENDED;
1163015a6ef6SSaurabh Misra 		atge_device_stop(atgep);
1164015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1165015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
1166015a6ef6SSaurabh Misra 
1167015a6ef6SSaurabh Misra 		return (DDI_SUCCESS);
1168015a6ef6SSaurabh Misra 
1169015a6ef6SSaurabh Misra 	default:
1170015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1171015a6ef6SSaurabh Misra 	}
1172015a6ef6SSaurabh Misra }
1173015a6ef6SSaurabh Misra 
1174015a6ef6SSaurabh Misra int
1175015a6ef6SSaurabh Misra atge_alloc_buffers(atge_ring_t *r, size_t rcnt, size_t buflen, int f)
1176015a6ef6SSaurabh Misra {
1177015a6ef6SSaurabh Misra 	atge_dma_t *dma;
1178015a6ef6SSaurabh Misra 	atge_dma_t **tbl;
1179*0eb090a7SSaurabh Misra 	int err = DDI_SUCCESS;
1180015a6ef6SSaurabh Misra 	int i;
1181015a6ef6SSaurabh Misra 
1182015a6ef6SSaurabh Misra 	tbl = kmem_zalloc(rcnt * sizeof (atge_dma_t *), KM_SLEEP);
1183015a6ef6SSaurabh Misra 	r->r_buf_tbl = tbl;
1184015a6ef6SSaurabh Misra 
1185015a6ef6SSaurabh Misra 	for (i = 0; i < rcnt; i++) {
1186015a6ef6SSaurabh Misra 		dma = atge_buf_alloc(r->r_atge, buflen, f);
1187015a6ef6SSaurabh Misra 		if (dma == NULL) {
1188*0eb090a7SSaurabh Misra 			err = DDI_FAILURE;
1189015a6ef6SSaurabh Misra 			break;
1190015a6ef6SSaurabh Misra 		}
1191015a6ef6SSaurabh Misra 
1192015a6ef6SSaurabh Misra 		tbl[i] = dma;
1193015a6ef6SSaurabh Misra 	}
1194015a6ef6SSaurabh Misra 
1195015a6ef6SSaurabh Misra 	return (err);
1196015a6ef6SSaurabh Misra }
1197015a6ef6SSaurabh Misra 
1198015a6ef6SSaurabh Misra void
1199015a6ef6SSaurabh Misra atge_free_buffers(atge_ring_t *r, size_t rcnt)
1200015a6ef6SSaurabh Misra {
1201015a6ef6SSaurabh Misra 	atge_dma_t **tbl;
1202015a6ef6SSaurabh Misra 	int i;
1203015a6ef6SSaurabh Misra 
1204015a6ef6SSaurabh Misra 	if (r == NULL || r->r_buf_tbl == NULL)
1205015a6ef6SSaurabh Misra 		return;
1206015a6ef6SSaurabh Misra 
1207015a6ef6SSaurabh Misra 	tbl = r->r_buf_tbl;
1208015a6ef6SSaurabh Misra 	for (i = 0; i < rcnt; i++)  {
1209015a6ef6SSaurabh Misra 		if (tbl[i] != NULL) {
1210015a6ef6SSaurabh Misra 			atge_buf_free(tbl[i]);
1211015a6ef6SSaurabh Misra 		}
1212015a6ef6SSaurabh Misra 	}
1213015a6ef6SSaurabh Misra 
1214015a6ef6SSaurabh Misra 	kmem_free(tbl, rcnt * sizeof (atge_dma_t *));
1215015a6ef6SSaurabh Misra }
1216015a6ef6SSaurabh Misra 
1217015a6ef6SSaurabh Misra atge_dma_t *
1218015a6ef6SSaurabh Misra atge_alloc_a_dma_blk(atge_t *atgep, ddi_dma_attr_t *attr, int size, int d)
1219015a6ef6SSaurabh Misra {
1220015a6ef6SSaurabh Misra 	int err;
1221015a6ef6SSaurabh Misra 	atge_dma_t *dma;
1222015a6ef6SSaurabh Misra 
1223015a6ef6SSaurabh Misra 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
1224015a6ef6SSaurabh Misra 
1225015a6ef6SSaurabh Misra 	err = ddi_dma_alloc_handle(atgep->atge_dip, attr,
1226015a6ef6SSaurabh Misra 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
1227015a6ef6SSaurabh Misra 
1228015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1229015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1230015a6ef6SSaurabh Misra 		    " in ddi_dma_alloc_handle() : %d", __func__, err);
1231015a6ef6SSaurabh Misra 		goto fail;
1232015a6ef6SSaurabh Misra 	}
1233015a6ef6SSaurabh Misra 
1234015a6ef6SSaurabh Misra 	err = ddi_dma_mem_alloc(dma->hdl,
1235015a6ef6SSaurabh Misra 	    size, &atge_buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
1236015a6ef6SSaurabh Misra 	    &dma->addr, &dma->len, &dma->acchdl);
1237015a6ef6SSaurabh Misra 
1238015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1239015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1240015a6ef6SSaurabh Misra 		    " in ddi_dma_mem_alloc() : %d", __func__, err);
1241015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1242015a6ef6SSaurabh Misra 		goto fail;
1243015a6ef6SSaurabh Misra 	}
1244015a6ef6SSaurabh Misra 
1245015a6ef6SSaurabh Misra 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr,
1246015a6ef6SSaurabh Misra 	    dma->len, d | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
1247015a6ef6SSaurabh Misra 	    NULL, &dma->cookie, &dma->count);
1248015a6ef6SSaurabh Misra 
1249015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1250015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1251015a6ef6SSaurabh Misra 		    " in ddi_dma_addr_bind_handle() : %d", __func__, err);
1252015a6ef6SSaurabh Misra 		ddi_dma_mem_free(&dma->acchdl);
1253015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1254015a6ef6SSaurabh Misra 		goto fail;
1255015a6ef6SSaurabh Misra 	}
1256015a6ef6SSaurabh Misra 
1257015a6ef6SSaurabh Misra 	return (dma);
1258015a6ef6SSaurabh Misra fail:
1259015a6ef6SSaurabh Misra 	kmem_free(dma, sizeof (atge_dma_t));
1260015a6ef6SSaurabh Misra 	return (NULL);
1261015a6ef6SSaurabh Misra }
1262015a6ef6SSaurabh Misra 
1263015a6ef6SSaurabh Misra void
1264015a6ef6SSaurabh Misra atge_free_a_dma_blk(atge_dma_t *dma)
1265015a6ef6SSaurabh Misra {
1266015a6ef6SSaurabh Misra 	if (dma != NULL) {
1267015a6ef6SSaurabh Misra 		(void) ddi_dma_unbind_handle(dma->hdl);
1268015a6ef6SSaurabh Misra 		ddi_dma_mem_free(&dma->acchdl);
1269015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1270015a6ef6SSaurabh Misra 		kmem_free(dma, sizeof (atge_dma_t));
1271015a6ef6SSaurabh Misra 	}
1272015a6ef6SSaurabh Misra }
1273015a6ef6SSaurabh Misra 
1274015a6ef6SSaurabh Misra atge_dma_t *
1275015a6ef6SSaurabh Misra atge_buf_alloc(atge_t *atgep, size_t len, int f)
1276015a6ef6SSaurabh Misra {
1277015a6ef6SSaurabh Misra 	atge_dma_t *dma = NULL;
1278015a6ef6SSaurabh Misra 	int err;
1279015a6ef6SSaurabh Misra 
1280015a6ef6SSaurabh Misra 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
1281015a6ef6SSaurabh Misra 
1282015a6ef6SSaurabh Misra 	err = ddi_dma_alloc_handle(atgep->atge_dip, &atge_dma_attr_buf,
1283015a6ef6SSaurabh Misra 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
1284015a6ef6SSaurabh Misra 
1285015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1286015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1287015a6ef6SSaurabh Misra 		    " in %s() : %d", __func__, err);
1288015a6ef6SSaurabh Misra 		goto fail;
1289015a6ef6SSaurabh Misra 	}
1290015a6ef6SSaurabh Misra 
1291015a6ef6SSaurabh Misra 	err = ddi_dma_mem_alloc(dma->hdl, len, &atge_buf_attr,
1292015a6ef6SSaurabh Misra 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dma->addr,
1293015a6ef6SSaurabh Misra 	    &dma->len, &dma->acchdl);
1294015a6ef6SSaurabh Misra 
1295015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1296015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1297015a6ef6SSaurabh Misra 		    " in %s() : %d", __func__, err);
1298015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1299015a6ef6SSaurabh Misra 		goto fail;
1300015a6ef6SSaurabh Misra 	}
1301015a6ef6SSaurabh Misra 
1302015a6ef6SSaurabh Misra 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, dma->len,
1303015a6ef6SSaurabh Misra 	    (f | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, &dma->cookie,
1304015a6ef6SSaurabh Misra 	    &dma->count);
1305015a6ef6SSaurabh Misra 
1306015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1307015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1308015a6ef6SSaurabh Misra 		    " in %s() : %d", __func__, err);
1309015a6ef6SSaurabh Misra 		ddi_dma_mem_free(&dma->acchdl);
1310015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1311015a6ef6SSaurabh Misra 		goto fail;
1312015a6ef6SSaurabh Misra 	}
1313015a6ef6SSaurabh Misra 
1314015a6ef6SSaurabh Misra 	/*
1315015a6ef6SSaurabh Misra 	 * Number of return'ed cookie should be one.
1316015a6ef6SSaurabh Misra 	 */
1317015a6ef6SSaurabh Misra 	ASSERT(dma->count == 1);
1318015a6ef6SSaurabh Misra 
1319015a6ef6SSaurabh Misra 	return (dma);
1320015a6ef6SSaurabh Misra fail:
1321015a6ef6SSaurabh Misra 	kmem_free(dma, sizeof (atge_dma_t));
1322015a6ef6SSaurabh Misra 	return (NULL);
1323015a6ef6SSaurabh Misra }
1324015a6ef6SSaurabh Misra 
1325015a6ef6SSaurabh Misra void
1326015a6ef6SSaurabh Misra atge_buf_free(atge_dma_t *dma)
1327015a6ef6SSaurabh Misra {
1328015a6ef6SSaurabh Misra 	ASSERT(dma != NULL);
1329015a6ef6SSaurabh Misra 
1330015a6ef6SSaurabh Misra 	(void) ddi_dma_unbind_handle(dma->hdl);
1331015a6ef6SSaurabh Misra 	ddi_dma_mem_free(&dma->acchdl);
1332015a6ef6SSaurabh Misra 	ddi_dma_free_handle(&dma->hdl);
1333015a6ef6SSaurabh Misra 	kmem_free(dma, sizeof (atge_dma_t));
1334015a6ef6SSaurabh Misra }
1335015a6ef6SSaurabh Misra 
1336015a6ef6SSaurabh Misra static int
1337015a6ef6SSaurabh Misra atge_resume(dev_info_t *dip)
1338015a6ef6SSaurabh Misra {
1339015a6ef6SSaurabh Misra 	atge_t	*atgep;
1340015a6ef6SSaurabh Misra 
1341015a6ef6SSaurabh Misra 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
1342015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1343015a6ef6SSaurabh Misra 	}
1344015a6ef6SSaurabh Misra 
1345015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1346015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1347015a6ef6SSaurabh Misra 
1348015a6ef6SSaurabh Misra 	atgep->atge_chip_state &= ~ATGE_CHIP_SUSPENDED;
1349015a6ef6SSaurabh Misra 
1350015a6ef6SSaurabh Misra 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
1351015a6ef6SSaurabh Misra 		atge_device_restart(atgep);
1352015a6ef6SSaurabh Misra 	} else {
1353015a6ef6SSaurabh Misra 		atge_device_reset(atgep);
1354015a6ef6SSaurabh Misra 	}
1355015a6ef6SSaurabh Misra 
1356015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1357015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1358015a6ef6SSaurabh Misra 
1359015a6ef6SSaurabh Misra 	/*
1360015a6ef6SSaurabh Misra 	 * Reset the PHY before resuming MII.
1361015a6ef6SSaurabh Misra 	 */
1362015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1363015a6ef6SSaurabh Misra 		atge_l1e_mii_reset(atgep);
1364015a6ef6SSaurabh Misra 	}
1365015a6ef6SSaurabh Misra 
1366015a6ef6SSaurabh Misra 	mii_resume(atgep->atge_mii);
1367015a6ef6SSaurabh Misra 
1368015a6ef6SSaurabh Misra 	/* kick-off downstream */
1369015a6ef6SSaurabh Misra 	mac_tx_update(atgep->atge_mh);
1370015a6ef6SSaurabh Misra 
1371015a6ef6SSaurabh Misra 	return (DDI_SUCCESS);
1372015a6ef6SSaurabh Misra }
1373015a6ef6SSaurabh Misra 
1374015a6ef6SSaurabh Misra static int
1375015a6ef6SSaurabh Misra atge_quiesce(dev_info_t *dip)
1376015a6ef6SSaurabh Misra {
1377015a6ef6SSaurabh Misra 	atge_t	*atgep;
1378015a6ef6SSaurabh Misra 
1379015a6ef6SSaurabh Misra 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
1380015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1381015a6ef6SSaurabh Misra 	}
1382015a6ef6SSaurabh Misra 
1383015a6ef6SSaurabh Misra 	atge_device_stop(atgep);
1384015a6ef6SSaurabh Misra 
1385015a6ef6SSaurabh Misra 	return (DDI_SUCCESS);
1386015a6ef6SSaurabh Misra }
1387015a6ef6SSaurabh Misra 
1388015a6ef6SSaurabh Misra void
1389015a6ef6SSaurabh Misra atge_add_multicst(atge_t *atgep, uint8_t *macaddr)
1390015a6ef6SSaurabh Misra {
1391015a6ef6SSaurabh Misra 	uint32_t crc;
1392015a6ef6SSaurabh Misra 	int bit;
1393015a6ef6SSaurabh Misra 
1394015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
1395015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
1396015a6ef6SSaurabh Misra 
1397015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
1398015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
1399015a6ef6SSaurabh Misra 	    macaddr[3], macaddr[4], macaddr[5]));
1400015a6ef6SSaurabh Misra 
1401015a6ef6SSaurabh Misra 	crc = atge_ether_crc(macaddr, ETHERADDRL);
1402015a6ef6SSaurabh Misra 	bit = (crc >> 26);
1403015a6ef6SSaurabh Misra 	atgep->atge_mchash_ref_cnt[bit]++;
1404015a6ef6SSaurabh Misra 	atgep->atge_mchash |= (1ULL << (crc >> 26));
1405015a6ef6SSaurabh Misra 
1406015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
1407015a6ef6SSaurabh Misra 	    " atge_mchash_ref_cnt[bit] :%d",
1408015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
1409015a6ef6SSaurabh Misra 	    atgep->atge_mchash_ref_cnt[bit]));
1410015a6ef6SSaurabh Misra }
1411015a6ef6SSaurabh Misra 
1412015a6ef6SSaurabh Misra void
1413015a6ef6SSaurabh Misra atge_remove_multicst(atge_t *atgep, uint8_t *macaddr)
1414015a6ef6SSaurabh Misra {
1415015a6ef6SSaurabh Misra 	uint32_t crc;
1416015a6ef6SSaurabh Misra 	int bit;
1417015a6ef6SSaurabh Misra 
1418015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
1419015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
1420015a6ef6SSaurabh Misra 
1421015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
1422015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
1423015a6ef6SSaurabh Misra 	    macaddr[3], macaddr[4], macaddr[5]));
1424015a6ef6SSaurabh Misra 
1425015a6ef6SSaurabh Misra 	crc = atge_ether_crc(macaddr, ETHERADDRL);
1426015a6ef6SSaurabh Misra 	bit = (crc >> 26);
1427015a6ef6SSaurabh Misra 	atgep->atge_mchash_ref_cnt[bit]--;
1428015a6ef6SSaurabh Misra 	if (atgep->atge_mchash_ref_cnt[bit] == 0)
1429015a6ef6SSaurabh Misra 		atgep->atge_mchash &= ~(1ULL << (crc >> 26));
1430015a6ef6SSaurabh Misra 
1431015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
1432015a6ef6SSaurabh Misra 	    " atge_mchash_ref_cnt[bit] :%d",
1433015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
1434015a6ef6SSaurabh Misra 	    atgep->atge_mchash_ref_cnt[bit]));
1435015a6ef6SSaurabh Misra }
1436015a6ef6SSaurabh Misra 
1437015a6ef6SSaurabh Misra int
1438015a6ef6SSaurabh Misra atge_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
1439015a6ef6SSaurabh Misra {
1440015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1441015a6ef6SSaurabh Misra 
1442015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1443015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1444015a6ef6SSaurabh Misra 
1445015a6ef6SSaurabh Misra 	if (add) {
1446015a6ef6SSaurabh Misra 		atge_add_multicst(atgep, (uint8_t *)macaddr);
1447015a6ef6SSaurabh Misra 	} else {
1448015a6ef6SSaurabh Misra 		atge_remove_multicst(atgep, (uint8_t *)macaddr);
1449015a6ef6SSaurabh Misra 	}
1450015a6ef6SSaurabh Misra 
1451015a6ef6SSaurabh Misra 	atge_rxfilter(atgep);
1452015a6ef6SSaurabh Misra 
1453015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1454015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1455015a6ef6SSaurabh Misra 
1456015a6ef6SSaurabh Misra 	return (0);
1457015a6ef6SSaurabh Misra }
1458015a6ef6SSaurabh Misra 
1459015a6ef6SSaurabh Misra int
1460015a6ef6SSaurabh Misra atge_m_promisc(void *arg, boolean_t on)
1461015a6ef6SSaurabh Misra {
1462015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1463015a6ef6SSaurabh Misra 
1464015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1465015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1466015a6ef6SSaurabh Misra 
1467015a6ef6SSaurabh Misra 	if (on) {
1468015a6ef6SSaurabh Misra 		atgep->atge_filter_flags |= ATGE_PROMISC;
1469015a6ef6SSaurabh Misra 	} else {
1470015a6ef6SSaurabh Misra 		atgep->atge_filter_flags &= ~ATGE_PROMISC;
1471015a6ef6SSaurabh Misra 	}
1472015a6ef6SSaurabh Misra 
1473015a6ef6SSaurabh Misra 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
1474015a6ef6SSaurabh Misra 		atge_rxfilter(atgep);
1475015a6ef6SSaurabh Misra 	}
1476015a6ef6SSaurabh Misra 
1477015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1478015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1479015a6ef6SSaurabh Misra 
1480015a6ef6SSaurabh Misra 	return (0);
1481015a6ef6SSaurabh Misra }
1482015a6ef6SSaurabh Misra 
1483015a6ef6SSaurabh Misra int
1484015a6ef6SSaurabh Misra atge_m_unicst(void *arg, const uint8_t *macaddr)
1485015a6ef6SSaurabh Misra {
1486015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1487015a6ef6SSaurabh Misra 
1488015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1489015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1490015a6ef6SSaurabh Misra 	bcopy(macaddr, atgep->atge_ether_addr, ETHERADDRL);
1491015a6ef6SSaurabh Misra 	atge_program_ether(atgep);
1492015a6ef6SSaurabh Misra 	atge_rxfilter(atgep);
1493015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1494015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1495015a6ef6SSaurabh Misra 
1496015a6ef6SSaurabh Misra 	return (0);
1497015a6ef6SSaurabh Misra }
1498015a6ef6SSaurabh Misra 
1499015a6ef6SSaurabh Misra mblk_t *
1500015a6ef6SSaurabh Misra atge_m_tx(void *arg, mblk_t *mp)
1501015a6ef6SSaurabh Misra {
1502015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1503015a6ef6SSaurabh Misra 	mblk_t	*nmp;
1504015a6ef6SSaurabh Misra 
1505015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1506015a6ef6SSaurabh Misra 
1507015a6ef6SSaurabh Misra 	/*
1508015a6ef6SSaurabh Misra 	 * This NIC does not like us to send pkt when link is down.
1509015a6ef6SSaurabh Misra 	 */
1510015a6ef6SSaurabh Misra 	if (!(atgep->atge_link_state & LINK_STATE_UP)) {
1511015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 1;
1512*0eb090a7SSaurabh Misra 
1513015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1514015a6ef6SSaurabh Misra 		return (mp);
1515015a6ef6SSaurabh Misra 	}
1516015a6ef6SSaurabh Misra 
1517015a6ef6SSaurabh Misra 	/*
1518015a6ef6SSaurabh Misra 	 * Don't send a pkt if chip isn't running or in suspended state.
1519015a6ef6SSaurabh Misra 	 */
1520015a6ef6SSaurabh Misra 	if ((atgep->atge_chip_state & ATGE_CHIP_RUNNING) == 0 ||
1521015a6ef6SSaurabh Misra 	    atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
1522015a6ef6SSaurabh Misra 		atgep->atge_carrier_errors++;
1523015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 1;
1524*0eb090a7SSaurabh Misra 
1525015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1526015a6ef6SSaurabh Misra 		return (mp);
1527015a6ef6SSaurabh Misra 	}
1528015a6ef6SSaurabh Misra 
1529015a6ef6SSaurabh Misra 	while (mp != NULL) {
1530015a6ef6SSaurabh Misra 		nmp = mp->b_next;
1531015a6ef6SSaurabh Misra 		mp->b_next = NULL;
1532015a6ef6SSaurabh Misra 
1533*0eb090a7SSaurabh Misra 		if (atge_send_a_packet(atgep, mp) == DDI_FAILURE) {
1534015a6ef6SSaurabh Misra 			mp->b_next = nmp;
1535015a6ef6SSaurabh Misra 			break;
1536015a6ef6SSaurabh Misra 		}
1537015a6ef6SSaurabh Misra 
1538015a6ef6SSaurabh Misra 		mp = nmp;
1539015a6ef6SSaurabh Misra 	}
1540015a6ef6SSaurabh Misra 
1541015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1542015a6ef6SSaurabh Misra 	return (mp);
1543015a6ef6SSaurabh Misra }
1544015a6ef6SSaurabh Misra 
1545015a6ef6SSaurabh Misra int
1546015a6ef6SSaurabh Misra atge_m_start(void *arg)
1547015a6ef6SSaurabh Misra {
1548015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1549015a6ef6SSaurabh Misra 	int started = 0;
1550015a6ef6SSaurabh Misra 
1551015a6ef6SSaurabh Misra 	ASSERT(atgep != NULL);
1552015a6ef6SSaurabh Misra 
1553015a6ef6SSaurabh Misra 
1554015a6ef6SSaurabh Misra 	mii_stop(atgep->atge_mii);
1555015a6ef6SSaurabh Misra 
1556015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1557015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1558015a6ef6SSaurabh Misra 
1559015a6ef6SSaurabh Misra 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
1560015a6ef6SSaurabh Misra 		atge_device_restart(atgep);
1561015a6ef6SSaurabh Misra 		started = 1;
1562015a6ef6SSaurabh Misra 	}
1563015a6ef6SSaurabh Misra 
1564015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1565015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1566015a6ef6SSaurabh Misra 
1567015a6ef6SSaurabh Misra 	mii_start(atgep->atge_mii);
1568015a6ef6SSaurabh Misra 
1569015a6ef6SSaurabh Misra 	/* kick-off downstream */
1570015a6ef6SSaurabh Misra 	if (started)
1571015a6ef6SSaurabh Misra 		mac_tx_update(atgep->atge_mh);
1572015a6ef6SSaurabh Misra 
1573015a6ef6SSaurabh Misra 	return (0);
1574015a6ef6SSaurabh Misra }
1575015a6ef6SSaurabh Misra 
1576015a6ef6SSaurabh Misra void
1577015a6ef6SSaurabh Misra atge_m_stop(void *arg)
1578015a6ef6SSaurabh Misra {
1579015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1580015a6ef6SSaurabh Misra 
1581015a6ef6SSaurabh Misra 	mii_stop(atgep->atge_mii);
1582015a6ef6SSaurabh Misra 
1583015a6ef6SSaurabh Misra 	/*
1584015a6ef6SSaurabh Misra 	 * Cancel any pending I/O.
1585015a6ef6SSaurabh Misra 	 */
1586015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1587015a6ef6SSaurabh Misra 	atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
1588015a6ef6SSaurabh Misra 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED))
1589015a6ef6SSaurabh Misra 		atge_device_stop(atgep);
1590015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1591015a6ef6SSaurabh Misra }
1592015a6ef6SSaurabh Misra 
1593015a6ef6SSaurabh Misra int
1594015a6ef6SSaurabh Misra atge_m_stat(void *arg, uint_t stat, uint64_t *val)
1595015a6ef6SSaurabh Misra {
1596015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1597015a6ef6SSaurabh Misra 
1598015a6ef6SSaurabh Misra 	if (mii_m_getstat(atgep->atge_mii, stat, val) == 0) {
1599015a6ef6SSaurabh Misra 		return (0);
1600015a6ef6SSaurabh Misra 	}
1601015a6ef6SSaurabh Misra 
1602015a6ef6SSaurabh Misra 	switch (stat) {
1603015a6ef6SSaurabh Misra 	case MAC_STAT_MULTIRCV:
1604015a6ef6SSaurabh Misra 		*val = atgep->atge_multircv;
1605015a6ef6SSaurabh Misra 		break;
1606015a6ef6SSaurabh Misra 
1607015a6ef6SSaurabh Misra 	case MAC_STAT_BRDCSTRCV:
1608015a6ef6SSaurabh Misra 		*val = atgep->atge_brdcstrcv;
1609015a6ef6SSaurabh Misra 		break;
1610015a6ef6SSaurabh Misra 
1611015a6ef6SSaurabh Misra 	case MAC_STAT_MULTIXMT:
1612015a6ef6SSaurabh Misra 		*val = atgep->atge_multixmt;
1613015a6ef6SSaurabh Misra 		break;
1614015a6ef6SSaurabh Misra 
1615015a6ef6SSaurabh Misra 	case MAC_STAT_BRDCSTXMT:
1616015a6ef6SSaurabh Misra 		*val = atgep->atge_brdcstxmt;
1617015a6ef6SSaurabh Misra 		break;
1618015a6ef6SSaurabh Misra 
1619015a6ef6SSaurabh Misra 	case MAC_STAT_IPACKETS:
1620015a6ef6SSaurabh Misra 		*val = atgep->atge_ipackets;
1621015a6ef6SSaurabh Misra 		break;
1622015a6ef6SSaurabh Misra 
1623015a6ef6SSaurabh Misra 	case MAC_STAT_RBYTES:
1624015a6ef6SSaurabh Misra 		*val = atgep->atge_rbytes;
1625015a6ef6SSaurabh Misra 		break;
1626015a6ef6SSaurabh Misra 
1627015a6ef6SSaurabh Misra 	case MAC_STAT_OPACKETS:
1628015a6ef6SSaurabh Misra 		*val = atgep->atge_opackets;
1629015a6ef6SSaurabh Misra 		break;
1630015a6ef6SSaurabh Misra 
1631015a6ef6SSaurabh Misra 	case MAC_STAT_OBYTES:
1632015a6ef6SSaurabh Misra 		*val = atgep->atge_obytes;
1633015a6ef6SSaurabh Misra 		break;
1634015a6ef6SSaurabh Misra 
1635015a6ef6SSaurabh Misra 	case MAC_STAT_NORCVBUF:
1636015a6ef6SSaurabh Misra 		*val = atgep->atge_norcvbuf;
1637015a6ef6SSaurabh Misra 		break;
1638015a6ef6SSaurabh Misra 
1639015a6ef6SSaurabh Misra 	case MAC_STAT_NOXMTBUF:
1640015a6ef6SSaurabh Misra 		*val = 0;
1641015a6ef6SSaurabh Misra 		break;
1642015a6ef6SSaurabh Misra 
1643015a6ef6SSaurabh Misra 	case MAC_STAT_COLLISIONS:
1644015a6ef6SSaurabh Misra 		*val = atgep->atge_collisions;
1645015a6ef6SSaurabh Misra 		break;
1646015a6ef6SSaurabh Misra 
1647015a6ef6SSaurabh Misra 	case MAC_STAT_IERRORS:
1648015a6ef6SSaurabh Misra 		*val = atgep->atge_errrcv;
1649015a6ef6SSaurabh Misra 		break;
1650015a6ef6SSaurabh Misra 
1651015a6ef6SSaurabh Misra 	case MAC_STAT_OERRORS:
1652015a6ef6SSaurabh Misra 		*val = atgep->atge_errxmt;
1653015a6ef6SSaurabh Misra 		break;
1654015a6ef6SSaurabh Misra 
1655015a6ef6SSaurabh Misra 	case ETHER_STAT_ALIGN_ERRORS:
1656015a6ef6SSaurabh Misra 		*val = atgep->atge_align_errors;
1657015a6ef6SSaurabh Misra 		break;
1658015a6ef6SSaurabh Misra 
1659015a6ef6SSaurabh Misra 	case ETHER_STAT_FCS_ERRORS:
1660015a6ef6SSaurabh Misra 		*val = atgep->atge_fcs_errors;
1661015a6ef6SSaurabh Misra 		break;
1662015a6ef6SSaurabh Misra 
1663015a6ef6SSaurabh Misra 	case ETHER_STAT_SQE_ERRORS:
1664015a6ef6SSaurabh Misra 		*val = atgep->atge_sqe_errors;
1665015a6ef6SSaurabh Misra 		break;
1666015a6ef6SSaurabh Misra 
1667015a6ef6SSaurabh Misra 	case ETHER_STAT_DEFER_XMTS:
1668015a6ef6SSaurabh Misra 		*val = atgep->atge_defer_xmts;
1669015a6ef6SSaurabh Misra 		break;
1670015a6ef6SSaurabh Misra 
1671015a6ef6SSaurabh Misra 	case ETHER_STAT_FIRST_COLLISIONS:
1672015a6ef6SSaurabh Misra 		*val = atgep->atge_first_collisions;
1673015a6ef6SSaurabh Misra 		break;
1674015a6ef6SSaurabh Misra 
1675015a6ef6SSaurabh Misra 	case ETHER_STAT_MULTI_COLLISIONS:
1676015a6ef6SSaurabh Misra 		*val = atgep->atge_multi_collisions;
1677015a6ef6SSaurabh Misra 		break;
1678015a6ef6SSaurabh Misra 
1679015a6ef6SSaurabh Misra 	case ETHER_STAT_TX_LATE_COLLISIONS:
1680015a6ef6SSaurabh Misra 		*val = atgep->atge_tx_late_collisions;
1681015a6ef6SSaurabh Misra 		break;
1682015a6ef6SSaurabh Misra 
1683015a6ef6SSaurabh Misra 	case ETHER_STAT_EX_COLLISIONS:
1684015a6ef6SSaurabh Misra 		*val = atgep->atge_ex_collisions;
1685015a6ef6SSaurabh Misra 		break;
1686015a6ef6SSaurabh Misra 
1687015a6ef6SSaurabh Misra 	case ETHER_STAT_MACXMT_ERRORS:
1688015a6ef6SSaurabh Misra 		*val = atgep->atge_macxmt_errors;
1689015a6ef6SSaurabh Misra 		break;
1690015a6ef6SSaurabh Misra 
1691015a6ef6SSaurabh Misra 	case ETHER_STAT_CARRIER_ERRORS:
1692015a6ef6SSaurabh Misra 		*val = atgep->atge_carrier_errors;
1693015a6ef6SSaurabh Misra 		break;
1694015a6ef6SSaurabh Misra 
1695015a6ef6SSaurabh Misra 	case ETHER_STAT_TOOLONG_ERRORS:
1696015a6ef6SSaurabh Misra 		*val = atgep->atge_toolong_errors;
1697015a6ef6SSaurabh Misra 		break;
1698015a6ef6SSaurabh Misra 
1699015a6ef6SSaurabh Misra 	case ETHER_STAT_MACRCV_ERRORS:
1700015a6ef6SSaurabh Misra 		*val = atgep->atge_macrcv_errors;
1701015a6ef6SSaurabh Misra 		break;
1702015a6ef6SSaurabh Misra 
1703015a6ef6SSaurabh Misra 	case MAC_STAT_OVERFLOWS:
1704015a6ef6SSaurabh Misra 		*val = atgep->atge_overflow;
1705015a6ef6SSaurabh Misra 		break;
1706015a6ef6SSaurabh Misra 
1707015a6ef6SSaurabh Misra 	case MAC_STAT_UNDERFLOWS:
1708015a6ef6SSaurabh Misra 		*val = atgep->atge_underflow;
1709015a6ef6SSaurabh Misra 		break;
1710015a6ef6SSaurabh Misra 
1711015a6ef6SSaurabh Misra 	case ETHER_STAT_TOOSHORT_ERRORS:
1712015a6ef6SSaurabh Misra 		*val = atgep->atge_runt;
1713015a6ef6SSaurabh Misra 		break;
1714015a6ef6SSaurabh Misra 
1715015a6ef6SSaurabh Misra 	case ETHER_STAT_JABBER_ERRORS:
1716015a6ef6SSaurabh Misra 		*val = atgep->atge_jabber;
1717015a6ef6SSaurabh Misra 		break;
1718015a6ef6SSaurabh Misra 
1719015a6ef6SSaurabh Misra 	default:
1720015a6ef6SSaurabh Misra 		return (ENOTSUP);
1721015a6ef6SSaurabh Misra 	}
1722015a6ef6SSaurabh Misra 
1723015a6ef6SSaurabh Misra 	return (0);
1724015a6ef6SSaurabh Misra }
1725015a6ef6SSaurabh Misra 
1726015a6ef6SSaurabh Misra int
1727015a6ef6SSaurabh Misra atge_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags,
1728015a6ef6SSaurabh Misra     uint_t sz, void *val, uint_t *perm)
1729015a6ef6SSaurabh Misra {
1730015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1731015a6ef6SSaurabh Misra 
1732015a6ef6SSaurabh Misra 	return (mii_m_getprop(atgep->atge_mii, name, num, flags, sz, val,
1733015a6ef6SSaurabh Misra 	    perm));
1734015a6ef6SSaurabh Misra }
1735015a6ef6SSaurabh Misra 
1736015a6ef6SSaurabh Misra int
1737015a6ef6SSaurabh Misra atge_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1738015a6ef6SSaurabh Misra     const void *val)
1739015a6ef6SSaurabh Misra {
1740015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1741*0eb090a7SSaurabh Misra 	int r;
1742015a6ef6SSaurabh Misra 
1743*0eb090a7SSaurabh Misra 	r = mii_m_setprop(atgep->atge_mii, name, num, sz, val);
1744*0eb090a7SSaurabh Misra 
1745*0eb090a7SSaurabh Misra 	if (r == 0) {
1746*0eb090a7SSaurabh Misra 		mutex_enter(&atgep->atge_intr_lock);
1747*0eb090a7SSaurabh Misra 		mutex_enter(&atgep->atge_tx_lock);
1748*0eb090a7SSaurabh Misra 
1749*0eb090a7SSaurabh Misra 		if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
1750*0eb090a7SSaurabh Misra 			atge_device_restart(atgep);
1751*0eb090a7SSaurabh Misra 		}
1752*0eb090a7SSaurabh Misra 
1753*0eb090a7SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1754*0eb090a7SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
1755*0eb090a7SSaurabh Misra 	}
1756*0eb090a7SSaurabh Misra 
1757*0eb090a7SSaurabh Misra 	return (r);
1758015a6ef6SSaurabh Misra }
1759015a6ef6SSaurabh Misra 
1760015a6ef6SSaurabh Misra 
1761015a6ef6SSaurabh Misra void
1762015a6ef6SSaurabh Misra atge_program_ether(atge_t *atgep)
1763015a6ef6SSaurabh Misra {
1764015a6ef6SSaurabh Misra 	ether_addr_t e;
1765015a6ef6SSaurabh Misra 
1766015a6ef6SSaurabh Misra 	/*
1767015a6ef6SSaurabh Misra 	 * Reprogram the Station address.
1768015a6ef6SSaurabh Misra 	 */
1769015a6ef6SSaurabh Misra 	bcopy(atgep->atge_ether_addr, e, ETHERADDRL);
1770015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_PAR0,
1771015a6ef6SSaurabh Misra 	    ((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5]));
1772015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_PAR1, (e[0] << 8) | e[1]);
1773015a6ef6SSaurabh Misra }
1774015a6ef6SSaurabh Misra 
1775015a6ef6SSaurabh Misra /*
1776015a6ef6SSaurabh Misra  * Device specific operations.
1777015a6ef6SSaurabh Misra  */
1778015a6ef6SSaurabh Misra void
1779015a6ef6SSaurabh Misra atge_device_start(atge_t *atgep)
1780015a6ef6SSaurabh Misra {
1781*0eb090a7SSaurabh Misra 	uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo;
1782015a6ef6SSaurabh Misra 	uint32_t reg;
1783015a6ef6SSaurabh Misra 	uint32_t fsize;
1784015a6ef6SSaurabh Misra 
1785015a6ef6SSaurabh Misra 	/*
1786015a6ef6SSaurabh Misra 	 * Reprogram the Station address.
1787015a6ef6SSaurabh Misra 	 */
1788015a6ef6SSaurabh Misra 	atge_program_ether(atgep);
1789015a6ef6SSaurabh Misra 
1790015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1791015a6ef6SSaurabh Misra 		atge_l1e_program_dma(atgep);
1792*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1793*0eb090a7SSaurabh Misra 		atge_l1_program_dma(atgep);
1794015a6ef6SSaurabh Misra 	}
1795015a6ef6SSaurabh Misra 
1796015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name,
1797015a6ef6SSaurabh Misra 	    __func__));
1798015a6ef6SSaurabh Misra 
1799015a6ef6SSaurabh Misra 	OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
1800015a6ef6SSaurabh Misra 
1801015a6ef6SSaurabh Misra 	/*
1802*0eb090a7SSaurabh Misra 	 * Set Maximum frame size but don't let MTU be less than ETHER_MTU.
1803015a6ef6SSaurabh Misra 	 */
1804015a6ef6SSaurabh Misra 	if (atgep->atge_mtu < ETHERMTU)
1805015a6ef6SSaurabh Misra 		atgep->atge_max_frame_size = ETHERMTU;
1806015a6ef6SSaurabh Misra 	else
1807015a6ef6SSaurabh Misra 		atgep->atge_max_frame_size = atgep->atge_mtu;
1808015a6ef6SSaurabh Misra 
1809015a6ef6SSaurabh Misra 	atgep->atge_max_frame_size += sizeof (struct ether_header) +
1810015a6ef6SSaurabh Misra 	    VLAN_TAGSZ + ETHERFCSL;
1811015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size);
1812015a6ef6SSaurabh Misra 
1813015a6ef6SSaurabh Misra 
1814015a6ef6SSaurabh Misra 	/*
1815015a6ef6SSaurabh Misra 	 * Configure IPG/IFG parameters.
1816015a6ef6SSaurabh Misra 	 */
1817015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_IPG_IFG_CFG,
1818015a6ef6SSaurabh Misra 	    ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) |
1819015a6ef6SSaurabh Misra 	    ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) |
1820015a6ef6SSaurabh Misra 	    ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) |
1821015a6ef6SSaurabh Misra 	    ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK));
1822015a6ef6SSaurabh Misra 
1823015a6ef6SSaurabh Misra 	/*
1824015a6ef6SSaurabh Misra 	 * Set parameters for half-duplex media.
1825015a6ef6SSaurabh Misra 	 */
1826015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_HDPX_CFG,
1827015a6ef6SSaurabh Misra 	    ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) &
1828015a6ef6SSaurabh Misra 	    HDPX_CFG_LCOL_MASK) |
1829015a6ef6SSaurabh Misra 	    ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) &
1830015a6ef6SSaurabh Misra 	    HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN |
1831015a6ef6SSaurabh Misra 	    ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) &
1832015a6ef6SSaurabh Misra 	    HDPX_CFG_ABEBT_MASK) |
1833015a6ef6SSaurabh Misra 	    ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) &
1834015a6ef6SSaurabh Misra 	    HDPX_CFG_JAMIPG_MASK));
1835015a6ef6SSaurabh Misra 
1836015a6ef6SSaurabh Misra 	/*
1837015a6ef6SSaurabh Misra 	 * Configure jumbo frame.
1838015a6ef6SSaurabh Misra 	 */
1839015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1840015a6ef6SSaurabh Misra 		fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t));
1841015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_JUMBO_CFG,
1842015a6ef6SSaurabh Misra 		    (((fsize / sizeof (uint64_t)) <<
1843015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) &
1844015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_SZ_THRESH_MASK) |
1845015a6ef6SSaurabh Misra 		    ((RXQ_JUMBO_CFG_LKAH_DEFAULT <<
1846015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) |
1847015a6ef6SSaurabh Misra 		    ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) &
1848015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_RRD_TIMER_MASK));
1849015a6ef6SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E &&
1850015a6ef6SSaurabh Misra 	    atgep->atge_flags & ATGE_FLAG_JUMBO) {
1851015a6ef6SSaurabh Misra 
1852015a6ef6SSaurabh Misra 		if (atgep->atge_mtu < ETHERMTU)
1853015a6ef6SSaurabh Misra 			reg = atgep->atge_max_frame_size;
1854015a6ef6SSaurabh Misra 		else if (atgep->atge_mtu < 6 * 1024)
1855015a6ef6SSaurabh Misra 			reg = (atgep->atge_max_frame_size * 2) / 3;
1856015a6ef6SSaurabh Misra 		else
1857015a6ef6SSaurabh Misra 			reg = atgep->atge_max_frame_size / 2;
1858015a6ef6SSaurabh Misra 
1859015a6ef6SSaurabh Misra 		OUTL(atgep, L1E_TX_JUMBO_THRESH,
1860015a6ef6SSaurabh Misra 		    ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
1861015a6ef6SSaurabh Misra 		    TX_JUMBO_THRESH_UNIT_SHIFT);
1862015a6ef6SSaurabh Misra 	}
1863015a6ef6SSaurabh Misra 
1864015a6ef6SSaurabh Misra 	/*
1865015a6ef6SSaurabh Misra 	 * Configure flow-control parameters.
1866015a6ef6SSaurabh Misra 	 */
1867015a6ef6SSaurabh Misra 	if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
1868015a6ef6SSaurabh Misra 		/*
1869015a6ef6SSaurabh Misra 		 * Some hardware version require this magic.
1870015a6ef6SSaurabh Misra 		 */
1871015a6ef6SSaurabh Misra 		OUTL(atgep, 0x12FC, 0x6500);
1872015a6ef6SSaurabh Misra 		reg = INL(atgep, 0x1008);
1873015a6ef6SSaurabh Misra 		OUTL(atgep, 0x1008, reg | 0x8000);
1874015a6ef6SSaurabh Misra 	}
1875015a6ef6SSaurabh Misra 
1876015a6ef6SSaurabh Misra 	/*
1877015a6ef6SSaurabh Misra 	 * These are all magic parameters which came from FreeBSD.
1878015a6ef6SSaurabh Misra 	 */
1879*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1880*0eb090a7SSaurabh Misra 		switch (atgep->atge_chip_rev) {
1881*0eb090a7SSaurabh Misra 		case 0x8001:
1882*0eb090a7SSaurabh Misra 		case 0x9001:
1883*0eb090a7SSaurabh Misra 		case 0x9002:
1884*0eb090a7SSaurabh Misra 		case 0x9003:
1885*0eb090a7SSaurabh Misra 			rxf_hi = L1_RX_RING_CNT / 16;
1886*0eb090a7SSaurabh Misra 			rxf_lo = (L1_RX_RING_CNT * 7) / 8;
1887*0eb090a7SSaurabh Misra 			rrd_hi = (L1_RR_RING_CNT * 7) / 8;
1888*0eb090a7SSaurabh Misra 			rrd_lo = L1_RR_RING_CNT / 16;
1889*0eb090a7SSaurabh Misra 			break;
1890*0eb090a7SSaurabh Misra 		default:
1891*0eb090a7SSaurabh Misra 			reg = INL(atgep, L1_SRAM_RX_FIFO_LEN);
1892*0eb090a7SSaurabh Misra 			rxf_lo = reg / 16;
1893*0eb090a7SSaurabh Misra 			if (rxf_lo > 192)
1894*0eb090a7SSaurabh Misra 				rxf_lo = 192;
1895*0eb090a7SSaurabh Misra 			rxf_hi = (reg * 7) / 8;
1896*0eb090a7SSaurabh Misra 			if (rxf_hi < rxf_lo)
1897*0eb090a7SSaurabh Misra 				rxf_hi = rxf_lo + 16;
1898*0eb090a7SSaurabh Misra 			reg = INL(atgep, L1_SRAM_RRD_LEN);
1899*0eb090a7SSaurabh Misra 			rrd_lo = reg / 8;
1900*0eb090a7SSaurabh Misra 			rrd_hi = (reg * 7) / 8;
1901*0eb090a7SSaurabh Misra 			if (rrd_lo > 2)
1902*0eb090a7SSaurabh Misra 				rrd_lo = 2;
1903*0eb090a7SSaurabh Misra 			if (rrd_hi < rrd_lo)
1904*0eb090a7SSaurabh Misra 				rrd_hi = rrd_lo + 3;
1905*0eb090a7SSaurabh Misra 			break;
1906*0eb090a7SSaurabh Misra 		}
1907*0eb090a7SSaurabh Misra 
1908*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
1909*0eb090a7SSaurabh Misra 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
1910*0eb090a7SSaurabh Misra 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
1911*0eb090a7SSaurabh Misra 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
1912*0eb090a7SSaurabh Misra 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
1913*0eb090a7SSaurabh Misra 
1914*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_RXQ_RRD_PAUSE_THRESH,
1915*0eb090a7SSaurabh Misra 		    ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) &
1916*0eb090a7SSaurabh Misra 		    RXQ_RRD_PAUSE_THRESH_LO_MASK) |
1917*0eb090a7SSaurabh Misra 		    ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
1918*0eb090a7SSaurabh Misra 		    RXQ_RRD_PAUSE_THRESH_HI_MASK));
1919*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1920015a6ef6SSaurabh Misra 		reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
1921015a6ef6SSaurabh Misra 		rxf_hi = (reg * 4) / 5;
1922015a6ef6SSaurabh Misra 		rxf_lo = reg/ 5;
1923015a6ef6SSaurabh Misra 
1924015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
1925015a6ef6SSaurabh Misra 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
1926015a6ef6SSaurabh Misra 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
1927015a6ef6SSaurabh Misra 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
1928015a6ef6SSaurabh Misra 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
1929015a6ef6SSaurabh Misra 	}
1930015a6ef6SSaurabh Misra 
1931015a6ef6SSaurabh Misra 	/* Configure RxQ. */
1932015a6ef6SSaurabh Misra 	reg = 0;
1933*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1934*0eb090a7SSaurabh Misra 		reg =
1935*0eb090a7SSaurabh Misra 		    ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
1936*0eb090a7SSaurabh Misra 		    RXQ_CFG_RD_BURST_MASK) |
1937*0eb090a7SSaurabh Misra 		    ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
1938*0eb090a7SSaurabh Misra 		    RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
1939*0eb090a7SSaurabh Misra 		    RXQ_CFG_RRD_BURST_THRESH_MASK) |
1940*0eb090a7SSaurabh Misra 		    ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
1941*0eb090a7SSaurabh Misra 		    RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
1942*0eb090a7SSaurabh Misra 		    RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
1943*0eb090a7SSaurabh Misra 		    RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
1944*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_CFG, reg);
1945*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1946015a6ef6SSaurabh Misra 		reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB |
1947015a6ef6SSaurabh Misra 		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
1948015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_CFG, reg);
1949015a6ef6SSaurabh Misra 	}
1950015a6ef6SSaurabh Misra 
1951015a6ef6SSaurabh Misra 	/*
1952015a6ef6SSaurabh Misra 	 * Configure TxQ.
1953015a6ef6SSaurabh Misra 	 */
1954*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1955*0eb090a7SSaurabh Misra 		reg =
1956*0eb090a7SSaurabh Misra 		    (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
1957*0eb090a7SSaurabh Misra 		    TXQ_CFG_TPD_BURST_MASK) |
1958*0eb090a7SSaurabh Misra 		    ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
1959*0eb090a7SSaurabh Misra 		    TXQ_CFG_TX_FIFO_BURST_SHIFT) &
1960*0eb090a7SSaurabh Misra 		    TXQ_CFG_TX_FIFO_BURST_MASK) |
1961*0eb090a7SSaurabh Misra 		    ((TXQ_CFG_TPD_FETCH_DEFAULT <<
1962*0eb090a7SSaurabh Misra 		    TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
1963*0eb090a7SSaurabh Misra 		    TXQ_CFG_TPD_FETCH_THRESH_MASK) |
1964*0eb090a7SSaurabh Misra 		    TXQ_CFG_ENB);
1965*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_TXQ_CFG, reg);
1966*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1967015a6ef6SSaurabh Misra 		reg = (128 <<
1968015a6ef6SSaurabh Misra 		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
1969015a6ef6SSaurabh Misra 		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
1970015a6ef6SSaurabh Misra 
1971015a6ef6SSaurabh Misra 		reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
1972015a6ef6SSaurabh Misra 		    TXQ_CFG_TPD_BURST_MASK;
1973015a6ef6SSaurabh Misra 
1974015a6ef6SSaurabh Misra 		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
1975015a6ef6SSaurabh Misra 
1976015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_TXQ_CFG, reg);
1977015a6ef6SSaurabh Misra 	}
1978015a6ef6SSaurabh Misra 
1979*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1980*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
1981*0eb090a7SSaurabh Misra 		    (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
1982*0eb090a7SSaurabh Misra 		    TX_JUMBO_TPD_TH_MASK) |
1983*0eb090a7SSaurabh Misra 		    ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
1984*0eb090a7SSaurabh Misra 		    TX_JUMBO_TPD_IPG_MASK));
1985*0eb090a7SSaurabh Misra 	}
1986*0eb090a7SSaurabh Misra 
1987015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
1988015a6ef6SSaurabh Misra 		/* Disable RSS. */
1989015a6ef6SSaurabh Misra 		OUTL(atgep, L1E_RSS_IDT_TABLE0, 0);
1990015a6ef6SSaurabh Misra 		OUTL(atgep, L1E_RSS_CPU, 0);
1991015a6ef6SSaurabh Misra 	}
1992015a6ef6SSaurabh Misra 
1993015a6ef6SSaurabh Misra 	/*
1994015a6ef6SSaurabh Misra 	 * Configure DMA parameters.
1995015a6ef6SSaurabh Misra 	 */
1996*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1997*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG,
1998*0eb090a7SSaurabh Misra 		    DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
1999*0eb090a7SSaurabh Misra 		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
2000*0eb090a7SSaurabh Misra 		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
2001*0eb090a7SSaurabh Misra 
2002*0eb090a7SSaurabh Misra 		/* Configure CMB DMA write threshold. */
2003*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_CMB_WR_THRESH,
2004*0eb090a7SSaurabh Misra 		    ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
2005*0eb090a7SSaurabh Misra 		    CMB_WR_THRESH_RRD_MASK) |
2006*0eb090a7SSaurabh Misra 		    ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
2007*0eb090a7SSaurabh Misra 		    CMB_WR_THRESH_TPD_MASK));
2008*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2009015a6ef6SSaurabh Misra 		/*
2010015a6ef6SSaurabh Misra 		 * Don't use Tx CMB. It is known to cause RRS update failure
2011015a6ef6SSaurabh Misra 		 * under certain circumstances. Typical phenomenon of the
2012015a6ef6SSaurabh Misra 		 * issue would be unexpected sequence number encountered in
2013015a6ef6SSaurabh Misra 		 * Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB.
2014015a6ef6SSaurabh Misra 		 */
2015015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG,
2016015a6ef6SSaurabh Misra 		    DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
2017015a6ef6SSaurabh Misra 		    atgep->atge_dma_rd_burst | atgep->atge_dma_wr_burst |
2018015a6ef6SSaurabh Misra 		    DMA_CFG_RXCMB_ENB |
2019015a6ef6SSaurabh Misra 		    ((DMA_CFG_RD_DELAY_CNT_DEFAULT <<
2020015a6ef6SSaurabh Misra 		    DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) |
2021015a6ef6SSaurabh Misra 		    ((DMA_CFG_WR_DELAY_CNT_DEFAULT <<
2022015a6ef6SSaurabh Misra 		    DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK));
2023015a6ef6SSaurabh Misra 	}
2024015a6ef6SSaurabh Misra 
2025015a6ef6SSaurabh Misra 	/*
2026*0eb090a7SSaurabh Misra 	 * Enable CMB/SMB timer.
2027015a6ef6SSaurabh Misra 	 */
2028*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2029*0eb090a7SSaurabh Misra 		/* Set CMB/SMB timer and enable them. */
2030*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_CMB_WR_TIMER,
2031*0eb090a7SSaurabh Misra 		    ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) &
2032*0eb090a7SSaurabh Misra 		    CMB_WR_TIMER_TX_MASK) |
2033*0eb090a7SSaurabh Misra 		    ((ATGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) &
2034*0eb090a7SSaurabh Misra 		    CMB_WR_TIMER_RX_MASK));
2035*0eb090a7SSaurabh Misra 
2036*0eb090a7SSaurabh Misra 		/* Request SMB updates for every seconds. */
2037*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000));
2038*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_CSMB_CTRL,
2039*0eb090a7SSaurabh Misra 		    CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB);
2040*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2041015a6ef6SSaurabh Misra 		OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
2042015a6ef6SSaurabh Misra 		atge_l1e_clear_stats(atgep);
2043015a6ef6SSaurabh Misra 	}
2044015a6ef6SSaurabh Misra 
2045*0eb090a7SSaurabh Misra 
2046015a6ef6SSaurabh Misra 	/*
2047015a6ef6SSaurabh Misra 	 * Disable all WOL bits as WOL can interfere normal Rx
2048015a6ef6SSaurabh Misra 	 * operation.
2049015a6ef6SSaurabh Misra 	 */
2050015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_WOL_CFG, 0);
2051015a6ef6SSaurabh Misra 
2052015a6ef6SSaurabh Misra 	/*
2053015a6ef6SSaurabh Misra 	 * Configure Tx/Rx MACs.
2054015a6ef6SSaurabh Misra 	 *  - Auto-padding for short frames.
2055015a6ef6SSaurabh Misra 	 *  - Enable CRC generation.
2056015a6ef6SSaurabh Misra 	 *
2057015a6ef6SSaurabh Misra 	 *  Start with full-duplex/1000Mbps media. Actual reconfiguration
2058015a6ef6SSaurabh Misra 	 *  of MAC is followed after link establishment.
2059015a6ef6SSaurabh Misra 	 */
2060015a6ef6SSaurabh Misra 	reg = (ATGE_CFG_TX_CRC_ENB | ATGE_CFG_TX_AUTO_PAD |
2061015a6ef6SSaurabh Misra 	    ATGE_CFG_FULL_DUPLEX |
2062015a6ef6SSaurabh Misra 	    ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) &
2063015a6ef6SSaurabh Misra 	    ATGE_CFG_PREAMBLE_MASK));
2064015a6ef6SSaurabh Misra 
2065015a6ef6SSaurabh Misra 	if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) {
2066015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_10_100;
2067015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__));
2068015a6ef6SSaurabh Misra 	} else {
2069015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_1000;
2070015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__));
2071015a6ef6SSaurabh Misra 	}
2072015a6ef6SSaurabh Misra 
2073015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAC_CFG, reg);
2074015a6ef6SSaurabh Misra 
2075015a6ef6SSaurabh Misra 	atgep->atge_chip_state |= ATGE_CHIP_RUNNING;
2076015a6ef6SSaurabh Misra 
2077015a6ef6SSaurabh Misra 	/*
2078015a6ef6SSaurabh Misra 	 * Set up the receive filter.
2079015a6ef6SSaurabh Misra 	 */
2080015a6ef6SSaurabh Misra 	atge_rxfilter(atgep);
2081015a6ef6SSaurabh Misra 
2082015a6ef6SSaurabh Misra 	/*
2083015a6ef6SSaurabh Misra 	 * Acknowledge all pending interrupts and clear it.
2084015a6ef6SSaurabh Misra 	 */
2085*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2086*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_INTR_STATUS, 0);
2087*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
2088*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2089015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS);
2090015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
2091015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_STATUS, 0);
2092*0eb090a7SSaurabh Misra 	}
2093015a6ef6SSaurabh Misra 
2094015a6ef6SSaurabh Misra 	atge_mac_config(atgep);
2095015a6ef6SSaurabh Misra 
2096015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() device started", atgep->atge_name, __func__));
2097015a6ef6SSaurabh Misra }
2098015a6ef6SSaurabh Misra 
2099015a6ef6SSaurabh Misra /*
2100015a6ef6SSaurabh Misra  * Generic functions.
2101015a6ef6SSaurabh Misra  */
2102015a6ef6SSaurabh Misra 
2103015a6ef6SSaurabh Misra #define	CRC32_POLY_BE   0x04c11db7
2104015a6ef6SSaurabh Misra uint32_t
2105015a6ef6SSaurabh Misra atge_ether_crc(const uint8_t *addr, int len)
2106015a6ef6SSaurabh Misra {
2107015a6ef6SSaurabh Misra 	int idx;
2108015a6ef6SSaurabh Misra 	int bit;
2109015a6ef6SSaurabh Misra 	uint_t data;
2110015a6ef6SSaurabh Misra 	uint32_t crc;
2111015a6ef6SSaurabh Misra 
2112015a6ef6SSaurabh Misra 	crc = 0xffffffff;
2113015a6ef6SSaurabh Misra 	for (idx = 0; idx < len; idx++) {
2114015a6ef6SSaurabh Misra 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
2115015a6ef6SSaurabh Misra 			crc = (crc << 1)
2116015a6ef6SSaurabh Misra 			    ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
2117015a6ef6SSaurabh Misra 		}
2118015a6ef6SSaurabh Misra 	}
2119015a6ef6SSaurabh Misra 
2120015a6ef6SSaurabh Misra 	return (crc);
2121015a6ef6SSaurabh Misra }
2122015a6ef6SSaurabh Misra 
2123015a6ef6SSaurabh Misra 
2124015a6ef6SSaurabh Misra /*
2125015a6ef6SSaurabh Misra  * Programs RX filter. We use a link-list to keep track of all multicast
2126015a6ef6SSaurabh Misra  * addressess.
2127015a6ef6SSaurabh Misra  */
2128015a6ef6SSaurabh Misra void
2129015a6ef6SSaurabh Misra atge_rxfilter(atge_t *atgep)
2130015a6ef6SSaurabh Misra {
2131015a6ef6SSaurabh Misra 	uint32_t rxcfg;
2132015a6ef6SSaurabh Misra 	uint64_t mchash;
2133015a6ef6SSaurabh Misra 
2134015a6ef6SSaurabh Misra 	rxcfg = INL(atgep, ATGE_MAC_CFG);
2135015a6ef6SSaurabh Misra 	rxcfg &= ~(ATGE_CFG_ALLMULTI | ATGE_CFG_PROMISC);
2136015a6ef6SSaurabh Misra 
2137015a6ef6SSaurabh Misra 	/*
2138015a6ef6SSaurabh Misra 	 * Accept broadcast frames.
2139015a6ef6SSaurabh Misra 	 */
2140015a6ef6SSaurabh Misra 	rxcfg |= ATGE_CFG_BCAST;
2141015a6ef6SSaurabh Misra 
2142015a6ef6SSaurabh Misra 	/*
2143015a6ef6SSaurabh Misra 	 * We don't use Hardware VLAN tagging.
2144015a6ef6SSaurabh Misra 	 */
2145015a6ef6SSaurabh Misra 	rxcfg &= ~ATGE_CFG_VLAN_TAG_STRIP;
2146015a6ef6SSaurabh Misra 
2147015a6ef6SSaurabh Misra 	if (atgep->atge_filter_flags & (ATGE_PROMISC | ATGE_ALL_MULTICST)) {
2148015a6ef6SSaurabh Misra 		mchash = ~0ULL;
2149015a6ef6SSaurabh Misra 
2150015a6ef6SSaurabh Misra 		if (atgep->atge_filter_flags & ATGE_PROMISC)
2151015a6ef6SSaurabh Misra 			rxcfg |= ATGE_CFG_PROMISC;
2152015a6ef6SSaurabh Misra 
2153015a6ef6SSaurabh Misra 		if (atgep->atge_filter_flags & ATGE_ALL_MULTICST)
2154015a6ef6SSaurabh Misra 			rxcfg |= ATGE_CFG_ALLMULTI;
2155015a6ef6SSaurabh Misra 	} else {
2156015a6ef6SSaurabh Misra 		mchash = atgep->atge_mchash;
2157015a6ef6SSaurabh Misra 	}
2158015a6ef6SSaurabh Misra 
2159015a6ef6SSaurabh Misra 	atge_program_ether(atgep);
2160015a6ef6SSaurabh Misra 
2161015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAR0, (uint32_t)mchash);
2162015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAR1, (uint32_t)(mchash >> 32));
2163015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAC_CFG, rxcfg);
2164015a6ef6SSaurabh Misra 
2165015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx",
2166015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, rxcfg, mchash));
2167015a6ef6SSaurabh Misra }
2168015a6ef6SSaurabh Misra 
2169015a6ef6SSaurabh Misra void
2170015a6ef6SSaurabh Misra atge_device_stop(atge_t *atgep)
2171015a6ef6SSaurabh Misra {
2172015a6ef6SSaurabh Misra 	uint32_t reg;
2173015a6ef6SSaurabh Misra 	int t;
2174015a6ef6SSaurabh Misra 
2175015a6ef6SSaurabh Misra 	/*
2176015a6ef6SSaurabh Misra 	 * If the chip is being suspended, then don't touch the state. Caller
2177015a6ef6SSaurabh Misra 	 * will take care of setting the correct state.
2178015a6ef6SSaurabh Misra 	 */
2179015a6ef6SSaurabh Misra 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
2180015a6ef6SSaurabh Misra 		atgep->atge_chip_state |= ATGE_CHIP_STOPPED;
2181015a6ef6SSaurabh Misra 		atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
2182015a6ef6SSaurabh Misra 	}
2183015a6ef6SSaurabh Misra 
2184015a6ef6SSaurabh Misra 	/*
2185015a6ef6SSaurabh Misra 	 * Collect stats for L1E. L1 chip's stats are collected by interrupt.
2186015a6ef6SSaurabh Misra 	 */
2187015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2188015a6ef6SSaurabh Misra 		atge_l1e_gather_stats(atgep);
2189015a6ef6SSaurabh Misra 	}
2190015a6ef6SSaurabh Misra 
2191015a6ef6SSaurabh Misra 	/*
2192015a6ef6SSaurabh Misra 	 * Disable interrupts.
2193015a6ef6SSaurabh Misra 	 */
2194015a6ef6SSaurabh Misra 	atge_disable_intrs(atgep);
2195015a6ef6SSaurabh Misra 
2196*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1)
2197*0eb090a7SSaurabh Misra 		OUTL(atgep, L1_CSMB_CTRL, 0);
2198*0eb090a7SSaurabh Misra 
2199*0eb090a7SSaurabh Misra 	/* Stop DMA Engine */
2200*0eb090a7SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2201*0eb090a7SSaurabh Misra 		atge_l1_stop_tx_mac(atgep);
2202*0eb090a7SSaurabh Misra 		atge_l1_stop_rx_mac(atgep);
2203*0eb090a7SSaurabh Misra 
2204*0eb090a7SSaurabh Misra 		reg = INL(atgep, ATGE_DMA_CFG);
2205*0eb090a7SSaurabh Misra 		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
2206*0eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG, reg);
2207*0eb090a7SSaurabh Misra 
2208*0eb090a7SSaurabh Misra 	}
2209*0eb090a7SSaurabh Misra 
2210015a6ef6SSaurabh Misra 	/*
2211015a6ef6SSaurabh Misra 	 * Disable queue processing.
2212015a6ef6SSaurabh Misra 	 */
2213015a6ef6SSaurabh Misra 	/* Stop TxQ */
2214015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_TXQ_CFG);
2215015a6ef6SSaurabh Misra 	reg = reg & ~TXQ_CFG_ENB;
2216015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_TXQ_CFG, reg);
2217015a6ef6SSaurabh Misra 
2218015a6ef6SSaurabh Misra 	/* Stop RxQ */
2219015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_RXQ_CFG);
2220015a6ef6SSaurabh Misra 	reg = reg & ~RXQ_CFG_ENB;
2221015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_RXQ_CFG, reg);
2222015a6ef6SSaurabh Misra 
2223015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2224015a6ef6SSaurabh Misra 		reg = INL(atgep, ATGE_DMA_CFG);
2225015a6ef6SSaurabh Misra 		reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB);
2226015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG, reg);
2227015a6ef6SSaurabh Misra 		drv_usecwait(1000);
2228015a6ef6SSaurabh Misra 		atge_l1e_stop_mac(atgep);
2229015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
2230015a6ef6SSaurabh Misra 	}
2231015a6ef6SSaurabh Misra 
2232015a6ef6SSaurabh Misra 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
2233015a6ef6SSaurabh Misra 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
2234015a6ef6SSaurabh Misra 			break;
2235015a6ef6SSaurabh Misra 		drv_usecwait(10);
2236015a6ef6SSaurabh Misra 	}
2237015a6ef6SSaurabh Misra 
2238015a6ef6SSaurabh Misra 	if (t == 0) {
2239015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() stopping TX/RX MAC timeout",
2240015a6ef6SSaurabh Misra 		    __func__);
2241015a6ef6SSaurabh Misra 	}
2242015a6ef6SSaurabh Misra }
2243015a6ef6SSaurabh Misra 
2244015a6ef6SSaurabh Misra void
2245015a6ef6SSaurabh Misra atge_disable_intrs(atge_t *atgep)
2246015a6ef6SSaurabh Misra {
2247015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_INTR_MASK, 0);
2248015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
2249015a6ef6SSaurabh Misra }
2250015a6ef6SSaurabh Misra 
2251015a6ef6SSaurabh Misra void
2252015a6ef6SSaurabh Misra atge_device_init(atge_t *atgep)
2253015a6ef6SSaurabh Misra {
2254015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2255015a6ef6SSaurabh Misra 		atgep->atge_intrs = L1E_INTRS;
2256015a6ef6SSaurabh Misra 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
2257015a6ef6SSaurabh Misra 
2258015a6ef6SSaurabh Misra 		atge_l1e_init_tx_ring(atgep);
2259015a6ef6SSaurabh Misra 		atge_l1e_init_rx_pages(atgep);
2260*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2261*0eb090a7SSaurabh Misra 		atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN |
2262*0eb090a7SSaurabh Misra 		    INTR_LINK_CHG;
2263*0eb090a7SSaurabh Misra 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
2264*0eb090a7SSaurabh Misra 
2265*0eb090a7SSaurabh Misra 		atge_l1_init_tx_ring(atgep);
2266*0eb090a7SSaurabh Misra 		atge_l1_init_rx_ring(atgep);
2267*0eb090a7SSaurabh Misra 		atge_l1_init_rr_ring(atgep);
2268*0eb090a7SSaurabh Misra 		atge_l1_init_cmb(atgep);
2269*0eb090a7SSaurabh Misra 		atge_l1_init_smb(atgep);
2270015a6ef6SSaurabh Misra 	}
2271015a6ef6SSaurabh Misra }
2272015a6ef6SSaurabh Misra 
2273015a6ef6SSaurabh Misra void
2274015a6ef6SSaurabh Misra atge_device_restart(atge_t *atgep)
2275015a6ef6SSaurabh Misra {
2276015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
2277015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
2278015a6ef6SSaurabh Misra 
2279015a6ef6SSaurabh Misra 	/*
2280015a6ef6SSaurabh Misra 	 * Cancel any pending I/O.
2281015a6ef6SSaurabh Misra 	 */
2282015a6ef6SSaurabh Misra 	atge_device_stop(atgep);
2283015a6ef6SSaurabh Misra 
2284015a6ef6SSaurabh Misra 	/*
2285015a6ef6SSaurabh Misra 	 * Reset the chip to a known state.
2286015a6ef6SSaurabh Misra 	 */
2287015a6ef6SSaurabh Misra 	atge_device_reset(atgep);
2288015a6ef6SSaurabh Misra 
2289015a6ef6SSaurabh Misra 	/*
2290015a6ef6SSaurabh Misra 	 * Initialize the ring and other descriptor like CMB/SMB/Rx return.
2291015a6ef6SSaurabh Misra 	 */
2292015a6ef6SSaurabh Misra 	atge_device_init(atgep);
2293015a6ef6SSaurabh Misra 
2294015a6ef6SSaurabh Misra 	/*
2295015a6ef6SSaurabh Misra 	 * Start the chip.
2296015a6ef6SSaurabh Misra 	 */
2297015a6ef6SSaurabh Misra 	atge_device_start(atgep);
2298015a6ef6SSaurabh Misra 
2299015a6ef6SSaurabh Misra }
2300015a6ef6SSaurabh Misra 
2301015a6ef6SSaurabh Misra static int
2302015a6ef6SSaurabh Misra atge_send_a_packet(atge_t *atgep, mblk_t *mp)
2303015a6ef6SSaurabh Misra {
2304*0eb090a7SSaurabh Misra 	atge_tx_desc_t	*txd;
2305*0eb090a7SSaurabh Misra 	uchar_t *c;
2306*0eb090a7SSaurabh Misra 	uint32_t cflags = 0;
2307015a6ef6SSaurabh Misra 	atge_ring_t *r;
2308015a6ef6SSaurabh Misra 	size_t pktlen;
2309015a6ef6SSaurabh Misra 	uchar_t *buf;
2310015a6ef6SSaurabh Misra 	int	start;
2311015a6ef6SSaurabh Misra 
2312015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
2313015a6ef6SSaurabh Misra 	ASSERT(mp != NULL);
2314015a6ef6SSaurabh Misra 
2315015a6ef6SSaurabh Misra 	pktlen = msgsize(mp);
2316015a6ef6SSaurabh Misra 	if (pktlen > atgep->atge_tx_buf_len) {
2317015a6ef6SSaurabh Misra 		atgep->atge_macxmt_errors++;
2318015a6ef6SSaurabh Misra 
2319015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)",
2320015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__,
2321015a6ef6SSaurabh Misra 		    pktlen, atgep->atge_rx_buf_len));
2322015a6ef6SSaurabh Misra 
2323015a6ef6SSaurabh Misra 		freemsg(mp);
2324*0eb090a7SSaurabh Misra 		return (DDI_SUCCESS);
2325015a6ef6SSaurabh Misra 	}
2326015a6ef6SSaurabh Misra 
2327015a6ef6SSaurabh Misra 	r = atgep->atge_tx_ring;
2328015a6ef6SSaurabh Misra 
2329015a6ef6SSaurabh Misra 	if (r->r_avail_desc <= 1) {
2330015a6ef6SSaurabh Misra 		atgep->atge_noxmtbuf++;
2331015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 1;
2332*0eb090a7SSaurabh Misra 
2333*0eb090a7SSaurabh Misra 		ATGE_DB(("%s: %s() No transmit buf",
2334*0eb090a7SSaurabh Misra 		    atgep->atge_name, __func__));
2335*0eb090a7SSaurabh Misra 
2336*0eb090a7SSaurabh Misra 		return (DDI_FAILURE);
2337015a6ef6SSaurabh Misra 	}
2338015a6ef6SSaurabh Misra 
2339015a6ef6SSaurabh Misra 	start = r->r_producer;
2340015a6ef6SSaurabh Misra 
2341015a6ef6SSaurabh Misra 	/*
2342015a6ef6SSaurabh Misra 	 * Get the DMA buffer to hold a packet.
2343015a6ef6SSaurabh Misra 	 */
2344015a6ef6SSaurabh Misra 	buf = (uchar_t *)r->r_buf_tbl[start]->addr;
2345015a6ef6SSaurabh Misra 
2346015a6ef6SSaurabh Misra 	/*
2347015a6ef6SSaurabh Misra 	 * Copy the msg and free mp
2348015a6ef6SSaurabh Misra 	 */
2349015a6ef6SSaurabh Misra 	mcopymsg(mp, buf);
2350015a6ef6SSaurabh Misra 
2351015a6ef6SSaurabh Misra 	r->r_avail_desc--;
2352015a6ef6SSaurabh Misra 
2353*0eb090a7SSaurabh Misra 	c = (uchar_t *)r->r_desc_ring->addr;
2354*0eb090a7SSaurabh Misra 	c += (sizeof (atge_tx_desc_t) * start);
2355*0eb090a7SSaurabh Misra 	txd = (atge_tx_desc_t *)c;
2356*0eb090a7SSaurabh Misra 
2357*0eb090a7SSaurabh Misra 	ATGE_PUT64(r->r_desc_ring, &txd->addr,
2358*0eb090a7SSaurabh Misra 	    r->r_buf_tbl[start]->cookie.dmac_laddress);
2359*0eb090a7SSaurabh Misra 
2360*0eb090a7SSaurabh Misra 	ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
2361*0eb090a7SSaurabh Misra 
2362*0eb090a7SSaurabh Misra 	cflags |= ATGE_TD_EOP;
2363*0eb090a7SSaurabh Misra 	ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
2364*0eb090a7SSaurabh Misra 
2365*0eb090a7SSaurabh Misra 	/*
2366*0eb090a7SSaurabh Misra 	 * Sync buffer first.
2367*0eb090a7SSaurabh Misra 	 */
2368*0eb090a7SSaurabh Misra 	DMA_SYNC(r->r_buf_tbl[start], 0, pktlen, DDI_DMA_SYNC_FORDEV);
2369*0eb090a7SSaurabh Misra 
2370*0eb090a7SSaurabh Misra 	/*
2371*0eb090a7SSaurabh Misra 	 * Increment TX producer count by one.
2372*0eb090a7SSaurabh Misra 	 */
2373*0eb090a7SSaurabh Misra 	ATGE_INC_SLOT(r->r_producer, ATGE_TX_RING_CNT);
2374*0eb090a7SSaurabh Misra 
2375*0eb090a7SSaurabh Misra 	/*
2376*0eb090a7SSaurabh Misra 	 * Sync descriptor table.
2377*0eb090a7SSaurabh Misra 	 */
2378*0eb090a7SSaurabh Misra 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
2379*0eb090a7SSaurabh Misra 
2380015a6ef6SSaurabh Misra 	/*
2381015a6ef6SSaurabh Misra 	 * Program TX descriptor to send a packet.
2382015a6ef6SSaurabh Misra 	 */
2383015a6ef6SSaurabh Misra 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2384*0eb090a7SSaurabh Misra 		atge_l1e_send_packet(r);
2385*0eb090a7SSaurabh Misra 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2386*0eb090a7SSaurabh Misra 		atge_l1_send_packet(r);
2387015a6ef6SSaurabh Misra 	}
2388015a6ef6SSaurabh Misra 
2389*0eb090a7SSaurabh Misra 	r->r_atge->atge_opackets++;
2390*0eb090a7SSaurabh Misra 	r->r_atge->atge_obytes += pktlen;
2391*0eb090a7SSaurabh Misra 
2392*0eb090a7SSaurabh Misra 	ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer  :%d, "
2393*0eb090a7SSaurabh Misra 	    "consumer : %d", atgep->atge_name, __func__, pktlen,
2394*0eb090a7SSaurabh Misra 	    r->r_avail_desc, r->r_producer, r->r_consumer));
2395*0eb090a7SSaurabh Misra 
2396*0eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
2397015a6ef6SSaurabh Misra }
2398015a6ef6SSaurabh Misra 
2399015a6ef6SSaurabh Misra /*
2400015a6ef6SSaurabh Misra  * Stream Information.
2401015a6ef6SSaurabh Misra  */
2402015a6ef6SSaurabh Misra DDI_DEFINE_STREAM_OPS(atge_devops, nulldev, nulldev, atge_attach, atge_detach,
2403015a6ef6SSaurabh Misra     nodev, NULL, D_MP, NULL, atge_quiesce);
2404015a6ef6SSaurabh Misra 
2405015a6ef6SSaurabh Misra /*
2406015a6ef6SSaurabh Misra  * Module linkage information.
2407015a6ef6SSaurabh Misra  */
2408015a6ef6SSaurabh Misra static	struct	modldrv	atge_modldrv = {
2409015a6ef6SSaurabh Misra 	&mod_driverops,				/* Type of Module */
2410015a6ef6SSaurabh Misra 	"Atheros/Attansic Gb Ethernet",		/* Description */
2411015a6ef6SSaurabh Misra 	&atge_devops				/* drv_dev_ops */
2412015a6ef6SSaurabh Misra };
2413015a6ef6SSaurabh Misra 
2414015a6ef6SSaurabh Misra static	struct	modlinkage atge_modlinkage = {
2415015a6ef6SSaurabh Misra 	MODREV_1,			/* ml_rev */
2416015a6ef6SSaurabh Misra 	(void *)&atge_modldrv,
2417015a6ef6SSaurabh Misra 	NULL
2418015a6ef6SSaurabh Misra };
2419015a6ef6SSaurabh Misra 
2420015a6ef6SSaurabh Misra /*
2421015a6ef6SSaurabh Misra  * DDI Entry points.
2422015a6ef6SSaurabh Misra  */
2423015a6ef6SSaurabh Misra int
2424015a6ef6SSaurabh Misra _init(void)
2425015a6ef6SSaurabh Misra {
2426015a6ef6SSaurabh Misra 	int	r;
2427015a6ef6SSaurabh Misra 	mac_init_ops(&atge_devops, "atge");
2428015a6ef6SSaurabh Misra 	if ((r = mod_install(&atge_modlinkage)) != DDI_SUCCESS) {
2429015a6ef6SSaurabh Misra 		mac_fini_ops(&atge_devops);
2430015a6ef6SSaurabh Misra 	}
2431015a6ef6SSaurabh Misra 
2432015a6ef6SSaurabh Misra 	return (r);
2433015a6ef6SSaurabh Misra }
2434015a6ef6SSaurabh Misra 
2435015a6ef6SSaurabh Misra int
2436015a6ef6SSaurabh Misra _fini(void)
2437015a6ef6SSaurabh Misra {
2438015a6ef6SSaurabh Misra 	int	r;
2439015a6ef6SSaurabh Misra 
2440015a6ef6SSaurabh Misra 	if ((r = mod_remove(&atge_modlinkage)) == DDI_SUCCESS) {
2441015a6ef6SSaurabh Misra 		mac_fini_ops(&atge_devops);
2442015a6ef6SSaurabh Misra 	}
2443015a6ef6SSaurabh Misra 
2444015a6ef6SSaurabh Misra 	return (r);
2445015a6ef6SSaurabh Misra }
2446015a6ef6SSaurabh Misra 
2447015a6ef6SSaurabh Misra int
2448015a6ef6SSaurabh Misra _info(struct modinfo *modinfop)
2449015a6ef6SSaurabh Misra {
2450015a6ef6SSaurabh Misra 	return (mod_info(&atge_modlinkage, modinfop));
2451015a6ef6SSaurabh Misra }
2452