xref: /onnv-gate/usr/src/uts/common/io/bfe/bfe.c (revision 11878:ac93462db6d7)
19865SSaurabh.Mishra@Sun.COM /*
29865SSaurabh.Mishra@Sun.COM  * CDDL HEADER START
39865SSaurabh.Mishra@Sun.COM  *
49865SSaurabh.Mishra@Sun.COM  * The contents of this file are subject to the terms of the
59865SSaurabh.Mishra@Sun.COM  * Common Development and Distribution License (the "License").
69865SSaurabh.Mishra@Sun.COM  * You may not use this file except in compliance with the License.
79865SSaurabh.Mishra@Sun.COM  *
89865SSaurabh.Mishra@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99865SSaurabh.Mishra@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109865SSaurabh.Mishra@Sun.COM  * See the License for the specific language governing permissions
119865SSaurabh.Mishra@Sun.COM  * and limitations under the License.
129865SSaurabh.Mishra@Sun.COM  *
139865SSaurabh.Mishra@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149865SSaurabh.Mishra@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159865SSaurabh.Mishra@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169865SSaurabh.Mishra@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179865SSaurabh.Mishra@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189865SSaurabh.Mishra@Sun.COM  *
199865SSaurabh.Mishra@Sun.COM  * CDDL HEADER END
209865SSaurabh.Mishra@Sun.COM  */
219865SSaurabh.Mishra@Sun.COM 
229865SSaurabh.Mishra@Sun.COM /*
23*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
249865SSaurabh.Mishra@Sun.COM  * Use is subject to license terms.
259865SSaurabh.Mishra@Sun.COM  */
269865SSaurabh.Mishra@Sun.COM #include <sys/stream.h>
279865SSaurabh.Mishra@Sun.COM #include <sys/strsun.h>
289865SSaurabh.Mishra@Sun.COM #include <sys/stat.h>
299865SSaurabh.Mishra@Sun.COM #include <sys/pci.h>
309865SSaurabh.Mishra@Sun.COM #include <sys/modctl.h>
319865SSaurabh.Mishra@Sun.COM #include <sys/kstat.h>
329865SSaurabh.Mishra@Sun.COM #include <sys/ethernet.h>
339865SSaurabh.Mishra@Sun.COM #include <sys/devops.h>
349865SSaurabh.Mishra@Sun.COM #include <sys/debug.h>
359865SSaurabh.Mishra@Sun.COM #include <sys/conf.h>
369865SSaurabh.Mishra@Sun.COM #include <sys/sysmacros.h>
379865SSaurabh.Mishra@Sun.COM #include <sys/dditypes.h>
389865SSaurabh.Mishra@Sun.COM #include <sys/ddi.h>
399865SSaurabh.Mishra@Sun.COM #include <sys/sunddi.h>
409865SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h>
419865SSaurabh.Mishra@Sun.COM #include <sys/byteorder.h>
429865SSaurabh.Mishra@Sun.COM #include <sys/cyclic.h>
439865SSaurabh.Mishra@Sun.COM #include <sys/note.h>
449865SSaurabh.Mishra@Sun.COM #include <sys/crc32.h>
459865SSaurabh.Mishra@Sun.COM #include <sys/mac_provider.h>
469865SSaurabh.Mishra@Sun.COM #include <sys/mac_ether.h>
479865SSaurabh.Mishra@Sun.COM #include <sys/vlan.h>
489865SSaurabh.Mishra@Sun.COM #include <sys/errno.h>
499865SSaurabh.Mishra@Sun.COM #include <sys/sdt.h>
509865SSaurabh.Mishra@Sun.COM #include <sys/strsubr.h>
519865SSaurabh.Mishra@Sun.COM 
529865SSaurabh.Mishra@Sun.COM #include "bfe.h"
539865SSaurabh.Mishra@Sun.COM #include "bfe_hw.h"
549865SSaurabh.Mishra@Sun.COM 
559865SSaurabh.Mishra@Sun.COM 
569865SSaurabh.Mishra@Sun.COM /*
579865SSaurabh.Mishra@Sun.COM  * Broadcom BCM4401 chipsets use two rings :
589865SSaurabh.Mishra@Sun.COM  *
599865SSaurabh.Mishra@Sun.COM  * - One TX : For sending packets down the wire.
609865SSaurabh.Mishra@Sun.COM  * - One RX : For receving packets.
619865SSaurabh.Mishra@Sun.COM  *
629865SSaurabh.Mishra@Sun.COM  * Each ring can have any number of descriptors (configured during attach).
639865SSaurabh.Mishra@Sun.COM  * As of now we configure only 128 descriptor per ring (TX/RX). Each descriptor
649865SSaurabh.Mishra@Sun.COM  * has address (desc_addr) and control (desc_ctl) which holds a DMA buffer for
659865SSaurabh.Mishra@Sun.COM  * the packet and control information (like start/end of frame or end of table).
669865SSaurabh.Mishra@Sun.COM  * The descriptor table is allocated first and then a DMA buffer (for a packet)
679865SSaurabh.Mishra@Sun.COM  * is allocated and linked to each descriptor.
689865SSaurabh.Mishra@Sun.COM  *
699865SSaurabh.Mishra@Sun.COM  * Each descriptor entry is bfe_desc_t structure in bfe. During TX/RX
709865SSaurabh.Mishra@Sun.COM  * interrupt, the stat register will point to current descriptor being
719865SSaurabh.Mishra@Sun.COM  * processed.
729865SSaurabh.Mishra@Sun.COM  *
739865SSaurabh.Mishra@Sun.COM  * Here's an example of TX and RX ring :
749865SSaurabh.Mishra@Sun.COM  *
759865SSaurabh.Mishra@Sun.COM  * TX:
769865SSaurabh.Mishra@Sun.COM  *
779865SSaurabh.Mishra@Sun.COM  *   Base of the descriptor table is programmed using BFE_DMATX_CTRL control
789865SSaurabh.Mishra@Sun.COM  *   register. Each 'addr' points to DMA buffer (or packet data buffer) to
799865SSaurabh.Mishra@Sun.COM  *   be transmitted and 'ctl' has the length of the packet (usually MTU).
809865SSaurabh.Mishra@Sun.COM  *
819865SSaurabh.Mishra@Sun.COM  *  ----------------------|
829865SSaurabh.Mishra@Sun.COM  *  | addr |Descriptor 0  |
839865SSaurabh.Mishra@Sun.COM  *  | ctl  |              |
849865SSaurabh.Mishra@Sun.COM  *  ----------------------|
859865SSaurabh.Mishra@Sun.COM  *  | addr |Descriptor 1  |    SOF (start of the frame)
869865SSaurabh.Mishra@Sun.COM  *  | ctl  |              |
879865SSaurabh.Mishra@Sun.COM  *  ----------------------|
889865SSaurabh.Mishra@Sun.COM  *  | ...  |Descriptor... |    EOF (end of the frame)
899865SSaurabh.Mishra@Sun.COM  *  | ...  |              |
909865SSaurabh.Mishra@Sun.COM  *  ----------------------|
919865SSaurabh.Mishra@Sun.COM  *  | addr |Descritor 127 |
929865SSaurabh.Mishra@Sun.COM  *  | ctl  | EOT          |    EOT (End of Table)
939865SSaurabh.Mishra@Sun.COM  *  ----------------------|
949865SSaurabh.Mishra@Sun.COM  *
959865SSaurabh.Mishra@Sun.COM  * 'r_curr_desc'  : pointer to current descriptor which can be used to transmit
969865SSaurabh.Mishra@Sun.COM  *                  a packet.
979865SSaurabh.Mishra@Sun.COM  * 'r_avail_desc' : decremented whenever a packet is being sent.
989865SSaurabh.Mishra@Sun.COM  * 'r_cons_desc'  : incremented whenever a packet is sent down the wire and
999865SSaurabh.Mishra@Sun.COM  *                  notified by an interrupt to bfe driver.
1009865SSaurabh.Mishra@Sun.COM  *
1019865SSaurabh.Mishra@Sun.COM  * RX:
1029865SSaurabh.Mishra@Sun.COM  *
1039865SSaurabh.Mishra@Sun.COM  *   Base of the descriptor table is programmed using BFE_DMARX_CTRL control
1049865SSaurabh.Mishra@Sun.COM  *   register. Each 'addr' points to DMA buffer (or packet data buffer). 'ctl'
1059865SSaurabh.Mishra@Sun.COM  *   contains the size of the DMA buffer and all the DMA buffers are
1069865SSaurabh.Mishra@Sun.COM  *   pre-allocated during attach and hence the maxmium size of the packet is
1079865SSaurabh.Mishra@Sun.COM  *   also known (r_buf_len from the bfe_rint_t structure). During RX interrupt
1089865SSaurabh.Mishra@Sun.COM  *   the packet length is embedded in bfe_header_t which is added by the
1099865SSaurabh.Mishra@Sun.COM  *   chip in the beginning of the packet.
1109865SSaurabh.Mishra@Sun.COM  *
1119865SSaurabh.Mishra@Sun.COM  *  ----------------------|
1129865SSaurabh.Mishra@Sun.COM  *  | addr |Descriptor 0  |
1139865SSaurabh.Mishra@Sun.COM  *  | ctl  |              |
1149865SSaurabh.Mishra@Sun.COM  *  ----------------------|
1159865SSaurabh.Mishra@Sun.COM  *  | addr |Descriptor 1  |
1169865SSaurabh.Mishra@Sun.COM  *  | ctl  |              |
1179865SSaurabh.Mishra@Sun.COM  *  ----------------------|
1189865SSaurabh.Mishra@Sun.COM  *  | ...  |Descriptor... |
1199865SSaurabh.Mishra@Sun.COM  *  | ...  |              |
1209865SSaurabh.Mishra@Sun.COM  *  ----------------------|
1219865SSaurabh.Mishra@Sun.COM  *  | addr |Descriptor 127|
1229865SSaurabh.Mishra@Sun.COM  *  | ctl  | EOT          |    EOT (End of Table)
1239865SSaurabh.Mishra@Sun.COM  *  ----------------------|
1249865SSaurabh.Mishra@Sun.COM  *
1259865SSaurabh.Mishra@Sun.COM  * 'r_curr_desc'  : pointer to current descriptor while receving a packet.
1269865SSaurabh.Mishra@Sun.COM  *
1279865SSaurabh.Mishra@Sun.COM  */
1289865SSaurabh.Mishra@Sun.COM 
1299865SSaurabh.Mishra@Sun.COM #define	MODULE_NAME	"bfe"
1309865SSaurabh.Mishra@Sun.COM 
1319865SSaurabh.Mishra@Sun.COM /*
1329865SSaurabh.Mishra@Sun.COM  * Used for checking PHY (link state, speed)
1339865SSaurabh.Mishra@Sun.COM  */
1349865SSaurabh.Mishra@Sun.COM #define	BFE_TIMEOUT_INTERVAL	(1000 * 1000 * 1000)
1359865SSaurabh.Mishra@Sun.COM 
1369865SSaurabh.Mishra@Sun.COM 
1379865SSaurabh.Mishra@Sun.COM /*
1389865SSaurabh.Mishra@Sun.COM  * Chip restart action and reason for restart
1399865SSaurabh.Mishra@Sun.COM  */
1409865SSaurabh.Mishra@Sun.COM #define	BFE_ACTION_RESTART		0x1	/* For restarting the chip */
1419865SSaurabh.Mishra@Sun.COM #define	BFE_ACTION_RESTART_SETPROP	0x2	/* restart due to setprop */
1429865SSaurabh.Mishra@Sun.COM #define	BFE_ACTION_RESTART_FAULT	0x4	/* restart due to fault */
1439865SSaurabh.Mishra@Sun.COM #define	BFE_ACTION_RESTART_PKT		0x8	/* restart due to pkt timeout */
1449865SSaurabh.Mishra@Sun.COM 
1459865SSaurabh.Mishra@Sun.COM static	char	bfe_ident[] = "bfe driver for Broadcom BCM4401 chipsets";
1469865SSaurabh.Mishra@Sun.COM 
1479865SSaurabh.Mishra@Sun.COM /*
1489865SSaurabh.Mishra@Sun.COM  * Function Prototypes for bfe driver.
1499865SSaurabh.Mishra@Sun.COM  */
1509865SSaurabh.Mishra@Sun.COM static	int	bfe_check_link(bfe_t *);
1519865SSaurabh.Mishra@Sun.COM static	void	bfe_report_link(bfe_t *);
1529865SSaurabh.Mishra@Sun.COM static	void	bfe_chip_halt(bfe_t *);
1539865SSaurabh.Mishra@Sun.COM static	void	bfe_chip_reset(bfe_t *);
1549865SSaurabh.Mishra@Sun.COM static	void	bfe_tx_desc_init(bfe_ring_t *);
1559865SSaurabh.Mishra@Sun.COM static	void	bfe_rx_desc_init(bfe_ring_t *);
1569865SSaurabh.Mishra@Sun.COM static	void	bfe_set_rx_mode(bfe_t *);
1579865SSaurabh.Mishra@Sun.COM static	void	bfe_enable_chip_intrs(bfe_t *);
1589865SSaurabh.Mishra@Sun.COM static	void	bfe_chip_restart(bfe_t *);
1599865SSaurabh.Mishra@Sun.COM static	void	bfe_init_vars(bfe_t *);
1609865SSaurabh.Mishra@Sun.COM static	void	bfe_clear_stats(bfe_t *);
1619865SSaurabh.Mishra@Sun.COM static	void	bfe_gather_stats(bfe_t *);
1629865SSaurabh.Mishra@Sun.COM static	void	bfe_error(dev_info_t *, char *, ...);
1639865SSaurabh.Mishra@Sun.COM static	int	bfe_mac_getprop(void *, const char *, mac_prop_id_t, uint_t,
164*11878SVenu.Iyer@Sun.COM     void *);
1659865SSaurabh.Mishra@Sun.COM static	int	bfe_mac_setprop(void *, const char *, mac_prop_id_t, uint_t,
1669865SSaurabh.Mishra@Sun.COM     const void *);
1679865SSaurabh.Mishra@Sun.COM static	int	bfe_tx_reclaim(bfe_ring_t *);
1689865SSaurabh.Mishra@Sun.COM int	bfe_mac_set_ether_addr(void *, const uint8_t *);
1699865SSaurabh.Mishra@Sun.COM 
1709865SSaurabh.Mishra@Sun.COM 
1719865SSaurabh.Mishra@Sun.COM /*
1729865SSaurabh.Mishra@Sun.COM  * Macros for ddi_dma_sync().
1739865SSaurabh.Mishra@Sun.COM  */
1749865SSaurabh.Mishra@Sun.COM #define	SYNC_DESC(r, s, l, d)	\
1759865SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_sync(r->r_desc_dma_handle, \
1769865SSaurabh.Mishra@Sun.COM 	    (off_t)(s * sizeof (bfe_desc_t)), \
1779865SSaurabh.Mishra@Sun.COM 	    (size_t)(l * sizeof (bfe_desc_t)), \
1789865SSaurabh.Mishra@Sun.COM 	    d)
1799865SSaurabh.Mishra@Sun.COM 
1809865SSaurabh.Mishra@Sun.COM #define	SYNC_BUF(r, s, b, l, d) \
1819865SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_sync(r->r_buf_dma[s].handle, \
1829865SSaurabh.Mishra@Sun.COM 	    (off_t)(b), (size_t)(l), d)
1839865SSaurabh.Mishra@Sun.COM 
1849865SSaurabh.Mishra@Sun.COM /*
1859865SSaurabh.Mishra@Sun.COM  * Supported Broadcom BCM4401 Cards.
1869865SSaurabh.Mishra@Sun.COM  */
1879865SSaurabh.Mishra@Sun.COM static bfe_cards_t bfe_cards[] = {
1889865SSaurabh.Mishra@Sun.COM 	{ 0x14e4, 0x170c, "BCM4401 100Base-TX"},
1899865SSaurabh.Mishra@Sun.COM };
1909865SSaurabh.Mishra@Sun.COM 
1919865SSaurabh.Mishra@Sun.COM 
1929865SSaurabh.Mishra@Sun.COM /*
1939865SSaurabh.Mishra@Sun.COM  * DMA attributes for device registers, packet data (buffer) and
1949865SSaurabh.Mishra@Sun.COM  * descriptor table.
1959865SSaurabh.Mishra@Sun.COM  */
1969865SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr bfe_dev_attr = {
1979865SSaurabh.Mishra@Sun.COM 	DDI_DEVICE_ATTR_V0,
1989865SSaurabh.Mishra@Sun.COM 	DDI_STRUCTURE_LE_ACC,
1999865SSaurabh.Mishra@Sun.COM 	DDI_STRICTORDER_ACC
2009865SSaurabh.Mishra@Sun.COM };
2019865SSaurabh.Mishra@Sun.COM 
2029865SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr bfe_buf_attr = {
2039865SSaurabh.Mishra@Sun.COM 	DDI_DEVICE_ATTR_V0,
2049865SSaurabh.Mishra@Sun.COM 	DDI_NEVERSWAP_ACC,	/* native endianness */
2059865SSaurabh.Mishra@Sun.COM 	DDI_STRICTORDER_ACC
2069865SSaurabh.Mishra@Sun.COM };
2079865SSaurabh.Mishra@Sun.COM 
2089865SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t bfe_dma_attr_buf = {
2099865SSaurabh.Mishra@Sun.COM 	DMA_ATTR_V0,		/* dma_attr_version */
2109865SSaurabh.Mishra@Sun.COM 	0,			/* dma_attr_addr_lo */
2119865SSaurabh.Mishra@Sun.COM 	BFE_PCI_DMA - 1,	/* dma_attr_addr_hi */
2129865SSaurabh.Mishra@Sun.COM 	0x1fff,			/* dma_attr_count_max */
2139865SSaurabh.Mishra@Sun.COM 	8,			/* dma_attr_align */
2149865SSaurabh.Mishra@Sun.COM 	0,			/* dma_attr_burstsizes */
2159865SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_minxfer */
2169865SSaurabh.Mishra@Sun.COM 	0x1fff,			/* dma_attr_maxxfer */
2179865SSaurabh.Mishra@Sun.COM 	BFE_PCI_DMA - 1,	/* dma_attr_seg */
2189865SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_sgllen */
2199865SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_granular */
2209865SSaurabh.Mishra@Sun.COM 	0			/* dma_attr_flags */
2219865SSaurabh.Mishra@Sun.COM };
2229865SSaurabh.Mishra@Sun.COM 
2239865SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t bfe_dma_attr_desc = {
2249865SSaurabh.Mishra@Sun.COM 	DMA_ATTR_V0,		/* dma_attr_version */
2259865SSaurabh.Mishra@Sun.COM 	0,			/* dma_attr_addr_lo */
2269865SSaurabh.Mishra@Sun.COM 	BFE_PCI_DMA - 1,	/* dma_attr_addr_hi */
2279865SSaurabh.Mishra@Sun.COM 	BFE_PCI_DMA - 1,	/* dma_attr_count_max */
2289865SSaurabh.Mishra@Sun.COM 	BFE_DESC_ALIGN,		/* dma_attr_align */
2299865SSaurabh.Mishra@Sun.COM 	0,			/* dma_attr_burstsizes */
2309865SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_minxfer */
2319865SSaurabh.Mishra@Sun.COM 	BFE_PCI_DMA - 1,	/* dma_attr_maxxfer */
2329865SSaurabh.Mishra@Sun.COM 	BFE_PCI_DMA - 1,	/* dma_attr_seg */
2339865SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_sgllen */
2349865SSaurabh.Mishra@Sun.COM 	1,			/* dma_attr_granular */
2359865SSaurabh.Mishra@Sun.COM 	0			/* dma_attr_flags */
2369865SSaurabh.Mishra@Sun.COM };
2379865SSaurabh.Mishra@Sun.COM 
2389865SSaurabh.Mishra@Sun.COM /*
2399865SSaurabh.Mishra@Sun.COM  * Ethernet broadcast addresses.
2409865SSaurabh.Mishra@Sun.COM  */
2419865SSaurabh.Mishra@Sun.COM static uchar_t bfe_broadcast[ETHERADDRL] = {
2429865SSaurabh.Mishra@Sun.COM 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2439865SSaurabh.Mishra@Sun.COM };
2449865SSaurabh.Mishra@Sun.COM 
2459865SSaurabh.Mishra@Sun.COM #define	ASSERT_ALL_LOCKS(bfe) {	\
2469865SSaurabh.Mishra@Sun.COM 	ASSERT(mutex_owned(&bfe->bfe_tx_ring.r_lock));	\
2479865SSaurabh.Mishra@Sun.COM 	ASSERT(rw_write_held(&bfe->bfe_rwlock));	\
2489865SSaurabh.Mishra@Sun.COM }
2499865SSaurabh.Mishra@Sun.COM 
2509865SSaurabh.Mishra@Sun.COM /*
2519865SSaurabh.Mishra@Sun.COM  * Debugging and error reproting code.
2529865SSaurabh.Mishra@Sun.COM  */
2539865SSaurabh.Mishra@Sun.COM static void
2549865SSaurabh.Mishra@Sun.COM bfe_error(dev_info_t *dip, char *fmt, ...)
2559865SSaurabh.Mishra@Sun.COM {
2569865SSaurabh.Mishra@Sun.COM 	va_list ap;
2579865SSaurabh.Mishra@Sun.COM 	char	buf[256];
2589865SSaurabh.Mishra@Sun.COM 
2599865SSaurabh.Mishra@Sun.COM 	va_start(ap, fmt);
2609865SSaurabh.Mishra@Sun.COM 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
2619865SSaurabh.Mishra@Sun.COM 	va_end(ap);
2629865SSaurabh.Mishra@Sun.COM 
2639865SSaurabh.Mishra@Sun.COM 	if (dip) {
2649865SSaurabh.Mishra@Sun.COM 		cmn_err(CE_WARN, "%s%d: %s",
2659865SSaurabh.Mishra@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
2669865SSaurabh.Mishra@Sun.COM 	} else {
2679865SSaurabh.Mishra@Sun.COM 		cmn_err(CE_WARN, "bfe: %s", buf);
2689865SSaurabh.Mishra@Sun.COM 	}
2699865SSaurabh.Mishra@Sun.COM }
2709865SSaurabh.Mishra@Sun.COM 
2719865SSaurabh.Mishra@Sun.COM /*
2729865SSaurabh.Mishra@Sun.COM  * Grabs all necessary locks to block any other operation on the chip.
2739865SSaurabh.Mishra@Sun.COM  */
2749865SSaurabh.Mishra@Sun.COM static void
2759865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe_t *bfe)
2769865SSaurabh.Mishra@Sun.COM {
2779865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *tx = &bfe->bfe_tx_ring;
2789865SSaurabh.Mishra@Sun.COM 
2799865SSaurabh.Mishra@Sun.COM 	/*
2809865SSaurabh.Mishra@Sun.COM 	 * Grab all the locks.
2819865SSaurabh.Mishra@Sun.COM 	 * - bfe_rwlock : locks down whole chip including RX.
2829865SSaurabh.Mishra@Sun.COM 	 * - tx's r_lock : locks down only TX side.
2839865SSaurabh.Mishra@Sun.COM 	 */
2849865SSaurabh.Mishra@Sun.COM 	rw_enter(&bfe->bfe_rwlock, RW_WRITER);
2859865SSaurabh.Mishra@Sun.COM 	mutex_enter(&tx->r_lock);
2869865SSaurabh.Mishra@Sun.COM 
2879865SSaurabh.Mishra@Sun.COM 	/*
2889865SSaurabh.Mishra@Sun.COM 	 * Note that we don't use RX's r_lock.
2899865SSaurabh.Mishra@Sun.COM 	 */
2909865SSaurabh.Mishra@Sun.COM }
2919865SSaurabh.Mishra@Sun.COM 
2929865SSaurabh.Mishra@Sun.COM /*
2939865SSaurabh.Mishra@Sun.COM  * Release lock on chip/drver.
2949865SSaurabh.Mishra@Sun.COM  */
2959865SSaurabh.Mishra@Sun.COM static void
2969865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe_t *bfe)
2979865SSaurabh.Mishra@Sun.COM {
2989865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *tx = &bfe->bfe_tx_ring;
2999865SSaurabh.Mishra@Sun.COM 
3009865SSaurabh.Mishra@Sun.COM 	/*
3019865SSaurabh.Mishra@Sun.COM 	 * Release all the locks in the order in which they were grabbed.
3029865SSaurabh.Mishra@Sun.COM 	 */
3039865SSaurabh.Mishra@Sun.COM 	mutex_exit(&tx->r_lock);
3049865SSaurabh.Mishra@Sun.COM 	rw_exit(&bfe->bfe_rwlock);
3059865SSaurabh.Mishra@Sun.COM }
3069865SSaurabh.Mishra@Sun.COM 
3079865SSaurabh.Mishra@Sun.COM 
3089865SSaurabh.Mishra@Sun.COM /*
3099865SSaurabh.Mishra@Sun.COM  * It's used to make sure that the write to device register was successful.
3109865SSaurabh.Mishra@Sun.COM  */
3119865SSaurabh.Mishra@Sun.COM static int
3129865SSaurabh.Mishra@Sun.COM bfe_wait_bit(bfe_t *bfe, uint32_t reg, uint32_t bit,
3139865SSaurabh.Mishra@Sun.COM     ulong_t t, const int clear)
3149865SSaurabh.Mishra@Sun.COM {
3159865SSaurabh.Mishra@Sun.COM 	ulong_t i;
3169865SSaurabh.Mishra@Sun.COM 	uint32_t v;
3179865SSaurabh.Mishra@Sun.COM 
3189865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < t; i++) {
3199865SSaurabh.Mishra@Sun.COM 		v = INL(bfe, reg);
3209865SSaurabh.Mishra@Sun.COM 
3219865SSaurabh.Mishra@Sun.COM 		if (clear && !(v & bit))
3229865SSaurabh.Mishra@Sun.COM 			break;
3239865SSaurabh.Mishra@Sun.COM 
3249865SSaurabh.Mishra@Sun.COM 		if (!clear && (v & bit))
3259865SSaurabh.Mishra@Sun.COM 			break;
3269865SSaurabh.Mishra@Sun.COM 
3279865SSaurabh.Mishra@Sun.COM 		drv_usecwait(10);
3289865SSaurabh.Mishra@Sun.COM 	}
3299865SSaurabh.Mishra@Sun.COM 
3309865SSaurabh.Mishra@Sun.COM 	/* if device still didn't see the value */
3319865SSaurabh.Mishra@Sun.COM 	if (i == t)
3329865SSaurabh.Mishra@Sun.COM 		return (-1);
3339865SSaurabh.Mishra@Sun.COM 
3349865SSaurabh.Mishra@Sun.COM 	return (0);
3359865SSaurabh.Mishra@Sun.COM }
3369865SSaurabh.Mishra@Sun.COM 
3379865SSaurabh.Mishra@Sun.COM /*
3389865SSaurabh.Mishra@Sun.COM  * PHY functions (read, write, stop, reset and startup)
3399865SSaurabh.Mishra@Sun.COM  */
3409865SSaurabh.Mishra@Sun.COM static int
3419865SSaurabh.Mishra@Sun.COM bfe_read_phy(bfe_t *bfe, uint32_t reg)
3429865SSaurabh.Mishra@Sun.COM {
3439865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
3449865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
3459865SSaurabh.Mishra@Sun.COM 	    (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) |
3469865SSaurabh.Mishra@Sun.COM 	    (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) |
3479865SSaurabh.Mishra@Sun.COM 	    (reg << BFE_MDIO_RA_SHIFT) |
3489865SSaurabh.Mishra@Sun.COM 	    (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT)));
3499865SSaurabh.Mishra@Sun.COM 
3509865SSaurabh.Mishra@Sun.COM 	(void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0);
3519865SSaurabh.Mishra@Sun.COM 
3529865SSaurabh.Mishra@Sun.COM 	return ((INL(bfe, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA));
3539865SSaurabh.Mishra@Sun.COM }
3549865SSaurabh.Mishra@Sun.COM 
3559865SSaurabh.Mishra@Sun.COM static void
3569865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe_t *bfe, uint32_t reg, uint32_t val)
3579865SSaurabh.Mishra@Sun.COM {
3589865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
3599865SSaurabh.Mishra@Sun.COM 	OUTL(bfe,  BFE_MDIO_DATA, (BFE_MDIO_SB_START |
3609865SSaurabh.Mishra@Sun.COM 	    (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) |
3619865SSaurabh.Mishra@Sun.COM 	    (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) |
3629865SSaurabh.Mishra@Sun.COM 	    (reg << BFE_MDIO_RA_SHIFT) |
3639865SSaurabh.Mishra@Sun.COM 	    (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) |
3649865SSaurabh.Mishra@Sun.COM 	    (val & BFE_MDIO_DATA_DATA)));
3659865SSaurabh.Mishra@Sun.COM 
3669865SSaurabh.Mishra@Sun.COM 	(void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0);
3679865SSaurabh.Mishra@Sun.COM }
3689865SSaurabh.Mishra@Sun.COM 
3699865SSaurabh.Mishra@Sun.COM /*
3709865SSaurabh.Mishra@Sun.COM  * It resets the PHY layer.
3719865SSaurabh.Mishra@Sun.COM  */
3729865SSaurabh.Mishra@Sun.COM static int
3739865SSaurabh.Mishra@Sun.COM bfe_reset_phy(bfe_t *bfe)
3749865SSaurabh.Mishra@Sun.COM {
3759865SSaurabh.Mishra@Sun.COM 	uint32_t i;
3769865SSaurabh.Mishra@Sun.COM 
3779865SSaurabh.Mishra@Sun.COM 	bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_RESET);
3789865SSaurabh.Mishra@Sun.COM 	drv_usecwait(100);
3799865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < 10; i++) {
3809865SSaurabh.Mishra@Sun.COM 		if (bfe_read_phy(bfe, MII_CONTROL) &
3819865SSaurabh.Mishra@Sun.COM 		    MII_CONTROL_RESET) {
3829865SSaurabh.Mishra@Sun.COM 			drv_usecwait(500);
3839865SSaurabh.Mishra@Sun.COM 			continue;
3849865SSaurabh.Mishra@Sun.COM 		}
3859865SSaurabh.Mishra@Sun.COM 
3869865SSaurabh.Mishra@Sun.COM 		break;
3879865SSaurabh.Mishra@Sun.COM 	}
3889865SSaurabh.Mishra@Sun.COM 
3899865SSaurabh.Mishra@Sun.COM 	if (i == 10) {
3909865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "Timeout waiting for PHY to reset");
3919865SSaurabh.Mishra@Sun.COM 		bfe->bfe_phy_state = BFE_PHY_RESET_TIMEOUT;
3929865SSaurabh.Mishra@Sun.COM 		return (BFE_FAILURE);
3939865SSaurabh.Mishra@Sun.COM 	}
3949865SSaurabh.Mishra@Sun.COM 
3959865SSaurabh.Mishra@Sun.COM 	bfe->bfe_phy_state = BFE_PHY_RESET_DONE;
3969865SSaurabh.Mishra@Sun.COM 
3979865SSaurabh.Mishra@Sun.COM 	return (BFE_SUCCESS);
3989865SSaurabh.Mishra@Sun.COM }
3999865SSaurabh.Mishra@Sun.COM 
4009865SSaurabh.Mishra@Sun.COM /*
4019865SSaurabh.Mishra@Sun.COM  * Make sure timer function is out of our way and especially during
4029865SSaurabh.Mishra@Sun.COM  * detach.
4039865SSaurabh.Mishra@Sun.COM  */
4049865SSaurabh.Mishra@Sun.COM static void
4059865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe_t *bfe)
4069865SSaurabh.Mishra@Sun.COM {
4079865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_periodic_id) {
4089865SSaurabh.Mishra@Sun.COM 		ddi_periodic_delete(bfe->bfe_periodic_id);
4099865SSaurabh.Mishra@Sun.COM 		bfe->bfe_periodic_id = NULL;
4109865SSaurabh.Mishra@Sun.COM 	}
4119865SSaurabh.Mishra@Sun.COM }
4129865SSaurabh.Mishra@Sun.COM 
4139865SSaurabh.Mishra@Sun.COM /*
4149865SSaurabh.Mishra@Sun.COM  * Stops the PHY
4159865SSaurabh.Mishra@Sun.COM  */
4169865SSaurabh.Mishra@Sun.COM static void
4179865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe_t *bfe)
4189865SSaurabh.Mishra@Sun.COM {
4199865SSaurabh.Mishra@Sun.COM 	bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_PWRDN |
4209865SSaurabh.Mishra@Sun.COM 	    MII_CONTROL_ISOLATE);
4219865SSaurabh.Mishra@Sun.COM 
4229865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.link = LINK_STATE_UNKNOWN;
4239865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.speed = 0;
4249865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
4259865SSaurabh.Mishra@Sun.COM 
4269865SSaurabh.Mishra@Sun.COM 	bfe->bfe_phy_state = BFE_PHY_STOPPED;
4279865SSaurabh.Mishra@Sun.COM 
4289865SSaurabh.Mishra@Sun.COM 	/*
4299865SSaurabh.Mishra@Sun.COM 	 * Report the link status to MAC layer.
4309865SSaurabh.Mishra@Sun.COM 	 */
4319865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_machdl != NULL)
4329865SSaurabh.Mishra@Sun.COM 		(void) bfe_report_link(bfe);
4339865SSaurabh.Mishra@Sun.COM }
4349865SSaurabh.Mishra@Sun.COM 
4359865SSaurabh.Mishra@Sun.COM static int
4369865SSaurabh.Mishra@Sun.COM bfe_probe_phy(bfe_t *bfe)
4379865SSaurabh.Mishra@Sun.COM {
4389865SSaurabh.Mishra@Sun.COM 	int phy;
4399865SSaurabh.Mishra@Sun.COM 	uint32_t status;
4409865SSaurabh.Mishra@Sun.COM 
4419865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_phy_addr) {
4429865SSaurabh.Mishra@Sun.COM 		status = bfe_read_phy(bfe, MII_STATUS);
4439865SSaurabh.Mishra@Sun.COM 		if (status != 0xffff && status != 0) {
4449865SSaurabh.Mishra@Sun.COM 			bfe_write_phy(bfe, MII_CONTROL, 0);
4459865SSaurabh.Mishra@Sun.COM 			return (BFE_SUCCESS);
4469865SSaurabh.Mishra@Sun.COM 		}
4479865SSaurabh.Mishra@Sun.COM 	}
4489865SSaurabh.Mishra@Sun.COM 
4499865SSaurabh.Mishra@Sun.COM 	for (phy = 0; phy < 32; phy++) {
4509865SSaurabh.Mishra@Sun.COM 		bfe->bfe_phy_addr = phy;
4519865SSaurabh.Mishra@Sun.COM 		status = bfe_read_phy(bfe, MII_STATUS);
4529865SSaurabh.Mishra@Sun.COM 		if (status != 0xffff && status != 0) {
4539865SSaurabh.Mishra@Sun.COM 			bfe_write_phy(bfe, MII_CONTROL, 0);
4549865SSaurabh.Mishra@Sun.COM 			return (BFE_SUCCESS);
4559865SSaurabh.Mishra@Sun.COM 		}
4569865SSaurabh.Mishra@Sun.COM 	}
4579865SSaurabh.Mishra@Sun.COM 
4589865SSaurabh.Mishra@Sun.COM 	return (BFE_FAILURE);
4599865SSaurabh.Mishra@Sun.COM }
4609865SSaurabh.Mishra@Sun.COM 
4619865SSaurabh.Mishra@Sun.COM /*
4629865SSaurabh.Mishra@Sun.COM  * This timeout function fires at BFE_TIMEOUT_INTERVAL to check the link
4639865SSaurabh.Mishra@Sun.COM  * status.
4649865SSaurabh.Mishra@Sun.COM  */
4659865SSaurabh.Mishra@Sun.COM static void
4669865SSaurabh.Mishra@Sun.COM bfe_timeout(void *arg)
4679865SSaurabh.Mishra@Sun.COM {
4689865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
46910591SSaurabh.Mishra@Sun.COM 	int resched = 0;
4709865SSaurabh.Mishra@Sun.COM 
4719865SSaurabh.Mishra@Sun.COM 	/*
4729865SSaurabh.Mishra@Sun.COM 	 * We don't grab any lock because bfe can't go away.
4739865SSaurabh.Mishra@Sun.COM 	 * untimeout() will wait for this timeout instance to complete.
4749865SSaurabh.Mishra@Sun.COM 	 */
4759865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_chip_action & BFE_ACTION_RESTART) {
4769865SSaurabh.Mishra@Sun.COM 		/*
4779865SSaurabh.Mishra@Sun.COM 		 * Restart the chip.
4789865SSaurabh.Mishra@Sun.COM 		 */
4799865SSaurabh.Mishra@Sun.COM 		bfe_grab_locks(bfe);
4809865SSaurabh.Mishra@Sun.COM 		bfe_chip_restart(bfe);
4819865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART;
4829865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_FAULT;
4839865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_PKT;
4849865SSaurabh.Mishra@Sun.COM 		bfe_release_locks(bfe);
4859865SSaurabh.Mishra@Sun.COM 		mac_tx_update(bfe->bfe_machdl);
4869865SSaurabh.Mishra@Sun.COM 		/* Restart will register a new timeout */
4879865SSaurabh.Mishra@Sun.COM 		return;
4889865SSaurabh.Mishra@Sun.COM 	}
4899865SSaurabh.Mishra@Sun.COM 
4909865SSaurabh.Mishra@Sun.COM 	rw_enter(&bfe->bfe_rwlock, RW_READER);
4919865SSaurabh.Mishra@Sun.COM 
4929865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
4939865SSaurabh.Mishra@Sun.COM 		hrtime_t hr;
4949865SSaurabh.Mishra@Sun.COM 
4959865SSaurabh.Mishra@Sun.COM 		hr = gethrtime();
4969865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_tx_stall_time != 0 &&
4979865SSaurabh.Mishra@Sun.COM 		    hr > bfe->bfe_tx_stall_time) {
4989865SSaurabh.Mishra@Sun.COM 			DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit,
4999865SSaurabh.Mishra@Sun.COM 			    char *, "pkt timeout");
5009865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip_action |=
5019865SSaurabh.Mishra@Sun.COM 			    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_PKT);
5029865SSaurabh.Mishra@Sun.COM 			bfe->bfe_tx_stall_time = 0;
5039865SSaurabh.Mishra@Sun.COM 		}
5049865SSaurabh.Mishra@Sun.COM 	}
5059865SSaurabh.Mishra@Sun.COM 
5069865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_phy_state == BFE_PHY_STARTED) {
5079865SSaurabh.Mishra@Sun.COM 		/*
5089865SSaurabh.Mishra@Sun.COM 		 * Report the link status to MAC layer if link status changed.
5099865SSaurabh.Mishra@Sun.COM 		 */
5109865SSaurabh.Mishra@Sun.COM 		if (bfe_check_link(bfe)) {
5119865SSaurabh.Mishra@Sun.COM 			bfe_report_link(bfe);
5129865SSaurabh.Mishra@Sun.COM 			if (bfe->bfe_chip.link == LINK_STATE_UP) {
5139865SSaurabh.Mishra@Sun.COM 				uint32_t val, flow;
5149865SSaurabh.Mishra@Sun.COM 
5159865SSaurabh.Mishra@Sun.COM 				val = INL(bfe, BFE_TX_CTRL);
5169865SSaurabh.Mishra@Sun.COM 				val &= ~BFE_TX_DUPLEX;
5179865SSaurabh.Mishra@Sun.COM 				if (bfe->bfe_chip.duplex == LINK_DUPLEX_FULL) {
5189865SSaurabh.Mishra@Sun.COM 					val |= BFE_TX_DUPLEX;
5199865SSaurabh.Mishra@Sun.COM 					flow = INL(bfe, BFE_RXCONF);
5209865SSaurabh.Mishra@Sun.COM 					flow &= ~BFE_RXCONF_FLOW;
5219865SSaurabh.Mishra@Sun.COM 					OUTL(bfe, BFE_RXCONF, flow);
5229865SSaurabh.Mishra@Sun.COM 
5239865SSaurabh.Mishra@Sun.COM 					flow = INL(bfe, BFE_MAC_FLOW);
5249865SSaurabh.Mishra@Sun.COM 					flow &= ~(BFE_FLOW_RX_HIWAT);
5259865SSaurabh.Mishra@Sun.COM 					OUTL(bfe, BFE_MAC_FLOW, flow);
5269865SSaurabh.Mishra@Sun.COM 				}
5279865SSaurabh.Mishra@Sun.COM 
52810591SSaurabh.Mishra@Sun.COM 				resched = 1;
52910591SSaurabh.Mishra@Sun.COM 
5309865SSaurabh.Mishra@Sun.COM 				OUTL(bfe, BFE_TX_CTRL, val);
5319865SSaurabh.Mishra@Sun.COM 				DTRACE_PROBE1(link__up,
5329865SSaurabh.Mishra@Sun.COM 				    int, bfe->bfe_unit);
5339865SSaurabh.Mishra@Sun.COM 			}
5349865SSaurabh.Mishra@Sun.COM 		}
5359865SSaurabh.Mishra@Sun.COM 	}
5369865SSaurabh.Mishra@Sun.COM 
5379865SSaurabh.Mishra@Sun.COM 	rw_exit(&bfe->bfe_rwlock);
53810591SSaurabh.Mishra@Sun.COM 
53910591SSaurabh.Mishra@Sun.COM 	if (resched)
54010591SSaurabh.Mishra@Sun.COM 		mac_tx_update(bfe->bfe_machdl);
5419865SSaurabh.Mishra@Sun.COM }
5429865SSaurabh.Mishra@Sun.COM 
5439865SSaurabh.Mishra@Sun.COM /*
5449865SSaurabh.Mishra@Sun.COM  * Starts PHY layer.
5459865SSaurabh.Mishra@Sun.COM  */
5469865SSaurabh.Mishra@Sun.COM static int
5479865SSaurabh.Mishra@Sun.COM bfe_startup_phy(bfe_t *bfe)
5489865SSaurabh.Mishra@Sun.COM {
5499865SSaurabh.Mishra@Sun.COM 	uint16_t bmsr, bmcr, anar;
5509865SSaurabh.Mishra@Sun.COM 	int	prog, s;
5519865SSaurabh.Mishra@Sun.COM 	int phyid1, phyid2;
5529865SSaurabh.Mishra@Sun.COM 
5539865SSaurabh.Mishra@Sun.COM 	if (bfe_probe_phy(bfe) == BFE_FAILURE) {
5549865SSaurabh.Mishra@Sun.COM 		bfe->bfe_phy_state = BFE_PHY_NOTFOUND;
5559865SSaurabh.Mishra@Sun.COM 		return (BFE_FAILURE);
5569865SSaurabh.Mishra@Sun.COM 	}
5579865SSaurabh.Mishra@Sun.COM 
5589865SSaurabh.Mishra@Sun.COM 	(void) bfe_reset_phy(bfe);
5599865SSaurabh.Mishra@Sun.COM 
5609865SSaurabh.Mishra@Sun.COM 	phyid1 = bfe_read_phy(bfe, MII_PHYIDH);
5619865SSaurabh.Mishra@Sun.COM 	phyid2 = bfe_read_phy(bfe, MII_PHYIDL);
5629865SSaurabh.Mishra@Sun.COM 	bfe->bfe_phy_id = (phyid1 << 16) | phyid2;
5639865SSaurabh.Mishra@Sun.COM 
5649865SSaurabh.Mishra@Sun.COM 	bmsr = bfe_read_phy(bfe, MII_STATUS);
5659865SSaurabh.Mishra@Sun.COM 	anar = bfe_read_phy(bfe, MII_AN_ADVERT);
5669865SSaurabh.Mishra@Sun.COM 
5679865SSaurabh.Mishra@Sun.COM again:
5689865SSaurabh.Mishra@Sun.COM 	anar &= ~(MII_ABILITY_100BASE_T4 |
5699865SSaurabh.Mishra@Sun.COM 	    MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
5709865SSaurabh.Mishra@Sun.COM 	    MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
5719865SSaurabh.Mishra@Sun.COM 
5729865SSaurabh.Mishra@Sun.COM 	/*
5739865SSaurabh.Mishra@Sun.COM 	 * Supported hardware modes are in bmsr.
5749865SSaurabh.Mishra@Sun.COM 	 */
5759865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.bmsr = bmsr;
5769865SSaurabh.Mishra@Sun.COM 
5779865SSaurabh.Mishra@Sun.COM 	/*
5789865SSaurabh.Mishra@Sun.COM 	 * Assume no capabilities are supported in the hardware.
5799865SSaurabh.Mishra@Sun.COM 	 */
5809865SSaurabh.Mishra@Sun.COM 	bfe->bfe_cap_aneg = bfe->bfe_cap_100T4 =
5819865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_cap_100fdx = bfe->bfe_cap_100hdx =
5829865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_cap_10fdx = bfe->bfe_cap_10hdx = 0;
5839865SSaurabh.Mishra@Sun.COM 
5849865SSaurabh.Mishra@Sun.COM 	/*
5859865SSaurabh.Mishra@Sun.COM 	 * Assume property is set.
5869865SSaurabh.Mishra@Sun.COM 	 */
5879865SSaurabh.Mishra@Sun.COM 	s = 1;
5889865SSaurabh.Mishra@Sun.COM 	if (!(bfe->bfe_chip_action & BFE_ACTION_RESTART_SETPROP)) {
5899865SSaurabh.Mishra@Sun.COM 		/*
5909865SSaurabh.Mishra@Sun.COM 		 * Property is not set which means bfe_mac_setprop()
5919865SSaurabh.Mishra@Sun.COM 		 * is not called on us.
5929865SSaurabh.Mishra@Sun.COM 		 */
5939865SSaurabh.Mishra@Sun.COM 		s = 0;
5949865SSaurabh.Mishra@Sun.COM 	}
5959865SSaurabh.Mishra@Sun.COM 
5969865SSaurabh.Mishra@Sun.COM 	bmcr = prog = 0;
5979865SSaurabh.Mishra@Sun.COM 
5989865SSaurabh.Mishra@Sun.COM 	if (bmsr & MII_STATUS_100_BASEX_FD) {
5999865SSaurabh.Mishra@Sun.COM 		bfe->bfe_cap_100fdx = 1;
6009865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6019865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_100BASE_TX_FD;
6029865SSaurabh.Mishra@Sun.COM 			bfe->bfe_adv_100fdx = 1;
6039865SSaurabh.Mishra@Sun.COM 			prog++;
6049865SSaurabh.Mishra@Sun.COM 		} else if (bfe->bfe_adv_100fdx) {
6059865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_100BASE_TX_FD;
6069865SSaurabh.Mishra@Sun.COM 			prog++;
6079865SSaurabh.Mishra@Sun.COM 		}
6089865SSaurabh.Mishra@Sun.COM 	}
6099865SSaurabh.Mishra@Sun.COM 
6109865SSaurabh.Mishra@Sun.COM 	if (bmsr & MII_STATUS_100_BASE_T4) {
6119865SSaurabh.Mishra@Sun.COM 		bfe->bfe_cap_100T4 = 1;
6129865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6139865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_100BASE_T4;
6149865SSaurabh.Mishra@Sun.COM 			bfe->bfe_adv_100T4 = 1;
6159865SSaurabh.Mishra@Sun.COM 			prog++;
6169865SSaurabh.Mishra@Sun.COM 		} else if (bfe->bfe_adv_100T4) {
6179865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_100BASE_T4;
6189865SSaurabh.Mishra@Sun.COM 			prog++;
6199865SSaurabh.Mishra@Sun.COM 		}
6209865SSaurabh.Mishra@Sun.COM 	}
6219865SSaurabh.Mishra@Sun.COM 
6229865SSaurabh.Mishra@Sun.COM 	if (bmsr & MII_STATUS_100_BASEX) {
6239865SSaurabh.Mishra@Sun.COM 		bfe->bfe_cap_100hdx = 1;
6249865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6259865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_100BASE_TX;
6269865SSaurabh.Mishra@Sun.COM 			bfe->bfe_adv_100hdx = 1;
6279865SSaurabh.Mishra@Sun.COM 			prog++;
6289865SSaurabh.Mishra@Sun.COM 		} else if (bfe->bfe_adv_100hdx) {
6299865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_100BASE_TX;
6309865SSaurabh.Mishra@Sun.COM 			prog++;
6319865SSaurabh.Mishra@Sun.COM 		}
6329865SSaurabh.Mishra@Sun.COM 	}
6339865SSaurabh.Mishra@Sun.COM 
6349865SSaurabh.Mishra@Sun.COM 	if (bmsr & MII_STATUS_10_FD) {
6359865SSaurabh.Mishra@Sun.COM 		bfe->bfe_cap_10fdx = 1;
6369865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6379865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_10BASE_T_FD;
6389865SSaurabh.Mishra@Sun.COM 			bfe->bfe_adv_10fdx = 1;
6399865SSaurabh.Mishra@Sun.COM 			prog++;
6409865SSaurabh.Mishra@Sun.COM 		} else if (bfe->bfe_adv_10fdx) {
6419865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_10BASE_T_FD;
6429865SSaurabh.Mishra@Sun.COM 			prog++;
6439865SSaurabh.Mishra@Sun.COM 		}
6449865SSaurabh.Mishra@Sun.COM 	}
6459865SSaurabh.Mishra@Sun.COM 
6469865SSaurabh.Mishra@Sun.COM 	if (bmsr & MII_STATUS_10) {
6479865SSaurabh.Mishra@Sun.COM 		bfe->bfe_cap_10hdx = 1;
6489865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6499865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_10BASE_T;
6509865SSaurabh.Mishra@Sun.COM 			bfe->bfe_adv_10hdx = 1;
6519865SSaurabh.Mishra@Sun.COM 			prog++;
6529865SSaurabh.Mishra@Sun.COM 		} else if (bfe->bfe_adv_10hdx) {
6539865SSaurabh.Mishra@Sun.COM 			anar |= MII_ABILITY_10BASE_T;
6549865SSaurabh.Mishra@Sun.COM 			prog++;
6559865SSaurabh.Mishra@Sun.COM 		}
6569865SSaurabh.Mishra@Sun.COM 	}
6579865SSaurabh.Mishra@Sun.COM 
6589865SSaurabh.Mishra@Sun.COM 	if (bmsr & MII_STATUS_CANAUTONEG) {
6599865SSaurabh.Mishra@Sun.COM 		bfe->bfe_cap_aneg = 1;
6609865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6619865SSaurabh.Mishra@Sun.COM 			bfe->bfe_adv_aneg = 1;
6629865SSaurabh.Mishra@Sun.COM 		}
6639865SSaurabh.Mishra@Sun.COM 	}
6649865SSaurabh.Mishra@Sun.COM 
6659865SSaurabh.Mishra@Sun.COM 	if (prog == 0) {
6669865SSaurabh.Mishra@Sun.COM 		if (s == 0) {
6679865SSaurabh.Mishra@Sun.COM 			bfe_error(bfe->bfe_dip,
6689865SSaurabh.Mishra@Sun.COM 			    "No valid link mode selected. Powering down PHY");
6699865SSaurabh.Mishra@Sun.COM 			bfe_stop_phy(bfe);
6709865SSaurabh.Mishra@Sun.COM 			bfe_report_link(bfe);
6719865SSaurabh.Mishra@Sun.COM 			return (BFE_FAILURE);
6729865SSaurabh.Mishra@Sun.COM 		}
6739865SSaurabh.Mishra@Sun.COM 
6749865SSaurabh.Mishra@Sun.COM 		/*
6759865SSaurabh.Mishra@Sun.COM 		 * If property is set then user would have goofed up. So we
6769865SSaurabh.Mishra@Sun.COM 		 * go back to default properties.
6779865SSaurabh.Mishra@Sun.COM 		 */
6789865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_SETPROP;
6799865SSaurabh.Mishra@Sun.COM 		goto again;
6809865SSaurabh.Mishra@Sun.COM 	}
6819865SSaurabh.Mishra@Sun.COM 
6829865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_adv_aneg && (bmsr & MII_STATUS_CANAUTONEG)) {
6839865SSaurabh.Mishra@Sun.COM 		bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
6849865SSaurabh.Mishra@Sun.COM 	} else {
6859865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_adv_100fdx)
6869865SSaurabh.Mishra@Sun.COM 			bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
6879865SSaurabh.Mishra@Sun.COM 		else if (bfe->bfe_adv_100hdx)
6889865SSaurabh.Mishra@Sun.COM 			bmcr = MII_CONTROL_100MB;
6899865SSaurabh.Mishra@Sun.COM 		else if (bfe->bfe_adv_10fdx)
6909865SSaurabh.Mishra@Sun.COM 			bmcr = MII_CONTROL_FDUPLEX;
6919865SSaurabh.Mishra@Sun.COM 		else
6929865SSaurabh.Mishra@Sun.COM 			bmcr = 0;		/* 10HDX */
6939865SSaurabh.Mishra@Sun.COM 	}
6949865SSaurabh.Mishra@Sun.COM 
6959865SSaurabh.Mishra@Sun.COM 	if (prog)
6969865SSaurabh.Mishra@Sun.COM 		bfe_write_phy(bfe, MII_AN_ADVERT, anar);
6979865SSaurabh.Mishra@Sun.COM 
6989865SSaurabh.Mishra@Sun.COM 	if (bmcr)
6999865SSaurabh.Mishra@Sun.COM 		bfe_write_phy(bfe, MII_CONTROL, bmcr);
7009865SSaurabh.Mishra@Sun.COM 
7019865SSaurabh.Mishra@Sun.COM 	bfe->bfe_mii_anar = anar;
7029865SSaurabh.Mishra@Sun.COM 	bfe->bfe_mii_bmcr = bmcr;
7039865SSaurabh.Mishra@Sun.COM 	bfe->bfe_phy_state = BFE_PHY_STARTED;
7049865SSaurabh.Mishra@Sun.COM 
7059865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_periodic_id == NULL) {
7069865SSaurabh.Mishra@Sun.COM 		bfe->bfe_periodic_id = ddi_periodic_add(bfe_timeout,
7079865SSaurabh.Mishra@Sun.COM 		    (void *)bfe, BFE_TIMEOUT_INTERVAL, DDI_IPL_0);
7089865SSaurabh.Mishra@Sun.COM 
7099865SSaurabh.Mishra@Sun.COM 		DTRACE_PROBE1(first__timeout, int, bfe->bfe_unit);
7109865SSaurabh.Mishra@Sun.COM 	}
7119865SSaurabh.Mishra@Sun.COM 
7129865SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE4(phy_started, int, bfe->bfe_unit,
7139865SSaurabh.Mishra@Sun.COM 	    int, bmsr, int, bmcr, int, anar);
7149865SSaurabh.Mishra@Sun.COM 
7159865SSaurabh.Mishra@Sun.COM 	return (BFE_SUCCESS);
7169865SSaurabh.Mishra@Sun.COM }
7179865SSaurabh.Mishra@Sun.COM 
7189865SSaurabh.Mishra@Sun.COM /*
7199865SSaurabh.Mishra@Sun.COM  * Reports link status back to MAC Layer.
7209865SSaurabh.Mishra@Sun.COM  */
7219865SSaurabh.Mishra@Sun.COM static void
7229865SSaurabh.Mishra@Sun.COM bfe_report_link(bfe_t *bfe)
7239865SSaurabh.Mishra@Sun.COM {
7249865SSaurabh.Mishra@Sun.COM 	mac_link_update(bfe->bfe_machdl, bfe->bfe_chip.link);
7259865SSaurabh.Mishra@Sun.COM }
7269865SSaurabh.Mishra@Sun.COM 
7279865SSaurabh.Mishra@Sun.COM /*
7289865SSaurabh.Mishra@Sun.COM  * Reads PHY/MII registers and get the link status for us.
7299865SSaurabh.Mishra@Sun.COM  */
7309865SSaurabh.Mishra@Sun.COM static int
7319865SSaurabh.Mishra@Sun.COM bfe_check_link(bfe_t *bfe)
7329865SSaurabh.Mishra@Sun.COM {
7339865SSaurabh.Mishra@Sun.COM 	uint16_t bmsr, bmcr, anar, anlpar;
7349865SSaurabh.Mishra@Sun.COM 	int speed, duplex, link;
7359865SSaurabh.Mishra@Sun.COM 
7369865SSaurabh.Mishra@Sun.COM 	speed = bfe->bfe_chip.speed;
7379865SSaurabh.Mishra@Sun.COM 	duplex = bfe->bfe_chip.duplex;
7389865SSaurabh.Mishra@Sun.COM 	link = bfe->bfe_chip.link;
7399865SSaurabh.Mishra@Sun.COM 
7409865SSaurabh.Mishra@Sun.COM 	bmsr = bfe_read_phy(bfe, MII_STATUS);
7419865SSaurabh.Mishra@Sun.COM 	bfe->bfe_mii_bmsr = bmsr;
7429865SSaurabh.Mishra@Sun.COM 
7439865SSaurabh.Mishra@Sun.COM 	bmcr = bfe_read_phy(bfe, MII_CONTROL);
7449865SSaurabh.Mishra@Sun.COM 
7459865SSaurabh.Mishra@Sun.COM 	anar = bfe_read_phy(bfe, MII_AN_ADVERT);
7469865SSaurabh.Mishra@Sun.COM 	bfe->bfe_mii_anar = anar;
7479865SSaurabh.Mishra@Sun.COM 
7489865SSaurabh.Mishra@Sun.COM 	anlpar = bfe_read_phy(bfe, MII_AN_LPABLE);
7499865SSaurabh.Mishra@Sun.COM 	bfe->bfe_mii_anlpar = anlpar;
7509865SSaurabh.Mishra@Sun.COM 
7519865SSaurabh.Mishra@Sun.COM 	bfe->bfe_mii_exp = bfe_read_phy(bfe, MII_AN_EXPANSION);
7529865SSaurabh.Mishra@Sun.COM 
7539865SSaurabh.Mishra@Sun.COM 	/*
7549865SSaurabh.Mishra@Sun.COM 	 * If exp register is not present in PHY.
7559865SSaurabh.Mishra@Sun.COM 	 */
7569865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_mii_exp == 0xffff) {
7579865SSaurabh.Mishra@Sun.COM 		bfe->bfe_mii_exp = 0;
7589865SSaurabh.Mishra@Sun.COM 	}
7599865SSaurabh.Mishra@Sun.COM 
7609865SSaurabh.Mishra@Sun.COM 	if ((bmsr & MII_STATUS_LINKUP) == 0) {
7619865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.link = LINK_STATE_DOWN;
7629865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 0;
7639865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
7649865SSaurabh.Mishra@Sun.COM 		goto done;
7659865SSaurabh.Mishra@Sun.COM 	}
7669865SSaurabh.Mishra@Sun.COM 
7679865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.link = LINK_STATE_UP;
7689865SSaurabh.Mishra@Sun.COM 
7699865SSaurabh.Mishra@Sun.COM 	if (!(bmcr & MII_CONTROL_ANE)) {
7709865SSaurabh.Mishra@Sun.COM 		/* Forced mode */
7719865SSaurabh.Mishra@Sun.COM 		if (bmcr & MII_CONTROL_100MB)
7729865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip.speed = 100000000;
7739865SSaurabh.Mishra@Sun.COM 		else
7749865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip.speed = 10000000;
7759865SSaurabh.Mishra@Sun.COM 
7769865SSaurabh.Mishra@Sun.COM 		if (bmcr & MII_CONTROL_FDUPLEX)
7779865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
7789865SSaurabh.Mishra@Sun.COM 		else
7799865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
7809865SSaurabh.Mishra@Sun.COM 
7819865SSaurabh.Mishra@Sun.COM 	} else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
7829865SSaurabh.Mishra@Sun.COM 	    (!(bmsr & MII_STATUS_ANDONE))) {
7839865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 0;
7849865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
7859865SSaurabh.Mishra@Sun.COM 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
7869865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 100000000;
7879865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
7889865SSaurabh.Mishra@Sun.COM 	} else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
7899865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 100000000;
7909865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
7919865SSaurabh.Mishra@Sun.COM 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
7929865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 100000000;
7939865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
7949865SSaurabh.Mishra@Sun.COM 	} else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
7959865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 10000000;
7969865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
7979865SSaurabh.Mishra@Sun.COM 	} else if (anar & anlpar & MII_ABILITY_10BASE_T) {
7989865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 10000000;
7999865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
8009865SSaurabh.Mishra@Sun.COM 	} else {
8019865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.speed = 0;
8029865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
8039865SSaurabh.Mishra@Sun.COM 	}
8049865SSaurabh.Mishra@Sun.COM 
8059865SSaurabh.Mishra@Sun.COM done:
8069865SSaurabh.Mishra@Sun.COM 	/*
8079865SSaurabh.Mishra@Sun.COM 	 * If speed or link status or duplex mode changed then report to
8089865SSaurabh.Mishra@Sun.COM 	 * MAC layer which is done by the caller.
8099865SSaurabh.Mishra@Sun.COM 	 */
8109865SSaurabh.Mishra@Sun.COM 	if (speed != bfe->bfe_chip.speed ||
8119865SSaurabh.Mishra@Sun.COM 	    duplex != bfe->bfe_chip.duplex ||
8129865SSaurabh.Mishra@Sun.COM 	    link != bfe->bfe_chip.link) {
8139865SSaurabh.Mishra@Sun.COM 		return (1);
8149865SSaurabh.Mishra@Sun.COM 	}
8159865SSaurabh.Mishra@Sun.COM 
8169865SSaurabh.Mishra@Sun.COM 	return (0);
8179865SSaurabh.Mishra@Sun.COM }
8189865SSaurabh.Mishra@Sun.COM 
8199865SSaurabh.Mishra@Sun.COM static void
8209865SSaurabh.Mishra@Sun.COM bfe_cam_write(bfe_t *bfe, uchar_t *d, int index)
8219865SSaurabh.Mishra@Sun.COM {
8229865SSaurabh.Mishra@Sun.COM 	uint32_t v;
8239865SSaurabh.Mishra@Sun.COM 
8249865SSaurabh.Mishra@Sun.COM 	v = ((uint32_t)d[2] << 24);
8259865SSaurabh.Mishra@Sun.COM 	v |= ((uint32_t)d[3] << 16);
8269865SSaurabh.Mishra@Sun.COM 	v |= ((uint32_t)d[4] << 8);
8279865SSaurabh.Mishra@Sun.COM 	v |= (uint32_t)d[5];
8289865SSaurabh.Mishra@Sun.COM 
8299865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_CAM_DATA_LO, v);
8309865SSaurabh.Mishra@Sun.COM 	v = (BFE_CAM_HI_VALID |
8319865SSaurabh.Mishra@Sun.COM 	    (((uint32_t)d[0]) << 8) |
8329865SSaurabh.Mishra@Sun.COM 	    (((uint32_t)d[1])));
8339865SSaurabh.Mishra@Sun.COM 
8349865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_CAM_DATA_HI, v);
8359865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_CAM_CTRL, (BFE_CAM_WRITE |
8369865SSaurabh.Mishra@Sun.COM 	    ((uint32_t)index << BFE_CAM_INDEX_SHIFT)));
8379865SSaurabh.Mishra@Sun.COM 	(void) bfe_wait_bit(bfe, BFE_CAM_CTRL, BFE_CAM_BUSY, 10, 1);
8389865SSaurabh.Mishra@Sun.COM }
8399865SSaurabh.Mishra@Sun.COM 
8409865SSaurabh.Mishra@Sun.COM /*
8419865SSaurabh.Mishra@Sun.COM  * Chip related functions (halt, reset, start).
8429865SSaurabh.Mishra@Sun.COM  */
8439865SSaurabh.Mishra@Sun.COM static void
8449865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe_t *bfe)
8459865SSaurabh.Mishra@Sun.COM {
8469865SSaurabh.Mishra@Sun.COM 	/*
8479865SSaurabh.Mishra@Sun.COM 	 * Disables interrupts.
8489865SSaurabh.Mishra@Sun.COM 	 */
8499865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_INTR_MASK, 0);
8509865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_INTR_MASK);
8519865SSaurabh.Mishra@Sun.COM 
8529865SSaurabh.Mishra@Sun.COM 	OUTL(bfe,  BFE_ENET_CTRL, BFE_ENET_DISABLE);
8539865SSaurabh.Mishra@Sun.COM 
8549865SSaurabh.Mishra@Sun.COM 	/*
8559865SSaurabh.Mishra@Sun.COM 	 * Wait until TX and RX finish their job.
8569865SSaurabh.Mishra@Sun.COM 	 */
8579865SSaurabh.Mishra@Sun.COM 	(void) bfe_wait_bit(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE, 20, 1);
8589865SSaurabh.Mishra@Sun.COM 
8599865SSaurabh.Mishra@Sun.COM 	/*
8609865SSaurabh.Mishra@Sun.COM 	 * Disables DMA engine.
8619865SSaurabh.Mishra@Sun.COM 	 */
8629865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMARX_CTRL, 0);
8639865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMATX_CTRL, 0);
8649865SSaurabh.Mishra@Sun.COM 
8659865SSaurabh.Mishra@Sun.COM 	drv_usecwait(10);
8669865SSaurabh.Mishra@Sun.COM 
8679865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_HALT;
8689865SSaurabh.Mishra@Sun.COM }
8699865SSaurabh.Mishra@Sun.COM 
8709865SSaurabh.Mishra@Sun.COM static void
8719865SSaurabh.Mishra@Sun.COM bfe_chip_restart(bfe_t *bfe)
8729865SSaurabh.Mishra@Sun.COM {
8739865SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit,
8749865SSaurabh.Mishra@Sun.COM 	    int, bfe->bfe_chip_action);
8759865SSaurabh.Mishra@Sun.COM 
8769865SSaurabh.Mishra@Sun.COM 	/*
8779865SSaurabh.Mishra@Sun.COM 	 * Halt chip and PHY.
8789865SSaurabh.Mishra@Sun.COM 	 */
8799865SSaurabh.Mishra@Sun.COM 	bfe_chip_halt(bfe);
8809865SSaurabh.Mishra@Sun.COM 	bfe_stop_phy(bfe);
8819865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_STOPPED;
8829865SSaurabh.Mishra@Sun.COM 
8839865SSaurabh.Mishra@Sun.COM 	/*
8849865SSaurabh.Mishra@Sun.COM 	 * Init variables.
8859865SSaurabh.Mishra@Sun.COM 	 */
8869865SSaurabh.Mishra@Sun.COM 	bfe_init_vars(bfe);
8879865SSaurabh.Mishra@Sun.COM 
8889865SSaurabh.Mishra@Sun.COM 	/*
8899865SSaurabh.Mishra@Sun.COM 	 * Reset chip and start PHY.
8909865SSaurabh.Mishra@Sun.COM 	 */
8919865SSaurabh.Mishra@Sun.COM 	bfe_chip_reset(bfe);
8929865SSaurabh.Mishra@Sun.COM 
8939865SSaurabh.Mishra@Sun.COM 	/*
8949865SSaurabh.Mishra@Sun.COM 	 * DMA descriptor rings.
8959865SSaurabh.Mishra@Sun.COM 	 */
8969865SSaurabh.Mishra@Sun.COM 	bfe_tx_desc_init(&bfe->bfe_tx_ring);
8979865SSaurabh.Mishra@Sun.COM 	bfe_rx_desc_init(&bfe->bfe_rx_ring);
8989865SSaurabh.Mishra@Sun.COM 
8999865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_ACTIVE;
9009865SSaurabh.Mishra@Sun.COM 	bfe_set_rx_mode(bfe);
9019865SSaurabh.Mishra@Sun.COM 	bfe_enable_chip_intrs(bfe);
9029865SSaurabh.Mishra@Sun.COM }
9039865SSaurabh.Mishra@Sun.COM 
9049865SSaurabh.Mishra@Sun.COM /*
9059865SSaurabh.Mishra@Sun.COM  * Disables core by stopping the clock.
9069865SSaurabh.Mishra@Sun.COM  */
9079865SSaurabh.Mishra@Sun.COM static void
9089865SSaurabh.Mishra@Sun.COM bfe_core_disable(bfe_t *bfe)
9099865SSaurabh.Mishra@Sun.COM {
9109865SSaurabh.Mishra@Sun.COM 	if ((INL(bfe, BFE_SBTMSLOW) & BFE_RESET))
9119865SSaurabh.Mishra@Sun.COM 		return;
9129865SSaurabh.Mishra@Sun.COM 
9139865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK));
9149865SSaurabh.Mishra@Sun.COM 	(void) bfe_wait_bit(bfe, BFE_SBTMSLOW, BFE_REJECT, 100, 0);
9159865SSaurabh.Mishra@Sun.COM 	(void) bfe_wait_bit(bfe, BFE_SBTMSHIGH, BFE_BUSY, 100, 1);
9169865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | BFE_RESET));
9179865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_SBTMSLOW);
9189865SSaurabh.Mishra@Sun.COM 	drv_usecwait(10);
9199865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET));
9209865SSaurabh.Mishra@Sun.COM 	drv_usecwait(10);
9219865SSaurabh.Mishra@Sun.COM }
9229865SSaurabh.Mishra@Sun.COM 
9239865SSaurabh.Mishra@Sun.COM /*
9249865SSaurabh.Mishra@Sun.COM  * Resets core.
9259865SSaurabh.Mishra@Sun.COM  */
9269865SSaurabh.Mishra@Sun.COM static void
9279865SSaurabh.Mishra@Sun.COM bfe_core_reset(bfe_t *bfe)
9289865SSaurabh.Mishra@Sun.COM {
9299865SSaurabh.Mishra@Sun.COM 	uint32_t val;
9309865SSaurabh.Mishra@Sun.COM 
9319865SSaurabh.Mishra@Sun.COM 	/*
9329865SSaurabh.Mishra@Sun.COM 	 * First disable the core.
9339865SSaurabh.Mishra@Sun.COM 	 */
9349865SSaurabh.Mishra@Sun.COM 	bfe_core_disable(bfe);
9359865SSaurabh.Mishra@Sun.COM 
9369865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
9379865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_SBTMSLOW);
9389865SSaurabh.Mishra@Sun.COM 	drv_usecwait(1);
9399865SSaurabh.Mishra@Sun.COM 
9409865SSaurabh.Mishra@Sun.COM 	if (INL(bfe, BFE_SBTMSHIGH) & BFE_SERR)
9419865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_SBTMSHIGH, 0);
9429865SSaurabh.Mishra@Sun.COM 
9439865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_SBIMSTATE);
9449865SSaurabh.Mishra@Sun.COM 	if (val & (BFE_IBE | BFE_TO))
9459865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO));
9469865SSaurabh.Mishra@Sun.COM 
9479865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
9489865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_SBTMSLOW);
9499865SSaurabh.Mishra@Sun.COM 	drv_usecwait(1);
9509865SSaurabh.Mishra@Sun.COM 
9519865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBTMSLOW, BFE_CLOCK);
9529865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_SBTMSLOW);
9539865SSaurabh.Mishra@Sun.COM 	drv_usecwait(1);
9549865SSaurabh.Mishra@Sun.COM }
9559865SSaurabh.Mishra@Sun.COM 
9569865SSaurabh.Mishra@Sun.COM static void
9579865SSaurabh.Mishra@Sun.COM bfe_setup_config(bfe_t *bfe, uint32_t cores)
9589865SSaurabh.Mishra@Sun.COM {
9599865SSaurabh.Mishra@Sun.COM 	uint32_t bar_orig, val;
9609865SSaurabh.Mishra@Sun.COM 
9619865SSaurabh.Mishra@Sun.COM 	/*
9629865SSaurabh.Mishra@Sun.COM 	 * Change bar0 window to map sbtopci registers.
9639865SSaurabh.Mishra@Sun.COM 	 */
9649865SSaurabh.Mishra@Sun.COM 	bar_orig = pci_config_get32(bfe->bfe_conf_handle, BFE_BAR0_WIN);
9659865SSaurabh.Mishra@Sun.COM 	pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, BFE_REG_PCI);
9669865SSaurabh.Mishra@Sun.COM 
9679865SSaurabh.Mishra@Sun.COM 	/* Just read it and don't do anything */
9689865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_SBIDHIGH) & BFE_IDH_CORE;
9699865SSaurabh.Mishra@Sun.COM 
9709865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_SBINTVEC);
9719865SSaurabh.Mishra@Sun.COM 	val |= cores;
9729865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SBINTVEC, val);
9739865SSaurabh.Mishra@Sun.COM 
9749865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_SSB_PCI_TRANS_2);
9759865SSaurabh.Mishra@Sun.COM 	val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST;
9769865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_SSB_PCI_TRANS_2, val);
9779865SSaurabh.Mishra@Sun.COM 
9789865SSaurabh.Mishra@Sun.COM 	/*
9799865SSaurabh.Mishra@Sun.COM 	 * Restore bar0 window mapping.
9809865SSaurabh.Mishra@Sun.COM 	 */
9819865SSaurabh.Mishra@Sun.COM 	pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, bar_orig);
9829865SSaurabh.Mishra@Sun.COM }
9839865SSaurabh.Mishra@Sun.COM 
9849865SSaurabh.Mishra@Sun.COM /*
9859865SSaurabh.Mishra@Sun.COM  * Resets chip and starts PHY.
9869865SSaurabh.Mishra@Sun.COM  */
9879865SSaurabh.Mishra@Sun.COM static void
9889865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe_t *bfe)
9899865SSaurabh.Mishra@Sun.COM {
9909865SSaurabh.Mishra@Sun.COM 	uint32_t val;
9919865SSaurabh.Mishra@Sun.COM 
9929865SSaurabh.Mishra@Sun.COM 	/* Set the interrupt vector for the enet core */
9939865SSaurabh.Mishra@Sun.COM 	bfe_setup_config(bfe, BFE_INTVEC_ENET0);
9949865SSaurabh.Mishra@Sun.COM 
9959865SSaurabh.Mishra@Sun.COM 	/* check if core is up */
9969865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_SBTMSLOW) &
9979865SSaurabh.Mishra@Sun.COM 	    (BFE_RESET | BFE_REJECT | BFE_CLOCK);
9989865SSaurabh.Mishra@Sun.COM 
9999865SSaurabh.Mishra@Sun.COM 	if (val == BFE_CLOCK) {
10009865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_RCV_LAZY, 0);
10019865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE);
10029865SSaurabh.Mishra@Sun.COM 		(void) bfe_wait_bit(bfe, BFE_ENET_CTRL,
10039865SSaurabh.Mishra@Sun.COM 		    BFE_ENET_DISABLE, 10, 1);
10049865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_DMATX_CTRL, 0);
10059865SSaurabh.Mishra@Sun.COM 		FLUSH(bfe, BFE_DMARX_STAT);
10069865SSaurabh.Mishra@Sun.COM 		drv_usecwait(20000);	/* 20 milli seconds */
10079865SSaurabh.Mishra@Sun.COM 		if (INL(bfe, BFE_DMARX_STAT) & BFE_STAT_EMASK) {
10089865SSaurabh.Mishra@Sun.COM 			(void) bfe_wait_bit(bfe, BFE_DMARX_STAT, BFE_STAT_SIDLE,
10099865SSaurabh.Mishra@Sun.COM 			    10, 0);
10109865SSaurabh.Mishra@Sun.COM 		}
10119865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_DMARX_CTRL, 0);
10129865SSaurabh.Mishra@Sun.COM 	}
10139865SSaurabh.Mishra@Sun.COM 
10149865SSaurabh.Mishra@Sun.COM 	bfe_core_reset(bfe);
10159865SSaurabh.Mishra@Sun.COM 	bfe_clear_stats(bfe);
10169865SSaurabh.Mishra@Sun.COM 
10179865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_MDIO_CTRL, 0x8d);
10189865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_DEVCTRL);
10199865SSaurabh.Mishra@Sun.COM 	if (!(val & BFE_IPP))
10209865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_EPSEL);
10219865SSaurabh.Mishra@Sun.COM 	else if (INL(bfe, BFE_DEVCTRL & BFE_EPR)) {
10229865SSaurabh.Mishra@Sun.COM 		OUTL_AND(bfe, BFE_DEVCTRL, ~BFE_EPR);
10239865SSaurabh.Mishra@Sun.COM 		drv_usecwait(20000);    /* 20 milli seconds */
10249865SSaurabh.Mishra@Sun.COM 	}
10259865SSaurabh.Mishra@Sun.COM 
10269865SSaurabh.Mishra@Sun.COM 	OUTL_OR(bfe, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED);
10279865SSaurabh.Mishra@Sun.COM 
10289865SSaurabh.Mishra@Sun.COM 	OUTL_AND(bfe, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN);
10299865SSaurabh.Mishra@Sun.COM 
10309865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) &
10319865SSaurabh.Mishra@Sun.COM 	    BFE_LAZY_FC_MASK));
10329865SSaurabh.Mishra@Sun.COM 
10339865SSaurabh.Mishra@Sun.COM 	OUTL_OR(bfe, BFE_RCV_LAZY, 0);
10349865SSaurabh.Mishra@Sun.COM 
10359865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_RXMAXLEN, bfe->bfe_rx_ring.r_buf_len);
10369865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_TXMAXLEN, bfe->bfe_tx_ring.r_buf_len);
10379865SSaurabh.Mishra@Sun.COM 
10389865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_TX_WMARK, 56);
10399865SSaurabh.Mishra@Sun.COM 
10409865SSaurabh.Mishra@Sun.COM 	/* Program DMA channels */
10419865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE);
10429865SSaurabh.Mishra@Sun.COM 
10439865SSaurabh.Mishra@Sun.COM 	/*
10449865SSaurabh.Mishra@Sun.COM 	 * DMA addresses need to be added to BFE_PCI_DMA
10459865SSaurabh.Mishra@Sun.COM 	 */
10469865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMATX_ADDR,
10479865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_tx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA);
10489865SSaurabh.Mishra@Sun.COM 
10499865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT)
10509865SSaurabh.Mishra@Sun.COM 	    | BFE_RX_CTRL_ENABLE);
10519865SSaurabh.Mishra@Sun.COM 
10529865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMARX_ADDR,
10539865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_rx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA);
10549865SSaurabh.Mishra@Sun.COM 
10559865SSaurabh.Mishra@Sun.COM 	(void) bfe_startup_phy(bfe);
10569865SSaurabh.Mishra@Sun.COM 
10579865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_INITIALIZED;
10589865SSaurabh.Mishra@Sun.COM }
10599865SSaurabh.Mishra@Sun.COM 
10609865SSaurabh.Mishra@Sun.COM /*
10619865SSaurabh.Mishra@Sun.COM  * It enables interrupts. Should be the last step while starting chip.
10629865SSaurabh.Mishra@Sun.COM  */
10639865SSaurabh.Mishra@Sun.COM static void
10649865SSaurabh.Mishra@Sun.COM bfe_enable_chip_intrs(bfe_t *bfe)
10659865SSaurabh.Mishra@Sun.COM {
10669865SSaurabh.Mishra@Sun.COM 	/* Enable the chip and core */
10679865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_ENABLE);
10689865SSaurabh.Mishra@Sun.COM 
10699865SSaurabh.Mishra@Sun.COM 	/* Enable interrupts */
10709865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_INTR_MASK, BFE_IMASK_DEF);
10719865SSaurabh.Mishra@Sun.COM }
10729865SSaurabh.Mishra@Sun.COM 
10739865SSaurabh.Mishra@Sun.COM /*
10749865SSaurabh.Mishra@Sun.COM  * Common code to take care of setting RX side mode (filter).
10759865SSaurabh.Mishra@Sun.COM  */
10769865SSaurabh.Mishra@Sun.COM static void
10779865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe_t *bfe)
10789865SSaurabh.Mishra@Sun.COM {
10799865SSaurabh.Mishra@Sun.COM 	uint32_t val;
10809865SSaurabh.Mishra@Sun.COM 	int i;
10819865SSaurabh.Mishra@Sun.COM 	ether_addr_t mac[ETHERADDRL] = {0, 0, 0, 0, 0, 0};
10829865SSaurabh.Mishra@Sun.COM 
10839865SSaurabh.Mishra@Sun.COM 	/*
10849865SSaurabh.Mishra@Sun.COM 	 * We don't touch RX filter if we were asked to suspend. It's fine
10859865SSaurabh.Mishra@Sun.COM 	 * if chip is not active (no interface is plumbed on us).
10869865SSaurabh.Mishra@Sun.COM 	 */
10879865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED)
10889865SSaurabh.Mishra@Sun.COM 		return;
10899865SSaurabh.Mishra@Sun.COM 
10909865SSaurabh.Mishra@Sun.COM 	val = INL(bfe, BFE_RXCONF);
10919865SSaurabh.Mishra@Sun.COM 
10929865SSaurabh.Mishra@Sun.COM 	val &= ~BFE_RXCONF_PROMISC;
10939865SSaurabh.Mishra@Sun.COM 	val &= ~BFE_RXCONF_DBCAST;
10949865SSaurabh.Mishra@Sun.COM 
10959865SSaurabh.Mishra@Sun.COM 	if ((bfe->bfe_chip_mode & BFE_RX_MODE_ENABLE) == 0) {
10969865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_CAM_CTRL, 0);
10979865SSaurabh.Mishra@Sun.COM 		FLUSH(bfe, BFE_CAM_CTRL);
10989865SSaurabh.Mishra@Sun.COM 	} else if (bfe->bfe_chip_mode & BFE_RX_MODE_PROMISC) {
10999865SSaurabh.Mishra@Sun.COM 		val |= BFE_RXCONF_PROMISC;
11009865SSaurabh.Mishra@Sun.COM 		val &= ~BFE_RXCONF_DBCAST;
11019865SSaurabh.Mishra@Sun.COM 	} else {
11029865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
11039865SSaurabh.Mishra@Sun.COM 			/* Flush everything */
11049865SSaurabh.Mishra@Sun.COM 			OUTL(bfe, BFE_RXCONF, val |
11059865SSaurabh.Mishra@Sun.COM 			    BFE_RXCONF_PROMISC | BFE_RXCONF_ALLMULTI);
11069865SSaurabh.Mishra@Sun.COM 			FLUSH(bfe, BFE_RXCONF);
11079865SSaurabh.Mishra@Sun.COM 		}
11089865SSaurabh.Mishra@Sun.COM 
11099865SSaurabh.Mishra@Sun.COM 		/* Disable CAM */
11109865SSaurabh.Mishra@Sun.COM 		OUTL(bfe, BFE_CAM_CTRL, 0);
11119865SSaurabh.Mishra@Sun.COM 		FLUSH(bfe, BFE_CAM_CTRL);
11129865SSaurabh.Mishra@Sun.COM 
11139865SSaurabh.Mishra@Sun.COM 		/*
11149865SSaurabh.Mishra@Sun.COM 		 * We receive all multicast packets.
11159865SSaurabh.Mishra@Sun.COM 		 */
11169865SSaurabh.Mishra@Sun.COM 		val |= BFE_RXCONF_ALLMULTI;
11179865SSaurabh.Mishra@Sun.COM 
11189865SSaurabh.Mishra@Sun.COM 		for (i = 0; i < BFE_MAX_MULTICAST_TABLE - 1; i++) {
11199865SSaurabh.Mishra@Sun.COM 			bfe_cam_write(bfe, (uchar_t *)mac, i);
11209865SSaurabh.Mishra@Sun.COM 		}
11219865SSaurabh.Mishra@Sun.COM 
11229865SSaurabh.Mishra@Sun.COM 		bfe_cam_write(bfe, bfe->bfe_ether_addr, i);
11239865SSaurabh.Mishra@Sun.COM 
11249865SSaurabh.Mishra@Sun.COM 		/* Enable CAM */
11259865SSaurabh.Mishra@Sun.COM 		OUTL_OR(bfe, BFE_CAM_CTRL, BFE_CAM_ENABLE);
11269865SSaurabh.Mishra@Sun.COM 		FLUSH(bfe, BFE_CAM_CTRL);
11279865SSaurabh.Mishra@Sun.COM 	}
11289865SSaurabh.Mishra@Sun.COM 
11299865SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE2(rx__mode__filter, int, bfe->bfe_unit,
11309865SSaurabh.Mishra@Sun.COM 	    int, val);
11319865SSaurabh.Mishra@Sun.COM 
11329865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_RXCONF, val);
11339865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_RXCONF);
11349865SSaurabh.Mishra@Sun.COM }
11359865SSaurabh.Mishra@Sun.COM 
11369865SSaurabh.Mishra@Sun.COM /*
11379865SSaurabh.Mishra@Sun.COM  * Reset various variable values to initial state.
11389865SSaurabh.Mishra@Sun.COM  */
11399865SSaurabh.Mishra@Sun.COM static void
11409865SSaurabh.Mishra@Sun.COM bfe_init_vars(bfe_t *bfe)
11419865SSaurabh.Mishra@Sun.COM {
11429865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_mode = BFE_RX_MODE_ENABLE;
11439865SSaurabh.Mishra@Sun.COM 
11449865SSaurabh.Mishra@Sun.COM 	/* Initial assumption */
11459865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.link = LINK_STATE_UNKNOWN;
11469865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.speed = 0;
11479865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
11489865SSaurabh.Mishra@Sun.COM 
11499865SSaurabh.Mishra@Sun.COM 	bfe->bfe_periodic_id = NULL;
11509865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_UNINITIALIZED;
11519865SSaurabh.Mishra@Sun.COM 
11529865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_stall_time = 0;
11539865SSaurabh.Mishra@Sun.COM }
11549865SSaurabh.Mishra@Sun.COM 
11559865SSaurabh.Mishra@Sun.COM /*
11569865SSaurabh.Mishra@Sun.COM  * Initializes TX side descriptor entries (bfe_desc_t). Each descriptor entry
11579865SSaurabh.Mishra@Sun.COM  * has control (desc_ctl) and address (desc_addr) member.
11589865SSaurabh.Mishra@Sun.COM  */
11599865SSaurabh.Mishra@Sun.COM static void
11609865SSaurabh.Mishra@Sun.COM bfe_tx_desc_init(bfe_ring_t *r)
11619865SSaurabh.Mishra@Sun.COM {
11629865SSaurabh.Mishra@Sun.COM 	int i;
11639865SSaurabh.Mishra@Sun.COM 	uint32_t v;
11649865SSaurabh.Mishra@Sun.COM 
11659865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < r->r_ndesc; i++) {
11669865SSaurabh.Mishra@Sun.COM 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl),
11679865SSaurabh.Mishra@Sun.COM 		    (r->r_buf_dma[i].len & BFE_DESC_LEN));
11689865SSaurabh.Mishra@Sun.COM 
11699865SSaurabh.Mishra@Sun.COM 		/*
11709865SSaurabh.Mishra@Sun.COM 		 * DMA addresses need to be added to BFE_PCI_DMA
11719865SSaurabh.Mishra@Sun.COM 		 */
11729865SSaurabh.Mishra@Sun.COM 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr),
11739865SSaurabh.Mishra@Sun.COM 		    (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA));
11749865SSaurabh.Mishra@Sun.COM 	}
11759865SSaurabh.Mishra@Sun.COM 
11769865SSaurabh.Mishra@Sun.COM 	v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl));
11779865SSaurabh.Mishra@Sun.COM 	PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl),
11789865SSaurabh.Mishra@Sun.COM 	    v | BFE_DESC_EOT);
11799865SSaurabh.Mishra@Sun.COM 
11809865SSaurabh.Mishra@Sun.COM 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
11819865SSaurabh.Mishra@Sun.COM 
11829865SSaurabh.Mishra@Sun.COM 	r->r_curr_desc = 0;
11839865SSaurabh.Mishra@Sun.COM 	r->r_avail_desc = TX_NUM_DESC;
11849865SSaurabh.Mishra@Sun.COM 	r->r_cons_desc = 0;
11859865SSaurabh.Mishra@Sun.COM }
11869865SSaurabh.Mishra@Sun.COM 
11879865SSaurabh.Mishra@Sun.COM /*
11889865SSaurabh.Mishra@Sun.COM  * Initializes RX side descriptor entries (bfe_desc_t). Each descriptor entry
11899865SSaurabh.Mishra@Sun.COM  * has control (desc_ctl) and address (desc_addr) member.
11909865SSaurabh.Mishra@Sun.COM  */
11919865SSaurabh.Mishra@Sun.COM static void
11929865SSaurabh.Mishra@Sun.COM bfe_rx_desc_init(bfe_ring_t *r)
11939865SSaurabh.Mishra@Sun.COM {
11949865SSaurabh.Mishra@Sun.COM 	int i;
11959865SSaurabh.Mishra@Sun.COM 	uint32_t v;
11969865SSaurabh.Mishra@Sun.COM 
11979865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < r->r_ndesc; i++) {
11989865SSaurabh.Mishra@Sun.COM 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl),
11999865SSaurabh.Mishra@Sun.COM 		    (r->r_buf_dma[i].len& BFE_DESC_LEN));
12009865SSaurabh.Mishra@Sun.COM 
12019865SSaurabh.Mishra@Sun.COM 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr),
12029865SSaurabh.Mishra@Sun.COM 		    (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA));
12039865SSaurabh.Mishra@Sun.COM 
12049865SSaurabh.Mishra@Sun.COM 		/* Initialize rx header (len, flags) */
12059865SSaurabh.Mishra@Sun.COM 		bzero(r->r_buf_dma[i].addr, sizeof (bfe_rx_header_t));
12069865SSaurabh.Mishra@Sun.COM 
12079865SSaurabh.Mishra@Sun.COM 		(void) SYNC_BUF(r, i, 0, sizeof (bfe_rx_header_t),
12089865SSaurabh.Mishra@Sun.COM 		    DDI_DMA_SYNC_FORDEV);
12099865SSaurabh.Mishra@Sun.COM 	}
12109865SSaurabh.Mishra@Sun.COM 
12119865SSaurabh.Mishra@Sun.COM 	v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl));
12129865SSaurabh.Mishra@Sun.COM 	PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl),
12139865SSaurabh.Mishra@Sun.COM 	    v | BFE_DESC_EOT);
12149865SSaurabh.Mishra@Sun.COM 
12159865SSaurabh.Mishra@Sun.COM 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
12169865SSaurabh.Mishra@Sun.COM 
12179865SSaurabh.Mishra@Sun.COM 	/* TAIL of RX Descriptor */
12189865SSaurabh.Mishra@Sun.COM 	OUTL(r->r_bfe, BFE_DMARX_PTR, ((i) * sizeof (bfe_desc_t)));
12199865SSaurabh.Mishra@Sun.COM 
12209865SSaurabh.Mishra@Sun.COM 	r->r_curr_desc = 0;
12219865SSaurabh.Mishra@Sun.COM 	r->r_avail_desc = RX_NUM_DESC;
12229865SSaurabh.Mishra@Sun.COM }
12239865SSaurabh.Mishra@Sun.COM 
12249865SSaurabh.Mishra@Sun.COM static int
12259865SSaurabh.Mishra@Sun.COM bfe_chip_start(bfe_t *bfe)
12269865SSaurabh.Mishra@Sun.COM {
122710591SSaurabh.Mishra@Sun.COM 	ASSERT_ALL_LOCKS(bfe);
12289865SSaurabh.Mishra@Sun.COM 
12299865SSaurabh.Mishra@Sun.COM 	/*
12309865SSaurabh.Mishra@Sun.COM 	 * Stop the chip first & then Reset the chip. At last enable interrupts.
12319865SSaurabh.Mishra@Sun.COM 	 */
12329865SSaurabh.Mishra@Sun.COM 	bfe_chip_halt(bfe);
12339865SSaurabh.Mishra@Sun.COM 	bfe_stop_phy(bfe);
12349865SSaurabh.Mishra@Sun.COM 
12359865SSaurabh.Mishra@Sun.COM 	/*
12369865SSaurabh.Mishra@Sun.COM 	 * Reset chip and start PHY.
12379865SSaurabh.Mishra@Sun.COM 	 */
12389865SSaurabh.Mishra@Sun.COM 	bfe_chip_reset(bfe);
12399865SSaurabh.Mishra@Sun.COM 
12409865SSaurabh.Mishra@Sun.COM 	/*
12419865SSaurabh.Mishra@Sun.COM 	 * Initailize Descriptor Rings.
12429865SSaurabh.Mishra@Sun.COM 	 */
12439865SSaurabh.Mishra@Sun.COM 	bfe_tx_desc_init(&bfe->bfe_tx_ring);
12449865SSaurabh.Mishra@Sun.COM 	bfe_rx_desc_init(&bfe->bfe_rx_ring);
12459865SSaurabh.Mishra@Sun.COM 
12469865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_ACTIVE;
12479865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_mode |= BFE_RX_MODE_ENABLE;
12489865SSaurabh.Mishra@Sun.COM 	bfe_set_rx_mode(bfe);
12499865SSaurabh.Mishra@Sun.COM 	bfe_enable_chip_intrs(bfe);
12509865SSaurabh.Mishra@Sun.COM 
12519865SSaurabh.Mishra@Sun.COM 	/* Check link, speed and duplex mode */
12529865SSaurabh.Mishra@Sun.COM 	(void) bfe_check_link(bfe);
12539865SSaurabh.Mishra@Sun.COM 
12549865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
12559865SSaurabh.Mishra@Sun.COM }
12569865SSaurabh.Mishra@Sun.COM 
12579865SSaurabh.Mishra@Sun.COM 
12589865SSaurabh.Mishra@Sun.COM /*
12599865SSaurabh.Mishra@Sun.COM  * Clear chip statistics.
12609865SSaurabh.Mishra@Sun.COM  */
12619865SSaurabh.Mishra@Sun.COM static void
12629865SSaurabh.Mishra@Sun.COM bfe_clear_stats(bfe_t *bfe)
12639865SSaurabh.Mishra@Sun.COM {
12649865SSaurabh.Mishra@Sun.COM 	ulong_t r;
12659865SSaurabh.Mishra@Sun.COM 
12669865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ);
12679865SSaurabh.Mishra@Sun.COM 
12689865SSaurabh.Mishra@Sun.COM 	/*
12699865SSaurabh.Mishra@Sun.COM 	 * Stat registers are cleared by reading.
12709865SSaurabh.Mishra@Sun.COM 	 */
12719865SSaurabh.Mishra@Sun.COM 	for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4)
12729865SSaurabh.Mishra@Sun.COM 		(void) INL(bfe, r);
12739865SSaurabh.Mishra@Sun.COM 
12749865SSaurabh.Mishra@Sun.COM 	for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4)
12759865SSaurabh.Mishra@Sun.COM 		(void) INL(bfe, r);
12769865SSaurabh.Mishra@Sun.COM }
12779865SSaurabh.Mishra@Sun.COM 
12789865SSaurabh.Mishra@Sun.COM /*
12799865SSaurabh.Mishra@Sun.COM  * Collect chip statistics.
12809865SSaurabh.Mishra@Sun.COM  */
12819865SSaurabh.Mishra@Sun.COM static void
12829865SSaurabh.Mishra@Sun.COM bfe_gather_stats(bfe_t *bfe)
12839865SSaurabh.Mishra@Sun.COM {
12849865SSaurabh.Mishra@Sun.COM 	ulong_t r;
12859865SSaurabh.Mishra@Sun.COM 	uint32_t *v;
12869865SSaurabh.Mishra@Sun.COM 	uint32_t txerr = 0, rxerr = 0, coll = 0;
12879865SSaurabh.Mishra@Sun.COM 
12889865SSaurabh.Mishra@Sun.COM 	v = &bfe->bfe_hw_stats.tx_good_octets;
12899865SSaurabh.Mishra@Sun.COM 	for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4) {
12909865SSaurabh.Mishra@Sun.COM 		*v += INL(bfe, r);
12919865SSaurabh.Mishra@Sun.COM 		v++;
12929865SSaurabh.Mishra@Sun.COM 	}
12939865SSaurabh.Mishra@Sun.COM 
12949865SSaurabh.Mishra@Sun.COM 	v = &bfe->bfe_hw_stats.rx_good_octets;
12959865SSaurabh.Mishra@Sun.COM 	for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4) {
12969865SSaurabh.Mishra@Sun.COM 		*v += INL(bfe, r);
12979865SSaurabh.Mishra@Sun.COM 		v++;
12989865SSaurabh.Mishra@Sun.COM 	}
12999865SSaurabh.Mishra@Sun.COM 
13009865SSaurabh.Mishra@Sun.COM 	/*
13019865SSaurabh.Mishra@Sun.COM 	 * TX :
13029865SSaurabh.Mishra@Sun.COM 	 * -------
13039865SSaurabh.Mishra@Sun.COM 	 * tx_good_octets, tx_good_pkts, tx_octets
13049865SSaurabh.Mishra@Sun.COM 	 * tx_pkts, tx_broadcast_pkts, tx_multicast_pkts
13059865SSaurabh.Mishra@Sun.COM 	 * tx_len_64, tx_len_65_to_127, tx_len_128_to_255
13069865SSaurabh.Mishra@Sun.COM 	 * tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max
13079865SSaurabh.Mishra@Sun.COM 	 * tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts
13089865SSaurabh.Mishra@Sun.COM 	 * tx_underruns, tx_total_cols, tx_single_cols
13099865SSaurabh.Mishra@Sun.COM 	 * tx_multiple_cols, tx_excessive_cols, tx_late_cols
13109865SSaurabh.Mishra@Sun.COM 	 * tx_defered, tx_carrier_lost, tx_pause_pkts
13119865SSaurabh.Mishra@Sun.COM 	 *
13129865SSaurabh.Mishra@Sun.COM 	 * RX :
13139865SSaurabh.Mishra@Sun.COM 	 * -------
13149865SSaurabh.Mishra@Sun.COM 	 * rx_good_octets, rx_good_pkts, rx_octets
13159865SSaurabh.Mishra@Sun.COM 	 * rx_pkts, rx_broadcast_pkts, rx_multicast_pkts
13169865SSaurabh.Mishra@Sun.COM 	 * rx_len_64, rx_len_65_to_127, rx_len_128_to_255
13179865SSaurabh.Mishra@Sun.COM 	 * rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max
13189865SSaurabh.Mishra@Sun.COM 	 * rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts
13199865SSaurabh.Mishra@Sun.COM 	 * rx_missed_pkts, rx_crc_align_errs, rx_undersize
13209865SSaurabh.Mishra@Sun.COM 	 * rx_crc_errs, rx_align_errs, rx_symbol_errs
13219865SSaurabh.Mishra@Sun.COM 	 * rx_pause_pkts, rx_nonpause_pkts
13229865SSaurabh.Mishra@Sun.COM 	 */
13239865SSaurabh.Mishra@Sun.COM 
13249865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_carrier_errors =
13259865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.tx_carrier_lost;
13269865SSaurabh.Mishra@Sun.COM 
13279865SSaurabh.Mishra@Sun.COM 	/* txerr += bfe->bfe_hw_stats.tx_carrier_lost; */
13289865SSaurabh.Mishra@Sun.COM 
13299865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_ex_collisions =
13309865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.tx_excessive_cols;
13319865SSaurabh.Mishra@Sun.COM 	txerr += bfe->bfe_hw_stats.tx_excessive_cols;
13329865SSaurabh.Mishra@Sun.COM 	coll += bfe->bfe_hw_stats.tx_excessive_cols;
13339865SSaurabh.Mishra@Sun.COM 
13349865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_fcs_errors =
13359865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.rx_crc_errs;
13369865SSaurabh.Mishra@Sun.COM 	rxerr += bfe->bfe_hw_stats.rx_crc_errs;
13379865SSaurabh.Mishra@Sun.COM 
13389865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_first_collisions =
13399865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.tx_single_cols;
13409865SSaurabh.Mishra@Sun.COM 	coll += bfe->bfe_hw_stats.tx_single_cols;
13419865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_multi_collisions =
13429865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.tx_multiple_cols;
13439865SSaurabh.Mishra@Sun.COM 	coll += bfe->bfe_hw_stats.tx_multiple_cols;
13449865SSaurabh.Mishra@Sun.COM 
13459865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_toolong_errors =
13469865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.rx_oversize_pkts;
13479865SSaurabh.Mishra@Sun.COM 	rxerr += bfe->bfe_hw_stats.rx_oversize_pkts;
13489865SSaurabh.Mishra@Sun.COM 
13499865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_tooshort_errors =
13509865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.rx_undersize;
13519865SSaurabh.Mishra@Sun.COM 	rxerr += bfe->bfe_hw_stats.rx_undersize;
13529865SSaurabh.Mishra@Sun.COM 
13539865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_tx_late_collisions +=
13549865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.tx_late_cols;
13559865SSaurabh.Mishra@Sun.COM 
13569865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_defer_xmts +=
13579865SSaurabh.Mishra@Sun.COM 	    bfe->bfe_hw_stats.tx_defered;
13589865SSaurabh.Mishra@Sun.COM 
13599865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_macrcv_errors += rxerr;
13609865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.ether_stat_macxmt_errors += txerr;
13619865SSaurabh.Mishra@Sun.COM 
13629865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.collisions += coll;
13639865SSaurabh.Mishra@Sun.COM }
13649865SSaurabh.Mishra@Sun.COM 
13659865SSaurabh.Mishra@Sun.COM /*
13669865SSaurabh.Mishra@Sun.COM  * Gets the state for dladm command and all.
13679865SSaurabh.Mishra@Sun.COM  */
13689865SSaurabh.Mishra@Sun.COM int
13699865SSaurabh.Mishra@Sun.COM bfe_mac_getstat(void *arg, uint_t stat, uint64_t *val)
13709865SSaurabh.Mishra@Sun.COM {
13719865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
13729865SSaurabh.Mishra@Sun.COM 	uint64_t	v;
13739865SSaurabh.Mishra@Sun.COM 	int err = 0;
13749865SSaurabh.Mishra@Sun.COM 
13759865SSaurabh.Mishra@Sun.COM 	rw_enter(&bfe->bfe_rwlock, RW_READER);
13769865SSaurabh.Mishra@Sun.COM 
13779865SSaurabh.Mishra@Sun.COM 
13789865SSaurabh.Mishra@Sun.COM 	switch (stat) {
13799865SSaurabh.Mishra@Sun.COM 	default:
13809865SSaurabh.Mishra@Sun.COM 		err = ENOTSUP;
13819865SSaurabh.Mishra@Sun.COM 		break;
13829865SSaurabh.Mishra@Sun.COM 
13839865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IFSPEED:
13849865SSaurabh.Mishra@Sun.COM 		/*
13859865SSaurabh.Mishra@Sun.COM 		 * MAC layer will ask for IFSPEED first and hence we
13869865SSaurabh.Mishra@Sun.COM 		 * collect it only once.
13879865SSaurabh.Mishra@Sun.COM 		 */
13889865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
13899865SSaurabh.Mishra@Sun.COM 			/*
13909865SSaurabh.Mishra@Sun.COM 			 * Update stats from the hardware.
13919865SSaurabh.Mishra@Sun.COM 			 */
13929865SSaurabh.Mishra@Sun.COM 			bfe_gather_stats(bfe);
13939865SSaurabh.Mishra@Sun.COM 		}
13949865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_chip.speed;
13959865SSaurabh.Mishra@Sun.COM 		break;
13969865SSaurabh.Mishra@Sun.COM 
13979865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_100T4:
13989865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_adv_100T4;
13999865SSaurabh.Mishra@Sun.COM 		break;
14009865SSaurabh.Mishra@Sun.COM 
14019865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_100FDX:
14029865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX_FD) != 0;
14039865SSaurabh.Mishra@Sun.COM 		break;
14049865SSaurabh.Mishra@Sun.COM 
14059865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_100HDX:
14069865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX) != 0;
14079865SSaurabh.Mishra@Sun.COM 		break;
14089865SSaurabh.Mishra@Sun.COM 
14099865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_10FDX:
14109865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T_FD) != 0;
14119865SSaurabh.Mishra@Sun.COM 		break;
14129865SSaurabh.Mishra@Sun.COM 
14139865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_10HDX:
14149865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T) != 0;
14159865SSaurabh.Mishra@Sun.COM 		break;
14169865SSaurabh.Mishra@Sun.COM 
14179865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
14189865SSaurabh.Mishra@Sun.COM 		v = 0;
14199865SSaurabh.Mishra@Sun.COM 		break;
14209865SSaurabh.Mishra@Sun.COM 
14219865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_AUTONEG:
14229865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_adv_aneg;
14239865SSaurabh.Mishra@Sun.COM 		break;
14249865SSaurabh.Mishra@Sun.COM 
14259865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_CAP_PAUSE:
14269865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anar & MII_ABILITY_PAUSE) != 0;
14279865SSaurabh.Mishra@Sun.COM 		break;
14289865SSaurabh.Mishra@Sun.COM 
14299865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ADV_REMFAULT:
14309865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anar & MII_AN_ADVERT_REMFAULT) != 0;
14319865SSaurabh.Mishra@Sun.COM 		break;
14329865SSaurabh.Mishra@Sun.COM 
14339865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_ALIGN_ERRORS:
14349865SSaurabh.Mishra@Sun.COM 		/* MIB */
14359865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_align_errors;
14369865SSaurabh.Mishra@Sun.COM 		break;
14379865SSaurabh.Mishra@Sun.COM 
14389865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_100T4:
14399865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASE_T4) != 0;
14409865SSaurabh.Mishra@Sun.COM 		break;
14419865SSaurabh.Mishra@Sun.COM 
14429865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_100FDX:
14439865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX_FD) != 0;
14449865SSaurabh.Mishra@Sun.COM 		break;
14459865SSaurabh.Mishra@Sun.COM 
14469865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_100HDX:
14479865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX) != 0;
14489865SSaurabh.Mishra@Sun.COM 		break;
14499865SSaurabh.Mishra@Sun.COM 
14509865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_10FDX:
14519865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmsr & MII_STATUS_10_FD) != 0;
14529865SSaurabh.Mishra@Sun.COM 		break;
14539865SSaurabh.Mishra@Sun.COM 
14549865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_10HDX:
14559865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmsr & MII_STATUS_10) != 0;
14569865SSaurabh.Mishra@Sun.COM 		break;
14579865SSaurabh.Mishra@Sun.COM 
14589865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_ASMPAUSE:
14599865SSaurabh.Mishra@Sun.COM 		v = 0;
14609865SSaurabh.Mishra@Sun.COM 		break;
14619865SSaurabh.Mishra@Sun.COM 
14629865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_AUTONEG:
14639865SSaurabh.Mishra@Sun.COM 		v = ((bfe->bfe_mii_bmsr & MII_STATUS_CANAUTONEG) != 0);
14649865SSaurabh.Mishra@Sun.COM 		break;
14659865SSaurabh.Mishra@Sun.COM 
14669865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_PAUSE:
14679865SSaurabh.Mishra@Sun.COM 		v = 1;
14689865SSaurabh.Mishra@Sun.COM 		break;
14699865SSaurabh.Mishra@Sun.COM 
14709865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CAP_REMFAULT:
14719865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmsr & MII_STATUS_REMFAULT) != 0;
14729865SSaurabh.Mishra@Sun.COM 		break;
14739865SSaurabh.Mishra@Sun.COM 
14749865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_CARRIER_ERRORS:
14759865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_carrier_errors;
14769865SSaurabh.Mishra@Sun.COM 		break;
14779865SSaurabh.Mishra@Sun.COM 
14789865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_JABBER_ERRORS:
14799865SSaurabh.Mishra@Sun.COM 		err = ENOTSUP;
14809865SSaurabh.Mishra@Sun.COM 		break;
14819865SSaurabh.Mishra@Sun.COM 
14829865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_DEFER_XMTS:
14839865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_defer_xmts;
14849865SSaurabh.Mishra@Sun.COM 		break;
14859865SSaurabh.Mishra@Sun.COM 
14869865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_EX_COLLISIONS:
14879865SSaurabh.Mishra@Sun.COM 		/* MIB */
14889865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_ex_collisions;
14899865SSaurabh.Mishra@Sun.COM 		break;
14909865SSaurabh.Mishra@Sun.COM 
14919865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_FCS_ERRORS:
14929865SSaurabh.Mishra@Sun.COM 		/* MIB */
14939865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_fcs_errors;
14949865SSaurabh.Mishra@Sun.COM 		break;
14959865SSaurabh.Mishra@Sun.COM 
14969865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_FIRST_COLLISIONS:
14979865SSaurabh.Mishra@Sun.COM 		/* MIB */
14989865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_first_collisions;
14999865SSaurabh.Mishra@Sun.COM 		break;
15009865SSaurabh.Mishra@Sun.COM 
15019865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LINK_ASMPAUSE:
15029865SSaurabh.Mishra@Sun.COM 		v = 0;
15039865SSaurabh.Mishra@Sun.COM 		break;
15049865SSaurabh.Mishra@Sun.COM 
15059865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LINK_AUTONEG:
15069865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_bmcr & MII_CONTROL_ANE) != 0 &&
15079865SSaurabh.Mishra@Sun.COM 		    (bfe->bfe_mii_bmsr & MII_STATUS_ANDONE) != 0;
15089865SSaurabh.Mishra@Sun.COM 		break;
15099865SSaurabh.Mishra@Sun.COM 
15109865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LINK_DUPLEX:
15119865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_chip.duplex;
15129865SSaurabh.Mishra@Sun.COM 		break;
15139865SSaurabh.Mishra@Sun.COM 
15149865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_100T4:
15159865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_T4) != 0;
15169865SSaurabh.Mishra@Sun.COM 		break;
15179865SSaurabh.Mishra@Sun.COM 
15189865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_100FDX:
15199865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX_FD) != 0;
15209865SSaurabh.Mishra@Sun.COM 		break;
15219865SSaurabh.Mishra@Sun.COM 
15229865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_100HDX:
15239865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX) != 0;
15249865SSaurabh.Mishra@Sun.COM 		break;
15259865SSaurabh.Mishra@Sun.COM 
15269865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_10FDX:
15279865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T_FD) != 0;
15289865SSaurabh.Mishra@Sun.COM 		break;
15299865SSaurabh.Mishra@Sun.COM 
15309865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_10HDX:
15319865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T) != 0;
15329865SSaurabh.Mishra@Sun.COM 		break;
15339865SSaurabh.Mishra@Sun.COM 
15349865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_ASMPAUSE:
15359865SSaurabh.Mishra@Sun.COM 		v = 0;
15369865SSaurabh.Mishra@Sun.COM 		break;
15379865SSaurabh.Mishra@Sun.COM 
15389865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_AUTONEG:
15399865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_exp & MII_AN_EXP_LPCANAN) != 0;
15409865SSaurabh.Mishra@Sun.COM 		break;
15419865SSaurabh.Mishra@Sun.COM 
15429865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_CAP_PAUSE:
15439865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_PAUSE) != 0;
15449865SSaurabh.Mishra@Sun.COM 		break;
15459865SSaurabh.Mishra@Sun.COM 
15469865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_LP_REMFAULT:
15479865SSaurabh.Mishra@Sun.COM 		v = (bfe->bfe_mii_anlpar & MII_STATUS_REMFAULT) != 0;
15489865SSaurabh.Mishra@Sun.COM 		break;
15499865SSaurabh.Mishra@Sun.COM 
15509865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MACRCV_ERRORS:
15519865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_macrcv_errors;
15529865SSaurabh.Mishra@Sun.COM 		break;
15539865SSaurabh.Mishra@Sun.COM 
15549865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MACXMT_ERRORS:
15559865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_macxmt_errors;
15569865SSaurabh.Mishra@Sun.COM 		break;
15579865SSaurabh.Mishra@Sun.COM 
15589865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_MULTI_COLLISIONS:
15599865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_multi_collisions;
15609865SSaurabh.Mishra@Sun.COM 		break;
15619865SSaurabh.Mishra@Sun.COM 
15629865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_SQE_ERRORS:
15639865SSaurabh.Mishra@Sun.COM 		err = ENOTSUP;
15649865SSaurabh.Mishra@Sun.COM 		break;
15659865SSaurabh.Mishra@Sun.COM 
15669865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TOOLONG_ERRORS:
15679865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_toolong_errors;
15689865SSaurabh.Mishra@Sun.COM 		break;
15699865SSaurabh.Mishra@Sun.COM 
15709865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TOOSHORT_ERRORS:
15719865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_tooshort_errors;
15729865SSaurabh.Mishra@Sun.COM 		break;
15739865SSaurabh.Mishra@Sun.COM 
15749865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_TX_LATE_COLLISIONS:
15759865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_tx_late_collisions;
15769865SSaurabh.Mishra@Sun.COM 		break;
15779865SSaurabh.Mishra@Sun.COM 
15789865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_XCVR_ADDR:
15799865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_phy_addr;
15809865SSaurabh.Mishra@Sun.COM 		break;
15819865SSaurabh.Mishra@Sun.COM 
15829865SSaurabh.Mishra@Sun.COM 	case ETHER_STAT_XCVR_ID:
15839865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_phy_id;
15849865SSaurabh.Mishra@Sun.COM 		break;
15859865SSaurabh.Mishra@Sun.COM 
15869865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_BRDCSTRCV:
15879865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.brdcstrcv;
15889865SSaurabh.Mishra@Sun.COM 		break;
15899865SSaurabh.Mishra@Sun.COM 
15909865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_BRDCSTXMT:
15919865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.brdcstxmt;
15929865SSaurabh.Mishra@Sun.COM 		break;
15939865SSaurabh.Mishra@Sun.COM 
15949865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_MULTIXMT:
15959865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.multixmt;
15969865SSaurabh.Mishra@Sun.COM 		break;
15979865SSaurabh.Mishra@Sun.COM 
15989865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_COLLISIONS:
15999865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.collisions;
16009865SSaurabh.Mishra@Sun.COM 		break;
16019865SSaurabh.Mishra@Sun.COM 
16029865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IERRORS:
16039865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ierrors;
16049865SSaurabh.Mishra@Sun.COM 		break;
16059865SSaurabh.Mishra@Sun.COM 
16069865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_IPACKETS:
16079865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ipackets;
16089865SSaurabh.Mishra@Sun.COM 		break;
16099865SSaurabh.Mishra@Sun.COM 
16109865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_MULTIRCV:
16119865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.multircv;
16129865SSaurabh.Mishra@Sun.COM 		break;
16139865SSaurabh.Mishra@Sun.COM 
16149865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_NORCVBUF:
16159865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.norcvbuf;
16169865SSaurabh.Mishra@Sun.COM 		break;
16179865SSaurabh.Mishra@Sun.COM 
16189865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_NOXMTBUF:
16199865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.noxmtbuf;
16209865SSaurabh.Mishra@Sun.COM 		break;
16219865SSaurabh.Mishra@Sun.COM 
16229865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OBYTES:
16239865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.obytes;
16249865SSaurabh.Mishra@Sun.COM 		break;
16259865SSaurabh.Mishra@Sun.COM 
16269865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OERRORS:
16279865SSaurabh.Mishra@Sun.COM 		/* MIB */
16289865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.ether_stat_macxmt_errors;
16299865SSaurabh.Mishra@Sun.COM 		break;
16309865SSaurabh.Mishra@Sun.COM 
16319865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OPACKETS:
16329865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.opackets;
16339865SSaurabh.Mishra@Sun.COM 		break;
16349865SSaurabh.Mishra@Sun.COM 
16359865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_RBYTES:
16369865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.rbytes;
16379865SSaurabh.Mishra@Sun.COM 		break;
16389865SSaurabh.Mishra@Sun.COM 
16399865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_UNDERFLOWS:
16409865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.underflows;
16419865SSaurabh.Mishra@Sun.COM 		break;
16429865SSaurabh.Mishra@Sun.COM 
16439865SSaurabh.Mishra@Sun.COM 	case MAC_STAT_OVERFLOWS:
16449865SSaurabh.Mishra@Sun.COM 		v = bfe->bfe_stats.overflows;
16459865SSaurabh.Mishra@Sun.COM 		break;
16469865SSaurabh.Mishra@Sun.COM 	}
16479865SSaurabh.Mishra@Sun.COM 
16489865SSaurabh.Mishra@Sun.COM 	rw_exit(&bfe->bfe_rwlock);
16499865SSaurabh.Mishra@Sun.COM 
16509865SSaurabh.Mishra@Sun.COM 	*val = v;
16519865SSaurabh.Mishra@Sun.COM 	return (err);
16529865SSaurabh.Mishra@Sun.COM }
16539865SSaurabh.Mishra@Sun.COM 
16549865SSaurabh.Mishra@Sun.COM int
1655*11878SVenu.Iyer@Sun.COM bfe_mac_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1656*11878SVenu.Iyer@Sun.COM     void *val)
16579865SSaurabh.Mishra@Sun.COM {
16589865SSaurabh.Mishra@Sun.COM 	bfe_t		*bfe = (bfe_t *)arg;
16599865SSaurabh.Mishra@Sun.COM 	int		err = 0;
1660*11878SVenu.Iyer@Sun.COM 
16619865SSaurabh.Mishra@Sun.COM 	switch (num) {
16629865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_DUPLEX:
1663*11878SVenu.Iyer@Sun.COM 		ASSERT(sz >= sizeof (link_duplex_t));
1664*11878SVenu.Iyer@Sun.COM 		bcopy(&bfe->bfe_chip.duplex, val, sizeof (link_duplex_t));
16659865SSaurabh.Mishra@Sun.COM 		break;
16669865SSaurabh.Mishra@Sun.COM 
16679865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_SPEED:
1668*11878SVenu.Iyer@Sun.COM 		ASSERT(sz >= sizeof (uint64_t));
1669*11878SVenu.Iyer@Sun.COM 		bcopy(&bfe->bfe_chip.speed, val, sizeof (uint64_t));
16709865SSaurabh.Mishra@Sun.COM 		break;
16719865SSaurabh.Mishra@Sun.COM 
16729865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_AUTONEG:
1673*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_aneg;
16749865SSaurabh.Mishra@Sun.COM 		break;
16759865SSaurabh.Mishra@Sun.COM 
16769865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
1677*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_100fdx;
16789865SSaurabh.Mishra@Sun.COM 		break;
1679*11878SVenu.Iyer@Sun.COM 
16809865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
1681*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_100fdx;
16829865SSaurabh.Mishra@Sun.COM 		break;
16839865SSaurabh.Mishra@Sun.COM 
16849865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
1685*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_100hdx;
16869865SSaurabh.Mishra@Sun.COM 		break;
1687*11878SVenu.Iyer@Sun.COM 
16889865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
1689*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_100hdx;
16909865SSaurabh.Mishra@Sun.COM 		break;
16919865SSaurabh.Mishra@Sun.COM 
16929865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
1693*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_10fdx;
16949865SSaurabh.Mishra@Sun.COM 		break;
1695*11878SVenu.Iyer@Sun.COM 
16969865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
1697*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_10fdx;
16989865SSaurabh.Mishra@Sun.COM 		break;
16999865SSaurabh.Mishra@Sun.COM 
17009865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
1701*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_10hdx;
17029865SSaurabh.Mishra@Sun.COM 		break;
1703*11878SVenu.Iyer@Sun.COM 
17049865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
1705*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_10hdx;
17069865SSaurabh.Mishra@Sun.COM 		break;
17079865SSaurabh.Mishra@Sun.COM 
17089865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
1709*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_100T4;
17109865SSaurabh.Mishra@Sun.COM 		break;
1711*11878SVenu.Iyer@Sun.COM 
17129865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
1713*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = bfe->bfe_adv_100T4;
17149865SSaurabh.Mishra@Sun.COM 		break;
17159865SSaurabh.Mishra@Sun.COM 
17169865SSaurabh.Mishra@Sun.COM 	default:
17179865SSaurabh.Mishra@Sun.COM 		err = ENOTSUP;
17189865SSaurabh.Mishra@Sun.COM 	}
17199865SSaurabh.Mishra@Sun.COM 
17209865SSaurabh.Mishra@Sun.COM 	return (err);
17219865SSaurabh.Mishra@Sun.COM }
17229865SSaurabh.Mishra@Sun.COM 
1723*11878SVenu.Iyer@Sun.COM 
1724*11878SVenu.Iyer@Sun.COM static void
1725*11878SVenu.Iyer@Sun.COM bfe_mac_propinfo(void *arg, const char *name, mac_prop_id_t num,
1726*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t prh)
1727*11878SVenu.Iyer@Sun.COM {
1728*11878SVenu.Iyer@Sun.COM 	bfe_t		*bfe = (bfe_t *)arg;
1729*11878SVenu.Iyer@Sun.COM 
1730*11878SVenu.Iyer@Sun.COM 	switch (num) {
1731*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_DUPLEX:
1732*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_SPEED:
1733*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
1734*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
1735*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
1736*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
1737*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
1738*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1739*11878SVenu.Iyer@Sun.COM 		break;
1740*11878SVenu.Iyer@Sun.COM 
1741*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_AUTONEG:
1742*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_aneg);
1743*11878SVenu.Iyer@Sun.COM 		break;
1744*11878SVenu.Iyer@Sun.COM 
1745*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
1746*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100fdx);
1747*11878SVenu.Iyer@Sun.COM 		break;
1748*11878SVenu.Iyer@Sun.COM 
1749*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
1750*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100hdx);
1751*11878SVenu.Iyer@Sun.COM 		break;
1752*11878SVenu.Iyer@Sun.COM 
1753*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
1754*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10fdx);
1755*11878SVenu.Iyer@Sun.COM 		break;
1756*11878SVenu.Iyer@Sun.COM 
1757*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
1758*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10hdx);
1759*11878SVenu.Iyer@Sun.COM 		break;
1760*11878SVenu.Iyer@Sun.COM 
1761*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
1762*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100T4);
1763*11878SVenu.Iyer@Sun.COM 		break;
1764*11878SVenu.Iyer@Sun.COM 	}
1765*11878SVenu.Iyer@Sun.COM }
1766*11878SVenu.Iyer@Sun.COM 
1767*11878SVenu.Iyer@Sun.COM 
17689865SSaurabh.Mishra@Sun.COM /*ARGSUSED*/
17699865SSaurabh.Mishra@Sun.COM int
17709865SSaurabh.Mishra@Sun.COM bfe_mac_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
17719865SSaurabh.Mishra@Sun.COM     const void *val)
17729865SSaurabh.Mishra@Sun.COM {
17739865SSaurabh.Mishra@Sun.COM 	bfe_t		*bfe = (bfe_t *)arg;
17749865SSaurabh.Mishra@Sun.COM 	uint8_t		*advp;
17759865SSaurabh.Mishra@Sun.COM 	uint8_t		*capp;
17769865SSaurabh.Mishra@Sun.COM 	int 		r = 0;
17779865SSaurabh.Mishra@Sun.COM 
17789865SSaurabh.Mishra@Sun.COM 	switch (num) {
17799865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
17809865SSaurabh.Mishra@Sun.COM 		advp = &bfe->bfe_adv_100fdx;
17819865SSaurabh.Mishra@Sun.COM 		capp = &bfe->bfe_cap_100fdx;
17829865SSaurabh.Mishra@Sun.COM 		break;
17839865SSaurabh.Mishra@Sun.COM 
17849865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
17859865SSaurabh.Mishra@Sun.COM 		advp = &bfe->bfe_adv_100hdx;
17869865SSaurabh.Mishra@Sun.COM 		capp = &bfe->bfe_cap_100hdx;
17879865SSaurabh.Mishra@Sun.COM 		break;
17889865SSaurabh.Mishra@Sun.COM 
17899865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
17909865SSaurabh.Mishra@Sun.COM 		advp = &bfe->bfe_adv_10fdx;
17919865SSaurabh.Mishra@Sun.COM 		capp = &bfe->bfe_cap_10fdx;
17929865SSaurabh.Mishra@Sun.COM 		break;
17939865SSaurabh.Mishra@Sun.COM 
17949865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
17959865SSaurabh.Mishra@Sun.COM 		advp = &bfe->bfe_adv_10hdx;
17969865SSaurabh.Mishra@Sun.COM 		capp = &bfe->bfe_cap_10hdx;
17979865SSaurabh.Mishra@Sun.COM 		break;
17989865SSaurabh.Mishra@Sun.COM 
17999865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
18009865SSaurabh.Mishra@Sun.COM 		advp = &bfe->bfe_adv_100T4;
18019865SSaurabh.Mishra@Sun.COM 		capp = &bfe->bfe_cap_100T4;
18029865SSaurabh.Mishra@Sun.COM 		break;
18039865SSaurabh.Mishra@Sun.COM 
18049865SSaurabh.Mishra@Sun.COM 	case MAC_PROP_AUTONEG:
18059865SSaurabh.Mishra@Sun.COM 		advp = &bfe->bfe_adv_aneg;
18069865SSaurabh.Mishra@Sun.COM 		capp = &bfe->bfe_cap_aneg;
18079865SSaurabh.Mishra@Sun.COM 		break;
18089865SSaurabh.Mishra@Sun.COM 
18099865SSaurabh.Mishra@Sun.COM 	default:
18109865SSaurabh.Mishra@Sun.COM 		return (ENOTSUP);
18119865SSaurabh.Mishra@Sun.COM 	}
18129865SSaurabh.Mishra@Sun.COM 
18139865SSaurabh.Mishra@Sun.COM 	if (*capp == 0)
18149865SSaurabh.Mishra@Sun.COM 		return (ENOTSUP);
18159865SSaurabh.Mishra@Sun.COM 
18169865SSaurabh.Mishra@Sun.COM 	bfe_grab_locks(bfe);
18179865SSaurabh.Mishra@Sun.COM 
18189865SSaurabh.Mishra@Sun.COM 	if (*advp != *(const uint8_t *)val) {
18199865SSaurabh.Mishra@Sun.COM 		*advp = *(const uint8_t *)val;
18209865SSaurabh.Mishra@Sun.COM 
18219865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action = BFE_ACTION_RESTART_SETPROP;
18229865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
18239865SSaurabh.Mishra@Sun.COM 			/*
18249865SSaurabh.Mishra@Sun.COM 			 * We need to stop the timer before grabbing locks
18259865SSaurabh.Mishra@Sun.COM 			 * otherwise we can land-up in deadlock with untimeout.
18269865SSaurabh.Mishra@Sun.COM 			 */
18279865SSaurabh.Mishra@Sun.COM 			bfe_stop_timer(bfe);
18289865SSaurabh.Mishra@Sun.COM 
18299865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip_action |= BFE_ACTION_RESTART;
18309865SSaurabh.Mishra@Sun.COM 
18319865SSaurabh.Mishra@Sun.COM 			bfe_chip_restart(bfe);
18329865SSaurabh.Mishra@Sun.COM 
18339865SSaurabh.Mishra@Sun.COM 			/*
18349865SSaurabh.Mishra@Sun.COM 			 * We leave SETPROP because properties can be
18359865SSaurabh.Mishra@Sun.COM 			 * temporary.
18369865SSaurabh.Mishra@Sun.COM 			 */
18379865SSaurabh.Mishra@Sun.COM 			bfe->bfe_chip_action &= ~(BFE_ACTION_RESTART);
18389865SSaurabh.Mishra@Sun.COM 			r = 1;
18399865SSaurabh.Mishra@Sun.COM 		}
18409865SSaurabh.Mishra@Sun.COM 	}
18419865SSaurabh.Mishra@Sun.COM 
18429865SSaurabh.Mishra@Sun.COM 	bfe_release_locks(bfe);
18439865SSaurabh.Mishra@Sun.COM 
18449865SSaurabh.Mishra@Sun.COM 	/* kick-off a potential stopped downstream */
18459865SSaurabh.Mishra@Sun.COM 	if (r)
18469865SSaurabh.Mishra@Sun.COM 		mac_tx_update(bfe->bfe_machdl);
18479865SSaurabh.Mishra@Sun.COM 
18489865SSaurabh.Mishra@Sun.COM 	return (0);
18499865SSaurabh.Mishra@Sun.COM }
18509865SSaurabh.Mishra@Sun.COM 
18519865SSaurabh.Mishra@Sun.COM 
18529865SSaurabh.Mishra@Sun.COM int
18539865SSaurabh.Mishra@Sun.COM bfe_mac_set_ether_addr(void *arg, const uint8_t *ea)
18549865SSaurabh.Mishra@Sun.COM {
18559865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
18569865SSaurabh.Mishra@Sun.COM 
18579865SSaurabh.Mishra@Sun.COM 	bfe_grab_locks(bfe);
18589865SSaurabh.Mishra@Sun.COM 	bcopy(ea, bfe->bfe_ether_addr, ETHERADDRL);
18599865SSaurabh.Mishra@Sun.COM 	bfe_set_rx_mode(bfe);
18609865SSaurabh.Mishra@Sun.COM 	bfe_release_locks(bfe);
18619865SSaurabh.Mishra@Sun.COM 	return (0);
18629865SSaurabh.Mishra@Sun.COM }
18639865SSaurabh.Mishra@Sun.COM 
18649865SSaurabh.Mishra@Sun.COM int
18659865SSaurabh.Mishra@Sun.COM bfe_mac_start(void *arg)
18669865SSaurabh.Mishra@Sun.COM {
18679865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
18689865SSaurabh.Mishra@Sun.COM 
186910591SSaurabh.Mishra@Sun.COM 	bfe_grab_locks(bfe);
187010591SSaurabh.Mishra@Sun.COM 	if (bfe_chip_start(bfe) == DDI_FAILURE) {
187110591SSaurabh.Mishra@Sun.COM 		bfe_release_locks(bfe);
18729865SSaurabh.Mishra@Sun.COM 		return (EINVAL);
187310591SSaurabh.Mishra@Sun.COM 	}
187410591SSaurabh.Mishra@Sun.COM 
187510591SSaurabh.Mishra@Sun.COM 	bfe_release_locks(bfe);
187610591SSaurabh.Mishra@Sun.COM 
187710591SSaurabh.Mishra@Sun.COM 	mac_tx_update(bfe->bfe_machdl);
18789865SSaurabh.Mishra@Sun.COM 
18799865SSaurabh.Mishra@Sun.COM 	return (0);
18809865SSaurabh.Mishra@Sun.COM }
18819865SSaurabh.Mishra@Sun.COM 
18829865SSaurabh.Mishra@Sun.COM void
18839865SSaurabh.Mishra@Sun.COM bfe_mac_stop(void *arg)
18849865SSaurabh.Mishra@Sun.COM {
18859865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
18869865SSaurabh.Mishra@Sun.COM 
18879865SSaurabh.Mishra@Sun.COM 	/*
18889865SSaurabh.Mishra@Sun.COM 	 * We need to stop the timer before grabbing locks otherwise
18899865SSaurabh.Mishra@Sun.COM 	 * we can land-up in deadlock with untimeout.
18909865SSaurabh.Mishra@Sun.COM 	 */
18919865SSaurabh.Mishra@Sun.COM 	bfe_stop_timer(bfe);
18929865SSaurabh.Mishra@Sun.COM 
18939865SSaurabh.Mishra@Sun.COM 	bfe_grab_locks(bfe);
18949865SSaurabh.Mishra@Sun.COM 
18959865SSaurabh.Mishra@Sun.COM 	/*
18969865SSaurabh.Mishra@Sun.COM 	 * First halt the chip by disabling interrupts.
18979865SSaurabh.Mishra@Sun.COM 	 */
18989865SSaurabh.Mishra@Sun.COM 	bfe_chip_halt(bfe);
18999865SSaurabh.Mishra@Sun.COM 	bfe_stop_phy(bfe);
19009865SSaurabh.Mishra@Sun.COM 
19019865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_STOPPED;
19029865SSaurabh.Mishra@Sun.COM 
19039865SSaurabh.Mishra@Sun.COM 	/*
19049865SSaurabh.Mishra@Sun.COM 	 * This will leave the PHY running.
19059865SSaurabh.Mishra@Sun.COM 	 */
19069865SSaurabh.Mishra@Sun.COM 	bfe_chip_reset(bfe);
19079865SSaurabh.Mishra@Sun.COM 
19089865SSaurabh.Mishra@Sun.COM 	/*
19099865SSaurabh.Mishra@Sun.COM 	 * Disable RX register.
19109865SSaurabh.Mishra@Sun.COM 	 */
19119865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_mode &= ~BFE_RX_MODE_ENABLE;
19129865SSaurabh.Mishra@Sun.COM 	bfe_set_rx_mode(bfe);
19139865SSaurabh.Mishra@Sun.COM 
19149865SSaurabh.Mishra@Sun.COM 	bfe_release_locks(bfe);
19159865SSaurabh.Mishra@Sun.COM }
19169865SSaurabh.Mishra@Sun.COM 
19179865SSaurabh.Mishra@Sun.COM /*
19189865SSaurabh.Mishra@Sun.COM  * Send a packet down the wire.
19199865SSaurabh.Mishra@Sun.COM  */
19209865SSaurabh.Mishra@Sun.COM static int
19219865SSaurabh.Mishra@Sun.COM bfe_send_a_packet(bfe_t *bfe, mblk_t *mp)
19229865SSaurabh.Mishra@Sun.COM {
19239865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *r = &bfe->bfe_tx_ring;
19249865SSaurabh.Mishra@Sun.COM 	uint32_t cur = r->r_curr_desc;
19259865SSaurabh.Mishra@Sun.COM 	uint32_t next;
19269865SSaurabh.Mishra@Sun.COM 	size_t	pktlen = msgsize(mp);
19279865SSaurabh.Mishra@Sun.COM 	uchar_t *buf;
19289865SSaurabh.Mishra@Sun.COM 	uint32_t v;
19299865SSaurabh.Mishra@Sun.COM 
19309865SSaurabh.Mishra@Sun.COM 	ASSERT(MUTEX_HELD(&r->r_lock));
19319865SSaurabh.Mishra@Sun.COM 	ASSERT(mp != NULL);
19329865SSaurabh.Mishra@Sun.COM 
19339865SSaurabh.Mishra@Sun.COM 	if (pktlen > r->r_buf_len) {
19349865SSaurabh.Mishra@Sun.COM 		freemsg(mp);
19359865SSaurabh.Mishra@Sun.COM 		return (BFE_SUCCESS);
19369865SSaurabh.Mishra@Sun.COM 	}
19379865SSaurabh.Mishra@Sun.COM 
19389865SSaurabh.Mishra@Sun.COM 	/*
19399865SSaurabh.Mishra@Sun.COM 	 * There is a big reason why we don't check for '0'. It becomes easy
19409865SSaurabh.Mishra@Sun.COM 	 * for us to not roll over the ring since we are based on producer (tx)
19419865SSaurabh.Mishra@Sun.COM 	 * and consumer (reclaim by an interrupt) model. Especially when we
19429865SSaurabh.Mishra@Sun.COM 	 * run out of TX descriptor, chip will send a single interrupt and
19439865SSaurabh.Mishra@Sun.COM 	 * both producer and consumer counter will be same. So we keep a
19449865SSaurabh.Mishra@Sun.COM 	 * difference of 1 always.
19459865SSaurabh.Mishra@Sun.COM 	 */
19469865SSaurabh.Mishra@Sun.COM 	if (r->r_avail_desc <= 1) {
19479865SSaurabh.Mishra@Sun.COM 		bfe->bfe_stats.noxmtbuf++;
19489865SSaurabh.Mishra@Sun.COM 		bfe->bfe_tx_resched = 1;
19499865SSaurabh.Mishra@Sun.COM 		return (BFE_FAILURE);
19509865SSaurabh.Mishra@Sun.COM 	}
19519865SSaurabh.Mishra@Sun.COM 
19529865SSaurabh.Mishra@Sun.COM 	/*
19539865SSaurabh.Mishra@Sun.COM 	 * Get the DMA buffer to hold packet.
19549865SSaurabh.Mishra@Sun.COM 	 */
19559865SSaurabh.Mishra@Sun.COM 	buf = (uchar_t *)r->r_buf_dma[cur].addr;
19569865SSaurabh.Mishra@Sun.COM 
19579865SSaurabh.Mishra@Sun.COM 	mcopymsg(mp, buf);	/* it also frees mp */
19589865SSaurabh.Mishra@Sun.COM 
19599865SSaurabh.Mishra@Sun.COM 	/*
19609865SSaurabh.Mishra@Sun.COM 	 * Gather statistics.
19619865SSaurabh.Mishra@Sun.COM 	 */
19629865SSaurabh.Mishra@Sun.COM 	if (buf[0] & 0x1) {
19639865SSaurabh.Mishra@Sun.COM 		if (bcmp(buf, bfe_broadcast, ETHERADDRL) != 0)
19649865SSaurabh.Mishra@Sun.COM 			bfe->bfe_stats.multixmt++;
19659865SSaurabh.Mishra@Sun.COM 		else
19669865SSaurabh.Mishra@Sun.COM 			bfe->bfe_stats.brdcstxmt++;
19679865SSaurabh.Mishra@Sun.COM 	}
19689865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.opackets++;
19699865SSaurabh.Mishra@Sun.COM 	bfe->bfe_stats.obytes += pktlen;
19709865SSaurabh.Mishra@Sun.COM 
19719865SSaurabh.Mishra@Sun.COM 
19729865SSaurabh.Mishra@Sun.COM 	/*
19739865SSaurabh.Mishra@Sun.COM 	 * Program the DMA descriptor (start and end of frame are same).
19749865SSaurabh.Mishra@Sun.COM 	 */
19759865SSaurabh.Mishra@Sun.COM 	next = cur;
19769865SSaurabh.Mishra@Sun.COM 	v = (pktlen & BFE_DESC_LEN) | BFE_DESC_IOC | BFE_DESC_SOF |
19779865SSaurabh.Mishra@Sun.COM 	    BFE_DESC_EOF;
19789865SSaurabh.Mishra@Sun.COM 
19799865SSaurabh.Mishra@Sun.COM 	if (cur == (TX_NUM_DESC - 1))
19809865SSaurabh.Mishra@Sun.COM 		v |= BFE_DESC_EOT;
19819865SSaurabh.Mishra@Sun.COM 
19829865SSaurabh.Mishra@Sun.COM 	PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_ctl), v);
19839865SSaurabh.Mishra@Sun.COM 
19849865SSaurabh.Mishra@Sun.COM 	/*
19859865SSaurabh.Mishra@Sun.COM 	 * DMA addresses need to be added to BFE_PCI_DMA
19869865SSaurabh.Mishra@Sun.COM 	 */
19879865SSaurabh.Mishra@Sun.COM 	PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_addr),
19889865SSaurabh.Mishra@Sun.COM 	    (r->r_buf_dma[cur].cookie.dmac_laddress + BFE_PCI_DMA));
19899865SSaurabh.Mishra@Sun.COM 
19909865SSaurabh.Mishra@Sun.COM 	/*
19919865SSaurabh.Mishra@Sun.COM 	 * Sync the packet data for the device.
19929865SSaurabh.Mishra@Sun.COM 	 */
19939865SSaurabh.Mishra@Sun.COM 	(void) SYNC_BUF(r, cur, 0, pktlen, DDI_DMA_SYNC_FORDEV);
19949865SSaurabh.Mishra@Sun.COM 
19959865SSaurabh.Mishra@Sun.COM 	/* Move to next descriptor slot */
19969865SSaurabh.Mishra@Sun.COM 	BFE_INC_SLOT(next, TX_NUM_DESC);
19979865SSaurabh.Mishra@Sun.COM 
19989865SSaurabh.Mishra@Sun.COM 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
19999865SSaurabh.Mishra@Sun.COM 
20009865SSaurabh.Mishra@Sun.COM 	r->r_curr_desc = next;
20019865SSaurabh.Mishra@Sun.COM 
20029865SSaurabh.Mishra@Sun.COM 	/*
20039865SSaurabh.Mishra@Sun.COM 	 * The order should be 1,2,3,... for BFE_DMATX_PTR if 0,1,2,3,...
20049865SSaurabh.Mishra@Sun.COM 	 * descriptor slot are being programmed.
20059865SSaurabh.Mishra@Sun.COM 	 */
20069865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_DMATX_PTR, next * sizeof (bfe_desc_t));
20079865SSaurabh.Mishra@Sun.COM 	FLUSH(bfe, BFE_DMATX_PTR);
20089865SSaurabh.Mishra@Sun.COM 
20099865SSaurabh.Mishra@Sun.COM 	r->r_avail_desc--;
20109865SSaurabh.Mishra@Sun.COM 
20119865SSaurabh.Mishra@Sun.COM 	/*
20129865SSaurabh.Mishra@Sun.COM 	 * Let timeout know that it must reset the chip if a
20139865SSaurabh.Mishra@Sun.COM 	 * packet is not sent down the wire for more than 5 seconds.
20149865SSaurabh.Mishra@Sun.COM 	 */
20159865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_stall_time = gethrtime() + (5 * 1000000000ULL);
20169865SSaurabh.Mishra@Sun.COM 
20179865SSaurabh.Mishra@Sun.COM 	return (BFE_SUCCESS);
20189865SSaurabh.Mishra@Sun.COM }
20199865SSaurabh.Mishra@Sun.COM 
20209865SSaurabh.Mishra@Sun.COM mblk_t *
20219865SSaurabh.Mishra@Sun.COM bfe_mac_transmit_packet(void *arg, mblk_t *mp)
20229865SSaurabh.Mishra@Sun.COM {
20239865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
20249865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *r = &bfe->bfe_tx_ring;
20259865SSaurabh.Mishra@Sun.COM 	mblk_t	*nmp;
20269865SSaurabh.Mishra@Sun.COM 
20279865SSaurabh.Mishra@Sun.COM 	mutex_enter(&r->r_lock);
20289865SSaurabh.Mishra@Sun.COM 
20299865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
203010591SSaurabh.Mishra@Sun.COM 		DTRACE_PROBE1(tx__chip__not__active, int, bfe->bfe_unit);
20319865SSaurabh.Mishra@Sun.COM 
20329865SSaurabh.Mishra@Sun.COM 		freemsgchain(mp);
20339865SSaurabh.Mishra@Sun.COM 		mutex_exit(&r->r_lock);
20349865SSaurabh.Mishra@Sun.COM 		return (NULL);
20359865SSaurabh.Mishra@Sun.COM 	}
20369865SSaurabh.Mishra@Sun.COM 
20379865SSaurabh.Mishra@Sun.COM 
20389865SSaurabh.Mishra@Sun.COM 	while (mp != NULL) {
20399865SSaurabh.Mishra@Sun.COM 		nmp = mp->b_next;
20409865SSaurabh.Mishra@Sun.COM 		mp->b_next = NULL;
20419865SSaurabh.Mishra@Sun.COM 
20429865SSaurabh.Mishra@Sun.COM 		if (bfe_send_a_packet(bfe, mp) == BFE_FAILURE) {
20439865SSaurabh.Mishra@Sun.COM 			mp->b_next = nmp;
20449865SSaurabh.Mishra@Sun.COM 			break;
20459865SSaurabh.Mishra@Sun.COM 		}
20469865SSaurabh.Mishra@Sun.COM 		mp = nmp;
20479865SSaurabh.Mishra@Sun.COM 	}
20489865SSaurabh.Mishra@Sun.COM 
20499865SSaurabh.Mishra@Sun.COM 	mutex_exit(&r->r_lock);
20509865SSaurabh.Mishra@Sun.COM 
20519865SSaurabh.Mishra@Sun.COM 	return (mp);
20529865SSaurabh.Mishra@Sun.COM }
20539865SSaurabh.Mishra@Sun.COM 
20549865SSaurabh.Mishra@Sun.COM int
20559865SSaurabh.Mishra@Sun.COM bfe_mac_set_promisc(void *arg, boolean_t promiscflag)
20569865SSaurabh.Mishra@Sun.COM {
20579865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe = (bfe_t *)arg;
20589865SSaurabh.Mishra@Sun.COM 
20599865SSaurabh.Mishra@Sun.COM 	bfe_grab_locks(bfe);
20609865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
20619865SSaurabh.Mishra@Sun.COM 		bfe_release_locks(bfe);
20629865SSaurabh.Mishra@Sun.COM 		return (EIO);
20639865SSaurabh.Mishra@Sun.COM 	}
20649865SSaurabh.Mishra@Sun.COM 
20659865SSaurabh.Mishra@Sun.COM 	if (promiscflag) {
20669865SSaurabh.Mishra@Sun.COM 		/* Set Promiscous on */
20679865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_mode |= BFE_RX_MODE_PROMISC;
20689865SSaurabh.Mishra@Sun.COM 	} else {
20699865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_mode &= ~BFE_RX_MODE_PROMISC;
20709865SSaurabh.Mishra@Sun.COM 	}
20719865SSaurabh.Mishra@Sun.COM 
20729865SSaurabh.Mishra@Sun.COM 	bfe_set_rx_mode(bfe);
20739865SSaurabh.Mishra@Sun.COM 	bfe_release_locks(bfe);
20749865SSaurabh.Mishra@Sun.COM 
20759865SSaurabh.Mishra@Sun.COM 	return (0);
20769865SSaurabh.Mishra@Sun.COM }
20779865SSaurabh.Mishra@Sun.COM 
20789865SSaurabh.Mishra@Sun.COM int
20799865SSaurabh.Mishra@Sun.COM bfe_mac_set_multicast(void *arg, boolean_t add, const uint8_t *macaddr)
20809865SSaurabh.Mishra@Sun.COM {
20819865SSaurabh.Mishra@Sun.COM 	/*
20829865SSaurabh.Mishra@Sun.COM 	 * It was too much of pain to implement multicast in CAM. Instead
20839865SSaurabh.Mishra@Sun.COM 	 * we never disable multicast filter.
20849865SSaurabh.Mishra@Sun.COM 	 */
20859865SSaurabh.Mishra@Sun.COM 	return (0);
20869865SSaurabh.Mishra@Sun.COM }
20879865SSaurabh.Mishra@Sun.COM 
20889865SSaurabh.Mishra@Sun.COM static mac_callbacks_t bfe_mac_callbacks = {
2089*11878SVenu.Iyer@Sun.COM 	MC_SETPROP | MC_GETPROP | MC_PROPINFO,
20909865SSaurabh.Mishra@Sun.COM 	bfe_mac_getstat,	/* gets stats */
20919865SSaurabh.Mishra@Sun.COM 	bfe_mac_start,		/* starts mac */
20929865SSaurabh.Mishra@Sun.COM 	bfe_mac_stop,		/* stops mac */
20939865SSaurabh.Mishra@Sun.COM 	bfe_mac_set_promisc,	/* sets promisc mode for snoop */
20949865SSaurabh.Mishra@Sun.COM 	bfe_mac_set_multicast,	/* multicast implementation */
20959865SSaurabh.Mishra@Sun.COM 	bfe_mac_set_ether_addr,	/* sets ethernet address (unicast) */
20969865SSaurabh.Mishra@Sun.COM 	bfe_mac_transmit_packet, /* transmits packet */
2097*11878SVenu.Iyer@Sun.COM 	NULL,
20989865SSaurabh.Mishra@Sun.COM 	NULL,			/* ioctl */
20999865SSaurabh.Mishra@Sun.COM 	NULL,			/* getcap */
21009865SSaurabh.Mishra@Sun.COM 	NULL,			/* open */
21019865SSaurabh.Mishra@Sun.COM 	NULL,			/* close */
21029865SSaurabh.Mishra@Sun.COM 	bfe_mac_setprop,
21039865SSaurabh.Mishra@Sun.COM 	bfe_mac_getprop,
2104*11878SVenu.Iyer@Sun.COM 	bfe_mac_propinfo
21059865SSaurabh.Mishra@Sun.COM };
21069865SSaurabh.Mishra@Sun.COM 
21079865SSaurabh.Mishra@Sun.COM static void
21089865SSaurabh.Mishra@Sun.COM bfe_error_handler(bfe_t *bfe, int intr_mask)
21099865SSaurabh.Mishra@Sun.COM {
21109865SSaurabh.Mishra@Sun.COM 	uint32_t v;
21119865SSaurabh.Mishra@Sun.COM 
21129865SSaurabh.Mishra@Sun.COM 	if (intr_mask & BFE_ISTAT_RFO) {
21139865SSaurabh.Mishra@Sun.COM 		bfe->bfe_stats.overflows++;
211410591SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action |=
211510591SSaurabh.Mishra@Sun.COM 		    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
211610591SSaurabh.Mishra@Sun.COM 		goto action;
21179865SSaurabh.Mishra@Sun.COM 	}
21189865SSaurabh.Mishra@Sun.COM 
21199865SSaurabh.Mishra@Sun.COM 	if (intr_mask & BFE_ISTAT_TFU) {
21209865SSaurabh.Mishra@Sun.COM 		bfe->bfe_stats.underflows++;
21219865SSaurabh.Mishra@Sun.COM 		return;
21229865SSaurabh.Mishra@Sun.COM 	}
21239865SSaurabh.Mishra@Sun.COM 
21249865SSaurabh.Mishra@Sun.COM 	/* Descriptor Protocol Error */
21259865SSaurabh.Mishra@Sun.COM 	if (intr_mask & BFE_ISTAT_DPE) {
21269865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip,
21279865SSaurabh.Mishra@Sun.COM 		    "Descriptor Protocol Error. Halting Chip");
21289865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action |=
21299865SSaurabh.Mishra@Sun.COM 		    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
21309865SSaurabh.Mishra@Sun.COM 		goto action;
21319865SSaurabh.Mishra@Sun.COM 	}
21329865SSaurabh.Mishra@Sun.COM 
21339865SSaurabh.Mishra@Sun.COM 	/* Descriptor Error */
21349865SSaurabh.Mishra@Sun.COM 	if (intr_mask & BFE_ISTAT_DSCE && halt == 0) {
21359865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "Descriptor Error. Restarting Chip");
21369865SSaurabh.Mishra@Sun.COM 		goto action;
21379865SSaurabh.Mishra@Sun.COM 	}
21389865SSaurabh.Mishra@Sun.COM 
21399865SSaurabh.Mishra@Sun.COM 	/* Receive Descr. Underflow */
21409865SSaurabh.Mishra@Sun.COM 	if (intr_mask & BFE_ISTAT_RDU) {
21419865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip,
21429865SSaurabh.Mishra@Sun.COM 		    "Receive Descriptor Underflow. Restarting Chip");
21439865SSaurabh.Mishra@Sun.COM 		bfe->bfe_stats.ether_stat_macrcv_errors++;
21449865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_action |=
21459865SSaurabh.Mishra@Sun.COM 		    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
21469865SSaurabh.Mishra@Sun.COM 		goto action;
21479865SSaurabh.Mishra@Sun.COM 	}
21489865SSaurabh.Mishra@Sun.COM 
21499865SSaurabh.Mishra@Sun.COM 	v = INL(bfe, BFE_DMATX_STAT);
21509865SSaurabh.Mishra@Sun.COM 
21519865SSaurabh.Mishra@Sun.COM 	/* Error while sending a packet */
21529865SSaurabh.Mishra@Sun.COM 	if (v & BFE_STAT_EMASK) {
21539865SSaurabh.Mishra@Sun.COM 		bfe->bfe_stats.ether_stat_macxmt_errors++;
21549865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip,
21559865SSaurabh.Mishra@Sun.COM 		    "Error while sending a packet. Restarting Chip");
21569865SSaurabh.Mishra@Sun.COM 	}
21579865SSaurabh.Mishra@Sun.COM 
21589865SSaurabh.Mishra@Sun.COM 	/* Error while receiving a packet */
21599865SSaurabh.Mishra@Sun.COM 	v = INL(bfe, BFE_DMARX_STAT);
21609865SSaurabh.Mishra@Sun.COM 	if (v & BFE_RX_FLAG_ERRORS) {
21619865SSaurabh.Mishra@Sun.COM 		bfe->bfe_stats.ierrors++;
21629865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip,
21639865SSaurabh.Mishra@Sun.COM 		    "Error while receiving a packet. Restarting Chip");
21649865SSaurabh.Mishra@Sun.COM 	}
21659865SSaurabh.Mishra@Sun.COM 
21669865SSaurabh.Mishra@Sun.COM 
21679865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_action |=
21689865SSaurabh.Mishra@Sun.COM 	    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
21699865SSaurabh.Mishra@Sun.COM 
21709865SSaurabh.Mishra@Sun.COM action:
21719865SSaurabh.Mishra@Sun.COM 	bfe_chip_halt(bfe);
21729865SSaurabh.Mishra@Sun.COM }
21739865SSaurabh.Mishra@Sun.COM 
21749865SSaurabh.Mishra@Sun.COM /*
21759865SSaurabh.Mishra@Sun.COM  * It will recycle a RX descriptor slot.
21769865SSaurabh.Mishra@Sun.COM  */
21779865SSaurabh.Mishra@Sun.COM static void
21789865SSaurabh.Mishra@Sun.COM bfe_rx_desc_buf_reinit(bfe_t *bfe, uint_t slot)
21799865SSaurabh.Mishra@Sun.COM {
21809865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *r = &bfe->bfe_rx_ring;
21819865SSaurabh.Mishra@Sun.COM 	uint32_t v;
21829865SSaurabh.Mishra@Sun.COM 
21839865SSaurabh.Mishra@Sun.COM 	slot %= RX_NUM_DESC;
21849865SSaurabh.Mishra@Sun.COM 
21859865SSaurabh.Mishra@Sun.COM 	bzero(r->r_buf_dma[slot].addr, sizeof (bfe_rx_header_t));
21869865SSaurabh.Mishra@Sun.COM 
21879865SSaurabh.Mishra@Sun.COM 	(void) SYNC_BUF(r, slot, 0, BFE_RX_OFFSET, DDI_DMA_SYNC_FORDEV);
21889865SSaurabh.Mishra@Sun.COM 
21899865SSaurabh.Mishra@Sun.COM 	v = r->r_buf_dma[slot].len  & BFE_DESC_LEN;
21909865SSaurabh.Mishra@Sun.COM 	if (slot == (RX_NUM_DESC - 1))
21919865SSaurabh.Mishra@Sun.COM 		v |= BFE_DESC_EOT;
21929865SSaurabh.Mishra@Sun.COM 
21939865SSaurabh.Mishra@Sun.COM 	PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_ctl), v);
21949865SSaurabh.Mishra@Sun.COM 
21959865SSaurabh.Mishra@Sun.COM 	/*
21969865SSaurabh.Mishra@Sun.COM 	 * DMA addresses need to be added to BFE_PCI_DMA
21979865SSaurabh.Mishra@Sun.COM 	 */
21989865SSaurabh.Mishra@Sun.COM 	PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_addr),
21999865SSaurabh.Mishra@Sun.COM 	    (r->r_buf_dma[slot].cookie.dmac_laddress + BFE_PCI_DMA));
22009865SSaurabh.Mishra@Sun.COM }
22019865SSaurabh.Mishra@Sun.COM 
22029865SSaurabh.Mishra@Sun.COM /*
22039865SSaurabh.Mishra@Sun.COM  * Gets called from interrupt context to handle RX interrupt.
22049865SSaurabh.Mishra@Sun.COM  */
22059865SSaurabh.Mishra@Sun.COM static mblk_t *
22069865SSaurabh.Mishra@Sun.COM bfe_receive(bfe_t *bfe, int intr_mask)
22079865SSaurabh.Mishra@Sun.COM {
22089865SSaurabh.Mishra@Sun.COM 	int rxstat, current;
22099865SSaurabh.Mishra@Sun.COM 	mblk_t	*mp = NULL, *rx_head, *rx_tail;
22109865SSaurabh.Mishra@Sun.COM 	uchar_t	*rx_header;
22119865SSaurabh.Mishra@Sun.COM 	uint16_t len;
22129865SSaurabh.Mishra@Sun.COM 	uchar_t	*bp;
22139865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *r = &bfe->bfe_rx_ring;
22149865SSaurabh.Mishra@Sun.COM 	int i;
22159865SSaurabh.Mishra@Sun.COM 
22169865SSaurabh.Mishra@Sun.COM 	rxstat = INL(bfe, BFE_DMARX_STAT);
22179865SSaurabh.Mishra@Sun.COM 	current = (rxstat & BFE_STAT_CDMASK) / sizeof (bfe_desc_t);
22189865SSaurabh.Mishra@Sun.COM 	i = r->r_curr_desc;
22199865SSaurabh.Mishra@Sun.COM 
22209865SSaurabh.Mishra@Sun.COM 	rx_head = rx_tail = NULL;
22219865SSaurabh.Mishra@Sun.COM 
22229865SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE3(receive, int, bfe->bfe_unit,
22239865SSaurabh.Mishra@Sun.COM 	    int, r->r_curr_desc,
22249865SSaurabh.Mishra@Sun.COM 	    int, current);
22259865SSaurabh.Mishra@Sun.COM 
22269865SSaurabh.Mishra@Sun.COM 	for (i = r->r_curr_desc; i != current;
22279865SSaurabh.Mishra@Sun.COM 	    BFE_INC_SLOT(i, RX_NUM_DESC)) {
22289865SSaurabh.Mishra@Sun.COM 
22299865SSaurabh.Mishra@Sun.COM 		/*
22309865SSaurabh.Mishra@Sun.COM 		 * Sync the buffer associated with the descriptor table entry.
22319865SSaurabh.Mishra@Sun.COM 		 */
22329865SSaurabh.Mishra@Sun.COM 		(void) SYNC_BUF(r, i, 0, r->r_buf_dma[i].len,
22339865SSaurabh.Mishra@Sun.COM 		    DDI_DMA_SYNC_FORKERNEL);
22349865SSaurabh.Mishra@Sun.COM 
22359865SSaurabh.Mishra@Sun.COM 		rx_header = (void *)r->r_buf_dma[i].addr;
22369865SSaurabh.Mishra@Sun.COM 
22379865SSaurabh.Mishra@Sun.COM 		/*
22389865SSaurabh.Mishra@Sun.COM 		 * We do this to make sure we are endian neutral. Chip is
22399865SSaurabh.Mishra@Sun.COM 		 * big endian.
22409865SSaurabh.Mishra@Sun.COM 		 *
22419865SSaurabh.Mishra@Sun.COM 		 * The header looks like :-
22429865SSaurabh.Mishra@Sun.COM 		 *
22439865SSaurabh.Mishra@Sun.COM 		 *  Offset 0  -> uint16_t len
22449865SSaurabh.Mishra@Sun.COM 		 *  Offset 2  -> uint16_t flags
22459865SSaurabh.Mishra@Sun.COM 		 *  Offset 4  -> uint16_t pad[12]
22469865SSaurabh.Mishra@Sun.COM 		 */
22479865SSaurabh.Mishra@Sun.COM 		len = (rx_header[1] << 8) | rx_header[0];
22489865SSaurabh.Mishra@Sun.COM 		len -= 4;	/* CRC bytes need to be removed */
22499865SSaurabh.Mishra@Sun.COM 
22509865SSaurabh.Mishra@Sun.COM 		/*
22519865SSaurabh.Mishra@Sun.COM 		 * Don't receive this packet if pkt length is greater than
22529865SSaurabh.Mishra@Sun.COM 		 * MTU + VLAN_TAGSZ.
22539865SSaurabh.Mishra@Sun.COM 		 */
22549865SSaurabh.Mishra@Sun.COM 		if (len > r->r_buf_len) {
22559865SSaurabh.Mishra@Sun.COM 			/* Recycle slot for later use */
22569865SSaurabh.Mishra@Sun.COM 			bfe_rx_desc_buf_reinit(bfe, i);
22579865SSaurabh.Mishra@Sun.COM 			continue;
22589865SSaurabh.Mishra@Sun.COM 		}
22599865SSaurabh.Mishra@Sun.COM 
22609865SSaurabh.Mishra@Sun.COM 		if ((mp = allocb(len + VLAN_TAGSZ, BPRI_MED)) != NULL) {
22619865SSaurabh.Mishra@Sun.COM 			mp->b_rptr += VLAN_TAGSZ;
22629865SSaurabh.Mishra@Sun.COM 			bp = mp->b_rptr;
22639865SSaurabh.Mishra@Sun.COM 			mp->b_wptr = bp + len;
22649865SSaurabh.Mishra@Sun.COM 
22659865SSaurabh.Mishra@Sun.COM 			/* sizeof (bfe_rx_header_t) + 2 */
22669865SSaurabh.Mishra@Sun.COM 			bcopy(r->r_buf_dma[i].addr +
22679865SSaurabh.Mishra@Sun.COM 			    BFE_RX_OFFSET, bp, len);
22689865SSaurabh.Mishra@Sun.COM 
22699865SSaurabh.Mishra@Sun.COM 			mp->b_next = NULL;
22709865SSaurabh.Mishra@Sun.COM 			if (rx_tail == NULL)
22719865SSaurabh.Mishra@Sun.COM 				rx_head = rx_tail = mp;
22729865SSaurabh.Mishra@Sun.COM 			else {
22739865SSaurabh.Mishra@Sun.COM 				rx_tail->b_next = mp;
22749865SSaurabh.Mishra@Sun.COM 				rx_tail = mp;
22759865SSaurabh.Mishra@Sun.COM 			}
22769865SSaurabh.Mishra@Sun.COM 
22779865SSaurabh.Mishra@Sun.COM 			/* Number of packets received so far */
22789865SSaurabh.Mishra@Sun.COM 			bfe->bfe_stats.ipackets++;
22799865SSaurabh.Mishra@Sun.COM 
22809865SSaurabh.Mishra@Sun.COM 			/* Total bytes of packets received so far */
22819865SSaurabh.Mishra@Sun.COM 			bfe->bfe_stats.rbytes += len;
22829865SSaurabh.Mishra@Sun.COM 
22839865SSaurabh.Mishra@Sun.COM 			if (bcmp(mp->b_rptr, bfe_broadcast, ETHERADDRL) == 0)
22849865SSaurabh.Mishra@Sun.COM 				bfe->bfe_stats.brdcstrcv++;
22859865SSaurabh.Mishra@Sun.COM 			else
22869865SSaurabh.Mishra@Sun.COM 				bfe->bfe_stats.multircv++;
22879865SSaurabh.Mishra@Sun.COM 		} else {
22889865SSaurabh.Mishra@Sun.COM 			bfe->bfe_stats.norcvbuf++;
22899865SSaurabh.Mishra@Sun.COM 			/* Recycle the slot for later use */
22909865SSaurabh.Mishra@Sun.COM 			bfe_rx_desc_buf_reinit(bfe, i);
22919865SSaurabh.Mishra@Sun.COM 			break;
22929865SSaurabh.Mishra@Sun.COM 		}
22939865SSaurabh.Mishra@Sun.COM 
22949865SSaurabh.Mishra@Sun.COM 		/*
22959865SSaurabh.Mishra@Sun.COM 		 * Reinitialize the current descriptor slot's buffer so that
22969865SSaurabh.Mishra@Sun.COM 		 * it can be reused.
22979865SSaurabh.Mishra@Sun.COM 		 */
22989865SSaurabh.Mishra@Sun.COM 		bfe_rx_desc_buf_reinit(bfe, i);
22999865SSaurabh.Mishra@Sun.COM 	}
23009865SSaurabh.Mishra@Sun.COM 
23019865SSaurabh.Mishra@Sun.COM 	r->r_curr_desc = i;
23029865SSaurabh.Mishra@Sun.COM 
23039865SSaurabh.Mishra@Sun.COM 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
23049865SSaurabh.Mishra@Sun.COM 
23059865SSaurabh.Mishra@Sun.COM 	return (rx_head);
23069865SSaurabh.Mishra@Sun.COM }
23079865SSaurabh.Mishra@Sun.COM 
23089865SSaurabh.Mishra@Sun.COM static int
23099865SSaurabh.Mishra@Sun.COM bfe_tx_reclaim(bfe_ring_t *r)
23109865SSaurabh.Mishra@Sun.COM {
23119865SSaurabh.Mishra@Sun.COM 	uint32_t cur, start;
23129865SSaurabh.Mishra@Sun.COM 	uint32_t v;
23139865SSaurabh.Mishra@Sun.COM 
23149865SSaurabh.Mishra@Sun.COM 	cur = INL(r->r_bfe, BFE_DMATX_STAT) & BFE_STAT_CDMASK;
23159865SSaurabh.Mishra@Sun.COM 	cur = cur / sizeof (bfe_desc_t);
23169865SSaurabh.Mishra@Sun.COM 
23179865SSaurabh.Mishra@Sun.COM 	/*
23189865SSaurabh.Mishra@Sun.COM 	 * Start with the last descriptor consumed by the chip.
23199865SSaurabh.Mishra@Sun.COM 	 */
23209865SSaurabh.Mishra@Sun.COM 	start = r->r_cons_desc;
23219865SSaurabh.Mishra@Sun.COM 
23229865SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE3(tx__reclaim, int, r->r_bfe->bfe_unit,
23239865SSaurabh.Mishra@Sun.COM 	    int, start,
23249865SSaurabh.Mishra@Sun.COM 	    int, cur);
23259865SSaurabh.Mishra@Sun.COM 
23269865SSaurabh.Mishra@Sun.COM 	/*
23279865SSaurabh.Mishra@Sun.COM 	 * There will be at least one descriptor to process.
23289865SSaurabh.Mishra@Sun.COM 	 */
23299865SSaurabh.Mishra@Sun.COM 	while (start != cur) {
23309865SSaurabh.Mishra@Sun.COM 		r->r_avail_desc++;
23319865SSaurabh.Mishra@Sun.COM 		v = r->r_buf_dma[start].len  & BFE_DESC_LEN;
23329865SSaurabh.Mishra@Sun.COM 		if (start == (TX_NUM_DESC - 1))
23339865SSaurabh.Mishra@Sun.COM 			v |= BFE_DESC_EOT;
23349865SSaurabh.Mishra@Sun.COM 
23359865SSaurabh.Mishra@Sun.COM 		PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_ctl), v);
23369865SSaurabh.Mishra@Sun.COM 		PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_addr),
23379865SSaurabh.Mishra@Sun.COM 		    (r->r_buf_dma[start].cookie.dmac_laddress + BFE_PCI_DMA));
23389865SSaurabh.Mishra@Sun.COM 
23399865SSaurabh.Mishra@Sun.COM 		/* Move to next descriptor in TX ring */
23409865SSaurabh.Mishra@Sun.COM 		BFE_INC_SLOT(start, TX_NUM_DESC);
23419865SSaurabh.Mishra@Sun.COM 	}
23429865SSaurabh.Mishra@Sun.COM 
23439865SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_sync(r->r_desc_dma_handle,
23449865SSaurabh.Mishra@Sun.COM 	    0, (r->r_ndesc * sizeof (bfe_desc_t)),
23459865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SYNC_FORDEV);
23469865SSaurabh.Mishra@Sun.COM 
23479865SSaurabh.Mishra@Sun.COM 	r->r_cons_desc = start; 	/* consumed pointer */
23489865SSaurabh.Mishra@Sun.COM 	r->r_bfe->bfe_tx_stall_time = 0;
23499865SSaurabh.Mishra@Sun.COM 
23509865SSaurabh.Mishra@Sun.COM 	return (cur);
23519865SSaurabh.Mishra@Sun.COM }
23529865SSaurabh.Mishra@Sun.COM 
23539865SSaurabh.Mishra@Sun.COM static int
23549865SSaurabh.Mishra@Sun.COM bfe_tx_done(bfe_t *bfe, int intr_mask)
23559865SSaurabh.Mishra@Sun.COM {
23569865SSaurabh.Mishra@Sun.COM 	bfe_ring_t *r = &bfe->bfe_tx_ring;
23579865SSaurabh.Mishra@Sun.COM 	int resched = 0;
23589865SSaurabh.Mishra@Sun.COM 
23599865SSaurabh.Mishra@Sun.COM 	mutex_enter(&r->r_lock);
23609865SSaurabh.Mishra@Sun.COM 	(void) bfe_tx_reclaim(r);
23619865SSaurabh.Mishra@Sun.COM 
23629865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_tx_resched) {
23639865SSaurabh.Mishra@Sun.COM 		resched = 1;
23649865SSaurabh.Mishra@Sun.COM 		bfe->bfe_tx_resched = 0;
23659865SSaurabh.Mishra@Sun.COM 	}
23669865SSaurabh.Mishra@Sun.COM 	mutex_exit(&r->r_lock);
23679865SSaurabh.Mishra@Sun.COM 
23689865SSaurabh.Mishra@Sun.COM 	return (resched);
23699865SSaurabh.Mishra@Sun.COM }
23709865SSaurabh.Mishra@Sun.COM 
23719865SSaurabh.Mishra@Sun.COM /*
23729865SSaurabh.Mishra@Sun.COM  * ISR for interrupt handling
23739865SSaurabh.Mishra@Sun.COM  */
23749865SSaurabh.Mishra@Sun.COM static uint_t
23759865SSaurabh.Mishra@Sun.COM bfe_interrupt(caddr_t arg1, caddr_t arg2)
23769865SSaurabh.Mishra@Sun.COM {
23779865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe =  (void *)arg1;
23789865SSaurabh.Mishra@Sun.COM 	uint32_t	intr_stat;
23799865SSaurabh.Mishra@Sun.COM 	mblk_t *rx_head = NULL;
23809865SSaurabh.Mishra@Sun.COM 	int resched = 0;
23819865SSaurabh.Mishra@Sun.COM 
23829865SSaurabh.Mishra@Sun.COM 	/*
23839865SSaurabh.Mishra@Sun.COM 	 * Grab the lock to avoid stopping the chip while this interrupt
23849865SSaurabh.Mishra@Sun.COM 	 * is handled.
23859865SSaurabh.Mishra@Sun.COM 	 */
23869865SSaurabh.Mishra@Sun.COM 	rw_enter(&bfe->bfe_rwlock, RW_READER);
23879865SSaurabh.Mishra@Sun.COM 
23889865SSaurabh.Mishra@Sun.COM 	/*
23899865SSaurabh.Mishra@Sun.COM 	 * It's necessary to read intr stat again because masking interrupt
23909865SSaurabh.Mishra@Sun.COM 	 * register does not really mask interrupts coming from the chip.
23919865SSaurabh.Mishra@Sun.COM 	 */
23929865SSaurabh.Mishra@Sun.COM 	intr_stat = INL(bfe, BFE_INTR_STAT);
23939865SSaurabh.Mishra@Sun.COM 	intr_stat &= BFE_IMASK_DEF;
23949865SSaurabh.Mishra@Sun.COM 	OUTL(bfe, BFE_INTR_STAT, intr_stat);
23959865SSaurabh.Mishra@Sun.COM 	(void) INL(bfe, BFE_INTR_STAT);
23969865SSaurabh.Mishra@Sun.COM 
23979865SSaurabh.Mishra@Sun.COM 	if (intr_stat == 0) {
23989865SSaurabh.Mishra@Sun.COM 		rw_exit(&bfe->bfe_rwlock);
23999865SSaurabh.Mishra@Sun.COM 		return (DDI_INTR_UNCLAIMED);
24009865SSaurabh.Mishra@Sun.COM 	}
24019865SSaurabh.Mishra@Sun.COM 
240210591SSaurabh.Mishra@Sun.COM 	DTRACE_PROBE2(bfe__interrupt, int, bfe->bfe_unit,
240310591SSaurabh.Mishra@Sun.COM 	    int, intr_stat);
240410591SSaurabh.Mishra@Sun.COM 
24059865SSaurabh.Mishra@Sun.COM 	if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
24069865SSaurabh.Mishra@Sun.COM 		/*
24079865SSaurabh.Mishra@Sun.COM 		 * If chip is suspended then we just return.
24089865SSaurabh.Mishra@Sun.COM 		 */
24099865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED) {
24109865SSaurabh.Mishra@Sun.COM 			rw_exit(&bfe->bfe_rwlock);
24119865SSaurabh.Mishra@Sun.COM 			DTRACE_PROBE1(interrupt__chip__is__suspend, int,
24129865SSaurabh.Mishra@Sun.COM 			    bfe->bfe_unit);
24139865SSaurabh.Mishra@Sun.COM 			return (DDI_INTR_CLAIMED);
24149865SSaurabh.Mishra@Sun.COM 		}
24159865SSaurabh.Mishra@Sun.COM 
24169865SSaurabh.Mishra@Sun.COM 		/*
24179865SSaurabh.Mishra@Sun.COM 		 * Halt the chip again i.e basically disable interrupts.
24189865SSaurabh.Mishra@Sun.COM 		 */
24199865SSaurabh.Mishra@Sun.COM 		bfe_chip_halt(bfe);
24209865SSaurabh.Mishra@Sun.COM 		rw_exit(&bfe->bfe_rwlock);
24219865SSaurabh.Mishra@Sun.COM 		DTRACE_PROBE1(interrupt__chip__not__active, int,
24229865SSaurabh.Mishra@Sun.COM 		    bfe->bfe_unit);
24239865SSaurabh.Mishra@Sun.COM 		return (DDI_INTR_CLAIMED);
24249865SSaurabh.Mishra@Sun.COM 	}
24259865SSaurabh.Mishra@Sun.COM 
24269865SSaurabh.Mishra@Sun.COM 	/* A packet was received */
24279865SSaurabh.Mishra@Sun.COM 	if (intr_stat & BFE_ISTAT_RX) {
24289865SSaurabh.Mishra@Sun.COM 		rx_head = bfe_receive(bfe, intr_stat);
24299865SSaurabh.Mishra@Sun.COM 	}
24309865SSaurabh.Mishra@Sun.COM 
24319865SSaurabh.Mishra@Sun.COM 	/* A packet was sent down the wire */
24329865SSaurabh.Mishra@Sun.COM 	if (intr_stat & BFE_ISTAT_TX) {
24339865SSaurabh.Mishra@Sun.COM 		resched = bfe_tx_done(bfe, intr_stat);
24349865SSaurabh.Mishra@Sun.COM 	}
24359865SSaurabh.Mishra@Sun.COM 
24369865SSaurabh.Mishra@Sun.COM 	/* There was an error */
24379865SSaurabh.Mishra@Sun.COM 	if (intr_stat & BFE_ISTAT_ERRORS) {
24389865SSaurabh.Mishra@Sun.COM 		bfe_error_handler(bfe, intr_stat);
24399865SSaurabh.Mishra@Sun.COM 	}
24409865SSaurabh.Mishra@Sun.COM 
24419865SSaurabh.Mishra@Sun.COM 	rw_exit(&bfe->bfe_rwlock);
24429865SSaurabh.Mishra@Sun.COM 
24439865SSaurabh.Mishra@Sun.COM 	/*
24449865SSaurabh.Mishra@Sun.COM 	 * Pass the list of packets received from chip to MAC layer.
24459865SSaurabh.Mishra@Sun.COM 	 */
24469865SSaurabh.Mishra@Sun.COM 	if (rx_head) {
24479865SSaurabh.Mishra@Sun.COM 		mac_rx(bfe->bfe_machdl, 0, rx_head);
24489865SSaurabh.Mishra@Sun.COM 	}
24499865SSaurabh.Mishra@Sun.COM 
24509865SSaurabh.Mishra@Sun.COM 	/*
24519865SSaurabh.Mishra@Sun.COM 	 * Let the MAC start sending pkts to a potential stopped stream.
24529865SSaurabh.Mishra@Sun.COM 	 */
24539865SSaurabh.Mishra@Sun.COM 	if (resched)
24549865SSaurabh.Mishra@Sun.COM 		mac_tx_update(bfe->bfe_machdl);
24559865SSaurabh.Mishra@Sun.COM 
24569865SSaurabh.Mishra@Sun.COM 	return (DDI_INTR_CLAIMED);
24579865SSaurabh.Mishra@Sun.COM }
24589865SSaurabh.Mishra@Sun.COM 
24599865SSaurabh.Mishra@Sun.COM /*
24609865SSaurabh.Mishra@Sun.COM  * Removes registered interrupt handler.
24619865SSaurabh.Mishra@Sun.COM  */
24629865SSaurabh.Mishra@Sun.COM static void
24639865SSaurabh.Mishra@Sun.COM bfe_remove_intr(bfe_t *bfe)
24649865SSaurabh.Mishra@Sun.COM {
24659865SSaurabh.Mishra@Sun.COM 	(void) ddi_intr_remove_handler(bfe->bfe_intrhdl);
24669865SSaurabh.Mishra@Sun.COM 	(void) ddi_intr_free(bfe->bfe_intrhdl);
24679865SSaurabh.Mishra@Sun.COM }
24689865SSaurabh.Mishra@Sun.COM 
24699865SSaurabh.Mishra@Sun.COM /*
24709865SSaurabh.Mishra@Sun.COM  * Add an interrupt for the driver.
24719865SSaurabh.Mishra@Sun.COM  */
24729865SSaurabh.Mishra@Sun.COM static int
24739865SSaurabh.Mishra@Sun.COM bfe_add_intr(bfe_t *bfe)
24749865SSaurabh.Mishra@Sun.COM {
24759865SSaurabh.Mishra@Sun.COM 	int	nintrs = 1;
24769865SSaurabh.Mishra@Sun.COM 	int ret;
24779865SSaurabh.Mishra@Sun.COM 
24789865SSaurabh.Mishra@Sun.COM 	ret = ddi_intr_alloc(bfe->bfe_dip, &bfe->bfe_intrhdl,
24799865SSaurabh.Mishra@Sun.COM 	    DDI_INTR_TYPE_FIXED,	/* type */
24809865SSaurabh.Mishra@Sun.COM 	    0,	/* inumber */
24819865SSaurabh.Mishra@Sun.COM 	    1,	/* count */
24829865SSaurabh.Mishra@Sun.COM 	    &nintrs,	/* actual nintrs */
24839865SSaurabh.Mishra@Sun.COM 	    DDI_INTR_ALLOC_STRICT);
24849865SSaurabh.Mishra@Sun.COM 
24859865SSaurabh.Mishra@Sun.COM 	if (ret != DDI_SUCCESS) {
24869865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "ddi_intr_alloc() failed"
24879865SSaurabh.Mishra@Sun.COM 		    " : ret : %d", ret);
24889865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
24899865SSaurabh.Mishra@Sun.COM 	}
24909865SSaurabh.Mishra@Sun.COM 
24919865SSaurabh.Mishra@Sun.COM 	ret = ddi_intr_add_handler(bfe->bfe_intrhdl, bfe_interrupt, bfe, NULL);
24929865SSaurabh.Mishra@Sun.COM 	if (ret != DDI_SUCCESS) {
24939865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "ddi_intr_add_handler() failed");
24949865SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_free(bfe->bfe_intrhdl);
24959865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
24969865SSaurabh.Mishra@Sun.COM 	}
24979865SSaurabh.Mishra@Sun.COM 
24989865SSaurabh.Mishra@Sun.COM 	ret = ddi_intr_get_pri(bfe->bfe_intrhdl, &bfe->bfe_intrpri);
24999865SSaurabh.Mishra@Sun.COM 	if (ret != DDI_SUCCESS) {
25009865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "ddi_intr_get_pri() failed");
25019865SSaurabh.Mishra@Sun.COM 		bfe_remove_intr(bfe);
25029865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
25039865SSaurabh.Mishra@Sun.COM 	}
25049865SSaurabh.Mishra@Sun.COM 
25059865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
25069865SSaurabh.Mishra@Sun.COM }
25079865SSaurabh.Mishra@Sun.COM 
25089865SSaurabh.Mishra@Sun.COM 
25099865SSaurabh.Mishra@Sun.COM /*
25109865SSaurabh.Mishra@Sun.COM  * Identify chipset family.
25119865SSaurabh.Mishra@Sun.COM  */
25129865SSaurabh.Mishra@Sun.COM static int
25139865SSaurabh.Mishra@Sun.COM bfe_identify_hardware(bfe_t *bfe)
25149865SSaurabh.Mishra@Sun.COM {
25159865SSaurabh.Mishra@Sun.COM 	uint16_t	vid, did;
25169865SSaurabh.Mishra@Sun.COM 	int i;
25179865SSaurabh.Mishra@Sun.COM 
25189865SSaurabh.Mishra@Sun.COM 	vid = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_VENID);
25199865SSaurabh.Mishra@Sun.COM 	did = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_DEVID);
25209865SSaurabh.Mishra@Sun.COM 
25219865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < (sizeof (bfe_cards) / sizeof (bfe_cards_t)); i++) {
25229865SSaurabh.Mishra@Sun.COM 		if (bfe_cards[i].vendor_id == vid &&
25239865SSaurabh.Mishra@Sun.COM 		    bfe_cards[i].device_id == did) {
25249865SSaurabh.Mishra@Sun.COM 			return (BFE_SUCCESS);
25259865SSaurabh.Mishra@Sun.COM 		}
25269865SSaurabh.Mishra@Sun.COM 	}
25279865SSaurabh.Mishra@Sun.COM 
25289865SSaurabh.Mishra@Sun.COM 	bfe_error(bfe->bfe_dip, "bfe driver is attaching to unknown pci%d,%d"
25299865SSaurabh.Mishra@Sun.COM 	    " vendor/device-id card", vid, did);
25309865SSaurabh.Mishra@Sun.COM 
25319865SSaurabh.Mishra@Sun.COM 	return (BFE_SUCCESS);
25329865SSaurabh.Mishra@Sun.COM }
25339865SSaurabh.Mishra@Sun.COM 
25349865SSaurabh.Mishra@Sun.COM /*
25359865SSaurabh.Mishra@Sun.COM  * Maps device registers.
25369865SSaurabh.Mishra@Sun.COM  */
25379865SSaurabh.Mishra@Sun.COM static int
25389865SSaurabh.Mishra@Sun.COM bfe_regs_map(bfe_t *bfe)
25399865SSaurabh.Mishra@Sun.COM {
25409865SSaurabh.Mishra@Sun.COM 	dev_info_t *dip = bfe->bfe_dip;
25419865SSaurabh.Mishra@Sun.COM 	int ret;
25429865SSaurabh.Mishra@Sun.COM 
25439865SSaurabh.Mishra@Sun.COM 	ret = ddi_regs_map_setup(dip, 1, &bfe->bfe_mem_regset.addr, 0, 0,
25449865SSaurabh.Mishra@Sun.COM 	    &bfe_dev_attr, &bfe->bfe_mem_regset.hdl);
25459865SSaurabh.Mishra@Sun.COM 
25469865SSaurabh.Mishra@Sun.COM 	if (ret != DDI_SUCCESS) {
25479865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "ddi_regs_map_setup failed");
25489865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
25499865SSaurabh.Mishra@Sun.COM 	}
25509865SSaurabh.Mishra@Sun.COM 
25519865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
25529865SSaurabh.Mishra@Sun.COM }
25539865SSaurabh.Mishra@Sun.COM 
25549865SSaurabh.Mishra@Sun.COM static void
25559865SSaurabh.Mishra@Sun.COM bfe_unmap_regs(bfe_t *bfe)
25569865SSaurabh.Mishra@Sun.COM {
25579865SSaurabh.Mishra@Sun.COM 	ddi_regs_map_free(&bfe->bfe_mem_regset.hdl);
25589865SSaurabh.Mishra@Sun.COM }
25599865SSaurabh.Mishra@Sun.COM 
25609865SSaurabh.Mishra@Sun.COM static int
25619865SSaurabh.Mishra@Sun.COM bfe_get_chip_config(bfe_t *bfe)
25629865SSaurabh.Mishra@Sun.COM {
25639865SSaurabh.Mishra@Sun.COM 	uint32_t	prom[BFE_EEPROM_SIZE];
25649865SSaurabh.Mishra@Sun.COM 	int i;
25659865SSaurabh.Mishra@Sun.COM 
25669865SSaurabh.Mishra@Sun.COM 	/*
25679865SSaurabh.Mishra@Sun.COM 	 * Read EEPROM in prom[]
25689865SSaurabh.Mishra@Sun.COM 	 */
25699865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < BFE_EEPROM_SIZE; i++) {
25709865SSaurabh.Mishra@Sun.COM 		prom[i] = INL(bfe, BFE_EEPROM_BASE + i * sizeof (uint32_t));
25719865SSaurabh.Mishra@Sun.COM 	}
25729865SSaurabh.Mishra@Sun.COM 
25739865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dev_addr[0] = bfe->bfe_ether_addr[0] =
25749865SSaurabh.Mishra@Sun.COM 	    INB(bfe, BFE_EEPROM_BASE + 79);
25759865SSaurabh.Mishra@Sun.COM 
25769865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dev_addr[1] = bfe->bfe_ether_addr[1] =
25779865SSaurabh.Mishra@Sun.COM 	    INB(bfe, BFE_EEPROM_BASE + 78);
25789865SSaurabh.Mishra@Sun.COM 
25799865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dev_addr[2] = bfe->bfe_ether_addr[2] =
25809865SSaurabh.Mishra@Sun.COM 	    INB(bfe, BFE_EEPROM_BASE + 81);
25819865SSaurabh.Mishra@Sun.COM 
25829865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dev_addr[3] = bfe->bfe_ether_addr[3] =
25839865SSaurabh.Mishra@Sun.COM 	    INB(bfe, BFE_EEPROM_BASE + 80);
25849865SSaurabh.Mishra@Sun.COM 
25859865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dev_addr[4] = bfe->bfe_ether_addr[4] =
25869865SSaurabh.Mishra@Sun.COM 	    INB(bfe, BFE_EEPROM_BASE + 83);
25879865SSaurabh.Mishra@Sun.COM 
25889865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dev_addr[5] = bfe->bfe_ether_addr[5] =
25899865SSaurabh.Mishra@Sun.COM 	    INB(bfe, BFE_EEPROM_BASE + 82);
25909865SSaurabh.Mishra@Sun.COM 
25919865SSaurabh.Mishra@Sun.COM 	bfe->bfe_phy_addr = -1;
25929865SSaurabh.Mishra@Sun.COM 
25939865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
25949865SSaurabh.Mishra@Sun.COM }
25959865SSaurabh.Mishra@Sun.COM 
25969865SSaurabh.Mishra@Sun.COM /*
25979865SSaurabh.Mishra@Sun.COM  * Ring Management routines
25989865SSaurabh.Mishra@Sun.COM  */
25999865SSaurabh.Mishra@Sun.COM static int
26009865SSaurabh.Mishra@Sun.COM bfe_ring_buf_alloc(bfe_t *bfe, bfe_ring_t *r, int slot, int d)
26019865SSaurabh.Mishra@Sun.COM {
26029865SSaurabh.Mishra@Sun.COM 	int err;
26039865SSaurabh.Mishra@Sun.COM 	uint_t count = 0;
26049865SSaurabh.Mishra@Sun.COM 
26059865SSaurabh.Mishra@Sun.COM 	err = ddi_dma_alloc_handle(bfe->bfe_dip,
26069865SSaurabh.Mishra@Sun.COM 	    &bfe_dma_attr_buf, DDI_DMA_SLEEP, NULL,
26079865SSaurabh.Mishra@Sun.COM 	    &r->r_buf_dma[slot].handle);
26089865SSaurabh.Mishra@Sun.COM 
26099865SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
26109865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
26119865SSaurabh.Mishra@Sun.COM 		    " alloc_handle failed");
26129865SSaurabh.Mishra@Sun.COM 		goto fail0;
26139865SSaurabh.Mishra@Sun.COM 	}
26149865SSaurabh.Mishra@Sun.COM 
26159865SSaurabh.Mishra@Sun.COM 	err = ddi_dma_mem_alloc(r->r_buf_dma[slot].handle,
26169865SSaurabh.Mishra@Sun.COM 	    r->r_buf_len, &bfe_buf_attr, DDI_DMA_STREAMING,
26179865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL, &r->r_buf_dma[slot].addr,
26189865SSaurabh.Mishra@Sun.COM 	    &r->r_buf_dma[slot].len,
26199865SSaurabh.Mishra@Sun.COM 	    &r->r_buf_dma[slot].acchdl);
26209865SSaurabh.Mishra@Sun.COM 
26219865SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
26229865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
26239865SSaurabh.Mishra@Sun.COM 		    " mem_alloc failed :%d", err);
26249865SSaurabh.Mishra@Sun.COM 		goto fail1;
26259865SSaurabh.Mishra@Sun.COM 	}
26269865SSaurabh.Mishra@Sun.COM 
26279865SSaurabh.Mishra@Sun.COM 	err = ddi_dma_addr_bind_handle(r->r_buf_dma[slot].handle,
26289865SSaurabh.Mishra@Sun.COM 	    NULL, r->r_buf_dma[slot].addr,
26299865SSaurabh.Mishra@Sun.COM 	    r->r_buf_dma[slot].len,
26309865SSaurabh.Mishra@Sun.COM 	    (DDI_DMA_RDWR | DDI_DMA_STREAMING),
26319865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL,
26329865SSaurabh.Mishra@Sun.COM 	    &r->r_buf_dma[slot].cookie,
26339865SSaurabh.Mishra@Sun.COM 	    &count);
26349865SSaurabh.Mishra@Sun.COM 
26359865SSaurabh.Mishra@Sun.COM 	if (err != DDI_DMA_MAPPED) {
26369865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
26379865SSaurabh.Mishra@Sun.COM 		    " bind_handle failed");
26389865SSaurabh.Mishra@Sun.COM 		goto fail2;
26399865SSaurabh.Mishra@Sun.COM 	}
26409865SSaurabh.Mishra@Sun.COM 
26419865SSaurabh.Mishra@Sun.COM 	if (count > 1) {
26429865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
26439865SSaurabh.Mishra@Sun.COM 		    " more than one DMA cookie");
26449865SSaurabh.Mishra@Sun.COM 		(void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle);
26459865SSaurabh.Mishra@Sun.COM 		goto fail2;
26469865SSaurabh.Mishra@Sun.COM 	}
26479865SSaurabh.Mishra@Sun.COM 
26489865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
26499865SSaurabh.Mishra@Sun.COM fail2:
26509865SSaurabh.Mishra@Sun.COM 	ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl);
26519865SSaurabh.Mishra@Sun.COM fail1:
26529865SSaurabh.Mishra@Sun.COM 	ddi_dma_free_handle(&r->r_buf_dma[slot].handle);
26539865SSaurabh.Mishra@Sun.COM fail0:
26549865SSaurabh.Mishra@Sun.COM 	return (DDI_FAILURE);
26559865SSaurabh.Mishra@Sun.COM }
26569865SSaurabh.Mishra@Sun.COM 
26579865SSaurabh.Mishra@Sun.COM static void
26589865SSaurabh.Mishra@Sun.COM bfe_ring_buf_free(bfe_ring_t *r, int slot)
26599865SSaurabh.Mishra@Sun.COM {
26609865SSaurabh.Mishra@Sun.COM 	if (r->r_buf_dma == NULL)
26619865SSaurabh.Mishra@Sun.COM 		return;
26629865SSaurabh.Mishra@Sun.COM 
26639865SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle);
26649865SSaurabh.Mishra@Sun.COM 	ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl);
26659865SSaurabh.Mishra@Sun.COM 	ddi_dma_free_handle(&r->r_buf_dma[slot].handle);
26669865SSaurabh.Mishra@Sun.COM }
26679865SSaurabh.Mishra@Sun.COM 
26689865SSaurabh.Mishra@Sun.COM static void
26699865SSaurabh.Mishra@Sun.COM bfe_buffer_free(bfe_ring_t *r)
26709865SSaurabh.Mishra@Sun.COM {
26719865SSaurabh.Mishra@Sun.COM 	int i;
26729865SSaurabh.Mishra@Sun.COM 
26739865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < r->r_ndesc; i++) {
26749865SSaurabh.Mishra@Sun.COM 		bfe_ring_buf_free(r, i);
26759865SSaurabh.Mishra@Sun.COM 	}
26769865SSaurabh.Mishra@Sun.COM }
26779865SSaurabh.Mishra@Sun.COM 
26789865SSaurabh.Mishra@Sun.COM static void
26799865SSaurabh.Mishra@Sun.COM bfe_ring_desc_free(bfe_ring_t *r)
26809865SSaurabh.Mishra@Sun.COM {
26819865SSaurabh.Mishra@Sun.COM 	(void) ddi_dma_unbind_handle(r->r_desc_dma_handle);
26829865SSaurabh.Mishra@Sun.COM 	ddi_dma_mem_free(&r->r_desc_acc_handle);
26839865SSaurabh.Mishra@Sun.COM 	ddi_dma_free_handle(&r->r_desc_dma_handle);
26849865SSaurabh.Mishra@Sun.COM 	kmem_free(r->r_buf_dma, r->r_ndesc * sizeof (bfe_dma_t));
26859865SSaurabh.Mishra@Sun.COM 
26869865SSaurabh.Mishra@Sun.COM 	r->r_buf_dma = NULL;
26879865SSaurabh.Mishra@Sun.COM 	r->r_desc = NULL;
26889865SSaurabh.Mishra@Sun.COM }
26899865SSaurabh.Mishra@Sun.COM 
26909865SSaurabh.Mishra@Sun.COM 
26919865SSaurabh.Mishra@Sun.COM static int
26929865SSaurabh.Mishra@Sun.COM bfe_ring_desc_alloc(bfe_t *bfe, bfe_ring_t *r, int d)
26939865SSaurabh.Mishra@Sun.COM {
26949865SSaurabh.Mishra@Sun.COM 	int err, i, fail = 0;
26959865SSaurabh.Mishra@Sun.COM 	caddr_t	ring;
26969865SSaurabh.Mishra@Sun.COM 	size_t	size_krnl = 0, size_dma = 0, ring_len = 0;
26979865SSaurabh.Mishra@Sun.COM 	ddi_dma_cookie_t cookie;
26989865SSaurabh.Mishra@Sun.COM 	uint_t	count = 0;
26999865SSaurabh.Mishra@Sun.COM 
27009865SSaurabh.Mishra@Sun.COM 	ASSERT(bfe != NULL);
27019865SSaurabh.Mishra@Sun.COM 
27029865SSaurabh.Mishra@Sun.COM 	size_krnl = r->r_ndesc * sizeof (bfe_dma_t);
27039865SSaurabh.Mishra@Sun.COM 	size_dma = r->r_ndesc * sizeof (bfe_desc_t);
27049865SSaurabh.Mishra@Sun.COM 	r->r_buf_dma = kmem_zalloc(size_krnl, KM_SLEEP);
27059865SSaurabh.Mishra@Sun.COM 
27069865SSaurabh.Mishra@Sun.COM 
27079865SSaurabh.Mishra@Sun.COM 	err = ddi_dma_alloc_handle(bfe->bfe_dip, &bfe_dma_attr_desc,
27089865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL, &r->r_desc_dma_handle);
27099865SSaurabh.Mishra@Sun.COM 
27109865SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
27119865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
27129865SSaurabh.Mishra@Sun.COM 		    " ddi_dma_alloc_handle()");
27139865SSaurabh.Mishra@Sun.COM 		kmem_free(r->r_buf_dma, size_krnl);
27149865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
27159865SSaurabh.Mishra@Sun.COM 	}
27169865SSaurabh.Mishra@Sun.COM 
27179865SSaurabh.Mishra@Sun.COM 
27189865SSaurabh.Mishra@Sun.COM 	err = ddi_dma_mem_alloc(r->r_desc_dma_handle,
27199865SSaurabh.Mishra@Sun.COM 	    size_dma, &bfe_buf_attr,
27209865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
27219865SSaurabh.Mishra@Sun.COM 	    &ring, &ring_len, &r->r_desc_acc_handle);
27229865SSaurabh.Mishra@Sun.COM 
27239865SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
27249865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
27259865SSaurabh.Mishra@Sun.COM 		    " ddi_dma_mem_alloc()");
27269865SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&r->r_desc_dma_handle);
27279865SSaurabh.Mishra@Sun.COM 		kmem_free(r->r_buf_dma, size_krnl);
27289865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
27299865SSaurabh.Mishra@Sun.COM 	}
27309865SSaurabh.Mishra@Sun.COM 
27319865SSaurabh.Mishra@Sun.COM 	err = ddi_dma_addr_bind_handle(r->r_desc_dma_handle,
27329865SSaurabh.Mishra@Sun.COM 	    NULL, ring, ring_len,
27339865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
27349865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_SLEEP, NULL,
27359865SSaurabh.Mishra@Sun.COM 	    &cookie, &count);
27369865SSaurabh.Mishra@Sun.COM 
27379865SSaurabh.Mishra@Sun.COM 	if (err != DDI_SUCCESS) {
27389865SSaurabh.Mishra@Sun.COM 		bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
27399865SSaurabh.Mishra@Sun.COM 		    " ddi_dma_addr_bind_handle()");
27409865SSaurabh.Mishra@Sun.COM 		ddi_dma_mem_free(&r->r_desc_acc_handle);
27419865SSaurabh.Mishra@Sun.COM 		ddi_dma_free_handle(&r->r_desc_dma_handle);
27429865SSaurabh.Mishra@Sun.COM 		kmem_free(r->r_buf_dma, size_krnl);
27439865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
27449865SSaurabh.Mishra@Sun.COM 	}
27459865SSaurabh.Mishra@Sun.COM 
27469865SSaurabh.Mishra@Sun.COM 	/*
27479865SSaurabh.Mishra@Sun.COM 	 * We don't want to have multiple cookies. Descriptor should be
27489865SSaurabh.Mishra@Sun.COM 	 * aligned to PAGESIZE boundary.
27499865SSaurabh.Mishra@Sun.COM 	 */
27509865SSaurabh.Mishra@Sun.COM 	ASSERT(count == 1);
27519865SSaurabh.Mishra@Sun.COM 
27529865SSaurabh.Mishra@Sun.COM 	/* The actual descriptor for the ring */
27539865SSaurabh.Mishra@Sun.COM 	r->r_desc_len = ring_len;
27549865SSaurabh.Mishra@Sun.COM 	r->r_desc_cookie = cookie;
27559865SSaurabh.Mishra@Sun.COM 
27569865SSaurabh.Mishra@Sun.COM 	r->r_desc = (void *)ring;
27579865SSaurabh.Mishra@Sun.COM 
27589865SSaurabh.Mishra@Sun.COM 	bzero(r->r_desc, size_dma);
27599865SSaurabh.Mishra@Sun.COM 	bzero(r->r_desc, ring_len);
27609865SSaurabh.Mishra@Sun.COM 
27619865SSaurabh.Mishra@Sun.COM 	/* For each descriptor, allocate a DMA buffer */
27629865SSaurabh.Mishra@Sun.COM 	fail = 0;
27639865SSaurabh.Mishra@Sun.COM 	for (i = 0; i < r->r_ndesc; i++) {
27649865SSaurabh.Mishra@Sun.COM 		if (bfe_ring_buf_alloc(bfe, r, i, d) != DDI_SUCCESS) {
27659865SSaurabh.Mishra@Sun.COM 			i--;
27669865SSaurabh.Mishra@Sun.COM 			fail = 1;
27679865SSaurabh.Mishra@Sun.COM 			break;
27689865SSaurabh.Mishra@Sun.COM 		}
27699865SSaurabh.Mishra@Sun.COM 	}
27709865SSaurabh.Mishra@Sun.COM 
27719865SSaurabh.Mishra@Sun.COM 	if (fail) {
27729865SSaurabh.Mishra@Sun.COM 		while (i-- >= 0) {
27739865SSaurabh.Mishra@Sun.COM 			bfe_ring_buf_free(r, i);
27749865SSaurabh.Mishra@Sun.COM 		}
27759865SSaurabh.Mishra@Sun.COM 
27769865SSaurabh.Mishra@Sun.COM 		/* We don't need the descriptor anymore */
27779865SSaurabh.Mishra@Sun.COM 		bfe_ring_desc_free(r);
27789865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
27799865SSaurabh.Mishra@Sun.COM 	}
27809865SSaurabh.Mishra@Sun.COM 
27819865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
27829865SSaurabh.Mishra@Sun.COM }
27839865SSaurabh.Mishra@Sun.COM 
27849865SSaurabh.Mishra@Sun.COM static int
27859865SSaurabh.Mishra@Sun.COM bfe_rings_alloc(bfe_t *bfe)
27869865SSaurabh.Mishra@Sun.COM {
27879865SSaurabh.Mishra@Sun.COM 	/* TX */
27889865SSaurabh.Mishra@Sun.COM 	mutex_init(&bfe->bfe_tx_ring.r_lock, NULL, MUTEX_DRIVER, NULL);
27899865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_ring.r_lockp = &bfe->bfe_tx_ring.r_lock;
27909865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) +
27919865SSaurabh.Mishra@Sun.COM 	    VLAN_TAGSZ + ETHERFCSL;
27929865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_ring.r_ndesc = TX_NUM_DESC;
27939865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_ring.r_bfe = bfe;
27949865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_ring.r_avail_desc = TX_NUM_DESC;
27959865SSaurabh.Mishra@Sun.COM 
27969865SSaurabh.Mishra@Sun.COM 	/* RX */
27979865SSaurabh.Mishra@Sun.COM 	mutex_init(&bfe->bfe_rx_ring.r_lock, NULL, MUTEX_DRIVER, NULL);
27989865SSaurabh.Mishra@Sun.COM 	bfe->bfe_rx_ring.r_lockp = &bfe->bfe_rx_ring.r_lock;
27999865SSaurabh.Mishra@Sun.COM 	bfe->bfe_rx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) +
28009865SSaurabh.Mishra@Sun.COM 	    VLAN_TAGSZ + ETHERFCSL + RX_HEAD_ROOM;
28019865SSaurabh.Mishra@Sun.COM 	bfe->bfe_rx_ring.r_ndesc = RX_NUM_DESC;
28029865SSaurabh.Mishra@Sun.COM 	bfe->bfe_rx_ring.r_bfe = bfe;
28039865SSaurabh.Mishra@Sun.COM 	bfe->bfe_rx_ring.r_avail_desc = RX_NUM_DESC;
28049865SSaurabh.Mishra@Sun.COM 
28059865SSaurabh.Mishra@Sun.COM 	/* Allocate TX Ring */
28069865SSaurabh.Mishra@Sun.COM 	if (bfe_ring_desc_alloc(bfe, &bfe->bfe_tx_ring,
28079865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_WRITE) != DDI_SUCCESS)
28089865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
28099865SSaurabh.Mishra@Sun.COM 
28109865SSaurabh.Mishra@Sun.COM 	/* Allocate RX Ring */
28119865SSaurabh.Mishra@Sun.COM 	if (bfe_ring_desc_alloc(bfe, &bfe->bfe_rx_ring,
28129865SSaurabh.Mishra@Sun.COM 	    DDI_DMA_READ) != DDI_SUCCESS) {
28139865SSaurabh.Mishra@Sun.COM 		cmn_err(CE_NOTE, "RX ring allocation failed");
28149865SSaurabh.Mishra@Sun.COM 		bfe_ring_desc_free(&bfe->bfe_tx_ring);
28159865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
28169865SSaurabh.Mishra@Sun.COM 	}
28179865SSaurabh.Mishra@Sun.COM 
28189865SSaurabh.Mishra@Sun.COM 	bfe->bfe_tx_ring.r_flags = BFE_RING_ALLOCATED;
28199865SSaurabh.Mishra@Sun.COM 	bfe->bfe_rx_ring.r_flags = BFE_RING_ALLOCATED;
28209865SSaurabh.Mishra@Sun.COM 
28219865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
28229865SSaurabh.Mishra@Sun.COM }
28239865SSaurabh.Mishra@Sun.COM 
28249865SSaurabh.Mishra@Sun.COM static int
28259865SSaurabh.Mishra@Sun.COM bfe_resume(dev_info_t *dip)
28269865SSaurabh.Mishra@Sun.COM {
28279865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe;
28289865SSaurabh.Mishra@Sun.COM 	int err = DDI_SUCCESS;
28299865SSaurabh.Mishra@Sun.COM 
28309865SSaurabh.Mishra@Sun.COM 	if ((bfe = ddi_get_driver_private(dip)) == NULL) {
28319865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Unexpected error (no driver private data)"
28329865SSaurabh.Mishra@Sun.COM 		    " while resume");
28339865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
28349865SSaurabh.Mishra@Sun.COM 	}
28359865SSaurabh.Mishra@Sun.COM 
28369865SSaurabh.Mishra@Sun.COM 	/*
28379865SSaurabh.Mishra@Sun.COM 	 * Grab all the locks first.
28389865SSaurabh.Mishra@Sun.COM 	 */
28399865SSaurabh.Mishra@Sun.COM 	bfe_grab_locks(bfe);
28409865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_RESUME;
28419865SSaurabh.Mishra@Sun.COM 
28429865SSaurabh.Mishra@Sun.COM 	bfe_init_vars(bfe);
28439865SSaurabh.Mishra@Sun.COM 	/* PHY will also start running */
28449865SSaurabh.Mishra@Sun.COM 	bfe_chip_reset(bfe);
28459865SSaurabh.Mishra@Sun.COM 	if (bfe_chip_start(bfe) == DDI_FAILURE) {
28469865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Could not resume chip");
28479865SSaurabh.Mishra@Sun.COM 		err = DDI_FAILURE;
28489865SSaurabh.Mishra@Sun.COM 	}
284910591SSaurabh.Mishra@Sun.COM 
28509865SSaurabh.Mishra@Sun.COM 	bfe_release_locks(bfe);
285110591SSaurabh.Mishra@Sun.COM 
285210591SSaurabh.Mishra@Sun.COM 	if (err == DDI_SUCCESS)
285310591SSaurabh.Mishra@Sun.COM 		mac_tx_update(bfe->bfe_machdl);
285410591SSaurabh.Mishra@Sun.COM 
28559865SSaurabh.Mishra@Sun.COM 	return (err);
28569865SSaurabh.Mishra@Sun.COM }
28579865SSaurabh.Mishra@Sun.COM 
28589865SSaurabh.Mishra@Sun.COM static int
28599865SSaurabh.Mishra@Sun.COM bfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
28609865SSaurabh.Mishra@Sun.COM {
28619865SSaurabh.Mishra@Sun.COM 	int	unit;
28629865SSaurabh.Mishra@Sun.COM 	bfe_t	*bfe;
28639865SSaurabh.Mishra@Sun.COM 	mac_register_t	*macreg;
28649865SSaurabh.Mishra@Sun.COM 	int	ret;
28659865SSaurabh.Mishra@Sun.COM 
28669865SSaurabh.Mishra@Sun.COM 	switch (cmd) {
28679865SSaurabh.Mishra@Sun.COM 	case DDI_RESUME:
28689865SSaurabh.Mishra@Sun.COM 		return (bfe_resume(dip));
28699865SSaurabh.Mishra@Sun.COM 
28709865SSaurabh.Mishra@Sun.COM 	case DDI_ATTACH:
28719865SSaurabh.Mishra@Sun.COM 		break;
28729865SSaurabh.Mishra@Sun.COM 
28739865SSaurabh.Mishra@Sun.COM 	default:
28749865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
28759865SSaurabh.Mishra@Sun.COM 	}
28769865SSaurabh.Mishra@Sun.COM 
28779865SSaurabh.Mishra@Sun.COM 
28789865SSaurabh.Mishra@Sun.COM 	unit = ddi_get_instance(dip);
28799865SSaurabh.Mishra@Sun.COM 
28809865SSaurabh.Mishra@Sun.COM 	bfe = kmem_zalloc(sizeof (bfe_t), KM_SLEEP);
28819865SSaurabh.Mishra@Sun.COM 	bfe->bfe_dip = dip;
28829865SSaurabh.Mishra@Sun.COM 	bfe->bfe_unit = unit;
28839865SSaurabh.Mishra@Sun.COM 
28849865SSaurabh.Mishra@Sun.COM 	if (pci_config_setup(dip, &bfe->bfe_conf_handle) != DDI_SUCCESS) {
28859865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "pci_config_setup failed");
28869865SSaurabh.Mishra@Sun.COM 		goto fail0;
28879865SSaurabh.Mishra@Sun.COM 	}
28889865SSaurabh.Mishra@Sun.COM 
28899865SSaurabh.Mishra@Sun.COM 	/*
28909865SSaurabh.Mishra@Sun.COM 	 * Enable IO space, Bus Master and Memory Space accessess.
28919865SSaurabh.Mishra@Sun.COM 	 */
28929865SSaurabh.Mishra@Sun.COM 	ret = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_COMM);
28939865SSaurabh.Mishra@Sun.COM 	pci_config_put16(bfe->bfe_conf_handle, PCI_CONF_COMM,
28949865SSaurabh.Mishra@Sun.COM 	    PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | ret);
28959865SSaurabh.Mishra@Sun.COM 
28969865SSaurabh.Mishra@Sun.COM 	ddi_set_driver_private(dip, bfe);
28979865SSaurabh.Mishra@Sun.COM 
28989865SSaurabh.Mishra@Sun.COM 	/* Identify hardware */
28999865SSaurabh.Mishra@Sun.COM 	if (bfe_identify_hardware(bfe) == BFE_FAILURE) {
29009865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Could not identify device");
29019865SSaurabh.Mishra@Sun.COM 		goto fail1;
29029865SSaurabh.Mishra@Sun.COM 	}
29039865SSaurabh.Mishra@Sun.COM 
29049865SSaurabh.Mishra@Sun.COM 	if (bfe_regs_map(bfe) != DDI_SUCCESS) {
29059865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Could not map device registers");
29069865SSaurabh.Mishra@Sun.COM 		goto fail1;
29079865SSaurabh.Mishra@Sun.COM 	}
29089865SSaurabh.Mishra@Sun.COM 
29099865SSaurabh.Mishra@Sun.COM 	(void) bfe_get_chip_config(bfe);
29109865SSaurabh.Mishra@Sun.COM 
29119865SSaurabh.Mishra@Sun.COM 	/*
29129865SSaurabh.Mishra@Sun.COM 	 * Register with MAC layer
29139865SSaurabh.Mishra@Sun.COM 	 */
29149865SSaurabh.Mishra@Sun.COM 	if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
29159865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "mac_alloc() failed");
29169865SSaurabh.Mishra@Sun.COM 		goto fail2;
29179865SSaurabh.Mishra@Sun.COM 	}
29189865SSaurabh.Mishra@Sun.COM 
29199865SSaurabh.Mishra@Sun.COM 	macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
29209865SSaurabh.Mishra@Sun.COM 	macreg->m_driver = bfe;
29219865SSaurabh.Mishra@Sun.COM 	macreg->m_dip = dip;
29229865SSaurabh.Mishra@Sun.COM 	macreg->m_instance = unit;
29239865SSaurabh.Mishra@Sun.COM 	macreg->m_src_addr = bfe->bfe_ether_addr;
29249865SSaurabh.Mishra@Sun.COM 	macreg->m_callbacks = &bfe_mac_callbacks;
29259865SSaurabh.Mishra@Sun.COM 	macreg->m_min_sdu = 0;
29269865SSaurabh.Mishra@Sun.COM 	macreg->m_max_sdu = ETHERMTU;
29279865SSaurabh.Mishra@Sun.COM 	macreg->m_margin = VLAN_TAGSZ;
29289865SSaurabh.Mishra@Sun.COM 
29299865SSaurabh.Mishra@Sun.COM 	if ((ret = mac_register(macreg, &bfe->bfe_machdl)) != 0) {
29309865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "mac_register() failed with %d error", ret);
29319865SSaurabh.Mishra@Sun.COM 		mac_free(macreg);
29329865SSaurabh.Mishra@Sun.COM 		goto fail2;
29339865SSaurabh.Mishra@Sun.COM 	}
29349865SSaurabh.Mishra@Sun.COM 
29359865SSaurabh.Mishra@Sun.COM 	mac_free(macreg);
29369865SSaurabh.Mishra@Sun.COM 
29379865SSaurabh.Mishra@Sun.COM 	rw_init(&bfe->bfe_rwlock, NULL, RW_DRIVER,
29389865SSaurabh.Mishra@Sun.COM 	    DDI_INTR_PRI(bfe->bfe_intrpri));
29399865SSaurabh.Mishra@Sun.COM 
29409865SSaurabh.Mishra@Sun.COM 	if (bfe_add_intr(bfe) != DDI_SUCCESS) {
29419865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Could not add interrupt");
29429865SSaurabh.Mishra@Sun.COM 		goto fail3;
29439865SSaurabh.Mishra@Sun.COM 	}
29449865SSaurabh.Mishra@Sun.COM 
29459865SSaurabh.Mishra@Sun.COM 	if (bfe_rings_alloc(bfe) != DDI_SUCCESS) {
29469865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Could not allocate TX/RX Ring");
29479865SSaurabh.Mishra@Sun.COM 		goto fail4;
29489865SSaurabh.Mishra@Sun.COM 	}
29499865SSaurabh.Mishra@Sun.COM 
29509865SSaurabh.Mishra@Sun.COM 	/* Init and then reset the chip */
29519865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_action = 0;
29529865SSaurabh.Mishra@Sun.COM 	bfe_init_vars(bfe);
29539865SSaurabh.Mishra@Sun.COM 
29549865SSaurabh.Mishra@Sun.COM 	/* PHY will also start running */
29559865SSaurabh.Mishra@Sun.COM 	bfe_chip_reset(bfe);
29569865SSaurabh.Mishra@Sun.COM 
29579865SSaurabh.Mishra@Sun.COM 	/*
29589865SSaurabh.Mishra@Sun.COM 	 * Even though we enable the interrupts here but chip's interrupt
29599865SSaurabh.Mishra@Sun.COM 	 * is not enabled yet. It will be enabled once we plumb the interface.
29609865SSaurabh.Mishra@Sun.COM 	 */
29619865SSaurabh.Mishra@Sun.COM 	if (ddi_intr_enable(bfe->bfe_intrhdl) != DDI_SUCCESS) {
29629865SSaurabh.Mishra@Sun.COM 		bfe_error(dip, "Could not enable interrupt");
29639865SSaurabh.Mishra@Sun.COM 		goto fail4;
29649865SSaurabh.Mishra@Sun.COM 	}
29659865SSaurabh.Mishra@Sun.COM 
29669865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
29679865SSaurabh.Mishra@Sun.COM 
29689865SSaurabh.Mishra@Sun.COM fail4:
29699865SSaurabh.Mishra@Sun.COM 	bfe_remove_intr(bfe);
29709865SSaurabh.Mishra@Sun.COM fail3:
297111387SSurya.Prakki@Sun.COM 	(void) mac_unregister(bfe->bfe_machdl);
29729865SSaurabh.Mishra@Sun.COM fail2:
29739865SSaurabh.Mishra@Sun.COM 	bfe_unmap_regs(bfe);
29749865SSaurabh.Mishra@Sun.COM fail1:
29759865SSaurabh.Mishra@Sun.COM 	pci_config_teardown(&bfe->bfe_conf_handle);
29769865SSaurabh.Mishra@Sun.COM fail0:
29779865SSaurabh.Mishra@Sun.COM 	kmem_free(bfe, sizeof (bfe_t));
29789865SSaurabh.Mishra@Sun.COM 	return (DDI_FAILURE);
29799865SSaurabh.Mishra@Sun.COM }
29809865SSaurabh.Mishra@Sun.COM 
29819865SSaurabh.Mishra@Sun.COM static int
29829865SSaurabh.Mishra@Sun.COM bfe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
29839865SSaurabh.Mishra@Sun.COM {
29849865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe;
29859865SSaurabh.Mishra@Sun.COM 
29869865SSaurabh.Mishra@Sun.COM 	bfe = ddi_get_driver_private(devinfo);
29879865SSaurabh.Mishra@Sun.COM 
29889865SSaurabh.Mishra@Sun.COM 	switch (cmd) {
29899865SSaurabh.Mishra@Sun.COM 	case DDI_DETACH:
29909865SSaurabh.Mishra@Sun.COM 		/*
29919865SSaurabh.Mishra@Sun.COM 		 * We need to stop the timer before grabbing locks otherwise
29929865SSaurabh.Mishra@Sun.COM 		 * we can land-up in deadlock with untimeout.
29939865SSaurabh.Mishra@Sun.COM 		 */
29949865SSaurabh.Mishra@Sun.COM 		bfe_stop_timer(bfe);
29959865SSaurabh.Mishra@Sun.COM 
29969865SSaurabh.Mishra@Sun.COM 		/*
29979865SSaurabh.Mishra@Sun.COM 		 * First unregister with MAC layer before stopping DMA
29989865SSaurabh.Mishra@Sun.COM 		 * engine.
29999865SSaurabh.Mishra@Sun.COM 		 */
30009865SSaurabh.Mishra@Sun.COM 		if (mac_unregister(bfe->bfe_machdl) != DDI_SUCCESS)
30019865SSaurabh.Mishra@Sun.COM 			return (DDI_FAILURE);
30029865SSaurabh.Mishra@Sun.COM 
30039865SSaurabh.Mishra@Sun.COM 		bfe->bfe_machdl = NULL;
30049865SSaurabh.Mishra@Sun.COM 
30059865SSaurabh.Mishra@Sun.COM 		/*
30069865SSaurabh.Mishra@Sun.COM 		 * Quiesce the chip first.
30079865SSaurabh.Mishra@Sun.COM 		 */
30089865SSaurabh.Mishra@Sun.COM 		bfe_grab_locks(bfe);
30099865SSaurabh.Mishra@Sun.COM 		bfe_chip_halt(bfe);
30109865SSaurabh.Mishra@Sun.COM 		bfe_stop_phy(bfe);
30119865SSaurabh.Mishra@Sun.COM 		bfe_release_locks(bfe);
30129865SSaurabh.Mishra@Sun.COM 
30139865SSaurabh.Mishra@Sun.COM 		(void) ddi_intr_disable(bfe->bfe_intrhdl);
30149865SSaurabh.Mishra@Sun.COM 
30159865SSaurabh.Mishra@Sun.COM 		/* Make sure timer is gone. */
30169865SSaurabh.Mishra@Sun.COM 		bfe_stop_timer(bfe);
30179865SSaurabh.Mishra@Sun.COM 
30189865SSaurabh.Mishra@Sun.COM 		/*
30199865SSaurabh.Mishra@Sun.COM 		 * Free the DMA resources for buffer and then descriptors
30209865SSaurabh.Mishra@Sun.COM 		 */
30219865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_tx_ring.r_flags == BFE_RING_ALLOCATED) {
30229865SSaurabh.Mishra@Sun.COM 			/* TX */
30239865SSaurabh.Mishra@Sun.COM 			bfe_buffer_free(&bfe->bfe_tx_ring);
30249865SSaurabh.Mishra@Sun.COM 			bfe_ring_desc_free(&bfe->bfe_tx_ring);
30259865SSaurabh.Mishra@Sun.COM 		}
30269865SSaurabh.Mishra@Sun.COM 
30279865SSaurabh.Mishra@Sun.COM 		if (bfe->bfe_rx_ring.r_flags == BFE_RING_ALLOCATED) {
30289865SSaurabh.Mishra@Sun.COM 			/* RX */
30299865SSaurabh.Mishra@Sun.COM 			bfe_buffer_free(&bfe->bfe_rx_ring);
30309865SSaurabh.Mishra@Sun.COM 			bfe_ring_desc_free(&bfe->bfe_rx_ring);
30319865SSaurabh.Mishra@Sun.COM 		}
30329865SSaurabh.Mishra@Sun.COM 
30339865SSaurabh.Mishra@Sun.COM 		bfe_remove_intr(bfe);
30349865SSaurabh.Mishra@Sun.COM 		bfe_unmap_regs(bfe);
30359865SSaurabh.Mishra@Sun.COM 		pci_config_teardown(&bfe->bfe_conf_handle);
30369865SSaurabh.Mishra@Sun.COM 
30379865SSaurabh.Mishra@Sun.COM 		mutex_destroy(&bfe->bfe_tx_ring.r_lock);
30389865SSaurabh.Mishra@Sun.COM 		mutex_destroy(&bfe->bfe_rx_ring.r_lock);
30399865SSaurabh.Mishra@Sun.COM 		rw_destroy(&bfe->bfe_rwlock);
30409865SSaurabh.Mishra@Sun.COM 
30419865SSaurabh.Mishra@Sun.COM 		kmem_free(bfe, sizeof (bfe_t));
30429865SSaurabh.Mishra@Sun.COM 
30439865SSaurabh.Mishra@Sun.COM 		ddi_set_driver_private(devinfo, NULL);
30449865SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
30459865SSaurabh.Mishra@Sun.COM 
30469865SSaurabh.Mishra@Sun.COM 	case DDI_SUSPEND:
30479865SSaurabh.Mishra@Sun.COM 		/*
30489865SSaurabh.Mishra@Sun.COM 		 * We need to stop the timer before grabbing locks otherwise
30499865SSaurabh.Mishra@Sun.COM 		 * we can land-up in deadlock with untimeout.
30509865SSaurabh.Mishra@Sun.COM 		 */
30519865SSaurabh.Mishra@Sun.COM 		bfe_stop_timer(bfe);
30529865SSaurabh.Mishra@Sun.COM 
30539865SSaurabh.Mishra@Sun.COM 		/*
30549865SSaurabh.Mishra@Sun.COM 		 * Grab all the locks first.
30559865SSaurabh.Mishra@Sun.COM 		 */
30569865SSaurabh.Mishra@Sun.COM 		bfe_grab_locks(bfe);
30579865SSaurabh.Mishra@Sun.COM 		bfe_chip_halt(bfe);
30589865SSaurabh.Mishra@Sun.COM 		bfe_stop_phy(bfe);
30599865SSaurabh.Mishra@Sun.COM 		bfe->bfe_chip_state = BFE_CHIP_SUSPENDED;
30609865SSaurabh.Mishra@Sun.COM 		bfe_release_locks(bfe);
30619865SSaurabh.Mishra@Sun.COM 
30629865SSaurabh.Mishra@Sun.COM 		return (DDI_SUCCESS);
30639865SSaurabh.Mishra@Sun.COM 
30649865SSaurabh.Mishra@Sun.COM 	default:
30659865SSaurabh.Mishra@Sun.COM 		return (DDI_FAILURE);
30669865SSaurabh.Mishra@Sun.COM 	}
30679865SSaurabh.Mishra@Sun.COM }
30689865SSaurabh.Mishra@Sun.COM 
30699865SSaurabh.Mishra@Sun.COM /*
30709865SSaurabh.Mishra@Sun.COM  * Quiesce the card for fast reboot
30719865SSaurabh.Mishra@Sun.COM  */
30729865SSaurabh.Mishra@Sun.COM int
30739865SSaurabh.Mishra@Sun.COM bfe_quiesce(dev_info_t *dev_info)
30749865SSaurabh.Mishra@Sun.COM {
30759865SSaurabh.Mishra@Sun.COM 	bfe_t *bfe;
30769865SSaurabh.Mishra@Sun.COM 
30779865SSaurabh.Mishra@Sun.COM 	bfe = ddi_get_driver_private(dev_info);
30789865SSaurabh.Mishra@Sun.COM 
30799865SSaurabh.Mishra@Sun.COM 	bfe_chip_halt(bfe);
30809865SSaurabh.Mishra@Sun.COM 	bfe_stop_phy(bfe);
30819865SSaurabh.Mishra@Sun.COM 	bfe->bfe_chip_state = BFE_CHIP_QUIESCED;
30829865SSaurabh.Mishra@Sun.COM 
30839865SSaurabh.Mishra@Sun.COM 	return (DDI_SUCCESS);
30849865SSaurabh.Mishra@Sun.COM }
30859865SSaurabh.Mishra@Sun.COM 
30869865SSaurabh.Mishra@Sun.COM static struct cb_ops bfe_cb_ops = {
30879865SSaurabh.Mishra@Sun.COM 	nulldev,		/* cb_open */
30889865SSaurabh.Mishra@Sun.COM 	nulldev,		/* cb_close */
30899865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_strategy */
30909865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_print */
30919865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_dump */
30929865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_read */
30939865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_write */
30949865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_ioctl */
30959865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_devmap */
30969865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_mmap */
30979865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_segmap */
30989865SSaurabh.Mishra@Sun.COM 	nochpoll,		/* cb_chpoll */
30999865SSaurabh.Mishra@Sun.COM 	ddi_prop_op,		/* cb_prop_op */
31009865SSaurabh.Mishra@Sun.COM 	NULL,			/* cb_stream */
31019865SSaurabh.Mishra@Sun.COM 	D_MP | D_HOTPLUG,	/* cb_flag */
31029865SSaurabh.Mishra@Sun.COM 	CB_REV,			/* cb_rev */
31039865SSaurabh.Mishra@Sun.COM 	nodev,			/* cb_aread */
31049865SSaurabh.Mishra@Sun.COM 	nodev			/* cb_awrite */
31059865SSaurabh.Mishra@Sun.COM };
31069865SSaurabh.Mishra@Sun.COM 
31079865SSaurabh.Mishra@Sun.COM static struct dev_ops bfe_dev_ops = {
31089865SSaurabh.Mishra@Sun.COM 	DEVO_REV,	/* devo_rev */
31099865SSaurabh.Mishra@Sun.COM 	0,		/* devo_refcnt */
31109865SSaurabh.Mishra@Sun.COM 	NULL,		/* devo_getinfo */
31119865SSaurabh.Mishra@Sun.COM 	nulldev,	/* devo_identify */
31129865SSaurabh.Mishra@Sun.COM 	nulldev,	/* devo_probe */
31139865SSaurabh.Mishra@Sun.COM 	bfe_attach,	/* devo_attach */
31149865SSaurabh.Mishra@Sun.COM 	bfe_detach,	/* devo_detach */
31159865SSaurabh.Mishra@Sun.COM 	nodev,		/* devo_reset */
31169865SSaurabh.Mishra@Sun.COM 	&bfe_cb_ops,	/* devo_cb_ops */
31179865SSaurabh.Mishra@Sun.COM 	NULL,		/* devo_bus_ops */
31189865SSaurabh.Mishra@Sun.COM 	ddi_power,	/* devo_power */
31199865SSaurabh.Mishra@Sun.COM 	bfe_quiesce	/* devo_quiesce */
31209865SSaurabh.Mishra@Sun.COM };
31219865SSaurabh.Mishra@Sun.COM 
31229865SSaurabh.Mishra@Sun.COM static struct modldrv bfe_modldrv = {
31239865SSaurabh.Mishra@Sun.COM 	&mod_driverops,
31249865SSaurabh.Mishra@Sun.COM 	bfe_ident,
31259865SSaurabh.Mishra@Sun.COM 	&bfe_dev_ops
31269865SSaurabh.Mishra@Sun.COM };
31279865SSaurabh.Mishra@Sun.COM 
31289865SSaurabh.Mishra@Sun.COM static struct modlinkage modlinkage = {
31299865SSaurabh.Mishra@Sun.COM 	MODREV_1, (void *)&bfe_modldrv, NULL
31309865SSaurabh.Mishra@Sun.COM };
31319865SSaurabh.Mishra@Sun.COM 
31329865SSaurabh.Mishra@Sun.COM int
31339865SSaurabh.Mishra@Sun.COM _info(struct modinfo *modinfop)
31349865SSaurabh.Mishra@Sun.COM {
31359865SSaurabh.Mishra@Sun.COM 	return (mod_info(&modlinkage, modinfop));
31369865SSaurabh.Mishra@Sun.COM }
31379865SSaurabh.Mishra@Sun.COM 
31389865SSaurabh.Mishra@Sun.COM int
31399865SSaurabh.Mishra@Sun.COM _init(void)
31409865SSaurabh.Mishra@Sun.COM {
31419865SSaurabh.Mishra@Sun.COM 	int	status;
31429865SSaurabh.Mishra@Sun.COM 
31439865SSaurabh.Mishra@Sun.COM 	mac_init_ops(&bfe_dev_ops, MODULE_NAME);
31449865SSaurabh.Mishra@Sun.COM 	status = mod_install(&modlinkage);
31459865SSaurabh.Mishra@Sun.COM 	if (status == DDI_FAILURE)
31469865SSaurabh.Mishra@Sun.COM 		mac_fini_ops(&bfe_dev_ops);
31479865SSaurabh.Mishra@Sun.COM 	return (status);
31489865SSaurabh.Mishra@Sun.COM }
31499865SSaurabh.Mishra@Sun.COM 
31509865SSaurabh.Mishra@Sun.COM int
31519865SSaurabh.Mishra@Sun.COM _fini(void)
31529865SSaurabh.Mishra@Sun.COM {
31539865SSaurabh.Mishra@Sun.COM 	int status;
31549865SSaurabh.Mishra@Sun.COM 
31559865SSaurabh.Mishra@Sun.COM 	status = mod_remove(&modlinkage);
31569865SSaurabh.Mishra@Sun.COM 	if (status == 0) {
31579865SSaurabh.Mishra@Sun.COM 		mac_fini_ops(&bfe_dev_ops);
31589865SSaurabh.Mishra@Sun.COM 	}
31599865SSaurabh.Mishra@Sun.COM 	return (status);
31609865SSaurabh.Mishra@Sun.COM }
3161