xref: /onnv-gate/usr/src/uts/common/io/atge/atge_main.c (revision 11353:db56a54bf91c)
110393SSaurabh.Mishra@Sun.COM /*
210393SSaurabh.Mishra@Sun.COM  * CDDL HEADER START
310393SSaurabh.Mishra@Sun.COM  *
410393SSaurabh.Mishra@Sun.COM  * The contents of this file are subject to the terms of the
510393SSaurabh.Mishra@Sun.COM  * Common Development and Distribution License (the "License").
610393SSaurabh.Mishra@Sun.COM  * You may not use this file except in compliance with the License.
710393SSaurabh.Mishra@Sun.COM  *
810393SSaurabh.Mishra@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910393SSaurabh.Mishra@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010393SSaurabh.Mishra@Sun.COM  * See the License for the specific language governing permissions
1110393SSaurabh.Mishra@Sun.COM  * and limitations under the License.
1210393SSaurabh.Mishra@Sun.COM  *
1310393SSaurabh.Mishra@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410393SSaurabh.Mishra@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510393SSaurabh.Mishra@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610393SSaurabh.Mishra@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710393SSaurabh.Mishra@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810393SSaurabh.Mishra@Sun.COM  *
1910393SSaurabh.Mishra@Sun.COM  * CDDL HEADER END
2010393SSaurabh.Mishra@Sun.COM  */
2110393SSaurabh.Mishra@Sun.COM 
2210393SSaurabh.Mishra@Sun.COM /*
2310393SSaurabh.Mishra@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2410393SSaurabh.Mishra@Sun.COM  * Use is subject to license terms.
2510393SSaurabh.Mishra@Sun.COM  */
2610393SSaurabh.Mishra@Sun.COM 
2710393SSaurabh.Mishra@Sun.COM #include <sys/types.h>
2810393SSaurabh.Mishra@Sun.COM #include <sys/stream.h>
2910393SSaurabh.Mishra@Sun.COM #include <sys/strsun.h>
3010393SSaurabh.Mishra@Sun.COM #include <sys/stat.h>
3110393SSaurabh.Mishra@Sun.COM #include <sys/modctl.h>
3210393SSaurabh.Mishra@Sun.COM #include <sys/kstat.h>
3310393SSaurabh.Mishra@Sun.COM #include <sys/ethernet.h>
3410393SSaurabh.Mishra@Sun.COM #include <sys/devops.h>
3510393SSaurabh.Mishra@Sun.COM #include <sys/debug.h>
3610393SSaurabh.Mishra@Sun.COM #include <sys/conf.h>
3710393SSaurabh.Mishra@Sun.COM #include <sys/mii.h>
3810393SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h>
3910393SSaurabh.Mishra@Sun.COM #include <sys/mac.h>
4010393SSaurabh.Mishra@Sun.COM #include <sys/mac_provider.h>
4110393SSaurabh.Mishra@Sun.COM #include <sys/mac_ether.h>
4210393SSaurabh.Mishra@Sun.COM #include <sys/sysmacros.h>
4310393SSaurabh.Mishra@Sun.COM #include <sys/dditypes.h>
4410393SSaurabh.Mishra@Sun.COM #include <sys/ddi.h>
4510393SSaurabh.Mishra@Sun.COM #include <sys/sunddi.h>
4610393SSaurabh.Mishra@Sun.COM #include <sys/byteorder.h>
4710393SSaurabh.Mishra@Sun.COM #include <sys/note.h>
4810393SSaurabh.Mishra@Sun.COM #include <sys/vlan.h>
4910393SSaurabh.Mishra@Sun.COM #include <sys/strsubr.h>
5010393SSaurabh.Mishra@Sun.COM #include <sys/crc32.h>
5110393SSaurabh.Mishra@Sun.COM #include <sys/sdt.h>
5210393SSaurabh.Mishra@Sun.COM #include <sys/pci.h>
5310393SSaurabh.Mishra@Sun.COM #include <sys/pci_cap.h>
5410393SSaurabh.Mishra@Sun.COM 
5510393SSaurabh.Mishra@Sun.COM #include "atge.h"
5610393SSaurabh.Mishra@Sun.COM #include "atge_cmn_reg.h"
5710393SSaurabh.Mishra@Sun.COM #include "atge_l1e_reg.h"
58*11353SSaurabh.Mishra@Sun.COM #include "atge_l1_reg.h"
5910393SSaurabh.Mishra@Sun.COM 
6010393SSaurabh.Mishra@Sun.COM 
6110393SSaurabh.Mishra@Sun.COM /*
6210393SSaurabh.Mishra@Sun.COM  * Atheros/Attansic Ethernet chips are of three types - L1, L2 and L1E.
63*11353SSaurabh.Mishra@Sun.COM  * This driver is for L1E/L1 but can be extended to support other chips.
64*11353SSaurabh.Mishra@Sun.COM  * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
65*11353SSaurabh.Mishra@Sun.COM  * flavors only.
6610393SSaurabh.Mishra@Sun.COM  *
6710393SSaurabh.Mishra@Sun.COM  * Atheros/Attansic Ethernet controllers have descriptor based TX and RX
6810393SSaurabh.Mishra@Sun.COM  * with an exception of L1E. L1E's RX side is not descriptor based ring.
6910393SSaurabh.Mishra@Sun.COM  * The L1E's RX uses pages (not to be confused with MMU pages) for
7010393SSaurabh.Mishra@Sun.COM  * receiving pkts. The header has four fields :
7110393SSaurabh.Mishra@Sun.COM  *
7210393SSaurabh.Mishra@Sun.COM  *        uint32_t seqno;    Sequence number of the frame.
7310393SSaurabh.Mishra@Sun.COM  *        uint32_t length;   Length of the frame.
7410393SSaurabh.Mishra@Sun.COM  *        uint32_t flags;    Flags
7510393SSaurabh.Mishra@Sun.COM  *        uint32_t vtag;     We don't use hardware VTAG.
7610393SSaurabh.Mishra@Sun.COM  *
7710393SSaurabh.Mishra@Sun.COM  * We use only one queue for RX (each queue can have two pages) and each
7810393SSaurabh.Mishra@Sun.COM  * page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't
7910393SSaurabh.Mishra@Sun.COM  * use zero-copy RX because we are limited to two pages and each page
8010393SSaurabh.Mishra@Sun.COM  * accomodates large number of pkts.
8110393SSaurabh.Mishra@Sun.COM  *
8210393SSaurabh.Mishra@Sun.COM  * The TX side on all three chips is descriptor based ring; and all the
8310393SSaurabh.Mishra@Sun.COM  * more reason to have one driver for these chips.
8410393SSaurabh.Mishra@Sun.COM  *
8510393SSaurabh.Mishra@Sun.COM  * We use two locks - atge_intr_lock and atge_tx_lock. Both the locks
8610393SSaurabh.Mishra@Sun.COM  * should be held if the operation has impact on the driver instance.
8710393SSaurabh.Mishra@Sun.COM  *
8810393SSaurabh.Mishra@Sun.COM  * All the three chips have hash-based multicast filter.
8910393SSaurabh.Mishra@Sun.COM  *
9010393SSaurabh.Mishra@Sun.COM  * We use CMB (Coalescing Message Block) for RX but not for TX as there
9110393SSaurabh.Mishra@Sun.COM  * are some issues with TX. RX CMB is used to get the last descriptor
9210393SSaurabh.Mishra@Sun.COM  * posted by the chip. Each CMB is for a RX page (one queue can have two
9310393SSaurabh.Mishra@Sun.COM  * pages) and are uint32_t (4 bytes) long.
9410393SSaurabh.Mishra@Sun.COM  *
9510393SSaurabh.Mishra@Sun.COM  * The descriptor table should have 32-bit physical address limit due to
9610393SSaurabh.Mishra@Sun.COM  * the limitation of having same high address for TX/RX/SMB/CMB. The
9710393SSaurabh.Mishra@Sun.COM  * TX/RX buffers can be 64-bit.
9810393SSaurabh.Mishra@Sun.COM  *
9910393SSaurabh.Mishra@Sun.COM  * Every DMA memory in atge is represented by atge_dma_t be it TX/RX Buffers
10010393SSaurabh.Mishra@Sun.COM  * or TX/RX descriptor table or SMB/CMB. To keep the code simple, we have
10110393SSaurabh.Mishra@Sun.COM  * kept sgl as 1 so that we get contingous pages from root complex.
102*11353SSaurabh.Mishra@Sun.COM  *
103*11353SSaurabh.Mishra@Sun.COM  * L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are
104*11353SSaurabh.Mishra@Sun.COM  * common with L1E chip (0x1026).
10510393SSaurabh.Mishra@Sun.COM  */
10610393SSaurabh.Mishra@Sun.COM 
10710393SSaurabh.Mishra@Sun.COM /*
10810393SSaurabh.Mishra@Sun.COM  * Function Prototypes for debugging.
10910393SSaurabh.Mishra@Sun.COM  */
11010393SSaurabh.Mishra@Sun.COM void	atge_error(dev_info_t *, char *, ...);
11110393SSaurabh.Mishra@Sun.COM void	atge_debug_func(char *, ...);
11210393SSaurabh.Mishra@Sun.COM 
11310393SSaurabh.Mishra@Sun.COM /*
11410393SSaurabh.Mishra@Sun.COM  * Function Prototypes for driver operations.
11510393SSaurabh.Mishra@Sun.COM  */
11610393SSaurabh.Mishra@Sun.COM static int	atge_resume(dev_info_t *);
11710393SSaurabh.Mishra@Sun.COM static int	atge_add_intr(atge_t *);
11810393SSaurabh.Mishra@Sun.COM static int	atge_alloc_dma(atge_t *);
11910393SSaurabh.Mishra@Sun.COM static void	atge_remove_intr(atge_t *);
12010393SSaurabh.Mishra@Sun.COM static void	atge_free_dma(atge_t *);
12110393SSaurabh.Mishra@Sun.COM static void	atge_device_reset(atge_t *);
12210393SSaurabh.Mishra@Sun.COM static void	atge_device_init(atge_t *);
12310393SSaurabh.Mishra@Sun.COM static void	atge_device_start(atge_t *);
12410393SSaurabh.Mishra@Sun.COM static void	atge_disable_intrs(atge_t *);
12510393SSaurabh.Mishra@Sun.COM atge_dma_t *atge_alloc_a_dma_blk(atge_t *, ddi_dma_attr_t *, int, int);
12610393SSaurabh.Mishra@Sun.COM void	atge_free_a_dma_blk(atge_dma_t *);
12710393SSaurabh.Mishra@Sun.COM static void	atge_rxfilter(atge_t *);
12810393SSaurabh.Mishra@Sun.COM static void	atge_device_reset_l1_l1e(atge_t *);
12910393SSaurabh.Mishra@Sun.COM void	atge_program_ether(atge_t *atgep);
13010393SSaurabh.Mishra@Sun.COM void	atge_device_restart(atge_t *);
131*11353SSaurabh.Mishra@Sun.COM void	atge_device_stop(atge_t *);
13210393SSaurabh.Mishra@Sun.COM static int	atge_send_a_packet(atge_t *, mblk_t *);
13310393SSaurabh.Mishra@Sun.COM static uint32_t	atge_ether_crc(const uint8_t *, int);
13410393SSaurabh.Mishra@Sun.COM 
13510393SSaurabh.Mishra@Sun.COM 
13610393SSaurabh.Mishra@Sun.COM /*
137*11353SSaurabh.Mishra@Sun.COM  * L1E/L2E specific functions.
13810393SSaurabh.Mishra@Sun.COM  */
13910393SSaurabh.Mishra@Sun.COM void	atge_l1e_device_reset(atge_t *);
14010393SSaurabh.Mishra@Sun.COM void	atge_l1e_stop_mac(atge_t *);
14110393SSaurabh.Mishra@Sun.COM int	atge_l1e_alloc_dma(atge_t *);
14210393SSaurabh.Mishra@Sun.COM void	atge_l1e_free_dma(atge_t *);
14310393SSaurabh.Mishra@Sun.COM void	atge_l1e_init_tx_ring(atge_t *);
14410393SSaurabh.Mishra@Sun.COM void	atge_l1e_init_rx_pages(atge_t *);
14510393SSaurabh.Mishra@Sun.COM void	atge_l1e_program_dma(atge_t *);
146*11353SSaurabh.Mishra@Sun.COM void	atge_l1e_send_packet(atge_ring_t *);
14710393SSaurabh.Mishra@Sun.COM mblk_t	*atge_l1e_receive(atge_t *);
148*11353SSaurabh.Mishra@Sun.COM uint_t	atge_l1e_interrupt(caddr_t, caddr_t);
14910393SSaurabh.Mishra@Sun.COM void	atge_l1e_gather_stats(atge_t *);
15010393SSaurabh.Mishra@Sun.COM void	atge_l1e_clear_stats(atge_t *);
15110393SSaurabh.Mishra@Sun.COM 
15210393SSaurabh.Mishra@Sun.COM /*
153*11353SSaurabh.Mishra@Sun.COM  * L1 specific functions.
154*11353SSaurabh.Mishra@Sun.COM  */
155*11353SSaurabh.Mishra@Sun.COM int	atge_l1_alloc_dma(atge_t *);
156*11353SSaurabh.Mishra@Sun.COM void	atge_l1_init_tx_ring(atge_t *);
157*11353SSaurabh.Mishra@Sun.COM void	atge_l1_init_rx_ring(atge_t *);
158*11353SSaurabh.Mishra@Sun.COM void	atge_l1_init_rr_ring(atge_t *);
159*11353SSaurabh.Mishra@Sun.COM void	atge_l1_init_cmb(atge_t *);
160*11353SSaurabh.Mishra@Sun.COM void	atge_l1_init_smb(atge_t *);
161*11353SSaurabh.Mishra@Sun.COM void	atge_l1_program_dma(atge_t *);
162*11353SSaurabh.Mishra@Sun.COM void	atge_l1_stop_tx_mac(atge_t *);
163*11353SSaurabh.Mishra@Sun.COM void	atge_l1_stop_rx_mac(atge_t *);
164*11353SSaurabh.Mishra@Sun.COM uint_t	atge_l1_interrupt(caddr_t, caddr_t);
165*11353SSaurabh.Mishra@Sun.COM void	atge_l1_send_packet(atge_ring_t *);
166*11353SSaurabh.Mishra@Sun.COM 
167*11353SSaurabh.Mishra@Sun.COM 
168*11353SSaurabh.Mishra@Sun.COM /*
16910393SSaurabh.Mishra@Sun.COM  * Function prototyps for MII operations.
17010393SSaurabh.Mishra@Sun.COM  */
17110393SSaurabh.Mishra@Sun.COM uint16_t	atge_mii_read(void *, uint8_t, uint8_t);
17210393SSaurabh.Mishra@Sun.COM void	atge_mii_write(void *, uint8_t, uint8_t, uint16_t);
17310393SSaurabh.Mishra@Sun.COM void	atge_l1e_mii_reset(void *);
174*11353SSaurabh.Mishra@Sun.COM void	atge_l1_mii_reset(void *);
17510393SSaurabh.Mishra@Sun.COM static void	atge_mii_notify(void *, link_state_t);
176*11353SSaurabh.Mishra@Sun.COM void	atge_tx_reclaim(atge_t *atgep, int cons);
177*11353SSaurabh.Mishra@Sun.COM 
178*11353SSaurabh.Mishra@Sun.COM /*
179*11353SSaurabh.Mishra@Sun.COM  * L1E/L2E chip.
180*11353SSaurabh.Mishra@Sun.COM  */
18110393SSaurabh.Mishra@Sun.COM static	mii_ops_t atge_l1e_mii_ops = {
18210393SSaurabh.Mishra@Sun.COM 	MII_OPS_VERSION,
18310393SSaurabh.Mishra@Sun.COM 	atge_mii_read,
18410393SSaurabh.Mishra@Sun.COM 	atge_mii_write,
18510393SSaurabh.Mishra@Sun.COM 	atge_mii_notify,
18610393SSaurabh.Mishra@Sun.COM 	atge_l1e_mii_reset
18710393SSaurabh.Mishra@Sun.COM };
18810393SSaurabh.Mishra@Sun.COM 
18910393SSaurabh.Mishra@Sun.COM /*
190*11353SSaurabh.Mishra@Sun.COM  * L1 chip.
191*11353SSaurabh.Mishra@Sun.COM  */
192*11353SSaurabh.Mishra@Sun.COM static	mii_ops_t atge_l1_mii_ops = {
193*11353SSaurabh.Mishra@Sun.COM 	MII_OPS_VERSION,
194*11353SSaurabh.Mishra@Sun.COM 	atge_mii_read,
195*11353SSaurabh.Mishra@Sun.COM 	atge_mii_write,
196*11353SSaurabh.Mishra@Sun.COM 	atge_mii_notify,
197*11353SSaurabh.Mishra@Sun.COM 	atge_l1_mii_reset
198*11353SSaurabh.Mishra@Sun.COM };
199*11353SSaurabh.Mishra@Sun.COM 
200*11353SSaurabh.Mishra@Sun.COM /*
20110393SSaurabh.Mishra@Sun.COM  * Function Prototypes for MAC callbacks.
20210393SSaurabh.Mishra@Sun.COM  */
20310393SSaurabh.Mishra@Sun.COM static int	atge_m_stat(void *, uint_t, uint64_t *);
20410393SSaurabh.Mishra@Sun.COM static int	atge_m_start(void *);
20510393SSaurabh.Mishra@Sun.COM static void	atge_m_stop(void *);
20610393SSaurabh.Mishra@Sun.COM static int	atge_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
20710393SSaurabh.Mishra@Sun.COM     uint_t, void *, uint_t *);
20810393SSaurabh.Mishra@Sun.COM static int	atge_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
20910393SSaurabh.Mishra@Sun.COM     const void *);
21010393SSaurabh.Mishra@Sun.COM static int	atge_m_unicst(void *, const uint8_t *);
21110393SSaurabh.Mishra@Sun.COM static int	atge_m_multicst(void *, boolean_t, const uint8_t *);
21210393SSaurabh.Mishra@Sun.COM static int	atge_m_promisc(void *, boolean_t);
21310393SSaurabh.Mishra@Sun.COM static mblk_t	*atge_m_tx(void *, mblk_t *);
21410393SSaurabh.Mishra@Sun.COM 
21510393SSaurabh.Mishra@Sun.COM static	mac_callbacks_t	atge_m_callbacks = {
21610393SSaurabh.Mishra@Sun.COM 	MC_SETPROP | MC_GETPROP,
21710393SSaurabh.Mishra@Sun.COM 	atge_m_stat,
21810393SSaurabh.Mishra@Sun.COM 	atge_m_start,
21910393SSaurabh.Mishra@Sun.COM 	atge_m_stop,
22010393SSaurabh.Mishra@Sun.COM 	atge_m_promisc,
22110393SSaurabh.Mishra@Sun.COM 	atge_m_multicst,
22210393SSaurabh.Mishra@Sun.COM 	atge_m_unicst,
22310393SSaurabh.Mishra@Sun.COM 	atge_m_tx,
22410393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_ioctl */
22510393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_getcapab */
22610393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_open */
22710393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_close */
22810393SSaurabh.Mishra@Sun.COM 	atge_m_setprop,
22910393SSaurabh.Mishra@Sun.COM 	atge_m_getprop,
23010393SSaurabh.Mishra@Sun.COM };
23110393SSaurabh.Mishra@Sun.COM 
23210393SSaurabh.Mishra@Sun.COM /*
23310393SSaurabh.Mishra@Sun.COM  * DMA Data access requirements.
23410393SSaurabh.Mishra@Sun.COM  */
23510393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_dev_attr = {
23610393SSaurabh.Mishra@Sun.COM 	DDI_DEVICE_ATTR_V0,
23710393SSaurabh.Mishra@Sun.COM 	DDI_STRUCTURE_LE_ACC,
23810393SSaurabh.Mishra@Sun.COM 	DDI_STRICTORDER_ACC
23910393SSaurabh.Mishra@Sun.COM };
24010393SSaurabh.Mishra@Sun.COM 
24110393SSaurabh.Mishra@Sun.COM /*
24210393SSaurabh.Mishra@Sun.COM  * Buffers should be native endianness.
24310393SSaurabh.Mishra@Sun.COM  */
24410393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_buf_attr = {
24510393SSaurabh.Mishra@Sun.COM 	DDI_DEVICE_ATTR_V0,
24610393SSaurabh.Mishra@Sun.COM 	DDI_NEVERSWAP_ACC,	/* native endianness */
24710393SSaurabh.Mishra@Sun.COM 	DDI_STRICTORDER_ACC
24810393SSaurabh.Mishra@Sun.COM };
24910393SSaurabh.Mishra@Sun.COM 
25010393SSaurabh.Mishra@Sun.COM /*
251*11353SSaurabh.Mishra@Sun.COM  * DMA device attributes. Buffer can be 64-bit.
25210393SSaurabh.Mishra@Sun.COM  */
25310393SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t atge_dma_attr_buf = {
25410393SSaurabh.Mishra@Sun.COM 	DMA_ATTR_V0,		/* dma_attr_version */
25510393SSaurabh.Mishra@Sun.COM 	0,			/* dma_attr_addr_lo */
25610393SSaurabh.Mishra@Sun.COM 	0x00ffffffffffull,	/* dma_attr_addr_hi */
25710393SSaurabh.Mishra@Sun.COM 	0x000000003fffull,	/* dma_attr_count_max */
25810393SSaurabh.Mishra@Sun.COM 	8,			/* dma_attr_align */
25910393SSaurabh.Mishra@Sun.COM 	0x00003ffc,		/* dma_attr_burstsizes */
26010393SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_minxfer */
26110393SSaurabh.Mishra@Sun.COM 	0x0000000027ffull,	/* dma_attr_maxxfer */
26210393SSaurabh.Mishra@Sun.COM 	0x0000ffffffffull,	/* dma_attr_seg */
26310393SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_sgllen */
26410393SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_granular */
26510393SSaurabh.Mishra@Sun.COM 	0			/* dma_attr_flags */
26610393SSaurabh.Mishra@Sun.COM };
26710393SSaurabh.Mishra@Sun.COM 
26810393SSaurabh.Mishra@Sun.COM /*
26910393SSaurabh.Mishra@Sun.COM  * Table of supported devices.
27010393SSaurabh.Mishra@Sun.COM  */
27110393SSaurabh.Mishra@Sun.COM #define	ATGE_VENDOR_ID	0x1969
27210393SSaurabh.Mishra@Sun.COM #define	ATGE_L1E_STR	"Atheros AR8121/8113/8114"
27310393SSaurabh.Mishra@Sun.COM 
27410393SSaurabh.Mishra@Sun.COM static atge_cards_t atge_cards[] = {
27510393SSaurabh.Mishra@Sun.COM 	{ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E},
276*11353SSaurabh.Mishra@Sun.COM 	{ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, "Attansic L1", ATGE_CHIP_L1},
27710393SSaurabh.Mishra@Sun.COM };
27810393SSaurabh.Mishra@Sun.COM 
27910393SSaurabh.Mishra@Sun.COM /*
28010393SSaurabh.Mishra@Sun.COM  * Global Debugging flag. Developer level debugging is done only in DEBUG mode.
28110393SSaurabh.Mishra@Sun.COM  */
28210393SSaurabh.Mishra@Sun.COM int	atge_debug = 1;
28310393SSaurabh.Mishra@Sun.COM 
28410393SSaurabh.Mishra@Sun.COM /*
28510393SSaurabh.Mishra@Sun.COM  * Debugging and error reporting.
28610393SSaurabh.Mishra@Sun.COM  */
28710393SSaurabh.Mishra@Sun.COM void
28810393SSaurabh.Mishra@Sun.COM atge_debug_func(char *fmt, ...)
28910393SSaurabh.Mishra@Sun.COM {
29010393SSaurabh.Mishra@Sun.COM 	va_list	ap;
29110393SSaurabh.Mishra@Sun.COM 	char	buf[256];
29210393SSaurabh.Mishra@Sun.COM 
29310393SSaurabh.Mishra@Sun.COM 	va_start(ap, fmt);
29410393SSaurabh.Mishra@Sun.COM 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
29510393SSaurabh.Mishra@Sun.COM 	va_end(ap);
29610393SSaurabh.Mishra@Sun.COM 
29710393SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE1(atge__debug, char *, buf);
29810393SSaurabh.Mishra@Sun.COM }
29910393SSaurabh.Mishra@Sun.COM 
30010393SSaurabh.Mishra@Sun.COM void
30110393SSaurabh.Mishra@Sun.COM atge_error(dev_info_t *dip, char *fmt, ...)
30210393SSaurabh.Mishra@Sun.COM {
30310393SSaurabh.Mishra@Sun.COM 	va_list	ap;
30410393SSaurabh.Mishra@Sun.COM 	char	buf[256];
30510393SSaurabh.Mishra@Sun.COM 
30610393SSaurabh.Mishra@Sun.COM 	va_start(ap, fmt);
30710393SSaurabh.Mishra@Sun.COM 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
30810393SSaurabh.Mishra@Sun.COM 	va_end(ap);
30910393SSaurabh.Mishra@Sun.COM 
31010393SSaurabh.Mishra@Sun.COM 	if (dip) {
31110393SSaurabh.Mishra@Sun.COM 		cmn_err(CE_WARN, "%s%d: %s",
31210393SSaurabh.Mishra@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
31310393SSaurabh.Mishra@Sun.COM 	} else {
31410393SSaurabh.Mishra@Sun.COM 		cmn_err(CE_WARN, "atge: %s", buf);
31510393SSaurabh.Mishra@Sun.COM 	}
31610393SSaurabh.Mishra@Sun.COM }
31710393SSaurabh.Mishra@Sun.COM 
31810393SSaurabh.Mishra@Sun.COM void
31910393SSaurabh.Mishra@Sun.COM atge_mac_config(atge_t *atgep)
32010393SSaurabh.Mishra@Sun.COM {
32110393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
32210393SSaurabh.Mishra@Sun.COM 	int speed;
32310393SSaurabh.Mishra@Sun.COM 	link_duplex_t ld;
32410393SSaurabh.Mishra@Sun.COM 
32510393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_MAC_CFG);
32610393SSaurabh.Mishra@Sun.COM 	reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC |
32710393SSaurabh.Mishra@Sun.COM 	    ATGE_CFG_SPEED_MASK);
32810393SSaurabh.Mishra@Sun.COM 
32910393SSaurabh.Mishra@Sun.COM 	speed = mii_get_speed(atgep->atge_mii);
33010393SSaurabh.Mishra@Sun.COM 	switch (speed) {
33110393SSaurabh.Mishra@Sun.COM 	case 10:
33210393SSaurabh.Mishra@Sun.COM 	case 100:
33310393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_10_100;
33410393SSaurabh.Mishra@Sun.COM 		break;
33510393SSaurabh.Mishra@Sun.COM 	case 1000:
33610393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_1000;
33710393SSaurabh.Mishra@Sun.COM 		break;
33810393SSaurabh.Mishra@Sun.COM 	}
33910393SSaurabh.Mishra@Sun.COM 
34010393SSaurabh.Mishra@Sun.COM 	ld = mii_get_duplex(atgep->atge_mii);
34110393SSaurabh.Mishra@Sun.COM 	if (ld == LINK_DUPLEX_FULL)
34210393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_FULL_DUPLEX;
34310393SSaurabh.Mishra@Sun.COM 
34410393SSaurabh.Mishra@Sun.COM 	/* Re-enable TX/RX MACs */
345*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
346*11353SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC;
347*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
348*11353SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
349*11353SSaurabh.Mishra@Sun.COM 	}
350*11353SSaurabh.Mishra@Sun.COM 
35110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAC_CFG, reg);
35210393SSaurabh.Mishra@Sun.COM 
35310393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
35410393SSaurabh.Mishra@Sun.COM 		reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
35510393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) <<
35610393SSaurabh.Mishra@Sun.COM 		    IM_TIMER_TX_SHIFT;
35710393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_IM_TIMER, reg);
35810393SSaurabh.Mishra@Sun.COM 	}
35910393SSaurabh.Mishra@Sun.COM 
36010393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mac_cfg is : %x",
36110393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, INL(atgep, ATGE_MAC_CFG)));
36210393SSaurabh.Mishra@Sun.COM }
36310393SSaurabh.Mishra@Sun.COM 
36410393SSaurabh.Mishra@Sun.COM static void
36510393SSaurabh.Mishra@Sun.COM atge_mii_notify(void *arg, link_state_t link)
36610393SSaurabh.Mishra@Sun.COM {
36710393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
36810393SSaurabh.Mishra@Sun.COM 
36910393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x",
37010393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, atgep->atge_link_state, link));
37110393SSaurabh.Mishra@Sun.COM 
37210393SSaurabh.Mishra@Sun.COM 	mac_link_update(atgep->atge_mh, link);
37310393SSaurabh.Mishra@Sun.COM 
37410393SSaurabh.Mishra@Sun.COM 	/*
37510393SSaurabh.Mishra@Sun.COM 	 * Reconfigure MAC if link status is UP now.
37610393SSaurabh.Mishra@Sun.COM 	 */
37710393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
37810393SSaurabh.Mishra@Sun.COM 	if (link == LINK_STATE_UP) {
379*11353SSaurabh.Mishra@Sun.COM 		atgep->atge_link_state = LINK_STATE_UP;
38010393SSaurabh.Mishra@Sun.COM 		atge_mac_config(atgep);
38110393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 0;
38210393SSaurabh.Mishra@Sun.COM 	} else {
38310393SSaurabh.Mishra@Sun.COM 		atgep->atge_link_state = LINK_STATE_DOWN;
384*11353SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_MII_CHECK;
38510393SSaurabh.Mishra@Sun.COM 	}
38610393SSaurabh.Mishra@Sun.COM 
38710393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
38810393SSaurabh.Mishra@Sun.COM 
38910393SSaurabh.Mishra@Sun.COM 	if (link == LINK_STATE_UP)
39010393SSaurabh.Mishra@Sun.COM 		mac_tx_update(atgep->atge_mh);
39110393SSaurabh.Mishra@Sun.COM }
39210393SSaurabh.Mishra@Sun.COM 
393*11353SSaurabh.Mishra@Sun.COM void
394*11353SSaurabh.Mishra@Sun.COM atge_tx_reclaim(atge_t *atgep, int end)
39510393SSaurabh.Mishra@Sun.COM {
396*11353SSaurabh.Mishra@Sun.COM 	atge_tx_desc_t  *txd;
397*11353SSaurabh.Mishra@Sun.COM 	atge_ring_t *r = atgep->atge_tx_ring;
398*11353SSaurabh.Mishra@Sun.COM 	uchar_t *c;
399*11353SSaurabh.Mishra@Sun.COM 	int start;
400*11353SSaurabh.Mishra@Sun.COM 
401*11353SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
402*11353SSaurabh.Mishra@Sun.COM 	ASSERT(r != NULL);
403*11353SSaurabh.Mishra@Sun.COM 
404*11353SSaurabh.Mishra@Sun.COM 	start = r->r_consumer;
405*11353SSaurabh.Mishra@Sun.COM 
406*11353SSaurabh.Mishra@Sun.COM 	if (start == end)
407*11353SSaurabh.Mishra@Sun.COM 		return;
408*11353SSaurabh.Mishra@Sun.COM 
409*11353SSaurabh.Mishra@Sun.COM 	while (start != end) {
410*11353SSaurabh.Mishra@Sun.COM 		r->r_avail_desc++;
411*11353SSaurabh.Mishra@Sun.COM 		if (r->r_avail_desc > ATGE_TX_RING_CNT) {
412*11353SSaurabh.Mishra@Sun.COM 
413*11353SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
414*11353SSaurabh.Mishra@Sun.COM 			    "Reclaim : TX descriptor error");
415*11353SSaurabh.Mishra@Sun.COM 
416*11353SSaurabh.Mishra@Sun.COM 			if (r->r_avail_desc > (ATGE_TX_RING_CNT + 5)) {
417*11353SSaurabh.Mishra@Sun.COM 				atge_device_stop(atgep);
418*11353SSaurabh.Mishra@Sun.COM 				break;
419*11353SSaurabh.Mishra@Sun.COM 			}
42010393SSaurabh.Mishra@Sun.COM 		}
42110393SSaurabh.Mishra@Sun.COM 
422*11353SSaurabh.Mishra@Sun.COM 		c = (uchar_t *)r->r_desc_ring->addr;
423*11353SSaurabh.Mishra@Sun.COM 		c += (sizeof (atge_tx_desc_t) * start);
424*11353SSaurabh.Mishra@Sun.COM 		txd = (atge_tx_desc_t *)c;
425*11353SSaurabh.Mishra@Sun.COM 
42610393SSaurabh.Mishra@Sun.COM 		/*
427*11353SSaurabh.Mishra@Sun.COM 		 * Clearing TX descriptor helps in debugging some strange
428*11353SSaurabh.Mishra@Sun.COM 		 * problems.
42910393SSaurabh.Mishra@Sun.COM 		 */
430*11353SSaurabh.Mishra@Sun.COM 		txd->addr = 0;
431*11353SSaurabh.Mishra@Sun.COM 		txd->len = 0;
432*11353SSaurabh.Mishra@Sun.COM 		txd->flags = 0;
433*11353SSaurabh.Mishra@Sun.COM 
434*11353SSaurabh.Mishra@Sun.COM 		ATGE_INC_SLOT(start, ATGE_TX_RING_CNT);
43510393SSaurabh.Mishra@Sun.COM 	}
43610393SSaurabh.Mishra@Sun.COM 
437*11353SSaurabh.Mishra@Sun.COM 	atgep->atge_tx_ring->r_consumer = start;
438*11353SSaurabh.Mishra@Sun.COM 
439*11353SSaurabh.Mishra@Sun.COM 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
44010393SSaurabh.Mishra@Sun.COM }
44110393SSaurabh.Mishra@Sun.COM 
44210393SSaurabh.Mishra@Sun.COM /*
44310393SSaurabh.Mishra@Sun.COM  * Adds interrupt handler depending upon the type of interrupt supported by
44410393SSaurabh.Mishra@Sun.COM  * the chip.
44510393SSaurabh.Mishra@Sun.COM  */
44610393SSaurabh.Mishra@Sun.COM static int
44710393SSaurabh.Mishra@Sun.COM atge_add_intr_handler(atge_t *atgep, int intr_type)
44810393SSaurabh.Mishra@Sun.COM {
44910393SSaurabh.Mishra@Sun.COM 	int err;
45010393SSaurabh.Mishra@Sun.COM 	int count = 0;
45110393SSaurabh.Mishra@Sun.COM 	int avail = 0;
45210393SSaurabh.Mishra@Sun.COM 	int i;
45310393SSaurabh.Mishra@Sun.COM 	int flag;
45410393SSaurabh.Mishra@Sun.COM 
45510393SSaurabh.Mishra@Sun.COM 	if (intr_type != DDI_INTR_TYPE_FIXED) {
45610393SSaurabh.Mishra@Sun.COM 		err = ddi_intr_get_nintrs(atgep->atge_dip, intr_type, &count);
45710393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
45810393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
45910393SSaurabh.Mishra@Sun.COM 			    "ddi_intr_get_nintrs failed : %d", err);
460*11353SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
46110393SSaurabh.Mishra@Sun.COM 		}
46210393SSaurabh.Mishra@Sun.COM 
46310393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() count : %d",
46410393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__, count));
46510393SSaurabh.Mishra@Sun.COM 
46610393SSaurabh.Mishra@Sun.COM 		err = ddi_intr_get_navail(atgep->atge_dip, intr_type, &avail);
46710393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
46810393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
46910393SSaurabh.Mishra@Sun.COM 			    "ddi_intr_get_navail failed : %d", err);
470*11353SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
47110393SSaurabh.Mishra@Sun.COM 		}
47210393SSaurabh.Mishra@Sun.COM 
47310393SSaurabh.Mishra@Sun.COM 		if (avail < count) {
47410393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip, "count :%d,"
47510393SSaurabh.Mishra@Sun.COM 			    " avail : %d", count, avail);
47610393SSaurabh.Mishra@Sun.COM 		}
47710393SSaurabh.Mishra@Sun.COM 
47810393SSaurabh.Mishra@Sun.COM 		flag = DDI_INTR_ALLOC_STRICT;
47910393SSaurabh.Mishra@Sun.COM 	} else {
48010393SSaurabh.Mishra@Sun.COM 		/*
48110393SSaurabh.Mishra@Sun.COM 		 * DDI_INTR_TYPE_FIXED case.
48210393SSaurabh.Mishra@Sun.COM 		 */
48310393SSaurabh.Mishra@Sun.COM 		count = 1;
48410393SSaurabh.Mishra@Sun.COM 		avail = 1;
48510393SSaurabh.Mishra@Sun.COM 		flag = DDI_INTR_ALLOC_NORMAL;
48610393SSaurabh.Mishra@Sun.COM 	}
48710393SSaurabh.Mishra@Sun.COM 
48810393SSaurabh.Mishra@Sun.COM 	atgep->atge_intr_size = avail * sizeof (ddi_intr_handle_t);
48910393SSaurabh.Mishra@Sun.COM 	atgep->atge_intr_handle = kmem_zalloc(atgep->atge_intr_size, KM_SLEEP);
49010393SSaurabh.Mishra@Sun.COM 
49110393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d",
49210393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, avail, count,
49310393SSaurabh.Mishra@Sun.COM 	    intr_type));
49410393SSaurabh.Mishra@Sun.COM 
49510393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_alloc(atgep->atge_dip, atgep->atge_intr_handle,
49610393SSaurabh.Mishra@Sun.COM 	    intr_type, 0, avail, &atgep->atge_intr_cnt, flag);
49710393SSaurabh.Mishra@Sun.COM 
49810393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
49910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "ddi_intr_alloc failed : %d", err);
50010393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
501*11353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
50210393SSaurabh.Mishra@Sun.COM 	}
50310393SSaurabh.Mishra@Sun.COM 
50410393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: atge_add_intr_handler() after alloc count"
50510393SSaurabh.Mishra@Sun.COM 	    " :%d, avail : %d", atgep->atge_name, count, avail));
50610393SSaurabh.Mishra@Sun.COM 
50710393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_get_pri(atgep->atge_intr_handle[0],
50810393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_intr_pri);
50910393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
51010393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "ddi_intr_get_pri failed:%d", err);
51110393SSaurabh.Mishra@Sun.COM 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
51210393SSaurabh.Mishra@Sun.COM 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
51310393SSaurabh.Mishra@Sun.COM 		}
51410393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
51510393SSaurabh.Mishra@Sun.COM 
516*11353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
51710393SSaurabh.Mishra@Sun.COM 	}
51810393SSaurabh.Mishra@Sun.COM 
51910393SSaurabh.Mishra@Sun.COM 	/*
52010393SSaurabh.Mishra@Sun.COM 	 * Add interrupt handler now.
52110393SSaurabh.Mishra@Sun.COM 	 */
52210393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
523*11353SSaurabh.Mishra@Sun.COM 		if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
524*11353SSaurabh.Mishra@Sun.COM 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
525*11353SSaurabh.Mishra@Sun.COM 			    atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i);
526*11353SSaurabh.Mishra@Sun.COM 		} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
527*11353SSaurabh.Mishra@Sun.COM 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
528*11353SSaurabh.Mishra@Sun.COM 			    atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i);
529*11353SSaurabh.Mishra@Sun.COM 		}
53010393SSaurabh.Mishra@Sun.COM 
53110393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
53210393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
53310393SSaurabh.Mishra@Sun.COM 			    "ddi_intr_add_handler failed : %d", err);
53410393SSaurabh.Mishra@Sun.COM 
53510393SSaurabh.Mishra@Sun.COM 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
53610393SSaurabh.Mishra@Sun.COM 			while (--i >= 0) {
53710393SSaurabh.Mishra@Sun.COM 				(void) ddi_intr_remove_handler(
53810393SSaurabh.Mishra@Sun.COM 				    atgep->atge_intr_handle[i]);
53910393SSaurabh.Mishra@Sun.COM 				(void) ddi_intr_free(
54010393SSaurabh.Mishra@Sun.COM 				    atgep->atge_intr_handle[i]);
54110393SSaurabh.Mishra@Sun.COM 			}
54210393SSaurabh.Mishra@Sun.COM 
54310393SSaurabh.Mishra@Sun.COM 			kmem_free(atgep->atge_intr_handle,
54410393SSaurabh.Mishra@Sun.COM 			    atgep->atge_intr_size);
54510393SSaurabh.Mishra@Sun.COM 
546*11353SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
54710393SSaurabh.Mishra@Sun.COM 		}
54810393SSaurabh.Mishra@Sun.COM 	}
54910393SSaurabh.Mishra@Sun.COM 
55010393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_get_cap(atgep->atge_intr_handle[0],
55110393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_intr_cap);
55210393SSaurabh.Mishra@Sun.COM 
55310393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
55410393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip,
55510393SSaurabh.Mishra@Sun.COM 		    "ddi_intr_get_cap failed : %d", err);
55610393SSaurabh.Mishra@Sun.COM 		atge_remove_intr(atgep);
557*11353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
55810393SSaurabh.Mishra@Sun.COM 	}
55910393SSaurabh.Mishra@Sun.COM 
56010393SSaurabh.Mishra@Sun.COM 	if (intr_type == DDI_INTR_TYPE_FIXED)
56110393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_FIXED_TYPE;
56210393SSaurabh.Mishra@Sun.COM 	else if (intr_type == DDI_INTR_TYPE_MSI)
56310393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_MSI_TYPE;
56410393SSaurabh.Mishra@Sun.COM 	else if (intr_type == DDI_INTR_TYPE_MSIX)
56510393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_MSIX_TYPE;
56610393SSaurabh.Mishra@Sun.COM 
567*11353SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
56810393SSaurabh.Mishra@Sun.COM }
56910393SSaurabh.Mishra@Sun.COM 
57010393SSaurabh.Mishra@Sun.COM void
57110393SSaurabh.Mishra@Sun.COM atge_remove_intr(atge_t *atgep)
57210393SSaurabh.Mishra@Sun.COM {
57310393SSaurabh.Mishra@Sun.COM 	int i;
57410393SSaurabh.Mishra@Sun.COM 	int cap = 0;
57510393SSaurabh.Mishra@Sun.COM 
57610393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_handle == NULL)
57710393SSaurabh.Mishra@Sun.COM 		return;
57810393SSaurabh.Mishra@Sun.COM 
57910393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
58010393SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_block_disable(atgep->atge_intr_handle,
58110393SSaurabh.Mishra@Sun.COM 		    atgep->atge_intr_cnt);
58210393SSaurabh.Mishra@Sun.COM 
58310393SSaurabh.Mishra@Sun.COM 		cap = 1;
58410393SSaurabh.Mishra@Sun.COM 	}
58510393SSaurabh.Mishra@Sun.COM 
58610393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
58710393SSaurabh.Mishra@Sun.COM 		if (cap == 0)
58810393SSaurabh.Mishra@Sun.COM 			(void) ddi_intr_disable(atgep->atge_intr_handle[i]);
58910393SSaurabh.Mishra@Sun.COM 
59010393SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_remove_handler(atgep->atge_intr_handle[i]);
59110393SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_free(atgep->atge_intr_handle[i]);
59210393SSaurabh.Mishra@Sun.COM 	}
59310393SSaurabh.Mishra@Sun.COM 
59410393SSaurabh.Mishra@Sun.COM 	kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
59510393SSaurabh.Mishra@Sun.COM }
59610393SSaurabh.Mishra@Sun.COM 
59710393SSaurabh.Mishra@Sun.COM int
59810393SSaurabh.Mishra@Sun.COM atge_enable_intrs(atge_t *atgep)
59910393SSaurabh.Mishra@Sun.COM {
60010393SSaurabh.Mishra@Sun.COM 	int err;
60110393SSaurabh.Mishra@Sun.COM 	int i;
60210393SSaurabh.Mishra@Sun.COM 
60310393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
60410393SSaurabh.Mishra@Sun.COM 		/*
60510393SSaurabh.Mishra@Sun.COM 		 * Do block enable.
60610393SSaurabh.Mishra@Sun.COM 		 */
60710393SSaurabh.Mishra@Sun.COM 		err = ddi_intr_block_enable(atgep->atge_intr_handle,
60810393SSaurabh.Mishra@Sun.COM 		    atgep->atge_intr_cnt);
60910393SSaurabh.Mishra@Sun.COM 
61010393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
61110393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
61210393SSaurabh.Mishra@Sun.COM 			    "Failed to block enable intrs %d", err);
613*11353SSaurabh.Mishra@Sun.COM 			err = DDI_FAILURE;
61410393SSaurabh.Mishra@Sun.COM 		} else {
615*11353SSaurabh.Mishra@Sun.COM 			err = DDI_SUCCESS;
61610393SSaurabh.Mishra@Sun.COM 		}
61710393SSaurabh.Mishra@Sun.COM 	} else {
61810393SSaurabh.Mishra@Sun.COM 		/*
61910393SSaurabh.Mishra@Sun.COM 		 * Call ddi_intr_enable() for MSI non-block enable.
62010393SSaurabh.Mishra@Sun.COM 		 */
62110393SSaurabh.Mishra@Sun.COM 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
62210393SSaurabh.Mishra@Sun.COM 			err = ddi_intr_enable(atgep->atge_intr_handle[i]);
62310393SSaurabh.Mishra@Sun.COM 			if (err != DDI_SUCCESS) {
62410393SSaurabh.Mishra@Sun.COM 				atge_error(atgep->atge_dip,
62510393SSaurabh.Mishra@Sun.COM 				    "Failed to enable intrs on %d with : %d",
62610393SSaurabh.Mishra@Sun.COM 				    i, err);
62710393SSaurabh.Mishra@Sun.COM 				break;
62810393SSaurabh.Mishra@Sun.COM 			}
62910393SSaurabh.Mishra@Sun.COM 		}
63010393SSaurabh.Mishra@Sun.COM 
63110393SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS)
632*11353SSaurabh.Mishra@Sun.COM 			err = DDI_SUCCESS;
63310393SSaurabh.Mishra@Sun.COM 		else
634*11353SSaurabh.Mishra@Sun.COM 			err = DDI_FAILURE;
63510393SSaurabh.Mishra@Sun.COM 	}
63610393SSaurabh.Mishra@Sun.COM 
63710393SSaurabh.Mishra@Sun.COM 	return (err);
63810393SSaurabh.Mishra@Sun.COM }
63910393SSaurabh.Mishra@Sun.COM 
64010393SSaurabh.Mishra@Sun.COM /*
64110393SSaurabh.Mishra@Sun.COM  * Adds interrupt handler depending on the supported interrupt type by the
64210393SSaurabh.Mishra@Sun.COM  * chip.
64310393SSaurabh.Mishra@Sun.COM  */
64410393SSaurabh.Mishra@Sun.COM static int
64510393SSaurabh.Mishra@Sun.COM atge_add_intr(atge_t *atgep)
64610393SSaurabh.Mishra@Sun.COM {
64710393SSaurabh.Mishra@Sun.COM 	int	err;
64810393SSaurabh.Mishra@Sun.COM 
64910393SSaurabh.Mishra@Sun.COM 	/*
65010393SSaurabh.Mishra@Sun.COM 	 * Get the supported interrupt types.
65110393SSaurabh.Mishra@Sun.COM 	 */
65210393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_get_supported_types(atgep->atge_dip,
65310393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_intr_types);
65410393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
65510393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip,
65610393SSaurabh.Mishra@Sun.COM 		    "ddi_intr_get_supported_types failed : %d", err);
657*11353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
65810393SSaurabh.Mishra@Sun.COM 	}
65910393SSaurabh.Mishra@Sun.COM 
66010393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d",
66110393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, atgep->atge_intr_types));
66210393SSaurabh.Mishra@Sun.COM 
66310393SSaurabh.Mishra@Sun.COM 
66410393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSIX) {
66510393SSaurabh.Mishra@Sun.COM 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSIX);
666*11353SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS) {
66710393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: Using MSIx for interrupt",
66810393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name));
66910393SSaurabh.Mishra@Sun.COM 			return (err);
67010393SSaurabh.Mishra@Sun.COM 		}
67110393SSaurabh.Mishra@Sun.COM 	}
67210393SSaurabh.Mishra@Sun.COM 
67310393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSI) {
67410393SSaurabh.Mishra@Sun.COM 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSI);
675*11353SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS) {
67610393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: Using MSI for interrupt",
67710393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name));
67810393SSaurabh.Mishra@Sun.COM 			return (err);
67910393SSaurabh.Mishra@Sun.COM 		}
68010393SSaurabh.Mishra@Sun.COM 	}
68110393SSaurabh.Mishra@Sun.COM 
682*11353SSaurabh.Mishra@Sun.COM 	err = DDI_FAILURE;
68310393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_types & DDI_INTR_TYPE_FIXED) {
68410393SSaurabh.Mishra@Sun.COM 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_FIXED);
685*11353SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS) {
68610393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: Using FIXED type for interrupt",
68710393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name));
68810393SSaurabh.Mishra@Sun.COM 			return (err);
68910393SSaurabh.Mishra@Sun.COM 		}
69010393SSaurabh.Mishra@Sun.COM 	}
69110393SSaurabh.Mishra@Sun.COM 
69210393SSaurabh.Mishra@Sun.COM 	return (err);
69310393SSaurabh.Mishra@Sun.COM }
69410393SSaurabh.Mishra@Sun.COM 
69510393SSaurabh.Mishra@Sun.COM int
69610393SSaurabh.Mishra@Sun.COM atge_identify_hardware(atge_t *atgep)
69710393SSaurabh.Mishra@Sun.COM {
69810393SSaurabh.Mishra@Sun.COM 	uint16_t vid, did;
69910393SSaurabh.Mishra@Sun.COM 	int i;
70010393SSaurabh.Mishra@Sun.COM 
70110393SSaurabh.Mishra@Sun.COM 	vid = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_VENID);
70210393SSaurabh.Mishra@Sun.COM 	did = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_DEVID);
70310393SSaurabh.Mishra@Sun.COM 
70410393SSaurabh.Mishra@Sun.COM 	atgep->atge_model = 0;
70510393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) {
70610393SSaurabh.Mishra@Sun.COM 		if (atge_cards[i].vendor_id == vid &&
70710393SSaurabh.Mishra@Sun.COM 		    atge_cards[i].device_id == did) {
70810393SSaurabh.Mishra@Sun.COM 			atgep->atge_model = atge_cards[i].model;
70910393SSaurabh.Mishra@Sun.COM 			atgep->atge_revid =
71010393SSaurabh.Mishra@Sun.COM 			    pci_config_get8(atgep->atge_conf_handle,
71110393SSaurabh.Mishra@Sun.COM 			    PCI_CONF_REVID);
71210393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
71310393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name, __func__, vid, did,
71410393SSaurabh.Mishra@Sun.COM 			    atgep->atge_model));
71510393SSaurabh.Mishra@Sun.COM 
716*11353SSaurabh.Mishra@Sun.COM 			return (DDI_SUCCESS);
71710393SSaurabh.Mishra@Sun.COM 		}
71810393SSaurabh.Mishra@Sun.COM 	}
71910393SSaurabh.Mishra@Sun.COM 
72010393SSaurabh.Mishra@Sun.COM 	atge_error(atgep->atge_dip, "atge driver is attaching to unknown"
72110393SSaurabh.Mishra@Sun.COM 	    " pci%d,%d vendor/device-id card", vid, did);
72210393SSaurabh.Mishra@Sun.COM 
72310393SSaurabh.Mishra@Sun.COM 	/*
724*11353SSaurabh.Mishra@Sun.COM 	 * Assume it's L1 chip.
72510393SSaurabh.Mishra@Sun.COM 	 */
726*11353SSaurabh.Mishra@Sun.COM 	atgep->atge_model = ATGE_CHIP_L1;
72710393SSaurabh.Mishra@Sun.COM 	atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle,
72810393SSaurabh.Mishra@Sun.COM 	    PCI_CONF_REVID);
72910393SSaurabh.Mishra@Sun.COM 
73010393SSaurabh.Mishra@Sun.COM 	/*
73110393SSaurabh.Mishra@Sun.COM 	 * We will leave the decision to caller.
73210393SSaurabh.Mishra@Sun.COM 	 */
733*11353SSaurabh.Mishra@Sun.COM 	return (DDI_FAILURE);
73410393SSaurabh.Mishra@Sun.COM }
73510393SSaurabh.Mishra@Sun.COM 
73610393SSaurabh.Mishra@Sun.COM int
73710393SSaurabh.Mishra@Sun.COM atge_get_macaddr(atge_t *atgep)
73810393SSaurabh.Mishra@Sun.COM {
73910393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
74010393SSaurabh.Mishra@Sun.COM 
74110393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_SPI_CTRL);
74210393SSaurabh.Mishra@Sun.COM 	if ((reg & SPI_VPD_ENB) != 0) {
74310393SSaurabh.Mishra@Sun.COM 		/*
74410393SSaurabh.Mishra@Sun.COM 		 * Get VPD stored in TWSI EEPROM.
74510393SSaurabh.Mishra@Sun.COM 		 */
74610393SSaurabh.Mishra@Sun.COM 		reg &= ~SPI_VPD_ENB;
74710393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_SPI_CTRL, reg);
74810393SSaurabh.Mishra@Sun.COM 
74910393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s called Get VPD", atgep->atge_name, __func__));
75010393SSaurabh.Mishra@Sun.COM 	}
75110393SSaurabh.Mishra@Sun.COM 
75210393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[5] = INB(atgep, ATGE_PAR0 + 0);
75310393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[4] = INB(atgep, ATGE_PAR0 + 1);
75410393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[3] = INB(atgep, ATGE_PAR0 + 2);
75510393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[2] = INB(atgep, ATGE_PAR0 + 3);
75610393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[1] = INB(atgep, ATGE_PAR1 + 0);
75710393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[0] = INB(atgep, ATGE_PAR1 + 1);
75810393SSaurabh.Mishra@Sun.COM 
75910393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x",
76010393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__,
76110393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[0],
76210393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[1],
76310393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[2],
76410393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[3],
76510393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[4],
76610393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[5]));
76710393SSaurabh.Mishra@Sun.COM 
76810393SSaurabh.Mishra@Sun.COM 	bcopy(atgep->atge_ether_addr, atgep->atge_dev_addr, ETHERADDRL);
76910393SSaurabh.Mishra@Sun.COM 
770*11353SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
77110393SSaurabh.Mishra@Sun.COM }
77210393SSaurabh.Mishra@Sun.COM 
77310393SSaurabh.Mishra@Sun.COM /*
77410393SSaurabh.Mishra@Sun.COM  * Reset functionality for L1 and L1E. It's same.
77510393SSaurabh.Mishra@Sun.COM  */
77610393SSaurabh.Mishra@Sun.COM static void
77710393SSaurabh.Mishra@Sun.COM atge_device_reset(atge_t *atgep)
77810393SSaurabh.Mishra@Sun.COM {
77910393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E ||
78010393SSaurabh.Mishra@Sun.COM 	    ATGE_MODEL(atgep) == ATGE_CHIP_L1)
78110393SSaurabh.Mishra@Sun.COM 		atge_device_reset_l1_l1e(atgep);
78210393SSaurabh.Mishra@Sun.COM }
78310393SSaurabh.Mishra@Sun.COM 
78410393SSaurabh.Mishra@Sun.COM void
78510393SSaurabh.Mishra@Sun.COM atge_device_reset_l1_l1e(atge_t *atgep)
78610393SSaurabh.Mishra@Sun.COM {
78710393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
78810393SSaurabh.Mishra@Sun.COM 	int t;
78910393SSaurabh.Mishra@Sun.COM 
79010393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
79110393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_MASTER_CFG);
79210393SSaurabh.Mishra@Sun.COM 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
79310393SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
79410393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, ATGE_MASTER_CFG);
79510393SSaurabh.Mishra@Sun.COM 		if ((reg & MASTER_RESET) == 0)
79610393SSaurabh.Mishra@Sun.COM 			break;
79710393SSaurabh.Mishra@Sun.COM 	}
79810393SSaurabh.Mishra@Sun.COM 
79910393SSaurabh.Mishra@Sun.COM 	if (t == 0) {
80010393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, " master reset timeout reg : %x",
80110393SSaurabh.Mishra@Sun.COM 		    reg);
80210393SSaurabh.Mishra@Sun.COM 	}
80310393SSaurabh.Mishra@Sun.COM 
80410393SSaurabh.Mishra@Sun.COM 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
80510393SSaurabh.Mishra@Sun.COM 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
80610393SSaurabh.Mishra@Sun.COM 			break;
80710393SSaurabh.Mishra@Sun.COM 
80810393SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
80910393SSaurabh.Mishra@Sun.COM 	}
81010393SSaurabh.Mishra@Sun.COM 
81110393SSaurabh.Mishra@Sun.COM 	if (t == 0) {
81210393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "device reset timeout reg : %x",
81310393SSaurabh.Mishra@Sun.COM 		    reg);
81410393SSaurabh.Mishra@Sun.COM 	}
81510393SSaurabh.Mishra@Sun.COM 
81610393SSaurabh.Mishra@Sun.COM 	/*
81710393SSaurabh.Mishra@Sun.COM 	 * Initialize PCIe module. These values came from FreeBSD and
81810393SSaurabh.Mishra@Sun.COM 	 * we don't know the meaning of it.
81910393SSaurabh.Mishra@Sun.COM 	 */
82010393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, 0x12FC, 0x6500);
82110393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, 0x1008) | 0x8000;
82210393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, 0x1008, reg);
82310393SSaurabh.Mishra@Sun.COM 
82410393SSaurabh.Mishra@Sun.COM 	/*
82510393SSaurabh.Mishra@Sun.COM 	 * Get chip revision.
82610393SSaurabh.Mishra@Sun.COM 	 */
82710393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_rev = INL(atgep, ATGE_MASTER_CFG) >>
82810393SSaurabh.Mishra@Sun.COM 	    MASTER_CHIP_REV_SHIFT;
82910393SSaurabh.Mishra@Sun.COM 
83010393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s reset successfully rev : %x", atgep->atge_name,
83110393SSaurabh.Mishra@Sun.COM 	    __func__, atgep->atge_chip_rev));
83210393SSaurabh.Mishra@Sun.COM }
83310393SSaurabh.Mishra@Sun.COM 
83410393SSaurabh.Mishra@Sun.COM /*
83510393SSaurabh.Mishra@Sun.COM  * DMA allocation for L1 and L1E is bit different since L1E uses RX pages
83610393SSaurabh.Mishra@Sun.COM  * instead of descriptor based RX model.
83710393SSaurabh.Mishra@Sun.COM  */
83810393SSaurabh.Mishra@Sun.COM static int
83910393SSaurabh.Mishra@Sun.COM atge_alloc_dma(atge_t *atgep)
84010393SSaurabh.Mishra@Sun.COM {
841*11353SSaurabh.Mishra@Sun.COM 	int err = DDI_FAILURE;
84210393SSaurabh.Mishra@Sun.COM 
84310393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
84410393SSaurabh.Mishra@Sun.COM 		err = atge_l1e_alloc_dma(atgep);
845*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
846*11353SSaurabh.Mishra@Sun.COM 		err = atge_l1_alloc_dma(atgep);
84710393SSaurabh.Mishra@Sun.COM 	}
84810393SSaurabh.Mishra@Sun.COM 
84910393SSaurabh.Mishra@Sun.COM 	return (err);
85010393SSaurabh.Mishra@Sun.COM }
85110393SSaurabh.Mishra@Sun.COM 
85210393SSaurabh.Mishra@Sun.COM static void
85310393SSaurabh.Mishra@Sun.COM atge_free_dma(atge_t *atgep)
85410393SSaurabh.Mishra@Sun.COM {
85510393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
85610393SSaurabh.Mishra@Sun.COM 		atge_l1e_free_dma(atgep);
85710393SSaurabh.Mishra@Sun.COM 	}
85810393SSaurabh.Mishra@Sun.COM }
85910393SSaurabh.Mishra@Sun.COM 
86010393SSaurabh.Mishra@Sun.COM /*
86110393SSaurabh.Mishra@Sun.COM  * Attach entry point in the driver.
86210393SSaurabh.Mishra@Sun.COM  */
86310393SSaurabh.Mishra@Sun.COM static int
86410393SSaurabh.Mishra@Sun.COM atge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
86510393SSaurabh.Mishra@Sun.COM {
86610393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
86710393SSaurabh.Mishra@Sun.COM 	mac_register_t	*macreg;
86810393SSaurabh.Mishra@Sun.COM 	int	instance;
86910393SSaurabh.Mishra@Sun.COM 	uint16_t cap_ptr;
87010393SSaurabh.Mishra@Sun.COM 	uint16_t burst;
87110393SSaurabh.Mishra@Sun.COM 	int err;
87210393SSaurabh.Mishra@Sun.COM 	mii_ops_t *mii_ops;
87310393SSaurabh.Mishra@Sun.COM 
87410393SSaurabh.Mishra@Sun.COM 	instance =  ddi_get_instance(devinfo);
87510393SSaurabh.Mishra@Sun.COM 
87610393SSaurabh.Mishra@Sun.COM 	switch (cmd) {
87710393SSaurabh.Mishra@Sun.COM 	default:
87810393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
87910393SSaurabh.Mishra@Sun.COM 
88010393SSaurabh.Mishra@Sun.COM 	case DDI_RESUME:
88110393SSaurabh.Mishra@Sun.COM 		return (atge_resume(devinfo));
88210393SSaurabh.Mishra@Sun.COM 
88310393SSaurabh.Mishra@Sun.COM 	case DDI_ATTACH:
88410393SSaurabh.Mishra@Sun.COM 		ddi_set_driver_private(devinfo, NULL);
88510393SSaurabh.Mishra@Sun.COM 		break;
88610393SSaurabh.Mishra@Sun.COM 	}
88710393SSaurabh.Mishra@Sun.COM 
88810393SSaurabh.Mishra@Sun.COM 	atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP);
88910393SSaurabh.Mishra@Sun.COM 	ddi_set_driver_private(devinfo, atgep);
89010393SSaurabh.Mishra@Sun.COM 	atgep->atge_dip = devinfo;
89110393SSaurabh.Mishra@Sun.COM 
89210393SSaurabh.Mishra@Sun.COM 	/*
89310393SSaurabh.Mishra@Sun.COM 	 * Setup name and instance number to be used for debugging and
89410393SSaurabh.Mishra@Sun.COM 	 * error reporting.
89510393SSaurabh.Mishra@Sun.COM 	 */
89610393SSaurabh.Mishra@Sun.COM 	(void) snprintf(atgep->atge_name, sizeof (atgep->atge_name), "%s%d",
89710393SSaurabh.Mishra@Sun.COM 	    "atge", instance);
89810393SSaurabh.Mishra@Sun.COM 
89910393SSaurabh.Mishra@Sun.COM 
90010393SSaurabh.Mishra@Sun.COM 	/*
90110393SSaurabh.Mishra@Sun.COM 	 * Map PCI config space.
90210393SSaurabh.Mishra@Sun.COM 	 */
90310393SSaurabh.Mishra@Sun.COM 	err = pci_config_setup(devinfo, &atgep->atge_conf_handle);
90410393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
90510393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "pci_config_setup() failed");
90610393SSaurabh.Mishra@Sun.COM 		goto fail1;
90710393SSaurabh.Mishra@Sun.COM 	}
90810393SSaurabh.Mishra@Sun.COM 
90910393SSaurabh.Mishra@Sun.COM 	(void) atge_identify_hardware(atgep);
91010393SSaurabh.Mishra@Sun.COM 
91110393SSaurabh.Mishra@Sun.COM 	/*
91210393SSaurabh.Mishra@Sun.COM 	 * Map Device registers.
91310393SSaurabh.Mishra@Sun.COM 	 */
91410393SSaurabh.Mishra@Sun.COM 	err = ddi_regs_map_setup(devinfo, ATGE_PCI_REG_NUMBER,
91510393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_io_regs, 0, 0, &atge_dev_attr, &atgep->atge_io_handle);
91610393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
91710393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "ddi_regs_map_setup() failed");
91810393SSaurabh.Mishra@Sun.COM 		goto fail2;
91910393SSaurabh.Mishra@Sun.COM 	}
92010393SSaurabh.Mishra@Sun.COM 
92110393SSaurabh.Mishra@Sun.COM 	/*
92210393SSaurabh.Mishra@Sun.COM 	 * Add interrupt and its associated handler.
92310393SSaurabh.Mishra@Sun.COM 	 */
92410393SSaurabh.Mishra@Sun.COM 	err = atge_add_intr(atgep);
925*11353SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
92610393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "Failed to add interrupt handler");
92710393SSaurabh.Mishra@Sun.COM 		goto fail3;
92810393SSaurabh.Mishra@Sun.COM 	}
92910393SSaurabh.Mishra@Sun.COM 
93010393SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_intr_lock, NULL, MUTEX_DRIVER,
93110393SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(atgep->atge_intr_pri));
93210393SSaurabh.Mishra@Sun.COM 
93310393SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_tx_lock, NULL, MUTEX_DRIVER,
93410393SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(atgep->atge_intr_pri));
93510393SSaurabh.Mishra@Sun.COM 
93610393SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_rx_lock, NULL, MUTEX_DRIVER,
93710393SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(atgep->atge_intr_pri));
93810393SSaurabh.Mishra@Sun.COM 
93910393SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_mii_lock, NULL, MUTEX_DRIVER, NULL);
94010393SSaurabh.Mishra@Sun.COM 
941*11353SSaurabh.Mishra@Sun.COM 	/*
942*11353SSaurabh.Mishra@Sun.COM 	 * Used to lock down MBOX register on L1 chip since RX consumer,
943*11353SSaurabh.Mishra@Sun.COM 	 * TX producer and RX return ring consumer are shared.
944*11353SSaurabh.Mishra@Sun.COM 	 */
945*11353SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_mbox_lock, NULL, MUTEX_DRIVER,
946*11353SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(atgep->atge_intr_pri));
947*11353SSaurabh.Mishra@Sun.COM 
94810393SSaurabh.Mishra@Sun.COM 	atgep->atge_link_state = LINK_STATE_DOWN;
94910393SSaurabh.Mishra@Sun.COM 	atgep->atge_mtu = ETHERMTU;
95010393SSaurabh.Mishra@Sun.COM 
951*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
952*11353SSaurabh.Mishra@Sun.COM 		if (atgep->atge_revid > 0xF0) {
953*11353SSaurabh.Mishra@Sun.COM 			/* L2E Rev. B. AR8114 */
954*11353SSaurabh.Mishra@Sun.COM 			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
95510393SSaurabh.Mishra@Sun.COM 		} else {
956*11353SSaurabh.Mishra@Sun.COM 			if ((INL(atgep, L1E_PHY_STATUS) &
957*11353SSaurabh.Mishra@Sun.COM 			    PHY_STATUS_100M) != 0) {
958*11353SSaurabh.Mishra@Sun.COM 				/* L1E AR8121 */
959*11353SSaurabh.Mishra@Sun.COM 				atgep->atge_flags |= ATGE_FLAG_JUMBO;
960*11353SSaurabh.Mishra@Sun.COM 			} else {
961*11353SSaurabh.Mishra@Sun.COM 				/* L2E Rev. A. AR8113 */
962*11353SSaurabh.Mishra@Sun.COM 				atgep->atge_flags |= ATGE_FLAG_FASTETHER;
963*11353SSaurabh.Mishra@Sun.COM 			}
96410393SSaurabh.Mishra@Sun.COM 		}
96510393SSaurabh.Mishra@Sun.COM 	}
96610393SSaurabh.Mishra@Sun.COM 
96710393SSaurabh.Mishra@Sun.COM 	/*
96810393SSaurabh.Mishra@Sun.COM 	 * Get DMA parameters from PCIe device control register.
96910393SSaurabh.Mishra@Sun.COM 	 */
97010393SSaurabh.Mishra@Sun.COM 	err = PCI_CAP_LOCATE(atgep->atge_conf_handle, PCI_CAP_ID_PCI_E,
97110393SSaurabh.Mishra@Sun.COM 	    &cap_ptr);
97210393SSaurabh.Mishra@Sun.COM 
97310393SSaurabh.Mishra@Sun.COM 	if (err == DDI_FAILURE) {
97410393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_rd_burst = DMA_CFG_RD_BURST_128;
97510393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_wr_burst = DMA_CFG_WR_BURST_128;
97610393SSaurabh.Mishra@Sun.COM 	} else {
97710393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_FLAG_PCIE;
97810393SSaurabh.Mishra@Sun.COM 		burst = pci_config_get16(atgep->atge_conf_handle,
97910393SSaurabh.Mishra@Sun.COM 		    cap_ptr + 0x08);
98010393SSaurabh.Mishra@Sun.COM 
98110393SSaurabh.Mishra@Sun.COM 		/*
98210393SSaurabh.Mishra@Sun.COM 		 * Max read request size.
98310393SSaurabh.Mishra@Sun.COM 		 */
98410393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_rd_burst = ((burst >> 12) & 0x07) <<
98510393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_RD_BURST_SHIFT;
98610393SSaurabh.Mishra@Sun.COM 
98710393SSaurabh.Mishra@Sun.COM 		/*
98810393SSaurabh.Mishra@Sun.COM 		 * Max Payload Size.
98910393SSaurabh.Mishra@Sun.COM 		 */
99010393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_wr_burst = ((burst >> 5) & 0x07) <<
99110393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_WR_BURST_SHIFT;
99210393SSaurabh.Mishra@Sun.COM 
99310393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() MRR : %d, MPS : %d",
99410393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__,
99510393SSaurabh.Mishra@Sun.COM 		    (128 << ((burst >> 12) & 0x07)),
99610393SSaurabh.Mishra@Sun.COM 		    (128 << ((burst >> 5) & 0x07))));
99710393SSaurabh.Mishra@Sun.COM 	}
99810393SSaurabh.Mishra@Sun.COM 
99910393SSaurabh.Mishra@Sun.COM 	/*
100010393SSaurabh.Mishra@Sun.COM 	 * Allocate DMA resources.
100110393SSaurabh.Mishra@Sun.COM 	 */
100210393SSaurabh.Mishra@Sun.COM 	err = atge_alloc_dma(atgep);
1003*11353SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
100410393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "Failed to allocate DMA resources");
100510393SSaurabh.Mishra@Sun.COM 		goto fail4;
100610393SSaurabh.Mishra@Sun.COM 	}
100710393SSaurabh.Mishra@Sun.COM 
100810393SSaurabh.Mishra@Sun.COM 	/*
100910393SSaurabh.Mishra@Sun.COM 	 * Get station address.
101010393SSaurabh.Mishra@Sun.COM 	 */
101110393SSaurabh.Mishra@Sun.COM 	(void) atge_get_macaddr(atgep);
101210393SSaurabh.Mishra@Sun.COM 
101310393SSaurabh.Mishra@Sun.COM 	/*
101410393SSaurabh.Mishra@Sun.COM 	 * Setup MII.
101510393SSaurabh.Mishra@Sun.COM 	 */
101610393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
101710393SSaurabh.Mishra@Sun.COM 		mii_ops = &atge_l1e_mii_ops;
1018*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1019*11353SSaurabh.Mishra@Sun.COM 		mii_ops = &atge_l1_mii_ops;
102010393SSaurabh.Mishra@Sun.COM 	}
102110393SSaurabh.Mishra@Sun.COM 
102210393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_mii = mii_alloc(atgep, devinfo,
102310393SSaurabh.Mishra@Sun.COM 	    mii_ops)) == NULL) {
102410393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "mii_alloc() failed");
102510393SSaurabh.Mishra@Sun.COM 		goto fail4;
102610393SSaurabh.Mishra@Sun.COM 	}
102710393SSaurabh.Mishra@Sun.COM 
102810393SSaurabh.Mishra@Sun.COM 	/*
102910393SSaurabh.Mishra@Sun.COM 	 * Register with MAC layer.
103010393SSaurabh.Mishra@Sun.COM 	 */
103110393SSaurabh.Mishra@Sun.COM 	if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
103210393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "mac_alloc() failed due to version");
103310393SSaurabh.Mishra@Sun.COM 		goto fail4;
103410393SSaurabh.Mishra@Sun.COM 	}
103510393SSaurabh.Mishra@Sun.COM 
103610393SSaurabh.Mishra@Sun.COM 	macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
103710393SSaurabh.Mishra@Sun.COM 	macreg->m_driver = atgep;
103810393SSaurabh.Mishra@Sun.COM 	macreg->m_dip = devinfo;
103910393SSaurabh.Mishra@Sun.COM 	macreg->m_instance = instance;
104010393SSaurabh.Mishra@Sun.COM 	macreg->m_src_addr = atgep->atge_ether_addr;
104110393SSaurabh.Mishra@Sun.COM 	macreg->m_callbacks = &atge_m_callbacks;
104210393SSaurabh.Mishra@Sun.COM 	macreg->m_min_sdu = 0;
104310393SSaurabh.Mishra@Sun.COM 	macreg->m_max_sdu = atgep->atge_mtu;
104410393SSaurabh.Mishra@Sun.COM 	macreg->m_margin = VLAN_TAGSZ;
104510393SSaurabh.Mishra@Sun.COM 
104610393SSaurabh.Mishra@Sun.COM 	if ((err = mac_register(macreg, &atgep->atge_mh)) != 0) {
104710393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "mac_register() failed with :%d", err);
104810393SSaurabh.Mishra@Sun.COM 		mac_free(macreg);
104910393SSaurabh.Mishra@Sun.COM 		goto fail4;
105010393SSaurabh.Mishra@Sun.COM 	}
105110393SSaurabh.Mishra@Sun.COM 
105210393SSaurabh.Mishra@Sun.COM 	mac_free(macreg);
105310393SSaurabh.Mishra@Sun.COM 
105410393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() driver attached successfully",
105510393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__));
105610393SSaurabh.Mishra@Sun.COM 
105710393SSaurabh.Mishra@Sun.COM 	atge_device_reset(atgep);
105810393SSaurabh.Mishra@Sun.COM 
105910393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state = ATGE_CHIP_INITIALIZED;
106010393SSaurabh.Mishra@Sun.COM 
106110393SSaurabh.Mishra@Sun.COM 	/*
106210393SSaurabh.Mishra@Sun.COM 	 * At last - enable interrupts.
106310393SSaurabh.Mishra@Sun.COM 	 */
106410393SSaurabh.Mishra@Sun.COM 	err = atge_enable_intrs(atgep);
1065*11353SSaurabh.Mishra@Sun.COM 	if (err == DDI_FAILURE) {
106610393SSaurabh.Mishra@Sun.COM 		goto fail5;
106710393SSaurabh.Mishra@Sun.COM 	}
106810393SSaurabh.Mishra@Sun.COM 
106910393SSaurabh.Mishra@Sun.COM 	/*
107010393SSaurabh.Mishra@Sun.COM 	 * Reset the PHY before starting.
107110393SSaurabh.Mishra@Sun.COM 	 */
107210393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
107310393SSaurabh.Mishra@Sun.COM 		atge_l1e_mii_reset(atgep);
1074*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1075*11353SSaurabh.Mishra@Sun.COM 		atge_l1_mii_reset(atgep);
107610393SSaurabh.Mishra@Sun.COM 	}
107710393SSaurabh.Mishra@Sun.COM 
107810393SSaurabh.Mishra@Sun.COM 	/*
107910393SSaurabh.Mishra@Sun.COM 	 * Let the PHY run.
108010393SSaurabh.Mishra@Sun.COM 	 */
108110393SSaurabh.Mishra@Sun.COM 	mii_start(atgep->atge_mii);
108210393SSaurabh.Mishra@Sun.COM 
108310393SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
108410393SSaurabh.Mishra@Sun.COM 
108510393SSaurabh.Mishra@Sun.COM fail5:
108610393SSaurabh.Mishra@Sun.COM 	(void) mac_unregister(atgep->atge_mh);
108710393SSaurabh.Mishra@Sun.COM 	atge_device_stop(atgep);
108810393SSaurabh.Mishra@Sun.COM 	mii_stop(atgep->atge_mii);
108910393SSaurabh.Mishra@Sun.COM 	mii_free(atgep->atge_mii);
109010393SSaurabh.Mishra@Sun.COM fail4:
109110393SSaurabh.Mishra@Sun.COM 	atge_free_dma(atgep);
109210393SSaurabh.Mishra@Sun.COM 	mutex_destroy(&atgep->atge_intr_lock);
109310393SSaurabh.Mishra@Sun.COM 	mutex_destroy(&atgep->atge_tx_lock);
109410393SSaurabh.Mishra@Sun.COM 	mutex_destroy(&atgep->atge_rx_lock);
109510393SSaurabh.Mishra@Sun.COM 	atge_remove_intr(atgep);
109610393SSaurabh.Mishra@Sun.COM fail3:
109710393SSaurabh.Mishra@Sun.COM 	ddi_regs_map_free(&atgep->atge_io_handle);
109810393SSaurabh.Mishra@Sun.COM fail2:
109910393SSaurabh.Mishra@Sun.COM 	pci_config_teardown(&atgep->atge_conf_handle);
110010393SSaurabh.Mishra@Sun.COM fail1:
110110393SSaurabh.Mishra@Sun.COM 	if (atgep)
110210393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep, sizeof (atge_t));
110310393SSaurabh.Mishra@Sun.COM 
110410393SSaurabh.Mishra@Sun.COM 	return (DDI_FAILURE);
110510393SSaurabh.Mishra@Sun.COM }
110610393SSaurabh.Mishra@Sun.COM 
110710393SSaurabh.Mishra@Sun.COM static int
110810393SSaurabh.Mishra@Sun.COM atge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
110910393SSaurabh.Mishra@Sun.COM {
111010393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
111110393SSaurabh.Mishra@Sun.COM 
111210393SSaurabh.Mishra@Sun.COM 	atgep = ddi_get_driver_private(dip);
111310393SSaurabh.Mishra@Sun.COM 	if (atgep == NULL) {
111410393SSaurabh.Mishra@Sun.COM 		atge_error(dip, "No soft state in detach");
111510393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
111610393SSaurabh.Mishra@Sun.COM 	}
111710393SSaurabh.Mishra@Sun.COM 
111810393SSaurabh.Mishra@Sun.COM 	switch (cmd) {
111910393SSaurabh.Mishra@Sun.COM 	case DDI_DETACH:
112010393SSaurabh.Mishra@Sun.COM 		mii_stop(atgep->atge_mii);
112110393SSaurabh.Mishra@Sun.COM 
112210393SSaurabh.Mishra@Sun.COM 		/*
112310393SSaurabh.Mishra@Sun.COM 		 * First unregister with MAC layer before stopping DMA
112410393SSaurabh.Mishra@Sun.COM 		 */
112510393SSaurabh.Mishra@Sun.COM 		if (mac_unregister(atgep->atge_mh) != DDI_SUCCESS)
112610393SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
112710393SSaurabh.Mishra@Sun.COM 
112810393SSaurabh.Mishra@Sun.COM 		atgep->atge_mh = NULL;
112910393SSaurabh.Mishra@Sun.COM 
113010393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_intr_lock);
113110393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_tx_lock);
113210393SSaurabh.Mishra@Sun.COM 		atge_device_stop(atgep);
113310393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
113410393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_intr_lock);
113510393SSaurabh.Mishra@Sun.COM 
113610393SSaurabh.Mishra@Sun.COM 		mii_free(atgep->atge_mii);
113710393SSaurabh.Mishra@Sun.COM 		atge_free_dma(atgep);
113810393SSaurabh.Mishra@Sun.COM 
113910393SSaurabh.Mishra@Sun.COM 		ddi_regs_map_free(&atgep->atge_io_handle);
114010393SSaurabh.Mishra@Sun.COM 		atge_remove_intr(atgep);
114110393SSaurabh.Mishra@Sun.COM 		pci_config_teardown(&atgep->atge_conf_handle);
114210393SSaurabh.Mishra@Sun.COM 
114310393SSaurabh.Mishra@Sun.COM 		mutex_destroy(&atgep->atge_intr_lock);
114410393SSaurabh.Mishra@Sun.COM 		mutex_destroy(&atgep->atge_tx_lock);
114510393SSaurabh.Mishra@Sun.COM 		mutex_destroy(&atgep->atge_rx_lock);
114610393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep, sizeof (atge_t));
114710393SSaurabh.Mishra@Sun.COM 		ddi_set_driver_private(dip, NULL);
114810393SSaurabh.Mishra@Sun.COM 
114910393SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
115010393SSaurabh.Mishra@Sun.COM 
115110393SSaurabh.Mishra@Sun.COM 	case DDI_SUSPEND:
115210393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() is being suspended",
115310393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__));
115410393SSaurabh.Mishra@Sun.COM 
115510393SSaurabh.Mishra@Sun.COM 		/*
115610393SSaurabh.Mishra@Sun.COM 		 * Suspend monitoring MII.
115710393SSaurabh.Mishra@Sun.COM 		 */
115810393SSaurabh.Mishra@Sun.COM 		mii_suspend(atgep->atge_mii);
115910393SSaurabh.Mishra@Sun.COM 
116010393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_intr_lock);
116110393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_tx_lock);
116210393SSaurabh.Mishra@Sun.COM 		atgep->atge_chip_state |= ATGE_CHIP_SUSPENDED;
116310393SSaurabh.Mishra@Sun.COM 		atge_device_stop(atgep);
116410393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
116510393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_intr_lock);
116610393SSaurabh.Mishra@Sun.COM 
116710393SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
116810393SSaurabh.Mishra@Sun.COM 
116910393SSaurabh.Mishra@Sun.COM 	default:
117010393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
117110393SSaurabh.Mishra@Sun.COM 	}
117210393SSaurabh.Mishra@Sun.COM }
117310393SSaurabh.Mishra@Sun.COM 
117410393SSaurabh.Mishra@Sun.COM int
117510393SSaurabh.Mishra@Sun.COM atge_alloc_buffers(atge_ring_t *r, size_t rcnt, size_t buflen, int f)
117610393SSaurabh.Mishra@Sun.COM {
117710393SSaurabh.Mishra@Sun.COM 	atge_dma_t *dma;
117810393SSaurabh.Mishra@Sun.COM 	atge_dma_t **tbl;
1179*11353SSaurabh.Mishra@Sun.COM 	int err = DDI_SUCCESS;
118010393SSaurabh.Mishra@Sun.COM 	int i;
118110393SSaurabh.Mishra@Sun.COM 
118210393SSaurabh.Mishra@Sun.COM 	tbl = kmem_zalloc(rcnt * sizeof (atge_dma_t *), KM_SLEEP);
118310393SSaurabh.Mishra@Sun.COM 	r->r_buf_tbl = tbl;
118410393SSaurabh.Mishra@Sun.COM 
118510393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < rcnt; i++) {
118610393SSaurabh.Mishra@Sun.COM 		dma = atge_buf_alloc(r->r_atge, buflen, f);
118710393SSaurabh.Mishra@Sun.COM 		if (dma == NULL) {
1188*11353SSaurabh.Mishra@Sun.COM 			err = DDI_FAILURE;
118910393SSaurabh.Mishra@Sun.COM 			break;
119010393SSaurabh.Mishra@Sun.COM 		}
119110393SSaurabh.Mishra@Sun.COM 
119210393SSaurabh.Mishra@Sun.COM 		tbl[i] = dma;
119310393SSaurabh.Mishra@Sun.COM 	}
119410393SSaurabh.Mishra@Sun.COM 
119510393SSaurabh.Mishra@Sun.COM 	return (err);
119610393SSaurabh.Mishra@Sun.COM }
119710393SSaurabh.Mishra@Sun.COM 
119810393SSaurabh.Mishra@Sun.COM void
119910393SSaurabh.Mishra@Sun.COM atge_free_buffers(atge_ring_t *r, size_t rcnt)
120010393SSaurabh.Mishra@Sun.COM {
120110393SSaurabh.Mishra@Sun.COM 	atge_dma_t **tbl;
120210393SSaurabh.Mishra@Sun.COM 	int i;
120310393SSaurabh.Mishra@Sun.COM 
120410393SSaurabh.Mishra@Sun.COM 	if (r == NULL || r->r_buf_tbl == NULL)
120510393SSaurabh.Mishra@Sun.COM 		return;
120610393SSaurabh.Mishra@Sun.COM 
120710393SSaurabh.Mishra@Sun.COM 	tbl = r->r_buf_tbl;
120810393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < rcnt; i++)  {
120910393SSaurabh.Mishra@Sun.COM 		if (tbl[i] != NULL) {
121010393SSaurabh.Mishra@Sun.COM 			atge_buf_free(tbl[i]);
121110393SSaurabh.Mishra@Sun.COM 		}
121210393SSaurabh.Mishra@Sun.COM 	}
121310393SSaurabh.Mishra@Sun.COM 
121410393SSaurabh.Mishra@Sun.COM 	kmem_free(tbl, rcnt * sizeof (atge_dma_t *));
121510393SSaurabh.Mishra@Sun.COM }
121610393SSaurabh.Mishra@Sun.COM 
121710393SSaurabh.Mishra@Sun.COM atge_dma_t *
121810393SSaurabh.Mishra@Sun.COM atge_alloc_a_dma_blk(atge_t *atgep, ddi_dma_attr_t *attr, int size, int d)
121910393SSaurabh.Mishra@Sun.COM {
122010393SSaurabh.Mishra@Sun.COM 	int err;
122110393SSaurabh.Mishra@Sun.COM 	atge_dma_t *dma;
122210393SSaurabh.Mishra@Sun.COM 
122310393SSaurabh.Mishra@Sun.COM 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
122410393SSaurabh.Mishra@Sun.COM 
122510393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_alloc_handle(atgep->atge_dip, attr,
122610393SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
122710393SSaurabh.Mishra@Sun.COM 
122810393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
122910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
123010393SSaurabh.Mishra@Sun.COM 		    " in ddi_dma_alloc_handle() : %d", __func__, err);
123110393SSaurabh.Mishra@Sun.COM 		goto fail;
123210393SSaurabh.Mishra@Sun.COM 	}
123310393SSaurabh.Mishra@Sun.COM 
123410393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_mem_alloc(dma->hdl,
123510393SSaurabh.Mishra@Sun.COM 	    size, &atge_buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
123610393SSaurabh.Mishra@Sun.COM 	    &dma->addr, &dma->len, &dma->acchdl);
123710393SSaurabh.Mishra@Sun.COM 
123810393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
123910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
124010393SSaurabh.Mishra@Sun.COM 		    " in ddi_dma_mem_alloc() : %d", __func__, err);
124110393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
124210393SSaurabh.Mishra@Sun.COM 		goto fail;
124310393SSaurabh.Mishra@Sun.COM 	}
124410393SSaurabh.Mishra@Sun.COM 
124510393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr,
124610393SSaurabh.Mishra@Sun.COM 	    dma->len, d | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
124710393SSaurabh.Mishra@Sun.COM 	    NULL, &dma->cookie, &dma->count);
124810393SSaurabh.Mishra@Sun.COM 
124910393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
125010393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
125110393SSaurabh.Mishra@Sun.COM 		    " in ddi_dma_addr_bind_handle() : %d", __func__, err);
125210393SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&dma->acchdl);
125310393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
125410393SSaurabh.Mishra@Sun.COM 		goto fail;
125510393SSaurabh.Mishra@Sun.COM 	}
125610393SSaurabh.Mishra@Sun.COM 
125710393SSaurabh.Mishra@Sun.COM 	return (dma);
125810393SSaurabh.Mishra@Sun.COM fail:
125910393SSaurabh.Mishra@Sun.COM 	kmem_free(dma, sizeof (atge_dma_t));
126010393SSaurabh.Mishra@Sun.COM 	return (NULL);
126110393SSaurabh.Mishra@Sun.COM }
126210393SSaurabh.Mishra@Sun.COM 
126310393SSaurabh.Mishra@Sun.COM void
126410393SSaurabh.Mishra@Sun.COM atge_free_a_dma_blk(atge_dma_t *dma)
126510393SSaurabh.Mishra@Sun.COM {
126610393SSaurabh.Mishra@Sun.COM 	if (dma != NULL) {
126710393SSaurabh.Mishra@Sun.COM 		(void) ddi_dma_unbind_handle(dma->hdl);
126810393SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&dma->acchdl);
126910393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
127010393SSaurabh.Mishra@Sun.COM 		kmem_free(dma, sizeof (atge_dma_t));
127110393SSaurabh.Mishra@Sun.COM 	}
127210393SSaurabh.Mishra@Sun.COM }
127310393SSaurabh.Mishra@Sun.COM 
127410393SSaurabh.Mishra@Sun.COM atge_dma_t *
127510393SSaurabh.Mishra@Sun.COM atge_buf_alloc(atge_t *atgep, size_t len, int f)
127610393SSaurabh.Mishra@Sun.COM {
127710393SSaurabh.Mishra@Sun.COM 	atge_dma_t *dma = NULL;
127810393SSaurabh.Mishra@Sun.COM 	int err;
127910393SSaurabh.Mishra@Sun.COM 
128010393SSaurabh.Mishra@Sun.COM 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
128110393SSaurabh.Mishra@Sun.COM 
128210393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_alloc_handle(atgep->atge_dip, &atge_dma_attr_buf,
128310393SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
128410393SSaurabh.Mishra@Sun.COM 
128510393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
128610393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
128710393SSaurabh.Mishra@Sun.COM 		    " in %s() : %d", __func__, err);
128810393SSaurabh.Mishra@Sun.COM 		goto fail;
128910393SSaurabh.Mishra@Sun.COM 	}
129010393SSaurabh.Mishra@Sun.COM 
129110393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_mem_alloc(dma->hdl, len, &atge_buf_attr,
129210393SSaurabh.Mishra@Sun.COM 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dma->addr,
129310393SSaurabh.Mishra@Sun.COM 	    &dma->len, &dma->acchdl);
129410393SSaurabh.Mishra@Sun.COM 
129510393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
129610393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
129710393SSaurabh.Mishra@Sun.COM 		    " in %s() : %d", __func__, err);
129810393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
129910393SSaurabh.Mishra@Sun.COM 		goto fail;
130010393SSaurabh.Mishra@Sun.COM 	}
130110393SSaurabh.Mishra@Sun.COM 
130210393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, dma->len,
130310393SSaurabh.Mishra@Sun.COM 	    (f | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, &dma->cookie,
130410393SSaurabh.Mishra@Sun.COM 	    &dma->count);
130510393SSaurabh.Mishra@Sun.COM 
130610393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
130710393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
130810393SSaurabh.Mishra@Sun.COM 		    " in %s() : %d", __func__, err);
130910393SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&dma->acchdl);
131010393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
131110393SSaurabh.Mishra@Sun.COM 		goto fail;
131210393SSaurabh.Mishra@Sun.COM 	}
131310393SSaurabh.Mishra@Sun.COM 
131410393SSaurabh.Mishra@Sun.COM 	/*
131510393SSaurabh.Mishra@Sun.COM 	 * Number of return'ed cookie should be one.
131610393SSaurabh.Mishra@Sun.COM 	 */
131710393SSaurabh.Mishra@Sun.COM 	ASSERT(dma->count == 1);
131810393SSaurabh.Mishra@Sun.COM 
131910393SSaurabh.Mishra@Sun.COM 	return (dma);
132010393SSaurabh.Mishra@Sun.COM fail:
132110393SSaurabh.Mishra@Sun.COM 	kmem_free(dma, sizeof (atge_dma_t));
132210393SSaurabh.Mishra@Sun.COM 	return (NULL);
132310393SSaurabh.Mishra@Sun.COM }
132410393SSaurabh.Mishra@Sun.COM 
132510393SSaurabh.Mishra@Sun.COM void
132610393SSaurabh.Mishra@Sun.COM atge_buf_free(atge_dma_t *dma)
132710393SSaurabh.Mishra@Sun.COM {
132810393SSaurabh.Mishra@Sun.COM 	ASSERT(dma != NULL);
132910393SSaurabh.Mishra@Sun.COM 
133010393SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_unbind_handle(dma->hdl);
133110393SSaurabh.Mishra@Sun.COM 	ddi_dma_mem_free(&dma->acchdl);
133210393SSaurabh.Mishra@Sun.COM 	ddi_dma_free_handle(&dma->hdl);
133310393SSaurabh.Mishra@Sun.COM 	kmem_free(dma, sizeof (atge_dma_t));
133410393SSaurabh.Mishra@Sun.COM }
133510393SSaurabh.Mishra@Sun.COM 
133610393SSaurabh.Mishra@Sun.COM static int
133710393SSaurabh.Mishra@Sun.COM atge_resume(dev_info_t *dip)
133810393SSaurabh.Mishra@Sun.COM {
133910393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
134010393SSaurabh.Mishra@Sun.COM 
134110393SSaurabh.Mishra@Sun.COM 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
134210393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
134310393SSaurabh.Mishra@Sun.COM 	}
134410393SSaurabh.Mishra@Sun.COM 
134510393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
134610393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
134710393SSaurabh.Mishra@Sun.COM 
134810393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state &= ~ATGE_CHIP_SUSPENDED;
134910393SSaurabh.Mishra@Sun.COM 
135010393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
135110393SSaurabh.Mishra@Sun.COM 		atge_device_restart(atgep);
135210393SSaurabh.Mishra@Sun.COM 	} else {
135310393SSaurabh.Mishra@Sun.COM 		atge_device_reset(atgep);
135410393SSaurabh.Mishra@Sun.COM 	}
135510393SSaurabh.Mishra@Sun.COM 
135610393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
135710393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
135810393SSaurabh.Mishra@Sun.COM 
135910393SSaurabh.Mishra@Sun.COM 	/*
136010393SSaurabh.Mishra@Sun.COM 	 * Reset the PHY before resuming MII.
136110393SSaurabh.Mishra@Sun.COM 	 */
136210393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
136310393SSaurabh.Mishra@Sun.COM 		atge_l1e_mii_reset(atgep);
136410393SSaurabh.Mishra@Sun.COM 	}
136510393SSaurabh.Mishra@Sun.COM 
136610393SSaurabh.Mishra@Sun.COM 	mii_resume(atgep->atge_mii);
136710393SSaurabh.Mishra@Sun.COM 
136810393SSaurabh.Mishra@Sun.COM 	/* kick-off downstream */
136910393SSaurabh.Mishra@Sun.COM 	mac_tx_update(atgep->atge_mh);
137010393SSaurabh.Mishra@Sun.COM 
137110393SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
137210393SSaurabh.Mishra@Sun.COM }
137310393SSaurabh.Mishra@Sun.COM 
137410393SSaurabh.Mishra@Sun.COM static int
137510393SSaurabh.Mishra@Sun.COM atge_quiesce(dev_info_t *dip)
137610393SSaurabh.Mishra@Sun.COM {
137710393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
137810393SSaurabh.Mishra@Sun.COM 
137910393SSaurabh.Mishra@Sun.COM 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
138010393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
138110393SSaurabh.Mishra@Sun.COM 	}
138210393SSaurabh.Mishra@Sun.COM 
138310393SSaurabh.Mishra@Sun.COM 	atge_device_stop(atgep);
138410393SSaurabh.Mishra@Sun.COM 
138510393SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
138610393SSaurabh.Mishra@Sun.COM }
138710393SSaurabh.Mishra@Sun.COM 
138810393SSaurabh.Mishra@Sun.COM void
138910393SSaurabh.Mishra@Sun.COM atge_add_multicst(atge_t *atgep, uint8_t *macaddr)
139010393SSaurabh.Mishra@Sun.COM {
139110393SSaurabh.Mishra@Sun.COM 	uint32_t crc;
139210393SSaurabh.Mishra@Sun.COM 	int bit;
139310393SSaurabh.Mishra@Sun.COM 
139410393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
139510393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
139610393SSaurabh.Mishra@Sun.COM 
139710393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
139810393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
139910393SSaurabh.Mishra@Sun.COM 	    macaddr[3], macaddr[4], macaddr[5]));
140010393SSaurabh.Mishra@Sun.COM 
140110393SSaurabh.Mishra@Sun.COM 	crc = atge_ether_crc(macaddr, ETHERADDRL);
140210393SSaurabh.Mishra@Sun.COM 	bit = (crc >> 26);
140310393SSaurabh.Mishra@Sun.COM 	atgep->atge_mchash_ref_cnt[bit]++;
140410393SSaurabh.Mishra@Sun.COM 	atgep->atge_mchash |= (1ULL << (crc >> 26));
140510393SSaurabh.Mishra@Sun.COM 
140610393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
140710393SSaurabh.Mishra@Sun.COM 	    " atge_mchash_ref_cnt[bit] :%d",
140810393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
140910393SSaurabh.Mishra@Sun.COM 	    atgep->atge_mchash_ref_cnt[bit]));
141010393SSaurabh.Mishra@Sun.COM }
141110393SSaurabh.Mishra@Sun.COM 
141210393SSaurabh.Mishra@Sun.COM void
141310393SSaurabh.Mishra@Sun.COM atge_remove_multicst(atge_t *atgep, uint8_t *macaddr)
141410393SSaurabh.Mishra@Sun.COM {
141510393SSaurabh.Mishra@Sun.COM 	uint32_t crc;
141610393SSaurabh.Mishra@Sun.COM 	int bit;
141710393SSaurabh.Mishra@Sun.COM 
141810393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
141910393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
142010393SSaurabh.Mishra@Sun.COM 
142110393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
142210393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
142310393SSaurabh.Mishra@Sun.COM 	    macaddr[3], macaddr[4], macaddr[5]));
142410393SSaurabh.Mishra@Sun.COM 
142510393SSaurabh.Mishra@Sun.COM 	crc = atge_ether_crc(macaddr, ETHERADDRL);
142610393SSaurabh.Mishra@Sun.COM 	bit = (crc >> 26);
142710393SSaurabh.Mishra@Sun.COM 	atgep->atge_mchash_ref_cnt[bit]--;
142810393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_mchash_ref_cnt[bit] == 0)
142910393SSaurabh.Mishra@Sun.COM 		atgep->atge_mchash &= ~(1ULL << (crc >> 26));
143010393SSaurabh.Mishra@Sun.COM 
143110393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
143210393SSaurabh.Mishra@Sun.COM 	    " atge_mchash_ref_cnt[bit] :%d",
143310393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
143410393SSaurabh.Mishra@Sun.COM 	    atgep->atge_mchash_ref_cnt[bit]));
143510393SSaurabh.Mishra@Sun.COM }
143610393SSaurabh.Mishra@Sun.COM 
143710393SSaurabh.Mishra@Sun.COM int
143810393SSaurabh.Mishra@Sun.COM atge_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
143910393SSaurabh.Mishra@Sun.COM {
144010393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
144110393SSaurabh.Mishra@Sun.COM 
144210393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
144310393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
144410393SSaurabh.Mishra@Sun.COM 
144510393SSaurabh.Mishra@Sun.COM 	if (add) {
144610393SSaurabh.Mishra@Sun.COM 		atge_add_multicst(atgep, (uint8_t *)macaddr);
144710393SSaurabh.Mishra@Sun.COM 	} else {
144810393SSaurabh.Mishra@Sun.COM 		atge_remove_multicst(atgep, (uint8_t *)macaddr);
144910393SSaurabh.Mishra@Sun.COM 	}
145010393SSaurabh.Mishra@Sun.COM 
145110393SSaurabh.Mishra@Sun.COM 	atge_rxfilter(atgep);
145210393SSaurabh.Mishra@Sun.COM 
145310393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
145410393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
145510393SSaurabh.Mishra@Sun.COM 
145610393SSaurabh.Mishra@Sun.COM 	return (0);
145710393SSaurabh.Mishra@Sun.COM }
145810393SSaurabh.Mishra@Sun.COM 
145910393SSaurabh.Mishra@Sun.COM int
146010393SSaurabh.Mishra@Sun.COM atge_m_promisc(void *arg, boolean_t on)
146110393SSaurabh.Mishra@Sun.COM {
146210393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
146310393SSaurabh.Mishra@Sun.COM 
146410393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
146510393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
146610393SSaurabh.Mishra@Sun.COM 
146710393SSaurabh.Mishra@Sun.COM 	if (on) {
146810393SSaurabh.Mishra@Sun.COM 		atgep->atge_filter_flags |= ATGE_PROMISC;
146910393SSaurabh.Mishra@Sun.COM 	} else {
147010393SSaurabh.Mishra@Sun.COM 		atgep->atge_filter_flags &= ~ATGE_PROMISC;
147110393SSaurabh.Mishra@Sun.COM 	}
147210393SSaurabh.Mishra@Sun.COM 
147310393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
147410393SSaurabh.Mishra@Sun.COM 		atge_rxfilter(atgep);
147510393SSaurabh.Mishra@Sun.COM 	}
147610393SSaurabh.Mishra@Sun.COM 
147710393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
147810393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
147910393SSaurabh.Mishra@Sun.COM 
148010393SSaurabh.Mishra@Sun.COM 	return (0);
148110393SSaurabh.Mishra@Sun.COM }
148210393SSaurabh.Mishra@Sun.COM 
148310393SSaurabh.Mishra@Sun.COM int
148410393SSaurabh.Mishra@Sun.COM atge_m_unicst(void *arg, const uint8_t *macaddr)
148510393SSaurabh.Mishra@Sun.COM {
148610393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
148710393SSaurabh.Mishra@Sun.COM 
148810393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
148910393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
149010393SSaurabh.Mishra@Sun.COM 	bcopy(macaddr, atgep->atge_ether_addr, ETHERADDRL);
149110393SSaurabh.Mishra@Sun.COM 	atge_program_ether(atgep);
149210393SSaurabh.Mishra@Sun.COM 	atge_rxfilter(atgep);
149310393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
149410393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
149510393SSaurabh.Mishra@Sun.COM 
149610393SSaurabh.Mishra@Sun.COM 	return (0);
149710393SSaurabh.Mishra@Sun.COM }
149810393SSaurabh.Mishra@Sun.COM 
149910393SSaurabh.Mishra@Sun.COM mblk_t *
150010393SSaurabh.Mishra@Sun.COM atge_m_tx(void *arg, mblk_t *mp)
150110393SSaurabh.Mishra@Sun.COM {
150210393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
150310393SSaurabh.Mishra@Sun.COM 	mblk_t	*nmp;
150410393SSaurabh.Mishra@Sun.COM 
150510393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
150610393SSaurabh.Mishra@Sun.COM 
150710393SSaurabh.Mishra@Sun.COM 	/*
150810393SSaurabh.Mishra@Sun.COM 	 * This NIC does not like us to send pkt when link is down.
150910393SSaurabh.Mishra@Sun.COM 	 */
151010393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_link_state & LINK_STATE_UP)) {
151110393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 1;
1512*11353SSaurabh.Mishra@Sun.COM 
151310393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
151410393SSaurabh.Mishra@Sun.COM 		return (mp);
151510393SSaurabh.Mishra@Sun.COM 	}
151610393SSaurabh.Mishra@Sun.COM 
151710393SSaurabh.Mishra@Sun.COM 	/*
151810393SSaurabh.Mishra@Sun.COM 	 * Don't send a pkt if chip isn't running or in suspended state.
151910393SSaurabh.Mishra@Sun.COM 	 */
152010393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_chip_state & ATGE_CHIP_RUNNING) == 0 ||
152110393SSaurabh.Mishra@Sun.COM 	    atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
152210393SSaurabh.Mishra@Sun.COM 		atgep->atge_carrier_errors++;
152310393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 1;
1524*11353SSaurabh.Mishra@Sun.COM 
152510393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
152610393SSaurabh.Mishra@Sun.COM 		return (mp);
152710393SSaurabh.Mishra@Sun.COM 	}
152810393SSaurabh.Mishra@Sun.COM 
152910393SSaurabh.Mishra@Sun.COM 	while (mp != NULL) {
153010393SSaurabh.Mishra@Sun.COM 		nmp = mp->b_next;
153110393SSaurabh.Mishra@Sun.COM 		mp->b_next = NULL;
153210393SSaurabh.Mishra@Sun.COM 
1533*11353SSaurabh.Mishra@Sun.COM 		if (atge_send_a_packet(atgep, mp) == DDI_FAILURE) {
153410393SSaurabh.Mishra@Sun.COM 			mp->b_next = nmp;
153510393SSaurabh.Mishra@Sun.COM 			break;
153610393SSaurabh.Mishra@Sun.COM 		}
153710393SSaurabh.Mishra@Sun.COM 
153810393SSaurabh.Mishra@Sun.COM 		mp = nmp;
153910393SSaurabh.Mishra@Sun.COM 	}
154010393SSaurabh.Mishra@Sun.COM 
154110393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
154210393SSaurabh.Mishra@Sun.COM 	return (mp);
154310393SSaurabh.Mishra@Sun.COM }
154410393SSaurabh.Mishra@Sun.COM 
154510393SSaurabh.Mishra@Sun.COM int
154610393SSaurabh.Mishra@Sun.COM atge_m_start(void *arg)
154710393SSaurabh.Mishra@Sun.COM {
154810393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
154910393SSaurabh.Mishra@Sun.COM 	int started = 0;
155010393SSaurabh.Mishra@Sun.COM 
155110393SSaurabh.Mishra@Sun.COM 	ASSERT(atgep != NULL);
155210393SSaurabh.Mishra@Sun.COM 
155310393SSaurabh.Mishra@Sun.COM 
155410393SSaurabh.Mishra@Sun.COM 	mii_stop(atgep->atge_mii);
155510393SSaurabh.Mishra@Sun.COM 
155610393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
155710393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
155810393SSaurabh.Mishra@Sun.COM 
155910393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
156010393SSaurabh.Mishra@Sun.COM 		atge_device_restart(atgep);
156110393SSaurabh.Mishra@Sun.COM 		started = 1;
156210393SSaurabh.Mishra@Sun.COM 	}
156310393SSaurabh.Mishra@Sun.COM 
156410393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
156510393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
156610393SSaurabh.Mishra@Sun.COM 
156710393SSaurabh.Mishra@Sun.COM 	mii_start(atgep->atge_mii);
156810393SSaurabh.Mishra@Sun.COM 
156910393SSaurabh.Mishra@Sun.COM 	/* kick-off downstream */
157010393SSaurabh.Mishra@Sun.COM 	if (started)
157110393SSaurabh.Mishra@Sun.COM 		mac_tx_update(atgep->atge_mh);
157210393SSaurabh.Mishra@Sun.COM 
157310393SSaurabh.Mishra@Sun.COM 	return (0);
157410393SSaurabh.Mishra@Sun.COM }
157510393SSaurabh.Mishra@Sun.COM 
157610393SSaurabh.Mishra@Sun.COM void
157710393SSaurabh.Mishra@Sun.COM atge_m_stop(void *arg)
157810393SSaurabh.Mishra@Sun.COM {
157910393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
158010393SSaurabh.Mishra@Sun.COM 
158110393SSaurabh.Mishra@Sun.COM 	mii_stop(atgep->atge_mii);
158210393SSaurabh.Mishra@Sun.COM 
158310393SSaurabh.Mishra@Sun.COM 	/*
158410393SSaurabh.Mishra@Sun.COM 	 * Cancel any pending I/O.
158510393SSaurabh.Mishra@Sun.COM 	 */
158610393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
158710393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
158810393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED))
158910393SSaurabh.Mishra@Sun.COM 		atge_device_stop(atgep);
159010393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
159110393SSaurabh.Mishra@Sun.COM }
159210393SSaurabh.Mishra@Sun.COM 
159310393SSaurabh.Mishra@Sun.COM int
159410393SSaurabh.Mishra@Sun.COM atge_m_stat(void *arg, uint_t stat, uint64_t *val)
159510393SSaurabh.Mishra@Sun.COM {
159610393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
159710393SSaurabh.Mishra@Sun.COM 
159810393SSaurabh.Mishra@Sun.COM 	if (mii_m_getstat(atgep->atge_mii, stat, val) == 0) {
159910393SSaurabh.Mishra@Sun.COM 		return (0);
160010393SSaurabh.Mishra@Sun.COM 	}
160110393SSaurabh.Mishra@Sun.COM 
160210393SSaurabh.Mishra@Sun.COM 	switch (stat) {
160310393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_MULTIRCV:
160410393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_multircv;
160510393SSaurabh.Mishra@Sun.COM 		break;
160610393SSaurabh.Mishra@Sun.COM 
160710393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_BRDCSTRCV:
160810393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_brdcstrcv;
160910393SSaurabh.Mishra@Sun.COM 		break;
161010393SSaurabh.Mishra@Sun.COM 
161110393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_MULTIXMT:
161210393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_multixmt;
161310393SSaurabh.Mishra@Sun.COM 		break;
161410393SSaurabh.Mishra@Sun.COM 
161510393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_BRDCSTXMT:
161610393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_brdcstxmt;
161710393SSaurabh.Mishra@Sun.COM 		break;
161810393SSaurabh.Mishra@Sun.COM 
161910393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IPACKETS:
162010393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_ipackets;
162110393SSaurabh.Mishra@Sun.COM 		break;
162210393SSaurabh.Mishra@Sun.COM 
162310393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_RBYTES:
162410393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_rbytes;
162510393SSaurabh.Mishra@Sun.COM 		break;
162610393SSaurabh.Mishra@Sun.COM 
162710393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OPACKETS:
162810393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_opackets;
162910393SSaurabh.Mishra@Sun.COM 		break;
163010393SSaurabh.Mishra@Sun.COM 
163110393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OBYTES:
163210393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_obytes;
163310393SSaurabh.Mishra@Sun.COM 		break;
163410393SSaurabh.Mishra@Sun.COM 
163510393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_NORCVBUF:
163610393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_norcvbuf;
163710393SSaurabh.Mishra@Sun.COM 		break;
163810393SSaurabh.Mishra@Sun.COM 
163910393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_NOXMTBUF:
164010393SSaurabh.Mishra@Sun.COM 		*val = 0;
164110393SSaurabh.Mishra@Sun.COM 		break;
164210393SSaurabh.Mishra@Sun.COM 
164310393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_COLLISIONS:
164410393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_collisions;
164510393SSaurabh.Mishra@Sun.COM 		break;
164610393SSaurabh.Mishra@Sun.COM 
164710393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IERRORS:
164810393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_errrcv;
164910393SSaurabh.Mishra@Sun.COM 		break;
165010393SSaurabh.Mishra@Sun.COM 
165110393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OERRORS:
165210393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_errxmt;
165310393SSaurabh.Mishra@Sun.COM 		break;
165410393SSaurabh.Mishra@Sun.COM 
165510393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ALIGN_ERRORS:
165610393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_align_errors;
165710393SSaurabh.Mishra@Sun.COM 		break;
165810393SSaurabh.Mishra@Sun.COM 
165910393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_FCS_ERRORS:
166010393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_fcs_errors;
166110393SSaurabh.Mishra@Sun.COM 		break;
166210393SSaurabh.Mishra@Sun.COM 
166310393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_SQE_ERRORS:
166410393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_sqe_errors;
166510393SSaurabh.Mishra@Sun.COM 		break;
166610393SSaurabh.Mishra@Sun.COM 
166710393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_DEFER_XMTS:
166810393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_defer_xmts;
166910393SSaurabh.Mishra@Sun.COM 		break;
167010393SSaurabh.Mishra@Sun.COM 
167110393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_FIRST_COLLISIONS:
167210393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_first_collisions;
167310393SSaurabh.Mishra@Sun.COM 		break;
167410393SSaurabh.Mishra@Sun.COM 
167510393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MULTI_COLLISIONS:
167610393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_multi_collisions;
167710393SSaurabh.Mishra@Sun.COM 		break;
167810393SSaurabh.Mishra@Sun.COM 
167910393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TX_LATE_COLLISIONS:
168010393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_tx_late_collisions;
168110393SSaurabh.Mishra@Sun.COM 		break;
168210393SSaurabh.Mishra@Sun.COM 
168310393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_EX_COLLISIONS:
168410393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_ex_collisions;
168510393SSaurabh.Mishra@Sun.COM 		break;
168610393SSaurabh.Mishra@Sun.COM 
168710393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MACXMT_ERRORS:
168810393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_macxmt_errors;
168910393SSaurabh.Mishra@Sun.COM 		break;
169010393SSaurabh.Mishra@Sun.COM 
169110393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CARRIER_ERRORS:
169210393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_carrier_errors;
169310393SSaurabh.Mishra@Sun.COM 		break;
169410393SSaurabh.Mishra@Sun.COM 
169510393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TOOLONG_ERRORS:
169610393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_toolong_errors;
169710393SSaurabh.Mishra@Sun.COM 		break;
169810393SSaurabh.Mishra@Sun.COM 
169910393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MACRCV_ERRORS:
170010393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_macrcv_errors;
170110393SSaurabh.Mishra@Sun.COM 		break;
170210393SSaurabh.Mishra@Sun.COM 
170310393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OVERFLOWS:
170410393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_overflow;
170510393SSaurabh.Mishra@Sun.COM 		break;
170610393SSaurabh.Mishra@Sun.COM 
170710393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_UNDERFLOWS:
170810393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_underflow;
170910393SSaurabh.Mishra@Sun.COM 		break;
171010393SSaurabh.Mishra@Sun.COM 
171110393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TOOSHORT_ERRORS:
171210393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_runt;
171310393SSaurabh.Mishra@Sun.COM 		break;
171410393SSaurabh.Mishra@Sun.COM 
171510393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_JABBER_ERRORS:
171610393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_jabber;
171710393SSaurabh.Mishra@Sun.COM 		break;
171810393SSaurabh.Mishra@Sun.COM 
171910393SSaurabh.Mishra@Sun.COM 	default:
172010393SSaurabh.Mishra@Sun.COM 		return (ENOTSUP);
172110393SSaurabh.Mishra@Sun.COM 	}
172210393SSaurabh.Mishra@Sun.COM 
172310393SSaurabh.Mishra@Sun.COM 	return (0);
172410393SSaurabh.Mishra@Sun.COM }
172510393SSaurabh.Mishra@Sun.COM 
172610393SSaurabh.Mishra@Sun.COM int
172710393SSaurabh.Mishra@Sun.COM atge_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags,
172810393SSaurabh.Mishra@Sun.COM     uint_t sz, void *val, uint_t *perm)
172910393SSaurabh.Mishra@Sun.COM {
173010393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
173110393SSaurabh.Mishra@Sun.COM 
173210393SSaurabh.Mishra@Sun.COM 	return (mii_m_getprop(atgep->atge_mii, name, num, flags, sz, val,
173310393SSaurabh.Mishra@Sun.COM 	    perm));
173410393SSaurabh.Mishra@Sun.COM }
173510393SSaurabh.Mishra@Sun.COM 
173610393SSaurabh.Mishra@Sun.COM int
173710393SSaurabh.Mishra@Sun.COM atge_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
173810393SSaurabh.Mishra@Sun.COM     const void *val)
173910393SSaurabh.Mishra@Sun.COM {
174010393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
1741*11353SSaurabh.Mishra@Sun.COM 	int r;
1742*11353SSaurabh.Mishra@Sun.COM 
1743*11353SSaurabh.Mishra@Sun.COM 	r = mii_m_setprop(atgep->atge_mii, name, num, sz, val);
1744*11353SSaurabh.Mishra@Sun.COM 
1745*11353SSaurabh.Mishra@Sun.COM 	if (r == 0) {
1746*11353SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_intr_lock);
1747*11353SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_tx_lock);
1748*11353SSaurabh.Mishra@Sun.COM 
1749*11353SSaurabh.Mishra@Sun.COM 		if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
1750*11353SSaurabh.Mishra@Sun.COM 			atge_device_restart(atgep);
1751*11353SSaurabh.Mishra@Sun.COM 		}
1752*11353SSaurabh.Mishra@Sun.COM 
1753*11353SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
1754*11353SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_intr_lock);
1755*11353SSaurabh.Mishra@Sun.COM 	}
1756*11353SSaurabh.Mishra@Sun.COM 
1757*11353SSaurabh.Mishra@Sun.COM 	return (r);
175810393SSaurabh.Mishra@Sun.COM }
175910393SSaurabh.Mishra@Sun.COM 
176010393SSaurabh.Mishra@Sun.COM 
176110393SSaurabh.Mishra@Sun.COM void
176210393SSaurabh.Mishra@Sun.COM atge_program_ether(atge_t *atgep)
176310393SSaurabh.Mishra@Sun.COM {
176410393SSaurabh.Mishra@Sun.COM 	ether_addr_t e;
176510393SSaurabh.Mishra@Sun.COM 
176610393SSaurabh.Mishra@Sun.COM 	/*
176710393SSaurabh.Mishra@Sun.COM 	 * Reprogram the Station address.
176810393SSaurabh.Mishra@Sun.COM 	 */
176910393SSaurabh.Mishra@Sun.COM 	bcopy(atgep->atge_ether_addr, e, ETHERADDRL);
177010393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_PAR0,
177110393SSaurabh.Mishra@Sun.COM 	    ((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5]));
177210393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_PAR1, (e[0] << 8) | e[1]);
177310393SSaurabh.Mishra@Sun.COM }
177410393SSaurabh.Mishra@Sun.COM 
177510393SSaurabh.Mishra@Sun.COM /*
177610393SSaurabh.Mishra@Sun.COM  * Device specific operations.
177710393SSaurabh.Mishra@Sun.COM  */
177810393SSaurabh.Mishra@Sun.COM void
177910393SSaurabh.Mishra@Sun.COM atge_device_start(atge_t *atgep)
178010393SSaurabh.Mishra@Sun.COM {
1781*11353SSaurabh.Mishra@Sun.COM 	uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo;
178210393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
178310393SSaurabh.Mishra@Sun.COM 	uint32_t fsize;
178410393SSaurabh.Mishra@Sun.COM 
178510393SSaurabh.Mishra@Sun.COM 	/*
178610393SSaurabh.Mishra@Sun.COM 	 * Reprogram the Station address.
178710393SSaurabh.Mishra@Sun.COM 	 */
178810393SSaurabh.Mishra@Sun.COM 	atge_program_ether(atgep);
178910393SSaurabh.Mishra@Sun.COM 
179010393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
179110393SSaurabh.Mishra@Sun.COM 		atge_l1e_program_dma(atgep);
1792*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1793*11353SSaurabh.Mishra@Sun.COM 		atge_l1_program_dma(atgep);
179410393SSaurabh.Mishra@Sun.COM 	}
179510393SSaurabh.Mishra@Sun.COM 
179610393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name,
179710393SSaurabh.Mishra@Sun.COM 	    __func__));
179810393SSaurabh.Mishra@Sun.COM 
179910393SSaurabh.Mishra@Sun.COM 	OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
180010393SSaurabh.Mishra@Sun.COM 
180110393SSaurabh.Mishra@Sun.COM 	/*
1802*11353SSaurabh.Mishra@Sun.COM 	 * Set Maximum frame size but don't let MTU be less than ETHER_MTU.
180310393SSaurabh.Mishra@Sun.COM 	 */
180410393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_mtu < ETHERMTU)
180510393SSaurabh.Mishra@Sun.COM 		atgep->atge_max_frame_size = ETHERMTU;
180610393SSaurabh.Mishra@Sun.COM 	else
180710393SSaurabh.Mishra@Sun.COM 		atgep->atge_max_frame_size = atgep->atge_mtu;
180810393SSaurabh.Mishra@Sun.COM 
180910393SSaurabh.Mishra@Sun.COM 	atgep->atge_max_frame_size += sizeof (struct ether_header) +
181010393SSaurabh.Mishra@Sun.COM 	    VLAN_TAGSZ + ETHERFCSL;
181110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size);
181210393SSaurabh.Mishra@Sun.COM 
181310393SSaurabh.Mishra@Sun.COM 
181410393SSaurabh.Mishra@Sun.COM 	/*
181510393SSaurabh.Mishra@Sun.COM 	 * Configure IPG/IFG parameters.
181610393SSaurabh.Mishra@Sun.COM 	 */
181710393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_IPG_IFG_CFG,
181810393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) |
181910393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) |
182010393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) |
182110393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK));
182210393SSaurabh.Mishra@Sun.COM 
182310393SSaurabh.Mishra@Sun.COM 	/*
182410393SSaurabh.Mishra@Sun.COM 	 * Set parameters for half-duplex media.
182510393SSaurabh.Mishra@Sun.COM 	 */
182610393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_HDPX_CFG,
182710393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) &
182810393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_LCOL_MASK) |
182910393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) &
183010393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN |
183110393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) &
183210393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_ABEBT_MASK) |
183310393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) &
183410393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_JAMIPG_MASK));
183510393SSaurabh.Mishra@Sun.COM 
183610393SSaurabh.Mishra@Sun.COM 	/*
183710393SSaurabh.Mishra@Sun.COM 	 * Configure jumbo frame.
183810393SSaurabh.Mishra@Sun.COM 	 */
183910393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
184010393SSaurabh.Mishra@Sun.COM 		fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t));
184110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_JUMBO_CFG,
184210393SSaurabh.Mishra@Sun.COM 		    (((fsize / sizeof (uint64_t)) <<
184310393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) &
184410393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_SZ_THRESH_MASK) |
184510393SSaurabh.Mishra@Sun.COM 		    ((RXQ_JUMBO_CFG_LKAH_DEFAULT <<
184610393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) |
184710393SSaurabh.Mishra@Sun.COM 		    ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) &
184810393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_RRD_TIMER_MASK));
184910393SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E &&
185010393SSaurabh.Mishra@Sun.COM 	    atgep->atge_flags & ATGE_FLAG_JUMBO) {
185110393SSaurabh.Mishra@Sun.COM 
185210393SSaurabh.Mishra@Sun.COM 		if (atgep->atge_mtu < ETHERMTU)
185310393SSaurabh.Mishra@Sun.COM 			reg = atgep->atge_max_frame_size;
185410393SSaurabh.Mishra@Sun.COM 		else if (atgep->atge_mtu < 6 * 1024)
185510393SSaurabh.Mishra@Sun.COM 			reg = (atgep->atge_max_frame_size * 2) / 3;
185610393SSaurabh.Mishra@Sun.COM 		else
185710393SSaurabh.Mishra@Sun.COM 			reg = atgep->atge_max_frame_size / 2;
185810393SSaurabh.Mishra@Sun.COM 
185910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_TX_JUMBO_THRESH,
186010393SSaurabh.Mishra@Sun.COM 		    ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
186110393SSaurabh.Mishra@Sun.COM 		    TX_JUMBO_THRESH_UNIT_SHIFT);
186210393SSaurabh.Mishra@Sun.COM 	}
186310393SSaurabh.Mishra@Sun.COM 
186410393SSaurabh.Mishra@Sun.COM 	/*
186510393SSaurabh.Mishra@Sun.COM 	 * Configure flow-control parameters.
186610393SSaurabh.Mishra@Sun.COM 	 */
186710393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
186810393SSaurabh.Mishra@Sun.COM 		/*
186910393SSaurabh.Mishra@Sun.COM 		 * Some hardware version require this magic.
187010393SSaurabh.Mishra@Sun.COM 		 */
187110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, 0x12FC, 0x6500);
187210393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, 0x1008);
187310393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, 0x1008, reg | 0x8000);
187410393SSaurabh.Mishra@Sun.COM 	}
187510393SSaurabh.Mishra@Sun.COM 
187610393SSaurabh.Mishra@Sun.COM 	/*
187710393SSaurabh.Mishra@Sun.COM 	 * These are all magic parameters which came from FreeBSD.
187810393SSaurabh.Mishra@Sun.COM 	 */
1879*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1880*11353SSaurabh.Mishra@Sun.COM 		switch (atgep->atge_chip_rev) {
1881*11353SSaurabh.Mishra@Sun.COM 		case 0x8001:
1882*11353SSaurabh.Mishra@Sun.COM 		case 0x9001:
1883*11353SSaurabh.Mishra@Sun.COM 		case 0x9002:
1884*11353SSaurabh.Mishra@Sun.COM 		case 0x9003:
1885*11353SSaurabh.Mishra@Sun.COM 			rxf_hi = L1_RX_RING_CNT / 16;
1886*11353SSaurabh.Mishra@Sun.COM 			rxf_lo = (L1_RX_RING_CNT * 7) / 8;
1887*11353SSaurabh.Mishra@Sun.COM 			rrd_hi = (L1_RR_RING_CNT * 7) / 8;
1888*11353SSaurabh.Mishra@Sun.COM 			rrd_lo = L1_RR_RING_CNT / 16;
1889*11353SSaurabh.Mishra@Sun.COM 			break;
1890*11353SSaurabh.Mishra@Sun.COM 		default:
1891*11353SSaurabh.Mishra@Sun.COM 			reg = INL(atgep, L1_SRAM_RX_FIFO_LEN);
1892*11353SSaurabh.Mishra@Sun.COM 			rxf_lo = reg / 16;
1893*11353SSaurabh.Mishra@Sun.COM 			if (rxf_lo > 192)
1894*11353SSaurabh.Mishra@Sun.COM 				rxf_lo = 192;
1895*11353SSaurabh.Mishra@Sun.COM 			rxf_hi = (reg * 7) / 8;
1896*11353SSaurabh.Mishra@Sun.COM 			if (rxf_hi < rxf_lo)
1897*11353SSaurabh.Mishra@Sun.COM 				rxf_hi = rxf_lo + 16;
1898*11353SSaurabh.Mishra@Sun.COM 			reg = INL(atgep, L1_SRAM_RRD_LEN);
1899*11353SSaurabh.Mishra@Sun.COM 			rrd_lo = reg / 8;
1900*11353SSaurabh.Mishra@Sun.COM 			rrd_hi = (reg * 7) / 8;
1901*11353SSaurabh.Mishra@Sun.COM 			if (rrd_lo > 2)
1902*11353SSaurabh.Mishra@Sun.COM 				rrd_lo = 2;
1903*11353SSaurabh.Mishra@Sun.COM 			if (rrd_hi < rrd_lo)
1904*11353SSaurabh.Mishra@Sun.COM 				rrd_hi = rrd_lo + 3;
1905*11353SSaurabh.Mishra@Sun.COM 			break;
1906*11353SSaurabh.Mishra@Sun.COM 		}
1907*11353SSaurabh.Mishra@Sun.COM 
1908*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
1909*11353SSaurabh.Mishra@Sun.COM 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
1910*11353SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
1911*11353SSaurabh.Mishra@Sun.COM 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
1912*11353SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
1913*11353SSaurabh.Mishra@Sun.COM 
1914*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_RXQ_RRD_PAUSE_THRESH,
1915*11353SSaurabh.Mishra@Sun.COM 		    ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) &
1916*11353SSaurabh.Mishra@Sun.COM 		    RXQ_RRD_PAUSE_THRESH_LO_MASK) |
1917*11353SSaurabh.Mishra@Sun.COM 		    ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
1918*11353SSaurabh.Mishra@Sun.COM 		    RXQ_RRD_PAUSE_THRESH_HI_MASK));
1919*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
192010393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
192110393SSaurabh.Mishra@Sun.COM 		rxf_hi = (reg * 4) / 5;
192210393SSaurabh.Mishra@Sun.COM 		rxf_lo = reg/ 5;
192310393SSaurabh.Mishra@Sun.COM 
192410393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
192510393SSaurabh.Mishra@Sun.COM 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
192610393SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
192710393SSaurabh.Mishra@Sun.COM 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
192810393SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
192910393SSaurabh.Mishra@Sun.COM 	}
193010393SSaurabh.Mishra@Sun.COM 
193110393SSaurabh.Mishra@Sun.COM 	/* Configure RxQ. */
193210393SSaurabh.Mishra@Sun.COM 	reg = 0;
1933*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1934*11353SSaurabh.Mishra@Sun.COM 		reg =
1935*11353SSaurabh.Mishra@Sun.COM 		    ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
1936*11353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RD_BURST_MASK) |
1937*11353SSaurabh.Mishra@Sun.COM 		    ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
1938*11353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
1939*11353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RRD_BURST_THRESH_MASK) |
1940*11353SSaurabh.Mishra@Sun.COM 		    ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
1941*11353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
1942*11353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
1943*11353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
1944*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_CFG, reg);
1945*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
194610393SSaurabh.Mishra@Sun.COM 		reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB |
194710393SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
194810393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_CFG, reg);
194910393SSaurabh.Mishra@Sun.COM 	}
195010393SSaurabh.Mishra@Sun.COM 
195110393SSaurabh.Mishra@Sun.COM 	/*
195210393SSaurabh.Mishra@Sun.COM 	 * Configure TxQ.
195310393SSaurabh.Mishra@Sun.COM 	 */
1954*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1955*11353SSaurabh.Mishra@Sun.COM 		reg =
1956*11353SSaurabh.Mishra@Sun.COM 		    (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
1957*11353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_BURST_MASK) |
1958*11353SSaurabh.Mishra@Sun.COM 		    ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
1959*11353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TX_FIFO_BURST_SHIFT) &
1960*11353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TX_FIFO_BURST_MASK) |
1961*11353SSaurabh.Mishra@Sun.COM 		    ((TXQ_CFG_TPD_FETCH_DEFAULT <<
1962*11353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
1963*11353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_FETCH_THRESH_MASK) |
1964*11353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_ENB);
1965*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_TXQ_CFG, reg);
1966*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
196710393SSaurabh.Mishra@Sun.COM 		reg = (128 <<
196810393SSaurabh.Mishra@Sun.COM 		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
196910393SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
197010393SSaurabh.Mishra@Sun.COM 
197110393SSaurabh.Mishra@Sun.COM 		reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
197210393SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_BURST_MASK;
197310393SSaurabh.Mishra@Sun.COM 
197410393SSaurabh.Mishra@Sun.COM 		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
197510393SSaurabh.Mishra@Sun.COM 
197610393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_TXQ_CFG, reg);
197710393SSaurabh.Mishra@Sun.COM 	}
197810393SSaurabh.Mishra@Sun.COM 
1979*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1980*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
1981*11353SSaurabh.Mishra@Sun.COM 		    (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
1982*11353SSaurabh.Mishra@Sun.COM 		    TX_JUMBO_TPD_TH_MASK) |
1983*11353SSaurabh.Mishra@Sun.COM 		    ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
1984*11353SSaurabh.Mishra@Sun.COM 		    TX_JUMBO_TPD_IPG_MASK));
1985*11353SSaurabh.Mishra@Sun.COM 	}
1986*11353SSaurabh.Mishra@Sun.COM 
198710393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
198810393SSaurabh.Mishra@Sun.COM 		/* Disable RSS. */
198910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_RSS_IDT_TABLE0, 0);
199010393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_RSS_CPU, 0);
199110393SSaurabh.Mishra@Sun.COM 	}
199210393SSaurabh.Mishra@Sun.COM 
199310393SSaurabh.Mishra@Sun.COM 	/*
199410393SSaurabh.Mishra@Sun.COM 	 * Configure DMA parameters.
199510393SSaurabh.Mishra@Sun.COM 	 */
1996*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
1997*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG,
1998*11353SSaurabh.Mishra@Sun.COM 		    DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
1999*11353SSaurabh.Mishra@Sun.COM 		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
2000*11353SSaurabh.Mishra@Sun.COM 		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
2001*11353SSaurabh.Mishra@Sun.COM 
2002*11353SSaurabh.Mishra@Sun.COM 		/* Configure CMB DMA write threshold. */
2003*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CMB_WR_THRESH,
2004*11353SSaurabh.Mishra@Sun.COM 		    ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
2005*11353SSaurabh.Mishra@Sun.COM 		    CMB_WR_THRESH_RRD_MASK) |
2006*11353SSaurabh.Mishra@Sun.COM 		    ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
2007*11353SSaurabh.Mishra@Sun.COM 		    CMB_WR_THRESH_TPD_MASK));
2008*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
200910393SSaurabh.Mishra@Sun.COM 		/*
201010393SSaurabh.Mishra@Sun.COM 		 * Don't use Tx CMB. It is known to cause RRS update failure
201110393SSaurabh.Mishra@Sun.COM 		 * under certain circumstances. Typical phenomenon of the
201210393SSaurabh.Mishra@Sun.COM 		 * issue would be unexpected sequence number encountered in
201310393SSaurabh.Mishra@Sun.COM 		 * Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB.
201410393SSaurabh.Mishra@Sun.COM 		 */
201510393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG,
201610393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
201710393SSaurabh.Mishra@Sun.COM 		    atgep->atge_dma_rd_burst | atgep->atge_dma_wr_burst |
201810393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_RXCMB_ENB |
201910393SSaurabh.Mishra@Sun.COM 		    ((DMA_CFG_RD_DELAY_CNT_DEFAULT <<
202010393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) |
202110393SSaurabh.Mishra@Sun.COM 		    ((DMA_CFG_WR_DELAY_CNT_DEFAULT <<
202210393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK));
202310393SSaurabh.Mishra@Sun.COM 	}
202410393SSaurabh.Mishra@Sun.COM 
202510393SSaurabh.Mishra@Sun.COM 	/*
2026*11353SSaurabh.Mishra@Sun.COM 	 * Enable CMB/SMB timer.
202710393SSaurabh.Mishra@Sun.COM 	 */
2028*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2029*11353SSaurabh.Mishra@Sun.COM 		/* Set CMB/SMB timer and enable them. */
2030*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CMB_WR_TIMER,
2031*11353SSaurabh.Mishra@Sun.COM 		    ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) &
2032*11353SSaurabh.Mishra@Sun.COM 		    CMB_WR_TIMER_TX_MASK) |
2033*11353SSaurabh.Mishra@Sun.COM 		    ((ATGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) &
2034*11353SSaurabh.Mishra@Sun.COM 		    CMB_WR_TIMER_RX_MASK));
2035*11353SSaurabh.Mishra@Sun.COM 
2036*11353SSaurabh.Mishra@Sun.COM 		/* Request SMB updates for every seconds. */
2037*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000));
2038*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CSMB_CTRL,
2039*11353SSaurabh.Mishra@Sun.COM 		    CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB);
2040*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
204110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
204210393SSaurabh.Mishra@Sun.COM 		atge_l1e_clear_stats(atgep);
204310393SSaurabh.Mishra@Sun.COM 	}
204410393SSaurabh.Mishra@Sun.COM 
2045*11353SSaurabh.Mishra@Sun.COM 
204610393SSaurabh.Mishra@Sun.COM 	/*
204710393SSaurabh.Mishra@Sun.COM 	 * Disable all WOL bits as WOL can interfere normal Rx
204810393SSaurabh.Mishra@Sun.COM 	 * operation.
204910393SSaurabh.Mishra@Sun.COM 	 */
205010393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_WOL_CFG, 0);
205110393SSaurabh.Mishra@Sun.COM 
205210393SSaurabh.Mishra@Sun.COM 	/*
205310393SSaurabh.Mishra@Sun.COM 	 * Configure Tx/Rx MACs.
205410393SSaurabh.Mishra@Sun.COM 	 *  - Auto-padding for short frames.
205510393SSaurabh.Mishra@Sun.COM 	 *  - Enable CRC generation.
205610393SSaurabh.Mishra@Sun.COM 	 *
205710393SSaurabh.Mishra@Sun.COM 	 *  Start with full-duplex/1000Mbps media. Actual reconfiguration
205810393SSaurabh.Mishra@Sun.COM 	 *  of MAC is followed after link establishment.
205910393SSaurabh.Mishra@Sun.COM 	 */
206010393SSaurabh.Mishra@Sun.COM 	reg = (ATGE_CFG_TX_CRC_ENB | ATGE_CFG_TX_AUTO_PAD |
206110393SSaurabh.Mishra@Sun.COM 	    ATGE_CFG_FULL_DUPLEX |
206210393SSaurabh.Mishra@Sun.COM 	    ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) &
206310393SSaurabh.Mishra@Sun.COM 	    ATGE_CFG_PREAMBLE_MASK));
206410393SSaurabh.Mishra@Sun.COM 
206510393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) {
206610393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_10_100;
206710393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__));
206810393SSaurabh.Mishra@Sun.COM 	} else {
206910393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_1000;
207010393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__));
207110393SSaurabh.Mishra@Sun.COM 	}
207210393SSaurabh.Mishra@Sun.COM 
207310393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAC_CFG, reg);
207410393SSaurabh.Mishra@Sun.COM 
207510393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state |= ATGE_CHIP_RUNNING;
207610393SSaurabh.Mishra@Sun.COM 
207710393SSaurabh.Mishra@Sun.COM 	/*
207810393SSaurabh.Mishra@Sun.COM 	 * Set up the receive filter.
207910393SSaurabh.Mishra@Sun.COM 	 */
208010393SSaurabh.Mishra@Sun.COM 	atge_rxfilter(atgep);
208110393SSaurabh.Mishra@Sun.COM 
2082*11353SSaurabh.Mishra@Sun.COM 	/*
2083*11353SSaurabh.Mishra@Sun.COM 	 * Acknowledge all pending interrupts and clear it.
2084*11353SSaurabh.Mishra@Sun.COM 	 */
2085*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2086*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0);
2087*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
2088*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
208910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS);
209010393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
209110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0);
209210393SSaurabh.Mishra@Sun.COM 	}
209310393SSaurabh.Mishra@Sun.COM 
2094*11353SSaurabh.Mishra@Sun.COM 	atge_mac_config(atgep);
2095*11353SSaurabh.Mishra@Sun.COM 
209610393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() device started", atgep->atge_name, __func__));
209710393SSaurabh.Mishra@Sun.COM }
209810393SSaurabh.Mishra@Sun.COM 
209910393SSaurabh.Mishra@Sun.COM /*
210010393SSaurabh.Mishra@Sun.COM  * Generic functions.
210110393SSaurabh.Mishra@Sun.COM  */
210210393SSaurabh.Mishra@Sun.COM 
210310393SSaurabh.Mishra@Sun.COM #define	CRC32_POLY_BE   0x04c11db7
210410393SSaurabh.Mishra@Sun.COM uint32_t
210510393SSaurabh.Mishra@Sun.COM atge_ether_crc(const uint8_t *addr, int len)
210610393SSaurabh.Mishra@Sun.COM {
210710393SSaurabh.Mishra@Sun.COM 	int idx;
210810393SSaurabh.Mishra@Sun.COM 	int bit;
210910393SSaurabh.Mishra@Sun.COM 	uint_t data;
211010393SSaurabh.Mishra@Sun.COM 	uint32_t crc;
211110393SSaurabh.Mishra@Sun.COM 
211210393SSaurabh.Mishra@Sun.COM 	crc = 0xffffffff;
211310393SSaurabh.Mishra@Sun.COM 	for (idx = 0; idx < len; idx++) {
211410393SSaurabh.Mishra@Sun.COM 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
211510393SSaurabh.Mishra@Sun.COM 			crc = (crc << 1)
211610393SSaurabh.Mishra@Sun.COM 			    ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
211710393SSaurabh.Mishra@Sun.COM 		}
211810393SSaurabh.Mishra@Sun.COM 	}
211910393SSaurabh.Mishra@Sun.COM 
212010393SSaurabh.Mishra@Sun.COM 	return (crc);
212110393SSaurabh.Mishra@Sun.COM }
212210393SSaurabh.Mishra@Sun.COM 
212310393SSaurabh.Mishra@Sun.COM 
212410393SSaurabh.Mishra@Sun.COM /*
212510393SSaurabh.Mishra@Sun.COM  * Programs RX filter. We use a link-list to keep track of all multicast
212610393SSaurabh.Mishra@Sun.COM  * addressess.
212710393SSaurabh.Mishra@Sun.COM  */
212810393SSaurabh.Mishra@Sun.COM void
212910393SSaurabh.Mishra@Sun.COM atge_rxfilter(atge_t *atgep)
213010393SSaurabh.Mishra@Sun.COM {
213110393SSaurabh.Mishra@Sun.COM 	uint32_t rxcfg;
213210393SSaurabh.Mishra@Sun.COM 	uint64_t mchash;
213310393SSaurabh.Mishra@Sun.COM 
213410393SSaurabh.Mishra@Sun.COM 	rxcfg = INL(atgep, ATGE_MAC_CFG);
213510393SSaurabh.Mishra@Sun.COM 	rxcfg &= ~(ATGE_CFG_ALLMULTI | ATGE_CFG_PROMISC);
213610393SSaurabh.Mishra@Sun.COM 
213710393SSaurabh.Mishra@Sun.COM 	/*
213810393SSaurabh.Mishra@Sun.COM 	 * Accept broadcast frames.
213910393SSaurabh.Mishra@Sun.COM 	 */
214010393SSaurabh.Mishra@Sun.COM 	rxcfg |= ATGE_CFG_BCAST;
214110393SSaurabh.Mishra@Sun.COM 
214210393SSaurabh.Mishra@Sun.COM 	/*
214310393SSaurabh.Mishra@Sun.COM 	 * We don't use Hardware VLAN tagging.
214410393SSaurabh.Mishra@Sun.COM 	 */
214510393SSaurabh.Mishra@Sun.COM 	rxcfg &= ~ATGE_CFG_VLAN_TAG_STRIP;
214610393SSaurabh.Mishra@Sun.COM 
214710393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_filter_flags & (ATGE_PROMISC | ATGE_ALL_MULTICST)) {
214810393SSaurabh.Mishra@Sun.COM 		mchash = ~0ULL;
214910393SSaurabh.Mishra@Sun.COM 
215010393SSaurabh.Mishra@Sun.COM 		if (atgep->atge_filter_flags & ATGE_PROMISC)
215110393SSaurabh.Mishra@Sun.COM 			rxcfg |= ATGE_CFG_PROMISC;
215210393SSaurabh.Mishra@Sun.COM 
215310393SSaurabh.Mishra@Sun.COM 		if (atgep->atge_filter_flags & ATGE_ALL_MULTICST)
215410393SSaurabh.Mishra@Sun.COM 			rxcfg |= ATGE_CFG_ALLMULTI;
215510393SSaurabh.Mishra@Sun.COM 	} else {
215610393SSaurabh.Mishra@Sun.COM 		mchash = atgep->atge_mchash;
215710393SSaurabh.Mishra@Sun.COM 	}
215810393SSaurabh.Mishra@Sun.COM 
215910393SSaurabh.Mishra@Sun.COM 	atge_program_ether(atgep);
216010393SSaurabh.Mishra@Sun.COM 
216110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAR0, (uint32_t)mchash);
216210393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAR1, (uint32_t)(mchash >> 32));
216310393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAC_CFG, rxcfg);
216410393SSaurabh.Mishra@Sun.COM 
216510393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx",
216610393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, rxcfg, mchash));
216710393SSaurabh.Mishra@Sun.COM }
216810393SSaurabh.Mishra@Sun.COM 
216910393SSaurabh.Mishra@Sun.COM void
217010393SSaurabh.Mishra@Sun.COM atge_device_stop(atge_t *atgep)
217110393SSaurabh.Mishra@Sun.COM {
217210393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
217310393SSaurabh.Mishra@Sun.COM 	int t;
217410393SSaurabh.Mishra@Sun.COM 
217510393SSaurabh.Mishra@Sun.COM 	/*
217610393SSaurabh.Mishra@Sun.COM 	 * If the chip is being suspended, then don't touch the state. Caller
217710393SSaurabh.Mishra@Sun.COM 	 * will take care of setting the correct state.
217810393SSaurabh.Mishra@Sun.COM 	 */
217910393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
218010393SSaurabh.Mishra@Sun.COM 		atgep->atge_chip_state |= ATGE_CHIP_STOPPED;
218110393SSaurabh.Mishra@Sun.COM 		atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
218210393SSaurabh.Mishra@Sun.COM 	}
218310393SSaurabh.Mishra@Sun.COM 
218410393SSaurabh.Mishra@Sun.COM 	/*
218510393SSaurabh.Mishra@Sun.COM 	 * Collect stats for L1E. L1 chip's stats are collected by interrupt.
218610393SSaurabh.Mishra@Sun.COM 	 */
218710393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
218810393SSaurabh.Mishra@Sun.COM 		atge_l1e_gather_stats(atgep);
218910393SSaurabh.Mishra@Sun.COM 	}
219010393SSaurabh.Mishra@Sun.COM 
219110393SSaurabh.Mishra@Sun.COM 	/*
219210393SSaurabh.Mishra@Sun.COM 	 * Disable interrupts.
219310393SSaurabh.Mishra@Sun.COM 	 */
219410393SSaurabh.Mishra@Sun.COM 	atge_disable_intrs(atgep);
219510393SSaurabh.Mishra@Sun.COM 
2196*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1)
2197*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CSMB_CTRL, 0);
2198*11353SSaurabh.Mishra@Sun.COM 
2199*11353SSaurabh.Mishra@Sun.COM 	/* Stop DMA Engine */
2200*11353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2201*11353SSaurabh.Mishra@Sun.COM 		atge_l1_stop_tx_mac(atgep);
2202*11353SSaurabh.Mishra@Sun.COM 		atge_l1_stop_rx_mac(atgep);
2203*11353SSaurabh.Mishra@Sun.COM 
2204*11353SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, ATGE_DMA_CFG);
2205*11353SSaurabh.Mishra@Sun.COM 		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
2206*11353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG, reg);
2207*11353SSaurabh.Mishra@Sun.COM 
2208*11353SSaurabh.Mishra@Sun.COM 	}
2209*11353SSaurabh.Mishra@Sun.COM 
221010393SSaurabh.Mishra@Sun.COM 	/*
221110393SSaurabh.Mishra@Sun.COM 	 * Disable queue processing.
221210393SSaurabh.Mishra@Sun.COM 	 */
221310393SSaurabh.Mishra@Sun.COM 	/* Stop TxQ */
221410393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_TXQ_CFG);
221510393SSaurabh.Mishra@Sun.COM 	reg = reg & ~TXQ_CFG_ENB;
221610393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_TXQ_CFG, reg);
221710393SSaurabh.Mishra@Sun.COM 
221810393SSaurabh.Mishra@Sun.COM 	/* Stop RxQ */
221910393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_RXQ_CFG);
222010393SSaurabh.Mishra@Sun.COM 	reg = reg & ~RXQ_CFG_ENB;
222110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_RXQ_CFG, reg);
222210393SSaurabh.Mishra@Sun.COM 
222310393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
222410393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, ATGE_DMA_CFG);
222510393SSaurabh.Mishra@Sun.COM 		reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB);
222610393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG, reg);
222710393SSaurabh.Mishra@Sun.COM 		drv_usecwait(1000);
222810393SSaurabh.Mishra@Sun.COM 		atge_l1e_stop_mac(atgep);
222910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
223010393SSaurabh.Mishra@Sun.COM 	}
223110393SSaurabh.Mishra@Sun.COM 
223210393SSaurabh.Mishra@Sun.COM 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
223310393SSaurabh.Mishra@Sun.COM 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
223410393SSaurabh.Mishra@Sun.COM 			break;
223510393SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
223610393SSaurabh.Mishra@Sun.COM 	}
223710393SSaurabh.Mishra@Sun.COM 
223810393SSaurabh.Mishra@Sun.COM 	if (t == 0) {
223910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() stopping TX/RX MAC timeout",
224010393SSaurabh.Mishra@Sun.COM 		    __func__);
224110393SSaurabh.Mishra@Sun.COM 	}
224210393SSaurabh.Mishra@Sun.COM }
224310393SSaurabh.Mishra@Sun.COM 
224410393SSaurabh.Mishra@Sun.COM void
224510393SSaurabh.Mishra@Sun.COM atge_disable_intrs(atge_t *atgep)
224610393SSaurabh.Mishra@Sun.COM {
224710393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_INTR_MASK, 0);
224810393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
224910393SSaurabh.Mishra@Sun.COM }
225010393SSaurabh.Mishra@Sun.COM 
225110393SSaurabh.Mishra@Sun.COM void
225210393SSaurabh.Mishra@Sun.COM atge_device_init(atge_t *atgep)
225310393SSaurabh.Mishra@Sun.COM {
225410393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
225510393SSaurabh.Mishra@Sun.COM 		atgep->atge_intrs = L1E_INTRS;
225610393SSaurabh.Mishra@Sun.COM 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
225710393SSaurabh.Mishra@Sun.COM 
225810393SSaurabh.Mishra@Sun.COM 		atge_l1e_init_tx_ring(atgep);
225910393SSaurabh.Mishra@Sun.COM 		atge_l1e_init_rx_pages(atgep);
2260*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2261*11353SSaurabh.Mishra@Sun.COM 		atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN |
2262*11353SSaurabh.Mishra@Sun.COM 		    INTR_LINK_CHG;
2263*11353SSaurabh.Mishra@Sun.COM 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
2264*11353SSaurabh.Mishra@Sun.COM 
2265*11353SSaurabh.Mishra@Sun.COM 		atge_l1_init_tx_ring(atgep);
2266*11353SSaurabh.Mishra@Sun.COM 		atge_l1_init_rx_ring(atgep);
2267*11353SSaurabh.Mishra@Sun.COM 		atge_l1_init_rr_ring(atgep);
2268*11353SSaurabh.Mishra@Sun.COM 		atge_l1_init_cmb(atgep);
2269*11353SSaurabh.Mishra@Sun.COM 		atge_l1_init_smb(atgep);
227010393SSaurabh.Mishra@Sun.COM 	}
227110393SSaurabh.Mishra@Sun.COM }
227210393SSaurabh.Mishra@Sun.COM 
227310393SSaurabh.Mishra@Sun.COM void
227410393SSaurabh.Mishra@Sun.COM atge_device_restart(atge_t *atgep)
227510393SSaurabh.Mishra@Sun.COM {
227610393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
227710393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
227810393SSaurabh.Mishra@Sun.COM 
227910393SSaurabh.Mishra@Sun.COM 	/*
228010393SSaurabh.Mishra@Sun.COM 	 * Cancel any pending I/O.
228110393SSaurabh.Mishra@Sun.COM 	 */
228210393SSaurabh.Mishra@Sun.COM 	atge_device_stop(atgep);
228310393SSaurabh.Mishra@Sun.COM 
228410393SSaurabh.Mishra@Sun.COM 	/*
228510393SSaurabh.Mishra@Sun.COM 	 * Reset the chip to a known state.
228610393SSaurabh.Mishra@Sun.COM 	 */
228710393SSaurabh.Mishra@Sun.COM 	atge_device_reset(atgep);
228810393SSaurabh.Mishra@Sun.COM 
228910393SSaurabh.Mishra@Sun.COM 	/*
229010393SSaurabh.Mishra@Sun.COM 	 * Initialize the ring and other descriptor like CMB/SMB/Rx return.
229110393SSaurabh.Mishra@Sun.COM 	 */
229210393SSaurabh.Mishra@Sun.COM 	atge_device_init(atgep);
229310393SSaurabh.Mishra@Sun.COM 
229410393SSaurabh.Mishra@Sun.COM 	/*
229510393SSaurabh.Mishra@Sun.COM 	 * Start the chip.
229610393SSaurabh.Mishra@Sun.COM 	 */
229710393SSaurabh.Mishra@Sun.COM 	atge_device_start(atgep);
229810393SSaurabh.Mishra@Sun.COM 
229910393SSaurabh.Mishra@Sun.COM }
230010393SSaurabh.Mishra@Sun.COM 
230110393SSaurabh.Mishra@Sun.COM static int
230210393SSaurabh.Mishra@Sun.COM atge_send_a_packet(atge_t *atgep, mblk_t *mp)
230310393SSaurabh.Mishra@Sun.COM {
2304*11353SSaurabh.Mishra@Sun.COM 	atge_tx_desc_t	*txd;
2305*11353SSaurabh.Mishra@Sun.COM 	uchar_t *c;
2306*11353SSaurabh.Mishra@Sun.COM 	uint32_t cflags = 0;
230710393SSaurabh.Mishra@Sun.COM 	atge_ring_t *r;
230810393SSaurabh.Mishra@Sun.COM 	size_t pktlen;
230910393SSaurabh.Mishra@Sun.COM 	uchar_t *buf;
231010393SSaurabh.Mishra@Sun.COM 	int	start;
231110393SSaurabh.Mishra@Sun.COM 
231210393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
231310393SSaurabh.Mishra@Sun.COM 	ASSERT(mp != NULL);
231410393SSaurabh.Mishra@Sun.COM 
231510393SSaurabh.Mishra@Sun.COM 	pktlen = msgsize(mp);
231610393SSaurabh.Mishra@Sun.COM 	if (pktlen > atgep->atge_tx_buf_len) {
231710393SSaurabh.Mishra@Sun.COM 		atgep->atge_macxmt_errors++;
231810393SSaurabh.Mishra@Sun.COM 
231910393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)",
232010393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__,
232110393SSaurabh.Mishra@Sun.COM 		    pktlen, atgep->atge_rx_buf_len));
232210393SSaurabh.Mishra@Sun.COM 
232310393SSaurabh.Mishra@Sun.COM 		freemsg(mp);
2324*11353SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
232510393SSaurabh.Mishra@Sun.COM 	}
232610393SSaurabh.Mishra@Sun.COM 
232710393SSaurabh.Mishra@Sun.COM 	r = atgep->atge_tx_ring;
232810393SSaurabh.Mishra@Sun.COM 
232910393SSaurabh.Mishra@Sun.COM 	if (r->r_avail_desc <= 1) {
233010393SSaurabh.Mishra@Sun.COM 		atgep->atge_noxmtbuf++;
233110393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 1;
2332*11353SSaurabh.Mishra@Sun.COM 
2333*11353SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() No transmit buf",
2334*11353SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__));
2335*11353SSaurabh.Mishra@Sun.COM 
2336*11353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
233710393SSaurabh.Mishra@Sun.COM 	}
233810393SSaurabh.Mishra@Sun.COM 
233910393SSaurabh.Mishra@Sun.COM 	start = r->r_producer;
234010393SSaurabh.Mishra@Sun.COM 
234110393SSaurabh.Mishra@Sun.COM 	/*
234210393SSaurabh.Mishra@Sun.COM 	 * Get the DMA buffer to hold a packet.
234310393SSaurabh.Mishra@Sun.COM 	 */
234410393SSaurabh.Mishra@Sun.COM 	buf = (uchar_t *)r->r_buf_tbl[start]->addr;
234510393SSaurabh.Mishra@Sun.COM 
234610393SSaurabh.Mishra@Sun.COM 	/*
234710393SSaurabh.Mishra@Sun.COM 	 * Copy the msg and free mp
234810393SSaurabh.Mishra@Sun.COM 	 */
234910393SSaurabh.Mishra@Sun.COM 	mcopymsg(mp, buf);
235010393SSaurabh.Mishra@Sun.COM 
235110393SSaurabh.Mishra@Sun.COM 	r->r_avail_desc--;
235210393SSaurabh.Mishra@Sun.COM 
2353*11353SSaurabh.Mishra@Sun.COM 	c = (uchar_t *)r->r_desc_ring->addr;
2354*11353SSaurabh.Mishra@Sun.COM 	c += (sizeof (atge_tx_desc_t) * start);
2355*11353SSaurabh.Mishra@Sun.COM 	txd = (atge_tx_desc_t *)c;
2356*11353SSaurabh.Mishra@Sun.COM 
2357*11353SSaurabh.Mishra@Sun.COM 	ATGE_PUT64(r->r_desc_ring, &txd->addr,
2358*11353SSaurabh.Mishra@Sun.COM 	    r->r_buf_tbl[start]->cookie.dmac_laddress);
2359*11353SSaurabh.Mishra@Sun.COM 
2360*11353SSaurabh.Mishra@Sun.COM 	ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
2361*11353SSaurabh.Mishra@Sun.COM 
2362*11353SSaurabh.Mishra@Sun.COM 	cflags |= ATGE_TD_EOP;
2363*11353SSaurabh.Mishra@Sun.COM 	ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
2364*11353SSaurabh.Mishra@Sun.COM 
2365*11353SSaurabh.Mishra@Sun.COM 	/*
2366*11353SSaurabh.Mishra@Sun.COM 	 * Sync buffer first.
2367*11353SSaurabh.Mishra@Sun.COM 	 */
2368*11353SSaurabh.Mishra@Sun.COM 	DMA_SYNC(r->r_buf_tbl[start], 0, pktlen, DDI_DMA_SYNC_FORDEV);
2369*11353SSaurabh.Mishra@Sun.COM 
2370*11353SSaurabh.Mishra@Sun.COM 	/*
2371*11353SSaurabh.Mishra@Sun.COM 	 * Increment TX producer count by one.
2372*11353SSaurabh.Mishra@Sun.COM 	 */
2373*11353SSaurabh.Mishra@Sun.COM 	ATGE_INC_SLOT(r->r_producer, ATGE_TX_RING_CNT);
2374*11353SSaurabh.Mishra@Sun.COM 
2375*11353SSaurabh.Mishra@Sun.COM 	/*
2376*11353SSaurabh.Mishra@Sun.COM 	 * Sync descriptor table.
2377*11353SSaurabh.Mishra@Sun.COM 	 */
2378*11353SSaurabh.Mishra@Sun.COM 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
2379*11353SSaurabh.Mishra@Sun.COM 
238010393SSaurabh.Mishra@Sun.COM 	/*
238110393SSaurabh.Mishra@Sun.COM 	 * Program TX descriptor to send a packet.
238210393SSaurabh.Mishra@Sun.COM 	 */
238310393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
2384*11353SSaurabh.Mishra@Sun.COM 		atge_l1e_send_packet(r);
2385*11353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
2386*11353SSaurabh.Mishra@Sun.COM 		atge_l1_send_packet(r);
238710393SSaurabh.Mishra@Sun.COM 	}
238810393SSaurabh.Mishra@Sun.COM 
2389*11353SSaurabh.Mishra@Sun.COM 	r->r_atge->atge_opackets++;
2390*11353SSaurabh.Mishra@Sun.COM 	r->r_atge->atge_obytes += pktlen;
2391*11353SSaurabh.Mishra@Sun.COM 
2392*11353SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer  :%d, "
2393*11353SSaurabh.Mishra@Sun.COM 	    "consumer : %d", atgep->atge_name, __func__, pktlen,
2394*11353SSaurabh.Mishra@Sun.COM 	    r->r_avail_desc, r->r_producer, r->r_consumer));
2395*11353SSaurabh.Mishra@Sun.COM 
2396*11353SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
239710393SSaurabh.Mishra@Sun.COM }
239810393SSaurabh.Mishra@Sun.COM 
239910393SSaurabh.Mishra@Sun.COM /*
240010393SSaurabh.Mishra@Sun.COM  * Stream Information.
240110393SSaurabh.Mishra@Sun.COM  */
240210393SSaurabh.Mishra@Sun.COM DDI_DEFINE_STREAM_OPS(atge_devops, nulldev, nulldev, atge_attach, atge_detach,
240310393SSaurabh.Mishra@Sun.COM     nodev, NULL, D_MP, NULL, atge_quiesce);
240410393SSaurabh.Mishra@Sun.COM 
240510393SSaurabh.Mishra@Sun.COM /*
240610393SSaurabh.Mishra@Sun.COM  * Module linkage information.
240710393SSaurabh.Mishra@Sun.COM  */
240810393SSaurabh.Mishra@Sun.COM static	struct	modldrv	atge_modldrv = {
240910393SSaurabh.Mishra@Sun.COM 	&mod_driverops,				/* Type of Module */
241010393SSaurabh.Mishra@Sun.COM 	"Atheros/Attansic Gb Ethernet",		/* Description */
241110393SSaurabh.Mishra@Sun.COM 	&atge_devops				/* drv_dev_ops */
241210393SSaurabh.Mishra@Sun.COM };
241310393SSaurabh.Mishra@Sun.COM 
241410393SSaurabh.Mishra@Sun.COM static	struct	modlinkage atge_modlinkage = {
241510393SSaurabh.Mishra@Sun.COM 	MODREV_1,			/* ml_rev */
241610393SSaurabh.Mishra@Sun.COM 	(void *)&atge_modldrv,
241710393SSaurabh.Mishra@Sun.COM 	NULL
241810393SSaurabh.Mishra@Sun.COM };
241910393SSaurabh.Mishra@Sun.COM 
242010393SSaurabh.Mishra@Sun.COM /*
242110393SSaurabh.Mishra@Sun.COM  * DDI Entry points.
242210393SSaurabh.Mishra@Sun.COM  */
242310393SSaurabh.Mishra@Sun.COM int
242410393SSaurabh.Mishra@Sun.COM _init(void)
242510393SSaurabh.Mishra@Sun.COM {
242610393SSaurabh.Mishra@Sun.COM 	int	r;
242710393SSaurabh.Mishra@Sun.COM 	mac_init_ops(&atge_devops, "atge");
242810393SSaurabh.Mishra@Sun.COM 	if ((r = mod_install(&atge_modlinkage)) != DDI_SUCCESS) {
242910393SSaurabh.Mishra@Sun.COM 		mac_fini_ops(&atge_devops);
243010393SSaurabh.Mishra@Sun.COM 	}
243110393SSaurabh.Mishra@Sun.COM 
243210393SSaurabh.Mishra@Sun.COM 	return (r);
243310393SSaurabh.Mishra@Sun.COM }
243410393SSaurabh.Mishra@Sun.COM 
243510393SSaurabh.Mishra@Sun.COM int
243610393SSaurabh.Mishra@Sun.COM _fini(void)
243710393SSaurabh.Mishra@Sun.COM {
243810393SSaurabh.Mishra@Sun.COM 	int	r;
243910393SSaurabh.Mishra@Sun.COM 
244010393SSaurabh.Mishra@Sun.COM 	if ((r = mod_remove(&atge_modlinkage)) == DDI_SUCCESS) {
244110393SSaurabh.Mishra@Sun.COM 		mac_fini_ops(&atge_devops);
244210393SSaurabh.Mishra@Sun.COM 	}
244310393SSaurabh.Mishra@Sun.COM 
244410393SSaurabh.Mishra@Sun.COM 	return (r);
244510393SSaurabh.Mishra@Sun.COM }
244610393SSaurabh.Mishra@Sun.COM 
244710393SSaurabh.Mishra@Sun.COM int
244810393SSaurabh.Mishra@Sun.COM _info(struct modinfo *modinfop)
244910393SSaurabh.Mishra@Sun.COM {
245010393SSaurabh.Mishra@Sun.COM 	return (mod_info(&atge_modlinkage, modinfop));
245110393SSaurabh.Mishra@Sun.COM }
2452