xref: /onnv-gate/usr/src/uts/common/io/atge/atge_main.c (revision 12398:d1a36c3701ab)
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 /*
23*12398Sgdamore@opensolaris.org  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410393SSaurabh.Mishra@Sun.COM  */
2510393SSaurabh.Mishra@Sun.COM 
2610393SSaurabh.Mishra@Sun.COM #include <sys/types.h>
2710393SSaurabh.Mishra@Sun.COM #include <sys/stream.h>
2810393SSaurabh.Mishra@Sun.COM #include <sys/strsun.h>
2910393SSaurabh.Mishra@Sun.COM #include <sys/stat.h>
3010393SSaurabh.Mishra@Sun.COM #include <sys/modctl.h>
3110393SSaurabh.Mishra@Sun.COM #include <sys/kstat.h>
3210393SSaurabh.Mishra@Sun.COM #include <sys/ethernet.h>
3310393SSaurabh.Mishra@Sun.COM #include <sys/devops.h>
3410393SSaurabh.Mishra@Sun.COM #include <sys/debug.h>
3510393SSaurabh.Mishra@Sun.COM #include <sys/conf.h>
3610393SSaurabh.Mishra@Sun.COM #include <sys/mii.h>
3710393SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h>
3810393SSaurabh.Mishra@Sun.COM #include <sys/mac.h>
3910393SSaurabh.Mishra@Sun.COM #include <sys/mac_provider.h>
4010393SSaurabh.Mishra@Sun.COM #include <sys/mac_ether.h>
4110393SSaurabh.Mishra@Sun.COM #include <sys/sysmacros.h>
4210393SSaurabh.Mishra@Sun.COM #include <sys/dditypes.h>
4310393SSaurabh.Mishra@Sun.COM #include <sys/ddi.h>
4410393SSaurabh.Mishra@Sun.COM #include <sys/sunddi.h>
4510393SSaurabh.Mishra@Sun.COM #include <sys/byteorder.h>
4610393SSaurabh.Mishra@Sun.COM #include <sys/note.h>
4710393SSaurabh.Mishra@Sun.COM #include <sys/vlan.h>
4810393SSaurabh.Mishra@Sun.COM #include <sys/strsubr.h>
4910393SSaurabh.Mishra@Sun.COM #include <sys/crc32.h>
5010393SSaurabh.Mishra@Sun.COM #include <sys/sdt.h>
5110393SSaurabh.Mishra@Sun.COM #include <sys/pci.h>
5210393SSaurabh.Mishra@Sun.COM #include <sys/pci_cap.h>
5310393SSaurabh.Mishra@Sun.COM 
5410393SSaurabh.Mishra@Sun.COM #include "atge.h"
5510393SSaurabh.Mishra@Sun.COM #include "atge_cmn_reg.h"
5610393SSaurabh.Mishra@Sun.COM #include "atge_l1e_reg.h"
5711353SSaurabh.Mishra@Sun.COM #include "atge_l1_reg.h"
5810393SSaurabh.Mishra@Sun.COM 
5910393SSaurabh.Mishra@Sun.COM 
6010393SSaurabh.Mishra@Sun.COM /*
6110393SSaurabh.Mishra@Sun.COM  * Atheros/Attansic Ethernet chips are of three types - L1, L2 and L1E.
6211353SSaurabh.Mishra@Sun.COM  * This driver is for L1E/L1 but can be extended to support other chips.
6311353SSaurabh.Mishra@Sun.COM  * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
6411353SSaurabh.Mishra@Sun.COM  * flavors only.
6510393SSaurabh.Mishra@Sun.COM  *
6610393SSaurabh.Mishra@Sun.COM  * Atheros/Attansic Ethernet controllers have descriptor based TX and RX
6710393SSaurabh.Mishra@Sun.COM  * with an exception of L1E. L1E's RX side is not descriptor based ring.
6810393SSaurabh.Mishra@Sun.COM  * The L1E's RX uses pages (not to be confused with MMU pages) for
6910393SSaurabh.Mishra@Sun.COM  * receiving pkts. The header has four fields :
7010393SSaurabh.Mishra@Sun.COM  *
7110393SSaurabh.Mishra@Sun.COM  *        uint32_t seqno;    Sequence number of the frame.
7210393SSaurabh.Mishra@Sun.COM  *        uint32_t length;   Length of the frame.
7310393SSaurabh.Mishra@Sun.COM  *        uint32_t flags;    Flags
7410393SSaurabh.Mishra@Sun.COM  *        uint32_t vtag;     We don't use hardware VTAG.
7510393SSaurabh.Mishra@Sun.COM  *
7610393SSaurabh.Mishra@Sun.COM  * We use only one queue for RX (each queue can have two pages) and each
7710393SSaurabh.Mishra@Sun.COM  * page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't
7810393SSaurabh.Mishra@Sun.COM  * use zero-copy RX because we are limited to two pages and each page
7910393SSaurabh.Mishra@Sun.COM  * accomodates large number of pkts.
8010393SSaurabh.Mishra@Sun.COM  *
8110393SSaurabh.Mishra@Sun.COM  * The TX side on all three chips is descriptor based ring; and all the
8210393SSaurabh.Mishra@Sun.COM  * more reason to have one driver for these chips.
8310393SSaurabh.Mishra@Sun.COM  *
8410393SSaurabh.Mishra@Sun.COM  * We use two locks - atge_intr_lock and atge_tx_lock. Both the locks
8510393SSaurabh.Mishra@Sun.COM  * should be held if the operation has impact on the driver instance.
8610393SSaurabh.Mishra@Sun.COM  *
8710393SSaurabh.Mishra@Sun.COM  * All the three chips have hash-based multicast filter.
8810393SSaurabh.Mishra@Sun.COM  *
8910393SSaurabh.Mishra@Sun.COM  * We use CMB (Coalescing Message Block) for RX but not for TX as there
9010393SSaurabh.Mishra@Sun.COM  * are some issues with TX. RX CMB is used to get the last descriptor
9110393SSaurabh.Mishra@Sun.COM  * posted by the chip. Each CMB is for a RX page (one queue can have two
9210393SSaurabh.Mishra@Sun.COM  * pages) and are uint32_t (4 bytes) long.
9310393SSaurabh.Mishra@Sun.COM  *
9410393SSaurabh.Mishra@Sun.COM  * The descriptor table should have 32-bit physical address limit due to
9510393SSaurabh.Mishra@Sun.COM  * the limitation of having same high address for TX/RX/SMB/CMB. The
9610393SSaurabh.Mishra@Sun.COM  * TX/RX buffers can be 64-bit.
9710393SSaurabh.Mishra@Sun.COM  *
9810393SSaurabh.Mishra@Sun.COM  * Every DMA memory in atge is represented by atge_dma_t be it TX/RX Buffers
9910393SSaurabh.Mishra@Sun.COM  * or TX/RX descriptor table or SMB/CMB. To keep the code simple, we have
10010393SSaurabh.Mishra@Sun.COM  * kept sgl as 1 so that we get contingous pages from root complex.
10111353SSaurabh.Mishra@Sun.COM  *
10211353SSaurabh.Mishra@Sun.COM  * L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are
10311353SSaurabh.Mishra@Sun.COM  * common with L1E chip (0x1026).
10410393SSaurabh.Mishra@Sun.COM  */
10510393SSaurabh.Mishra@Sun.COM 
10610393SSaurabh.Mishra@Sun.COM /*
10710393SSaurabh.Mishra@Sun.COM  * Function Prototypes for debugging.
10810393SSaurabh.Mishra@Sun.COM  */
10910393SSaurabh.Mishra@Sun.COM void	atge_error(dev_info_t *, char *, ...);
11010393SSaurabh.Mishra@Sun.COM void	atge_debug_func(char *, ...);
11110393SSaurabh.Mishra@Sun.COM 
11210393SSaurabh.Mishra@Sun.COM /*
11310393SSaurabh.Mishra@Sun.COM  * Function Prototypes for driver operations.
11410393SSaurabh.Mishra@Sun.COM  */
11510393SSaurabh.Mishra@Sun.COM static int	atge_resume(dev_info_t *);
11610393SSaurabh.Mishra@Sun.COM static int	atge_add_intr(atge_t *);
11710393SSaurabh.Mishra@Sun.COM static int	atge_alloc_dma(atge_t *);
11810393SSaurabh.Mishra@Sun.COM static void	atge_remove_intr(atge_t *);
11910393SSaurabh.Mishra@Sun.COM static void	atge_free_dma(atge_t *);
12010393SSaurabh.Mishra@Sun.COM static void	atge_device_reset(atge_t *);
12110393SSaurabh.Mishra@Sun.COM static void	atge_device_init(atge_t *);
12210393SSaurabh.Mishra@Sun.COM static void	atge_device_start(atge_t *);
12310393SSaurabh.Mishra@Sun.COM static void	atge_disable_intrs(atge_t *);
12410393SSaurabh.Mishra@Sun.COM atge_dma_t *atge_alloc_a_dma_blk(atge_t *, ddi_dma_attr_t *, int, int);
12510393SSaurabh.Mishra@Sun.COM void	atge_free_a_dma_blk(atge_dma_t *);
12610393SSaurabh.Mishra@Sun.COM static void	atge_rxfilter(atge_t *);
12710393SSaurabh.Mishra@Sun.COM static void	atge_device_reset_l1_l1e(atge_t *);
12810393SSaurabh.Mishra@Sun.COM void	atge_program_ether(atge_t *atgep);
12910393SSaurabh.Mishra@Sun.COM void	atge_device_restart(atge_t *);
13011353SSaurabh.Mishra@Sun.COM void	atge_device_stop(atge_t *);
13110393SSaurabh.Mishra@Sun.COM static int	atge_send_a_packet(atge_t *, mblk_t *);
13210393SSaurabh.Mishra@Sun.COM static uint32_t	atge_ether_crc(const uint8_t *, int);
13310393SSaurabh.Mishra@Sun.COM 
13410393SSaurabh.Mishra@Sun.COM 
13510393SSaurabh.Mishra@Sun.COM /*
13611353SSaurabh.Mishra@Sun.COM  * L1E/L2E specific functions.
13710393SSaurabh.Mishra@Sun.COM  */
13810393SSaurabh.Mishra@Sun.COM void	atge_l1e_device_reset(atge_t *);
13910393SSaurabh.Mishra@Sun.COM void	atge_l1e_stop_mac(atge_t *);
14010393SSaurabh.Mishra@Sun.COM int	atge_l1e_alloc_dma(atge_t *);
14110393SSaurabh.Mishra@Sun.COM void	atge_l1e_free_dma(atge_t *);
14210393SSaurabh.Mishra@Sun.COM void	atge_l1e_init_tx_ring(atge_t *);
14310393SSaurabh.Mishra@Sun.COM void	atge_l1e_init_rx_pages(atge_t *);
14410393SSaurabh.Mishra@Sun.COM void	atge_l1e_program_dma(atge_t *);
14511353SSaurabh.Mishra@Sun.COM void	atge_l1e_send_packet(atge_ring_t *);
14610393SSaurabh.Mishra@Sun.COM mblk_t	*atge_l1e_receive(atge_t *);
14711353SSaurabh.Mishra@Sun.COM uint_t	atge_l1e_interrupt(caddr_t, caddr_t);
14810393SSaurabh.Mishra@Sun.COM void	atge_l1e_gather_stats(atge_t *);
14910393SSaurabh.Mishra@Sun.COM void	atge_l1e_clear_stats(atge_t *);
15010393SSaurabh.Mishra@Sun.COM 
15110393SSaurabh.Mishra@Sun.COM /*
15211353SSaurabh.Mishra@Sun.COM  * L1 specific functions.
15311353SSaurabh.Mishra@Sun.COM  */
15411353SSaurabh.Mishra@Sun.COM int	atge_l1_alloc_dma(atge_t *);
15511353SSaurabh.Mishra@Sun.COM void	atge_l1_init_tx_ring(atge_t *);
15611353SSaurabh.Mishra@Sun.COM void	atge_l1_init_rx_ring(atge_t *);
15711353SSaurabh.Mishra@Sun.COM void	atge_l1_init_rr_ring(atge_t *);
15811353SSaurabh.Mishra@Sun.COM void	atge_l1_init_cmb(atge_t *);
15911353SSaurabh.Mishra@Sun.COM void	atge_l1_init_smb(atge_t *);
16011353SSaurabh.Mishra@Sun.COM void	atge_l1_program_dma(atge_t *);
16111353SSaurabh.Mishra@Sun.COM void	atge_l1_stop_tx_mac(atge_t *);
16211353SSaurabh.Mishra@Sun.COM void	atge_l1_stop_rx_mac(atge_t *);
16311353SSaurabh.Mishra@Sun.COM uint_t	atge_l1_interrupt(caddr_t, caddr_t);
16411353SSaurabh.Mishra@Sun.COM void	atge_l1_send_packet(atge_ring_t *);
16511353SSaurabh.Mishra@Sun.COM 
16611353SSaurabh.Mishra@Sun.COM 
16711353SSaurabh.Mishra@Sun.COM /*
16810393SSaurabh.Mishra@Sun.COM  * Function prototyps for MII operations.
16910393SSaurabh.Mishra@Sun.COM  */
17010393SSaurabh.Mishra@Sun.COM uint16_t	atge_mii_read(void *, uint8_t, uint8_t);
17110393SSaurabh.Mishra@Sun.COM void	atge_mii_write(void *, uint8_t, uint8_t, uint16_t);
17210393SSaurabh.Mishra@Sun.COM void	atge_l1e_mii_reset(void *);
17311353SSaurabh.Mishra@Sun.COM void	atge_l1_mii_reset(void *);
17410393SSaurabh.Mishra@Sun.COM static void	atge_mii_notify(void *, link_state_t);
17511353SSaurabh.Mishra@Sun.COM void	atge_tx_reclaim(atge_t *atgep, int cons);
17611353SSaurabh.Mishra@Sun.COM 
17711353SSaurabh.Mishra@Sun.COM /*
17811353SSaurabh.Mishra@Sun.COM  * L1E/L2E chip.
17911353SSaurabh.Mishra@Sun.COM  */
18010393SSaurabh.Mishra@Sun.COM static	mii_ops_t atge_l1e_mii_ops = {
18110393SSaurabh.Mishra@Sun.COM 	MII_OPS_VERSION,
18210393SSaurabh.Mishra@Sun.COM 	atge_mii_read,
18310393SSaurabh.Mishra@Sun.COM 	atge_mii_write,
18410393SSaurabh.Mishra@Sun.COM 	atge_mii_notify,
18510393SSaurabh.Mishra@Sun.COM 	atge_l1e_mii_reset
18610393SSaurabh.Mishra@Sun.COM };
18710393SSaurabh.Mishra@Sun.COM 
18810393SSaurabh.Mishra@Sun.COM /*
18911353SSaurabh.Mishra@Sun.COM  * L1 chip.
19011353SSaurabh.Mishra@Sun.COM  */
19111353SSaurabh.Mishra@Sun.COM static	mii_ops_t atge_l1_mii_ops = {
19211353SSaurabh.Mishra@Sun.COM 	MII_OPS_VERSION,
19311353SSaurabh.Mishra@Sun.COM 	atge_mii_read,
19411353SSaurabh.Mishra@Sun.COM 	atge_mii_write,
19511353SSaurabh.Mishra@Sun.COM 	atge_mii_notify,
19611353SSaurabh.Mishra@Sun.COM 	atge_l1_mii_reset
19711353SSaurabh.Mishra@Sun.COM };
19811353SSaurabh.Mishra@Sun.COM 
19911353SSaurabh.Mishra@Sun.COM /*
20010393SSaurabh.Mishra@Sun.COM  * Function Prototypes for MAC callbacks.
20110393SSaurabh.Mishra@Sun.COM  */
20210393SSaurabh.Mishra@Sun.COM static int	atge_m_stat(void *, uint_t, uint64_t *);
20310393SSaurabh.Mishra@Sun.COM static int	atge_m_start(void *);
20410393SSaurabh.Mishra@Sun.COM static void	atge_m_stop(void *);
20510393SSaurabh.Mishra@Sun.COM static int	atge_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
20611878SVenu.Iyer@Sun.COM     void *);
20710393SSaurabh.Mishra@Sun.COM static int	atge_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
20810393SSaurabh.Mishra@Sun.COM     const void *);
20911878SVenu.Iyer@Sun.COM static void	atge_m_propinfo(void *, const char *, mac_prop_id_t,
21011878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t);
21110393SSaurabh.Mishra@Sun.COM static int	atge_m_unicst(void *, const uint8_t *);
21210393SSaurabh.Mishra@Sun.COM static int	atge_m_multicst(void *, boolean_t, const uint8_t *);
21310393SSaurabh.Mishra@Sun.COM static int	atge_m_promisc(void *, boolean_t);
21410393SSaurabh.Mishra@Sun.COM static mblk_t	*atge_m_tx(void *, mblk_t *);
21510393SSaurabh.Mishra@Sun.COM 
21610393SSaurabh.Mishra@Sun.COM static	mac_callbacks_t	atge_m_callbacks = {
21711878SVenu.Iyer@Sun.COM 	MC_SETPROP | MC_GETPROP | MC_PROPINFO,
21810393SSaurabh.Mishra@Sun.COM 	atge_m_stat,
21910393SSaurabh.Mishra@Sun.COM 	atge_m_start,
22010393SSaurabh.Mishra@Sun.COM 	atge_m_stop,
22110393SSaurabh.Mishra@Sun.COM 	atge_m_promisc,
22210393SSaurabh.Mishra@Sun.COM 	atge_m_multicst,
22310393SSaurabh.Mishra@Sun.COM 	atge_m_unicst,
22410393SSaurabh.Mishra@Sun.COM 	atge_m_tx,
22511878SVenu.Iyer@Sun.COM 	NULL,		/* mc_reserved */
22610393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_ioctl */
22710393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_getcapab */
22810393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_open */
22910393SSaurabh.Mishra@Sun.COM 	NULL,		/* mc_close */
23010393SSaurabh.Mishra@Sun.COM 	atge_m_setprop,
23110393SSaurabh.Mishra@Sun.COM 	atge_m_getprop,
23211878SVenu.Iyer@Sun.COM 	atge_m_propinfo
23310393SSaurabh.Mishra@Sun.COM };
23410393SSaurabh.Mishra@Sun.COM 
23510393SSaurabh.Mishra@Sun.COM /*
23610393SSaurabh.Mishra@Sun.COM  * DMA Data access requirements.
23710393SSaurabh.Mishra@Sun.COM  */
23810393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_dev_attr = {
23910393SSaurabh.Mishra@Sun.COM 	DDI_DEVICE_ATTR_V0,
24010393SSaurabh.Mishra@Sun.COM 	DDI_STRUCTURE_LE_ACC,
24110393SSaurabh.Mishra@Sun.COM 	DDI_STRICTORDER_ACC
24210393SSaurabh.Mishra@Sun.COM };
24310393SSaurabh.Mishra@Sun.COM 
24410393SSaurabh.Mishra@Sun.COM /*
24510393SSaurabh.Mishra@Sun.COM  * Buffers should be native endianness.
24610393SSaurabh.Mishra@Sun.COM  */
24710393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_buf_attr = {
24810393SSaurabh.Mishra@Sun.COM 	DDI_DEVICE_ATTR_V0,
24910393SSaurabh.Mishra@Sun.COM 	DDI_NEVERSWAP_ACC,	/* native endianness */
25010393SSaurabh.Mishra@Sun.COM 	DDI_STRICTORDER_ACC
25110393SSaurabh.Mishra@Sun.COM };
25210393SSaurabh.Mishra@Sun.COM 
25310393SSaurabh.Mishra@Sun.COM /*
25411353SSaurabh.Mishra@Sun.COM  * DMA device attributes. Buffer can be 64-bit.
25510393SSaurabh.Mishra@Sun.COM  */
25610393SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t atge_dma_attr_buf = {
25710393SSaurabh.Mishra@Sun.COM 	DMA_ATTR_V0,		/* dma_attr_version */
25810393SSaurabh.Mishra@Sun.COM 	0,			/* dma_attr_addr_lo */
25910393SSaurabh.Mishra@Sun.COM 	0x00ffffffffffull,	/* dma_attr_addr_hi */
26010393SSaurabh.Mishra@Sun.COM 	0x000000003fffull,	/* dma_attr_count_max */
26110393SSaurabh.Mishra@Sun.COM 	8,			/* dma_attr_align */
26210393SSaurabh.Mishra@Sun.COM 	0x00003ffc,		/* dma_attr_burstsizes */
26310393SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_minxfer */
26410393SSaurabh.Mishra@Sun.COM 	0x0000000027ffull,	/* dma_attr_maxxfer */
26510393SSaurabh.Mishra@Sun.COM 	0x0000ffffffffull,	/* dma_attr_seg */
26610393SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_sgllen */
26710393SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_granular */
26810393SSaurabh.Mishra@Sun.COM 	0			/* dma_attr_flags */
26910393SSaurabh.Mishra@Sun.COM };
27010393SSaurabh.Mishra@Sun.COM 
27110393SSaurabh.Mishra@Sun.COM /*
27210393SSaurabh.Mishra@Sun.COM  * Table of supported devices.
27310393SSaurabh.Mishra@Sun.COM  */
27410393SSaurabh.Mishra@Sun.COM #define	ATGE_VENDOR_ID	0x1969
27510393SSaurabh.Mishra@Sun.COM #define	ATGE_L1E_STR	"Atheros AR8121/8113/8114"
27610393SSaurabh.Mishra@Sun.COM 
27710393SSaurabh.Mishra@Sun.COM static atge_cards_t atge_cards[] = {
27810393SSaurabh.Mishra@Sun.COM 	{ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E},
27911353SSaurabh.Mishra@Sun.COM 	{ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, "Attansic L1", ATGE_CHIP_L1},
28010393SSaurabh.Mishra@Sun.COM };
28110393SSaurabh.Mishra@Sun.COM 
28210393SSaurabh.Mishra@Sun.COM /*
28310393SSaurabh.Mishra@Sun.COM  * Global Debugging flag. Developer level debugging is done only in DEBUG mode.
28410393SSaurabh.Mishra@Sun.COM  */
28510393SSaurabh.Mishra@Sun.COM int	atge_debug = 1;
28610393SSaurabh.Mishra@Sun.COM 
28710393SSaurabh.Mishra@Sun.COM /*
28810393SSaurabh.Mishra@Sun.COM  * Debugging and error reporting.
28910393SSaurabh.Mishra@Sun.COM  */
29010393SSaurabh.Mishra@Sun.COM void
atge_debug_func(char * fmt,...)29110393SSaurabh.Mishra@Sun.COM atge_debug_func(char *fmt, ...)
29210393SSaurabh.Mishra@Sun.COM {
29310393SSaurabh.Mishra@Sun.COM 	va_list	ap;
29410393SSaurabh.Mishra@Sun.COM 	char	buf[256];
29510393SSaurabh.Mishra@Sun.COM 
29610393SSaurabh.Mishra@Sun.COM 	va_start(ap, fmt);
29710393SSaurabh.Mishra@Sun.COM 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
29810393SSaurabh.Mishra@Sun.COM 	va_end(ap);
29910393SSaurabh.Mishra@Sun.COM 
30010393SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE1(atge__debug, char *, buf);
30110393SSaurabh.Mishra@Sun.COM }
30210393SSaurabh.Mishra@Sun.COM 
30310393SSaurabh.Mishra@Sun.COM void
atge_error(dev_info_t * dip,char * fmt,...)30410393SSaurabh.Mishra@Sun.COM atge_error(dev_info_t *dip, char *fmt, ...)
30510393SSaurabh.Mishra@Sun.COM {
30610393SSaurabh.Mishra@Sun.COM 	va_list	ap;
30710393SSaurabh.Mishra@Sun.COM 	char	buf[256];
30810393SSaurabh.Mishra@Sun.COM 
30910393SSaurabh.Mishra@Sun.COM 	va_start(ap, fmt);
31010393SSaurabh.Mishra@Sun.COM 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
31110393SSaurabh.Mishra@Sun.COM 	va_end(ap);
31210393SSaurabh.Mishra@Sun.COM 
31310393SSaurabh.Mishra@Sun.COM 	if (dip) {
31410393SSaurabh.Mishra@Sun.COM 		cmn_err(CE_WARN, "%s%d: %s",
31510393SSaurabh.Mishra@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
31610393SSaurabh.Mishra@Sun.COM 	} else {
31710393SSaurabh.Mishra@Sun.COM 		cmn_err(CE_WARN, "atge: %s", buf);
31810393SSaurabh.Mishra@Sun.COM 	}
31910393SSaurabh.Mishra@Sun.COM }
32010393SSaurabh.Mishra@Sun.COM 
32110393SSaurabh.Mishra@Sun.COM void
atge_mac_config(atge_t * atgep)32210393SSaurabh.Mishra@Sun.COM atge_mac_config(atge_t *atgep)
32310393SSaurabh.Mishra@Sun.COM {
32410393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
32510393SSaurabh.Mishra@Sun.COM 	int speed;
32610393SSaurabh.Mishra@Sun.COM 	link_duplex_t ld;
32710393SSaurabh.Mishra@Sun.COM 
32810393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_MAC_CFG);
32910393SSaurabh.Mishra@Sun.COM 	reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC |
33010393SSaurabh.Mishra@Sun.COM 	    ATGE_CFG_SPEED_MASK);
33110393SSaurabh.Mishra@Sun.COM 
33210393SSaurabh.Mishra@Sun.COM 	speed = mii_get_speed(atgep->atge_mii);
33310393SSaurabh.Mishra@Sun.COM 	switch (speed) {
33410393SSaurabh.Mishra@Sun.COM 	case 10:
33510393SSaurabh.Mishra@Sun.COM 	case 100:
33610393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_10_100;
33710393SSaurabh.Mishra@Sun.COM 		break;
33810393SSaurabh.Mishra@Sun.COM 	case 1000:
33910393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_1000;
34010393SSaurabh.Mishra@Sun.COM 		break;
34110393SSaurabh.Mishra@Sun.COM 	}
34210393SSaurabh.Mishra@Sun.COM 
34310393SSaurabh.Mishra@Sun.COM 	ld = mii_get_duplex(atgep->atge_mii);
34410393SSaurabh.Mishra@Sun.COM 	if (ld == LINK_DUPLEX_FULL)
34510393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_FULL_DUPLEX;
34610393SSaurabh.Mishra@Sun.COM 
34710393SSaurabh.Mishra@Sun.COM 	/* Re-enable TX/RX MACs */
34811353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
34911353SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC;
35011353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
35111353SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
35211353SSaurabh.Mishra@Sun.COM 	}
35311353SSaurabh.Mishra@Sun.COM 
35410393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAC_CFG, reg);
35510393SSaurabh.Mishra@Sun.COM 
35610393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
35710393SSaurabh.Mishra@Sun.COM 		reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
35810393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) <<
35910393SSaurabh.Mishra@Sun.COM 		    IM_TIMER_TX_SHIFT;
36010393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_IM_TIMER, reg);
36110393SSaurabh.Mishra@Sun.COM 	}
36210393SSaurabh.Mishra@Sun.COM 
36310393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mac_cfg is : %x",
36410393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, INL(atgep, ATGE_MAC_CFG)));
36510393SSaurabh.Mishra@Sun.COM }
36610393SSaurabh.Mishra@Sun.COM 
36710393SSaurabh.Mishra@Sun.COM static void
atge_mii_notify(void * arg,link_state_t link)36810393SSaurabh.Mishra@Sun.COM atge_mii_notify(void *arg, link_state_t link)
36910393SSaurabh.Mishra@Sun.COM {
37010393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
37110393SSaurabh.Mishra@Sun.COM 
37210393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x",
37310393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, atgep->atge_link_state, link));
37410393SSaurabh.Mishra@Sun.COM 
37510393SSaurabh.Mishra@Sun.COM 	mac_link_update(atgep->atge_mh, link);
37610393SSaurabh.Mishra@Sun.COM 
37710393SSaurabh.Mishra@Sun.COM 	/*
37810393SSaurabh.Mishra@Sun.COM 	 * Reconfigure MAC if link status is UP now.
37910393SSaurabh.Mishra@Sun.COM 	 */
38010393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
38110393SSaurabh.Mishra@Sun.COM 	if (link == LINK_STATE_UP) {
38211353SSaurabh.Mishra@Sun.COM 		atgep->atge_link_state = LINK_STATE_UP;
38310393SSaurabh.Mishra@Sun.COM 		atge_mac_config(atgep);
38410393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 0;
38510393SSaurabh.Mishra@Sun.COM 	} else {
38610393SSaurabh.Mishra@Sun.COM 		atgep->atge_link_state = LINK_STATE_DOWN;
38711353SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_MII_CHECK;
38810393SSaurabh.Mishra@Sun.COM 	}
38910393SSaurabh.Mishra@Sun.COM 
39010393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
39110393SSaurabh.Mishra@Sun.COM 
39210393SSaurabh.Mishra@Sun.COM 	if (link == LINK_STATE_UP)
39310393SSaurabh.Mishra@Sun.COM 		mac_tx_update(atgep->atge_mh);
39410393SSaurabh.Mishra@Sun.COM }
39510393SSaurabh.Mishra@Sun.COM 
39611353SSaurabh.Mishra@Sun.COM void
atge_tx_reclaim(atge_t * atgep,int end)39711353SSaurabh.Mishra@Sun.COM atge_tx_reclaim(atge_t *atgep, int end)
39810393SSaurabh.Mishra@Sun.COM {
39911353SSaurabh.Mishra@Sun.COM 	atge_tx_desc_t  *txd;
40011353SSaurabh.Mishra@Sun.COM 	atge_ring_t *r = atgep->atge_tx_ring;
40111353SSaurabh.Mishra@Sun.COM 	uchar_t *c;
40211353SSaurabh.Mishra@Sun.COM 	int start;
40311353SSaurabh.Mishra@Sun.COM 
40411353SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
40511353SSaurabh.Mishra@Sun.COM 	ASSERT(r != NULL);
40611353SSaurabh.Mishra@Sun.COM 
40711353SSaurabh.Mishra@Sun.COM 	start = r->r_consumer;
40811353SSaurabh.Mishra@Sun.COM 
40911353SSaurabh.Mishra@Sun.COM 	if (start == end)
41011353SSaurabh.Mishra@Sun.COM 		return;
41111353SSaurabh.Mishra@Sun.COM 
41211353SSaurabh.Mishra@Sun.COM 	while (start != end) {
41311353SSaurabh.Mishra@Sun.COM 		r->r_avail_desc++;
41411353SSaurabh.Mishra@Sun.COM 		if (r->r_avail_desc > ATGE_TX_RING_CNT) {
41511353SSaurabh.Mishra@Sun.COM 
41611353SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
41711353SSaurabh.Mishra@Sun.COM 			    "Reclaim : TX descriptor error");
41811353SSaurabh.Mishra@Sun.COM 
41911353SSaurabh.Mishra@Sun.COM 			if (r->r_avail_desc > (ATGE_TX_RING_CNT + 5)) {
42011353SSaurabh.Mishra@Sun.COM 				atge_device_stop(atgep);
42111353SSaurabh.Mishra@Sun.COM 				break;
42211353SSaurabh.Mishra@Sun.COM 			}
42310393SSaurabh.Mishra@Sun.COM 		}
42410393SSaurabh.Mishra@Sun.COM 
42511353SSaurabh.Mishra@Sun.COM 		c = (uchar_t *)r->r_desc_ring->addr;
42611353SSaurabh.Mishra@Sun.COM 		c += (sizeof (atge_tx_desc_t) * start);
42711353SSaurabh.Mishra@Sun.COM 		txd = (atge_tx_desc_t *)c;
42811353SSaurabh.Mishra@Sun.COM 
42910393SSaurabh.Mishra@Sun.COM 		/*
43011353SSaurabh.Mishra@Sun.COM 		 * Clearing TX descriptor helps in debugging some strange
43111353SSaurabh.Mishra@Sun.COM 		 * problems.
43210393SSaurabh.Mishra@Sun.COM 		 */
43311353SSaurabh.Mishra@Sun.COM 		txd->addr = 0;
43411353SSaurabh.Mishra@Sun.COM 		txd->len = 0;
43511353SSaurabh.Mishra@Sun.COM 		txd->flags = 0;
43611353SSaurabh.Mishra@Sun.COM 
43711353SSaurabh.Mishra@Sun.COM 		ATGE_INC_SLOT(start, ATGE_TX_RING_CNT);
43810393SSaurabh.Mishra@Sun.COM 	}
43910393SSaurabh.Mishra@Sun.COM 
44011353SSaurabh.Mishra@Sun.COM 	atgep->atge_tx_ring->r_consumer = start;
44111353SSaurabh.Mishra@Sun.COM 
44211353SSaurabh.Mishra@Sun.COM 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
44310393SSaurabh.Mishra@Sun.COM }
44410393SSaurabh.Mishra@Sun.COM 
44510393SSaurabh.Mishra@Sun.COM /*
44610393SSaurabh.Mishra@Sun.COM  * Adds interrupt handler depending upon the type of interrupt supported by
44710393SSaurabh.Mishra@Sun.COM  * the chip.
44810393SSaurabh.Mishra@Sun.COM  */
44910393SSaurabh.Mishra@Sun.COM static int
atge_add_intr_handler(atge_t * atgep,int intr_type)45010393SSaurabh.Mishra@Sun.COM atge_add_intr_handler(atge_t *atgep, int intr_type)
45110393SSaurabh.Mishra@Sun.COM {
45210393SSaurabh.Mishra@Sun.COM 	int err;
45310393SSaurabh.Mishra@Sun.COM 	int count = 0;
45410393SSaurabh.Mishra@Sun.COM 	int avail = 0;
45510393SSaurabh.Mishra@Sun.COM 	int i;
45610393SSaurabh.Mishra@Sun.COM 	int flag;
45710393SSaurabh.Mishra@Sun.COM 
45810393SSaurabh.Mishra@Sun.COM 	if (intr_type != DDI_INTR_TYPE_FIXED) {
45910393SSaurabh.Mishra@Sun.COM 		err = ddi_intr_get_nintrs(atgep->atge_dip, intr_type, &count);
46010393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
46110393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
46210393SSaurabh.Mishra@Sun.COM 			    "ddi_intr_get_nintrs failed : %d", err);
46311353SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
46410393SSaurabh.Mishra@Sun.COM 		}
46510393SSaurabh.Mishra@Sun.COM 
46610393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() count : %d",
46710393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__, count));
46810393SSaurabh.Mishra@Sun.COM 
46910393SSaurabh.Mishra@Sun.COM 		err = ddi_intr_get_navail(atgep->atge_dip, intr_type, &avail);
47010393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
47110393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
47210393SSaurabh.Mishra@Sun.COM 			    "ddi_intr_get_navail failed : %d", err);
47311353SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
47410393SSaurabh.Mishra@Sun.COM 		}
47510393SSaurabh.Mishra@Sun.COM 
47610393SSaurabh.Mishra@Sun.COM 		if (avail < count) {
47710393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip, "count :%d,"
47810393SSaurabh.Mishra@Sun.COM 			    " avail : %d", count, avail);
47910393SSaurabh.Mishra@Sun.COM 		}
48010393SSaurabh.Mishra@Sun.COM 
48110393SSaurabh.Mishra@Sun.COM 		flag = DDI_INTR_ALLOC_STRICT;
48210393SSaurabh.Mishra@Sun.COM 	} else {
48310393SSaurabh.Mishra@Sun.COM 		/*
48410393SSaurabh.Mishra@Sun.COM 		 * DDI_INTR_TYPE_FIXED case.
48510393SSaurabh.Mishra@Sun.COM 		 */
48610393SSaurabh.Mishra@Sun.COM 		count = 1;
48710393SSaurabh.Mishra@Sun.COM 		avail = 1;
48810393SSaurabh.Mishra@Sun.COM 		flag = DDI_INTR_ALLOC_NORMAL;
48910393SSaurabh.Mishra@Sun.COM 	}
49010393SSaurabh.Mishra@Sun.COM 
49110393SSaurabh.Mishra@Sun.COM 	atgep->atge_intr_size = avail * sizeof (ddi_intr_handle_t);
49210393SSaurabh.Mishra@Sun.COM 	atgep->atge_intr_handle = kmem_zalloc(atgep->atge_intr_size, KM_SLEEP);
49310393SSaurabh.Mishra@Sun.COM 
49410393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d",
49510393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, avail, count,
49610393SSaurabh.Mishra@Sun.COM 	    intr_type));
49710393SSaurabh.Mishra@Sun.COM 
49810393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_alloc(atgep->atge_dip, atgep->atge_intr_handle,
49910393SSaurabh.Mishra@Sun.COM 	    intr_type, 0, avail, &atgep->atge_intr_cnt, flag);
50010393SSaurabh.Mishra@Sun.COM 
50110393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
50210393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "ddi_intr_alloc failed : %d", err);
50310393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
50411353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
50510393SSaurabh.Mishra@Sun.COM 	}
50610393SSaurabh.Mishra@Sun.COM 
50710393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: atge_add_intr_handler() after alloc count"
50810393SSaurabh.Mishra@Sun.COM 	    " :%d, avail : %d", atgep->atge_name, count, avail));
50910393SSaurabh.Mishra@Sun.COM 
51010393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_get_pri(atgep->atge_intr_handle[0],
51110393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_intr_pri);
51210393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
51310393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "ddi_intr_get_pri failed:%d", err);
51410393SSaurabh.Mishra@Sun.COM 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
51510393SSaurabh.Mishra@Sun.COM 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
51610393SSaurabh.Mishra@Sun.COM 		}
51710393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
51810393SSaurabh.Mishra@Sun.COM 
51911353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
52010393SSaurabh.Mishra@Sun.COM 	}
52110393SSaurabh.Mishra@Sun.COM 
52210393SSaurabh.Mishra@Sun.COM 	/*
52310393SSaurabh.Mishra@Sun.COM 	 * Add interrupt handler now.
52410393SSaurabh.Mishra@Sun.COM 	 */
52510393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
52611353SSaurabh.Mishra@Sun.COM 		if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
52711353SSaurabh.Mishra@Sun.COM 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
52811353SSaurabh.Mishra@Sun.COM 			    atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i);
52911353SSaurabh.Mishra@Sun.COM 		} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
53011353SSaurabh.Mishra@Sun.COM 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
53111353SSaurabh.Mishra@Sun.COM 			    atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i);
53211353SSaurabh.Mishra@Sun.COM 		}
53310393SSaurabh.Mishra@Sun.COM 
53410393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
53510393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
53610393SSaurabh.Mishra@Sun.COM 			    "ddi_intr_add_handler failed : %d", err);
53710393SSaurabh.Mishra@Sun.COM 
53810393SSaurabh.Mishra@Sun.COM 			(void) ddi_intr_free(atgep->atge_intr_handle[i]);
53910393SSaurabh.Mishra@Sun.COM 			while (--i >= 0) {
54010393SSaurabh.Mishra@Sun.COM 				(void) ddi_intr_remove_handler(
54110393SSaurabh.Mishra@Sun.COM 				    atgep->atge_intr_handle[i]);
54210393SSaurabh.Mishra@Sun.COM 				(void) ddi_intr_free(
54310393SSaurabh.Mishra@Sun.COM 				    atgep->atge_intr_handle[i]);
54410393SSaurabh.Mishra@Sun.COM 			}
54510393SSaurabh.Mishra@Sun.COM 
54610393SSaurabh.Mishra@Sun.COM 			kmem_free(atgep->atge_intr_handle,
54710393SSaurabh.Mishra@Sun.COM 			    atgep->atge_intr_size);
54810393SSaurabh.Mishra@Sun.COM 
54911353SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
55010393SSaurabh.Mishra@Sun.COM 		}
55110393SSaurabh.Mishra@Sun.COM 	}
55210393SSaurabh.Mishra@Sun.COM 
55310393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_get_cap(atgep->atge_intr_handle[0],
55410393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_intr_cap);
55510393SSaurabh.Mishra@Sun.COM 
55610393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
55710393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip,
55810393SSaurabh.Mishra@Sun.COM 		    "ddi_intr_get_cap failed : %d", err);
55910393SSaurabh.Mishra@Sun.COM 		atge_remove_intr(atgep);
56011353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
56110393SSaurabh.Mishra@Sun.COM 	}
56210393SSaurabh.Mishra@Sun.COM 
56310393SSaurabh.Mishra@Sun.COM 	if (intr_type == DDI_INTR_TYPE_FIXED)
56410393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_FIXED_TYPE;
56510393SSaurabh.Mishra@Sun.COM 	else if (intr_type == DDI_INTR_TYPE_MSI)
56610393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_MSI_TYPE;
56710393SSaurabh.Mishra@Sun.COM 	else if (intr_type == DDI_INTR_TYPE_MSIX)
56810393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_MSIX_TYPE;
56910393SSaurabh.Mishra@Sun.COM 
57011353SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
57110393SSaurabh.Mishra@Sun.COM }
57210393SSaurabh.Mishra@Sun.COM 
57310393SSaurabh.Mishra@Sun.COM void
atge_remove_intr(atge_t * atgep)57410393SSaurabh.Mishra@Sun.COM atge_remove_intr(atge_t *atgep)
57510393SSaurabh.Mishra@Sun.COM {
57610393SSaurabh.Mishra@Sun.COM 	int i;
57710393SSaurabh.Mishra@Sun.COM 	int cap = 0;
57810393SSaurabh.Mishra@Sun.COM 
57910393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_handle == NULL)
58010393SSaurabh.Mishra@Sun.COM 		return;
58110393SSaurabh.Mishra@Sun.COM 
58210393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
58310393SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_block_disable(atgep->atge_intr_handle,
58410393SSaurabh.Mishra@Sun.COM 		    atgep->atge_intr_cnt);
58510393SSaurabh.Mishra@Sun.COM 
58610393SSaurabh.Mishra@Sun.COM 		cap = 1;
58710393SSaurabh.Mishra@Sun.COM 	}
58810393SSaurabh.Mishra@Sun.COM 
58910393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
59010393SSaurabh.Mishra@Sun.COM 		if (cap == 0)
59110393SSaurabh.Mishra@Sun.COM 			(void) ddi_intr_disable(atgep->atge_intr_handle[i]);
59210393SSaurabh.Mishra@Sun.COM 
59310393SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_remove_handler(atgep->atge_intr_handle[i]);
59410393SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_free(atgep->atge_intr_handle[i]);
59510393SSaurabh.Mishra@Sun.COM 	}
59610393SSaurabh.Mishra@Sun.COM 
59710393SSaurabh.Mishra@Sun.COM 	kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
59810393SSaurabh.Mishra@Sun.COM }
59910393SSaurabh.Mishra@Sun.COM 
60010393SSaurabh.Mishra@Sun.COM int
atge_enable_intrs(atge_t * atgep)60110393SSaurabh.Mishra@Sun.COM atge_enable_intrs(atge_t *atgep)
60210393SSaurabh.Mishra@Sun.COM {
60310393SSaurabh.Mishra@Sun.COM 	int err;
60410393SSaurabh.Mishra@Sun.COM 	int i;
60510393SSaurabh.Mishra@Sun.COM 
60610393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
60710393SSaurabh.Mishra@Sun.COM 		/*
60810393SSaurabh.Mishra@Sun.COM 		 * Do block enable.
60910393SSaurabh.Mishra@Sun.COM 		 */
61010393SSaurabh.Mishra@Sun.COM 		err = ddi_intr_block_enable(atgep->atge_intr_handle,
61110393SSaurabh.Mishra@Sun.COM 		    atgep->atge_intr_cnt);
61210393SSaurabh.Mishra@Sun.COM 
61310393SSaurabh.Mishra@Sun.COM 		if (err != DDI_SUCCESS) {
61410393SSaurabh.Mishra@Sun.COM 			atge_error(atgep->atge_dip,
61510393SSaurabh.Mishra@Sun.COM 			    "Failed to block enable intrs %d", err);
61611353SSaurabh.Mishra@Sun.COM 			err = DDI_FAILURE;
61710393SSaurabh.Mishra@Sun.COM 		} else {
61811353SSaurabh.Mishra@Sun.COM 			err = DDI_SUCCESS;
61910393SSaurabh.Mishra@Sun.COM 		}
62010393SSaurabh.Mishra@Sun.COM 	} else {
62110393SSaurabh.Mishra@Sun.COM 		/*
62210393SSaurabh.Mishra@Sun.COM 		 * Call ddi_intr_enable() for MSI non-block enable.
62310393SSaurabh.Mishra@Sun.COM 		 */
62410393SSaurabh.Mishra@Sun.COM 		for (i = 0; i < atgep->atge_intr_cnt; i++) {
62510393SSaurabh.Mishra@Sun.COM 			err = ddi_intr_enable(atgep->atge_intr_handle[i]);
62610393SSaurabh.Mishra@Sun.COM 			if (err != DDI_SUCCESS) {
62710393SSaurabh.Mishra@Sun.COM 				atge_error(atgep->atge_dip,
62810393SSaurabh.Mishra@Sun.COM 				    "Failed to enable intrs on %d with : %d",
62910393SSaurabh.Mishra@Sun.COM 				    i, err);
63010393SSaurabh.Mishra@Sun.COM 				break;
63110393SSaurabh.Mishra@Sun.COM 			}
63210393SSaurabh.Mishra@Sun.COM 		}
63310393SSaurabh.Mishra@Sun.COM 
63410393SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS)
63511353SSaurabh.Mishra@Sun.COM 			err = DDI_SUCCESS;
63610393SSaurabh.Mishra@Sun.COM 		else
63711353SSaurabh.Mishra@Sun.COM 			err = DDI_FAILURE;
63810393SSaurabh.Mishra@Sun.COM 	}
63910393SSaurabh.Mishra@Sun.COM 
64010393SSaurabh.Mishra@Sun.COM 	return (err);
64110393SSaurabh.Mishra@Sun.COM }
64210393SSaurabh.Mishra@Sun.COM 
64310393SSaurabh.Mishra@Sun.COM /*
64410393SSaurabh.Mishra@Sun.COM  * Adds interrupt handler depending on the supported interrupt type by the
64510393SSaurabh.Mishra@Sun.COM  * chip.
64610393SSaurabh.Mishra@Sun.COM  */
64710393SSaurabh.Mishra@Sun.COM static int
atge_add_intr(atge_t * atgep)64810393SSaurabh.Mishra@Sun.COM atge_add_intr(atge_t *atgep)
64910393SSaurabh.Mishra@Sun.COM {
65010393SSaurabh.Mishra@Sun.COM 	int	err;
65110393SSaurabh.Mishra@Sun.COM 
65210393SSaurabh.Mishra@Sun.COM 	/*
65310393SSaurabh.Mishra@Sun.COM 	 * Get the supported interrupt types.
65410393SSaurabh.Mishra@Sun.COM 	 */
65510393SSaurabh.Mishra@Sun.COM 	err = ddi_intr_get_supported_types(atgep->atge_dip,
65610393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_intr_types);
65710393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
65810393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip,
65910393SSaurabh.Mishra@Sun.COM 		    "ddi_intr_get_supported_types failed : %d", err);
66011353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
66110393SSaurabh.Mishra@Sun.COM 	}
66210393SSaurabh.Mishra@Sun.COM 
66310393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d",
66410393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, atgep->atge_intr_types));
66510393SSaurabh.Mishra@Sun.COM 
66610393SSaurabh.Mishra@Sun.COM 
66710393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSIX) {
66810393SSaurabh.Mishra@Sun.COM 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSIX);
66911353SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS) {
67010393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: Using MSIx for interrupt",
67110393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name));
67210393SSaurabh.Mishra@Sun.COM 			return (err);
67310393SSaurabh.Mishra@Sun.COM 		}
67410393SSaurabh.Mishra@Sun.COM 	}
67510393SSaurabh.Mishra@Sun.COM 
67610393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_types & DDI_INTR_TYPE_MSI) {
67710393SSaurabh.Mishra@Sun.COM 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSI);
67811353SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS) {
67910393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: Using MSI for interrupt",
68010393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name));
68110393SSaurabh.Mishra@Sun.COM 			return (err);
68210393SSaurabh.Mishra@Sun.COM 		}
68310393SSaurabh.Mishra@Sun.COM 	}
68410393SSaurabh.Mishra@Sun.COM 
68511353SSaurabh.Mishra@Sun.COM 	err = DDI_FAILURE;
68610393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_intr_types & DDI_INTR_TYPE_FIXED) {
68710393SSaurabh.Mishra@Sun.COM 		err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_FIXED);
68811353SSaurabh.Mishra@Sun.COM 		if (err == DDI_SUCCESS) {
68910393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: Using FIXED type for interrupt",
69010393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name));
69110393SSaurabh.Mishra@Sun.COM 			return (err);
69210393SSaurabh.Mishra@Sun.COM 		}
69310393SSaurabh.Mishra@Sun.COM 	}
69410393SSaurabh.Mishra@Sun.COM 
69510393SSaurabh.Mishra@Sun.COM 	return (err);
69610393SSaurabh.Mishra@Sun.COM }
69710393SSaurabh.Mishra@Sun.COM 
69810393SSaurabh.Mishra@Sun.COM int
atge_identify_hardware(atge_t * atgep)69910393SSaurabh.Mishra@Sun.COM atge_identify_hardware(atge_t *atgep)
70010393SSaurabh.Mishra@Sun.COM {
70110393SSaurabh.Mishra@Sun.COM 	uint16_t vid, did;
70210393SSaurabh.Mishra@Sun.COM 	int i;
70310393SSaurabh.Mishra@Sun.COM 
70410393SSaurabh.Mishra@Sun.COM 	vid = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_VENID);
70510393SSaurabh.Mishra@Sun.COM 	did = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_DEVID);
70610393SSaurabh.Mishra@Sun.COM 
70710393SSaurabh.Mishra@Sun.COM 	atgep->atge_model = 0;
70810393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) {
70910393SSaurabh.Mishra@Sun.COM 		if (atge_cards[i].vendor_id == vid &&
71010393SSaurabh.Mishra@Sun.COM 		    atge_cards[i].device_id == did) {
71110393SSaurabh.Mishra@Sun.COM 			atgep->atge_model = atge_cards[i].model;
71210393SSaurabh.Mishra@Sun.COM 			atgep->atge_revid =
71310393SSaurabh.Mishra@Sun.COM 			    pci_config_get8(atgep->atge_conf_handle,
71410393SSaurabh.Mishra@Sun.COM 			    PCI_CONF_REVID);
71510393SSaurabh.Mishra@Sun.COM 			ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
71610393SSaurabh.Mishra@Sun.COM 			    atgep->atge_name, __func__, vid, did,
71710393SSaurabh.Mishra@Sun.COM 			    atgep->atge_model));
71810393SSaurabh.Mishra@Sun.COM 
71911353SSaurabh.Mishra@Sun.COM 			return (DDI_SUCCESS);
72010393SSaurabh.Mishra@Sun.COM 		}
72110393SSaurabh.Mishra@Sun.COM 	}
72210393SSaurabh.Mishra@Sun.COM 
72310393SSaurabh.Mishra@Sun.COM 	atge_error(atgep->atge_dip, "atge driver is attaching to unknown"
72410393SSaurabh.Mishra@Sun.COM 	    " pci%d,%d vendor/device-id card", vid, did);
72510393SSaurabh.Mishra@Sun.COM 
72610393SSaurabh.Mishra@Sun.COM 	/*
72711353SSaurabh.Mishra@Sun.COM 	 * Assume it's L1 chip.
72810393SSaurabh.Mishra@Sun.COM 	 */
72911353SSaurabh.Mishra@Sun.COM 	atgep->atge_model = ATGE_CHIP_L1;
73010393SSaurabh.Mishra@Sun.COM 	atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle,
73110393SSaurabh.Mishra@Sun.COM 	    PCI_CONF_REVID);
73210393SSaurabh.Mishra@Sun.COM 
73310393SSaurabh.Mishra@Sun.COM 	/*
73410393SSaurabh.Mishra@Sun.COM 	 * We will leave the decision to caller.
73510393SSaurabh.Mishra@Sun.COM 	 */
73611353SSaurabh.Mishra@Sun.COM 	return (DDI_FAILURE);
73710393SSaurabh.Mishra@Sun.COM }
73810393SSaurabh.Mishra@Sun.COM 
73910393SSaurabh.Mishra@Sun.COM int
atge_get_macaddr(atge_t * atgep)74010393SSaurabh.Mishra@Sun.COM atge_get_macaddr(atge_t *atgep)
74110393SSaurabh.Mishra@Sun.COM {
74210393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
74310393SSaurabh.Mishra@Sun.COM 
74410393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_SPI_CTRL);
74510393SSaurabh.Mishra@Sun.COM 	if ((reg & SPI_VPD_ENB) != 0) {
74610393SSaurabh.Mishra@Sun.COM 		/*
74710393SSaurabh.Mishra@Sun.COM 		 * Get VPD stored in TWSI EEPROM.
74810393SSaurabh.Mishra@Sun.COM 		 */
74910393SSaurabh.Mishra@Sun.COM 		reg &= ~SPI_VPD_ENB;
75010393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_SPI_CTRL, reg);
75110393SSaurabh.Mishra@Sun.COM 
75210393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s called Get VPD", atgep->atge_name, __func__));
75310393SSaurabh.Mishra@Sun.COM 	}
75410393SSaurabh.Mishra@Sun.COM 
75510393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[5] = INB(atgep, ATGE_PAR0 + 0);
75610393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[4] = INB(atgep, ATGE_PAR0 + 1);
75710393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[3] = INB(atgep, ATGE_PAR0 + 2);
75810393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[2] = INB(atgep, ATGE_PAR0 + 3);
75910393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[1] = INB(atgep, ATGE_PAR1 + 0);
76010393SSaurabh.Mishra@Sun.COM 	atgep->atge_ether_addr[0] = INB(atgep, ATGE_PAR1 + 1);
76110393SSaurabh.Mishra@Sun.COM 
76210393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x",
76310393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__,
76410393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[0],
76510393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[1],
76610393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[2],
76710393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[3],
76810393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[4],
76910393SSaurabh.Mishra@Sun.COM 	    atgep->atge_ether_addr[5]));
77010393SSaurabh.Mishra@Sun.COM 
77110393SSaurabh.Mishra@Sun.COM 	bcopy(atgep->atge_ether_addr, atgep->atge_dev_addr, ETHERADDRL);
77210393SSaurabh.Mishra@Sun.COM 
77311353SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
77410393SSaurabh.Mishra@Sun.COM }
77510393SSaurabh.Mishra@Sun.COM 
77610393SSaurabh.Mishra@Sun.COM /*
77710393SSaurabh.Mishra@Sun.COM  * Reset functionality for L1 and L1E. It's same.
77810393SSaurabh.Mishra@Sun.COM  */
77910393SSaurabh.Mishra@Sun.COM static void
atge_device_reset(atge_t * atgep)78010393SSaurabh.Mishra@Sun.COM atge_device_reset(atge_t *atgep)
78110393SSaurabh.Mishra@Sun.COM {
78210393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E ||
78310393SSaurabh.Mishra@Sun.COM 	    ATGE_MODEL(atgep) == ATGE_CHIP_L1)
78410393SSaurabh.Mishra@Sun.COM 		atge_device_reset_l1_l1e(atgep);
78510393SSaurabh.Mishra@Sun.COM }
78610393SSaurabh.Mishra@Sun.COM 
78710393SSaurabh.Mishra@Sun.COM void
atge_device_reset_l1_l1e(atge_t * atgep)78810393SSaurabh.Mishra@Sun.COM atge_device_reset_l1_l1e(atge_t *atgep)
78910393SSaurabh.Mishra@Sun.COM {
79010393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
79110393SSaurabh.Mishra@Sun.COM 	int t;
79210393SSaurabh.Mishra@Sun.COM 
79310393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
79410393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_MASTER_CFG);
79510393SSaurabh.Mishra@Sun.COM 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
79610393SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
79710393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, ATGE_MASTER_CFG);
79810393SSaurabh.Mishra@Sun.COM 		if ((reg & MASTER_RESET) == 0)
79910393SSaurabh.Mishra@Sun.COM 			break;
80010393SSaurabh.Mishra@Sun.COM 	}
80110393SSaurabh.Mishra@Sun.COM 
80210393SSaurabh.Mishra@Sun.COM 	if (t == 0) {
80310393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, " master reset timeout reg : %x",
80410393SSaurabh.Mishra@Sun.COM 		    reg);
80510393SSaurabh.Mishra@Sun.COM 	}
80610393SSaurabh.Mishra@Sun.COM 
80710393SSaurabh.Mishra@Sun.COM 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
80810393SSaurabh.Mishra@Sun.COM 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
80910393SSaurabh.Mishra@Sun.COM 			break;
81010393SSaurabh.Mishra@Sun.COM 
81110393SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
81210393SSaurabh.Mishra@Sun.COM 	}
81310393SSaurabh.Mishra@Sun.COM 
81410393SSaurabh.Mishra@Sun.COM 	if (t == 0) {
81510393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "device reset timeout reg : %x",
81610393SSaurabh.Mishra@Sun.COM 		    reg);
81710393SSaurabh.Mishra@Sun.COM 	}
81810393SSaurabh.Mishra@Sun.COM 
81910393SSaurabh.Mishra@Sun.COM 	/*
82010393SSaurabh.Mishra@Sun.COM 	 * Initialize PCIe module. These values came from FreeBSD and
82110393SSaurabh.Mishra@Sun.COM 	 * we don't know the meaning of it.
82210393SSaurabh.Mishra@Sun.COM 	 */
82310393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, 0x12FC, 0x6500);
82410393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, 0x1008) | 0x8000;
82510393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, 0x1008, reg);
82610393SSaurabh.Mishra@Sun.COM 
82710393SSaurabh.Mishra@Sun.COM 	/*
82810393SSaurabh.Mishra@Sun.COM 	 * Get chip revision.
82910393SSaurabh.Mishra@Sun.COM 	 */
83010393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_rev = INL(atgep, ATGE_MASTER_CFG) >>
83110393SSaurabh.Mishra@Sun.COM 	    MASTER_CHIP_REV_SHIFT;
83210393SSaurabh.Mishra@Sun.COM 
83310393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s reset successfully rev : %x", atgep->atge_name,
83410393SSaurabh.Mishra@Sun.COM 	    __func__, atgep->atge_chip_rev));
83510393SSaurabh.Mishra@Sun.COM }
83610393SSaurabh.Mishra@Sun.COM 
83710393SSaurabh.Mishra@Sun.COM /*
83810393SSaurabh.Mishra@Sun.COM  * DMA allocation for L1 and L1E is bit different since L1E uses RX pages
83910393SSaurabh.Mishra@Sun.COM  * instead of descriptor based RX model.
84010393SSaurabh.Mishra@Sun.COM  */
84110393SSaurabh.Mishra@Sun.COM static int
atge_alloc_dma(atge_t * atgep)84210393SSaurabh.Mishra@Sun.COM atge_alloc_dma(atge_t *atgep)
84310393SSaurabh.Mishra@Sun.COM {
84411353SSaurabh.Mishra@Sun.COM 	int err = DDI_FAILURE;
84510393SSaurabh.Mishra@Sun.COM 
84610393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
84710393SSaurabh.Mishra@Sun.COM 		err = atge_l1e_alloc_dma(atgep);
84811353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
84911353SSaurabh.Mishra@Sun.COM 		err = atge_l1_alloc_dma(atgep);
85010393SSaurabh.Mishra@Sun.COM 	}
85110393SSaurabh.Mishra@Sun.COM 
85210393SSaurabh.Mishra@Sun.COM 	return (err);
85310393SSaurabh.Mishra@Sun.COM }
85410393SSaurabh.Mishra@Sun.COM 
85510393SSaurabh.Mishra@Sun.COM static void
atge_free_dma(atge_t * atgep)85610393SSaurabh.Mishra@Sun.COM atge_free_dma(atge_t *atgep)
85710393SSaurabh.Mishra@Sun.COM {
85810393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
85910393SSaurabh.Mishra@Sun.COM 		atge_l1e_free_dma(atgep);
86010393SSaurabh.Mishra@Sun.COM 	}
86110393SSaurabh.Mishra@Sun.COM }
86210393SSaurabh.Mishra@Sun.COM 
86310393SSaurabh.Mishra@Sun.COM /*
86410393SSaurabh.Mishra@Sun.COM  * Attach entry point in the driver.
86510393SSaurabh.Mishra@Sun.COM  */
86610393SSaurabh.Mishra@Sun.COM static int
atge_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)86710393SSaurabh.Mishra@Sun.COM atge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
86810393SSaurabh.Mishra@Sun.COM {
86910393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
87010393SSaurabh.Mishra@Sun.COM 	mac_register_t	*macreg;
87110393SSaurabh.Mishra@Sun.COM 	int	instance;
87210393SSaurabh.Mishra@Sun.COM 	uint16_t cap_ptr;
87310393SSaurabh.Mishra@Sun.COM 	uint16_t burst;
87410393SSaurabh.Mishra@Sun.COM 	int err;
87510393SSaurabh.Mishra@Sun.COM 	mii_ops_t *mii_ops;
87610393SSaurabh.Mishra@Sun.COM 
87710393SSaurabh.Mishra@Sun.COM 	instance =  ddi_get_instance(devinfo);
87810393SSaurabh.Mishra@Sun.COM 
87910393SSaurabh.Mishra@Sun.COM 	switch (cmd) {
88010393SSaurabh.Mishra@Sun.COM 	default:
88110393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
88210393SSaurabh.Mishra@Sun.COM 
88310393SSaurabh.Mishra@Sun.COM 	case DDI_RESUME:
88410393SSaurabh.Mishra@Sun.COM 		return (atge_resume(devinfo));
88510393SSaurabh.Mishra@Sun.COM 
88610393SSaurabh.Mishra@Sun.COM 	case DDI_ATTACH:
88710393SSaurabh.Mishra@Sun.COM 		ddi_set_driver_private(devinfo, NULL);
88810393SSaurabh.Mishra@Sun.COM 		break;
88910393SSaurabh.Mishra@Sun.COM 	}
89010393SSaurabh.Mishra@Sun.COM 
89110393SSaurabh.Mishra@Sun.COM 	atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP);
89210393SSaurabh.Mishra@Sun.COM 	ddi_set_driver_private(devinfo, atgep);
89310393SSaurabh.Mishra@Sun.COM 	atgep->atge_dip = devinfo;
89410393SSaurabh.Mishra@Sun.COM 
89510393SSaurabh.Mishra@Sun.COM 	/*
89610393SSaurabh.Mishra@Sun.COM 	 * Setup name and instance number to be used for debugging and
89710393SSaurabh.Mishra@Sun.COM 	 * error reporting.
89810393SSaurabh.Mishra@Sun.COM 	 */
89910393SSaurabh.Mishra@Sun.COM 	(void) snprintf(atgep->atge_name, sizeof (atgep->atge_name), "%s%d",
90010393SSaurabh.Mishra@Sun.COM 	    "atge", instance);
90110393SSaurabh.Mishra@Sun.COM 
90210393SSaurabh.Mishra@Sun.COM 
90310393SSaurabh.Mishra@Sun.COM 	/*
90410393SSaurabh.Mishra@Sun.COM 	 * Map PCI config space.
90510393SSaurabh.Mishra@Sun.COM 	 */
90610393SSaurabh.Mishra@Sun.COM 	err = pci_config_setup(devinfo, &atgep->atge_conf_handle);
90710393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
90810393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "pci_config_setup() failed");
90910393SSaurabh.Mishra@Sun.COM 		goto fail1;
91010393SSaurabh.Mishra@Sun.COM 	}
91110393SSaurabh.Mishra@Sun.COM 
91210393SSaurabh.Mishra@Sun.COM 	(void) atge_identify_hardware(atgep);
91310393SSaurabh.Mishra@Sun.COM 
91410393SSaurabh.Mishra@Sun.COM 	/*
91510393SSaurabh.Mishra@Sun.COM 	 * Map Device registers.
91610393SSaurabh.Mishra@Sun.COM 	 */
91710393SSaurabh.Mishra@Sun.COM 	err = ddi_regs_map_setup(devinfo, ATGE_PCI_REG_NUMBER,
91810393SSaurabh.Mishra@Sun.COM 	    &atgep->atge_io_regs, 0, 0, &atge_dev_attr, &atgep->atge_io_handle);
91910393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
92010393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "ddi_regs_map_setup() failed");
92110393SSaurabh.Mishra@Sun.COM 		goto fail2;
92210393SSaurabh.Mishra@Sun.COM 	}
92310393SSaurabh.Mishra@Sun.COM 
92410393SSaurabh.Mishra@Sun.COM 	/*
92510393SSaurabh.Mishra@Sun.COM 	 * Add interrupt and its associated handler.
92610393SSaurabh.Mishra@Sun.COM 	 */
92710393SSaurabh.Mishra@Sun.COM 	err = atge_add_intr(atgep);
92811353SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
92910393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "Failed to add interrupt handler");
93010393SSaurabh.Mishra@Sun.COM 		goto fail3;
93110393SSaurabh.Mishra@Sun.COM 	}
93210393SSaurabh.Mishra@Sun.COM 
93310393SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_intr_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_tx_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_rx_lock, NULL, MUTEX_DRIVER,
94010393SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(atgep->atge_intr_pri));
94110393SSaurabh.Mishra@Sun.COM 
94210393SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_mii_lock, NULL, MUTEX_DRIVER, NULL);
94310393SSaurabh.Mishra@Sun.COM 
94411353SSaurabh.Mishra@Sun.COM 	/*
94511353SSaurabh.Mishra@Sun.COM 	 * Used to lock down MBOX register on L1 chip since RX consumer,
94611353SSaurabh.Mishra@Sun.COM 	 * TX producer and RX return ring consumer are shared.
94711353SSaurabh.Mishra@Sun.COM 	 */
94811353SSaurabh.Mishra@Sun.COM 	mutex_init(&atgep->atge_mbox_lock, NULL, MUTEX_DRIVER,
94911353SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(atgep->atge_intr_pri));
95011353SSaurabh.Mishra@Sun.COM 
95110393SSaurabh.Mishra@Sun.COM 	atgep->atge_link_state = LINK_STATE_DOWN;
95210393SSaurabh.Mishra@Sun.COM 	atgep->atge_mtu = ETHERMTU;
95310393SSaurabh.Mishra@Sun.COM 
95411353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
95511353SSaurabh.Mishra@Sun.COM 		if (atgep->atge_revid > 0xF0) {
95611353SSaurabh.Mishra@Sun.COM 			/* L2E Rev. B. AR8114 */
95711353SSaurabh.Mishra@Sun.COM 			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
95810393SSaurabh.Mishra@Sun.COM 		} else {
95911353SSaurabh.Mishra@Sun.COM 			if ((INL(atgep, L1E_PHY_STATUS) &
96011353SSaurabh.Mishra@Sun.COM 			    PHY_STATUS_100M) != 0) {
96111353SSaurabh.Mishra@Sun.COM 				/* L1E AR8121 */
96211353SSaurabh.Mishra@Sun.COM 				atgep->atge_flags |= ATGE_FLAG_JUMBO;
96311353SSaurabh.Mishra@Sun.COM 			} else {
96411353SSaurabh.Mishra@Sun.COM 				/* L2E Rev. A. AR8113 */
96511353SSaurabh.Mishra@Sun.COM 				atgep->atge_flags |= ATGE_FLAG_FASTETHER;
96611353SSaurabh.Mishra@Sun.COM 			}
96710393SSaurabh.Mishra@Sun.COM 		}
96810393SSaurabh.Mishra@Sun.COM 	}
96910393SSaurabh.Mishra@Sun.COM 
97010393SSaurabh.Mishra@Sun.COM 	/*
97110393SSaurabh.Mishra@Sun.COM 	 * Get DMA parameters from PCIe device control register.
97210393SSaurabh.Mishra@Sun.COM 	 */
97310393SSaurabh.Mishra@Sun.COM 	err = PCI_CAP_LOCATE(atgep->atge_conf_handle, PCI_CAP_ID_PCI_E,
97410393SSaurabh.Mishra@Sun.COM 	    &cap_ptr);
97510393SSaurabh.Mishra@Sun.COM 
97610393SSaurabh.Mishra@Sun.COM 	if (err == DDI_FAILURE) {
97710393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_rd_burst = DMA_CFG_RD_BURST_128;
97810393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_wr_burst = DMA_CFG_WR_BURST_128;
97910393SSaurabh.Mishra@Sun.COM 	} else {
98010393SSaurabh.Mishra@Sun.COM 		atgep->atge_flags |= ATGE_FLAG_PCIE;
98110393SSaurabh.Mishra@Sun.COM 		burst = pci_config_get16(atgep->atge_conf_handle,
98210393SSaurabh.Mishra@Sun.COM 		    cap_ptr + 0x08);
98310393SSaurabh.Mishra@Sun.COM 
98410393SSaurabh.Mishra@Sun.COM 		/*
98510393SSaurabh.Mishra@Sun.COM 		 * Max read request size.
98610393SSaurabh.Mishra@Sun.COM 		 */
98710393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_rd_burst = ((burst >> 12) & 0x07) <<
98810393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_RD_BURST_SHIFT;
98910393SSaurabh.Mishra@Sun.COM 
99010393SSaurabh.Mishra@Sun.COM 		/*
99110393SSaurabh.Mishra@Sun.COM 		 * Max Payload Size.
99210393SSaurabh.Mishra@Sun.COM 		 */
99310393SSaurabh.Mishra@Sun.COM 		atgep->atge_dma_wr_burst = ((burst >> 5) & 0x07) <<
99410393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_WR_BURST_SHIFT;
99510393SSaurabh.Mishra@Sun.COM 
99610393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() MRR : %d, MPS : %d",
99710393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__,
99810393SSaurabh.Mishra@Sun.COM 		    (128 << ((burst >> 12) & 0x07)),
99910393SSaurabh.Mishra@Sun.COM 		    (128 << ((burst >> 5) & 0x07))));
100010393SSaurabh.Mishra@Sun.COM 	}
100110393SSaurabh.Mishra@Sun.COM 
100210393SSaurabh.Mishra@Sun.COM 	/*
100310393SSaurabh.Mishra@Sun.COM 	 * Allocate DMA resources.
100410393SSaurabh.Mishra@Sun.COM 	 */
100510393SSaurabh.Mishra@Sun.COM 	err = atge_alloc_dma(atgep);
100611353SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
100710393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "Failed to allocate DMA resources");
100810393SSaurabh.Mishra@Sun.COM 		goto fail4;
100910393SSaurabh.Mishra@Sun.COM 	}
101010393SSaurabh.Mishra@Sun.COM 
101110393SSaurabh.Mishra@Sun.COM 	/*
101210393SSaurabh.Mishra@Sun.COM 	 * Get station address.
101310393SSaurabh.Mishra@Sun.COM 	 */
101410393SSaurabh.Mishra@Sun.COM 	(void) atge_get_macaddr(atgep);
101510393SSaurabh.Mishra@Sun.COM 
101610393SSaurabh.Mishra@Sun.COM 	/*
101710393SSaurabh.Mishra@Sun.COM 	 * Setup MII.
101810393SSaurabh.Mishra@Sun.COM 	 */
101910393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
102010393SSaurabh.Mishra@Sun.COM 		mii_ops = &atge_l1e_mii_ops;
102111353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
102211353SSaurabh.Mishra@Sun.COM 		mii_ops = &atge_l1_mii_ops;
102310393SSaurabh.Mishra@Sun.COM 	}
102410393SSaurabh.Mishra@Sun.COM 
102510393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_mii = mii_alloc(atgep, devinfo,
102610393SSaurabh.Mishra@Sun.COM 	    mii_ops)) == NULL) {
102710393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "mii_alloc() failed");
102810393SSaurabh.Mishra@Sun.COM 		goto fail4;
102910393SSaurabh.Mishra@Sun.COM 	}
103010393SSaurabh.Mishra@Sun.COM 
103110393SSaurabh.Mishra@Sun.COM 	/*
103210393SSaurabh.Mishra@Sun.COM 	 * Register with MAC layer.
103310393SSaurabh.Mishra@Sun.COM 	 */
103410393SSaurabh.Mishra@Sun.COM 	if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
103510393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "mac_alloc() failed due to version");
103610393SSaurabh.Mishra@Sun.COM 		goto fail4;
103710393SSaurabh.Mishra@Sun.COM 	}
103810393SSaurabh.Mishra@Sun.COM 
103910393SSaurabh.Mishra@Sun.COM 	macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
104010393SSaurabh.Mishra@Sun.COM 	macreg->m_driver = atgep;
104110393SSaurabh.Mishra@Sun.COM 	macreg->m_dip = devinfo;
104210393SSaurabh.Mishra@Sun.COM 	macreg->m_instance = instance;
104310393SSaurabh.Mishra@Sun.COM 	macreg->m_src_addr = atgep->atge_ether_addr;
104410393SSaurabh.Mishra@Sun.COM 	macreg->m_callbacks = &atge_m_callbacks;
104510393SSaurabh.Mishra@Sun.COM 	macreg->m_min_sdu = 0;
104610393SSaurabh.Mishra@Sun.COM 	macreg->m_max_sdu = atgep->atge_mtu;
104710393SSaurabh.Mishra@Sun.COM 	macreg->m_margin = VLAN_TAGSZ;
104810393SSaurabh.Mishra@Sun.COM 
104910393SSaurabh.Mishra@Sun.COM 	if ((err = mac_register(macreg, &atgep->atge_mh)) != 0) {
105010393SSaurabh.Mishra@Sun.COM 		atge_error(devinfo, "mac_register() failed with :%d", err);
105110393SSaurabh.Mishra@Sun.COM 		mac_free(macreg);
105210393SSaurabh.Mishra@Sun.COM 		goto fail4;
105310393SSaurabh.Mishra@Sun.COM 	}
105410393SSaurabh.Mishra@Sun.COM 
105510393SSaurabh.Mishra@Sun.COM 	mac_free(macreg);
105610393SSaurabh.Mishra@Sun.COM 
105710393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() driver attached successfully",
105810393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__));
105910393SSaurabh.Mishra@Sun.COM 
106010393SSaurabh.Mishra@Sun.COM 	atge_device_reset(atgep);
106110393SSaurabh.Mishra@Sun.COM 
106210393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state = ATGE_CHIP_INITIALIZED;
106310393SSaurabh.Mishra@Sun.COM 
106410393SSaurabh.Mishra@Sun.COM 	/*
106510393SSaurabh.Mishra@Sun.COM 	 * At last - enable interrupts.
106610393SSaurabh.Mishra@Sun.COM 	 */
106710393SSaurabh.Mishra@Sun.COM 	err = atge_enable_intrs(atgep);
106811353SSaurabh.Mishra@Sun.COM 	if (err == DDI_FAILURE) {
106910393SSaurabh.Mishra@Sun.COM 		goto fail5;
107010393SSaurabh.Mishra@Sun.COM 	}
107110393SSaurabh.Mishra@Sun.COM 
107210393SSaurabh.Mishra@Sun.COM 	/*
107310393SSaurabh.Mishra@Sun.COM 	 * Reset the PHY before starting.
107410393SSaurabh.Mishra@Sun.COM 	 */
107510393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
107610393SSaurabh.Mishra@Sun.COM 		atge_l1e_mii_reset(atgep);
107711353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
107811353SSaurabh.Mishra@Sun.COM 		atge_l1_mii_reset(atgep);
107910393SSaurabh.Mishra@Sun.COM 	}
108010393SSaurabh.Mishra@Sun.COM 
108110393SSaurabh.Mishra@Sun.COM 	/*
108210393SSaurabh.Mishra@Sun.COM 	 * Let the PHY run.
108310393SSaurabh.Mishra@Sun.COM 	 */
108410393SSaurabh.Mishra@Sun.COM 	mii_start(atgep->atge_mii);
108510393SSaurabh.Mishra@Sun.COM 
108610393SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
108710393SSaurabh.Mishra@Sun.COM 
108810393SSaurabh.Mishra@Sun.COM fail5:
108910393SSaurabh.Mishra@Sun.COM 	(void) mac_unregister(atgep->atge_mh);
109010393SSaurabh.Mishra@Sun.COM 	atge_device_stop(atgep);
109110393SSaurabh.Mishra@Sun.COM 	mii_stop(atgep->atge_mii);
109210393SSaurabh.Mishra@Sun.COM 	mii_free(atgep->atge_mii);
109310393SSaurabh.Mishra@Sun.COM fail4:
109410393SSaurabh.Mishra@Sun.COM 	atge_free_dma(atgep);
109510393SSaurabh.Mishra@Sun.COM 	mutex_destroy(&atgep->atge_intr_lock);
109610393SSaurabh.Mishra@Sun.COM 	mutex_destroy(&atgep->atge_tx_lock);
109710393SSaurabh.Mishra@Sun.COM 	mutex_destroy(&atgep->atge_rx_lock);
109810393SSaurabh.Mishra@Sun.COM 	atge_remove_intr(atgep);
109910393SSaurabh.Mishra@Sun.COM fail3:
110010393SSaurabh.Mishra@Sun.COM 	ddi_regs_map_free(&atgep->atge_io_handle);
110110393SSaurabh.Mishra@Sun.COM fail2:
110210393SSaurabh.Mishra@Sun.COM 	pci_config_teardown(&atgep->atge_conf_handle);
110310393SSaurabh.Mishra@Sun.COM fail1:
110410393SSaurabh.Mishra@Sun.COM 	if (atgep)
110510393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep, sizeof (atge_t));
110610393SSaurabh.Mishra@Sun.COM 
110710393SSaurabh.Mishra@Sun.COM 	return (DDI_FAILURE);
110810393SSaurabh.Mishra@Sun.COM }
110910393SSaurabh.Mishra@Sun.COM 
111010393SSaurabh.Mishra@Sun.COM static int
atge_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)111110393SSaurabh.Mishra@Sun.COM atge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
111210393SSaurabh.Mishra@Sun.COM {
111310393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
111410393SSaurabh.Mishra@Sun.COM 
111510393SSaurabh.Mishra@Sun.COM 	atgep = ddi_get_driver_private(dip);
111610393SSaurabh.Mishra@Sun.COM 	if (atgep == NULL) {
111710393SSaurabh.Mishra@Sun.COM 		atge_error(dip, "No soft state in detach");
111810393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
111910393SSaurabh.Mishra@Sun.COM 	}
112010393SSaurabh.Mishra@Sun.COM 
112110393SSaurabh.Mishra@Sun.COM 	switch (cmd) {
112210393SSaurabh.Mishra@Sun.COM 	case DDI_DETACH:
112310393SSaurabh.Mishra@Sun.COM 
112410393SSaurabh.Mishra@Sun.COM 		/*
112510393SSaurabh.Mishra@Sun.COM 		 * First unregister with MAC layer before stopping DMA
112610393SSaurabh.Mishra@Sun.COM 		 */
1127*12398Sgdamore@opensolaris.org 		if (mac_disable(atgep->atge_mh) != DDI_SUCCESS)
112810393SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
112910393SSaurabh.Mishra@Sun.COM 
1130*12398Sgdamore@opensolaris.org 		mii_stop(atgep->atge_mii);
113110393SSaurabh.Mishra@Sun.COM 
113210393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_intr_lock);
113310393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_tx_lock);
113410393SSaurabh.Mishra@Sun.COM 		atge_device_stop(atgep);
113510393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
113610393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_intr_lock);
113710393SSaurabh.Mishra@Sun.COM 
113810393SSaurabh.Mishra@Sun.COM 		mii_free(atgep->atge_mii);
113910393SSaurabh.Mishra@Sun.COM 		atge_free_dma(atgep);
114010393SSaurabh.Mishra@Sun.COM 
114110393SSaurabh.Mishra@Sun.COM 		ddi_regs_map_free(&atgep->atge_io_handle);
114210393SSaurabh.Mishra@Sun.COM 		atge_remove_intr(atgep);
114310393SSaurabh.Mishra@Sun.COM 		pci_config_teardown(&atgep->atge_conf_handle);
114410393SSaurabh.Mishra@Sun.COM 
1145*12398Sgdamore@opensolaris.org 		(void) mac_unregister(atgep->atge_mh);
114610393SSaurabh.Mishra@Sun.COM 		mutex_destroy(&atgep->atge_intr_lock);
114710393SSaurabh.Mishra@Sun.COM 		mutex_destroy(&atgep->atge_tx_lock);
114810393SSaurabh.Mishra@Sun.COM 		mutex_destroy(&atgep->atge_rx_lock);
114910393SSaurabh.Mishra@Sun.COM 		kmem_free(atgep, sizeof (atge_t));
115010393SSaurabh.Mishra@Sun.COM 		ddi_set_driver_private(dip, NULL);
115110393SSaurabh.Mishra@Sun.COM 
115210393SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
115310393SSaurabh.Mishra@Sun.COM 
115410393SSaurabh.Mishra@Sun.COM 	case DDI_SUSPEND:
115510393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() is being suspended",
115610393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__));
115710393SSaurabh.Mishra@Sun.COM 
115810393SSaurabh.Mishra@Sun.COM 		/*
115910393SSaurabh.Mishra@Sun.COM 		 * Suspend monitoring MII.
116010393SSaurabh.Mishra@Sun.COM 		 */
116110393SSaurabh.Mishra@Sun.COM 		mii_suspend(atgep->atge_mii);
116210393SSaurabh.Mishra@Sun.COM 
116310393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_intr_lock);
116410393SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_tx_lock);
116510393SSaurabh.Mishra@Sun.COM 		atgep->atge_chip_state |= ATGE_CHIP_SUSPENDED;
116610393SSaurabh.Mishra@Sun.COM 		atge_device_stop(atgep);
116710393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
116810393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_intr_lock);
116910393SSaurabh.Mishra@Sun.COM 
117010393SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
117110393SSaurabh.Mishra@Sun.COM 
117210393SSaurabh.Mishra@Sun.COM 	default:
117310393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
117410393SSaurabh.Mishra@Sun.COM 	}
117510393SSaurabh.Mishra@Sun.COM }
117610393SSaurabh.Mishra@Sun.COM 
117710393SSaurabh.Mishra@Sun.COM int
atge_alloc_buffers(atge_ring_t * r,size_t rcnt,size_t buflen,int f)117810393SSaurabh.Mishra@Sun.COM atge_alloc_buffers(atge_ring_t *r, size_t rcnt, size_t buflen, int f)
117910393SSaurabh.Mishra@Sun.COM {
118010393SSaurabh.Mishra@Sun.COM 	atge_dma_t *dma;
118110393SSaurabh.Mishra@Sun.COM 	atge_dma_t **tbl;
118211353SSaurabh.Mishra@Sun.COM 	int err = DDI_SUCCESS;
118310393SSaurabh.Mishra@Sun.COM 	int i;
118410393SSaurabh.Mishra@Sun.COM 
118510393SSaurabh.Mishra@Sun.COM 	tbl = kmem_zalloc(rcnt * sizeof (atge_dma_t *), KM_SLEEP);
118610393SSaurabh.Mishra@Sun.COM 	r->r_buf_tbl = tbl;
118710393SSaurabh.Mishra@Sun.COM 
118810393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < rcnt; i++) {
118910393SSaurabh.Mishra@Sun.COM 		dma = atge_buf_alloc(r->r_atge, buflen, f);
119010393SSaurabh.Mishra@Sun.COM 		if (dma == NULL) {
119111353SSaurabh.Mishra@Sun.COM 			err = DDI_FAILURE;
119210393SSaurabh.Mishra@Sun.COM 			break;
119310393SSaurabh.Mishra@Sun.COM 		}
119410393SSaurabh.Mishra@Sun.COM 
119510393SSaurabh.Mishra@Sun.COM 		tbl[i] = dma;
119610393SSaurabh.Mishra@Sun.COM 	}
119710393SSaurabh.Mishra@Sun.COM 
119810393SSaurabh.Mishra@Sun.COM 	return (err);
119910393SSaurabh.Mishra@Sun.COM }
120010393SSaurabh.Mishra@Sun.COM 
120110393SSaurabh.Mishra@Sun.COM void
atge_free_buffers(atge_ring_t * r,size_t rcnt)120210393SSaurabh.Mishra@Sun.COM atge_free_buffers(atge_ring_t *r, size_t rcnt)
120310393SSaurabh.Mishra@Sun.COM {
120410393SSaurabh.Mishra@Sun.COM 	atge_dma_t **tbl;
120510393SSaurabh.Mishra@Sun.COM 	int i;
120610393SSaurabh.Mishra@Sun.COM 
120710393SSaurabh.Mishra@Sun.COM 	if (r == NULL || r->r_buf_tbl == NULL)
120810393SSaurabh.Mishra@Sun.COM 		return;
120910393SSaurabh.Mishra@Sun.COM 
121010393SSaurabh.Mishra@Sun.COM 	tbl = r->r_buf_tbl;
121110393SSaurabh.Mishra@Sun.COM 	for (i = 0; i < rcnt; i++)  {
121210393SSaurabh.Mishra@Sun.COM 		if (tbl[i] != NULL) {
121310393SSaurabh.Mishra@Sun.COM 			atge_buf_free(tbl[i]);
121410393SSaurabh.Mishra@Sun.COM 		}
121510393SSaurabh.Mishra@Sun.COM 	}
121610393SSaurabh.Mishra@Sun.COM 
121710393SSaurabh.Mishra@Sun.COM 	kmem_free(tbl, rcnt * sizeof (atge_dma_t *));
121810393SSaurabh.Mishra@Sun.COM }
121910393SSaurabh.Mishra@Sun.COM 
122010393SSaurabh.Mishra@Sun.COM atge_dma_t *
atge_alloc_a_dma_blk(atge_t * atgep,ddi_dma_attr_t * attr,int size,int d)122110393SSaurabh.Mishra@Sun.COM atge_alloc_a_dma_blk(atge_t *atgep, ddi_dma_attr_t *attr, int size, int d)
122210393SSaurabh.Mishra@Sun.COM {
122310393SSaurabh.Mishra@Sun.COM 	int err;
122410393SSaurabh.Mishra@Sun.COM 	atge_dma_t *dma;
122510393SSaurabh.Mishra@Sun.COM 
122610393SSaurabh.Mishra@Sun.COM 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
122710393SSaurabh.Mishra@Sun.COM 
122810393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_alloc_handle(atgep->atge_dip, attr,
122910393SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
123010393SSaurabh.Mishra@Sun.COM 
123110393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
123210393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
123310393SSaurabh.Mishra@Sun.COM 		    " in ddi_dma_alloc_handle() : %d", __func__, err);
123410393SSaurabh.Mishra@Sun.COM 		goto fail;
123510393SSaurabh.Mishra@Sun.COM 	}
123610393SSaurabh.Mishra@Sun.COM 
123710393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_mem_alloc(dma->hdl,
123810393SSaurabh.Mishra@Sun.COM 	    size, &atge_buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
123910393SSaurabh.Mishra@Sun.COM 	    &dma->addr, &dma->len, &dma->acchdl);
124010393SSaurabh.Mishra@Sun.COM 
124110393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
124210393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
124310393SSaurabh.Mishra@Sun.COM 		    " in ddi_dma_mem_alloc() : %d", __func__, err);
124410393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
124510393SSaurabh.Mishra@Sun.COM 		goto fail;
124610393SSaurabh.Mishra@Sun.COM 	}
124710393SSaurabh.Mishra@Sun.COM 
124810393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr,
124910393SSaurabh.Mishra@Sun.COM 	    dma->len, d | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
125010393SSaurabh.Mishra@Sun.COM 	    NULL, &dma->cookie, &dma->count);
125110393SSaurabh.Mishra@Sun.COM 
125210393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
125310393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
125410393SSaurabh.Mishra@Sun.COM 		    " in ddi_dma_addr_bind_handle() : %d", __func__, err);
125510393SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&dma->acchdl);
125610393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
125710393SSaurabh.Mishra@Sun.COM 		goto fail;
125810393SSaurabh.Mishra@Sun.COM 	}
125910393SSaurabh.Mishra@Sun.COM 
126010393SSaurabh.Mishra@Sun.COM 	return (dma);
126110393SSaurabh.Mishra@Sun.COM fail:
126210393SSaurabh.Mishra@Sun.COM 	kmem_free(dma, sizeof (atge_dma_t));
126310393SSaurabh.Mishra@Sun.COM 	return (NULL);
126410393SSaurabh.Mishra@Sun.COM }
126510393SSaurabh.Mishra@Sun.COM 
126610393SSaurabh.Mishra@Sun.COM void
atge_free_a_dma_blk(atge_dma_t * dma)126710393SSaurabh.Mishra@Sun.COM atge_free_a_dma_blk(atge_dma_t *dma)
126810393SSaurabh.Mishra@Sun.COM {
126910393SSaurabh.Mishra@Sun.COM 	if (dma != NULL) {
127010393SSaurabh.Mishra@Sun.COM 		(void) ddi_dma_unbind_handle(dma->hdl);
127110393SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&dma->acchdl);
127210393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
127310393SSaurabh.Mishra@Sun.COM 		kmem_free(dma, sizeof (atge_dma_t));
127410393SSaurabh.Mishra@Sun.COM 	}
127510393SSaurabh.Mishra@Sun.COM }
127610393SSaurabh.Mishra@Sun.COM 
127710393SSaurabh.Mishra@Sun.COM atge_dma_t *
atge_buf_alloc(atge_t * atgep,size_t len,int f)127810393SSaurabh.Mishra@Sun.COM atge_buf_alloc(atge_t *atgep, size_t len, int f)
127910393SSaurabh.Mishra@Sun.COM {
128010393SSaurabh.Mishra@Sun.COM 	atge_dma_t *dma = NULL;
128110393SSaurabh.Mishra@Sun.COM 	int err;
128210393SSaurabh.Mishra@Sun.COM 
128310393SSaurabh.Mishra@Sun.COM 	dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
128410393SSaurabh.Mishra@Sun.COM 
128510393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_alloc_handle(atgep->atge_dip, &atge_dma_attr_buf,
128610393SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL, &dma->hdl);
128710393SSaurabh.Mishra@Sun.COM 
128810393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
128910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
129010393SSaurabh.Mishra@Sun.COM 		    " in %s() : %d", __func__, err);
129110393SSaurabh.Mishra@Sun.COM 		goto fail;
129210393SSaurabh.Mishra@Sun.COM 	}
129310393SSaurabh.Mishra@Sun.COM 
129410393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_mem_alloc(dma->hdl, len, &atge_buf_attr,
129510393SSaurabh.Mishra@Sun.COM 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dma->addr,
129610393SSaurabh.Mishra@Sun.COM 	    &dma->len, &dma->acchdl);
129710393SSaurabh.Mishra@Sun.COM 
129810393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
129910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
130010393SSaurabh.Mishra@Sun.COM 		    " in %s() : %d", __func__, err);
130110393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
130210393SSaurabh.Mishra@Sun.COM 		goto fail;
130310393SSaurabh.Mishra@Sun.COM 	}
130410393SSaurabh.Mishra@Sun.COM 
130510393SSaurabh.Mishra@Sun.COM 	err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, dma->len,
130610393SSaurabh.Mishra@Sun.COM 	    (f | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, &dma->cookie,
130710393SSaurabh.Mishra@Sun.COM 	    &dma->count);
130810393SSaurabh.Mishra@Sun.COM 
130910393SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
131010393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() : failed"
131110393SSaurabh.Mishra@Sun.COM 		    " in %s() : %d", __func__, err);
131210393SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&dma->acchdl);
131310393SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&dma->hdl);
131410393SSaurabh.Mishra@Sun.COM 		goto fail;
131510393SSaurabh.Mishra@Sun.COM 	}
131610393SSaurabh.Mishra@Sun.COM 
131710393SSaurabh.Mishra@Sun.COM 	/*
131810393SSaurabh.Mishra@Sun.COM 	 * Number of return'ed cookie should be one.
131910393SSaurabh.Mishra@Sun.COM 	 */
132010393SSaurabh.Mishra@Sun.COM 	ASSERT(dma->count == 1);
132110393SSaurabh.Mishra@Sun.COM 
132210393SSaurabh.Mishra@Sun.COM 	return (dma);
132310393SSaurabh.Mishra@Sun.COM fail:
132410393SSaurabh.Mishra@Sun.COM 	kmem_free(dma, sizeof (atge_dma_t));
132510393SSaurabh.Mishra@Sun.COM 	return (NULL);
132610393SSaurabh.Mishra@Sun.COM }
132710393SSaurabh.Mishra@Sun.COM 
132810393SSaurabh.Mishra@Sun.COM void
atge_buf_free(atge_dma_t * dma)132910393SSaurabh.Mishra@Sun.COM atge_buf_free(atge_dma_t *dma)
133010393SSaurabh.Mishra@Sun.COM {
133110393SSaurabh.Mishra@Sun.COM 	ASSERT(dma != NULL);
133210393SSaurabh.Mishra@Sun.COM 
133310393SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_unbind_handle(dma->hdl);
133410393SSaurabh.Mishra@Sun.COM 	ddi_dma_mem_free(&dma->acchdl);
133510393SSaurabh.Mishra@Sun.COM 	ddi_dma_free_handle(&dma->hdl);
133610393SSaurabh.Mishra@Sun.COM 	kmem_free(dma, sizeof (atge_dma_t));
133710393SSaurabh.Mishra@Sun.COM }
133810393SSaurabh.Mishra@Sun.COM 
133910393SSaurabh.Mishra@Sun.COM static int
atge_resume(dev_info_t * dip)134010393SSaurabh.Mishra@Sun.COM atge_resume(dev_info_t *dip)
134110393SSaurabh.Mishra@Sun.COM {
134210393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
134310393SSaurabh.Mishra@Sun.COM 
134410393SSaurabh.Mishra@Sun.COM 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
134510393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
134610393SSaurabh.Mishra@Sun.COM 	}
134710393SSaurabh.Mishra@Sun.COM 
134810393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
134910393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
135010393SSaurabh.Mishra@Sun.COM 
135110393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state &= ~ATGE_CHIP_SUSPENDED;
135210393SSaurabh.Mishra@Sun.COM 
135310393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
135410393SSaurabh.Mishra@Sun.COM 		atge_device_restart(atgep);
135510393SSaurabh.Mishra@Sun.COM 	} else {
135610393SSaurabh.Mishra@Sun.COM 		atge_device_reset(atgep);
135710393SSaurabh.Mishra@Sun.COM 	}
135810393SSaurabh.Mishra@Sun.COM 
135910393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
136010393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
136110393SSaurabh.Mishra@Sun.COM 
136210393SSaurabh.Mishra@Sun.COM 	/*
136310393SSaurabh.Mishra@Sun.COM 	 * Reset the PHY before resuming MII.
136410393SSaurabh.Mishra@Sun.COM 	 */
136510393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
136610393SSaurabh.Mishra@Sun.COM 		atge_l1e_mii_reset(atgep);
136710393SSaurabh.Mishra@Sun.COM 	}
136810393SSaurabh.Mishra@Sun.COM 
136910393SSaurabh.Mishra@Sun.COM 	mii_resume(atgep->atge_mii);
137010393SSaurabh.Mishra@Sun.COM 
137110393SSaurabh.Mishra@Sun.COM 	/* kick-off downstream */
137210393SSaurabh.Mishra@Sun.COM 	mac_tx_update(atgep->atge_mh);
137310393SSaurabh.Mishra@Sun.COM 
137410393SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
137510393SSaurabh.Mishra@Sun.COM }
137610393SSaurabh.Mishra@Sun.COM 
137710393SSaurabh.Mishra@Sun.COM static int
atge_quiesce(dev_info_t * dip)137810393SSaurabh.Mishra@Sun.COM atge_quiesce(dev_info_t *dip)
137910393SSaurabh.Mishra@Sun.COM {
138010393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep;
138110393SSaurabh.Mishra@Sun.COM 
138210393SSaurabh.Mishra@Sun.COM 	if ((atgep = ddi_get_driver_private(dip)) == NULL) {
138310393SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
138410393SSaurabh.Mishra@Sun.COM 	}
138510393SSaurabh.Mishra@Sun.COM 
138610393SSaurabh.Mishra@Sun.COM 	atge_device_stop(atgep);
138710393SSaurabh.Mishra@Sun.COM 
138810393SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
138910393SSaurabh.Mishra@Sun.COM }
139010393SSaurabh.Mishra@Sun.COM 
139110393SSaurabh.Mishra@Sun.COM void
atge_add_multicst(atge_t * atgep,uint8_t * macaddr)139210393SSaurabh.Mishra@Sun.COM atge_add_multicst(atge_t *atgep, uint8_t *macaddr)
139310393SSaurabh.Mishra@Sun.COM {
139410393SSaurabh.Mishra@Sun.COM 	uint32_t crc;
139510393SSaurabh.Mishra@Sun.COM 	int bit;
139610393SSaurabh.Mishra@Sun.COM 
139710393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
139810393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
139910393SSaurabh.Mishra@Sun.COM 
140010393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
140110393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
140210393SSaurabh.Mishra@Sun.COM 	    macaddr[3], macaddr[4], macaddr[5]));
140310393SSaurabh.Mishra@Sun.COM 
140410393SSaurabh.Mishra@Sun.COM 	crc = atge_ether_crc(macaddr, ETHERADDRL);
140510393SSaurabh.Mishra@Sun.COM 	bit = (crc >> 26);
140610393SSaurabh.Mishra@Sun.COM 	atgep->atge_mchash_ref_cnt[bit]++;
140710393SSaurabh.Mishra@Sun.COM 	atgep->atge_mchash |= (1ULL << (crc >> 26));
140810393SSaurabh.Mishra@Sun.COM 
140910393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
141010393SSaurabh.Mishra@Sun.COM 	    " atge_mchash_ref_cnt[bit] :%d",
141110393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
141210393SSaurabh.Mishra@Sun.COM 	    atgep->atge_mchash_ref_cnt[bit]));
141310393SSaurabh.Mishra@Sun.COM }
141410393SSaurabh.Mishra@Sun.COM 
141510393SSaurabh.Mishra@Sun.COM void
atge_remove_multicst(atge_t * atgep,uint8_t * macaddr)141610393SSaurabh.Mishra@Sun.COM atge_remove_multicst(atge_t *atgep, uint8_t *macaddr)
141710393SSaurabh.Mishra@Sun.COM {
141810393SSaurabh.Mishra@Sun.COM 	uint32_t crc;
141910393SSaurabh.Mishra@Sun.COM 	int bit;
142010393SSaurabh.Mishra@Sun.COM 
142110393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
142210393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
142310393SSaurabh.Mishra@Sun.COM 
142410393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
142510393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
142610393SSaurabh.Mishra@Sun.COM 	    macaddr[3], macaddr[4], macaddr[5]));
142710393SSaurabh.Mishra@Sun.COM 
142810393SSaurabh.Mishra@Sun.COM 	crc = atge_ether_crc(macaddr, ETHERADDRL);
142910393SSaurabh.Mishra@Sun.COM 	bit = (crc >> 26);
143010393SSaurabh.Mishra@Sun.COM 	atgep->atge_mchash_ref_cnt[bit]--;
143110393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_mchash_ref_cnt[bit] == 0)
143210393SSaurabh.Mishra@Sun.COM 		atgep->atge_mchash &= ~(1ULL << (crc >> 26));
143310393SSaurabh.Mishra@Sun.COM 
143410393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
143510393SSaurabh.Mishra@Sun.COM 	    " atge_mchash_ref_cnt[bit] :%d",
143610393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, atgep->atge_mchash, bit,
143710393SSaurabh.Mishra@Sun.COM 	    atgep->atge_mchash_ref_cnt[bit]));
143810393SSaurabh.Mishra@Sun.COM }
143910393SSaurabh.Mishra@Sun.COM 
144010393SSaurabh.Mishra@Sun.COM int
atge_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)144110393SSaurabh.Mishra@Sun.COM atge_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
144210393SSaurabh.Mishra@Sun.COM {
144310393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
144410393SSaurabh.Mishra@Sun.COM 
144510393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
144610393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
144710393SSaurabh.Mishra@Sun.COM 
144810393SSaurabh.Mishra@Sun.COM 	if (add) {
144910393SSaurabh.Mishra@Sun.COM 		atge_add_multicst(atgep, (uint8_t *)macaddr);
145010393SSaurabh.Mishra@Sun.COM 	} else {
145110393SSaurabh.Mishra@Sun.COM 		atge_remove_multicst(atgep, (uint8_t *)macaddr);
145210393SSaurabh.Mishra@Sun.COM 	}
145310393SSaurabh.Mishra@Sun.COM 
145410393SSaurabh.Mishra@Sun.COM 	atge_rxfilter(atgep);
145510393SSaurabh.Mishra@Sun.COM 
145610393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
145710393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
145810393SSaurabh.Mishra@Sun.COM 
145910393SSaurabh.Mishra@Sun.COM 	return (0);
146010393SSaurabh.Mishra@Sun.COM }
146110393SSaurabh.Mishra@Sun.COM 
146210393SSaurabh.Mishra@Sun.COM int
atge_m_promisc(void * arg,boolean_t on)146310393SSaurabh.Mishra@Sun.COM atge_m_promisc(void *arg, boolean_t on)
146410393SSaurabh.Mishra@Sun.COM {
146510393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
146610393SSaurabh.Mishra@Sun.COM 
146710393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
146810393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
146910393SSaurabh.Mishra@Sun.COM 
147010393SSaurabh.Mishra@Sun.COM 	if (on) {
147110393SSaurabh.Mishra@Sun.COM 		atgep->atge_filter_flags |= ATGE_PROMISC;
147210393SSaurabh.Mishra@Sun.COM 	} else {
147310393SSaurabh.Mishra@Sun.COM 		atgep->atge_filter_flags &= ~ATGE_PROMISC;
147410393SSaurabh.Mishra@Sun.COM 	}
147510393SSaurabh.Mishra@Sun.COM 
147610393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
147710393SSaurabh.Mishra@Sun.COM 		atge_rxfilter(atgep);
147810393SSaurabh.Mishra@Sun.COM 	}
147910393SSaurabh.Mishra@Sun.COM 
148010393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
148110393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
148210393SSaurabh.Mishra@Sun.COM 
148310393SSaurabh.Mishra@Sun.COM 	return (0);
148410393SSaurabh.Mishra@Sun.COM }
148510393SSaurabh.Mishra@Sun.COM 
148610393SSaurabh.Mishra@Sun.COM int
atge_m_unicst(void * arg,const uint8_t * macaddr)148710393SSaurabh.Mishra@Sun.COM atge_m_unicst(void *arg, const uint8_t *macaddr)
148810393SSaurabh.Mishra@Sun.COM {
148910393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
149010393SSaurabh.Mishra@Sun.COM 
149110393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
149210393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
149310393SSaurabh.Mishra@Sun.COM 	bcopy(macaddr, atgep->atge_ether_addr, ETHERADDRL);
149410393SSaurabh.Mishra@Sun.COM 	atge_program_ether(atgep);
149510393SSaurabh.Mishra@Sun.COM 	atge_rxfilter(atgep);
149610393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
149710393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
149810393SSaurabh.Mishra@Sun.COM 
149910393SSaurabh.Mishra@Sun.COM 	return (0);
150010393SSaurabh.Mishra@Sun.COM }
150110393SSaurabh.Mishra@Sun.COM 
150210393SSaurabh.Mishra@Sun.COM mblk_t *
atge_m_tx(void * arg,mblk_t * mp)150310393SSaurabh.Mishra@Sun.COM atge_m_tx(void *arg, mblk_t *mp)
150410393SSaurabh.Mishra@Sun.COM {
150510393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
150610393SSaurabh.Mishra@Sun.COM 	mblk_t	*nmp;
150710393SSaurabh.Mishra@Sun.COM 
150810393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
150910393SSaurabh.Mishra@Sun.COM 
151010393SSaurabh.Mishra@Sun.COM 	/*
151110393SSaurabh.Mishra@Sun.COM 	 * This NIC does not like us to send pkt when link is down.
151210393SSaurabh.Mishra@Sun.COM 	 */
151310393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_link_state & LINK_STATE_UP)) {
151410393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 1;
151511353SSaurabh.Mishra@Sun.COM 
151610393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
151710393SSaurabh.Mishra@Sun.COM 		return (mp);
151810393SSaurabh.Mishra@Sun.COM 	}
151910393SSaurabh.Mishra@Sun.COM 
152010393SSaurabh.Mishra@Sun.COM 	/*
152110393SSaurabh.Mishra@Sun.COM 	 * Don't send a pkt if chip isn't running or in suspended state.
152210393SSaurabh.Mishra@Sun.COM 	 */
152310393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_chip_state & ATGE_CHIP_RUNNING) == 0 ||
152410393SSaurabh.Mishra@Sun.COM 	    atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
152510393SSaurabh.Mishra@Sun.COM 		atgep->atge_carrier_errors++;
152610393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 1;
152711353SSaurabh.Mishra@Sun.COM 
152810393SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
152910393SSaurabh.Mishra@Sun.COM 		return (mp);
153010393SSaurabh.Mishra@Sun.COM 	}
153110393SSaurabh.Mishra@Sun.COM 
153210393SSaurabh.Mishra@Sun.COM 	while (mp != NULL) {
153310393SSaurabh.Mishra@Sun.COM 		nmp = mp->b_next;
153410393SSaurabh.Mishra@Sun.COM 		mp->b_next = NULL;
153510393SSaurabh.Mishra@Sun.COM 
153611353SSaurabh.Mishra@Sun.COM 		if (atge_send_a_packet(atgep, mp) == DDI_FAILURE) {
153710393SSaurabh.Mishra@Sun.COM 			mp->b_next = nmp;
153810393SSaurabh.Mishra@Sun.COM 			break;
153910393SSaurabh.Mishra@Sun.COM 		}
154010393SSaurabh.Mishra@Sun.COM 
154110393SSaurabh.Mishra@Sun.COM 		mp = nmp;
154210393SSaurabh.Mishra@Sun.COM 	}
154310393SSaurabh.Mishra@Sun.COM 
154410393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
154510393SSaurabh.Mishra@Sun.COM 	return (mp);
154610393SSaurabh.Mishra@Sun.COM }
154710393SSaurabh.Mishra@Sun.COM 
154810393SSaurabh.Mishra@Sun.COM int
atge_m_start(void * arg)154910393SSaurabh.Mishra@Sun.COM atge_m_start(void *arg)
155010393SSaurabh.Mishra@Sun.COM {
155110393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
155210393SSaurabh.Mishra@Sun.COM 	int started = 0;
155310393SSaurabh.Mishra@Sun.COM 
155410393SSaurabh.Mishra@Sun.COM 	ASSERT(atgep != NULL);
155510393SSaurabh.Mishra@Sun.COM 
155610393SSaurabh.Mishra@Sun.COM 
155710393SSaurabh.Mishra@Sun.COM 	mii_stop(atgep->atge_mii);
155810393SSaurabh.Mishra@Sun.COM 
155910393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
156010393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_tx_lock);
156110393SSaurabh.Mishra@Sun.COM 
156210393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
156310393SSaurabh.Mishra@Sun.COM 		atge_device_restart(atgep);
156410393SSaurabh.Mishra@Sun.COM 		started = 1;
156510393SSaurabh.Mishra@Sun.COM 	}
156610393SSaurabh.Mishra@Sun.COM 
156710393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_tx_lock);
156810393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
156910393SSaurabh.Mishra@Sun.COM 
157010393SSaurabh.Mishra@Sun.COM 	mii_start(atgep->atge_mii);
157110393SSaurabh.Mishra@Sun.COM 
157210393SSaurabh.Mishra@Sun.COM 	/* kick-off downstream */
157310393SSaurabh.Mishra@Sun.COM 	if (started)
157410393SSaurabh.Mishra@Sun.COM 		mac_tx_update(atgep->atge_mh);
157510393SSaurabh.Mishra@Sun.COM 
157610393SSaurabh.Mishra@Sun.COM 	return (0);
157710393SSaurabh.Mishra@Sun.COM }
157810393SSaurabh.Mishra@Sun.COM 
157910393SSaurabh.Mishra@Sun.COM void
atge_m_stop(void * arg)158010393SSaurabh.Mishra@Sun.COM atge_m_stop(void *arg)
158110393SSaurabh.Mishra@Sun.COM {
158210393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
158310393SSaurabh.Mishra@Sun.COM 
158410393SSaurabh.Mishra@Sun.COM 	mii_stop(atgep->atge_mii);
158510393SSaurabh.Mishra@Sun.COM 
158610393SSaurabh.Mishra@Sun.COM 	/*
158710393SSaurabh.Mishra@Sun.COM 	 * Cancel any pending I/O.
158810393SSaurabh.Mishra@Sun.COM 	 */
158910393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_intr_lock);
159010393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
159110393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED))
159210393SSaurabh.Mishra@Sun.COM 		atge_device_stop(atgep);
159310393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_intr_lock);
159410393SSaurabh.Mishra@Sun.COM }
159510393SSaurabh.Mishra@Sun.COM 
159610393SSaurabh.Mishra@Sun.COM int
atge_m_stat(void * arg,uint_t stat,uint64_t * val)159710393SSaurabh.Mishra@Sun.COM atge_m_stat(void *arg, uint_t stat, uint64_t *val)
159810393SSaurabh.Mishra@Sun.COM {
159910393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
160010393SSaurabh.Mishra@Sun.COM 
160110393SSaurabh.Mishra@Sun.COM 	if (mii_m_getstat(atgep->atge_mii, stat, val) == 0) {
160210393SSaurabh.Mishra@Sun.COM 		return (0);
160310393SSaurabh.Mishra@Sun.COM 	}
160410393SSaurabh.Mishra@Sun.COM 
160510393SSaurabh.Mishra@Sun.COM 	switch (stat) {
160610393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_MULTIRCV:
160710393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_multircv;
160810393SSaurabh.Mishra@Sun.COM 		break;
160910393SSaurabh.Mishra@Sun.COM 
161010393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_BRDCSTRCV:
161110393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_brdcstrcv;
161210393SSaurabh.Mishra@Sun.COM 		break;
161310393SSaurabh.Mishra@Sun.COM 
161410393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_MULTIXMT:
161510393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_multixmt;
161610393SSaurabh.Mishra@Sun.COM 		break;
161710393SSaurabh.Mishra@Sun.COM 
161810393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_BRDCSTXMT:
161910393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_brdcstxmt;
162010393SSaurabh.Mishra@Sun.COM 		break;
162110393SSaurabh.Mishra@Sun.COM 
162210393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IPACKETS:
162310393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_ipackets;
162410393SSaurabh.Mishra@Sun.COM 		break;
162510393SSaurabh.Mishra@Sun.COM 
162610393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_RBYTES:
162710393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_rbytes;
162810393SSaurabh.Mishra@Sun.COM 		break;
162910393SSaurabh.Mishra@Sun.COM 
163010393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OPACKETS:
163110393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_opackets;
163210393SSaurabh.Mishra@Sun.COM 		break;
163310393SSaurabh.Mishra@Sun.COM 
163410393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OBYTES:
163510393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_obytes;
163610393SSaurabh.Mishra@Sun.COM 		break;
163710393SSaurabh.Mishra@Sun.COM 
163810393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_NORCVBUF:
163910393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_norcvbuf;
164010393SSaurabh.Mishra@Sun.COM 		break;
164110393SSaurabh.Mishra@Sun.COM 
164210393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_NOXMTBUF:
164310393SSaurabh.Mishra@Sun.COM 		*val = 0;
164410393SSaurabh.Mishra@Sun.COM 		break;
164510393SSaurabh.Mishra@Sun.COM 
164610393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_COLLISIONS:
164710393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_collisions;
164810393SSaurabh.Mishra@Sun.COM 		break;
164910393SSaurabh.Mishra@Sun.COM 
165010393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IERRORS:
165110393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_errrcv;
165210393SSaurabh.Mishra@Sun.COM 		break;
165310393SSaurabh.Mishra@Sun.COM 
165410393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OERRORS:
165510393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_errxmt;
165610393SSaurabh.Mishra@Sun.COM 		break;
165710393SSaurabh.Mishra@Sun.COM 
165810393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ALIGN_ERRORS:
165910393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_align_errors;
166010393SSaurabh.Mishra@Sun.COM 		break;
166110393SSaurabh.Mishra@Sun.COM 
166210393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_FCS_ERRORS:
166310393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_fcs_errors;
166410393SSaurabh.Mishra@Sun.COM 		break;
166510393SSaurabh.Mishra@Sun.COM 
166610393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_SQE_ERRORS:
166710393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_sqe_errors;
166810393SSaurabh.Mishra@Sun.COM 		break;
166910393SSaurabh.Mishra@Sun.COM 
167010393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_DEFER_XMTS:
167110393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_defer_xmts;
167210393SSaurabh.Mishra@Sun.COM 		break;
167310393SSaurabh.Mishra@Sun.COM 
167410393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_FIRST_COLLISIONS:
167510393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_first_collisions;
167610393SSaurabh.Mishra@Sun.COM 		break;
167710393SSaurabh.Mishra@Sun.COM 
167810393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MULTI_COLLISIONS:
167910393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_multi_collisions;
168010393SSaurabh.Mishra@Sun.COM 		break;
168110393SSaurabh.Mishra@Sun.COM 
168210393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TX_LATE_COLLISIONS:
168310393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_tx_late_collisions;
168410393SSaurabh.Mishra@Sun.COM 		break;
168510393SSaurabh.Mishra@Sun.COM 
168610393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_EX_COLLISIONS:
168710393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_ex_collisions;
168810393SSaurabh.Mishra@Sun.COM 		break;
168910393SSaurabh.Mishra@Sun.COM 
169010393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MACXMT_ERRORS:
169110393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_macxmt_errors;
169210393SSaurabh.Mishra@Sun.COM 		break;
169310393SSaurabh.Mishra@Sun.COM 
169410393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CARRIER_ERRORS:
169510393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_carrier_errors;
169610393SSaurabh.Mishra@Sun.COM 		break;
169710393SSaurabh.Mishra@Sun.COM 
169810393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TOOLONG_ERRORS:
169910393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_toolong_errors;
170010393SSaurabh.Mishra@Sun.COM 		break;
170110393SSaurabh.Mishra@Sun.COM 
170210393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MACRCV_ERRORS:
170310393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_macrcv_errors;
170410393SSaurabh.Mishra@Sun.COM 		break;
170510393SSaurabh.Mishra@Sun.COM 
170610393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OVERFLOWS:
170710393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_overflow;
170810393SSaurabh.Mishra@Sun.COM 		break;
170910393SSaurabh.Mishra@Sun.COM 
171010393SSaurabh.Mishra@Sun.COM 	case MAC_STAT_UNDERFLOWS:
171110393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_underflow;
171210393SSaurabh.Mishra@Sun.COM 		break;
171310393SSaurabh.Mishra@Sun.COM 
171410393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TOOSHORT_ERRORS:
171510393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_runt;
171610393SSaurabh.Mishra@Sun.COM 		break;
171710393SSaurabh.Mishra@Sun.COM 
171810393SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_JABBER_ERRORS:
171910393SSaurabh.Mishra@Sun.COM 		*val = atgep->atge_jabber;
172010393SSaurabh.Mishra@Sun.COM 		break;
172110393SSaurabh.Mishra@Sun.COM 
172210393SSaurabh.Mishra@Sun.COM 	default:
172310393SSaurabh.Mishra@Sun.COM 		return (ENOTSUP);
172410393SSaurabh.Mishra@Sun.COM 	}
172510393SSaurabh.Mishra@Sun.COM 
172610393SSaurabh.Mishra@Sun.COM 	return (0);
172710393SSaurabh.Mishra@Sun.COM }
172810393SSaurabh.Mishra@Sun.COM 
172910393SSaurabh.Mishra@Sun.COM int
atge_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)173011878SVenu.Iyer@Sun.COM atge_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
173111878SVenu.Iyer@Sun.COM     void *val)
173210393SSaurabh.Mishra@Sun.COM {
173310393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
173410393SSaurabh.Mishra@Sun.COM 
173511878SVenu.Iyer@Sun.COM 	return (mii_m_getprop(atgep->atge_mii, name, num, sz, val));
173610393SSaurabh.Mishra@Sun.COM }
173710393SSaurabh.Mishra@Sun.COM 
173810393SSaurabh.Mishra@Sun.COM int
atge_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)173910393SSaurabh.Mishra@Sun.COM atge_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
174010393SSaurabh.Mishra@Sun.COM     const void *val)
174110393SSaurabh.Mishra@Sun.COM {
174210393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
174311353SSaurabh.Mishra@Sun.COM 	int r;
174411353SSaurabh.Mishra@Sun.COM 
174511353SSaurabh.Mishra@Sun.COM 	r = mii_m_setprop(atgep->atge_mii, name, num, sz, val);
174611353SSaurabh.Mishra@Sun.COM 
174711353SSaurabh.Mishra@Sun.COM 	if (r == 0) {
174811353SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_intr_lock);
174911353SSaurabh.Mishra@Sun.COM 		mutex_enter(&atgep->atge_tx_lock);
175011353SSaurabh.Mishra@Sun.COM 
175111353SSaurabh.Mishra@Sun.COM 		if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
175211353SSaurabh.Mishra@Sun.COM 			atge_device_restart(atgep);
175311353SSaurabh.Mishra@Sun.COM 		}
175411353SSaurabh.Mishra@Sun.COM 
175511353SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_tx_lock);
175611353SSaurabh.Mishra@Sun.COM 		mutex_exit(&atgep->atge_intr_lock);
175711353SSaurabh.Mishra@Sun.COM 	}
175811353SSaurabh.Mishra@Sun.COM 
175911353SSaurabh.Mishra@Sun.COM 	return (r);
176010393SSaurabh.Mishra@Sun.COM }
176110393SSaurabh.Mishra@Sun.COM 
176211878SVenu.Iyer@Sun.COM static void
atge_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t prh)176311878SVenu.Iyer@Sun.COM atge_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
176411878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t prh)
176511878SVenu.Iyer@Sun.COM {
176611878SVenu.Iyer@Sun.COM 	atge_t *atgep = arg;
176711878SVenu.Iyer@Sun.COM 
176811878SVenu.Iyer@Sun.COM 	mii_m_propinfo(atgep->atge_mii, name, num, prh);
176911878SVenu.Iyer@Sun.COM }
177010393SSaurabh.Mishra@Sun.COM 
177110393SSaurabh.Mishra@Sun.COM void
atge_program_ether(atge_t * atgep)177210393SSaurabh.Mishra@Sun.COM atge_program_ether(atge_t *atgep)
177310393SSaurabh.Mishra@Sun.COM {
177410393SSaurabh.Mishra@Sun.COM 	ether_addr_t e;
177510393SSaurabh.Mishra@Sun.COM 
177610393SSaurabh.Mishra@Sun.COM 	/*
177710393SSaurabh.Mishra@Sun.COM 	 * Reprogram the Station address.
177810393SSaurabh.Mishra@Sun.COM 	 */
177910393SSaurabh.Mishra@Sun.COM 	bcopy(atgep->atge_ether_addr, e, ETHERADDRL);
178010393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_PAR0,
178110393SSaurabh.Mishra@Sun.COM 	    ((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5]));
178210393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_PAR1, (e[0] << 8) | e[1]);
178310393SSaurabh.Mishra@Sun.COM }
178410393SSaurabh.Mishra@Sun.COM 
178510393SSaurabh.Mishra@Sun.COM /*
178610393SSaurabh.Mishra@Sun.COM  * Device specific operations.
178710393SSaurabh.Mishra@Sun.COM  */
178810393SSaurabh.Mishra@Sun.COM void
atge_device_start(atge_t * atgep)178910393SSaurabh.Mishra@Sun.COM atge_device_start(atge_t *atgep)
179010393SSaurabh.Mishra@Sun.COM {
179111353SSaurabh.Mishra@Sun.COM 	uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo;
179210393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
179310393SSaurabh.Mishra@Sun.COM 	uint32_t fsize;
179410393SSaurabh.Mishra@Sun.COM 
179510393SSaurabh.Mishra@Sun.COM 	/*
179610393SSaurabh.Mishra@Sun.COM 	 * Reprogram the Station address.
179710393SSaurabh.Mishra@Sun.COM 	 */
179810393SSaurabh.Mishra@Sun.COM 	atge_program_ether(atgep);
179910393SSaurabh.Mishra@Sun.COM 
180010393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
180110393SSaurabh.Mishra@Sun.COM 		atge_l1e_program_dma(atgep);
180211353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
180311353SSaurabh.Mishra@Sun.COM 		atge_l1_program_dma(atgep);
180410393SSaurabh.Mishra@Sun.COM 	}
180510393SSaurabh.Mishra@Sun.COM 
180610393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name,
180710393SSaurabh.Mishra@Sun.COM 	    __func__));
180810393SSaurabh.Mishra@Sun.COM 
180910393SSaurabh.Mishra@Sun.COM 	OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
181010393SSaurabh.Mishra@Sun.COM 
181110393SSaurabh.Mishra@Sun.COM 	/*
181211353SSaurabh.Mishra@Sun.COM 	 * Set Maximum frame size but don't let MTU be less than ETHER_MTU.
181310393SSaurabh.Mishra@Sun.COM 	 */
181410393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_mtu < ETHERMTU)
181510393SSaurabh.Mishra@Sun.COM 		atgep->atge_max_frame_size = ETHERMTU;
181610393SSaurabh.Mishra@Sun.COM 	else
181710393SSaurabh.Mishra@Sun.COM 		atgep->atge_max_frame_size = atgep->atge_mtu;
181810393SSaurabh.Mishra@Sun.COM 
181910393SSaurabh.Mishra@Sun.COM 	atgep->atge_max_frame_size += sizeof (struct ether_header) +
182010393SSaurabh.Mishra@Sun.COM 	    VLAN_TAGSZ + ETHERFCSL;
182110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size);
182210393SSaurabh.Mishra@Sun.COM 
182310393SSaurabh.Mishra@Sun.COM 
182410393SSaurabh.Mishra@Sun.COM 	/*
182510393SSaurabh.Mishra@Sun.COM 	 * Configure IPG/IFG parameters.
182610393SSaurabh.Mishra@Sun.COM 	 */
182710393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_IPG_IFG_CFG,
182810393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) |
182910393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) |
183010393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) |
183110393SSaurabh.Mishra@Sun.COM 	    ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK));
183210393SSaurabh.Mishra@Sun.COM 
183310393SSaurabh.Mishra@Sun.COM 	/*
183410393SSaurabh.Mishra@Sun.COM 	 * Set parameters for half-duplex media.
183510393SSaurabh.Mishra@Sun.COM 	 */
183610393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_HDPX_CFG,
183710393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) &
183810393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_LCOL_MASK) |
183910393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) &
184010393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN |
184110393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) &
184210393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_ABEBT_MASK) |
184310393SSaurabh.Mishra@Sun.COM 	    ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) &
184410393SSaurabh.Mishra@Sun.COM 	    HDPX_CFG_JAMIPG_MASK));
184510393SSaurabh.Mishra@Sun.COM 
184610393SSaurabh.Mishra@Sun.COM 	/*
184710393SSaurabh.Mishra@Sun.COM 	 * Configure jumbo frame.
184810393SSaurabh.Mishra@Sun.COM 	 */
184910393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
185010393SSaurabh.Mishra@Sun.COM 		fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t));
185110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_JUMBO_CFG,
185210393SSaurabh.Mishra@Sun.COM 		    (((fsize / sizeof (uint64_t)) <<
185310393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) &
185410393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_SZ_THRESH_MASK) |
185510393SSaurabh.Mishra@Sun.COM 		    ((RXQ_JUMBO_CFG_LKAH_DEFAULT <<
185610393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) |
185710393SSaurabh.Mishra@Sun.COM 		    ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) &
185810393SSaurabh.Mishra@Sun.COM 		    RXQ_JUMBO_CFG_RRD_TIMER_MASK));
185910393SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E &&
186010393SSaurabh.Mishra@Sun.COM 	    atgep->atge_flags & ATGE_FLAG_JUMBO) {
186110393SSaurabh.Mishra@Sun.COM 
186210393SSaurabh.Mishra@Sun.COM 		if (atgep->atge_mtu < ETHERMTU)
186310393SSaurabh.Mishra@Sun.COM 			reg = atgep->atge_max_frame_size;
186410393SSaurabh.Mishra@Sun.COM 		else if (atgep->atge_mtu < 6 * 1024)
186510393SSaurabh.Mishra@Sun.COM 			reg = (atgep->atge_max_frame_size * 2) / 3;
186610393SSaurabh.Mishra@Sun.COM 		else
186710393SSaurabh.Mishra@Sun.COM 			reg = atgep->atge_max_frame_size / 2;
186810393SSaurabh.Mishra@Sun.COM 
186910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_TX_JUMBO_THRESH,
187010393SSaurabh.Mishra@Sun.COM 		    ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
187110393SSaurabh.Mishra@Sun.COM 		    TX_JUMBO_THRESH_UNIT_SHIFT);
187210393SSaurabh.Mishra@Sun.COM 	}
187310393SSaurabh.Mishra@Sun.COM 
187410393SSaurabh.Mishra@Sun.COM 	/*
187510393SSaurabh.Mishra@Sun.COM 	 * Configure flow-control parameters.
187610393SSaurabh.Mishra@Sun.COM 	 */
187710393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
187810393SSaurabh.Mishra@Sun.COM 		/*
187910393SSaurabh.Mishra@Sun.COM 		 * Some hardware version require this magic.
188010393SSaurabh.Mishra@Sun.COM 		 */
188110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, 0x12FC, 0x6500);
188210393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, 0x1008);
188310393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, 0x1008, reg | 0x8000);
188410393SSaurabh.Mishra@Sun.COM 	}
188510393SSaurabh.Mishra@Sun.COM 
188610393SSaurabh.Mishra@Sun.COM 	/*
188710393SSaurabh.Mishra@Sun.COM 	 * These are all magic parameters which came from FreeBSD.
188810393SSaurabh.Mishra@Sun.COM 	 */
188911353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
189011353SSaurabh.Mishra@Sun.COM 		switch (atgep->atge_chip_rev) {
189111353SSaurabh.Mishra@Sun.COM 		case 0x8001:
189211353SSaurabh.Mishra@Sun.COM 		case 0x9001:
189311353SSaurabh.Mishra@Sun.COM 		case 0x9002:
189411353SSaurabh.Mishra@Sun.COM 		case 0x9003:
189511353SSaurabh.Mishra@Sun.COM 			rxf_hi = L1_RX_RING_CNT / 16;
189611353SSaurabh.Mishra@Sun.COM 			rxf_lo = (L1_RX_RING_CNT * 7) / 8;
189711353SSaurabh.Mishra@Sun.COM 			rrd_hi = (L1_RR_RING_CNT * 7) / 8;
189811353SSaurabh.Mishra@Sun.COM 			rrd_lo = L1_RR_RING_CNT / 16;
189911353SSaurabh.Mishra@Sun.COM 			break;
190011353SSaurabh.Mishra@Sun.COM 		default:
190111353SSaurabh.Mishra@Sun.COM 			reg = INL(atgep, L1_SRAM_RX_FIFO_LEN);
190211353SSaurabh.Mishra@Sun.COM 			rxf_lo = reg / 16;
190311353SSaurabh.Mishra@Sun.COM 			if (rxf_lo > 192)
190411353SSaurabh.Mishra@Sun.COM 				rxf_lo = 192;
190511353SSaurabh.Mishra@Sun.COM 			rxf_hi = (reg * 7) / 8;
190611353SSaurabh.Mishra@Sun.COM 			if (rxf_hi < rxf_lo)
190711353SSaurabh.Mishra@Sun.COM 				rxf_hi = rxf_lo + 16;
190811353SSaurabh.Mishra@Sun.COM 			reg = INL(atgep, L1_SRAM_RRD_LEN);
190911353SSaurabh.Mishra@Sun.COM 			rrd_lo = reg / 8;
191011353SSaurabh.Mishra@Sun.COM 			rrd_hi = (reg * 7) / 8;
191111353SSaurabh.Mishra@Sun.COM 			if (rrd_lo > 2)
191211353SSaurabh.Mishra@Sun.COM 				rrd_lo = 2;
191311353SSaurabh.Mishra@Sun.COM 			if (rrd_hi < rrd_lo)
191411353SSaurabh.Mishra@Sun.COM 				rrd_hi = rrd_lo + 3;
191511353SSaurabh.Mishra@Sun.COM 			break;
191611353SSaurabh.Mishra@Sun.COM 		}
191711353SSaurabh.Mishra@Sun.COM 
191811353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
191911353SSaurabh.Mishra@Sun.COM 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
192011353SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
192111353SSaurabh.Mishra@Sun.COM 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
192211353SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
192311353SSaurabh.Mishra@Sun.COM 
192411353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_RXQ_RRD_PAUSE_THRESH,
192511353SSaurabh.Mishra@Sun.COM 		    ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) &
192611353SSaurabh.Mishra@Sun.COM 		    RXQ_RRD_PAUSE_THRESH_LO_MASK) |
192711353SSaurabh.Mishra@Sun.COM 		    ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
192811353SSaurabh.Mishra@Sun.COM 		    RXQ_RRD_PAUSE_THRESH_HI_MASK));
192911353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
193010393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
193110393SSaurabh.Mishra@Sun.COM 		rxf_hi = (reg * 4) / 5;
193210393SSaurabh.Mishra@Sun.COM 		rxf_lo = reg/ 5;
193310393SSaurabh.Mishra@Sun.COM 
193410393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
193510393SSaurabh.Mishra@Sun.COM 		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
193610393SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
193710393SSaurabh.Mishra@Sun.COM 		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
193810393SSaurabh.Mishra@Sun.COM 		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
193910393SSaurabh.Mishra@Sun.COM 	}
194010393SSaurabh.Mishra@Sun.COM 
194110393SSaurabh.Mishra@Sun.COM 	/* Configure RxQ. */
194210393SSaurabh.Mishra@Sun.COM 	reg = 0;
194311353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
194411353SSaurabh.Mishra@Sun.COM 		reg =
194511353SSaurabh.Mishra@Sun.COM 		    ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
194611353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RD_BURST_MASK) |
194711353SSaurabh.Mishra@Sun.COM 		    ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
194811353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
194911353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RRD_BURST_THRESH_MASK) |
195011353SSaurabh.Mishra@Sun.COM 		    ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
195111353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
195211353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
195311353SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
195411353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_CFG, reg);
195511353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
195610393SSaurabh.Mishra@Sun.COM 		reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB |
195710393SSaurabh.Mishra@Sun.COM 		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
195810393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_RXQ_CFG, reg);
195910393SSaurabh.Mishra@Sun.COM 	}
196010393SSaurabh.Mishra@Sun.COM 
196110393SSaurabh.Mishra@Sun.COM 	/*
196210393SSaurabh.Mishra@Sun.COM 	 * Configure TxQ.
196310393SSaurabh.Mishra@Sun.COM 	 */
196411353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
196511353SSaurabh.Mishra@Sun.COM 		reg =
196611353SSaurabh.Mishra@Sun.COM 		    (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
196711353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_BURST_MASK) |
196811353SSaurabh.Mishra@Sun.COM 		    ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
196911353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TX_FIFO_BURST_SHIFT) &
197011353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TX_FIFO_BURST_MASK) |
197111353SSaurabh.Mishra@Sun.COM 		    ((TXQ_CFG_TPD_FETCH_DEFAULT <<
197211353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
197311353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_FETCH_THRESH_MASK) |
197411353SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_ENB);
197511353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_TXQ_CFG, reg);
197611353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
197710393SSaurabh.Mishra@Sun.COM 		reg = (128 <<
197810393SSaurabh.Mishra@Sun.COM 		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
197910393SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
198010393SSaurabh.Mishra@Sun.COM 
198110393SSaurabh.Mishra@Sun.COM 		reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
198210393SSaurabh.Mishra@Sun.COM 		    TXQ_CFG_TPD_BURST_MASK;
198310393SSaurabh.Mishra@Sun.COM 
198410393SSaurabh.Mishra@Sun.COM 		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
198510393SSaurabh.Mishra@Sun.COM 
198610393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_TXQ_CFG, reg);
198710393SSaurabh.Mishra@Sun.COM 	}
198810393SSaurabh.Mishra@Sun.COM 
198911353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
199011353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
199111353SSaurabh.Mishra@Sun.COM 		    (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
199211353SSaurabh.Mishra@Sun.COM 		    TX_JUMBO_TPD_TH_MASK) |
199311353SSaurabh.Mishra@Sun.COM 		    ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
199411353SSaurabh.Mishra@Sun.COM 		    TX_JUMBO_TPD_IPG_MASK));
199511353SSaurabh.Mishra@Sun.COM 	}
199611353SSaurabh.Mishra@Sun.COM 
199710393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
199810393SSaurabh.Mishra@Sun.COM 		/* Disable RSS. */
199910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_RSS_IDT_TABLE0, 0);
200010393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_RSS_CPU, 0);
200110393SSaurabh.Mishra@Sun.COM 	}
200210393SSaurabh.Mishra@Sun.COM 
200310393SSaurabh.Mishra@Sun.COM 	/*
200410393SSaurabh.Mishra@Sun.COM 	 * Configure DMA parameters.
200510393SSaurabh.Mishra@Sun.COM 	 */
200611353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
200711353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG,
200811353SSaurabh.Mishra@Sun.COM 		    DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
200911353SSaurabh.Mishra@Sun.COM 		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
201011353SSaurabh.Mishra@Sun.COM 		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
201111353SSaurabh.Mishra@Sun.COM 
201211353SSaurabh.Mishra@Sun.COM 		/* Configure CMB DMA write threshold. */
201311353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CMB_WR_THRESH,
201411353SSaurabh.Mishra@Sun.COM 		    ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
201511353SSaurabh.Mishra@Sun.COM 		    CMB_WR_THRESH_RRD_MASK) |
201611353SSaurabh.Mishra@Sun.COM 		    ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
201711353SSaurabh.Mishra@Sun.COM 		    CMB_WR_THRESH_TPD_MASK));
201811353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
201910393SSaurabh.Mishra@Sun.COM 		/*
202010393SSaurabh.Mishra@Sun.COM 		 * Don't use Tx CMB. It is known to cause RRS update failure
202110393SSaurabh.Mishra@Sun.COM 		 * under certain circumstances. Typical phenomenon of the
202210393SSaurabh.Mishra@Sun.COM 		 * issue would be unexpected sequence number encountered in
202310393SSaurabh.Mishra@Sun.COM 		 * Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB.
202410393SSaurabh.Mishra@Sun.COM 		 */
202510393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG,
202610393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
202710393SSaurabh.Mishra@Sun.COM 		    atgep->atge_dma_rd_burst | atgep->atge_dma_wr_burst |
202810393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_RXCMB_ENB |
202910393SSaurabh.Mishra@Sun.COM 		    ((DMA_CFG_RD_DELAY_CNT_DEFAULT <<
203010393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) |
203110393SSaurabh.Mishra@Sun.COM 		    ((DMA_CFG_WR_DELAY_CNT_DEFAULT <<
203210393SSaurabh.Mishra@Sun.COM 		    DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK));
203310393SSaurabh.Mishra@Sun.COM 	}
203410393SSaurabh.Mishra@Sun.COM 
203510393SSaurabh.Mishra@Sun.COM 	/*
203611353SSaurabh.Mishra@Sun.COM 	 * Enable CMB/SMB timer.
203710393SSaurabh.Mishra@Sun.COM 	 */
203811353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
203911353SSaurabh.Mishra@Sun.COM 		/* Set CMB/SMB timer and enable them. */
204011353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CMB_WR_TIMER,
204111353SSaurabh.Mishra@Sun.COM 		    ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) &
204211353SSaurabh.Mishra@Sun.COM 		    CMB_WR_TIMER_TX_MASK) |
204311353SSaurabh.Mishra@Sun.COM 		    ((ATGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) &
204411353SSaurabh.Mishra@Sun.COM 		    CMB_WR_TIMER_RX_MASK));
204511353SSaurabh.Mishra@Sun.COM 
204611353SSaurabh.Mishra@Sun.COM 		/* Request SMB updates for every seconds. */
204711353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000));
204811353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CSMB_CTRL,
204911353SSaurabh.Mishra@Sun.COM 		    CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB);
205011353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
205110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
205210393SSaurabh.Mishra@Sun.COM 		atge_l1e_clear_stats(atgep);
205310393SSaurabh.Mishra@Sun.COM 	}
205410393SSaurabh.Mishra@Sun.COM 
205511353SSaurabh.Mishra@Sun.COM 
205610393SSaurabh.Mishra@Sun.COM 	/*
205710393SSaurabh.Mishra@Sun.COM 	 * Disable all WOL bits as WOL can interfere normal Rx
205810393SSaurabh.Mishra@Sun.COM 	 * operation.
205910393SSaurabh.Mishra@Sun.COM 	 */
206010393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_WOL_CFG, 0);
206110393SSaurabh.Mishra@Sun.COM 
206210393SSaurabh.Mishra@Sun.COM 	/*
206310393SSaurabh.Mishra@Sun.COM 	 * Configure Tx/Rx MACs.
206410393SSaurabh.Mishra@Sun.COM 	 *  - Auto-padding for short frames.
206510393SSaurabh.Mishra@Sun.COM 	 *  - Enable CRC generation.
206610393SSaurabh.Mishra@Sun.COM 	 *
206710393SSaurabh.Mishra@Sun.COM 	 *  Start with full-duplex/1000Mbps media. Actual reconfiguration
206810393SSaurabh.Mishra@Sun.COM 	 *  of MAC is followed after link establishment.
206910393SSaurabh.Mishra@Sun.COM 	 */
207010393SSaurabh.Mishra@Sun.COM 	reg = (ATGE_CFG_TX_CRC_ENB | ATGE_CFG_TX_AUTO_PAD |
207110393SSaurabh.Mishra@Sun.COM 	    ATGE_CFG_FULL_DUPLEX |
207210393SSaurabh.Mishra@Sun.COM 	    ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) &
207310393SSaurabh.Mishra@Sun.COM 	    ATGE_CFG_PREAMBLE_MASK));
207410393SSaurabh.Mishra@Sun.COM 
207510393SSaurabh.Mishra@Sun.COM 	if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) {
207610393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_10_100;
207710393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__));
207810393SSaurabh.Mishra@Sun.COM 	} else {
207910393SSaurabh.Mishra@Sun.COM 		reg |= ATGE_CFG_SPEED_1000;
208010393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__));
208110393SSaurabh.Mishra@Sun.COM 	}
208210393SSaurabh.Mishra@Sun.COM 
208310393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAC_CFG, reg);
208410393SSaurabh.Mishra@Sun.COM 
208510393SSaurabh.Mishra@Sun.COM 	atgep->atge_chip_state |= ATGE_CHIP_RUNNING;
208610393SSaurabh.Mishra@Sun.COM 
208710393SSaurabh.Mishra@Sun.COM 	/*
208810393SSaurabh.Mishra@Sun.COM 	 * Set up the receive filter.
208910393SSaurabh.Mishra@Sun.COM 	 */
209010393SSaurabh.Mishra@Sun.COM 	atge_rxfilter(atgep);
209110393SSaurabh.Mishra@Sun.COM 
209211353SSaurabh.Mishra@Sun.COM 	/*
209311353SSaurabh.Mishra@Sun.COM 	 * Acknowledge all pending interrupts and clear it.
209411353SSaurabh.Mishra@Sun.COM 	 */
209511353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
209611353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0);
209711353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
209811353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
209910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS);
210010393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
210110393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0);
210210393SSaurabh.Mishra@Sun.COM 	}
210310393SSaurabh.Mishra@Sun.COM 
210411353SSaurabh.Mishra@Sun.COM 	atge_mac_config(atgep);
210511353SSaurabh.Mishra@Sun.COM 
210610393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() device started", atgep->atge_name, __func__));
210710393SSaurabh.Mishra@Sun.COM }
210810393SSaurabh.Mishra@Sun.COM 
210910393SSaurabh.Mishra@Sun.COM /*
211010393SSaurabh.Mishra@Sun.COM  * Generic functions.
211110393SSaurabh.Mishra@Sun.COM  */
211210393SSaurabh.Mishra@Sun.COM 
211310393SSaurabh.Mishra@Sun.COM #define	CRC32_POLY_BE   0x04c11db7
211410393SSaurabh.Mishra@Sun.COM uint32_t
atge_ether_crc(const uint8_t * addr,int len)211510393SSaurabh.Mishra@Sun.COM atge_ether_crc(const uint8_t *addr, int len)
211610393SSaurabh.Mishra@Sun.COM {
211710393SSaurabh.Mishra@Sun.COM 	int idx;
211810393SSaurabh.Mishra@Sun.COM 	int bit;
211910393SSaurabh.Mishra@Sun.COM 	uint_t data;
212010393SSaurabh.Mishra@Sun.COM 	uint32_t crc;
212110393SSaurabh.Mishra@Sun.COM 
212210393SSaurabh.Mishra@Sun.COM 	crc = 0xffffffff;
212310393SSaurabh.Mishra@Sun.COM 	for (idx = 0; idx < len; idx++) {
212410393SSaurabh.Mishra@Sun.COM 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
212510393SSaurabh.Mishra@Sun.COM 			crc = (crc << 1)
212610393SSaurabh.Mishra@Sun.COM 			    ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
212710393SSaurabh.Mishra@Sun.COM 		}
212810393SSaurabh.Mishra@Sun.COM 	}
212910393SSaurabh.Mishra@Sun.COM 
213010393SSaurabh.Mishra@Sun.COM 	return (crc);
213110393SSaurabh.Mishra@Sun.COM }
213210393SSaurabh.Mishra@Sun.COM 
213310393SSaurabh.Mishra@Sun.COM 
213410393SSaurabh.Mishra@Sun.COM /*
213510393SSaurabh.Mishra@Sun.COM  * Programs RX filter. We use a link-list to keep track of all multicast
213610393SSaurabh.Mishra@Sun.COM  * addressess.
213710393SSaurabh.Mishra@Sun.COM  */
213810393SSaurabh.Mishra@Sun.COM void
atge_rxfilter(atge_t * atgep)213910393SSaurabh.Mishra@Sun.COM atge_rxfilter(atge_t *atgep)
214010393SSaurabh.Mishra@Sun.COM {
214110393SSaurabh.Mishra@Sun.COM 	uint32_t rxcfg;
214210393SSaurabh.Mishra@Sun.COM 	uint64_t mchash;
214310393SSaurabh.Mishra@Sun.COM 
214410393SSaurabh.Mishra@Sun.COM 	rxcfg = INL(atgep, ATGE_MAC_CFG);
214510393SSaurabh.Mishra@Sun.COM 	rxcfg &= ~(ATGE_CFG_ALLMULTI | ATGE_CFG_PROMISC);
214610393SSaurabh.Mishra@Sun.COM 
214710393SSaurabh.Mishra@Sun.COM 	/*
214810393SSaurabh.Mishra@Sun.COM 	 * Accept broadcast frames.
214910393SSaurabh.Mishra@Sun.COM 	 */
215010393SSaurabh.Mishra@Sun.COM 	rxcfg |= ATGE_CFG_BCAST;
215110393SSaurabh.Mishra@Sun.COM 
215210393SSaurabh.Mishra@Sun.COM 	/*
215310393SSaurabh.Mishra@Sun.COM 	 * We don't use Hardware VLAN tagging.
215410393SSaurabh.Mishra@Sun.COM 	 */
215510393SSaurabh.Mishra@Sun.COM 	rxcfg &= ~ATGE_CFG_VLAN_TAG_STRIP;
215610393SSaurabh.Mishra@Sun.COM 
215710393SSaurabh.Mishra@Sun.COM 	if (atgep->atge_filter_flags & (ATGE_PROMISC | ATGE_ALL_MULTICST)) {
215810393SSaurabh.Mishra@Sun.COM 		mchash = ~0ULL;
215910393SSaurabh.Mishra@Sun.COM 
216010393SSaurabh.Mishra@Sun.COM 		if (atgep->atge_filter_flags & ATGE_PROMISC)
216110393SSaurabh.Mishra@Sun.COM 			rxcfg |= ATGE_CFG_PROMISC;
216210393SSaurabh.Mishra@Sun.COM 
216310393SSaurabh.Mishra@Sun.COM 		if (atgep->atge_filter_flags & ATGE_ALL_MULTICST)
216410393SSaurabh.Mishra@Sun.COM 			rxcfg |= ATGE_CFG_ALLMULTI;
216510393SSaurabh.Mishra@Sun.COM 	} else {
216610393SSaurabh.Mishra@Sun.COM 		mchash = atgep->atge_mchash;
216710393SSaurabh.Mishra@Sun.COM 	}
216810393SSaurabh.Mishra@Sun.COM 
216910393SSaurabh.Mishra@Sun.COM 	atge_program_ether(atgep);
217010393SSaurabh.Mishra@Sun.COM 
217110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAR0, (uint32_t)mchash);
217210393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAR1, (uint32_t)(mchash >> 32));
217310393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MAC_CFG, rxcfg);
217410393SSaurabh.Mishra@Sun.COM 
217510393SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx",
217610393SSaurabh.Mishra@Sun.COM 	    atgep->atge_name, __func__, rxcfg, mchash));
217710393SSaurabh.Mishra@Sun.COM }
217810393SSaurabh.Mishra@Sun.COM 
217910393SSaurabh.Mishra@Sun.COM void
atge_device_stop(atge_t * atgep)218010393SSaurabh.Mishra@Sun.COM atge_device_stop(atge_t *atgep)
218110393SSaurabh.Mishra@Sun.COM {
218210393SSaurabh.Mishra@Sun.COM 	uint32_t reg;
218310393SSaurabh.Mishra@Sun.COM 	int t;
218410393SSaurabh.Mishra@Sun.COM 
218510393SSaurabh.Mishra@Sun.COM 	/*
218610393SSaurabh.Mishra@Sun.COM 	 * If the chip is being suspended, then don't touch the state. Caller
218710393SSaurabh.Mishra@Sun.COM 	 * will take care of setting the correct state.
218810393SSaurabh.Mishra@Sun.COM 	 */
218910393SSaurabh.Mishra@Sun.COM 	if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
219010393SSaurabh.Mishra@Sun.COM 		atgep->atge_chip_state |= ATGE_CHIP_STOPPED;
219110393SSaurabh.Mishra@Sun.COM 		atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
219210393SSaurabh.Mishra@Sun.COM 	}
219310393SSaurabh.Mishra@Sun.COM 
219410393SSaurabh.Mishra@Sun.COM 	/*
219510393SSaurabh.Mishra@Sun.COM 	 * Collect stats for L1E. L1 chip's stats are collected by interrupt.
219610393SSaurabh.Mishra@Sun.COM 	 */
219710393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
219810393SSaurabh.Mishra@Sun.COM 		atge_l1e_gather_stats(atgep);
219910393SSaurabh.Mishra@Sun.COM 	}
220010393SSaurabh.Mishra@Sun.COM 
220110393SSaurabh.Mishra@Sun.COM 	/*
220210393SSaurabh.Mishra@Sun.COM 	 * Disable interrupts.
220310393SSaurabh.Mishra@Sun.COM 	 */
220410393SSaurabh.Mishra@Sun.COM 	atge_disable_intrs(atgep);
220510393SSaurabh.Mishra@Sun.COM 
220611353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1)
220711353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, L1_CSMB_CTRL, 0);
220811353SSaurabh.Mishra@Sun.COM 
220911353SSaurabh.Mishra@Sun.COM 	/* Stop DMA Engine */
221011353SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
221111353SSaurabh.Mishra@Sun.COM 		atge_l1_stop_tx_mac(atgep);
221211353SSaurabh.Mishra@Sun.COM 		atge_l1_stop_rx_mac(atgep);
221311353SSaurabh.Mishra@Sun.COM 
221411353SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, ATGE_DMA_CFG);
221511353SSaurabh.Mishra@Sun.COM 		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
221611353SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG, reg);
221711353SSaurabh.Mishra@Sun.COM 
221811353SSaurabh.Mishra@Sun.COM 	}
221911353SSaurabh.Mishra@Sun.COM 
222010393SSaurabh.Mishra@Sun.COM 	/*
222110393SSaurabh.Mishra@Sun.COM 	 * Disable queue processing.
222210393SSaurabh.Mishra@Sun.COM 	 */
222310393SSaurabh.Mishra@Sun.COM 	/* Stop TxQ */
222410393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_TXQ_CFG);
222510393SSaurabh.Mishra@Sun.COM 	reg = reg & ~TXQ_CFG_ENB;
222610393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_TXQ_CFG, reg);
222710393SSaurabh.Mishra@Sun.COM 
222810393SSaurabh.Mishra@Sun.COM 	/* Stop RxQ */
222910393SSaurabh.Mishra@Sun.COM 	reg = INL(atgep, ATGE_RXQ_CFG);
223010393SSaurabh.Mishra@Sun.COM 	reg = reg & ~RXQ_CFG_ENB;
223110393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_RXQ_CFG, reg);
223210393SSaurabh.Mishra@Sun.COM 
223310393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
223410393SSaurabh.Mishra@Sun.COM 		reg = INL(atgep, ATGE_DMA_CFG);
223510393SSaurabh.Mishra@Sun.COM 		reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB);
223610393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_DMA_CFG, reg);
223710393SSaurabh.Mishra@Sun.COM 		drv_usecwait(1000);
223810393SSaurabh.Mishra@Sun.COM 		atge_l1e_stop_mac(atgep);
223910393SSaurabh.Mishra@Sun.COM 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
224010393SSaurabh.Mishra@Sun.COM 	}
224110393SSaurabh.Mishra@Sun.COM 
224210393SSaurabh.Mishra@Sun.COM 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
224310393SSaurabh.Mishra@Sun.COM 		if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
224410393SSaurabh.Mishra@Sun.COM 			break;
224510393SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
224610393SSaurabh.Mishra@Sun.COM 	}
224710393SSaurabh.Mishra@Sun.COM 
224810393SSaurabh.Mishra@Sun.COM 	if (t == 0) {
224910393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "%s() stopping TX/RX MAC timeout",
225010393SSaurabh.Mishra@Sun.COM 		    __func__);
225110393SSaurabh.Mishra@Sun.COM 	}
225210393SSaurabh.Mishra@Sun.COM }
225310393SSaurabh.Mishra@Sun.COM 
225410393SSaurabh.Mishra@Sun.COM void
atge_disable_intrs(atge_t * atgep)225510393SSaurabh.Mishra@Sun.COM atge_disable_intrs(atge_t *atgep)
225610393SSaurabh.Mishra@Sun.COM {
225710393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_INTR_MASK, 0);
225810393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
225910393SSaurabh.Mishra@Sun.COM }
226010393SSaurabh.Mishra@Sun.COM 
226110393SSaurabh.Mishra@Sun.COM void
atge_device_init(atge_t * atgep)226210393SSaurabh.Mishra@Sun.COM atge_device_init(atge_t *atgep)
226310393SSaurabh.Mishra@Sun.COM {
226410393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
226510393SSaurabh.Mishra@Sun.COM 		atgep->atge_intrs = L1E_INTRS;
226610393SSaurabh.Mishra@Sun.COM 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
226710393SSaurabh.Mishra@Sun.COM 
226810393SSaurabh.Mishra@Sun.COM 		atge_l1e_init_tx_ring(atgep);
226910393SSaurabh.Mishra@Sun.COM 		atge_l1e_init_rx_pages(atgep);
227011353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
227111353SSaurabh.Mishra@Sun.COM 		atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN |
227211353SSaurabh.Mishra@Sun.COM 		    INTR_LINK_CHG;
227311353SSaurabh.Mishra@Sun.COM 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
227411353SSaurabh.Mishra@Sun.COM 
227511353SSaurabh.Mishra@Sun.COM 		atge_l1_init_tx_ring(atgep);
227611353SSaurabh.Mishra@Sun.COM 		atge_l1_init_rx_ring(atgep);
227711353SSaurabh.Mishra@Sun.COM 		atge_l1_init_rr_ring(atgep);
227811353SSaurabh.Mishra@Sun.COM 		atge_l1_init_cmb(atgep);
227911353SSaurabh.Mishra@Sun.COM 		atge_l1_init_smb(atgep);
228010393SSaurabh.Mishra@Sun.COM 	}
228110393SSaurabh.Mishra@Sun.COM }
228210393SSaurabh.Mishra@Sun.COM 
228310393SSaurabh.Mishra@Sun.COM void
atge_device_restart(atge_t * atgep)228410393SSaurabh.Mishra@Sun.COM atge_device_restart(atge_t *atgep)
228510393SSaurabh.Mishra@Sun.COM {
228610393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
228710393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
228810393SSaurabh.Mishra@Sun.COM 
228910393SSaurabh.Mishra@Sun.COM 	/*
229010393SSaurabh.Mishra@Sun.COM 	 * Cancel any pending I/O.
229110393SSaurabh.Mishra@Sun.COM 	 */
229210393SSaurabh.Mishra@Sun.COM 	atge_device_stop(atgep);
229310393SSaurabh.Mishra@Sun.COM 
229410393SSaurabh.Mishra@Sun.COM 	/*
229510393SSaurabh.Mishra@Sun.COM 	 * Reset the chip to a known state.
229610393SSaurabh.Mishra@Sun.COM 	 */
229710393SSaurabh.Mishra@Sun.COM 	atge_device_reset(atgep);
229810393SSaurabh.Mishra@Sun.COM 
229910393SSaurabh.Mishra@Sun.COM 	/*
230010393SSaurabh.Mishra@Sun.COM 	 * Initialize the ring and other descriptor like CMB/SMB/Rx return.
230110393SSaurabh.Mishra@Sun.COM 	 */
230210393SSaurabh.Mishra@Sun.COM 	atge_device_init(atgep);
230310393SSaurabh.Mishra@Sun.COM 
230410393SSaurabh.Mishra@Sun.COM 	/*
230510393SSaurabh.Mishra@Sun.COM 	 * Start the chip.
230610393SSaurabh.Mishra@Sun.COM 	 */
230710393SSaurabh.Mishra@Sun.COM 	atge_device_start(atgep);
230810393SSaurabh.Mishra@Sun.COM 
230910393SSaurabh.Mishra@Sun.COM }
231010393SSaurabh.Mishra@Sun.COM 
231110393SSaurabh.Mishra@Sun.COM static int
atge_send_a_packet(atge_t * atgep,mblk_t * mp)231210393SSaurabh.Mishra@Sun.COM atge_send_a_packet(atge_t *atgep, mblk_t *mp)
231310393SSaurabh.Mishra@Sun.COM {
231411353SSaurabh.Mishra@Sun.COM 	atge_tx_desc_t	*txd;
231511353SSaurabh.Mishra@Sun.COM 	uchar_t *c;
231611353SSaurabh.Mishra@Sun.COM 	uint32_t cflags = 0;
231710393SSaurabh.Mishra@Sun.COM 	atge_ring_t *r;
231810393SSaurabh.Mishra@Sun.COM 	size_t pktlen;
231910393SSaurabh.Mishra@Sun.COM 	uchar_t *buf;
232010393SSaurabh.Mishra@Sun.COM 	int	start;
232110393SSaurabh.Mishra@Sun.COM 
232210393SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
232310393SSaurabh.Mishra@Sun.COM 	ASSERT(mp != NULL);
232410393SSaurabh.Mishra@Sun.COM 
232510393SSaurabh.Mishra@Sun.COM 	pktlen = msgsize(mp);
232610393SSaurabh.Mishra@Sun.COM 	if (pktlen > atgep->atge_tx_buf_len) {
232710393SSaurabh.Mishra@Sun.COM 		atgep->atge_macxmt_errors++;
232810393SSaurabh.Mishra@Sun.COM 
232910393SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)",
233010393SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__,
233110393SSaurabh.Mishra@Sun.COM 		    pktlen, atgep->atge_rx_buf_len));
233210393SSaurabh.Mishra@Sun.COM 
233310393SSaurabh.Mishra@Sun.COM 		freemsg(mp);
233411353SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
233510393SSaurabh.Mishra@Sun.COM 	}
233610393SSaurabh.Mishra@Sun.COM 
233710393SSaurabh.Mishra@Sun.COM 	r = atgep->atge_tx_ring;
233810393SSaurabh.Mishra@Sun.COM 
233910393SSaurabh.Mishra@Sun.COM 	if (r->r_avail_desc <= 1) {
234010393SSaurabh.Mishra@Sun.COM 		atgep->atge_noxmtbuf++;
234110393SSaurabh.Mishra@Sun.COM 		atgep->atge_tx_resched = 1;
234211353SSaurabh.Mishra@Sun.COM 
234311353SSaurabh.Mishra@Sun.COM 		ATGE_DB(("%s: %s() No transmit buf",
234411353SSaurabh.Mishra@Sun.COM 		    atgep->atge_name, __func__));
234511353SSaurabh.Mishra@Sun.COM 
234611353SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
234710393SSaurabh.Mishra@Sun.COM 	}
234810393SSaurabh.Mishra@Sun.COM 
234910393SSaurabh.Mishra@Sun.COM 	start = r->r_producer;
235010393SSaurabh.Mishra@Sun.COM 
235110393SSaurabh.Mishra@Sun.COM 	/*
235210393SSaurabh.Mishra@Sun.COM 	 * Get the DMA buffer to hold a packet.
235310393SSaurabh.Mishra@Sun.COM 	 */
235410393SSaurabh.Mishra@Sun.COM 	buf = (uchar_t *)r->r_buf_tbl[start]->addr;
235510393SSaurabh.Mishra@Sun.COM 
235610393SSaurabh.Mishra@Sun.COM 	/*
235710393SSaurabh.Mishra@Sun.COM 	 * Copy the msg and free mp
235810393SSaurabh.Mishra@Sun.COM 	 */
235910393SSaurabh.Mishra@Sun.COM 	mcopymsg(mp, buf);
236010393SSaurabh.Mishra@Sun.COM 
236110393SSaurabh.Mishra@Sun.COM 	r->r_avail_desc--;
236210393SSaurabh.Mishra@Sun.COM 
236311353SSaurabh.Mishra@Sun.COM 	c = (uchar_t *)r->r_desc_ring->addr;
236411353SSaurabh.Mishra@Sun.COM 	c += (sizeof (atge_tx_desc_t) * start);
236511353SSaurabh.Mishra@Sun.COM 	txd = (atge_tx_desc_t *)c;
236611353SSaurabh.Mishra@Sun.COM 
236711353SSaurabh.Mishra@Sun.COM 	ATGE_PUT64(r->r_desc_ring, &txd->addr,
236811353SSaurabh.Mishra@Sun.COM 	    r->r_buf_tbl[start]->cookie.dmac_laddress);
236911353SSaurabh.Mishra@Sun.COM 
237011353SSaurabh.Mishra@Sun.COM 	ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
237111353SSaurabh.Mishra@Sun.COM 
237211353SSaurabh.Mishra@Sun.COM 	cflags |= ATGE_TD_EOP;
237311353SSaurabh.Mishra@Sun.COM 	ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
237411353SSaurabh.Mishra@Sun.COM 
237511353SSaurabh.Mishra@Sun.COM 	/*
237611353SSaurabh.Mishra@Sun.COM 	 * Sync buffer first.
237711353SSaurabh.Mishra@Sun.COM 	 */
237811353SSaurabh.Mishra@Sun.COM 	DMA_SYNC(r->r_buf_tbl[start], 0, pktlen, DDI_DMA_SYNC_FORDEV);
237911353SSaurabh.Mishra@Sun.COM 
238011353SSaurabh.Mishra@Sun.COM 	/*
238111353SSaurabh.Mishra@Sun.COM 	 * Increment TX producer count by one.
238211353SSaurabh.Mishra@Sun.COM 	 */
238311353SSaurabh.Mishra@Sun.COM 	ATGE_INC_SLOT(r->r_producer, ATGE_TX_RING_CNT);
238411353SSaurabh.Mishra@Sun.COM 
238511353SSaurabh.Mishra@Sun.COM 	/*
238611353SSaurabh.Mishra@Sun.COM 	 * Sync descriptor table.
238711353SSaurabh.Mishra@Sun.COM 	 */
238811353SSaurabh.Mishra@Sun.COM 	DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
238911353SSaurabh.Mishra@Sun.COM 
239010393SSaurabh.Mishra@Sun.COM 	/*
239110393SSaurabh.Mishra@Sun.COM 	 * Program TX descriptor to send a packet.
239210393SSaurabh.Mishra@Sun.COM 	 */
239310393SSaurabh.Mishra@Sun.COM 	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
239411353SSaurabh.Mishra@Sun.COM 		atge_l1e_send_packet(r);
239511353SSaurabh.Mishra@Sun.COM 	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
239611353SSaurabh.Mishra@Sun.COM 		atge_l1_send_packet(r);
239710393SSaurabh.Mishra@Sun.COM 	}
239810393SSaurabh.Mishra@Sun.COM 
239911353SSaurabh.Mishra@Sun.COM 	r->r_atge->atge_opackets++;
240011353SSaurabh.Mishra@Sun.COM 	r->r_atge->atge_obytes += pktlen;
240111353SSaurabh.Mishra@Sun.COM 
240211353SSaurabh.Mishra@Sun.COM 	ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer  :%d, "
240311353SSaurabh.Mishra@Sun.COM 	    "consumer : %d", atgep->atge_name, __func__, pktlen,
240411353SSaurabh.Mishra@Sun.COM 	    r->r_avail_desc, r->r_producer, r->r_consumer));
240511353SSaurabh.Mishra@Sun.COM 
240611353SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
240710393SSaurabh.Mishra@Sun.COM }
240810393SSaurabh.Mishra@Sun.COM 
240910393SSaurabh.Mishra@Sun.COM /*
241010393SSaurabh.Mishra@Sun.COM  * Stream Information.
241110393SSaurabh.Mishra@Sun.COM  */
241210393SSaurabh.Mishra@Sun.COM DDI_DEFINE_STREAM_OPS(atge_devops, nulldev, nulldev, atge_attach, atge_detach,
241310393SSaurabh.Mishra@Sun.COM     nodev, NULL, D_MP, NULL, atge_quiesce);
241410393SSaurabh.Mishra@Sun.COM 
241510393SSaurabh.Mishra@Sun.COM /*
241610393SSaurabh.Mishra@Sun.COM  * Module linkage information.
241710393SSaurabh.Mishra@Sun.COM  */
241810393SSaurabh.Mishra@Sun.COM static	struct	modldrv	atge_modldrv = {
241910393SSaurabh.Mishra@Sun.COM 	&mod_driverops,				/* Type of Module */
242010393SSaurabh.Mishra@Sun.COM 	"Atheros/Attansic Gb Ethernet",		/* Description */
242110393SSaurabh.Mishra@Sun.COM 	&atge_devops				/* drv_dev_ops */
242210393SSaurabh.Mishra@Sun.COM };
242310393SSaurabh.Mishra@Sun.COM 
242410393SSaurabh.Mishra@Sun.COM static	struct	modlinkage atge_modlinkage = {
242510393SSaurabh.Mishra@Sun.COM 	MODREV_1,			/* ml_rev */
242610393SSaurabh.Mishra@Sun.COM 	(void *)&atge_modldrv,
242710393SSaurabh.Mishra@Sun.COM 	NULL
242810393SSaurabh.Mishra@Sun.COM };
242910393SSaurabh.Mishra@Sun.COM 
243010393SSaurabh.Mishra@Sun.COM /*
243110393SSaurabh.Mishra@Sun.COM  * DDI Entry points.
243210393SSaurabh.Mishra@Sun.COM  */
243310393SSaurabh.Mishra@Sun.COM int
_init(void)243410393SSaurabh.Mishra@Sun.COM _init(void)
243510393SSaurabh.Mishra@Sun.COM {
243610393SSaurabh.Mishra@Sun.COM 	int	r;
243710393SSaurabh.Mishra@Sun.COM 	mac_init_ops(&atge_devops, "atge");
243810393SSaurabh.Mishra@Sun.COM 	if ((r = mod_install(&atge_modlinkage)) != DDI_SUCCESS) {
243910393SSaurabh.Mishra@Sun.COM 		mac_fini_ops(&atge_devops);
244010393SSaurabh.Mishra@Sun.COM 	}
244110393SSaurabh.Mishra@Sun.COM 
244210393SSaurabh.Mishra@Sun.COM 	return (r);
244310393SSaurabh.Mishra@Sun.COM }
244410393SSaurabh.Mishra@Sun.COM 
244510393SSaurabh.Mishra@Sun.COM int
_fini(void)244610393SSaurabh.Mishra@Sun.COM _fini(void)
244710393SSaurabh.Mishra@Sun.COM {
244810393SSaurabh.Mishra@Sun.COM 	int	r;
244910393SSaurabh.Mishra@Sun.COM 
245010393SSaurabh.Mishra@Sun.COM 	if ((r = mod_remove(&atge_modlinkage)) == DDI_SUCCESS) {
245110393SSaurabh.Mishra@Sun.COM 		mac_fini_ops(&atge_devops);
245210393SSaurabh.Mishra@Sun.COM 	}
245310393SSaurabh.Mishra@Sun.COM 
245410393SSaurabh.Mishra@Sun.COM 	return (r);
245510393SSaurabh.Mishra@Sun.COM }
245610393SSaurabh.Mishra@Sun.COM 
245710393SSaurabh.Mishra@Sun.COM int
_info(struct modinfo * modinfop)245810393SSaurabh.Mishra@Sun.COM _info(struct modinfo *modinfop)
245910393SSaurabh.Mishra@Sun.COM {
246010393SSaurabh.Mishra@Sun.COM 	return (mod_info(&atge_modlinkage, modinfop));
246110393SSaurabh.Mishra@Sun.COM }
2462