xref: /illumos-gate/usr/src/uts/common/io/atge/atge_main.c (revision 80e3e236)
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 /*
235e8715b9SGary Mills  * Copyright (c) 2012 Gary Mills
245e8715b9SGary Mills  *
259d8d9e11SGarrett D'Amore  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
26*80e3e236SJohn Levon  *
27*80e3e236SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
28015a6ef6SSaurabh Misra  */
295e8715b9SGary Mills /*
305e8715b9SGary Mills  * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
315e8715b9SGary Mills  * All rights reserved.
325e8715b9SGary Mills  *
335e8715b9SGary Mills  * Redistribution and use in source and binary forms, with or without
345e8715b9SGary Mills  * modification, are permitted provided that the following conditions
355e8715b9SGary Mills  * are met:
365e8715b9SGary Mills  * 1. Redistributions of source code must retain the above copyright
375e8715b9SGary Mills  *    notice unmodified, this list of conditions, and the following
385e8715b9SGary Mills  *    disclaimer.
395e8715b9SGary Mills  * 2. Redistributions in binary form must reproduce the above copyright
405e8715b9SGary Mills  *    notice, this list of conditions and the following disclaimer in the
415e8715b9SGary Mills  *    documentation and/or other materials provided with the distribution.
425e8715b9SGary Mills  *
435e8715b9SGary Mills  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
445e8715b9SGary Mills  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
455e8715b9SGary Mills  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
465e8715b9SGary Mills  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
475e8715b9SGary Mills  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
485e8715b9SGary Mills  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
495e8715b9SGary Mills  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
505e8715b9SGary Mills  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
515e8715b9SGary Mills  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
525e8715b9SGary Mills  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
535e8715b9SGary Mills  * SUCH DAMAGE.
545e8715b9SGary Mills  */
55015a6ef6SSaurabh Misra 
56015a6ef6SSaurabh Misra #include <sys/types.h>
57015a6ef6SSaurabh Misra #include <sys/stream.h>
58015a6ef6SSaurabh Misra #include <sys/strsun.h>
59015a6ef6SSaurabh Misra #include <sys/stat.h>
60015a6ef6SSaurabh Misra #include <sys/modctl.h>
61015a6ef6SSaurabh Misra #include <sys/kstat.h>
62015a6ef6SSaurabh Misra #include <sys/ethernet.h>
63015a6ef6SSaurabh Misra #include <sys/devops.h>
64015a6ef6SSaurabh Misra #include <sys/debug.h>
65015a6ef6SSaurabh Misra #include <sys/conf.h>
66015a6ef6SSaurabh Misra #include <sys/mii.h>
67015a6ef6SSaurabh Misra #include <sys/miiregs.h>
68015a6ef6SSaurabh Misra #include <sys/mac.h>
69015a6ef6SSaurabh Misra #include <sys/mac_provider.h>
70015a6ef6SSaurabh Misra #include <sys/mac_ether.h>
71015a6ef6SSaurabh Misra #include <sys/sysmacros.h>
72015a6ef6SSaurabh Misra #include <sys/dditypes.h>
73015a6ef6SSaurabh Misra #include <sys/ddi.h>
74015a6ef6SSaurabh Misra #include <sys/sunddi.h>
75015a6ef6SSaurabh Misra #include <sys/byteorder.h>
76015a6ef6SSaurabh Misra #include <sys/note.h>
77015a6ef6SSaurabh Misra #include <sys/vlan.h>
78015a6ef6SSaurabh Misra #include <sys/strsubr.h>
79015a6ef6SSaurabh Misra #include <sys/crc32.h>
80015a6ef6SSaurabh Misra #include <sys/sdt.h>
81015a6ef6SSaurabh Misra #include <sys/pci.h>
82015a6ef6SSaurabh Misra #include <sys/pci_cap.h>
83015a6ef6SSaurabh Misra 
84015a6ef6SSaurabh Misra #include "atge.h"
85015a6ef6SSaurabh Misra #include "atge_cmn_reg.h"
865e8715b9SGary Mills #include "atge_l1c_reg.h"
87015a6ef6SSaurabh Misra #include "atge_l1e_reg.h"
880eb090a7SSaurabh Misra #include "atge_l1_reg.h"
89015a6ef6SSaurabh Misra 
90015a6ef6SSaurabh Misra 
91015a6ef6SSaurabh Misra /*
925e8715b9SGary Mills  * Atheros/Attansic Ethernet chips are of four types - L1, L2, L1E and L1C.
935e8715b9SGary Mills  * This driver is for L1E/L1/L1C but can be extended to support other chips.
940eb090a7SSaurabh Misra  * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
955e8715b9SGary Mills  * flavors only.  L1C comes in both flavours.
96015a6ef6SSaurabh Misra  *
97015a6ef6SSaurabh Misra  * Atheros/Attansic Ethernet controllers have descriptor based TX and RX
98015a6ef6SSaurabh Misra  * with an exception of L1E. L1E's RX side is not descriptor based ring.
99015a6ef6SSaurabh Misra  * The L1E's RX uses pages (not to be confused with MMU pages) for
100015a6ef6SSaurabh Misra  * receiving pkts. The header has four fields :
101015a6ef6SSaurabh Misra  *
102015a6ef6SSaurabh Misra  *        uint32_t seqno;    Sequence number of the frame.
103015a6ef6SSaurabh Misra  *        uint32_t length;   Length of the frame.
104015a6ef6SSaurabh Misra  *        uint32_t flags;    Flags
105015a6ef6SSaurabh Misra  *        uint32_t vtag;     We don't use hardware VTAG.
106015a6ef6SSaurabh Misra  *
107015a6ef6SSaurabh Misra  * We use only one queue for RX (each queue can have two pages) and each
108015a6ef6SSaurabh Misra  * page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't
109015a6ef6SSaurabh Misra  * use zero-copy RX because we are limited to two pages and each page
110015a6ef6SSaurabh Misra  * accomodates large number of pkts.
111015a6ef6SSaurabh Misra  *
112015a6ef6SSaurabh Misra  * The TX side on all three chips is descriptor based ring; and all the
113015a6ef6SSaurabh Misra  * more reason to have one driver for these chips.
114015a6ef6SSaurabh Misra  *
115015a6ef6SSaurabh Misra  * We use two locks - atge_intr_lock and atge_tx_lock. Both the locks
116015a6ef6SSaurabh Misra  * should be held if the operation has impact on the driver instance.
117015a6ef6SSaurabh Misra  *
118015a6ef6SSaurabh Misra  * All the three chips have hash-based multicast filter.
119015a6ef6SSaurabh Misra  *
120015a6ef6SSaurabh Misra  * We use CMB (Coalescing Message Block) for RX but not for TX as there
121015a6ef6SSaurabh Misra  * are some issues with TX. RX CMB is used to get the last descriptor
122015a6ef6SSaurabh Misra  * posted by the chip. Each CMB is for a RX page (one queue can have two
123015a6ef6SSaurabh Misra  * pages) and are uint32_t (4 bytes) long.
124015a6ef6SSaurabh Misra  *
125015a6ef6SSaurabh Misra  * The descriptor table should have 32-bit physical address limit due to
126015a6ef6SSaurabh Misra  * the limitation of having same high address for TX/RX/SMB/CMB. The
127015a6ef6SSaurabh Misra  * TX/RX buffers can be 64-bit.
128015a6ef6SSaurabh Misra  *
129015a6ef6SSaurabh Misra  * Every DMA memory in atge is represented by atge_dma_t be it TX/RX Buffers
130015a6ef6SSaurabh Misra  * or TX/RX descriptor table or SMB/CMB. To keep the code simple, we have
131015a6ef6SSaurabh Misra  * kept sgl as 1 so that we get contingous pages from root complex.
1320eb090a7SSaurabh Misra  *
1330eb090a7SSaurabh Misra  * L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are
1340eb090a7SSaurabh Misra  * common with L1E chip (0x1026).
135015a6ef6SSaurabh Misra  */
136015a6ef6SSaurabh Misra 
137015a6ef6SSaurabh Misra /*
138015a6ef6SSaurabh Misra  * Function Prototypes for debugging.
139015a6ef6SSaurabh Misra  */
140015a6ef6SSaurabh Misra void	atge_error(dev_info_t *, char *, ...);
141015a6ef6SSaurabh Misra void	atge_debug_func(char *, ...);
142015a6ef6SSaurabh Misra 
143015a6ef6SSaurabh Misra /*
144015a6ef6SSaurabh Misra  * Function Prototypes for driver operations.
145015a6ef6SSaurabh Misra  */
146015a6ef6SSaurabh Misra static int	atge_resume(dev_info_t *);
147015a6ef6SSaurabh Misra static int	atge_add_intr(atge_t *);
148015a6ef6SSaurabh Misra static int	atge_alloc_dma(atge_t *);
149015a6ef6SSaurabh Misra static void	atge_remove_intr(atge_t *);
150015a6ef6SSaurabh Misra static void	atge_free_dma(atge_t *);
151015a6ef6SSaurabh Misra static void	atge_device_reset(atge_t *);
152015a6ef6SSaurabh Misra static void	atge_device_init(atge_t *);
153015a6ef6SSaurabh Misra static void	atge_device_start(atge_t *);
154015a6ef6SSaurabh Misra static void	atge_disable_intrs(atge_t *);
155015a6ef6SSaurabh Misra atge_dma_t *atge_alloc_a_dma_blk(atge_t *, ddi_dma_attr_t *, int, int);
156015a6ef6SSaurabh Misra void	atge_free_a_dma_blk(atge_dma_t *);
157015a6ef6SSaurabh Misra static void	atge_rxfilter(atge_t *);
158015a6ef6SSaurabh Misra static void	atge_device_reset_l1_l1e(atge_t *);
159015a6ef6SSaurabh Misra void	atge_program_ether(atge_t *atgep);
160015a6ef6SSaurabh Misra void	atge_device_restart(atge_t *);
1610eb090a7SSaurabh Misra void	atge_device_stop(atge_t *);
162015a6ef6SSaurabh Misra static int	atge_send_a_packet(atge_t *, mblk_t *);
163015a6ef6SSaurabh Misra static uint32_t	atge_ether_crc(const uint8_t *, int);
164015a6ef6SSaurabh Misra 
165015a6ef6SSaurabh Misra 
166015a6ef6SSaurabh Misra /*
1670eb090a7SSaurabh Misra  * L1E/L2E specific functions.
168015a6ef6SSaurabh Misra  */
169015a6ef6SSaurabh Misra void	atge_l1e_device_reset(atge_t *);
170015a6ef6SSaurabh Misra void	atge_l1e_stop_mac(atge_t *);
171015a6ef6SSaurabh Misra int	atge_l1e_alloc_dma(atge_t *);
172015a6ef6SSaurabh Misra void	atge_l1e_free_dma(atge_t *);
173015a6ef6SSaurabh Misra void	atge_l1e_init_tx_ring(atge_t *);
174015a6ef6SSaurabh Misra void	atge_l1e_init_rx_pages(atge_t *);
175015a6ef6SSaurabh Misra void	atge_l1e_program_dma(atge_t *);
1760eb090a7SSaurabh Misra void	atge_l1e_send_packet(atge_ring_t *);
177015a6ef6SSaurabh Misra mblk_t	*atge_l1e_receive(atge_t *);
1780eb090a7SSaurabh Misra uint_t	atge_l1e_interrupt(caddr_t, caddr_t);
179015a6ef6SSaurabh Misra void	atge_l1e_gather_stats(atge_t *);
180015a6ef6SSaurabh Misra void	atge_l1e_clear_stats(atge_t *);
181015a6ef6SSaurabh Misra 
1820eb090a7SSaurabh Misra /*
1830eb090a7SSaurabh Misra  * L1 specific functions.
1840eb090a7SSaurabh Misra  */
1850eb090a7SSaurabh Misra int	atge_l1_alloc_dma(atge_t *);
1865e8715b9SGary Mills void	atge_l1_free_dma(atge_t *);
1870eb090a7SSaurabh Misra void	atge_l1_init_tx_ring(atge_t *);
1880eb090a7SSaurabh Misra void	atge_l1_init_rx_ring(atge_t *);
1890eb090a7SSaurabh Misra void	atge_l1_init_rr_ring(atge_t *);
1900eb090a7SSaurabh Misra void	atge_l1_init_cmb(atge_t *);
1910eb090a7SSaurabh Misra void	atge_l1_init_smb(atge_t *);
1920eb090a7SSaurabh Misra void	atge_l1_program_dma(atge_t *);
1930eb090a7SSaurabh Misra void	atge_l1_stop_tx_mac(atge_t *);
1940eb090a7SSaurabh Misra void	atge_l1_stop_rx_mac(atge_t *);
1950eb090a7SSaurabh Misra uint_t	atge_l1_interrupt(caddr_t, caddr_t);
1960eb090a7SSaurabh Misra void	atge_l1_send_packet(atge_ring_t *);
1970eb090a7SSaurabh Misra 
1985e8715b9SGary Mills /*
1995e8715b9SGary Mills  * L1C specific functions.
2005e8715b9SGary Mills  */
2015e8715b9SGary Mills int	atge_l1c_alloc_dma(atge_t *);
2025e8715b9SGary Mills void	atge_l1c_free_dma(atge_t *);
2035e8715b9SGary Mills void	atge_l1c_init_tx_ring(atge_t *);
2045e8715b9SGary Mills void	atge_l1c_init_rx_ring(atge_t *);
2055e8715b9SGary Mills void	atge_l1c_init_rr_ring(atge_t *);
2065e8715b9SGary Mills void	atge_l1c_init_cmb(atge_t *);
2075e8715b9SGary Mills void	atge_l1c_init_smb(atge_t *);
2085e8715b9SGary Mills void	atge_l1c_program_dma(atge_t *);
2095e8715b9SGary Mills void	atge_l1c_stop_tx_mac(atge_t *);
2105e8715b9SGary Mills void	atge_l1c_stop_rx_mac(atge_t *);
2115e8715b9SGary Mills uint_t	atge_l1c_interrupt(caddr_t, caddr_t);
2125e8715b9SGary Mills void	atge_l1c_send_packet(atge_ring_t *);
2135e8715b9SGary Mills void	atge_l1c_gather_stats(atge_t *);
2145e8715b9SGary Mills void	atge_l1c_clear_stats(atge_t *);
2150eb090a7SSaurabh Misra 
216015a6ef6SSaurabh Misra /*
217015a6ef6SSaurabh Misra  * Function prototyps for MII operations.
218015a6ef6SSaurabh Misra  */
219015a6ef6SSaurabh Misra uint16_t	atge_mii_read(void *, uint8_t, uint8_t);
220015a6ef6SSaurabh Misra void	atge_mii_write(void *, uint8_t, uint8_t, uint16_t);
2215e8715b9SGary Mills uint16_t	atge_l1c_mii_read(void *, uint8_t, uint8_t);
2225e8715b9SGary Mills void	atge_l1c_mii_write(void *, uint8_t, uint8_t, uint16_t);
223015a6ef6SSaurabh Misra void	atge_l1e_mii_reset(void *);
2240eb090a7SSaurabh Misra void	atge_l1_mii_reset(void *);
2255e8715b9SGary Mills void	atge_l1c_mii_reset(void *);
226015a6ef6SSaurabh Misra static void	atge_mii_notify(void *, link_state_t);
2270eb090a7SSaurabh Misra void	atge_tx_reclaim(atge_t *atgep, int cons);
228015a6ef6SSaurabh Misra 
2290eb090a7SSaurabh Misra /*
2300eb090a7SSaurabh Misra  * L1E/L2E chip.
2310eb090a7SSaurabh Misra  */
232015a6ef6SSaurabh Misra static	mii_ops_t atge_l1e_mii_ops = {
233015a6ef6SSaurabh Misra 	MII_OPS_VERSION,
234015a6ef6SSaurabh Misra 	atge_mii_read,
235015a6ef6SSaurabh Misra 	atge_mii_write,
236015a6ef6SSaurabh Misra 	atge_mii_notify,
237015a6ef6SSaurabh Misra 	atge_l1e_mii_reset
238015a6ef6SSaurabh Misra };
239015a6ef6SSaurabh Misra 
2400eb090a7SSaurabh Misra /*
2410eb090a7SSaurabh Misra  * L1 chip.
2420eb090a7SSaurabh Misra  */
2430eb090a7SSaurabh Misra static	mii_ops_t atge_l1_mii_ops = {
2440eb090a7SSaurabh Misra 	MII_OPS_VERSION,
2450eb090a7SSaurabh Misra 	atge_mii_read,
2460eb090a7SSaurabh Misra 	atge_mii_write,
2470eb090a7SSaurabh Misra 	atge_mii_notify,
2480eb090a7SSaurabh Misra 	atge_l1_mii_reset
2490eb090a7SSaurabh Misra };
2500eb090a7SSaurabh Misra 
2515e8715b9SGary Mills /*
2525e8715b9SGary Mills  * L1C chip.
2535e8715b9SGary Mills  */
2545e8715b9SGary Mills static	mii_ops_t atge_l1c_mii_ops = {
2555e8715b9SGary Mills 	MII_OPS_VERSION,
2565e8715b9SGary Mills 	atge_l1c_mii_read,
2575e8715b9SGary Mills 	atge_l1c_mii_write,
2585e8715b9SGary Mills 	atge_mii_notify,
2595e8715b9SGary Mills 	NULL
2605e8715b9SGary Mills };
2615e8715b9SGary Mills 
262015a6ef6SSaurabh Misra /*
263015a6ef6SSaurabh Misra  * Function Prototypes for MAC callbacks.
264015a6ef6SSaurabh Misra  */
265015a6ef6SSaurabh Misra static int	atge_m_stat(void *, uint_t, uint64_t *);
266015a6ef6SSaurabh Misra static int	atge_m_start(void *);
267015a6ef6SSaurabh Misra static void	atge_m_stop(void *);
268015a6ef6SSaurabh Misra static int	atge_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
2690dc2366fSVenugopal Iyer     void *);
270015a6ef6SSaurabh Misra static int	atge_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
271015a6ef6SSaurabh Misra     const void *);
2720dc2366fSVenugopal Iyer static void	atge_m_propinfo(void *, const char *, mac_prop_id_t,
2730dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
274015a6ef6SSaurabh Misra static int	atge_m_unicst(void *, const uint8_t *);
275015a6ef6SSaurabh Misra static int	atge_m_multicst(void *, boolean_t, const uint8_t *);
276015a6ef6SSaurabh Misra static int	atge_m_promisc(void *, boolean_t);
277015a6ef6SSaurabh Misra static mblk_t	*atge_m_tx(void *, mblk_t *);
278015a6ef6SSaurabh Misra 
279015a6ef6SSaurabh Misra static	mac_callbacks_t	atge_m_callbacks = {
2800dc2366fSVenugopal Iyer 	MC_SETPROP | MC_GETPROP | MC_PROPINFO,
281015a6ef6SSaurabh Misra 	atge_m_stat,
282015a6ef6SSaurabh Misra 	atge_m_start,
283015a6ef6SSaurabh Misra 	atge_m_stop,
284015a6ef6SSaurabh Misra 	atge_m_promisc,
285015a6ef6SSaurabh Misra 	atge_m_multicst,
286015a6ef6SSaurabh Misra 	atge_m_unicst,
287015a6ef6SSaurabh Misra 	atge_m_tx,
2880dc2366fSVenugopal Iyer 	NULL,		/* mc_reserved */
289015a6ef6SSaurabh Misra 	NULL,		/* mc_ioctl */
290015a6ef6SSaurabh Misra 	NULL,		/* mc_getcapab */
291015a6ef6SSaurabh Misra 	NULL,		/* mc_open */
292015a6ef6SSaurabh Misra 	NULL,		/* mc_close */
293015a6ef6SSaurabh Misra 	atge_m_setprop,
294015a6ef6SSaurabh Misra 	atge_m_getprop,
2950dc2366fSVenugopal Iyer 	atge_m_propinfo
296015a6ef6SSaurabh Misra };
297015a6ef6SSaurabh Misra 
298015a6ef6SSaurabh Misra /*
299015a6ef6SSaurabh Misra  * DMA Data access requirements.
300015a6ef6SSaurabh Misra  */
301015a6ef6SSaurabh Misra static struct ddi_device_acc_attr atge_dev_attr = {
302015a6ef6SSaurabh Misra 	DDI_DEVICE_ATTR_V0,
303015a6ef6SSaurabh Misra 	DDI_STRUCTURE_LE_ACC,
304015a6ef6SSaurabh Misra 	DDI_STRICTORDER_ACC
305015a6ef6SSaurabh Misra };
306015a6ef6SSaurabh Misra 
307015a6ef6SSaurabh Misra /*
308015a6ef6SSaurabh Misra  * Buffers should be native endianness.
309015a6ef6SSaurabh Misra  */
310015a6ef6SSaurabh Misra static struct ddi_device_acc_attr atge_buf_attr = {
311015a6ef6SSaurabh Misra 	DDI_DEVICE_ATTR_V0,
312015a6ef6SSaurabh Misra 	DDI_NEVERSWAP_ACC,	/* native endianness */
313015a6ef6SSaurabh Misra 	DDI_STRICTORDER_ACC
314015a6ef6SSaurabh Misra };
315015a6ef6SSaurabh Misra 
316015a6ef6SSaurabh Misra /*
3170eb090a7SSaurabh Misra  * DMA device attributes. Buffer can be 64-bit.
318015a6ef6SSaurabh Misra  */
319015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_dma_attr_buf = {
320015a6ef6SSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
321015a6ef6SSaurabh Misra 	0,			/* dma_attr_addr_lo */
322015a6ef6SSaurabh Misra 	0x00ffffffffffull,	/* dma_attr_addr_hi */
323015a6ef6SSaurabh Misra 	0x000000003fffull,	/* dma_attr_count_max */
324015a6ef6SSaurabh Misra 	8,			/* dma_attr_align */
325015a6ef6SSaurabh Misra 	0x00003ffc,		/* dma_attr_burstsizes */
326015a6ef6SSaurabh Misra 	1,			/* dma_attr_minxfer */
327015a6ef6SSaurabh Misra 	0x0000000027ffull,	/* dma_attr_maxxfer */
328015a6ef6SSaurabh Misra 	0x0000ffffffffull,	/* dma_attr_seg */
329015a6ef6SSaurabh Misra 	1,			/* dma_attr_sgllen */
330015a6ef6SSaurabh Misra 	1,			/* dma_attr_granular */
331015a6ef6SSaurabh Misra 	0			/* dma_attr_flags */
332015a6ef6SSaurabh Misra };
333015a6ef6SSaurabh Misra 
334015a6ef6SSaurabh Misra /*
335015a6ef6SSaurabh Misra  * Table of supported devices.
336015a6ef6SSaurabh Misra  */
337015a6ef6SSaurabh Misra #define	ATGE_VENDOR_ID	0x1969
3385e8715b9SGary Mills #define	ATGE_L1_STR	"Attansic L1"
3395e8715b9SGary Mills #define	ATGE_L1CG_STR	"Atheros AR8131 Gigabit Ethernet"
3405e8715b9SGary Mills #define	ATGE_L1CF_STR	"Atheros AR8132 Fast Ethernet"
341015a6ef6SSaurabh Misra #define	ATGE_L1E_STR	"Atheros AR8121/8113/8114"
3425e8715b9SGary Mills #define	ATGE_AR8151V1_STR	"Atheros AR8151 v1.0 Gigabit Ethernet"
3435e8715b9SGary Mills #define	ATGE_AR8151V2_STR	"Atheros AR8151 v2.0 Gigabit Ethernet"
3445e8715b9SGary Mills #define	ATGE_AR8152V1_STR	"Atheros AR8152 v1.1 Fast Ethernet"
3455e8715b9SGary Mills #define	ATGE_AR8152V2_STR	"Atheros AR8152 v2.0 Fast Ethernet"
346015a6ef6SSaurabh Misra 
347015a6ef6SSaurabh Misra static atge_cards_t atge_cards[] = {
3485e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_AR8151V2_DEV_ID, ATGE_AR8151V2_STR,
3495e8715b9SGary Mills 	    ATGE_CHIP_L1C},
3505e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_AR8151V1_DEV_ID, ATGE_AR8151V1_STR,
3515e8715b9SGary Mills 	    ATGE_CHIP_L1C},
3525e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_AR8152V2_DEV_ID, ATGE_AR8152V2_STR,
3535e8715b9SGary Mills 	    ATGE_CHIP_L1C},
3545e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_AR8152V1_DEV_ID, ATGE_AR8152V1_STR,
3555e8715b9SGary Mills 	    ATGE_CHIP_L1C},
3565e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_L1CG_DEV_ID, ATGE_L1CG_STR, ATGE_CHIP_L1C},
3575e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_L1CF_DEV_ID, ATGE_L1CF_STR, ATGE_CHIP_L1C},
358015a6ef6SSaurabh Misra 	{ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E},
3595e8715b9SGary Mills 	{ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, ATGE_L1_STR, ATGE_CHIP_L1},
360015a6ef6SSaurabh Misra };
361015a6ef6SSaurabh Misra 
362015a6ef6SSaurabh Misra /*
363015a6ef6SSaurabh Misra  * Global Debugging flag. Developer level debugging is done only in DEBUG mode.
364015a6ef6SSaurabh Misra  */
365015a6ef6SSaurabh Misra int	atge_debug = 1;
366015a6ef6SSaurabh Misra 
367015a6ef6SSaurabh Misra /*
368015a6ef6SSaurabh Misra  * Debugging and error reporting.
369015a6ef6SSaurabh Misra  */
370015a6ef6SSaurabh Misra void
atge_debug_func(char * fmt,...)371015a6ef6SSaurabh Misra atge_debug_func(char *fmt, ...)
372015a6ef6SSaurabh Misra {
373015a6ef6SSaurabh Misra 	va_list	ap;
374015a6ef6SSaurabh Misra 	char	buf[256];
375015a6ef6SSaurabh Misra 
376015a6ef6SSaurabh Misra 	va_start(ap, fmt);
377015a6ef6SSaurabh Misra 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
378015a6ef6SSaurabh Misra 	va_end(ap);
379015a6ef6SSaurabh Misra 
380015a6ef6SSaurabh Misra 	DTRACE_PROBE1(atge__debug, char *, buf);
381015a6ef6SSaurabh Misra }
382015a6ef6SSaurabh Misra 
3835e8715b9SGary Mills static
384015a6ef6SSaurabh Misra void
atge_message(dev_info_t * dip,int level,char * fmt,va_list ap)3855e8715b9SGary Mills atge_message(dev_info_t *dip, int level, char *fmt, va_list ap)
386015a6ef6SSaurabh Misra {
387015a6ef6SSaurabh Misra 	char	buf[256];
3885e8715b9SGary Mills 	char	*p = "!%s%d: %s";
3895e8715b9SGary Mills 	char	*q = "!atge: %s";
390015a6ef6SSaurabh Misra 
391015a6ef6SSaurabh Misra 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
3925e8715b9SGary Mills 
3935e8715b9SGary Mills 	if (level != CE_NOTE) {
3945e8715b9SGary Mills 		p++;
3955e8715b9SGary Mills 		q++;
3965e8715b9SGary Mills 	}
397015a6ef6SSaurabh Misra 
398015a6ef6SSaurabh Misra 	if (dip) {
3995e8715b9SGary Mills 		cmn_err(level, p,
400015a6ef6SSaurabh Misra 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
401015a6ef6SSaurabh Misra 	} else {
4025e8715b9SGary Mills 		cmn_err(level, q, buf);
403015a6ef6SSaurabh Misra 	}
404015a6ef6SSaurabh Misra }
405015a6ef6SSaurabh Misra 
4065e8715b9SGary Mills void
atge_notice(dev_info_t * dip,char * fmt,...)4075e8715b9SGary Mills atge_notice(dev_info_t *dip, char *fmt, ...)
4085e8715b9SGary Mills {
4095e8715b9SGary Mills 	va_list	ap;
4105e8715b9SGary Mills 
4115e8715b9SGary Mills 	va_start(ap, fmt);
4125e8715b9SGary Mills 	(void) atge_message(dip, CE_NOTE, fmt, ap);
4135e8715b9SGary Mills 	va_end(ap);
4145e8715b9SGary Mills }
4155e8715b9SGary Mills 
4165e8715b9SGary Mills void
atge_error(dev_info_t * dip,char * fmt,...)4175e8715b9SGary Mills atge_error(dev_info_t *dip, char *fmt, ...)
4185e8715b9SGary Mills {
4195e8715b9SGary Mills 	va_list	ap;
4205e8715b9SGary Mills 
4215e8715b9SGary Mills 	va_start(ap, fmt);
4225e8715b9SGary Mills 	(void) atge_message(dip, CE_WARN, fmt, ap);
4235e8715b9SGary Mills 	va_end(ap);
4245e8715b9SGary Mills }
4255e8715b9SGary Mills 
426015a6ef6SSaurabh Misra void
atge_mac_config(atge_t * atgep)427015a6ef6SSaurabh Misra atge_mac_config(atge_t *atgep)
428015a6ef6SSaurabh Misra {
429015a6ef6SSaurabh Misra 	uint32_t reg;
430015a6ef6SSaurabh Misra 	int speed;
431015a6ef6SSaurabh Misra 	link_duplex_t ld;
432015a6ef6SSaurabh Misra 
4335e8715b9SGary Mills 	/* Re-enable TX/RX MACs */
434015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_MAC_CFG);
435015a6ef6SSaurabh Misra 	reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC |
436015a6ef6SSaurabh Misra 	    ATGE_CFG_SPEED_MASK);
437015a6ef6SSaurabh Misra 
4385e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
4395e8715b9SGary Mills 	case ATGE_CHIP_L1C:
4405e8715b9SGary Mills 		switch (ATGE_DID(atgep)) {
4415e8715b9SGary Mills 		case ATGE_CHIP_AR8151V2_DEV_ID:
4425e8715b9SGary Mills 		case ATGE_CHIP_AR8151V1_DEV_ID:
4435e8715b9SGary Mills 		case ATGE_CHIP_AR8152V2_DEV_ID:
4445e8715b9SGary Mills 			reg |= ATGE_CFG_HASH_ALG_CRC32 | ATGE_CFG_SPEED_MODE_SW;
4455e8715b9SGary Mills 			break;
4465e8715b9SGary Mills 		}
4475e8715b9SGary Mills 		break;
4485e8715b9SGary Mills 	}
4495e8715b9SGary Mills 
450015a6ef6SSaurabh Misra 	speed = mii_get_speed(atgep->atge_mii);
451015a6ef6SSaurabh Misra 	switch (speed) {
452015a6ef6SSaurabh Misra 	case 10:
453015a6ef6SSaurabh Misra 	case 100:
454015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_10_100;
455015a6ef6SSaurabh Misra 		break;
456015a6ef6SSaurabh Misra 	case 1000:
457015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_1000;
458015a6ef6SSaurabh Misra 		break;
459015a6ef6SSaurabh Misra 	}
460015a6ef6SSaurabh Misra 
461015a6ef6SSaurabh Misra 	ld = mii_get_duplex(atgep->atge_mii);
462015a6ef6SSaurabh Misra 	if (ld == LINK_DUPLEX_FULL)
463015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_FULL_DUPLEX;
464015a6ef6SSaurabh Misra 
465015a6ef6SSaurabh Misra 	/* Re-enable TX/RX MACs */
4665e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
4675e8715b9SGary Mills 	case ATGE_CHIP_L1E:
4680eb090a7SSaurabh Misra 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC;
4695e8715b9SGary Mills 		break;
4705e8715b9SGary Mills 	case ATGE_CHIP_L1:
4715e8715b9SGary Mills 	case ATGE_CHIP_L1C:
4720eb090a7SSaurabh Misra 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
4735e8715b9SGary Mills 		break;
4740eb090a7SSaurabh Misra 	}
4750eb090a7SSaurabh Misra 
476015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAC_CFG, reg);
477015a6ef6SSaurabh Misra 
4785e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
4795e8715b9SGary Mills 	case ATGE_CHIP_L1E:
480015a6ef6SSaurabh Misra 		reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
481015a6ef6SSaurabh Misra 		reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) <<
482015a6ef6SSaurabh Misra 		    IM_TIMER_TX_SHIFT;
483015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_IM_TIMER, reg);
4845e8715b9SGary Mills 		break;
4855e8715b9SGary Mills 	case ATGE_CHIP_L1:
4865e8715b9SGary Mills 		break;
4875e8715b9SGary Mills 	case ATGE_CHIP_L1C:
4885e8715b9SGary Mills 		/* Configure interrupt moderation timer. */
4895e8715b9SGary Mills 		reg = ATGE_USECS(atgep->atge_int_rx_mod) << IM_TIMER_RX_SHIFT;
4905e8715b9SGary Mills 		reg |= ATGE_USECS(atgep->atge_int_tx_mod) << IM_TIMER_TX_SHIFT;
4915e8715b9SGary Mills 		OUTL(atgep, ATGE_IM_TIMER, reg);
4925e8715b9SGary Mills 		/*
4935e8715b9SGary Mills 		 * We don't want to automatic interrupt clear as task queue
4945e8715b9SGary Mills 		 * for the interrupt should know interrupt status.
4955e8715b9SGary Mills 		 */
4965e8715b9SGary Mills 		reg = 0;
4975e8715b9SGary Mills 		if (ATGE_USECS(atgep->atge_int_rx_mod) != 0)
4985e8715b9SGary Mills 			reg |= MASTER_IM_RX_TIMER_ENB;
4995e8715b9SGary Mills 		if (ATGE_USECS(atgep->atge_int_tx_mod) != 0)
5005e8715b9SGary Mills 			reg |= MASTER_IM_TX_TIMER_ENB;
5015e8715b9SGary Mills 		OUTL(atgep, ATGE_MASTER_CFG, reg);
5025e8715b9SGary Mills 		break;
503015a6ef6SSaurabh Misra 	}
504015a6ef6SSaurabh Misra 
505015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mac_cfg is : %x",
506015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, INL(atgep, ATGE_MAC_CFG)));
507015a6ef6SSaurabh Misra }
508015a6ef6SSaurabh Misra 
509015a6ef6SSaurabh Misra static void
atge_mii_notify(void * arg,link_state_t link)510015a6ef6SSaurabh Misra atge_mii_notify(void *arg, link_state_t link)
511015a6ef6SSaurabh Misra {
512015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
513015a6ef6SSaurabh Misra 
514015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x",
515015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, atgep->atge_link_state, link));
516015a6ef6SSaurabh Misra 
517015a6ef6SSaurabh Misra 	mac_link_update(atgep->atge_mh, link);
518015a6ef6SSaurabh Misra 
519015a6ef6SSaurabh Misra 	/*
520015a6ef6SSaurabh Misra 	 * Reconfigure MAC if link status is UP now.
521015a6ef6SSaurabh Misra 	 */
522015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
523015a6ef6SSaurabh Misra 	if (link == LINK_STATE_UP) {
524015a6ef6SSaurabh Misra 		atgep->atge_link_state = LINK_STATE_UP;
5250eb090a7SSaurabh Misra 		atge_mac_config(atgep);
526015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 0;
527015a6ef6SSaurabh Misra 	} else {
528015a6ef6SSaurabh Misra 		atgep->atge_link_state = LINK_STATE_DOWN;
5290eb090a7SSaurabh Misra 		atgep->atge_flags |= ATGE_MII_CHECK;
530015a6ef6SSaurabh Misra 	}
531015a6ef6SSaurabh Misra 
532015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
533015a6ef6SSaurabh Misra 
534015a6ef6SSaurabh Misra 	if (link == LINK_STATE_UP)
535015a6ef6SSaurabh Misra 		mac_tx_update(atgep->atge_mh);
536015a6ef6SSaurabh Misra }
537015a6ef6SSaurabh Misra 
5380eb090a7SSaurabh Misra void
atge_tx_reclaim(atge_t * atgep,int end)5390eb090a7SSaurabh Misra atge_tx_reclaim(atge_t *atgep, int end)
540015a6ef6SSaurabh Misra {
5410eb090a7SSaurabh Misra 	atge_tx_desc_t  *txd;
5420eb090a7SSaurabh Misra 	atge_ring_t *r = atgep->atge_tx_ring;
5430eb090a7SSaurabh Misra 	uchar_t *c;
5440eb090a7SSaurabh Misra 	int start;
545015a6ef6SSaurabh Misra 
5460eb090a7SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
5470eb090a7SSaurabh Misra 	ASSERT(r != NULL);
548015a6ef6SSaurabh Misra 
5490eb090a7SSaurabh Misra 	start = r->r_consumer;
550015a6ef6SSaurabh Misra 
5510eb090a7SSaurabh Misra 	if (start == end)
5520eb090a7SSaurabh Misra 		return;
553015a6ef6SSaurabh Misra 
5540eb090a7SSaurabh Misra 	while (start != end) {
5550eb090a7SSaurabh Misra 		r->r_avail_desc++;
5560eb090a7SSaurabh Misra 		if (r->r_avail_desc > ATGE_TX_RING_CNT) {
557015a6ef6SSaurabh Misra 
558015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
5590eb090a7SSaurabh Misra 			    "Reclaim : TX descriptor error");
560015a6ef6SSaurabh Misra 
5610eb090a7SSaurabh Misra 			if (r->r_avail_desc > (ATGE_TX_RING_CNT + 5)) {
562015a6ef6SSaurabh Misra 				atge_device_stop(atgep);
5630eb090a7SSaurabh Misra 				break;
564015a6ef6SSaurabh Misra 			}
565015a6ef6SSaurabh Misra 		}
566015a6ef6SSaurabh Misra 
5670eb090a7SSaurabh Misra 		c = (uchar_t *)r->r_desc_ring->addr;
5680eb090a7SSaurabh Misra 		c += (sizeof (atge_tx_desc_t) * start);
5690eb090a7SSaurabh Misra 		txd = (atge_tx_desc_t *)c;
570015a6ef6SSaurabh Misra 
5710eb090a7SSaurabh Misra 		/*
5720eb090a7SSaurabh Misra 		 * Clearing TX descriptor helps in debugging some strange
5730eb090a7SSaurabh Misra 		 * problems.
5740eb090a7SSaurabh Misra 		 */
5750eb090a7SSaurabh Misra 		txd->addr = 0;
5760eb090a7SSaurabh Misra 		txd->len = 0;
5770eb090a7SSaurabh Misra 		txd->flags = 0;
578015a6ef6SSaurabh Misra 
5790eb090a7SSaurabh Misra 		ATGE_INC_SLOT(start, ATGE_TX_RING_CNT);
580015a6ef6SSaurabh Misra 	}
581015a6ef6SSaurabh Misra 
5820eb090a7SSaurabh Misra 	atgep->atge_tx_ring->r_consumer = start;
583015a6ef6SSaurabh Misra 
5840eb090a7SSaurabh Misra 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
585015a6ef6SSaurabh Misra }
586015a6ef6SSaurabh Misra 
587015a6ef6SSaurabh Misra /*
588015a6ef6SSaurabh Misra  * Adds interrupt handler depending upon the type of interrupt supported by
589015a6ef6SSaurabh Misra  * the chip.
590015a6ef6SSaurabh Misra  */
591015a6ef6SSaurabh Misra static int
atge_add_intr_handler(atge_t * atgep,int intr_type)592015a6ef6SSaurabh Misra atge_add_intr_handler(atge_t *atgep, int intr_type)
593015a6ef6SSaurabh Misra {
594015a6ef6SSaurabh Misra 	int err;
595015a6ef6SSaurabh Misra 	int count = 0;
596015a6ef6SSaurabh Misra 	int avail = 0;
597015a6ef6SSaurabh Misra 	int i;
598015a6ef6SSaurabh Misra 	int flag;
599015a6ef6SSaurabh Misra 
600015a6ef6SSaurabh Misra 	if (intr_type != DDI_INTR_TYPE_FIXED) {
601015a6ef6SSaurabh Misra 		err = ddi_intr_get_nintrs(atgep->atge_dip, intr_type, &count);
602015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
603015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
604015a6ef6SSaurabh Misra 			    "ddi_intr_get_nintrs failed : %d", err);
6050eb090a7SSaurabh Misra 			return (DDI_FAILURE);
606015a6ef6SSaurabh Misra 		}
607015a6ef6SSaurabh Misra 
608015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() count : %d",
609015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__, count));
610015a6ef6SSaurabh Misra 
611015a6ef6SSaurabh Misra 		err = ddi_intr_get_navail(atgep->atge_dip, intr_type, &avail);
612015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
613015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
614015a6ef6SSaurabh Misra 			    "ddi_intr_get_navail failed : %d", err);
6150eb090a7SSaurabh Misra 			return (DDI_FAILURE);
616015a6ef6SSaurabh Misra 		}
617015a6ef6SSaurabh Misra 
618015a6ef6SSaurabh Misra 		if (avail < count) {
619015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip, "count :%d,"
620015a6ef6SSaurabh Misra 			    " avail : %d", count, avail);
621015a6ef6SSaurabh Misra 		}
622015a6ef6SSaurabh Misra 
623015a6ef6SSaurabh Misra 		flag = DDI_INTR_ALLOC_STRICT;
624015a6ef6SSaurabh Misra 	} else {
625015a6ef6SSaurabh Misra 		/*
626015a6ef6SSaurabh Misra 		 * DDI_INTR_TYPE_FIXED case.
627015a6ef6SSaurabh Misra 		 */
628015a6ef6SSaurabh Misra 		count = 1;
629015a6ef6SSaurabh Misra 		avail = 1;
630015a6ef6SSaurabh Misra 		flag = DDI_INTR_ALLOC_NORMAL;
631015a6ef6SSaurabh Misra 	}
632015a6ef6SSaurabh Misra 
633015a6ef6SSaurabh Misra 	atgep->atge_intr_size = avail * sizeof (ddi_intr_handle_t);
634015a6ef6SSaurabh Misra 	atgep->atge_intr_handle = kmem_zalloc(atgep->atge_intr_size, KM_SLEEP);
635015a6ef6SSaurabh Misra 
636015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d",
637015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, avail, count,
638015a6ef6SSaurabh Misra 	    intr_type));
639015a6ef6SSaurabh Misra 
640015a6ef6SSaurabh Misra 	err = ddi_intr_alloc(atgep->atge_dip, atgep->atge_intr_handle,
641015a6ef6SSaurabh Misra 	    intr_type, 0, avail, &atgep->atge_intr_cnt, flag);
642015a6ef6SSaurabh Misra 
643015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
644015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "ddi_intr_alloc failed : %d", err);
645015a6ef6SSaurabh Misra 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
6460eb090a7SSaurabh Misra 		return (DDI_FAILURE);
647015a6ef6SSaurabh Misra 	}
648015a6ef6SSaurabh Misra 
649015a6ef6SSaurabh Misra 	ATGE_DB(("%s: atge_add_intr_handler() after alloc count"
650015a6ef6SSaurabh Misra 	    " :%d, avail : %d", atgep->atge_name, count, avail));
651015a6ef6SSaurabh Misra 
652015a6ef6SSaurabh Misra 	err = ddi_intr_get_pri(atgep->atge_intr_handle[0],
653015a6ef6SSaurabh Misra 	    &atgep->atge_intr_pri);
654015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
655015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "ddi_intr_get_pri failed:%d", err);
656015a6ef6SSaurabh Misra 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
657015a6ef6SSaurabh Misra 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
658015a6ef6SSaurabh Misra 		}
659015a6ef6SSaurabh Misra 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
660015a6ef6SSaurabh Misra 
6610eb090a7SSaurabh Misra 		return (DDI_FAILURE);
662015a6ef6SSaurabh Misra 	}
663015a6ef6SSaurabh Misra 
664015a6ef6SSaurabh Misra 	/*
665015a6ef6SSaurabh Misra 	 * Add interrupt handler now.
666015a6ef6SSaurabh Misra 	 */
667015a6ef6SSaurabh Misra 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
6685e8715b9SGary Mills 		switch (ATGE_MODEL(atgep)) {
6695e8715b9SGary Mills 		case ATGE_CHIP_L1E:
6700eb090a7SSaurabh Misra 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
6710eb090a7SSaurabh Misra 			    atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i);
6725e8715b9SGary Mills 			break;
6735e8715b9SGary Mills 		case ATGE_CHIP_L1:
6740eb090a7SSaurabh Misra 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
6750eb090a7SSaurabh Misra 			    atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i);
6765e8715b9SGary Mills 			break;
6775e8715b9SGary Mills 		case ATGE_CHIP_L1C:
6785e8715b9SGary Mills 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
6795e8715b9SGary Mills 			    atge_l1c_interrupt, atgep, (caddr_t)(uintptr_t)i);
6805e8715b9SGary Mills 			break;
6810eb090a7SSaurabh Misra 		}
682015a6ef6SSaurabh Misra 
683015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
684015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
685015a6ef6SSaurabh Misra 			    "ddi_intr_add_handler failed : %d", err);
686015a6ef6SSaurabh Misra 
687015a6ef6SSaurabh Misra 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
688015a6ef6SSaurabh Misra 			while (--i >= 0) {
689015a6ef6SSaurabh Misra 				(void) ddi_intr_remove_handler(
690015a6ef6SSaurabh Misra 				    atgep->atge_intr_handle[i]);
691015a6ef6SSaurabh Misra 				(void) ddi_intr_free(
692015a6ef6SSaurabh Misra 				    atgep->atge_intr_handle[i]);
693015a6ef6SSaurabh Misra 			}
694015a6ef6SSaurabh Misra 
695015a6ef6SSaurabh Misra 			kmem_free(atgep->atge_intr_handle,
696015a6ef6SSaurabh Misra 			    atgep->atge_intr_size);
697015a6ef6SSaurabh Misra 
6980eb090a7SSaurabh Misra 			return (DDI_FAILURE);
699015a6ef6SSaurabh Misra 		}
700015a6ef6SSaurabh Misra 	}
701015a6ef6SSaurabh Misra 
702015a6ef6SSaurabh Misra 	err = ddi_intr_get_cap(atgep->atge_intr_handle[0],
703015a6ef6SSaurabh Misra 	    &atgep->atge_intr_cap);
704015a6ef6SSaurabh Misra 
705015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
706015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip,
707015a6ef6SSaurabh Misra 		    "ddi_intr_get_cap failed : %d", err);
708015a6ef6SSaurabh Misra 		atge_remove_intr(atgep);
7090eb090a7SSaurabh Misra 		return (DDI_FAILURE);
710015a6ef6SSaurabh Misra 	}
711015a6ef6SSaurabh Misra 
712015a6ef6SSaurabh Misra 	if (intr_type == DDI_INTR_TYPE_FIXED)
713015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_FIXED_TYPE;
714015a6ef6SSaurabh Misra 	else if (intr_type == DDI_INTR_TYPE_MSI)
715015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_MSI_TYPE;
716015a6ef6SSaurabh Misra 	else if (intr_type == DDI_INTR_TYPE_MSIX)
717015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_MSIX_TYPE;
718015a6ef6SSaurabh Misra 
7190eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
720015a6ef6SSaurabh Misra }
721015a6ef6SSaurabh Misra 
722015a6ef6SSaurabh Misra void
atge_remove_intr(atge_t * atgep)723015a6ef6SSaurabh Misra atge_remove_intr(atge_t *atgep)
724015a6ef6SSaurabh Misra {
725015a6ef6SSaurabh Misra 	int i;
726015a6ef6SSaurabh Misra 	int cap = 0;
727015a6ef6SSaurabh Misra 
728015a6ef6SSaurabh Misra 	if (atgep->atge_intr_handle == NULL)
729015a6ef6SSaurabh Misra 		return;
730015a6ef6SSaurabh Misra 
731015a6ef6SSaurabh Misra 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
732015a6ef6SSaurabh Misra 		(void) ddi_intr_block_disable(atgep->atge_intr_handle,
733015a6ef6SSaurabh Misra 		    atgep->atge_intr_cnt);
734015a6ef6SSaurabh Misra 
735015a6ef6SSaurabh Misra 		cap = 1;
736015a6ef6SSaurabh Misra 	}
737015a6ef6SSaurabh Misra 
738015a6ef6SSaurabh Misra 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
739015a6ef6SSaurabh Misra 		if (cap == 0)
740015a6ef6SSaurabh Misra 			(void) ddi_intr_disable(atgep->atge_intr_handle[i]);
741015a6ef6SSaurabh Misra 
742015a6ef6SSaurabh Misra 		(void) ddi_intr_remove_handler(atgep->atge_intr_handle[i]);
743015a6ef6SSaurabh Misra 		(void) ddi_intr_free(atgep->atge_intr_handle[i]);
744015a6ef6SSaurabh Misra 	}
745015a6ef6SSaurabh Misra 
746015a6ef6SSaurabh Misra 	kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
747015a6ef6SSaurabh Misra }
748015a6ef6SSaurabh Misra 
749015a6ef6SSaurabh Misra int
atge_enable_intrs(atge_t * atgep)750015a6ef6SSaurabh Misra atge_enable_intrs(atge_t *atgep)
751015a6ef6SSaurabh Misra {
752015a6ef6SSaurabh Misra 	int err;
753015a6ef6SSaurabh Misra 	int i;
754015a6ef6SSaurabh Misra 
755015a6ef6SSaurabh Misra 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
756015a6ef6SSaurabh Misra 		/*
757015a6ef6SSaurabh Misra 		 * Do block enable.
758015a6ef6SSaurabh Misra 		 */
759015a6ef6SSaurabh Misra 		err = ddi_intr_block_enable(atgep->atge_intr_handle,
760015a6ef6SSaurabh Misra 		    atgep->atge_intr_cnt);
761015a6ef6SSaurabh Misra 
762015a6ef6SSaurabh Misra 		if (err != DDI_SUCCESS) {
763015a6ef6SSaurabh Misra 			atge_error(atgep->atge_dip,
764015a6ef6SSaurabh Misra 			    "Failed to block enable intrs %d", err);
7650eb090a7SSaurabh Misra 			err = DDI_FAILURE;
766015a6ef6SSaurabh Misra 		} else {
7670eb090a7SSaurabh Misra 			err = DDI_SUCCESS;
768015a6ef6SSaurabh Misra 		}
769015a6ef6SSaurabh Misra 	} else {
770015a6ef6SSaurabh Misra 		/*
771015a6ef6SSaurabh Misra 		 * Call ddi_intr_enable() for MSI non-block enable.
772015a6ef6SSaurabh Misra 		 */
773015a6ef6SSaurabh Misra 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
774015a6ef6SSaurabh Misra 			err = ddi_intr_enable(atgep->atge_intr_handle[i]);
775015a6ef6SSaurabh Misra 			if (err != DDI_SUCCESS) {
776015a6ef6SSaurabh Misra 				atge_error(atgep->atge_dip,
777015a6ef6SSaurabh Misra 				    "Failed to enable intrs on %d with : %d",
778015a6ef6SSaurabh Misra 				    i, err);
779015a6ef6SSaurabh Misra 				break;
780015a6ef6SSaurabh Misra 			}
781015a6ef6SSaurabh Misra 		}
782015a6ef6SSaurabh Misra 
783015a6ef6SSaurabh Misra 		if (err == DDI_SUCCESS)
7840eb090a7SSaurabh Misra 			err = DDI_SUCCESS;
785015a6ef6SSaurabh Misra 		else
7860eb090a7SSaurabh Misra 			err = DDI_FAILURE;
787015a6ef6SSaurabh Misra 	}
788015a6ef6SSaurabh Misra 
789015a6ef6SSaurabh Misra 	return (err);
790015a6ef6SSaurabh Misra }
791015a6ef6SSaurabh Misra 
792015a6ef6SSaurabh Misra /*
793015a6ef6SSaurabh Misra  * Adds interrupt handler depending on the supported interrupt type by the
794015a6ef6SSaurabh Misra  * chip.
795015a6ef6SSaurabh Misra  */
796015a6ef6SSaurabh Misra static int
atge_add_intr(atge_t * atgep)797015a6ef6SSaurabh Misra atge_add_intr(atge_t *atgep)
798015a6ef6SSaurabh Misra {
799015a6ef6SSaurabh Misra 	int	err;
800015a6ef6SSaurabh Misra 
801015a6ef6SSaurabh Misra 	/*
802015a6ef6SSaurabh Misra 	 * Get the supported interrupt types.
803015a6ef6SSaurabh Misra 	 */
804015a6ef6SSaurabh Misra 	err = ddi_intr_get_supported_types(atgep->atge_dip,
805015a6ef6SSaurabh Misra 	    &atgep->atge_intr_types);
806015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
807015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip,
808015a6ef6SSaurabh Misra 		    "ddi_intr_get_supported_types failed : %d", err);
8090eb090a7SSaurabh Misra 		return (DDI_FAILURE);
810015a6ef6SSaurabh Misra 	}
811015a6ef6SSaurabh Misra 
812015a6ef6SSaurabh Misra 	ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d",
813015a6ef6SSaurabh Misra 	    atgep->atge_name, atgep->atge_intr_types));
814015a6ef6SSaurabh Misra 
815015a6ef6SSaurabh Misra 
816015a6ef6SSaurabh Misra 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSIX) {
817015a6ef6SSaurabh Misra 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSIX);
8180eb090a7SSaurabh Misra 		if (err == DDI_SUCCESS) {
819015a6ef6SSaurabh Misra 			ATGE_DB(("%s: Using MSIx for interrupt",
820015a6ef6SSaurabh Misra 			    atgep->atge_name));
821015a6ef6SSaurabh Misra 			return (err);
822015a6ef6SSaurabh Misra 		}
823015a6ef6SSaurabh Misra 	}
824015a6ef6SSaurabh Misra 
825015a6ef6SSaurabh Misra 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSI) {
826015a6ef6SSaurabh Misra 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSI);
8270eb090a7SSaurabh Misra 		if (err == DDI_SUCCESS) {
828015a6ef6SSaurabh Misra 			ATGE_DB(("%s: Using MSI for interrupt",
829015a6ef6SSaurabh Misra 			    atgep->atge_name));
830015a6ef6SSaurabh Misra 			return (err);
831015a6ef6SSaurabh Misra 		}
832015a6ef6SSaurabh Misra 	}
833015a6ef6SSaurabh Misra 
8340eb090a7SSaurabh Misra 	err = DDI_FAILURE;
835015a6ef6SSaurabh Misra 	if (atgep->atge_intr_types & DDI_INTR_TYPE_FIXED) {
836015a6ef6SSaurabh Misra 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_FIXED);
8370eb090a7SSaurabh Misra 		if (err == DDI_SUCCESS) {
838015a6ef6SSaurabh Misra 			ATGE_DB(("%s: Using FIXED type for interrupt",
839015a6ef6SSaurabh Misra 			    atgep->atge_name));
840015a6ef6SSaurabh Misra 			return (err);
841015a6ef6SSaurabh Misra 		}
842015a6ef6SSaurabh Misra 	}
843015a6ef6SSaurabh Misra 
844015a6ef6SSaurabh Misra 	return (err);
845015a6ef6SSaurabh Misra }
846015a6ef6SSaurabh Misra 
847015a6ef6SSaurabh Misra int
atge_identify_hardware(atge_t * atgep)848015a6ef6SSaurabh Misra atge_identify_hardware(atge_t *atgep)
849015a6ef6SSaurabh Misra {
850015a6ef6SSaurabh Misra 	uint16_t vid, did;
851015a6ef6SSaurabh Misra 	int i;
852015a6ef6SSaurabh Misra 
853015a6ef6SSaurabh Misra 	vid = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_VENID);
854015a6ef6SSaurabh Misra 	did = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_DEVID);
855015a6ef6SSaurabh Misra 
856015a6ef6SSaurabh Misra 	atgep->atge_model = 0;
857015a6ef6SSaurabh Misra 	for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) {
858015a6ef6SSaurabh Misra 		if (atge_cards[i].vendor_id == vid &&
859015a6ef6SSaurabh Misra 		    atge_cards[i].device_id == did) {
860015a6ef6SSaurabh Misra 			atgep->atge_model = atge_cards[i].model;
8615e8715b9SGary Mills 			atgep->atge_vid = vid;
8625e8715b9SGary Mills 			atgep->atge_did = did;
863015a6ef6SSaurabh Misra 			atgep->atge_revid =
864015a6ef6SSaurabh Misra 			    pci_config_get8(atgep->atge_conf_handle,
865015a6ef6SSaurabh Misra 			    PCI_CONF_REVID);
8665e8715b9SGary Mills 			atge_notice(atgep->atge_dip, "PCI-ID pci%x,%x,%x: %s",
8675e8715b9SGary Mills 			    vid, did, atgep->atge_revid,
8685e8715b9SGary Mills 			    atge_cards[i].cardname);
869015a6ef6SSaurabh Misra 			ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
870015a6ef6SSaurabh Misra 			    atgep->atge_name, __func__, vid, did,
871015a6ef6SSaurabh Misra 			    atgep->atge_model));
872015a6ef6SSaurabh Misra 
8730eb090a7SSaurabh Misra 			return (DDI_SUCCESS);
874015a6ef6SSaurabh Misra 		}
875015a6ef6SSaurabh Misra 	}
876015a6ef6SSaurabh Misra 
877015a6ef6SSaurabh Misra 	atge_error(atgep->atge_dip, "atge driver is attaching to unknown"
8785e8715b9SGary Mills 	    " pci%x,%x vendor/device-id card", vid, did);
879015a6ef6SSaurabh Misra 
880015a6ef6SSaurabh Misra 	/*
8815e8715b9SGary Mills 	 * Assume it's L1C chip.
882015a6ef6SSaurabh Misra 	 */
8835e8715b9SGary Mills 	atgep->atge_model = ATGE_CHIP_L1C;
8845e8715b9SGary Mills 	atgep->atge_vid = vid;
8855e8715b9SGary Mills 	atgep->atge_did = did;
886015a6ef6SSaurabh Misra 	atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle,
887015a6ef6SSaurabh Misra 	    PCI_CONF_REVID);
888015a6ef6SSaurabh Misra 
889015a6ef6SSaurabh Misra 	/*
890015a6ef6SSaurabh Misra 	 * We will leave the decision to caller.
891015a6ef6SSaurabh Misra 	 */
8920eb090a7SSaurabh Misra 	return (DDI_FAILURE);
893015a6ef6SSaurabh Misra }
894015a6ef6SSaurabh Misra 
895015a6ef6SSaurabh Misra int
atge_get_macaddr(atge_t * atgep)896015a6ef6SSaurabh Misra atge_get_macaddr(atge_t *atgep)
897015a6ef6SSaurabh Misra {
898015a6ef6SSaurabh Misra 	uint32_t reg;
899015a6ef6SSaurabh Misra 
900015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_SPI_CTRL);
901015a6ef6SSaurabh Misra 	if ((reg & SPI_VPD_ENB) != 0) {
902015a6ef6SSaurabh Misra 		/*
903015a6ef6SSaurabh Misra 		 * Get VPD stored in TWSI EEPROM.
904015a6ef6SSaurabh Misra 		 */
905015a6ef6SSaurabh Misra 		reg &= ~SPI_VPD_ENB;
906015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_SPI_CTRL, reg);
907015a6ef6SSaurabh Misra 
908015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s called Get VPD", atgep->atge_name, __func__));
909015a6ef6SSaurabh Misra 	}
910015a6ef6SSaurabh Misra 
911015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[5] = INB(atgep, ATGE_PAR0 + 0);
912015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[4] = INB(atgep, ATGE_PAR0 + 1);
913015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[3] = INB(atgep, ATGE_PAR0 + 2);
914015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[2] = INB(atgep, ATGE_PAR0 + 3);
915015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[1] = INB(atgep, ATGE_PAR1 + 0);
916015a6ef6SSaurabh Misra 	atgep->atge_ether_addr[0] = INB(atgep, ATGE_PAR1 + 1);
917015a6ef6SSaurabh Misra 
918015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x",
919015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__,
920015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[0],
921015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[1],
922015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[2],
923015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[3],
924015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[4],
925015a6ef6SSaurabh Misra 	    atgep->atge_ether_addr[5]));
926015a6ef6SSaurabh Misra 
927015a6ef6SSaurabh Misra 	bcopy(atgep->atge_ether_addr, atgep->atge_dev_addr, ETHERADDRL);
928015a6ef6SSaurabh Misra 
9290eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
930015a6ef6SSaurabh Misra }
931015a6ef6SSaurabh Misra 
932015a6ef6SSaurabh Misra /*
9335e8715b9SGary Mills  * Reset functionality for L1, L1E, and L1C. It's same.
934015a6ef6SSaurabh Misra  */
935015a6ef6SSaurabh Misra static void
atge_device_reset(atge_t * atgep)936015a6ef6SSaurabh Misra atge_device_reset(atge_t *atgep)
937015a6ef6SSaurabh Misra {
9385e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
9395e8715b9SGary Mills 	case ATGE_CHIP_L1E:
9405e8715b9SGary Mills 	case ATGE_CHIP_L1:
9415e8715b9SGary Mills 	case ATGE_CHIP_L1C:
942015a6ef6SSaurabh Misra 		atge_device_reset_l1_l1e(atgep);
9435e8715b9SGary Mills 		break;
9445e8715b9SGary Mills 	}
945015a6ef6SSaurabh Misra }
946015a6ef6SSaurabh Misra 
947015a6ef6SSaurabh Misra void
atge_device_reset_l1_l1e(atge_t * atgep)948015a6ef6SSaurabh Misra atge_device_reset_l1_l1e(atge_t *atgep)
949015a6ef6SSaurabh Misra {
950015a6ef6SSaurabh Misra 	uint32_t reg;
951015a6ef6SSaurabh Misra 	int t;
9525e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
9535e8715b9SGary Mills 	case ATGE_CHIP_L1C:
9545e8715b9SGary Mills 		OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET | 0x40);
9555e8715b9SGary Mills 		break;
9565e8715b9SGary Mills 	default:
9575e8715b9SGary Mills 		OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
9585e8715b9SGary Mills 		break;
9595e8715b9SGary Mills 	}
960015a6ef6SSaurabh Misra 	reg = INL(atgep, ATGE_MASTER_CFG);
961015a6ef6SSaurabh Misra 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
962015a6ef6SSaurabh Misra 		drv_usecwait(10);
963015a6ef6SSaurabh Misra 		reg = INL(atgep, ATGE_MASTER_CFG);
964015a6ef6SSaurabh Misra 		if ((reg & MASTER_RESET) == 0)
965015a6ef6SSaurabh Misra 			break;
966015a6ef6SSaurabh Misra 	}
967015a6ef6SSaurabh Misra 
968015a6ef6SSaurabh Misra 	if (t == 0) {
969015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, " master reset timeout reg : %x",
970015a6ef6SSaurabh Misra 		    reg);
971015a6ef6SSaurabh Misra 	}
972015a6ef6SSaurabh Misra 
973015a6ef6SSaurabh Misra 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
974015a6ef6SSaurabh Misra 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
975015a6ef6SSaurabh Misra 			break;
976015a6ef6SSaurabh Misra 
977015a6ef6SSaurabh Misra 		drv_usecwait(10);
978015a6ef6SSaurabh Misra 	}
979015a6ef6SSaurabh Misra 
980015a6ef6SSaurabh Misra 	if (t == 0) {
981015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "device reset timeout reg : %x",
982015a6ef6SSaurabh Misra 		    reg);
983015a6ef6SSaurabh Misra 	}
984015a6ef6SSaurabh Misra 
9855e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
9865e8715b9SGary Mills 	case ATGE_CHIP_L1E:
9875e8715b9SGary Mills 	case ATGE_CHIP_L1:
9885e8715b9SGary Mills 		/*
9895e8715b9SGary Mills 		 * Initialize PCIe module. These values came from FreeBSD and
9905e8715b9SGary Mills 		 * we don't know the meaning of it.
9915e8715b9SGary Mills 		 */
9925e8715b9SGary Mills 		OUTL(atgep, ATGE_LTSSM_ID_CFG, 0x6500);
9935e8715b9SGary Mills 		reg = INL(atgep, 0x1008) | 0x8000;
9945e8715b9SGary Mills 		OUTL(atgep, 0x1008, reg);
9955e8715b9SGary Mills 		break;
9965e8715b9SGary Mills 	case ATGE_CHIP_L1C:
9975e8715b9SGary Mills 		break;
9985e8715b9SGary Mills 	}
999015a6ef6SSaurabh Misra 
1000015a6ef6SSaurabh Misra 	/*
1001015a6ef6SSaurabh Misra 	 * Get chip revision.
1002015a6ef6SSaurabh Misra 	 */
1003015a6ef6SSaurabh Misra 	atgep->atge_chip_rev = INL(atgep, ATGE_MASTER_CFG) >>
1004015a6ef6SSaurabh Misra 	    MASTER_CHIP_REV_SHIFT;
1005015a6ef6SSaurabh Misra 
1006015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s reset successfully rev : %x", atgep->atge_name,
1007015a6ef6SSaurabh Misra 	    __func__, atgep->atge_chip_rev));
1008015a6ef6SSaurabh Misra }
1009015a6ef6SSaurabh Misra 
1010015a6ef6SSaurabh Misra /*
1011015a6ef6SSaurabh Misra  * DMA allocation for L1 and L1E is bit different since L1E uses RX pages
1012015a6ef6SSaurabh Misra  * instead of descriptor based RX model.
1013015a6ef6SSaurabh Misra  */
1014015a6ef6SSaurabh Misra static int
atge_alloc_dma(atge_t * atgep)1015015a6ef6SSaurabh Misra atge_alloc_dma(atge_t *atgep)
1016015a6ef6SSaurabh Misra {
10170eb090a7SSaurabh Misra 	int err = DDI_FAILURE;
1018015a6ef6SSaurabh Misra 
10195e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
10205e8715b9SGary Mills 	case ATGE_CHIP_L1E:
1021015a6ef6SSaurabh Misra 		err = atge_l1e_alloc_dma(atgep);
10225e8715b9SGary Mills 		break;
10235e8715b9SGary Mills 	case ATGE_CHIP_L1:
10240eb090a7SSaurabh Misra 		err = atge_l1_alloc_dma(atgep);
10255e8715b9SGary Mills 		break;
10265e8715b9SGary Mills 	case ATGE_CHIP_L1C:
10275e8715b9SGary Mills 		err = atge_l1c_alloc_dma(atgep);
10285e8715b9SGary Mills 		break;
1029015a6ef6SSaurabh Misra 	}
1030015a6ef6SSaurabh Misra 
1031015a6ef6SSaurabh Misra 	return (err);
1032015a6ef6SSaurabh Misra }
1033015a6ef6SSaurabh Misra 
1034015a6ef6SSaurabh Misra static void
atge_free_dma(atge_t * atgep)1035015a6ef6SSaurabh Misra atge_free_dma(atge_t *atgep)
1036015a6ef6SSaurabh Misra {
10375e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
10385e8715b9SGary Mills 	case ATGE_CHIP_L1E:
1039015a6ef6SSaurabh Misra 		atge_l1e_free_dma(atgep);
10405e8715b9SGary Mills 		break;
10415e8715b9SGary Mills 	case ATGE_CHIP_L1:
10425e8715b9SGary Mills 		atge_l1_free_dma(atgep);
10435e8715b9SGary Mills 		break;
10445e8715b9SGary Mills 	case ATGE_CHIP_L1C:
10455e8715b9SGary Mills 		atge_l1c_free_dma(atgep);
10465e8715b9SGary Mills 		break;
1047015a6ef6SSaurabh Misra 	}
1048015a6ef6SSaurabh Misra }
1049015a6ef6SSaurabh Misra 
1050015a6ef6SSaurabh Misra /*
1051015a6ef6SSaurabh Misra  * Attach entry point in the driver.
1052015a6ef6SSaurabh Misra  */
1053015a6ef6SSaurabh Misra static int
atge_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)1054015a6ef6SSaurabh Misra atge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
1055015a6ef6SSaurabh Misra {
1056015a6ef6SSaurabh Misra 	atge_t	*atgep;
1057015a6ef6SSaurabh Misra 	mac_register_t	*macreg;
1058015a6ef6SSaurabh Misra 	int	instance;
1059015a6ef6SSaurabh Misra 	uint16_t cap_ptr;
1060015a6ef6SSaurabh Misra 	uint16_t burst;
1061015a6ef6SSaurabh Misra 	int err;
1062015a6ef6SSaurabh Misra 	mii_ops_t *mii_ops;
1063015a6ef6SSaurabh Misra 
1064015a6ef6SSaurabh Misra 	instance =  ddi_get_instance(devinfo);
1065015a6ef6SSaurabh Misra 
1066015a6ef6SSaurabh Misra 	switch (cmd) {
1067015a6ef6SSaurabh Misra 	case DDI_RESUME:
1068015a6ef6SSaurabh Misra 		return (atge_resume(devinfo));
1069015a6ef6SSaurabh Misra 
1070015a6ef6SSaurabh Misra 	case DDI_ATTACH:
1071015a6ef6SSaurabh Misra 		ddi_set_driver_private(devinfo, NULL);
1072015a6ef6SSaurabh Misra 		break;
10735e8715b9SGary Mills 	default:
10745e8715b9SGary Mills 		return (DDI_FAILURE);
10755e8715b9SGary Mills 
1076015a6ef6SSaurabh Misra 	}
1077015a6ef6SSaurabh Misra 
1078015a6ef6SSaurabh Misra 	atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP);
1079015a6ef6SSaurabh Misra 	ddi_set_driver_private(devinfo, atgep);
1080015a6ef6SSaurabh Misra 	atgep->atge_dip = devinfo;
1081015a6ef6SSaurabh Misra 
1082015a6ef6SSaurabh Misra 	/*
1083015a6ef6SSaurabh Misra 	 * Setup name and instance number to be used for debugging and
1084015a6ef6SSaurabh Misra 	 * error reporting.
1085015a6ef6SSaurabh Misra 	 */
1086015a6ef6SSaurabh Misra 	(void) snprintf(atgep->atge_name, sizeof (atgep->atge_name), "%s%d",
1087015a6ef6SSaurabh Misra 	    "atge", instance);
1088015a6ef6SSaurabh Misra 
1089015a6ef6SSaurabh Misra 
1090015a6ef6SSaurabh Misra 	/*
1091015a6ef6SSaurabh Misra 	 * Map PCI config space.
1092015a6ef6SSaurabh Misra 	 */
1093015a6ef6SSaurabh Misra 	err = pci_config_setup(devinfo, &atgep->atge_conf_handle);
1094015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1095015a6ef6SSaurabh Misra 		atge_error(devinfo, "pci_config_setup() failed");
1096015a6ef6SSaurabh Misra 		goto fail1;
1097015a6ef6SSaurabh Misra 	}
1098015a6ef6SSaurabh Misra 
1099015a6ef6SSaurabh Misra 	(void) atge_identify_hardware(atgep);
1100015a6ef6SSaurabh Misra 
1101015a6ef6SSaurabh Misra 	/*
1102015a6ef6SSaurabh Misra 	 * Map Device registers.
1103015a6ef6SSaurabh Misra 	 */
1104015a6ef6SSaurabh Misra 	err = ddi_regs_map_setup(devinfo, ATGE_PCI_REG_NUMBER,
1105015a6ef6SSaurabh Misra 	    &atgep->atge_io_regs, 0, 0, &atge_dev_attr, &atgep->atge_io_handle);
1106015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1107015a6ef6SSaurabh Misra 		atge_error(devinfo, "ddi_regs_map_setup() failed");
1108015a6ef6SSaurabh Misra 		goto fail2;
1109015a6ef6SSaurabh Misra 	}
1110015a6ef6SSaurabh Misra 
1111015a6ef6SSaurabh Misra 	/*
1112015a6ef6SSaurabh Misra 	 * Add interrupt and its associated handler.
1113015a6ef6SSaurabh Misra 	 */
1114015a6ef6SSaurabh Misra 	err = atge_add_intr(atgep);
11150eb090a7SSaurabh Misra 	if (err != DDI_SUCCESS) {
1116015a6ef6SSaurabh Misra 		atge_error(devinfo, "Failed to add interrupt handler");
1117015a6ef6SSaurabh Misra 		goto fail3;
1118015a6ef6SSaurabh Misra 	}
1119015a6ef6SSaurabh Misra 
1120015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_intr_lock, NULL, MUTEX_DRIVER,
1121015a6ef6SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
1122015a6ef6SSaurabh Misra 
1123015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_tx_lock, NULL, MUTEX_DRIVER,
1124015a6ef6SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
1125015a6ef6SSaurabh Misra 
1126015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_rx_lock, NULL, MUTEX_DRIVER,
1127015a6ef6SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
1128015a6ef6SSaurabh Misra 
1129015a6ef6SSaurabh Misra 	mutex_init(&atgep->atge_mii_lock, NULL, MUTEX_DRIVER, NULL);
1130015a6ef6SSaurabh Misra 
11310eb090a7SSaurabh Misra 	/*
11320eb090a7SSaurabh Misra 	 * Used to lock down MBOX register on L1 chip since RX consumer,
11330eb090a7SSaurabh Misra 	 * TX producer and RX return ring consumer are shared.
11340eb090a7SSaurabh Misra 	 */
11350eb090a7SSaurabh Misra 	mutex_init(&atgep->atge_mbox_lock, NULL, MUTEX_DRIVER,
11360eb090a7SSaurabh Misra 	    DDI_INTR_PRI(atgep->atge_intr_pri));
11370eb090a7SSaurabh Misra 
1138015a6ef6SSaurabh Misra 	atgep->atge_link_state = LINK_STATE_DOWN;
1139015a6ef6SSaurabh Misra 	atgep->atge_mtu = ETHERMTU;
1140015a6ef6SSaurabh Misra 
11415e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
11425e8715b9SGary Mills 	case ATGE_CHIP_L1E:
11430eb090a7SSaurabh Misra 		if (atgep->atge_revid > 0xF0) {
11440eb090a7SSaurabh Misra 			/* L2E Rev. B. AR8114 */
1145015a6ef6SSaurabh Misra 			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
11460eb090a7SSaurabh Misra 		} else {
11470eb090a7SSaurabh Misra 			if ((INL(atgep, L1E_PHY_STATUS) &
11480eb090a7SSaurabh Misra 			    PHY_STATUS_100M) != 0) {
11490eb090a7SSaurabh Misra 				/* L1E AR8121 */
11500eb090a7SSaurabh Misra 				atgep->atge_flags |= ATGE_FLAG_JUMBO;
11510eb090a7SSaurabh Misra 			} else {
11520eb090a7SSaurabh Misra 				/* L2E Rev. A. AR8113 */
11530eb090a7SSaurabh Misra 				atgep->atge_flags |= ATGE_FLAG_FASTETHER;
11540eb090a7SSaurabh Misra 			}
1155015a6ef6SSaurabh Misra 		}
11565e8715b9SGary Mills 		break;
11575e8715b9SGary Mills 	case ATGE_CHIP_L1:
11585e8715b9SGary Mills 		break;
11595e8715b9SGary Mills 	case ATGE_CHIP_L1C:
11605e8715b9SGary Mills 		/*
11615e8715b9SGary Mills 		 * One odd thing is AR8132 uses the same PHY hardware(F1
11625e8715b9SGary Mills 		 * gigabit PHY) of AR8131. So atphy(4) of AR8132 reports
11635e8715b9SGary Mills 		 * the PHY supports 1000Mbps but that's not true. The PHY
11645e8715b9SGary Mills 		 * used in AR8132 can't establish gigabit link even if it
11655e8715b9SGary Mills 		 * shows the same PHY model/revision number of AR8131.
11665e8715b9SGary Mills 		 *
11675e8715b9SGary Mills 		 * It seems that AR813x/AR815x has silicon bug for SMB. In
11685e8715b9SGary Mills 		 * addition, Atheros said that enabling SMB wouldn't improve
11695e8715b9SGary Mills 		 * performance. However I think it's bad to access lots of
11705e8715b9SGary Mills 		 * registers to extract MAC statistics.
11715e8715b9SGary Mills 		 *
11725e8715b9SGary Mills 		 * Don't use Tx CMB. It is known to have silicon bug.
11735e8715b9SGary Mills 		 */
11745e8715b9SGary Mills 		switch (ATGE_DID(atgep)) {
11755e8715b9SGary Mills 		case ATGE_CHIP_AR8152V2_DEV_ID:
11765e8715b9SGary Mills 		case ATGE_CHIP_AR8152V1_DEV_ID:
11775e8715b9SGary Mills 			atgep->atge_flags |= ATGE_FLAG_APS |
11785e8715b9SGary Mills 			    ATGE_FLAG_FASTETHER |
11795e8715b9SGary Mills 			    ATGE_FLAG_ASPM_MON | ATGE_FLAG_JUMBO |
11805e8715b9SGary Mills 			    ATGE_FLAG_SMB_BUG | ATGE_FLAG_CMB_BUG;
11815e8715b9SGary Mills 			break;
11825e8715b9SGary Mills 		case ATGE_CHIP_AR8151V2_DEV_ID:
11835e8715b9SGary Mills 		case ATGE_CHIP_AR8151V1_DEV_ID:
11845e8715b9SGary Mills 			atgep->atge_flags |= ATGE_FLAG_APS |
11855e8715b9SGary Mills 			    ATGE_FLAG_ASPM_MON | ATGE_FLAG_JUMBO |
11865e8715b9SGary Mills 			    ATGE_FLAG_SMB_BUG | ATGE_FLAG_CMB_BUG;
11875e8715b9SGary Mills 			break;
11885e8715b9SGary Mills 		case ATGE_CHIP_L1CF_DEV_ID:
11895e8715b9SGary Mills 			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
11905e8715b9SGary Mills 			break;
11915e8715b9SGary Mills 		case ATGE_CHIP_L1CG_DEV_ID:
11925e8715b9SGary Mills 			break;
11935e8715b9SGary Mills 		}
11945e8715b9SGary Mills 		break;
1195015a6ef6SSaurabh Misra 	}
1196015a6ef6SSaurabh Misra 
1197015a6ef6SSaurabh Misra 	/*
1198015a6ef6SSaurabh Misra 	 * Get DMA parameters from PCIe device control register.
1199015a6ef6SSaurabh Misra 	 */
1200015a6ef6SSaurabh Misra 	err = PCI_CAP_LOCATE(atgep->atge_conf_handle, PCI_CAP_ID_PCI_E,
1201015a6ef6SSaurabh Misra 	    &cap_ptr);
1202015a6ef6SSaurabh Misra 
1203015a6ef6SSaurabh Misra 	if (err == DDI_FAILURE) {
1204015a6ef6SSaurabh Misra 		atgep->atge_dma_rd_burst = DMA_CFG_RD_BURST_128;
1205015a6ef6SSaurabh Misra 		atgep->atge_dma_wr_burst = DMA_CFG_WR_BURST_128;
1206015a6ef6SSaurabh Misra 	} else {
1207015a6ef6SSaurabh Misra 		atgep->atge_flags |= ATGE_FLAG_PCIE;
1208015a6ef6SSaurabh Misra 		burst = pci_config_get16(atgep->atge_conf_handle,
1209015a6ef6SSaurabh Misra 		    cap_ptr + 0x08);
1210015a6ef6SSaurabh Misra 
1211015a6ef6SSaurabh Misra 		/*
1212015a6ef6SSaurabh Misra 		 * Max read request size.
1213015a6ef6SSaurabh Misra 		 */
1214015a6ef6SSaurabh Misra 		atgep->atge_dma_rd_burst = ((burst >> 12) & 0x07) <<
1215015a6ef6SSaurabh Misra 		    DMA_CFG_RD_BURST_SHIFT;
1216015a6ef6SSaurabh Misra 
1217015a6ef6SSaurabh Misra 		/*
1218015a6ef6SSaurabh Misra 		 * Max Payload Size.
1219015a6ef6SSaurabh Misra 		 */
1220015a6ef6SSaurabh Misra 		atgep->atge_dma_wr_burst = ((burst >> 5) & 0x07) <<
1221015a6ef6SSaurabh Misra 		    DMA_CFG_WR_BURST_SHIFT;
1222015a6ef6SSaurabh Misra 
1223015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() MRR : %d, MPS : %d",
1224015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__,
1225015a6ef6SSaurabh Misra 		    (128 << ((burst >> 12) & 0x07)),
1226015a6ef6SSaurabh Misra 		    (128 << ((burst >> 5) & 0x07))));
1227015a6ef6SSaurabh Misra 	}
1228015a6ef6SSaurabh Misra 
12295e8715b9SGary Mills 	/* Clear data link and flow-control protocol error. */
12305e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
12315e8715b9SGary Mills 	case ATGE_CHIP_L1E:
12325e8715b9SGary Mills 		break;
12335e8715b9SGary Mills 	case ATGE_CHIP_L1:
12345e8715b9SGary Mills 		break;
12355e8715b9SGary Mills 	case ATGE_CHIP_L1C:
12365e8715b9SGary Mills 		OUTL_AND(atgep, ATGE_PEX_UNC_ERR_SEV,
12375e8715b9SGary Mills 		    ~(PEX_UNC_ERR_SEV_UC | PEX_UNC_ERR_SEV_FCP));
12385e8715b9SGary Mills 		OUTL_AND(atgep, ATGE_LTSSM_ID_CFG, ~LTSSM_ID_WRO_ENB);
12395e8715b9SGary Mills 		OUTL_OR(atgep, ATGE_PCIE_PHYMISC, PCIE_PHYMISC_FORCE_RCV_DET);
12405e8715b9SGary Mills 		break;
12415e8715b9SGary Mills 	}
12425e8715b9SGary Mills 
1243015a6ef6SSaurabh Misra 	/*
1244015a6ef6SSaurabh Misra 	 * Allocate DMA resources.
1245015a6ef6SSaurabh Misra 	 */
1246015a6ef6SSaurabh Misra 	err = atge_alloc_dma(atgep);
12470eb090a7SSaurabh Misra 	if (err != DDI_SUCCESS) {
1248015a6ef6SSaurabh Misra 		atge_error(devinfo, "Failed to allocate DMA resources");
1249015a6ef6SSaurabh Misra 		goto fail4;
1250015a6ef6SSaurabh Misra 	}
1251015a6ef6SSaurabh Misra 
1252015a6ef6SSaurabh Misra 	/*
1253015a6ef6SSaurabh Misra 	 * Get station address.
1254015a6ef6SSaurabh Misra 	 */
1255015a6ef6SSaurabh Misra 	(void) atge_get_macaddr(atgep);
1256015a6ef6SSaurabh Misra 
1257015a6ef6SSaurabh Misra 	/*
1258015a6ef6SSaurabh Misra 	 * Setup MII.
1259015a6ef6SSaurabh Misra 	 */
12605e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
12615e8715b9SGary Mills 	case ATGE_CHIP_L1E:
1262015a6ef6SSaurabh Misra 		mii_ops = &atge_l1e_mii_ops;
12635e8715b9SGary Mills 		break;
12645e8715b9SGary Mills 	case ATGE_CHIP_L1:
12650eb090a7SSaurabh Misra 		mii_ops = &atge_l1_mii_ops;
12665e8715b9SGary Mills 		break;
12675e8715b9SGary Mills 	case ATGE_CHIP_L1C:
12685e8715b9SGary Mills 		mii_ops = &atge_l1c_mii_ops;
12695e8715b9SGary Mills 		break;
1270015a6ef6SSaurabh Misra 	}
1271015a6ef6SSaurabh Misra 
1272015a6ef6SSaurabh Misra 	if ((atgep->atge_mii = mii_alloc(atgep, devinfo,
1273015a6ef6SSaurabh Misra 	    mii_ops)) == NULL) {
1274015a6ef6SSaurabh Misra 		atge_error(devinfo, "mii_alloc() failed");
1275015a6ef6SSaurabh Misra 		goto fail4;
1276015a6ef6SSaurabh Misra 	}
1277015a6ef6SSaurabh Misra 
1278015a6ef6SSaurabh Misra 	/*
1279015a6ef6SSaurabh Misra 	 * Register with MAC layer.
1280015a6ef6SSaurabh Misra 	 */
1281015a6ef6SSaurabh Misra 	if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
1282015a6ef6SSaurabh Misra 		atge_error(devinfo, "mac_alloc() failed due to version");
1283015a6ef6SSaurabh Misra 		goto fail4;
1284015a6ef6SSaurabh Misra 	}
1285015a6ef6SSaurabh Misra 
1286015a6ef6SSaurabh Misra 	macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1287015a6ef6SSaurabh Misra 	macreg->m_driver = atgep;
1288015a6ef6SSaurabh Misra 	macreg->m_dip = devinfo;
1289015a6ef6SSaurabh Misra 	macreg->m_instance = instance;
1290015a6ef6SSaurabh Misra 	macreg->m_src_addr = atgep->atge_ether_addr;
1291015a6ef6SSaurabh Misra 	macreg->m_callbacks = &atge_m_callbacks;
1292015a6ef6SSaurabh Misra 	macreg->m_min_sdu = 0;
1293015a6ef6SSaurabh Misra 	macreg->m_max_sdu = atgep->atge_mtu;
1294015a6ef6SSaurabh Misra 	macreg->m_margin = VLAN_TAGSZ;
1295015a6ef6SSaurabh Misra 
1296015a6ef6SSaurabh Misra 	if ((err = mac_register(macreg, &atgep->atge_mh)) != 0) {
1297015a6ef6SSaurabh Misra 		atge_error(devinfo, "mac_register() failed with :%d", err);
1298015a6ef6SSaurabh Misra 		mac_free(macreg);
1299015a6ef6SSaurabh Misra 		goto fail4;
1300015a6ef6SSaurabh Misra 	}
1301015a6ef6SSaurabh Misra 
1302015a6ef6SSaurabh Misra 	mac_free(macreg);
1303015a6ef6SSaurabh Misra 
1304015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() driver attached successfully",
1305015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__));
1306015a6ef6SSaurabh Misra 
1307015a6ef6SSaurabh Misra 	atge_device_reset(atgep);
1308015a6ef6SSaurabh Misra 
1309015a6ef6SSaurabh Misra 	atgep->atge_chip_state = ATGE_CHIP_INITIALIZED;
1310015a6ef6SSaurabh Misra 
1311015a6ef6SSaurabh Misra 	/*
1312015a6ef6SSaurabh Misra 	 * At last - enable interrupts.
1313015a6ef6SSaurabh Misra 	 */
1314015a6ef6SSaurabh Misra 	err = atge_enable_intrs(atgep);
13150eb090a7SSaurabh Misra 	if (err == DDI_FAILURE) {
1316015a6ef6SSaurabh Misra 		goto fail5;
1317015a6ef6SSaurabh Misra 	}
1318015a6ef6SSaurabh Misra 
1319015a6ef6SSaurabh Misra 	/*
1320015a6ef6SSaurabh Misra 	 * Reset the PHY before starting.
1321015a6ef6SSaurabh Misra 	 */
13225e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
13235e8715b9SGary Mills 	case ATGE_CHIP_L1E:
1324015a6ef6SSaurabh Misra 		atge_l1e_mii_reset(atgep);
13255e8715b9SGary Mills 		break;
13265e8715b9SGary Mills 	case ATGE_CHIP_L1:
13270eb090a7SSaurabh Misra 		atge_l1_mii_reset(atgep);
13285e8715b9SGary Mills 		break;
13295e8715b9SGary Mills 	case ATGE_CHIP_L1C:
13305e8715b9SGary Mills 		atge_l1c_mii_reset(atgep);
13315e8715b9SGary Mills 		break;
1332015a6ef6SSaurabh Misra 	}
1333015a6ef6SSaurabh Misra 
1334015a6ef6SSaurabh Misra 	/*
1335015a6ef6SSaurabh Misra 	 * Let the PHY run.
1336015a6ef6SSaurabh Misra 	 */
1337015a6ef6SSaurabh Misra 	mii_start(atgep->atge_mii);
1338015a6ef6SSaurabh Misra 
1339015a6ef6SSaurabh Misra 	return (DDI_SUCCESS);
1340015a6ef6SSaurabh Misra 
1341015a6ef6SSaurabh Misra fail5:
1342015a6ef6SSaurabh Misra 	(void) mac_unregister(atgep->atge_mh);
1343015a6ef6SSaurabh Misra 	atge_device_stop(atgep);
1344015a6ef6SSaurabh Misra 	mii_stop(atgep->atge_mii);
1345015a6ef6SSaurabh Misra 	mii_free(atgep->atge_mii);
1346015a6ef6SSaurabh Misra fail4:
1347015a6ef6SSaurabh Misra 	atge_free_dma(atgep);
1348015a6ef6SSaurabh Misra 	mutex_destroy(&atgep->atge_intr_lock);
1349015a6ef6SSaurabh Misra 	mutex_destroy(&atgep->atge_tx_lock);
1350015a6ef6SSaurabh Misra 	mutex_destroy(&atgep->atge_rx_lock);
1351015a6ef6SSaurabh Misra 	atge_remove_intr(atgep);
1352015a6ef6SSaurabh Misra fail3:
1353015a6ef6SSaurabh Misra 	ddi_regs_map_free(&atgep->atge_io_handle);
1354015a6ef6SSaurabh Misra fail2:
1355015a6ef6SSaurabh Misra 	pci_config_teardown(&atgep->atge_conf_handle);
1356015a6ef6SSaurabh Misra fail1:
1357*80e3e236SJohn Levon 	kmem_free(atgep, sizeof (atge_t));
1358015a6ef6SSaurabh Misra 	return (DDI_FAILURE);
1359015a6ef6SSaurabh Misra }
1360015a6ef6SSaurabh Misra 
1361015a6ef6SSaurabh Misra static int
atge_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1362015a6ef6SSaurabh Misra atge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1363015a6ef6SSaurabh Misra {
1364015a6ef6SSaurabh Misra 	atge_t	*atgep;
1365015a6ef6SSaurabh Misra 
1366015a6ef6SSaurabh Misra 	atgep = ddi_get_driver_private(dip);
1367015a6ef6SSaurabh Misra 	if (atgep == NULL) {
1368015a6ef6SSaurabh Misra 		atge_error(dip, "No soft state in detach");
1369015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1370015a6ef6SSaurabh Misra 	}
1371015a6ef6SSaurabh Misra 
1372015a6ef6SSaurabh Misra 	switch (cmd) {
1373015a6ef6SSaurabh Misra 	case DDI_DETACH:
1374015a6ef6SSaurabh Misra 
1375015a6ef6SSaurabh Misra 		/*
1376015a6ef6SSaurabh Misra 		 * First unregister with MAC layer before stopping DMA
1377015a6ef6SSaurabh Misra 		 */
13789d8d9e11SGarrett D'Amore 		if (mac_disable(atgep->atge_mh) != DDI_SUCCESS)
1379015a6ef6SSaurabh Misra 			return (DDI_FAILURE);
1380015a6ef6SSaurabh Misra 
13819d8d9e11SGarrett D'Amore 		mii_stop(atgep->atge_mii);
1382015a6ef6SSaurabh Misra 
1383015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_intr_lock);
1384015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_tx_lock);
1385015a6ef6SSaurabh Misra 		atge_device_stop(atgep);
1386015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1387015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
1388015a6ef6SSaurabh Misra 
1389015a6ef6SSaurabh Misra 		mii_free(atgep->atge_mii);
1390015a6ef6SSaurabh Misra 		atge_free_dma(atgep);
1391015a6ef6SSaurabh Misra 
1392015a6ef6SSaurabh Misra 		ddi_regs_map_free(&atgep->atge_io_handle);
1393015a6ef6SSaurabh Misra 		atge_remove_intr(atgep);
1394015a6ef6SSaurabh Misra 		pci_config_teardown(&atgep->atge_conf_handle);
1395015a6ef6SSaurabh Misra 
13969d8d9e11SGarrett D'Amore 		(void) mac_unregister(atgep->atge_mh);
1397015a6ef6SSaurabh Misra 		mutex_destroy(&atgep->atge_intr_lock);
1398015a6ef6SSaurabh Misra 		mutex_destroy(&atgep->atge_tx_lock);
1399015a6ef6SSaurabh Misra 		mutex_destroy(&atgep->atge_rx_lock);
1400015a6ef6SSaurabh Misra 		kmem_free(atgep, sizeof (atge_t));
1401015a6ef6SSaurabh Misra 		ddi_set_driver_private(dip, NULL);
1402015a6ef6SSaurabh Misra 
1403015a6ef6SSaurabh Misra 		return (DDI_SUCCESS);
1404015a6ef6SSaurabh Misra 
1405015a6ef6SSaurabh Misra 	case DDI_SUSPEND:
1406015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() is being suspended",
1407015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__));
1408015a6ef6SSaurabh Misra 
1409015a6ef6SSaurabh Misra 		/*
1410015a6ef6SSaurabh Misra 		 * Suspend monitoring MII.
1411015a6ef6SSaurabh Misra 		 */
1412015a6ef6SSaurabh Misra 		mii_suspend(atgep->atge_mii);
1413015a6ef6SSaurabh Misra 
1414015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_intr_lock);
1415015a6ef6SSaurabh Misra 		mutex_enter(&atgep->atge_tx_lock);
1416015a6ef6SSaurabh Misra 		atgep->atge_chip_state |= ATGE_CHIP_SUSPENDED;
1417015a6ef6SSaurabh Misra 		atge_device_stop(atgep);
1418015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1419015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
1420015a6ef6SSaurabh Misra 
1421015a6ef6SSaurabh Misra 		return (DDI_SUCCESS);
1422015a6ef6SSaurabh Misra 
1423015a6ef6SSaurabh Misra 	default:
1424015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1425015a6ef6SSaurabh Misra 	}
1426015a6ef6SSaurabh Misra }
1427015a6ef6SSaurabh Misra 
1428015a6ef6SSaurabh Misra int
atge_alloc_buffers(atge_ring_t * r,size_t rcnt,size_t buflen,int f)1429015a6ef6SSaurabh Misra atge_alloc_buffers(atge_ring_t *r, size_t rcnt, size_t buflen, int f)
1430015a6ef6SSaurabh Misra {
1431015a6ef6SSaurabh Misra 	atge_dma_t *dma;
1432015a6ef6SSaurabh Misra 	atge_dma_t **tbl;
14330eb090a7SSaurabh Misra 	int err = DDI_SUCCESS;
1434015a6ef6SSaurabh Misra 	int i;
1435015a6ef6SSaurabh Misra 
1436015a6ef6SSaurabh Misra 	tbl = kmem_zalloc(rcnt * sizeof (atge_dma_t *), KM_SLEEP);
1437015a6ef6SSaurabh Misra 	r->r_buf_tbl = tbl;
1438015a6ef6SSaurabh Misra 
1439015a6ef6SSaurabh Misra 	for (i = 0; i < rcnt; i++) {
1440015a6ef6SSaurabh Misra 		dma = atge_buf_alloc(r->r_atge, buflen, f);
1441015a6ef6SSaurabh Misra 		if (dma == NULL) {
14420eb090a7SSaurabh Misra 			err = DDI_FAILURE;
1443015a6ef6SSaurabh Misra 			break;
1444015a6ef6SSaurabh Misra 		}
1445015a6ef6SSaurabh Misra 
1446015a6ef6SSaurabh Misra 		tbl[i] = dma;
1447015a6ef6SSaurabh Misra 	}
1448015a6ef6SSaurabh Misra 
1449015a6ef6SSaurabh Misra 	return (err);
1450015a6ef6SSaurabh Misra }
1451015a6ef6SSaurabh Misra 
1452015a6ef6SSaurabh Misra void
atge_free_buffers(atge_ring_t * r,size_t rcnt)1453015a6ef6SSaurabh Misra atge_free_buffers(atge_ring_t *r, size_t rcnt)
1454015a6ef6SSaurabh Misra {
1455015a6ef6SSaurabh Misra 	atge_dma_t **tbl;
1456015a6ef6SSaurabh Misra 	int i;
1457015a6ef6SSaurabh Misra 
1458015a6ef6SSaurabh Misra 	if (r == NULL || r->r_buf_tbl == NULL)
1459015a6ef6SSaurabh Misra 		return;
1460015a6ef6SSaurabh Misra 
1461015a6ef6SSaurabh Misra 	tbl = r->r_buf_tbl;
1462015a6ef6SSaurabh Misra 	for (i = 0; i < rcnt; i++)  {
1463015a6ef6SSaurabh Misra 		if (tbl[i] != NULL) {
1464015a6ef6SSaurabh Misra 			atge_buf_free(tbl[i]);
1465015a6ef6SSaurabh Misra 		}
1466015a6ef6SSaurabh Misra 	}
1467015a6ef6SSaurabh Misra 
1468015a6ef6SSaurabh Misra 	kmem_free(tbl, rcnt * sizeof (atge_dma_t *));
1469015a6ef6SSaurabh Misra }
1470015a6ef6SSaurabh Misra 
1471015a6ef6SSaurabh Misra atge_dma_t *
atge_alloc_a_dma_blk(atge_t * atgep,ddi_dma_attr_t * attr,int size,int d)1472015a6ef6SSaurabh Misra atge_alloc_a_dma_blk(atge_t *atgep, ddi_dma_attr_t *attr, int size, int d)
1473015a6ef6SSaurabh Misra {
1474015a6ef6SSaurabh Misra 	int err;
1475015a6ef6SSaurabh Misra 	atge_dma_t *dma;
1476015a6ef6SSaurabh Misra 
1477015a6ef6SSaurabh Misra 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
1478015a6ef6SSaurabh Misra 
1479015a6ef6SSaurabh Misra 	err = ddi_dma_alloc_handle(atgep->atge_dip, attr,
1480015a6ef6SSaurabh Misra 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
1481015a6ef6SSaurabh Misra 
1482015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1483015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1484015a6ef6SSaurabh Misra 		    " in ddi_dma_alloc_handle() : %d", __func__, err);
1485015a6ef6SSaurabh Misra 		goto fail;
1486015a6ef6SSaurabh Misra 	}
1487015a6ef6SSaurabh Misra 
1488015a6ef6SSaurabh Misra 	err = ddi_dma_mem_alloc(dma->hdl,
1489015a6ef6SSaurabh Misra 	    size, &atge_buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
1490015a6ef6SSaurabh Misra 	    &dma->addr, &dma->len, &dma->acchdl);
1491015a6ef6SSaurabh Misra 
1492015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1493015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1494015a6ef6SSaurabh Misra 		    " in ddi_dma_mem_alloc() : %d", __func__, err);
1495015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1496015a6ef6SSaurabh Misra 		goto fail;
1497015a6ef6SSaurabh Misra 	}
1498015a6ef6SSaurabh Misra 
1499015a6ef6SSaurabh Misra 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr,
1500015a6ef6SSaurabh Misra 	    dma->len, d | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
1501015a6ef6SSaurabh Misra 	    NULL, &dma->cookie, &dma->count);
1502015a6ef6SSaurabh Misra 
1503015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1504015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1505015a6ef6SSaurabh Misra 		    " in ddi_dma_addr_bind_handle() : %d", __func__, err);
1506015a6ef6SSaurabh Misra 		ddi_dma_mem_free(&dma->acchdl);
1507015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1508015a6ef6SSaurabh Misra 		goto fail;
1509015a6ef6SSaurabh Misra 	}
1510015a6ef6SSaurabh Misra 
1511015a6ef6SSaurabh Misra 	return (dma);
1512015a6ef6SSaurabh Misra fail:
1513015a6ef6SSaurabh Misra 	kmem_free(dma, sizeof (atge_dma_t));
1514015a6ef6SSaurabh Misra 	return (NULL);
1515015a6ef6SSaurabh Misra }
1516015a6ef6SSaurabh Misra 
1517015a6ef6SSaurabh Misra void
atge_free_a_dma_blk(atge_dma_t * dma)1518015a6ef6SSaurabh Misra atge_free_a_dma_blk(atge_dma_t *dma)
1519015a6ef6SSaurabh Misra {
1520015a6ef6SSaurabh Misra 	if (dma != NULL) {
1521015a6ef6SSaurabh Misra 		(void) ddi_dma_unbind_handle(dma->hdl);
1522015a6ef6SSaurabh Misra 		ddi_dma_mem_free(&dma->acchdl);
1523015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1524015a6ef6SSaurabh Misra 		kmem_free(dma, sizeof (atge_dma_t));
1525015a6ef6SSaurabh Misra 	}
1526015a6ef6SSaurabh Misra }
1527015a6ef6SSaurabh Misra 
1528015a6ef6SSaurabh Misra atge_dma_t *
atge_buf_alloc(atge_t * atgep,size_t len,int f)1529015a6ef6SSaurabh Misra atge_buf_alloc(atge_t *atgep, size_t len, int f)
1530015a6ef6SSaurabh Misra {
1531015a6ef6SSaurabh Misra 	atge_dma_t *dma = NULL;
1532015a6ef6SSaurabh Misra 	int err;
1533015a6ef6SSaurabh Misra 
1534015a6ef6SSaurabh Misra 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
1535015a6ef6SSaurabh Misra 
1536015a6ef6SSaurabh Misra 	err = ddi_dma_alloc_handle(atgep->atge_dip, &atge_dma_attr_buf,
1537015a6ef6SSaurabh Misra 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
1538015a6ef6SSaurabh Misra 
1539015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1540015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1541015a6ef6SSaurabh Misra 		    " in %s() : %d", __func__, err);
1542015a6ef6SSaurabh Misra 		goto fail;
1543015a6ef6SSaurabh Misra 	}
1544015a6ef6SSaurabh Misra 
1545015a6ef6SSaurabh Misra 	err = ddi_dma_mem_alloc(dma->hdl, len, &atge_buf_attr,
1546015a6ef6SSaurabh Misra 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dma->addr,
1547015a6ef6SSaurabh Misra 	    &dma->len, &dma->acchdl);
1548015a6ef6SSaurabh Misra 
1549015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1550015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1551015a6ef6SSaurabh Misra 		    " in %s() : %d", __func__, err);
1552015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1553015a6ef6SSaurabh Misra 		goto fail;
1554015a6ef6SSaurabh Misra 	}
1555015a6ef6SSaurabh Misra 
1556015a6ef6SSaurabh Misra 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, dma->len,
1557015a6ef6SSaurabh Misra 	    (f | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, &dma->cookie,
1558015a6ef6SSaurabh Misra 	    &dma->count);
1559015a6ef6SSaurabh Misra 
1560015a6ef6SSaurabh Misra 	if (err != DDI_SUCCESS) {
1561015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() : failed"
1562015a6ef6SSaurabh Misra 		    " in %s() : %d", __func__, err);
1563015a6ef6SSaurabh Misra 		ddi_dma_mem_free(&dma->acchdl);
1564015a6ef6SSaurabh Misra 		ddi_dma_free_handle(&dma->hdl);
1565015a6ef6SSaurabh Misra 		goto fail;
1566015a6ef6SSaurabh Misra 	}
1567015a6ef6SSaurabh Misra 
1568015a6ef6SSaurabh Misra 	/*
1569015a6ef6SSaurabh Misra 	 * Number of return'ed cookie should be one.
1570015a6ef6SSaurabh Misra 	 */
1571015a6ef6SSaurabh Misra 	ASSERT(dma->count == 1);
1572015a6ef6SSaurabh Misra 
1573015a6ef6SSaurabh Misra 	return (dma);
1574015a6ef6SSaurabh Misra fail:
1575015a6ef6SSaurabh Misra 	kmem_free(dma, sizeof (atge_dma_t));
1576015a6ef6SSaurabh Misra 	return (NULL);
1577015a6ef6SSaurabh Misra }
1578015a6ef6SSaurabh Misra 
1579015a6ef6SSaurabh Misra void
atge_buf_free(atge_dma_t * dma)1580015a6ef6SSaurabh Misra atge_buf_free(atge_dma_t *dma)
1581015a6ef6SSaurabh Misra {
1582015a6ef6SSaurabh Misra 	ASSERT(dma != NULL);
1583015a6ef6SSaurabh Misra 
1584015a6ef6SSaurabh Misra 	(void) ddi_dma_unbind_handle(dma->hdl);
1585015a6ef6SSaurabh Misra 	ddi_dma_mem_free(&dma->acchdl);
1586015a6ef6SSaurabh Misra 	ddi_dma_free_handle(&dma->hdl);
1587015a6ef6SSaurabh Misra 	kmem_free(dma, sizeof (atge_dma_t));
1588015a6ef6SSaurabh Misra }
1589015a6ef6SSaurabh Misra 
1590015a6ef6SSaurabh Misra static int
atge_resume(dev_info_t * dip)1591015a6ef6SSaurabh Misra atge_resume(dev_info_t *dip)
1592015a6ef6SSaurabh Misra {
1593015a6ef6SSaurabh Misra 	atge_t	*atgep;
1594015a6ef6SSaurabh Misra 
1595015a6ef6SSaurabh Misra 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
1596015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1597015a6ef6SSaurabh Misra 	}
1598015a6ef6SSaurabh Misra 
1599015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1600015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1601015a6ef6SSaurabh Misra 
1602015a6ef6SSaurabh Misra 	atgep->atge_chip_state &= ~ATGE_CHIP_SUSPENDED;
1603015a6ef6SSaurabh Misra 
1604015a6ef6SSaurabh Misra 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
1605015a6ef6SSaurabh Misra 		atge_device_restart(atgep);
1606015a6ef6SSaurabh Misra 	} else {
1607015a6ef6SSaurabh Misra 		atge_device_reset(atgep);
1608015a6ef6SSaurabh Misra 	}
1609015a6ef6SSaurabh Misra 
1610015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1611015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1612015a6ef6SSaurabh Misra 
1613015a6ef6SSaurabh Misra 	/*
1614015a6ef6SSaurabh Misra 	 * Reset the PHY before resuming MII.
1615015a6ef6SSaurabh Misra 	 */
16165e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
16175e8715b9SGary Mills 	case ATGE_CHIP_L1E:
1618015a6ef6SSaurabh Misra 		atge_l1e_mii_reset(atgep);
16195e8715b9SGary Mills 		break;
16205e8715b9SGary Mills 	case ATGE_CHIP_L1:
16215e8715b9SGary Mills 		break;
16225e8715b9SGary Mills 	case ATGE_CHIP_L1C:
16235e8715b9SGary Mills 		break;
1624015a6ef6SSaurabh Misra 	}
1625015a6ef6SSaurabh Misra 
1626015a6ef6SSaurabh Misra 	mii_resume(atgep->atge_mii);
1627015a6ef6SSaurabh Misra 
1628015a6ef6SSaurabh Misra 	/* kick-off downstream */
1629015a6ef6SSaurabh Misra 	mac_tx_update(atgep->atge_mh);
1630015a6ef6SSaurabh Misra 
1631015a6ef6SSaurabh Misra 	return (DDI_SUCCESS);
1632015a6ef6SSaurabh Misra }
1633015a6ef6SSaurabh Misra 
1634015a6ef6SSaurabh Misra static int
atge_quiesce(dev_info_t * dip)1635015a6ef6SSaurabh Misra atge_quiesce(dev_info_t *dip)
1636015a6ef6SSaurabh Misra {
1637015a6ef6SSaurabh Misra 	atge_t	*atgep;
1638015a6ef6SSaurabh Misra 
1639015a6ef6SSaurabh Misra 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
1640015a6ef6SSaurabh Misra 		return (DDI_FAILURE);
1641015a6ef6SSaurabh Misra 	}
1642015a6ef6SSaurabh Misra 
1643015a6ef6SSaurabh Misra 	atge_device_stop(atgep);
1644015a6ef6SSaurabh Misra 
1645015a6ef6SSaurabh Misra 	return (DDI_SUCCESS);
1646015a6ef6SSaurabh Misra }
1647015a6ef6SSaurabh Misra 
1648015a6ef6SSaurabh Misra void
atge_add_multicst(atge_t * atgep,uint8_t * macaddr)1649015a6ef6SSaurabh Misra atge_add_multicst(atge_t *atgep, uint8_t *macaddr)
1650015a6ef6SSaurabh Misra {
1651015a6ef6SSaurabh Misra 	uint32_t crc;
1652015a6ef6SSaurabh Misra 	int bit;
1653015a6ef6SSaurabh Misra 
1654015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
1655015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
1656015a6ef6SSaurabh Misra 
1657015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
1658015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
1659015a6ef6SSaurabh Misra 	    macaddr[3], macaddr[4], macaddr[5]));
1660015a6ef6SSaurabh Misra 
1661015a6ef6SSaurabh Misra 	crc = atge_ether_crc(macaddr, ETHERADDRL);
1662015a6ef6SSaurabh Misra 	bit = (crc >> 26);
1663015a6ef6SSaurabh Misra 	atgep->atge_mchash_ref_cnt[bit]++;
1664015a6ef6SSaurabh Misra 	atgep->atge_mchash |= (1ULL << (crc >> 26));
1665015a6ef6SSaurabh Misra 
1666015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
1667015a6ef6SSaurabh Misra 	    " atge_mchash_ref_cnt[bit] :%d",
1668015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
1669015a6ef6SSaurabh Misra 	    atgep->atge_mchash_ref_cnt[bit]));
1670015a6ef6SSaurabh Misra }
1671015a6ef6SSaurabh Misra 
1672015a6ef6SSaurabh Misra void
atge_remove_multicst(atge_t * atgep,uint8_t * macaddr)1673015a6ef6SSaurabh Misra atge_remove_multicst(atge_t *atgep, uint8_t *macaddr)
1674015a6ef6SSaurabh Misra {
1675015a6ef6SSaurabh Misra 	uint32_t crc;
1676015a6ef6SSaurabh Misra 	int bit;
1677015a6ef6SSaurabh Misra 
1678015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
1679015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
1680015a6ef6SSaurabh Misra 
1681015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
1682015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
1683015a6ef6SSaurabh Misra 	    macaddr[3], macaddr[4], macaddr[5]));
1684015a6ef6SSaurabh Misra 
1685015a6ef6SSaurabh Misra 	crc = atge_ether_crc(macaddr, ETHERADDRL);
1686015a6ef6SSaurabh Misra 	bit = (crc >> 26);
1687015a6ef6SSaurabh Misra 	atgep->atge_mchash_ref_cnt[bit]--;
1688015a6ef6SSaurabh Misra 	if (atgep->atge_mchash_ref_cnt[bit] == 0)
1689015a6ef6SSaurabh Misra 		atgep->atge_mchash &= ~(1ULL << (crc >> 26));
1690015a6ef6SSaurabh Misra 
1691015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
1692015a6ef6SSaurabh Misra 	    " atge_mchash_ref_cnt[bit] :%d",
1693015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
1694015a6ef6SSaurabh Misra 	    atgep->atge_mchash_ref_cnt[bit]));
1695015a6ef6SSaurabh Misra }
1696015a6ef6SSaurabh Misra 
1697015a6ef6SSaurabh Misra int
atge_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)1698015a6ef6SSaurabh Misra atge_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
1699015a6ef6SSaurabh Misra {
1700015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1701015a6ef6SSaurabh Misra 
1702015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1703015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1704015a6ef6SSaurabh Misra 
1705015a6ef6SSaurabh Misra 	if (add) {
1706015a6ef6SSaurabh Misra 		atge_add_multicst(atgep, (uint8_t *)macaddr);
1707015a6ef6SSaurabh Misra 	} else {
1708015a6ef6SSaurabh Misra 		atge_remove_multicst(atgep, (uint8_t *)macaddr);
1709015a6ef6SSaurabh Misra 	}
1710015a6ef6SSaurabh Misra 
1711015a6ef6SSaurabh Misra 	atge_rxfilter(atgep);
1712015a6ef6SSaurabh Misra 
1713015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1714015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1715015a6ef6SSaurabh Misra 
1716015a6ef6SSaurabh Misra 	return (0);
1717015a6ef6SSaurabh Misra }
1718015a6ef6SSaurabh Misra 
1719015a6ef6SSaurabh Misra int
atge_m_promisc(void * arg,boolean_t on)1720015a6ef6SSaurabh Misra atge_m_promisc(void *arg, boolean_t on)
1721015a6ef6SSaurabh Misra {
1722015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1723015a6ef6SSaurabh Misra 
1724015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1725015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1726015a6ef6SSaurabh Misra 
1727015a6ef6SSaurabh Misra 	if (on) {
1728015a6ef6SSaurabh Misra 		atgep->atge_filter_flags |= ATGE_PROMISC;
1729015a6ef6SSaurabh Misra 	} else {
1730015a6ef6SSaurabh Misra 		atgep->atge_filter_flags &= ~ATGE_PROMISC;
1731015a6ef6SSaurabh Misra 	}
1732015a6ef6SSaurabh Misra 
1733015a6ef6SSaurabh Misra 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
1734015a6ef6SSaurabh Misra 		atge_rxfilter(atgep);
1735015a6ef6SSaurabh Misra 	}
1736015a6ef6SSaurabh Misra 
1737015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1738015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1739015a6ef6SSaurabh Misra 
1740015a6ef6SSaurabh Misra 	return (0);
1741015a6ef6SSaurabh Misra }
1742015a6ef6SSaurabh Misra 
1743015a6ef6SSaurabh Misra int
atge_m_unicst(void * arg,const uint8_t * macaddr)1744015a6ef6SSaurabh Misra atge_m_unicst(void *arg, const uint8_t *macaddr)
1745015a6ef6SSaurabh Misra {
1746015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1747015a6ef6SSaurabh Misra 
1748015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1749015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1750015a6ef6SSaurabh Misra 	bcopy(macaddr, atgep->atge_ether_addr, ETHERADDRL);
1751015a6ef6SSaurabh Misra 	atge_program_ether(atgep);
1752015a6ef6SSaurabh Misra 	atge_rxfilter(atgep);
1753015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1754015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1755015a6ef6SSaurabh Misra 
1756015a6ef6SSaurabh Misra 	return (0);
1757015a6ef6SSaurabh Misra }
1758015a6ef6SSaurabh Misra 
1759015a6ef6SSaurabh Misra mblk_t *
atge_m_tx(void * arg,mblk_t * mp)1760015a6ef6SSaurabh Misra atge_m_tx(void *arg, mblk_t *mp)
1761015a6ef6SSaurabh Misra {
1762015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1763015a6ef6SSaurabh Misra 	mblk_t	*nmp;
1764015a6ef6SSaurabh Misra 
1765015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1766015a6ef6SSaurabh Misra 
1767015a6ef6SSaurabh Misra 	/*
1768015a6ef6SSaurabh Misra 	 * This NIC does not like us to send pkt when link is down.
1769015a6ef6SSaurabh Misra 	 */
1770015a6ef6SSaurabh Misra 	if (!(atgep->atge_link_state & LINK_STATE_UP)) {
1771015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 1;
17720eb090a7SSaurabh Misra 
1773015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1774015a6ef6SSaurabh Misra 		return (mp);
1775015a6ef6SSaurabh Misra 	}
1776015a6ef6SSaurabh Misra 
1777015a6ef6SSaurabh Misra 	/*
1778015a6ef6SSaurabh Misra 	 * Don't send a pkt if chip isn't running or in suspended state.
1779015a6ef6SSaurabh Misra 	 */
1780015a6ef6SSaurabh Misra 	if ((atgep->atge_chip_state & ATGE_CHIP_RUNNING) == 0 ||
1781015a6ef6SSaurabh Misra 	    atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
1782015a6ef6SSaurabh Misra 		atgep->atge_carrier_errors++;
1783015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 1;
17840eb090a7SSaurabh Misra 
1785015a6ef6SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
1786015a6ef6SSaurabh Misra 		return (mp);
1787015a6ef6SSaurabh Misra 	}
1788015a6ef6SSaurabh Misra 
1789015a6ef6SSaurabh Misra 	while (mp != NULL) {
1790015a6ef6SSaurabh Misra 		nmp = mp->b_next;
1791015a6ef6SSaurabh Misra 		mp->b_next = NULL;
1792015a6ef6SSaurabh Misra 
17930eb090a7SSaurabh Misra 		if (atge_send_a_packet(atgep, mp) == DDI_FAILURE) {
1794015a6ef6SSaurabh Misra 			mp->b_next = nmp;
1795015a6ef6SSaurabh Misra 			break;
1796015a6ef6SSaurabh Misra 		}
1797015a6ef6SSaurabh Misra 
1798015a6ef6SSaurabh Misra 		mp = nmp;
1799015a6ef6SSaurabh Misra 	}
1800015a6ef6SSaurabh Misra 
1801015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1802015a6ef6SSaurabh Misra 	return (mp);
1803015a6ef6SSaurabh Misra }
1804015a6ef6SSaurabh Misra 
1805015a6ef6SSaurabh Misra int
atge_m_start(void * arg)1806015a6ef6SSaurabh Misra atge_m_start(void *arg)
1807015a6ef6SSaurabh Misra {
1808015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1809015a6ef6SSaurabh Misra 	int started = 0;
1810015a6ef6SSaurabh Misra 
1811015a6ef6SSaurabh Misra 	ASSERT(atgep != NULL);
1812015a6ef6SSaurabh Misra 
1813015a6ef6SSaurabh Misra 
1814015a6ef6SSaurabh Misra 	mii_stop(atgep->atge_mii);
1815015a6ef6SSaurabh Misra 
1816015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1817015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_tx_lock);
1818015a6ef6SSaurabh Misra 
1819015a6ef6SSaurabh Misra 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
1820015a6ef6SSaurabh Misra 		atge_device_restart(atgep);
1821015a6ef6SSaurabh Misra 		started = 1;
1822015a6ef6SSaurabh Misra 	}
1823015a6ef6SSaurabh Misra 
1824015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_tx_lock);
1825015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1826015a6ef6SSaurabh Misra 
1827015a6ef6SSaurabh Misra 	mii_start(atgep->atge_mii);
1828015a6ef6SSaurabh Misra 
1829015a6ef6SSaurabh Misra 	/* kick-off downstream */
1830015a6ef6SSaurabh Misra 	if (started)
1831015a6ef6SSaurabh Misra 		mac_tx_update(atgep->atge_mh);
1832015a6ef6SSaurabh Misra 
1833015a6ef6SSaurabh Misra 	return (0);
1834015a6ef6SSaurabh Misra }
1835015a6ef6SSaurabh Misra 
1836015a6ef6SSaurabh Misra void
atge_m_stop(void * arg)1837015a6ef6SSaurabh Misra atge_m_stop(void *arg)
1838015a6ef6SSaurabh Misra {
1839015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1840015a6ef6SSaurabh Misra 
1841015a6ef6SSaurabh Misra 	mii_stop(atgep->atge_mii);
1842015a6ef6SSaurabh Misra 
1843015a6ef6SSaurabh Misra 	/*
1844015a6ef6SSaurabh Misra 	 * Cancel any pending I/O.
1845015a6ef6SSaurabh Misra 	 */
1846015a6ef6SSaurabh Misra 	mutex_enter(&atgep->atge_intr_lock);
1847015a6ef6SSaurabh Misra 	atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
1848015a6ef6SSaurabh Misra 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED))
1849015a6ef6SSaurabh Misra 		atge_device_stop(atgep);
1850015a6ef6SSaurabh Misra 	mutex_exit(&atgep->atge_intr_lock);
1851015a6ef6SSaurabh Misra }
1852015a6ef6SSaurabh Misra 
1853015a6ef6SSaurabh Misra int
atge_m_stat(void * arg,uint_t stat,uint64_t * val)1854015a6ef6SSaurabh Misra atge_m_stat(void *arg, uint_t stat, uint64_t *val)
1855015a6ef6SSaurabh Misra {
1856015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1857015a6ef6SSaurabh Misra 
1858015a6ef6SSaurabh Misra 	if (mii_m_getstat(atgep->atge_mii, stat, val) == 0) {
1859015a6ef6SSaurabh Misra 		return (0);
1860015a6ef6SSaurabh Misra 	}
1861015a6ef6SSaurabh Misra 
1862015a6ef6SSaurabh Misra 	switch (stat) {
1863015a6ef6SSaurabh Misra 	case MAC_STAT_MULTIRCV:
1864015a6ef6SSaurabh Misra 		*val = atgep->atge_multircv;
1865015a6ef6SSaurabh Misra 		break;
1866015a6ef6SSaurabh Misra 
1867015a6ef6SSaurabh Misra 	case MAC_STAT_BRDCSTRCV:
1868015a6ef6SSaurabh Misra 		*val = atgep->atge_brdcstrcv;
1869015a6ef6SSaurabh Misra 		break;
1870015a6ef6SSaurabh Misra 
1871015a6ef6SSaurabh Misra 	case MAC_STAT_MULTIXMT:
1872015a6ef6SSaurabh Misra 		*val = atgep->atge_multixmt;
1873015a6ef6SSaurabh Misra 		break;
1874015a6ef6SSaurabh Misra 
1875015a6ef6SSaurabh Misra 	case MAC_STAT_BRDCSTXMT:
1876015a6ef6SSaurabh Misra 		*val = atgep->atge_brdcstxmt;
1877015a6ef6SSaurabh Misra 		break;
1878015a6ef6SSaurabh Misra 
1879015a6ef6SSaurabh Misra 	case MAC_STAT_IPACKETS:
1880015a6ef6SSaurabh Misra 		*val = atgep->atge_ipackets;
1881015a6ef6SSaurabh Misra 		break;
1882015a6ef6SSaurabh Misra 
1883015a6ef6SSaurabh Misra 	case MAC_STAT_RBYTES:
1884015a6ef6SSaurabh Misra 		*val = atgep->atge_rbytes;
1885015a6ef6SSaurabh Misra 		break;
1886015a6ef6SSaurabh Misra 
1887015a6ef6SSaurabh Misra 	case MAC_STAT_OPACKETS:
1888015a6ef6SSaurabh Misra 		*val = atgep->atge_opackets;
1889015a6ef6SSaurabh Misra 		break;
1890015a6ef6SSaurabh Misra 
1891015a6ef6SSaurabh Misra 	case MAC_STAT_OBYTES:
1892015a6ef6SSaurabh Misra 		*val = atgep->atge_obytes;
1893015a6ef6SSaurabh Misra 		break;
1894015a6ef6SSaurabh Misra 
1895015a6ef6SSaurabh Misra 	case MAC_STAT_NORCVBUF:
1896015a6ef6SSaurabh Misra 		*val = atgep->atge_norcvbuf;
1897015a6ef6SSaurabh Misra 		break;
1898015a6ef6SSaurabh Misra 
1899015a6ef6SSaurabh Misra 	case MAC_STAT_NOXMTBUF:
1900015a6ef6SSaurabh Misra 		*val = 0;
1901015a6ef6SSaurabh Misra 		break;
1902015a6ef6SSaurabh Misra 
1903015a6ef6SSaurabh Misra 	case MAC_STAT_COLLISIONS:
1904015a6ef6SSaurabh Misra 		*val = atgep->atge_collisions;
1905015a6ef6SSaurabh Misra 		break;
1906015a6ef6SSaurabh Misra 
1907015a6ef6SSaurabh Misra 	case MAC_STAT_IERRORS:
1908015a6ef6SSaurabh Misra 		*val = atgep->atge_errrcv;
1909015a6ef6SSaurabh Misra 		break;
1910015a6ef6SSaurabh Misra 
1911015a6ef6SSaurabh Misra 	case MAC_STAT_OERRORS:
1912015a6ef6SSaurabh Misra 		*val = atgep->atge_errxmt;
1913015a6ef6SSaurabh Misra 		break;
1914015a6ef6SSaurabh Misra 
1915015a6ef6SSaurabh Misra 	case ETHER_STAT_ALIGN_ERRORS:
1916015a6ef6SSaurabh Misra 		*val = atgep->atge_align_errors;
1917015a6ef6SSaurabh Misra 		break;
1918015a6ef6SSaurabh Misra 
1919015a6ef6SSaurabh Misra 	case ETHER_STAT_FCS_ERRORS:
1920015a6ef6SSaurabh Misra 		*val = atgep->atge_fcs_errors;
1921015a6ef6SSaurabh Misra 		break;
1922015a6ef6SSaurabh Misra 
1923015a6ef6SSaurabh Misra 	case ETHER_STAT_SQE_ERRORS:
1924015a6ef6SSaurabh Misra 		*val = atgep->atge_sqe_errors;
1925015a6ef6SSaurabh Misra 		break;
1926015a6ef6SSaurabh Misra 
1927015a6ef6SSaurabh Misra 	case ETHER_STAT_DEFER_XMTS:
1928015a6ef6SSaurabh Misra 		*val = atgep->atge_defer_xmts;
1929015a6ef6SSaurabh Misra 		break;
1930015a6ef6SSaurabh Misra 
1931015a6ef6SSaurabh Misra 	case ETHER_STAT_FIRST_COLLISIONS:
1932015a6ef6SSaurabh Misra 		*val = atgep->atge_first_collisions;
1933015a6ef6SSaurabh Misra 		break;
1934015a6ef6SSaurabh Misra 
1935015a6ef6SSaurabh Misra 	case ETHER_STAT_MULTI_COLLISIONS:
1936015a6ef6SSaurabh Misra 		*val = atgep->atge_multi_collisions;
1937015a6ef6SSaurabh Misra 		break;
1938015a6ef6SSaurabh Misra 
1939015a6ef6SSaurabh Misra 	case ETHER_STAT_TX_LATE_COLLISIONS:
1940015a6ef6SSaurabh Misra 		*val = atgep->atge_tx_late_collisions;
1941015a6ef6SSaurabh Misra 		break;
1942015a6ef6SSaurabh Misra 
1943015a6ef6SSaurabh Misra 	case ETHER_STAT_EX_COLLISIONS:
1944015a6ef6SSaurabh Misra 		*val = atgep->atge_ex_collisions;
1945015a6ef6SSaurabh Misra 		break;
1946015a6ef6SSaurabh Misra 
1947015a6ef6SSaurabh Misra 	case ETHER_STAT_MACXMT_ERRORS:
1948015a6ef6SSaurabh Misra 		*val = atgep->atge_macxmt_errors;
1949015a6ef6SSaurabh Misra 		break;
1950015a6ef6SSaurabh Misra 
1951015a6ef6SSaurabh Misra 	case ETHER_STAT_CARRIER_ERRORS:
1952015a6ef6SSaurabh Misra 		*val = atgep->atge_carrier_errors;
1953015a6ef6SSaurabh Misra 		break;
1954015a6ef6SSaurabh Misra 
1955015a6ef6SSaurabh Misra 	case ETHER_STAT_TOOLONG_ERRORS:
1956015a6ef6SSaurabh Misra 		*val = atgep->atge_toolong_errors;
1957015a6ef6SSaurabh Misra 		break;
1958015a6ef6SSaurabh Misra 
1959015a6ef6SSaurabh Misra 	case ETHER_STAT_MACRCV_ERRORS:
1960015a6ef6SSaurabh Misra 		*val = atgep->atge_macrcv_errors;
1961015a6ef6SSaurabh Misra 		break;
1962015a6ef6SSaurabh Misra 
1963015a6ef6SSaurabh Misra 	case MAC_STAT_OVERFLOWS:
1964015a6ef6SSaurabh Misra 		*val = atgep->atge_overflow;
1965015a6ef6SSaurabh Misra 		break;
1966015a6ef6SSaurabh Misra 
1967015a6ef6SSaurabh Misra 	case MAC_STAT_UNDERFLOWS:
1968015a6ef6SSaurabh Misra 		*val = atgep->atge_underflow;
1969015a6ef6SSaurabh Misra 		break;
1970015a6ef6SSaurabh Misra 
1971015a6ef6SSaurabh Misra 	case ETHER_STAT_TOOSHORT_ERRORS:
1972015a6ef6SSaurabh Misra 		*val = atgep->atge_runt;
1973015a6ef6SSaurabh Misra 		break;
1974015a6ef6SSaurabh Misra 
1975015a6ef6SSaurabh Misra 	case ETHER_STAT_JABBER_ERRORS:
1976015a6ef6SSaurabh Misra 		*val = atgep->atge_jabber;
1977015a6ef6SSaurabh Misra 		break;
1978015a6ef6SSaurabh Misra 
1979015a6ef6SSaurabh Misra 	default:
1980015a6ef6SSaurabh Misra 		return (ENOTSUP);
1981015a6ef6SSaurabh Misra 	}
1982015a6ef6SSaurabh Misra 
1983015a6ef6SSaurabh Misra 	return (0);
1984015a6ef6SSaurabh Misra }
1985015a6ef6SSaurabh Misra 
1986015a6ef6SSaurabh Misra int
atge_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)19870dc2366fSVenugopal Iyer atge_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
19880dc2366fSVenugopal Iyer     void *val)
1989015a6ef6SSaurabh Misra {
1990015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
1991015a6ef6SSaurabh Misra 
19920dc2366fSVenugopal Iyer 	return (mii_m_getprop(atgep->atge_mii, name, num, sz, val));
1993015a6ef6SSaurabh Misra }
1994015a6ef6SSaurabh Misra 
1995015a6ef6SSaurabh Misra int
atge_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)1996015a6ef6SSaurabh Misra atge_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1997015a6ef6SSaurabh Misra     const void *val)
1998015a6ef6SSaurabh Misra {
1999015a6ef6SSaurabh Misra 	atge_t *atgep = arg;
20000eb090a7SSaurabh Misra 	int r;
20010eb090a7SSaurabh Misra 
20020eb090a7SSaurabh Misra 	r = mii_m_setprop(atgep->atge_mii, name, num, sz, val);
20030eb090a7SSaurabh Misra 
20040eb090a7SSaurabh Misra 	if (r == 0) {
20050eb090a7SSaurabh Misra 		mutex_enter(&atgep->atge_intr_lock);
20060eb090a7SSaurabh Misra 		mutex_enter(&atgep->atge_tx_lock);
2007015a6ef6SSaurabh Misra 
20080eb090a7SSaurabh Misra 		if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
20090eb090a7SSaurabh Misra 			atge_device_restart(atgep);
20100eb090a7SSaurabh Misra 		}
20110eb090a7SSaurabh Misra 
20120eb090a7SSaurabh Misra 		mutex_exit(&atgep->atge_tx_lock);
20130eb090a7SSaurabh Misra 		mutex_exit(&atgep->atge_intr_lock);
20140eb090a7SSaurabh Misra 	}
20150eb090a7SSaurabh Misra 
20160eb090a7SSaurabh Misra 	return (r);
2017015a6ef6SSaurabh Misra }
2018015a6ef6SSaurabh Misra 
20190dc2366fSVenugopal Iyer static void
atge_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t prh)20200dc2366fSVenugopal Iyer atge_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
20210dc2366fSVenugopal Iyer     mac_prop_info_handle_t prh)
20220dc2366fSVenugopal Iyer {
20230dc2366fSVenugopal Iyer 	atge_t *atgep = arg;
20240dc2366fSVenugopal Iyer 
20250dc2366fSVenugopal Iyer 	mii_m_propinfo(atgep->atge_mii, name, num, prh);
20260dc2366fSVenugopal Iyer }
2027015a6ef6SSaurabh Misra 
2028015a6ef6SSaurabh Misra void
atge_program_ether(atge_t * atgep)2029015a6ef6SSaurabh Misra atge_program_ether(atge_t *atgep)
2030015a6ef6SSaurabh Misra {
2031015a6ef6SSaurabh Misra 	ether_addr_t e;
2032015a6ef6SSaurabh Misra 
2033015a6ef6SSaurabh Misra 	/*
2034015a6ef6SSaurabh Misra 	 * Reprogram the Station address.
2035015a6ef6SSaurabh Misra 	 */
2036015a6ef6SSaurabh Misra 	bcopy(atgep->atge_ether_addr, e, ETHERADDRL);
2037015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_PAR0,
2038015a6ef6SSaurabh Misra 	    ((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5]));
2039015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_PAR1, (e[0] << 8) | e[1]);
2040015a6ef6SSaurabh Misra }
2041015a6ef6SSaurabh Misra 
2042015a6ef6SSaurabh Misra /*
2043015a6ef6SSaurabh Misra  * Device specific operations.
2044015a6ef6SSaurabh Misra  */
2045015a6ef6SSaurabh Misra void
atge_device_start(atge_t * atgep)2046015a6ef6SSaurabh Misra atge_device_start(atge_t *atgep)
2047015a6ef6SSaurabh Misra {
20480eb090a7SSaurabh Misra 	uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo;
2049015a6ef6SSaurabh Misra 	uint32_t reg;
2050015a6ef6SSaurabh Misra 	uint32_t fsize;
2051015a6ef6SSaurabh Misra 
2052015a6ef6SSaurabh Misra 	/*
2053015a6ef6SSaurabh Misra 	 * Reprogram the Station address.
2054015a6ef6SSaurabh Misra 	 */
2055015a6ef6SSaurabh Misra 	atge_program_ether(atgep);
2056015a6ef6SSaurabh Misra 
20575e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
20585e8715b9SGary Mills 	case ATGE_CHIP_L1E:
2059015a6ef6SSaurabh Misra 		atge_l1e_program_dma(atgep);
20605e8715b9SGary Mills 		break;
20615e8715b9SGary Mills 	case ATGE_CHIP_L1:
20620eb090a7SSaurabh Misra 		atge_l1_program_dma(atgep);
20635e8715b9SGary Mills 		break;
20645e8715b9SGary Mills 	case ATGE_CHIP_L1C:
20655e8715b9SGary Mills 		atge_l1c_program_dma(atgep);
20665e8715b9SGary Mills 		break;
2067015a6ef6SSaurabh Misra 	}
2068015a6ef6SSaurabh Misra 
2069015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name,
2070015a6ef6SSaurabh Misra 	    __func__));
2071015a6ef6SSaurabh Misra 
20725e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
20735e8715b9SGary Mills 	case ATGE_CHIP_L1E:
20745e8715b9SGary Mills 	case ATGE_CHIP_L1:
20755e8715b9SGary Mills 		OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
20765e8715b9SGary Mills 		break;
20775e8715b9SGary Mills 	case ATGE_CHIP_L1C:
20785e8715b9SGary Mills 		/*
20795e8715b9SGary Mills 		 * Disable interrupt re-trigger timer. We don't want automatic
20805e8715b9SGary Mills 		 * re-triggering of un-ACKed interrupts.
20815e8715b9SGary Mills 		 */
20825e8715b9SGary Mills 		OUTL(atgep, ATGE_INTR_RETRIG_TIMER, ATGE_USECS(0));
20835e8715b9SGary Mills 		/* Configure CMB. */
20845e8715b9SGary Mills 		OUTL(atgep, ATGE_CMB_TX_TIMER, ATGE_USECS(0));
20855e8715b9SGary Mills 		/*
20865e8715b9SGary Mills 		 * Hardware can be configured to issue SMB interrupt based
20875e8715b9SGary Mills 		 * on programmed interval. Since there is a callout that is
20885e8715b9SGary Mills 		 * invoked for every hz in driver we use that instead of
20895e8715b9SGary Mills 		 * relying on periodic SMB interrupt.
20905e8715b9SGary Mills 		 */
20915e8715b9SGary Mills 		OUTL(atgep, ATGE_SMB_STAT_TIMER, ATGE_USECS(0));
20925e8715b9SGary Mills 		/* Clear MAC statistics. */
20935e8715b9SGary Mills 		atge_l1c_clear_stats(atgep);
20945e8715b9SGary Mills 		break;
20955e8715b9SGary Mills 	}
2096015a6ef6SSaurabh Misra 
2097015a6ef6SSaurabh Misra 	/*
20980eb090a7SSaurabh Misra 	 * Set Maximum frame size but don't let MTU be less than ETHER_MTU.
2099015a6ef6SSaurabh Misra 	 */
2100015a6ef6SSaurabh Misra 	if (atgep->atge_mtu < ETHERMTU)
2101015a6ef6SSaurabh Misra 		atgep->atge_max_frame_size = ETHERMTU;
2102015a6ef6SSaurabh Misra 	else
2103015a6ef6SSaurabh Misra 		atgep->atge_max_frame_size = atgep->atge_mtu;
2104015a6ef6SSaurabh Misra 
2105015a6ef6SSaurabh Misra 	atgep->atge_max_frame_size += sizeof (struct ether_header) +
2106015a6ef6SSaurabh Misra 	    VLAN_TAGSZ + ETHERFCSL;
2107015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size);
2108015a6ef6SSaurabh Misra 
21095e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
21105e8715b9SGary Mills 	case ATGE_CHIP_L1E:
21115e8715b9SGary Mills 		break;
21125e8715b9SGary Mills 	case ATGE_CHIP_L1:
21135e8715b9SGary Mills 		break;
21145e8715b9SGary Mills 	case ATGE_CHIP_L1C:
21155e8715b9SGary Mills 		/* Disable header split(?) */
21165e8715b9SGary Mills 		OUTL(atgep, ATGE_HDS_CFG, 0);
21175e8715b9SGary Mills 		break;
21185e8715b9SGary Mills 	}
2119015a6ef6SSaurabh Misra 
2120015a6ef6SSaurabh Misra 	/*
2121015a6ef6SSaurabh Misra 	 * Configure IPG/IFG parameters.
2122015a6ef6SSaurabh Misra 	 */
2123015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_IPG_IFG_CFG,
2124015a6ef6SSaurabh Misra 	    ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) |
2125015a6ef6SSaurabh Misra 	    ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) |
2126015a6ef6SSaurabh Misra 	    ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) |
2127015a6ef6SSaurabh Misra 	    ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK));
2128015a6ef6SSaurabh Misra 
2129015a6ef6SSaurabh Misra 	/*
2130015a6ef6SSaurabh Misra 	 * Set parameters for half-duplex media.
2131015a6ef6SSaurabh Misra 	 */
2132015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_HDPX_CFG,
2133015a6ef6SSaurabh Misra 	    ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) &
2134015a6ef6SSaurabh Misra 	    HDPX_CFG_LCOL_MASK) |
2135015a6ef6SSaurabh Misra 	    ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) &
2136015a6ef6SSaurabh Misra 	    HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN |
2137015a6ef6SSaurabh Misra 	    ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) &
2138015a6ef6SSaurabh Misra 	    HDPX_CFG_ABEBT_MASK) |
2139015a6ef6SSaurabh Misra 	    ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) &
2140015a6ef6SSaurabh Misra 	    HDPX_CFG_JAMIPG_MASK));
2141015a6ef6SSaurabh Misra 
2142015a6ef6SSaurabh Misra 	/*
2143015a6ef6SSaurabh Misra 	 * Configure jumbo frame.
2144015a6ef6SSaurabh Misra 	 */
21455e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
21465e8715b9SGary Mills 	case ATGE_CHIP_L1E:
21475e8715b9SGary Mills 		if (atgep->atge_flags & ATGE_FLAG_JUMBO) {
21485e8715b9SGary Mills 
21495e8715b9SGary Mills 			if (atgep->atge_mtu < ETHERMTU)
21505e8715b9SGary Mills 				reg = atgep->atge_max_frame_size;
21515e8715b9SGary Mills 			else if (atgep->atge_mtu < 6 * 1024)
21525e8715b9SGary Mills 				reg = (atgep->atge_max_frame_size * 2) / 3;
21535e8715b9SGary Mills 			else
21545e8715b9SGary Mills 				reg = atgep->atge_max_frame_size / 2;
21555e8715b9SGary Mills 
21565e8715b9SGary Mills 			OUTL(atgep, L1E_TX_JUMBO_THRESH,
21575e8715b9SGary Mills 			    ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
21585e8715b9SGary Mills 			    TX_JUMBO_THRESH_UNIT_SHIFT);
21595e8715b9SGary Mills 		}
21605e8715b9SGary Mills 		break;
21615e8715b9SGary Mills 	case ATGE_CHIP_L1:
2162015a6ef6SSaurabh Misra 		fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t));
2163015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_JUMBO_CFG,
2164015a6ef6SSaurabh Misra 		    (((fsize / sizeof (uint64_t)) <<
2165015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) &
2166015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_SZ_THRESH_MASK) |
2167015a6ef6SSaurabh Misra 		    ((RXQ_JUMBO_CFG_LKAH_DEFAULT <<
2168015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) |
2169015a6ef6SSaurabh Misra 		    ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) &
2170015a6ef6SSaurabh Misra 		    RXQ_JUMBO_CFG_RRD_TIMER_MASK));
21715e8715b9SGary Mills 		break;
21725e8715b9SGary Mills 	case ATGE_CHIP_L1C:
21735e8715b9SGary Mills 		break;
2174015a6ef6SSaurabh Misra 	}
2175015a6ef6SSaurabh Misra 
2176015a6ef6SSaurabh Misra 	/*
2177015a6ef6SSaurabh Misra 	 * Configure flow-control parameters.
2178015a6ef6SSaurabh Misra 	 */
21795e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
21805e8715b9SGary Mills 	case ATGE_CHIP_L1E:
21815e8715b9SGary Mills 	case ATGE_CHIP_L1:
21825e8715b9SGary Mills 		if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
2183015a6ef6SSaurabh Misra 		/*
2184015a6ef6SSaurabh Misra 		 * Some hardware version require this magic.
2185015a6ef6SSaurabh Misra 		 */
21865e8715b9SGary Mills 		OUTL(atgep, ATGE_LTSSM_ID_CFG, 0x6500);
2187015a6ef6SSaurabh Misra 		reg = INL(atgep, 0x1008);
2188015a6ef6SSaurabh Misra 		OUTL(atgep, 0x1008, reg | 0x8000);
21895e8715b9SGary Mills 		}
21905e8715b9SGary Mills 		break;
21915e8715b9SGary Mills 	case ATGE_CHIP_L1C:
21925e8715b9SGary Mills 		break;
2193015a6ef6SSaurabh Misra 	}
2194015a6ef6SSaurabh Misra 
2195015a6ef6SSaurabh Misra 	/*
2196015a6ef6SSaurabh Misra 	 * These are all magic parameters which came from FreeBSD.
2197015a6ef6SSaurabh Misra 	 */
21985e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
21995e8715b9SGary Mills 	case ATGE_CHIP_L1E:
22005e8715b9SGary Mills 		reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
22015e8715b9SGary Mills 		rxf_hi = (reg * 4) / 5;
22025e8715b9SGary Mills 		rxf_lo = reg/ 5;
22035e8715b9SGary Mills 
22045e8715b9SGary Mills 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
22055e8715b9SGary Mills 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
22065e8715b9SGary Mills 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
22075e8715b9SGary Mills 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
22085e8715b9SGary Mills 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
22095e8715b9SGary Mills 		break;
22105e8715b9SGary Mills 	case ATGE_CHIP_L1:
22110eb090a7SSaurabh Misra 		switch (atgep->atge_chip_rev) {
22120eb090a7SSaurabh Misra 		case 0x8001:
22130eb090a7SSaurabh Misra 		case 0x9001:
22140eb090a7SSaurabh Misra 		case 0x9002:
22150eb090a7SSaurabh Misra 		case 0x9003:
22160eb090a7SSaurabh Misra 			rxf_hi = L1_RX_RING_CNT / 16;
22170eb090a7SSaurabh Misra 			rxf_lo = (L1_RX_RING_CNT * 7) / 8;
22180eb090a7SSaurabh Misra 			rrd_hi = (L1_RR_RING_CNT * 7) / 8;
22190eb090a7SSaurabh Misra 			rrd_lo = L1_RR_RING_CNT / 16;
22200eb090a7SSaurabh Misra 			break;
22210eb090a7SSaurabh Misra 		default:
22220eb090a7SSaurabh Misra 			reg = INL(atgep, L1_SRAM_RX_FIFO_LEN);
22230eb090a7SSaurabh Misra 			rxf_lo = reg / 16;
22240eb090a7SSaurabh Misra 			if (rxf_lo > 192)
22250eb090a7SSaurabh Misra 				rxf_lo = 192;
22260eb090a7SSaurabh Misra 			rxf_hi = (reg * 7) / 8;
22270eb090a7SSaurabh Misra 			if (rxf_hi < rxf_lo)
22280eb090a7SSaurabh Misra 				rxf_hi = rxf_lo + 16;
22290eb090a7SSaurabh Misra 			reg = INL(atgep, L1_SRAM_RRD_LEN);
22300eb090a7SSaurabh Misra 			rrd_lo = reg / 8;
22310eb090a7SSaurabh Misra 			rrd_hi = (reg * 7) / 8;
22320eb090a7SSaurabh Misra 			if (rrd_lo > 2)
22330eb090a7SSaurabh Misra 				rrd_lo = 2;
22340eb090a7SSaurabh Misra 			if (rrd_hi < rrd_lo)
22350eb090a7SSaurabh Misra 				rrd_hi = rrd_lo + 3;
22360eb090a7SSaurabh Misra 			break;
22370eb090a7SSaurabh Misra 		}
22380eb090a7SSaurabh Misra 
22390eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
22400eb090a7SSaurabh Misra 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
22410eb090a7SSaurabh Misra 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
22420eb090a7SSaurabh Misra 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
22430eb090a7SSaurabh Misra 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
22440eb090a7SSaurabh Misra 
22450eb090a7SSaurabh Misra 		OUTL(atgep, L1_RXQ_RRD_PAUSE_THRESH,
22460eb090a7SSaurabh Misra 		    ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) &
22470eb090a7SSaurabh Misra 		    RXQ_RRD_PAUSE_THRESH_LO_MASK) |
22480eb090a7SSaurabh Misra 		    ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
22490eb090a7SSaurabh Misra 		    RXQ_RRD_PAUSE_THRESH_HI_MASK));
22505e8715b9SGary Mills 		break;
22515e8715b9SGary Mills 	case ATGE_CHIP_L1C:
22525e8715b9SGary Mills 		switch (ATGE_DID(atgep)) {
22535e8715b9SGary Mills 		case ATGE_CHIP_AR8151V2_DEV_ID:
22545e8715b9SGary Mills 		case ATGE_CHIP_AR8152V1_DEV_ID:
22555e8715b9SGary Mills 			OUTL(atgep, ATGE_SERDES_LOCK,
22565e8715b9SGary Mills 			    INL(atgep, ATGE_SERDES_LOCK) |
22575e8715b9SGary Mills 			    SERDES_MAC_CLK_SLOWDOWN |
22585e8715b9SGary Mills 			    SERDES_PHY_CLK_SLOWDOWN);
22595e8715b9SGary Mills 			break;
22605e8715b9SGary Mills 		case ATGE_CHIP_L1CG_DEV_ID:
22615e8715b9SGary Mills 		case ATGE_CHIP_L1CF_DEV_ID:
22625e8715b9SGary Mills 			/*
22635e8715b9SGary Mills 			 * Configure flow control parameters.
22645e8715b9SGary Mills 			 * XON	: 80% of Rx FIFO
22655e8715b9SGary Mills 			 * XOFF : 30% of Rx FIFO
22665e8715b9SGary Mills 			 */
22675e8715b9SGary Mills 			reg = INL(atgep, L1C_SRAM_RX_FIFO_LEN);
22685e8715b9SGary Mills 			rxf_hi = (reg * 8) / 10;
22695e8715b9SGary Mills 			rxf_lo = (reg * 3) / 10;
22705e8715b9SGary Mills 
22715e8715b9SGary Mills 			OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
22725e8715b9SGary Mills 			    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
22735e8715b9SGary Mills 			    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
22745e8715b9SGary Mills 			    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
22755e8715b9SGary Mills 			    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
22765e8715b9SGary Mills 			break;
22775e8715b9SGary Mills 		}
22785e8715b9SGary Mills 		break;
2279015a6ef6SSaurabh Misra 	}
2280015a6ef6SSaurabh Misra 
22815e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
22825e8715b9SGary Mills 	case ATGE_CHIP_L1E:
22835e8715b9SGary Mills 		/* Configure RxQ. */
22845e8715b9SGary Mills 		reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB |
22855e8715b9SGary Mills 		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
22865e8715b9SGary Mills 		OUTL(atgep, ATGE_RXQ_CFG, reg);
22875e8715b9SGary Mills 		/*
22885e8715b9SGary Mills 		 * Configure TxQ.
22895e8715b9SGary Mills 		 */
22905e8715b9SGary Mills 		reg = (128 <<
22915e8715b9SGary Mills 		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
22925e8715b9SGary Mills 		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
22935e8715b9SGary Mills 
22945e8715b9SGary Mills 		reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
22955e8715b9SGary Mills 		    TXQ_CFG_TPD_BURST_MASK;
22965e8715b9SGary Mills 
22975e8715b9SGary Mills 		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
22985e8715b9SGary Mills 
22995e8715b9SGary Mills 		OUTL(atgep, ATGE_TXQ_CFG, reg);
23005e8715b9SGary Mills 		/* Disable RSS. */
23015e8715b9SGary Mills 		OUTL(atgep, L1E_RSS_IDT_TABLE0, 0);
23025e8715b9SGary Mills 		OUTL(atgep, L1E_RSS_CPU, 0);
23035e8715b9SGary Mills 		/*
23045e8715b9SGary Mills 		 * Configure DMA parameters.
23055e8715b9SGary Mills 		 */
23065e8715b9SGary Mills 		/*
23075e8715b9SGary Mills 		 * Don't use Tx CMB. It is known to cause RRS update failure
23085e8715b9SGary Mills 		 * under certain circumstances. Typical phenomenon of the
23095e8715b9SGary Mills 		 * issue would be unexpected sequence number encountered in
23105e8715b9SGary Mills 		 * Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB.
23115e8715b9SGary Mills 		 */
23125e8715b9SGary Mills 		OUTL(atgep, ATGE_DMA_CFG,
23135e8715b9SGary Mills 		    DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
23145e8715b9SGary Mills 		    atgep->atge_dma_rd_burst | atgep->atge_dma_wr_burst |
23155e8715b9SGary Mills 		    DMA_CFG_RXCMB_ENB |
23165e8715b9SGary Mills 		    ((DMA_CFG_RD_DELAY_CNT_DEFAULT <<
23175e8715b9SGary Mills 		    DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) |
23185e8715b9SGary Mills 		    ((DMA_CFG_WR_DELAY_CNT_DEFAULT <<
23195e8715b9SGary Mills 		    DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK));
23205e8715b9SGary Mills 		/*
23215e8715b9SGary Mills 		 * Enable CMB/SMB timer.
23225e8715b9SGary Mills 		 */
23235e8715b9SGary Mills 		OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
23245e8715b9SGary Mills 		atge_l1e_clear_stats(atgep);
23255e8715b9SGary Mills 		break;
23265e8715b9SGary Mills 	case ATGE_CHIP_L1:
23275e8715b9SGary Mills 		/* Configure RxQ. */
23280eb090a7SSaurabh Misra 		reg =
23290eb090a7SSaurabh Misra 		    ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
23300eb090a7SSaurabh Misra 		    RXQ_CFG_RD_BURST_MASK) |
23310eb090a7SSaurabh Misra 		    ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
23320eb090a7SSaurabh Misra 		    RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
23330eb090a7SSaurabh Misra 		    RXQ_CFG_RRD_BURST_THRESH_MASK) |
23340eb090a7SSaurabh Misra 		    ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
23350eb090a7SSaurabh Misra 		    RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
23360eb090a7SSaurabh Misra 		    RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
23370eb090a7SSaurabh Misra 		    RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
23380eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_RXQ_CFG, reg);
23395e8715b9SGary Mills 		/*
23405e8715b9SGary Mills 		 * Configure TxQ.
23415e8715b9SGary Mills 		 */
23420eb090a7SSaurabh Misra 		reg =
23430eb090a7SSaurabh Misra 		    (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
23440eb090a7SSaurabh Misra 		    TXQ_CFG_TPD_BURST_MASK) |
23450eb090a7SSaurabh Misra 		    ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
23460eb090a7SSaurabh Misra 		    TXQ_CFG_TX_FIFO_BURST_SHIFT) &
23470eb090a7SSaurabh Misra 		    TXQ_CFG_TX_FIFO_BURST_MASK) |
23480eb090a7SSaurabh Misra 		    ((TXQ_CFG_TPD_FETCH_DEFAULT <<
23490eb090a7SSaurabh Misra 		    TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
23500eb090a7SSaurabh Misra 		    TXQ_CFG_TPD_FETCH_THRESH_MASK) |
23510eb090a7SSaurabh Misra 		    TXQ_CFG_ENB);
23520eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_TXQ_CFG, reg);
23535e8715b9SGary Mills 		/* Jumbo frames */
23540eb090a7SSaurabh Misra 		OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
23550eb090a7SSaurabh Misra 		    (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
23560eb090a7SSaurabh Misra 		    TX_JUMBO_TPD_TH_MASK) |
23570eb090a7SSaurabh Misra 		    ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
23580eb090a7SSaurabh Misra 		    TX_JUMBO_TPD_IPG_MASK));
23595e8715b9SGary Mills 		/*
23605e8715b9SGary Mills 		 * Configure DMA parameters.
23615e8715b9SGary Mills 		 */
23620eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG,
23630eb090a7SSaurabh Misra 		    DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
23640eb090a7SSaurabh Misra 		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
23650eb090a7SSaurabh Misra 		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
23660eb090a7SSaurabh Misra 
23670eb090a7SSaurabh Misra 		/* Configure CMB DMA write threshold. */
23680eb090a7SSaurabh Misra 		OUTL(atgep, L1_CMB_WR_THRESH,
23690eb090a7SSaurabh Misra 		    ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
23700eb090a7SSaurabh Misra 		    CMB_WR_THRESH_RRD_MASK) |
23710eb090a7SSaurabh Misra 		    ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
23720eb090a7SSaurabh Misra 		    CMB_WR_THRESH_TPD_MASK));
2373015a6ef6SSaurabh Misra 		/*
23745e8715b9SGary Mills 		 * Enable CMB/SMB timer.
2375015a6ef6SSaurabh Misra 		 */
23760eb090a7SSaurabh Misra 		/* Set CMB/SMB timer and enable them. */
23770eb090a7SSaurabh Misra 		OUTL(atgep, L1_CMB_WR_TIMER,
23780eb090a7SSaurabh Misra 		    ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) &
23790eb090a7SSaurabh Misra 		    CMB_WR_TIMER_TX_MASK) |
23800eb090a7SSaurabh Misra 		    ((ATGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) &
23810eb090a7SSaurabh Misra 		    CMB_WR_TIMER_RX_MASK));
23820eb090a7SSaurabh Misra 
23830eb090a7SSaurabh Misra 		/* Request SMB updates for every seconds. */
23840eb090a7SSaurabh Misra 		OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000));
23850eb090a7SSaurabh Misra 		OUTL(atgep, L1_CSMB_CTRL,
23860eb090a7SSaurabh Misra 		    CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB);
23875e8715b9SGary Mills 		break;
23885e8715b9SGary Mills 	case ATGE_CHIP_L1C:
23895e8715b9SGary Mills 		/* Configure RxQ. */
23905e8715b9SGary Mills 		reg =
23915e8715b9SGary Mills 		    RXQ_CFG_RD_BURST_DEFAULT << L1C_RXQ_CFG_RD_BURST_SHIFT |
23925e8715b9SGary Mills 		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
23935e8715b9SGary Mills 		if ((atgep->atge_flags & ATGE_FLAG_ASPM_MON) != 0)
23945e8715b9SGary Mills 			reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_1M;
23955e8715b9SGary Mills 		OUTL(atgep, ATGE_RXQ_CFG, reg);
23965e8715b9SGary Mills 		/*
23975e8715b9SGary Mills 		 * Configure TxQ.
23985e8715b9SGary Mills 		 */
23995e8715b9SGary Mills 		reg = (128 <<
24005e8715b9SGary Mills 		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
24015e8715b9SGary Mills 		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
24025e8715b9SGary Mills 
24035e8715b9SGary Mills 		switch (ATGE_DID(atgep)) {
24045e8715b9SGary Mills 		case ATGE_CHIP_AR8152V2_DEV_ID:
24055e8715b9SGary Mills 		case ATGE_CHIP_AR8152V1_DEV_ID:
24065e8715b9SGary Mills 			reg >>= 1;
24075e8715b9SGary Mills 			break;
24085e8715b9SGary Mills 		}
24095e8715b9SGary Mills 
24105e8715b9SGary Mills 		reg |= (L1C_TXQ_CFG_TPD_BURST_DEFAULT <<
24115e8715b9SGary Mills 		    TXQ_CFG_TPD_BURST_SHIFT) & TXQ_CFG_TPD_BURST_MASK;
2412015a6ef6SSaurabh Misra 
24135e8715b9SGary Mills 		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
24145e8715b9SGary Mills 
24155e8715b9SGary Mills 		OUTL(atgep, L1C_TXQ_CFG, reg);
24165e8715b9SGary Mills 		/* Disable RSS until I understand L1C/L2C's RSS logic. */
24175e8715b9SGary Mills 		OUTL(atgep, L1C_RSS_IDT_TABLE0, 0xe4e4e4e4);
24185e8715b9SGary Mills 		OUTL(atgep, L1C_RSS_CPU, 0);
24195e8715b9SGary Mills 		/*
24205e8715b9SGary Mills 		 * Configure DMA parameters.
24215e8715b9SGary Mills 		 */
24225e8715b9SGary Mills 		OUTL(atgep, ATGE_DMA_CFG,
24235e8715b9SGary Mills 		    DMA_CFG_SMB_DIS |
24245e8715b9SGary Mills 		    DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
24255e8715b9SGary Mills 		    DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT |
24265e8715b9SGary Mills 		    DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT |
24275e8715b9SGary Mills 
24285e8715b9SGary Mills 		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
24295e8715b9SGary Mills 		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
24305e8715b9SGary Mills 		/* Configure CMB DMA write threshold not required. */
24315e8715b9SGary Mills 		/* Set CMB/SMB timer and enable them not required. */
24325e8715b9SGary Mills 		break;
24335e8715b9SGary Mills 	}
24340eb090a7SSaurabh Misra 
2435015a6ef6SSaurabh Misra 	/*
2436015a6ef6SSaurabh Misra 	 * Disable all WOL bits as WOL can interfere normal Rx
2437015a6ef6SSaurabh Misra 	 * operation.
2438015a6ef6SSaurabh Misra 	 */
2439015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_WOL_CFG, 0);
2440015a6ef6SSaurabh Misra 
2441015a6ef6SSaurabh Misra 	/*
2442015a6ef6SSaurabh Misra 	 * Configure Tx/Rx MACs.
2443015a6ef6SSaurabh Misra 	 *  - Auto-padding for short frames.
2444015a6ef6SSaurabh Misra 	 *  - Enable CRC generation.
2445015a6ef6SSaurabh Misra 	 *
2446015a6ef6SSaurabh Misra 	 *  Start with full-duplex/1000Mbps media. Actual reconfiguration
2447015a6ef6SSaurabh Misra 	 *  of MAC is followed after link establishment.
2448015a6ef6SSaurabh Misra 	 */
2449015a6ef6SSaurabh Misra 	reg = (ATGE_CFG_TX_CRC_ENB | ATGE_CFG_TX_AUTO_PAD |
2450015a6ef6SSaurabh Misra 	    ATGE_CFG_FULL_DUPLEX |
2451015a6ef6SSaurabh Misra 	    ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) &
2452015a6ef6SSaurabh Misra 	    ATGE_CFG_PREAMBLE_MASK));
2453015a6ef6SSaurabh Misra 
24545e8715b9SGary Mills 	/*
24555e8715b9SGary Mills 	 *  AR813x/AR815x always does checksum computation regardless
24565e8715b9SGary Mills 	 *  of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to
24575e8715b9SGary Mills 	 *  have bug in protocol field in Rx return structure so
24585e8715b9SGary Mills 	 *  these controllers can't handle fragmented frames. Disable
24595e8715b9SGary Mills 	 *  Rx checksum offloading until there is a newer controller
24605e8715b9SGary Mills 	 *  that has sane implementation.
24615e8715b9SGary Mills 	 */
24625e8715b9SGary Mills 	switch (ATGE_DID(atgep)) {
24635e8715b9SGary Mills 	case ATGE_CHIP_AR8151V2_DEV_ID:
24645e8715b9SGary Mills 	case ATGE_CHIP_AR8151V1_DEV_ID:
24655e8715b9SGary Mills 	case ATGE_CHIP_AR8152V2_DEV_ID:
24665e8715b9SGary Mills 		reg |= ATGE_CFG_HASH_ALG_CRC32 | ATGE_CFG_SPEED_MODE_SW;
24675e8715b9SGary Mills 		break;
24685e8715b9SGary Mills 	}
24695e8715b9SGary Mills 
2470015a6ef6SSaurabh Misra 	if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) {
2471015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_10_100;
2472015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__));
2473015a6ef6SSaurabh Misra 	} else {
2474015a6ef6SSaurabh Misra 		reg |= ATGE_CFG_SPEED_1000;
2475015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__));
2476015a6ef6SSaurabh Misra 	}
24775e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
24785e8715b9SGary Mills 	case ATGE_CHIP_L1C:
24795e8715b9SGary Mills 		reg |= L1C_CFG_SINGLE_PAUSE_ENB;
24805e8715b9SGary Mills 		break;
24815e8715b9SGary Mills 	}
2482015a6ef6SSaurabh Misra 
2483015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAC_CFG, reg);
2484015a6ef6SSaurabh Misra 
2485015a6ef6SSaurabh Misra 	atgep->atge_chip_state |= ATGE_CHIP_RUNNING;
2486015a6ef6SSaurabh Misra 
2487015a6ef6SSaurabh Misra 	/*
2488015a6ef6SSaurabh Misra 	 * Set up the receive filter.
2489015a6ef6SSaurabh Misra 	 */
2490015a6ef6SSaurabh Misra 	atge_rxfilter(atgep);
2491015a6ef6SSaurabh Misra 
24920eb090a7SSaurabh Misra 	/*
24930eb090a7SSaurabh Misra 	 * Acknowledge all pending interrupts and clear it.
24940eb090a7SSaurabh Misra 	 */
24955e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
24965e8715b9SGary Mills 	case ATGE_CHIP_L1E:
2497015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS);
2498015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
2499015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_INTR_STATUS, 0);
25005e8715b9SGary Mills 		break;
25015e8715b9SGary Mills 	case ATGE_CHIP_L1:
25025e8715b9SGary Mills 	case ATGE_CHIP_L1C:
25035e8715b9SGary Mills 		OUTL(atgep, ATGE_INTR_STATUS, 0);
25045e8715b9SGary Mills 		OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
25055e8715b9SGary Mills 		break;
2506015a6ef6SSaurabh Misra 	}
2507015a6ef6SSaurabh Misra 
25080eb090a7SSaurabh Misra 	atge_mac_config(atgep);
25090eb090a7SSaurabh Misra 
2510015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() device started", atgep->atge_name, __func__));
2511015a6ef6SSaurabh Misra }
2512015a6ef6SSaurabh Misra 
2513015a6ef6SSaurabh Misra /*
2514015a6ef6SSaurabh Misra  * Generic functions.
2515015a6ef6SSaurabh Misra  */
2516015a6ef6SSaurabh Misra 
2517015a6ef6SSaurabh Misra #define	CRC32_POLY_BE   0x04c11db7
2518015a6ef6SSaurabh Misra uint32_t
atge_ether_crc(const uint8_t * addr,int len)2519015a6ef6SSaurabh Misra atge_ether_crc(const uint8_t *addr, int len)
2520015a6ef6SSaurabh Misra {
2521015a6ef6SSaurabh Misra 	int idx;
2522015a6ef6SSaurabh Misra 	int bit;
2523015a6ef6SSaurabh Misra 	uint_t data;
2524015a6ef6SSaurabh Misra 	uint32_t crc;
2525015a6ef6SSaurabh Misra 
2526015a6ef6SSaurabh Misra 	crc = 0xffffffff;
2527015a6ef6SSaurabh Misra 	for (idx = 0; idx < len; idx++) {
2528015a6ef6SSaurabh Misra 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
2529015a6ef6SSaurabh Misra 			crc = (crc << 1)
2530015a6ef6SSaurabh Misra 			    ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
2531015a6ef6SSaurabh Misra 		}
2532015a6ef6SSaurabh Misra 	}
2533015a6ef6SSaurabh Misra 
2534015a6ef6SSaurabh Misra 	return (crc);
2535015a6ef6SSaurabh Misra }
2536015a6ef6SSaurabh Misra 
2537015a6ef6SSaurabh Misra 
2538015a6ef6SSaurabh Misra /*
2539015a6ef6SSaurabh Misra  * Programs RX filter. We use a link-list to keep track of all multicast
2540015a6ef6SSaurabh Misra  * addressess.
2541015a6ef6SSaurabh Misra  */
2542015a6ef6SSaurabh Misra void
atge_rxfilter(atge_t * atgep)2543015a6ef6SSaurabh Misra atge_rxfilter(atge_t *atgep)
2544015a6ef6SSaurabh Misra {
2545015a6ef6SSaurabh Misra 	uint32_t rxcfg;
2546015a6ef6SSaurabh Misra 	uint64_t mchash;
2547015a6ef6SSaurabh Misra 
2548015a6ef6SSaurabh Misra 	rxcfg = INL(atgep, ATGE_MAC_CFG);
2549015a6ef6SSaurabh Misra 	rxcfg &= ~(ATGE_CFG_ALLMULTI | ATGE_CFG_PROMISC);
2550015a6ef6SSaurabh Misra 
2551015a6ef6SSaurabh Misra 	/*
2552015a6ef6SSaurabh Misra 	 * Accept broadcast frames.
2553015a6ef6SSaurabh Misra 	 */
2554015a6ef6SSaurabh Misra 	rxcfg |= ATGE_CFG_BCAST;
2555015a6ef6SSaurabh Misra 
2556015a6ef6SSaurabh Misra 	/*
2557015a6ef6SSaurabh Misra 	 * We don't use Hardware VLAN tagging.
2558015a6ef6SSaurabh Misra 	 */
2559015a6ef6SSaurabh Misra 	rxcfg &= ~ATGE_CFG_VLAN_TAG_STRIP;
2560015a6ef6SSaurabh Misra 
2561015a6ef6SSaurabh Misra 	if (atgep->atge_filter_flags & (ATGE_PROMISC | ATGE_ALL_MULTICST)) {
2562015a6ef6SSaurabh Misra 		mchash = ~0ULL;
2563015a6ef6SSaurabh Misra 
2564015a6ef6SSaurabh Misra 		if (atgep->atge_filter_flags & ATGE_PROMISC)
2565015a6ef6SSaurabh Misra 			rxcfg |= ATGE_CFG_PROMISC;
2566015a6ef6SSaurabh Misra 
2567015a6ef6SSaurabh Misra 		if (atgep->atge_filter_flags & ATGE_ALL_MULTICST)
2568015a6ef6SSaurabh Misra 			rxcfg |= ATGE_CFG_ALLMULTI;
2569015a6ef6SSaurabh Misra 	} else {
2570015a6ef6SSaurabh Misra 		mchash = atgep->atge_mchash;
2571015a6ef6SSaurabh Misra 	}
2572015a6ef6SSaurabh Misra 
2573015a6ef6SSaurabh Misra 	atge_program_ether(atgep);
2574015a6ef6SSaurabh Misra 
2575015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAR0, (uint32_t)mchash);
2576015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAR1, (uint32_t)(mchash >> 32));
2577015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_MAC_CFG, rxcfg);
2578015a6ef6SSaurabh Misra 
2579015a6ef6SSaurabh Misra 	ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx",
2580015a6ef6SSaurabh Misra 	    atgep->atge_name, __func__, rxcfg, mchash));
2581015a6ef6SSaurabh Misra }
2582015a6ef6SSaurabh Misra 
2583015a6ef6SSaurabh Misra void
atge_device_stop(atge_t * atgep)2584015a6ef6SSaurabh Misra atge_device_stop(atge_t *atgep)
2585015a6ef6SSaurabh Misra {
2586015a6ef6SSaurabh Misra 	uint32_t reg;
2587015a6ef6SSaurabh Misra 	int t;
2588015a6ef6SSaurabh Misra 
2589015a6ef6SSaurabh Misra 	/*
2590015a6ef6SSaurabh Misra 	 * If the chip is being suspended, then don't touch the state. Caller
2591015a6ef6SSaurabh Misra 	 * will take care of setting the correct state.
2592015a6ef6SSaurabh Misra 	 */
2593015a6ef6SSaurabh Misra 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
2594015a6ef6SSaurabh Misra 		atgep->atge_chip_state |= ATGE_CHIP_STOPPED;
2595015a6ef6SSaurabh Misra 		atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
2596015a6ef6SSaurabh Misra 	}
2597015a6ef6SSaurabh Misra 
2598015a6ef6SSaurabh Misra 	/*
2599015a6ef6SSaurabh Misra 	 * Collect stats for L1E. L1 chip's stats are collected by interrupt.
2600015a6ef6SSaurabh Misra 	 */
26015e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
26025e8715b9SGary Mills 	case ATGE_CHIP_L1E:
2603015a6ef6SSaurabh Misra 		atge_l1e_gather_stats(atgep);
26045e8715b9SGary Mills 		break;
26055e8715b9SGary Mills 	case ATGE_CHIP_L1:
26065e8715b9SGary Mills 	case ATGE_CHIP_L1C:
26075e8715b9SGary Mills 		break;
2608015a6ef6SSaurabh Misra 	}
2609015a6ef6SSaurabh Misra 
2610015a6ef6SSaurabh Misra 	/*
2611015a6ef6SSaurabh Misra 	 * Disable interrupts.
2612015a6ef6SSaurabh Misra 	 */
2613015a6ef6SSaurabh Misra 	atge_disable_intrs(atgep);
2614015a6ef6SSaurabh Misra 
26155e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
26165e8715b9SGary Mills 	case ATGE_CHIP_L1E:
26175e8715b9SGary Mills 		/* Clear CTRL not required. */
26185e8715b9SGary Mills 		/* Stop DMA Engine not required. */
26195e8715b9SGary Mills 		/*
26205e8715b9SGary Mills 		 * Disable queue processing.
26215e8715b9SGary Mills 		 */
26225e8715b9SGary Mills 		/* Stop TxQ */
26235e8715b9SGary Mills 		reg = INL(atgep, ATGE_TXQ_CFG);
26245e8715b9SGary Mills 		reg = reg & ~TXQ_CFG_ENB;
26255e8715b9SGary Mills 		OUTL(atgep, ATGE_TXQ_CFG, reg);
26265e8715b9SGary Mills 		/* Stop RxQ */
26275e8715b9SGary Mills 		reg = INL(atgep, ATGE_RXQ_CFG);
26285e8715b9SGary Mills 		reg = reg & ~RXQ_CFG_ENB;
26295e8715b9SGary Mills 		OUTL(atgep, ATGE_RXQ_CFG, reg);
26305e8715b9SGary Mills 		/* Stop DMA */
26315e8715b9SGary Mills 		reg = INL(atgep, ATGE_DMA_CFG);
26325e8715b9SGary Mills 		reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB);
26335e8715b9SGary Mills 		OUTL(atgep, ATGE_DMA_CFG, reg);
26345e8715b9SGary Mills 		drv_usecwait(1000);
26355e8715b9SGary Mills 		atge_l1e_stop_mac(atgep);
26365e8715b9SGary Mills 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
26375e8715b9SGary Mills 		break;
26385e8715b9SGary Mills 	case ATGE_CHIP_L1:
26395e8715b9SGary Mills 		/* Clear CTRL. */
26400eb090a7SSaurabh Misra 		OUTL(atgep, L1_CSMB_CTRL, 0);
26415e8715b9SGary Mills 		/* Stop DMA Engine */
26420eb090a7SSaurabh Misra 		atge_l1_stop_tx_mac(atgep);
26430eb090a7SSaurabh Misra 		atge_l1_stop_rx_mac(atgep);
26440eb090a7SSaurabh Misra 		reg = INL(atgep, ATGE_DMA_CFG);
26450eb090a7SSaurabh Misra 		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
26460eb090a7SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG, reg);
26475e8715b9SGary Mills 		/*
26485e8715b9SGary Mills 		 * Disable queue processing.
26495e8715b9SGary Mills 		 */
26505e8715b9SGary Mills 		/* Stop TxQ */
26515e8715b9SGary Mills 		reg = INL(atgep, ATGE_TXQ_CFG);
26525e8715b9SGary Mills 		reg = reg & ~TXQ_CFG_ENB;
26535e8715b9SGary Mills 		OUTL(atgep, ATGE_TXQ_CFG, reg);
26545e8715b9SGary Mills 		/* Stop RxQ */
26555e8715b9SGary Mills 		reg = INL(atgep, ATGE_RXQ_CFG);
26565e8715b9SGary Mills 		reg = reg & ~RXQ_CFG_ENB;
26575e8715b9SGary Mills 		OUTL(atgep, ATGE_RXQ_CFG, reg);
26585e8715b9SGary Mills 		break;
26595e8715b9SGary Mills 	case ATGE_CHIP_L1C:
26605e8715b9SGary Mills 		/* Clear CTRL not required. */
26615e8715b9SGary Mills 		/* Stop DMA Engine */
26625e8715b9SGary Mills 		atge_l1c_stop_tx_mac(atgep);
26635e8715b9SGary Mills 		atge_l1c_stop_rx_mac(atgep);
2664015a6ef6SSaurabh Misra 		reg = INL(atgep, ATGE_DMA_CFG);
26655e8715b9SGary Mills 		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
2666015a6ef6SSaurabh Misra 		OUTL(atgep, ATGE_DMA_CFG, reg);
26675e8715b9SGary Mills 		/*
26685e8715b9SGary Mills 		 * Disable queue processing.
26695e8715b9SGary Mills 		 */
26705e8715b9SGary Mills 		/* Stop TxQ */
26715e8715b9SGary Mills 		reg = INL(atgep, L1C_TXQ_CFG);
26725e8715b9SGary Mills 		reg = reg & ~TXQ_CFG_ENB;
26735e8715b9SGary Mills 		OUTL(atgep, L1C_TXQ_CFG, reg);
26745e8715b9SGary Mills 		/* Stop RxQ */
26755e8715b9SGary Mills 		reg = INL(atgep, ATGE_RXQ_CFG);
26765e8715b9SGary Mills 		reg = reg & ~RXQ_CFG_ENB;
26775e8715b9SGary Mills 		OUTL(atgep, ATGE_RXQ_CFG, reg);
26785e8715b9SGary Mills 		break;
2679015a6ef6SSaurabh Misra 	}
2680015a6ef6SSaurabh Misra 
2681015a6ef6SSaurabh Misra 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
2682015a6ef6SSaurabh Misra 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
2683015a6ef6SSaurabh Misra 			break;
2684015a6ef6SSaurabh Misra 		drv_usecwait(10);
2685015a6ef6SSaurabh Misra 	}
2686015a6ef6SSaurabh Misra 
2687015a6ef6SSaurabh Misra 	if (t == 0) {
2688015a6ef6SSaurabh Misra 		atge_error(atgep->atge_dip, "%s() stopping TX/RX MAC timeout",
2689015a6ef6SSaurabh Misra 		    __func__);
2690015a6ef6SSaurabh Misra 	}
2691015a6ef6SSaurabh Misra }
2692015a6ef6SSaurabh Misra 
2693015a6ef6SSaurabh Misra void
atge_disable_intrs(atge_t * atgep)2694015a6ef6SSaurabh Misra atge_disable_intrs(atge_t *atgep)
2695015a6ef6SSaurabh Misra {
2696015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_INTR_MASK, 0);
2697015a6ef6SSaurabh Misra 	OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
2698015a6ef6SSaurabh Misra }
2699015a6ef6SSaurabh Misra 
2700015a6ef6SSaurabh Misra void
atge_device_init(atge_t * atgep)2701015a6ef6SSaurabh Misra atge_device_init(atge_t *atgep)
2702015a6ef6SSaurabh Misra {
27035e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
27045e8715b9SGary Mills 	case ATGE_CHIP_L1E:
2705015a6ef6SSaurabh Misra 		atgep->atge_intrs = L1E_INTRS;
2706015a6ef6SSaurabh Misra 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
2707015a6ef6SSaurabh Misra 
2708015a6ef6SSaurabh Misra 		atge_l1e_init_tx_ring(atgep);
2709015a6ef6SSaurabh Misra 		atge_l1e_init_rx_pages(atgep);
27105e8715b9SGary Mills 		break;
27115e8715b9SGary Mills 	case ATGE_CHIP_L1:
27120eb090a7SSaurabh Misra 		atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN |
27130eb090a7SSaurabh Misra 		    INTR_LINK_CHG;
27140eb090a7SSaurabh Misra 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
27150eb090a7SSaurabh Misra 
27160eb090a7SSaurabh Misra 		atge_l1_init_tx_ring(atgep);
27170eb090a7SSaurabh Misra 		atge_l1_init_rx_ring(atgep);
27180eb090a7SSaurabh Misra 		atge_l1_init_rr_ring(atgep);
27190eb090a7SSaurabh Misra 		atge_l1_init_cmb(atgep);
27200eb090a7SSaurabh Misra 		atge_l1_init_smb(atgep);
27215e8715b9SGary Mills 		break;
27225e8715b9SGary Mills 	case ATGE_CHIP_L1C:
27235e8715b9SGary Mills 		atgep->atge_intrs = L1C_INTRS | L1C_INTR_GPHY |
27245e8715b9SGary Mills 		    L1C_INTR_PHY_LINK_DOWN;
27255e8715b9SGary Mills 		atgep->atge_int_rx_mod = 400/2;
27265e8715b9SGary Mills 		atgep->atge_int_tx_mod = 2000/1;
27275e8715b9SGary Mills 
27285e8715b9SGary Mills 		atge_l1c_init_tx_ring(atgep);
27295e8715b9SGary Mills 		atge_l1c_init_rx_ring(atgep);
27305e8715b9SGary Mills 		atge_l1c_init_rr_ring(atgep);
27315e8715b9SGary Mills 		atge_l1c_init_cmb(atgep);
27325e8715b9SGary Mills 		atge_l1c_init_smb(atgep);
27335e8715b9SGary Mills 
27345e8715b9SGary Mills 		/* Enable all clocks. */
27355e8715b9SGary Mills 		OUTL(atgep, ATGE_CLK_GATING_CFG, 0);
27365e8715b9SGary Mills 		break;
2737015a6ef6SSaurabh Misra 	}
2738015a6ef6SSaurabh Misra }
2739015a6ef6SSaurabh Misra 
2740015a6ef6SSaurabh Misra void
atge_device_restart(atge_t * atgep)2741015a6ef6SSaurabh Misra atge_device_restart(atge_t *atgep)
2742015a6ef6SSaurabh Misra {
2743015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
2744015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
2745015a6ef6SSaurabh Misra 
2746015a6ef6SSaurabh Misra 	/*
2747015a6ef6SSaurabh Misra 	 * Cancel any pending I/O.
2748015a6ef6SSaurabh Misra 	 */
2749015a6ef6SSaurabh Misra 	atge_device_stop(atgep);
2750015a6ef6SSaurabh Misra 
2751015a6ef6SSaurabh Misra 	/*
2752015a6ef6SSaurabh Misra 	 * Reset the chip to a known state.
2753015a6ef6SSaurabh Misra 	 */
2754015a6ef6SSaurabh Misra 	atge_device_reset(atgep);
2755015a6ef6SSaurabh Misra 
2756015a6ef6SSaurabh Misra 	/*
2757015a6ef6SSaurabh Misra 	 * Initialize the ring and other descriptor like CMB/SMB/Rx return.
2758015a6ef6SSaurabh Misra 	 */
2759015a6ef6SSaurabh Misra 	atge_device_init(atgep);
2760015a6ef6SSaurabh Misra 
2761015a6ef6SSaurabh Misra 	/*
2762015a6ef6SSaurabh Misra 	 * Start the chip.
2763015a6ef6SSaurabh Misra 	 */
2764015a6ef6SSaurabh Misra 	atge_device_start(atgep);
2765015a6ef6SSaurabh Misra 
2766015a6ef6SSaurabh Misra }
2767015a6ef6SSaurabh Misra 
2768015a6ef6SSaurabh Misra static int
atge_send_a_packet(atge_t * atgep,mblk_t * mp)2769015a6ef6SSaurabh Misra atge_send_a_packet(atge_t *atgep, mblk_t *mp)
2770015a6ef6SSaurabh Misra {
27710eb090a7SSaurabh Misra 	uchar_t *c;
27720eb090a7SSaurabh Misra 	uint32_t cflags = 0;
2773015a6ef6SSaurabh Misra 	atge_ring_t *r;
2774015a6ef6SSaurabh Misra 	size_t pktlen;
2775015a6ef6SSaurabh Misra 	uchar_t *buf;
2776015a6ef6SSaurabh Misra 	int	start;
2777015a6ef6SSaurabh Misra 
2778015a6ef6SSaurabh Misra 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
2779015a6ef6SSaurabh Misra 	ASSERT(mp != NULL);
2780015a6ef6SSaurabh Misra 
2781015a6ef6SSaurabh Misra 	pktlen = msgsize(mp);
2782015a6ef6SSaurabh Misra 	if (pktlen > atgep->atge_tx_buf_len) {
2783015a6ef6SSaurabh Misra 		atgep->atge_macxmt_errors++;
2784015a6ef6SSaurabh Misra 
2785015a6ef6SSaurabh Misra 		ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)",
2786015a6ef6SSaurabh Misra 		    atgep->atge_name, __func__,
2787015a6ef6SSaurabh Misra 		    pktlen, atgep->atge_rx_buf_len));
2788015a6ef6SSaurabh Misra 
2789015a6ef6SSaurabh Misra 		freemsg(mp);
27900eb090a7SSaurabh Misra 		return (DDI_SUCCESS);
2791015a6ef6SSaurabh Misra 	}
2792015a6ef6SSaurabh Misra 
2793015a6ef6SSaurabh Misra 	r = atgep->atge_tx_ring;
2794015a6ef6SSaurabh Misra 
2795015a6ef6SSaurabh Misra 	if (r->r_avail_desc <= 1) {
2796015a6ef6SSaurabh Misra 		atgep->atge_noxmtbuf++;
2797015a6ef6SSaurabh Misra 		atgep->atge_tx_resched = 1;
27980eb090a7SSaurabh Misra 
27990eb090a7SSaurabh Misra 		ATGE_DB(("%s: %s() No transmit buf",
28000eb090a7SSaurabh Misra 		    atgep->atge_name, __func__));
28010eb090a7SSaurabh Misra 
28020eb090a7SSaurabh Misra 		return (DDI_FAILURE);
2803015a6ef6SSaurabh Misra 	}
2804015a6ef6SSaurabh Misra 
2805015a6ef6SSaurabh Misra 	start = r->r_producer;
2806015a6ef6SSaurabh Misra 
2807015a6ef6SSaurabh Misra 	/*
2808015a6ef6SSaurabh Misra 	 * Get the DMA buffer to hold a packet.
2809015a6ef6SSaurabh Misra 	 */
2810015a6ef6SSaurabh Misra 	buf = (uchar_t *)r->r_buf_tbl[start]->addr;
2811015a6ef6SSaurabh Misra 
2812015a6ef6SSaurabh Misra 	/*
2813015a6ef6SSaurabh Misra 	 * Copy the msg and free mp
2814015a6ef6SSaurabh Misra 	 */
2815015a6ef6SSaurabh Misra 	mcopymsg(mp, buf);
2816015a6ef6SSaurabh Misra 
2817015a6ef6SSaurabh Misra 	r->r_avail_desc--;
2818015a6ef6SSaurabh Misra 
28190eb090a7SSaurabh Misra 	c = (uchar_t *)r->r_desc_ring->addr;
28205e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
28215e8715b9SGary Mills 	case ATGE_CHIP_L1C:
28225e8715b9SGary Mills 		{
28235e8715b9SGary Mills 		l1c_tx_desc_t	*txd;
28245e8715b9SGary Mills 
28255e8715b9SGary Mills 		c += (sizeof (l1c_tx_desc_t) * start);
28265e8715b9SGary Mills 		txd = (l1c_tx_desc_t *)c;
28275e8715b9SGary Mills 
28285e8715b9SGary Mills 		ATGE_PUT64(r->r_desc_ring, &txd->addr,
28295e8715b9SGary Mills 		    r->r_buf_tbl[start]->cookie.dmac_laddress);
28305e8715b9SGary Mills 
28315e8715b9SGary Mills 		ATGE_PUT32(r->r_desc_ring, &txd->len, L1C_TX_BYTES(pktlen));
28325e8715b9SGary Mills 
28335e8715b9SGary Mills 		cflags |= L1C_TD_EOP;
28345e8715b9SGary Mills 		ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
28355e8715b9SGary Mills 		break;
28365e8715b9SGary Mills 		}
28375e8715b9SGary Mills 	default:
28385e8715b9SGary Mills 		{
28395e8715b9SGary Mills 		atge_tx_desc_t	*txd;
28400eb090a7SSaurabh Misra 
28415e8715b9SGary Mills 		c += (sizeof (atge_tx_desc_t) * start);
28425e8715b9SGary Mills 		txd = (atge_tx_desc_t *)c;
28430eb090a7SSaurabh Misra 
28445e8715b9SGary Mills 		ATGE_PUT64(r->r_desc_ring, &txd->addr,
28455e8715b9SGary Mills 		    r->r_buf_tbl[start]->cookie.dmac_laddress);
28460eb090a7SSaurabh Misra 
28475e8715b9SGary Mills 		ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
28480eb090a7SSaurabh Misra 
28495e8715b9SGary Mills 		cflags |= ATGE_TD_EOP;
28505e8715b9SGary Mills 		ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
28515e8715b9SGary Mills 		break;
28525e8715b9SGary Mills 		}
28535e8715b9SGary Mills 	}
28540eb090a7SSaurabh Misra 	/*
28550eb090a7SSaurabh Misra 	 * Sync buffer first.
28560eb090a7SSaurabh Misra 	 */
28570eb090a7SSaurabh Misra 	DMA_SYNC(r->r_buf_tbl[start], 0, pktlen, DDI_DMA_SYNC_FORDEV);
28580eb090a7SSaurabh Misra 
28590eb090a7SSaurabh Misra 	/*
28600eb090a7SSaurabh Misra 	 * Increment TX producer count by one.
28610eb090a7SSaurabh Misra 	 */
28620eb090a7SSaurabh Misra 	ATGE_INC_SLOT(r->r_producer, ATGE_TX_RING_CNT);
28630eb090a7SSaurabh Misra 
28640eb090a7SSaurabh Misra 	/*
28650eb090a7SSaurabh Misra 	 * Sync descriptor table.
28660eb090a7SSaurabh Misra 	 */
28670eb090a7SSaurabh Misra 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
28680eb090a7SSaurabh Misra 
2869015a6ef6SSaurabh Misra 	/*
2870015a6ef6SSaurabh Misra 	 * Program TX descriptor to send a packet.
2871015a6ef6SSaurabh Misra 	 */
28725e8715b9SGary Mills 	switch (ATGE_MODEL(atgep)) {
28735e8715b9SGary Mills 	case ATGE_CHIP_L1E:
28740eb090a7SSaurabh Misra 		atge_l1e_send_packet(r);
28755e8715b9SGary Mills 		break;
28765e8715b9SGary Mills 	case ATGE_CHIP_L1:
28770eb090a7SSaurabh Misra 		atge_l1_send_packet(r);
28785e8715b9SGary Mills 		break;
28795e8715b9SGary Mills 	case ATGE_CHIP_L1C:
28805e8715b9SGary Mills 		atge_l1c_send_packet(r);
28815e8715b9SGary Mills 		break;
2882015a6ef6SSaurabh Misra 	}
2883015a6ef6SSaurabh Misra 
28840eb090a7SSaurabh Misra 	r->r_atge->atge_opackets++;
28850eb090a7SSaurabh Misra 	r->r_atge->atge_obytes += pktlen;
28860eb090a7SSaurabh Misra 
28870eb090a7SSaurabh Misra 	ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer  :%d, "
28880eb090a7SSaurabh Misra 	    "consumer : %d", atgep->atge_name, __func__, pktlen,
28890eb090a7SSaurabh Misra 	    r->r_avail_desc, r->r_producer, r->r_consumer));
28900eb090a7SSaurabh Misra 
28910eb090a7SSaurabh Misra 	return (DDI_SUCCESS);
2892015a6ef6SSaurabh Misra }
2893015a6ef6SSaurabh Misra 
2894015a6ef6SSaurabh Misra /*
2895015a6ef6SSaurabh Misra  * Stream Information.
2896015a6ef6SSaurabh Misra  */
2897015a6ef6SSaurabh Misra DDI_DEFINE_STREAM_OPS(atge_devops, nulldev, nulldev, atge_attach, atge_detach,
2898015a6ef6SSaurabh Misra     nodev, NULL, D_MP, NULL, atge_quiesce);
2899015a6ef6SSaurabh Misra 
2900015a6ef6SSaurabh Misra /*
2901015a6ef6SSaurabh Misra  * Module linkage information.
2902015a6ef6SSaurabh Misra  */
2903015a6ef6SSaurabh Misra static	struct	modldrv	atge_modldrv = {
2904015a6ef6SSaurabh Misra 	&mod_driverops,				/* Type of Module */
2905015a6ef6SSaurabh Misra 	"Atheros/Attansic Gb Ethernet",		/* Description */
2906015a6ef6SSaurabh Misra 	&atge_devops				/* drv_dev_ops */
2907015a6ef6SSaurabh Misra };
2908015a6ef6SSaurabh Misra 
2909015a6ef6SSaurabh Misra static	struct	modlinkage atge_modlinkage = {
2910015a6ef6SSaurabh Misra 	MODREV_1,			/* ml_rev */
2911015a6ef6SSaurabh Misra 	(void *)&atge_modldrv,
2912015a6ef6SSaurabh Misra 	NULL
2913015a6ef6SSaurabh Misra };
2914015a6ef6SSaurabh Misra 
2915015a6ef6SSaurabh Misra /*
2916015a6ef6SSaurabh Misra  * DDI Entry points.
2917015a6ef6SSaurabh Misra  */
2918015a6ef6SSaurabh Misra int
_init(void)2919015a6ef6SSaurabh Misra _init(void)
2920015a6ef6SSaurabh Misra {
2921015a6ef6SSaurabh Misra 	int	r;
2922015a6ef6SSaurabh Misra 	mac_init_ops(&atge_devops, "atge");
2923015a6ef6SSaurabh Misra 	if ((r = mod_install(&atge_modlinkage)) != DDI_SUCCESS) {
2924015a6ef6SSaurabh Misra 		mac_fini_ops(&atge_devops);
2925015a6ef6SSaurabh Misra 	}
2926015a6ef6SSaurabh Misra 
2927015a6ef6SSaurabh Misra 	return (r);
2928015a6ef6SSaurabh Misra }
2929015a6ef6SSaurabh Misra 
2930015a6ef6SSaurabh Misra int
_fini(void)2931015a6ef6SSaurabh Misra _fini(void)
2932015a6ef6SSaurabh Misra {
2933015a6ef6SSaurabh Misra 	int	r;
2934015a6ef6SSaurabh Misra 
2935015a6ef6SSaurabh Misra 	if ((r = mod_remove(&atge_modlinkage)) == DDI_SUCCESS) {
2936015a6ef6SSaurabh Misra 		mac_fini_ops(&atge_devops);
2937015a6ef6SSaurabh Misra 	}
2938015a6ef6SSaurabh Misra 
2939015a6ef6SSaurabh Misra 	return (r);
2940015a6ef6SSaurabh Misra }
2941015a6ef6SSaurabh Misra 
2942015a6ef6SSaurabh Misra int
_info(struct modinfo * modinfop)2943015a6ef6SSaurabh Misra _info(struct modinfo *modinfop)
2944015a6ef6SSaurabh Misra {
2945015a6ef6SSaurabh Misra 	return (mod_info(&atge_modlinkage, modinfop));
2946015a6ef6SSaurabh Misra }
2947