xref: /illumos-gate/usr/src/uts/common/io/bfe/bfe.c (revision 41be0ab3)
1dd52495fSSaurabh Misra /*
2dd52495fSSaurabh Misra  * CDDL HEADER START
3dd52495fSSaurabh Misra  *
4dd52495fSSaurabh Misra  * The contents of this file are subject to the terms of the
5dd52495fSSaurabh Misra  * Common Development and Distribution License (the "License").
6dd52495fSSaurabh Misra  * You may not use this file except in compliance with the License.
7dd52495fSSaurabh Misra  *
8dd52495fSSaurabh Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dd52495fSSaurabh Misra  * or http://www.opensolaris.org/os/licensing.
10dd52495fSSaurabh Misra  * See the License for the specific language governing permissions
11dd52495fSSaurabh Misra  * and limitations under the License.
12dd52495fSSaurabh Misra  *
13dd52495fSSaurabh Misra  * When distributing Covered Code, include this CDDL HEADER in each
14dd52495fSSaurabh Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dd52495fSSaurabh Misra  * If applicable, add the following below this CDDL HEADER, with the
16dd52495fSSaurabh Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17dd52495fSSaurabh Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18dd52495fSSaurabh Misra  *
19dd52495fSSaurabh Misra  * CDDL HEADER END
20dd52495fSSaurabh Misra  */
21dd52495fSSaurabh Misra 
22dd52495fSSaurabh Misra /*
237a0c1e29SCrisson Guanghao Hu  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24dd52495fSSaurabh Misra  */
25dd52495fSSaurabh Misra #include <sys/stream.h>
26dd52495fSSaurabh Misra #include <sys/strsun.h>
27dd52495fSSaurabh Misra #include <sys/stat.h>
28dd52495fSSaurabh Misra #include <sys/pci.h>
29dd52495fSSaurabh Misra #include <sys/modctl.h>
30dd52495fSSaurabh Misra #include <sys/kstat.h>
31dd52495fSSaurabh Misra #include <sys/ethernet.h>
32dd52495fSSaurabh Misra #include <sys/devops.h>
33dd52495fSSaurabh Misra #include <sys/debug.h>
34dd52495fSSaurabh Misra #include <sys/conf.h>
35dd52495fSSaurabh Misra #include <sys/sysmacros.h>
36dd52495fSSaurabh Misra #include <sys/dditypes.h>
37dd52495fSSaurabh Misra #include <sys/ddi.h>
38dd52495fSSaurabh Misra #include <sys/sunddi.h>
39dd52495fSSaurabh Misra #include <sys/miiregs.h>
40dd52495fSSaurabh Misra #include <sys/byteorder.h>
41dd52495fSSaurabh Misra #include <sys/cyclic.h>
42dd52495fSSaurabh Misra #include <sys/note.h>
43dd52495fSSaurabh Misra #include <sys/crc32.h>
44dd52495fSSaurabh Misra #include <sys/mac_provider.h>
45dd52495fSSaurabh Misra #include <sys/mac_ether.h>
46dd52495fSSaurabh Misra #include <sys/vlan.h>
47dd52495fSSaurabh Misra #include <sys/errno.h>
48dd52495fSSaurabh Misra #include <sys/sdt.h>
49dd52495fSSaurabh Misra #include <sys/strsubr.h>
50dd52495fSSaurabh Misra 
51dd52495fSSaurabh Misra #include "bfe.h"
52dd52495fSSaurabh Misra #include "bfe_hw.h"
53dd52495fSSaurabh Misra 
54dd52495fSSaurabh Misra 
55dd52495fSSaurabh Misra /*
56dd52495fSSaurabh Misra  * Broadcom BCM4401 chipsets use two rings :
57dd52495fSSaurabh Misra  *
58dd52495fSSaurabh Misra  * - One TX : For sending packets down the wire.
59dd52495fSSaurabh Misra  * - One RX : For receving packets.
60dd52495fSSaurabh Misra  *
61dd52495fSSaurabh Misra  * Each ring can have any number of descriptors (configured during attach).
62dd52495fSSaurabh Misra  * As of now we configure only 128 descriptor per ring (TX/RX). Each descriptor
63dd52495fSSaurabh Misra  * has address (desc_addr) and control (desc_ctl) which holds a DMA buffer for
64dd52495fSSaurabh Misra  * the packet and control information (like start/end of frame or end of table).
65dd52495fSSaurabh Misra  * The descriptor table is allocated first and then a DMA buffer (for a packet)
66dd52495fSSaurabh Misra  * is allocated and linked to each descriptor.
67dd52495fSSaurabh Misra  *
68dd52495fSSaurabh Misra  * Each descriptor entry is bfe_desc_t structure in bfe. During TX/RX
69dd52495fSSaurabh Misra  * interrupt, the stat register will point to current descriptor being
70dd52495fSSaurabh Misra  * processed.
71dd52495fSSaurabh Misra  *
72dd52495fSSaurabh Misra  * Here's an example of TX and RX ring :
73dd52495fSSaurabh Misra  *
74dd52495fSSaurabh Misra  * TX:
75dd52495fSSaurabh Misra  *
76dd52495fSSaurabh Misra  *   Base of the descriptor table is programmed using BFE_DMATX_CTRL control
77dd52495fSSaurabh Misra  *   register. Each 'addr' points to DMA buffer (or packet data buffer) to
78dd52495fSSaurabh Misra  *   be transmitted and 'ctl' has the length of the packet (usually MTU).
79dd52495fSSaurabh Misra  *
80dd52495fSSaurabh Misra  *  ----------------------|
81dd52495fSSaurabh Misra  *  | addr |Descriptor 0  |
82dd52495fSSaurabh Misra  *  | ctl  |              |
83dd52495fSSaurabh Misra  *  ----------------------|
84dd52495fSSaurabh Misra  *  | addr |Descriptor 1  |    SOF (start of the frame)
85dd52495fSSaurabh Misra  *  | ctl  |              |
86dd52495fSSaurabh Misra  *  ----------------------|
87dd52495fSSaurabh Misra  *  | ...  |Descriptor... |    EOF (end of the frame)
88dd52495fSSaurabh Misra  *  | ...  |              |
89dd52495fSSaurabh Misra  *  ----------------------|
90dd52495fSSaurabh Misra  *  | addr |Descritor 127 |
91dd52495fSSaurabh Misra  *  | ctl  | EOT          |    EOT (End of Table)
92dd52495fSSaurabh Misra  *  ----------------------|
93dd52495fSSaurabh Misra  *
94dd52495fSSaurabh Misra  * 'r_curr_desc'  : pointer to current descriptor which can be used to transmit
95dd52495fSSaurabh Misra  *                  a packet.
96dd52495fSSaurabh Misra  * 'r_avail_desc' : decremented whenever a packet is being sent.
97dd52495fSSaurabh Misra  * 'r_cons_desc'  : incremented whenever a packet is sent down the wire and
98dd52495fSSaurabh Misra  *                  notified by an interrupt to bfe driver.
99dd52495fSSaurabh Misra  *
100dd52495fSSaurabh Misra  * RX:
101dd52495fSSaurabh Misra  *
102dd52495fSSaurabh Misra  *   Base of the descriptor table is programmed using BFE_DMARX_CTRL control
103dd52495fSSaurabh Misra  *   register. Each 'addr' points to DMA buffer (or packet data buffer). 'ctl'
104dd52495fSSaurabh Misra  *   contains the size of the DMA buffer and all the DMA buffers are
105dd52495fSSaurabh Misra  *   pre-allocated during attach and hence the maxmium size of the packet is
106dd52495fSSaurabh Misra  *   also known (r_buf_len from the bfe_rint_t structure). During RX interrupt
107dd52495fSSaurabh Misra  *   the packet length is embedded in bfe_header_t which is added by the
108dd52495fSSaurabh Misra  *   chip in the beginning of the packet.
109dd52495fSSaurabh Misra  *
110dd52495fSSaurabh Misra  *  ----------------------|
111dd52495fSSaurabh Misra  *  | addr |Descriptor 0  |
112dd52495fSSaurabh Misra  *  | ctl  |              |
113dd52495fSSaurabh Misra  *  ----------------------|
114dd52495fSSaurabh Misra  *  | addr |Descriptor 1  |
115dd52495fSSaurabh Misra  *  | ctl  |              |
116dd52495fSSaurabh Misra  *  ----------------------|
117dd52495fSSaurabh Misra  *  | ...  |Descriptor... |
118dd52495fSSaurabh Misra  *  | ...  |              |
119dd52495fSSaurabh Misra  *  ----------------------|
120dd52495fSSaurabh Misra  *  | addr |Descriptor 127|
121dd52495fSSaurabh Misra  *  | ctl  | EOT          |    EOT (End of Table)
122dd52495fSSaurabh Misra  *  ----------------------|
123dd52495fSSaurabh Misra  *
124dd52495fSSaurabh Misra  * 'r_curr_desc'  : pointer to current descriptor while receving a packet.
125dd52495fSSaurabh Misra  *
126dd52495fSSaurabh Misra  */
127dd52495fSSaurabh Misra 
128dd52495fSSaurabh Misra #define	MODULE_NAME	"bfe"
129dd52495fSSaurabh Misra 
130dd52495fSSaurabh Misra /*
131dd52495fSSaurabh Misra  * Used for checking PHY (link state, speed)
132dd52495fSSaurabh Misra  */
133dd52495fSSaurabh Misra #define	BFE_TIMEOUT_INTERVAL	(1000 * 1000 * 1000)
134dd52495fSSaurabh Misra 
135dd52495fSSaurabh Misra 
136dd52495fSSaurabh Misra /*
137dd52495fSSaurabh Misra  * Chip restart action and reason for restart
138dd52495fSSaurabh Misra  */
139dd52495fSSaurabh Misra #define	BFE_ACTION_RESTART		0x1	/* For restarting the chip */
140dd52495fSSaurabh Misra #define	BFE_ACTION_RESTART_SETPROP	0x2	/* restart due to setprop */
141dd52495fSSaurabh Misra #define	BFE_ACTION_RESTART_FAULT	0x4	/* restart due to fault */
142dd52495fSSaurabh Misra #define	BFE_ACTION_RESTART_PKT		0x8	/* restart due to pkt timeout */
143dd52495fSSaurabh Misra 
144dd52495fSSaurabh Misra static	char	bfe_ident[] = "bfe driver for Broadcom BCM4401 chipsets";
145dd52495fSSaurabh Misra 
146dd52495fSSaurabh Misra /*
147dd52495fSSaurabh Misra  * Function Prototypes for bfe driver.
148dd52495fSSaurabh Misra  */
149dd52495fSSaurabh Misra static	int	bfe_check_link(bfe_t *);
150dd52495fSSaurabh Misra static	void	bfe_report_link(bfe_t *);
151dd52495fSSaurabh Misra static	void	bfe_chip_halt(bfe_t *);
152dd52495fSSaurabh Misra static	void	bfe_chip_reset(bfe_t *);
153dd52495fSSaurabh Misra static	void	bfe_tx_desc_init(bfe_ring_t *);
154dd52495fSSaurabh Misra static	void	bfe_rx_desc_init(bfe_ring_t *);
155dd52495fSSaurabh Misra static	void	bfe_set_rx_mode(bfe_t *);
156dd52495fSSaurabh Misra static	void	bfe_enable_chip_intrs(bfe_t *);
157dd52495fSSaurabh Misra static	void	bfe_chip_restart(bfe_t *);
158dd52495fSSaurabh Misra static	void	bfe_init_vars(bfe_t *);
159dd52495fSSaurabh Misra static	void	bfe_clear_stats(bfe_t *);
160dd52495fSSaurabh Misra static	void	bfe_gather_stats(bfe_t *);
161dd52495fSSaurabh Misra static	void	bfe_error(dev_info_t *, char *, ...);
162dd52495fSSaurabh Misra static	int	bfe_mac_getprop(void *, const char *, mac_prop_id_t, uint_t,
1630dc2366fSVenugopal Iyer     void *);
164dd52495fSSaurabh Misra static	int	bfe_mac_setprop(void *, const char *, mac_prop_id_t, uint_t,
165dd52495fSSaurabh Misra     const void *);
166dd52495fSSaurabh Misra static	int	bfe_tx_reclaim(bfe_ring_t *);
167dd52495fSSaurabh Misra int	bfe_mac_set_ether_addr(void *, const uint8_t *);
168dd52495fSSaurabh Misra 
169dd52495fSSaurabh Misra 
170dd52495fSSaurabh Misra /*
171dd52495fSSaurabh Misra  * Macros for ddi_dma_sync().
172dd52495fSSaurabh Misra  */
173dd52495fSSaurabh Misra #define	SYNC_DESC(r, s, l, d)	\
174dd52495fSSaurabh Misra 	(void) ddi_dma_sync(r->r_desc_dma_handle, \
175dd52495fSSaurabh Misra 	    (off_t)(s * sizeof (bfe_desc_t)), \
176dd52495fSSaurabh Misra 	    (size_t)(l * sizeof (bfe_desc_t)), \
177dd52495fSSaurabh Misra 	    d)
178dd52495fSSaurabh Misra 
179dd52495fSSaurabh Misra #define	SYNC_BUF(r, s, b, l, d) \
180dd52495fSSaurabh Misra 	(void) ddi_dma_sync(r->r_buf_dma[s].handle, \
181dd52495fSSaurabh Misra 	    (off_t)(b), (size_t)(l), d)
182dd52495fSSaurabh Misra 
183dd52495fSSaurabh Misra /*
184dd52495fSSaurabh Misra  * Supported Broadcom BCM4401 Cards.
185dd52495fSSaurabh Misra  */
186dd52495fSSaurabh Misra static bfe_cards_t bfe_cards[] = {
187dd52495fSSaurabh Misra 	{ 0x14e4, 0x170c, "BCM4401 100Base-TX"},
188dd52495fSSaurabh Misra };
189dd52495fSSaurabh Misra 
190dd52495fSSaurabh Misra 
191dd52495fSSaurabh Misra /*
192dd52495fSSaurabh Misra  * DMA attributes for device registers, packet data (buffer) and
193dd52495fSSaurabh Misra  * descriptor table.
194dd52495fSSaurabh Misra  */
195dd52495fSSaurabh Misra static struct ddi_device_acc_attr bfe_dev_attr = {
196dd52495fSSaurabh Misra 	DDI_DEVICE_ATTR_V0,
197dd52495fSSaurabh Misra 	DDI_STRUCTURE_LE_ACC,
198dd52495fSSaurabh Misra 	DDI_STRICTORDER_ACC
199dd52495fSSaurabh Misra };
200dd52495fSSaurabh Misra 
201dd52495fSSaurabh Misra static struct ddi_device_acc_attr bfe_buf_attr = {
202dd52495fSSaurabh Misra 	DDI_DEVICE_ATTR_V0,
203dd52495fSSaurabh Misra 	DDI_NEVERSWAP_ACC,	/* native endianness */
204dd52495fSSaurabh Misra 	DDI_STRICTORDER_ACC
205dd52495fSSaurabh Misra };
206dd52495fSSaurabh Misra 
207dd52495fSSaurabh Misra static ddi_dma_attr_t bfe_dma_attr_buf = {
208dd52495fSSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
209dd52495fSSaurabh Misra 	0,			/* dma_attr_addr_lo */
210dd52495fSSaurabh Misra 	BFE_PCI_DMA - 1,	/* dma_attr_addr_hi */
211dd52495fSSaurabh Misra 	0x1fff,			/* dma_attr_count_max */
212dd52495fSSaurabh Misra 	8,			/* dma_attr_align */
213dd52495fSSaurabh Misra 	0,			/* dma_attr_burstsizes */
214dd52495fSSaurabh Misra 	1,			/* dma_attr_minxfer */
215dd52495fSSaurabh Misra 	0x1fff,			/* dma_attr_maxxfer */
216dd52495fSSaurabh Misra 	BFE_PCI_DMA - 1,	/* dma_attr_seg */
217dd52495fSSaurabh Misra 	1,			/* dma_attr_sgllen */
218dd52495fSSaurabh Misra 	1,			/* dma_attr_granular */
219dd52495fSSaurabh Misra 	0			/* dma_attr_flags */
220dd52495fSSaurabh Misra };
221dd52495fSSaurabh Misra 
222dd52495fSSaurabh Misra static ddi_dma_attr_t bfe_dma_attr_desc = {
223dd52495fSSaurabh Misra 	DMA_ATTR_V0,		/* dma_attr_version */
224dd52495fSSaurabh Misra 	0,			/* dma_attr_addr_lo */
225dd52495fSSaurabh Misra 	BFE_PCI_DMA - 1,	/* dma_attr_addr_hi */
226dd52495fSSaurabh Misra 	BFE_PCI_DMA - 1,	/* dma_attr_count_max */
227dd52495fSSaurabh Misra 	BFE_DESC_ALIGN,		/* dma_attr_align */
228dd52495fSSaurabh Misra 	0,			/* dma_attr_burstsizes */
229dd52495fSSaurabh Misra 	1,			/* dma_attr_minxfer */
230dd52495fSSaurabh Misra 	BFE_PCI_DMA - 1,	/* dma_attr_maxxfer */
231dd52495fSSaurabh Misra 	BFE_PCI_DMA - 1,	/* dma_attr_seg */
232dd52495fSSaurabh Misra 	1,			/* dma_attr_sgllen */
233dd52495fSSaurabh Misra 	1,			/* dma_attr_granular */
234dd52495fSSaurabh Misra 	0			/* dma_attr_flags */
235dd52495fSSaurabh Misra };
236dd52495fSSaurabh Misra 
237dd52495fSSaurabh Misra /*
238dd52495fSSaurabh Misra  * Ethernet broadcast addresses.
239dd52495fSSaurabh Misra  */
240dd52495fSSaurabh Misra static uchar_t bfe_broadcast[ETHERADDRL] = {
241dd52495fSSaurabh Misra 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
242dd52495fSSaurabh Misra };
243dd52495fSSaurabh Misra 
244dd52495fSSaurabh Misra #define	ASSERT_ALL_LOCKS(bfe) {	\
245dd52495fSSaurabh Misra 	ASSERT(mutex_owned(&bfe->bfe_tx_ring.r_lock));	\
246dd52495fSSaurabh Misra 	ASSERT(rw_write_held(&bfe->bfe_rwlock));	\
247dd52495fSSaurabh Misra }
248dd52495fSSaurabh Misra 
249dd52495fSSaurabh Misra /*
250dd52495fSSaurabh Misra  * Debugging and error reproting code.
251dd52495fSSaurabh Misra  */
252dd52495fSSaurabh Misra static void
bfe_error(dev_info_t * dip,char * fmt,...)253dd52495fSSaurabh Misra bfe_error(dev_info_t *dip, char *fmt, ...)
254dd52495fSSaurabh Misra {
255dd52495fSSaurabh Misra 	va_list ap;
256dd52495fSSaurabh Misra 	char	buf[256];
257dd52495fSSaurabh Misra 
258dd52495fSSaurabh Misra 	va_start(ap, fmt);
259dd52495fSSaurabh Misra 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
260dd52495fSSaurabh Misra 	va_end(ap);
261dd52495fSSaurabh Misra 
262dd52495fSSaurabh Misra 	if (dip) {
263dd52495fSSaurabh Misra 		cmn_err(CE_WARN, "%s%d: %s",
264dd52495fSSaurabh Misra 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
265dd52495fSSaurabh Misra 	} else {
266dd52495fSSaurabh Misra 		cmn_err(CE_WARN, "bfe: %s", buf);
267dd52495fSSaurabh Misra 	}
268dd52495fSSaurabh Misra }
269dd52495fSSaurabh Misra 
270dd52495fSSaurabh Misra /*
271dd52495fSSaurabh Misra  * Grabs all necessary locks to block any other operation on the chip.
272dd52495fSSaurabh Misra  */
273dd52495fSSaurabh Misra static void
bfe_grab_locks(bfe_t * bfe)274dd52495fSSaurabh Misra bfe_grab_locks(bfe_t *bfe)
275dd52495fSSaurabh Misra {
276dd52495fSSaurabh Misra 	bfe_ring_t *tx = &bfe->bfe_tx_ring;
277dd52495fSSaurabh Misra 
278dd52495fSSaurabh Misra 	/*
279dd52495fSSaurabh Misra 	 * Grab all the locks.
280dd52495fSSaurabh Misra 	 * - bfe_rwlock : locks down whole chip including RX.
281dd52495fSSaurabh Misra 	 * - tx's r_lock : locks down only TX side.
282dd52495fSSaurabh Misra 	 */
283dd52495fSSaurabh Misra 	rw_enter(&bfe->bfe_rwlock, RW_WRITER);
284dd52495fSSaurabh Misra 	mutex_enter(&tx->r_lock);
285dd52495fSSaurabh Misra 
286dd52495fSSaurabh Misra 	/*
287dd52495fSSaurabh Misra 	 * Note that we don't use RX's r_lock.
288dd52495fSSaurabh Misra 	 */
289dd52495fSSaurabh Misra }
290dd52495fSSaurabh Misra 
291dd52495fSSaurabh Misra /*
292dd52495fSSaurabh Misra  * Release lock on chip/drver.
293dd52495fSSaurabh Misra  */
294dd52495fSSaurabh Misra static void
bfe_release_locks(bfe_t * bfe)295dd52495fSSaurabh Misra bfe_release_locks(bfe_t *bfe)
296dd52495fSSaurabh Misra {
297dd52495fSSaurabh Misra 	bfe_ring_t *tx = &bfe->bfe_tx_ring;
298dd52495fSSaurabh Misra 
299dd52495fSSaurabh Misra 	/*
300dd52495fSSaurabh Misra 	 * Release all the locks in the order in which they were grabbed.
301dd52495fSSaurabh Misra 	 */
302dd52495fSSaurabh Misra 	mutex_exit(&tx->r_lock);
303dd52495fSSaurabh Misra 	rw_exit(&bfe->bfe_rwlock);
304dd52495fSSaurabh Misra }
305dd52495fSSaurabh Misra 
306dd52495fSSaurabh Misra 
307dd52495fSSaurabh Misra /*
308dd52495fSSaurabh Misra  * It's used to make sure that the write to device register was successful.
309dd52495fSSaurabh Misra  */
310dd52495fSSaurabh Misra static int
bfe_wait_bit(bfe_t * bfe,uint32_t reg,uint32_t bit,ulong_t t,const int clear)311dd52495fSSaurabh Misra bfe_wait_bit(bfe_t *bfe, uint32_t reg, uint32_t bit,
312dd52495fSSaurabh Misra     ulong_t t, const int clear)
313dd52495fSSaurabh Misra {
314dd52495fSSaurabh Misra 	ulong_t i;
315dd52495fSSaurabh Misra 	uint32_t v;
316dd52495fSSaurabh Misra 
317dd52495fSSaurabh Misra 	for (i = 0; i < t; i++) {
318dd52495fSSaurabh Misra 		v = INL(bfe, reg);
319dd52495fSSaurabh Misra 
320dd52495fSSaurabh Misra 		if (clear && !(v & bit))
321dd52495fSSaurabh Misra 			break;
322dd52495fSSaurabh Misra 
323dd52495fSSaurabh Misra 		if (!clear && (v & bit))
324dd52495fSSaurabh Misra 			break;
325dd52495fSSaurabh Misra 
326dd52495fSSaurabh Misra 		drv_usecwait(10);
327dd52495fSSaurabh Misra 	}
328dd52495fSSaurabh Misra 
329dd52495fSSaurabh Misra 	/* if device still didn't see the value */
330dd52495fSSaurabh Misra 	if (i == t)
331dd52495fSSaurabh Misra 		return (-1);
332dd52495fSSaurabh Misra 
333dd52495fSSaurabh Misra 	return (0);
334dd52495fSSaurabh Misra }
335dd52495fSSaurabh Misra 
336dd52495fSSaurabh Misra /*
337dd52495fSSaurabh Misra  * PHY functions (read, write, stop, reset and startup)
338dd52495fSSaurabh Misra  */
339dd52495fSSaurabh Misra static int
bfe_read_phy(bfe_t * bfe,uint32_t reg)340dd52495fSSaurabh Misra bfe_read_phy(bfe_t *bfe, uint32_t reg)
341dd52495fSSaurabh Misra {
342dd52495fSSaurabh Misra 	OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
343dd52495fSSaurabh Misra 	OUTL(bfe, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
344dd52495fSSaurabh Misra 	    (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) |
345dd52495fSSaurabh Misra 	    (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) |
346dd52495fSSaurabh Misra 	    (reg << BFE_MDIO_RA_SHIFT) |
347dd52495fSSaurabh Misra 	    (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT)));
348dd52495fSSaurabh Misra 
349dd52495fSSaurabh Misra 	(void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0);
350dd52495fSSaurabh Misra 
351dd52495fSSaurabh Misra 	return ((INL(bfe, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA));
352dd52495fSSaurabh Misra }
353dd52495fSSaurabh Misra 
354dd52495fSSaurabh Misra static void
bfe_write_phy(bfe_t * bfe,uint32_t reg,uint32_t val)355dd52495fSSaurabh Misra bfe_write_phy(bfe_t *bfe, uint32_t reg, uint32_t val)
356dd52495fSSaurabh Misra {
357dd52495fSSaurabh Misra 	OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
358dd52495fSSaurabh Misra 	OUTL(bfe,  BFE_MDIO_DATA, (BFE_MDIO_SB_START |
359dd52495fSSaurabh Misra 	    (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) |
360dd52495fSSaurabh Misra 	    (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) |
361dd52495fSSaurabh Misra 	    (reg << BFE_MDIO_RA_SHIFT) |
362dd52495fSSaurabh Misra 	    (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) |
363dd52495fSSaurabh Misra 	    (val & BFE_MDIO_DATA_DATA)));
364dd52495fSSaurabh Misra 
365dd52495fSSaurabh Misra 	(void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0);
366dd52495fSSaurabh Misra }
367dd52495fSSaurabh Misra 
368dd52495fSSaurabh Misra /*
369dd52495fSSaurabh Misra  * It resets the PHY layer.
370dd52495fSSaurabh Misra  */
371dd52495fSSaurabh Misra static int
bfe_reset_phy(bfe_t * bfe)372dd52495fSSaurabh Misra bfe_reset_phy(bfe_t *bfe)
373dd52495fSSaurabh Misra {
374dd52495fSSaurabh Misra 	uint32_t i;
375dd52495fSSaurabh Misra 
376dd52495fSSaurabh Misra 	bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_RESET);
377dd52495fSSaurabh Misra 	drv_usecwait(100);
378dd52495fSSaurabh Misra 	for (i = 0; i < 10; i++) {
379dd52495fSSaurabh Misra 		if (bfe_read_phy(bfe, MII_CONTROL) &
380dd52495fSSaurabh Misra 		    MII_CONTROL_RESET) {
381dd52495fSSaurabh Misra 			drv_usecwait(500);
382dd52495fSSaurabh Misra 			continue;
383dd52495fSSaurabh Misra 		}
384dd52495fSSaurabh Misra 
385dd52495fSSaurabh Misra 		break;
386dd52495fSSaurabh Misra 	}
387dd52495fSSaurabh Misra 
388dd52495fSSaurabh Misra 	if (i == 10) {
389dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "Timeout waiting for PHY to reset");
390dd52495fSSaurabh Misra 		bfe->bfe_phy_state = BFE_PHY_RESET_TIMEOUT;
391dd52495fSSaurabh Misra 		return (BFE_FAILURE);
392dd52495fSSaurabh Misra 	}
393dd52495fSSaurabh Misra 
394dd52495fSSaurabh Misra 	bfe->bfe_phy_state = BFE_PHY_RESET_DONE;
395dd52495fSSaurabh Misra 
396dd52495fSSaurabh Misra 	return (BFE_SUCCESS);
397dd52495fSSaurabh Misra }
398dd52495fSSaurabh Misra 
399dd52495fSSaurabh Misra /*
400dd52495fSSaurabh Misra  * Make sure timer function is out of our way and especially during
401dd52495fSSaurabh Misra  * detach.
402dd52495fSSaurabh Misra  */
403dd52495fSSaurabh Misra static void
bfe_stop_timer(bfe_t * bfe)404dd52495fSSaurabh Misra bfe_stop_timer(bfe_t *bfe)
405dd52495fSSaurabh Misra {
406dd52495fSSaurabh Misra 	if (bfe->bfe_periodic_id) {
407dd52495fSSaurabh Misra 		ddi_periodic_delete(bfe->bfe_periodic_id);
408dd52495fSSaurabh Misra 		bfe->bfe_periodic_id = NULL;
409dd52495fSSaurabh Misra 	}
410dd52495fSSaurabh Misra }
411dd52495fSSaurabh Misra 
412dd52495fSSaurabh Misra /*
413dd52495fSSaurabh Misra  * Stops the PHY
414dd52495fSSaurabh Misra  */
415dd52495fSSaurabh Misra static void
bfe_stop_phy(bfe_t * bfe)416dd52495fSSaurabh Misra bfe_stop_phy(bfe_t *bfe)
417dd52495fSSaurabh Misra {
418dd52495fSSaurabh Misra 	bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_PWRDN |
419dd52495fSSaurabh Misra 	    MII_CONTROL_ISOLATE);
420dd52495fSSaurabh Misra 
421dd52495fSSaurabh Misra 	bfe->bfe_chip.link = LINK_STATE_UNKNOWN;
422dd52495fSSaurabh Misra 	bfe->bfe_chip.speed = 0;
423dd52495fSSaurabh Misra 	bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
424dd52495fSSaurabh Misra 
425dd52495fSSaurabh Misra 	bfe->bfe_phy_state = BFE_PHY_STOPPED;
426dd52495fSSaurabh Misra 
427dd52495fSSaurabh Misra 	/*
428dd52495fSSaurabh Misra 	 * Report the link status to MAC layer.
429dd52495fSSaurabh Misra 	 */
430dd52495fSSaurabh Misra 	if (bfe->bfe_machdl != NULL)
431dd52495fSSaurabh Misra 		(void) bfe_report_link(bfe);
432dd52495fSSaurabh Misra }
433dd52495fSSaurabh Misra 
434dd52495fSSaurabh Misra static int
bfe_probe_phy(bfe_t * bfe)435dd52495fSSaurabh Misra bfe_probe_phy(bfe_t *bfe)
436dd52495fSSaurabh Misra {
437dd52495fSSaurabh Misra 	int phy;
438dd52495fSSaurabh Misra 	uint32_t status;
439dd52495fSSaurabh Misra 
440dd52495fSSaurabh Misra 	if (bfe->bfe_phy_addr) {
441dd52495fSSaurabh Misra 		status = bfe_read_phy(bfe, MII_STATUS);
442dd52495fSSaurabh Misra 		if (status != 0xffff && status != 0) {
443dd52495fSSaurabh Misra 			bfe_write_phy(bfe, MII_CONTROL, 0);
444dd52495fSSaurabh Misra 			return (BFE_SUCCESS);
445dd52495fSSaurabh Misra 		}
446dd52495fSSaurabh Misra 	}
447dd52495fSSaurabh Misra 
448dd52495fSSaurabh Misra 	for (phy = 0; phy < 32; phy++) {
449dd52495fSSaurabh Misra 		bfe->bfe_phy_addr = phy;
450dd52495fSSaurabh Misra 		status = bfe_read_phy(bfe, MII_STATUS);
451dd52495fSSaurabh Misra 		if (status != 0xffff && status != 0) {
452dd52495fSSaurabh Misra 			bfe_write_phy(bfe, MII_CONTROL, 0);
453dd52495fSSaurabh Misra 			return (BFE_SUCCESS);
454dd52495fSSaurabh Misra 		}
455dd52495fSSaurabh Misra 	}
456dd52495fSSaurabh Misra 
457dd52495fSSaurabh Misra 	return (BFE_FAILURE);
458dd52495fSSaurabh Misra }
459dd52495fSSaurabh Misra 
460dd52495fSSaurabh Misra /*
461dd52495fSSaurabh Misra  * This timeout function fires at BFE_TIMEOUT_INTERVAL to check the link
462dd52495fSSaurabh Misra  * status.
463dd52495fSSaurabh Misra  */
464dd52495fSSaurabh Misra static void
bfe_timeout(void * arg)465dd52495fSSaurabh Misra bfe_timeout(void *arg)
466dd52495fSSaurabh Misra {
467dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
468954c6b5eSSaurabh Misra 	int resched = 0;
469dd52495fSSaurabh Misra 
470dd52495fSSaurabh Misra 	/*
471dd52495fSSaurabh Misra 	 * We don't grab any lock because bfe can't go away.
472dd52495fSSaurabh Misra 	 * untimeout() will wait for this timeout instance to complete.
473dd52495fSSaurabh Misra 	 */
474dd52495fSSaurabh Misra 	if (bfe->bfe_chip_action & BFE_ACTION_RESTART) {
475dd52495fSSaurabh Misra 		/*
476dd52495fSSaurabh Misra 		 * Restart the chip.
477dd52495fSSaurabh Misra 		 */
478dd52495fSSaurabh Misra 		bfe_grab_locks(bfe);
479dd52495fSSaurabh Misra 		bfe_chip_restart(bfe);
480dd52495fSSaurabh Misra 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART;
481dd52495fSSaurabh Misra 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_FAULT;
482dd52495fSSaurabh Misra 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_PKT;
483dd52495fSSaurabh Misra 		bfe_release_locks(bfe);
484dd52495fSSaurabh Misra 		mac_tx_update(bfe->bfe_machdl);
485dd52495fSSaurabh Misra 		/* Restart will register a new timeout */
486dd52495fSSaurabh Misra 		return;
487dd52495fSSaurabh Misra 	}
488dd52495fSSaurabh Misra 
489dd52495fSSaurabh Misra 	rw_enter(&bfe->bfe_rwlock, RW_READER);
490dd52495fSSaurabh Misra 
491dd52495fSSaurabh Misra 	if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
492dd52495fSSaurabh Misra 		hrtime_t hr;
493dd52495fSSaurabh Misra 
494dd52495fSSaurabh Misra 		hr = gethrtime();
495dd52495fSSaurabh Misra 		if (bfe->bfe_tx_stall_time != 0 &&
496dd52495fSSaurabh Misra 		    hr > bfe->bfe_tx_stall_time) {
497dd52495fSSaurabh Misra 			DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit,
498dd52495fSSaurabh Misra 			    char *, "pkt timeout");
499dd52495fSSaurabh Misra 			bfe->bfe_chip_action |=
500dd52495fSSaurabh Misra 			    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_PKT);
501dd52495fSSaurabh Misra 			bfe->bfe_tx_stall_time = 0;
502dd52495fSSaurabh Misra 		}
503dd52495fSSaurabh Misra 	}
504dd52495fSSaurabh Misra 
505dd52495fSSaurabh Misra 	if (bfe->bfe_phy_state == BFE_PHY_STARTED) {
506dd52495fSSaurabh Misra 		/*
507dd52495fSSaurabh Misra 		 * Report the link status to MAC layer if link status changed.
508dd52495fSSaurabh Misra 		 */
509dd52495fSSaurabh Misra 		if (bfe_check_link(bfe)) {
510dd52495fSSaurabh Misra 			bfe_report_link(bfe);
511dd52495fSSaurabh Misra 			if (bfe->bfe_chip.link == LINK_STATE_UP) {
512dd52495fSSaurabh Misra 				uint32_t val, flow;
513dd52495fSSaurabh Misra 
514dd52495fSSaurabh Misra 				val = INL(bfe, BFE_TX_CTRL);
515dd52495fSSaurabh Misra 				val &= ~BFE_TX_DUPLEX;
516dd52495fSSaurabh Misra 				if (bfe->bfe_chip.duplex == LINK_DUPLEX_FULL) {
517dd52495fSSaurabh Misra 					val |= BFE_TX_DUPLEX;
518dd52495fSSaurabh Misra 					flow = INL(bfe, BFE_RXCONF);
519dd52495fSSaurabh Misra 					flow &= ~BFE_RXCONF_FLOW;
520dd52495fSSaurabh Misra 					OUTL(bfe, BFE_RXCONF, flow);
521dd52495fSSaurabh Misra 
522dd52495fSSaurabh Misra 					flow = INL(bfe, BFE_MAC_FLOW);
523dd52495fSSaurabh Misra 					flow &= ~(BFE_FLOW_RX_HIWAT);
524dd52495fSSaurabh Misra 					OUTL(bfe, BFE_MAC_FLOW, flow);
525dd52495fSSaurabh Misra 				}
526dd52495fSSaurabh Misra 
527954c6b5eSSaurabh Misra 				resched = 1;
528954c6b5eSSaurabh Misra 
529dd52495fSSaurabh Misra 				OUTL(bfe, BFE_TX_CTRL, val);
530dd52495fSSaurabh Misra 				DTRACE_PROBE1(link__up,
531dd52495fSSaurabh Misra 				    int, bfe->bfe_unit);
532dd52495fSSaurabh Misra 			}
533dd52495fSSaurabh Misra 		}
534dd52495fSSaurabh Misra 	}
535dd52495fSSaurabh Misra 
536dd52495fSSaurabh Misra 	rw_exit(&bfe->bfe_rwlock);
537954c6b5eSSaurabh Misra 
538954c6b5eSSaurabh Misra 	if (resched)
539954c6b5eSSaurabh Misra 		mac_tx_update(bfe->bfe_machdl);
540dd52495fSSaurabh Misra }
541dd52495fSSaurabh Misra 
542dd52495fSSaurabh Misra /*
543dd52495fSSaurabh Misra  * Starts PHY layer.
544dd52495fSSaurabh Misra  */
545dd52495fSSaurabh Misra static int
bfe_startup_phy(bfe_t * bfe)546dd52495fSSaurabh Misra bfe_startup_phy(bfe_t *bfe)
547dd52495fSSaurabh Misra {
548dd52495fSSaurabh Misra 	uint16_t bmsr, bmcr, anar;
549dd52495fSSaurabh Misra 	int	prog, s;
550dd52495fSSaurabh Misra 	int phyid1, phyid2;
551dd52495fSSaurabh Misra 
552dd52495fSSaurabh Misra 	if (bfe_probe_phy(bfe) == BFE_FAILURE) {
553dd52495fSSaurabh Misra 		bfe->bfe_phy_state = BFE_PHY_NOTFOUND;
554dd52495fSSaurabh Misra 		return (BFE_FAILURE);
555dd52495fSSaurabh Misra 	}
556dd52495fSSaurabh Misra 
557dd52495fSSaurabh Misra 	(void) bfe_reset_phy(bfe);
558dd52495fSSaurabh Misra 
559dd52495fSSaurabh Misra 	phyid1 = bfe_read_phy(bfe, MII_PHYIDH);
560dd52495fSSaurabh Misra 	phyid2 = bfe_read_phy(bfe, MII_PHYIDL);
561dd52495fSSaurabh Misra 	bfe->bfe_phy_id = (phyid1 << 16) | phyid2;
562dd52495fSSaurabh Misra 
563dd52495fSSaurabh Misra 	bmsr = bfe_read_phy(bfe, MII_STATUS);
564dd52495fSSaurabh Misra 	anar = bfe_read_phy(bfe, MII_AN_ADVERT);
565dd52495fSSaurabh Misra 
566dd52495fSSaurabh Misra again:
567dd52495fSSaurabh Misra 	anar &= ~(MII_ABILITY_100BASE_T4 |
568dd52495fSSaurabh Misra 	    MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
569dd52495fSSaurabh Misra 	    MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
570dd52495fSSaurabh Misra 
571dd52495fSSaurabh Misra 	/*
572dd52495fSSaurabh Misra 	 * Supported hardware modes are in bmsr.
573dd52495fSSaurabh Misra 	 */
574dd52495fSSaurabh Misra 	bfe->bfe_chip.bmsr = bmsr;
575dd52495fSSaurabh Misra 
576dd52495fSSaurabh Misra 	/*
577dd52495fSSaurabh Misra 	 * Assume no capabilities are supported in the hardware.
578dd52495fSSaurabh Misra 	 */
579dd52495fSSaurabh Misra 	bfe->bfe_cap_aneg = bfe->bfe_cap_100T4 =
580dd52495fSSaurabh Misra 	    bfe->bfe_cap_100fdx = bfe->bfe_cap_100hdx =
581dd52495fSSaurabh Misra 	    bfe->bfe_cap_10fdx = bfe->bfe_cap_10hdx = 0;
582dd52495fSSaurabh Misra 
583dd52495fSSaurabh Misra 	/*
584dd52495fSSaurabh Misra 	 * Assume property is set.
585dd52495fSSaurabh Misra 	 */
586dd52495fSSaurabh Misra 	s = 1;
587dd52495fSSaurabh Misra 	if (!(bfe->bfe_chip_action & BFE_ACTION_RESTART_SETPROP)) {
588dd52495fSSaurabh Misra 		/*
589dd52495fSSaurabh Misra 		 * Property is not set which means bfe_mac_setprop()
590dd52495fSSaurabh Misra 		 * is not called on us.
591dd52495fSSaurabh Misra 		 */
592dd52495fSSaurabh Misra 		s = 0;
593dd52495fSSaurabh Misra 	}
594dd52495fSSaurabh Misra 
595dd52495fSSaurabh Misra 	bmcr = prog = 0;
596dd52495fSSaurabh Misra 
597dd52495fSSaurabh Misra 	if (bmsr & MII_STATUS_100_BASEX_FD) {
598dd52495fSSaurabh Misra 		bfe->bfe_cap_100fdx = 1;
599dd52495fSSaurabh Misra 		if (s == 0) {
600dd52495fSSaurabh Misra 			anar |= MII_ABILITY_100BASE_TX_FD;
601dd52495fSSaurabh Misra 			bfe->bfe_adv_100fdx = 1;
602dd52495fSSaurabh Misra 			prog++;
603dd52495fSSaurabh Misra 		} else if (bfe->bfe_adv_100fdx) {
604dd52495fSSaurabh Misra 			anar |= MII_ABILITY_100BASE_TX_FD;
605dd52495fSSaurabh Misra 			prog++;
606dd52495fSSaurabh Misra 		}
607dd52495fSSaurabh Misra 	}
608dd52495fSSaurabh Misra 
609dd52495fSSaurabh Misra 	if (bmsr & MII_STATUS_100_BASE_T4) {
610dd52495fSSaurabh Misra 		bfe->bfe_cap_100T4 = 1;
611dd52495fSSaurabh Misra 		if (s == 0) {
612dd52495fSSaurabh Misra 			anar |= MII_ABILITY_100BASE_T4;
613dd52495fSSaurabh Misra 			bfe->bfe_adv_100T4 = 1;
614dd52495fSSaurabh Misra 			prog++;
615dd52495fSSaurabh Misra 		} else if (bfe->bfe_adv_100T4) {
616dd52495fSSaurabh Misra 			anar |= MII_ABILITY_100BASE_T4;
617dd52495fSSaurabh Misra 			prog++;
618dd52495fSSaurabh Misra 		}
619dd52495fSSaurabh Misra 	}
620dd52495fSSaurabh Misra 
621dd52495fSSaurabh Misra 	if (bmsr & MII_STATUS_100_BASEX) {
622dd52495fSSaurabh Misra 		bfe->bfe_cap_100hdx = 1;
623dd52495fSSaurabh Misra 		if (s == 0) {
624dd52495fSSaurabh Misra 			anar |= MII_ABILITY_100BASE_TX;
625dd52495fSSaurabh Misra 			bfe->bfe_adv_100hdx = 1;
626dd52495fSSaurabh Misra 			prog++;
627dd52495fSSaurabh Misra 		} else if (bfe->bfe_adv_100hdx) {
628dd52495fSSaurabh Misra 			anar |= MII_ABILITY_100BASE_TX;
629dd52495fSSaurabh Misra 			prog++;
630dd52495fSSaurabh Misra 		}
631dd52495fSSaurabh Misra 	}
632dd52495fSSaurabh Misra 
633dd52495fSSaurabh Misra 	if (bmsr & MII_STATUS_10_FD) {
634dd52495fSSaurabh Misra 		bfe->bfe_cap_10fdx = 1;
635dd52495fSSaurabh Misra 		if (s == 0) {
636dd52495fSSaurabh Misra 			anar |= MII_ABILITY_10BASE_T_FD;
637dd52495fSSaurabh Misra 			bfe->bfe_adv_10fdx = 1;
638dd52495fSSaurabh Misra 			prog++;
639dd52495fSSaurabh Misra 		} else if (bfe->bfe_adv_10fdx) {
640dd52495fSSaurabh Misra 			anar |= MII_ABILITY_10BASE_T_FD;
641dd52495fSSaurabh Misra 			prog++;
642dd52495fSSaurabh Misra 		}
643dd52495fSSaurabh Misra 	}
644dd52495fSSaurabh Misra 
645dd52495fSSaurabh Misra 	if (bmsr & MII_STATUS_10) {
646dd52495fSSaurabh Misra 		bfe->bfe_cap_10hdx = 1;
647dd52495fSSaurabh Misra 		if (s == 0) {
648dd52495fSSaurabh Misra 			anar |= MII_ABILITY_10BASE_T;
649dd52495fSSaurabh Misra 			bfe->bfe_adv_10hdx = 1;
650dd52495fSSaurabh Misra 			prog++;
651dd52495fSSaurabh Misra 		} else if (bfe->bfe_adv_10hdx) {
652dd52495fSSaurabh Misra 			anar |= MII_ABILITY_10BASE_T;
653dd52495fSSaurabh Misra 			prog++;
654dd52495fSSaurabh Misra 		}
655dd52495fSSaurabh Misra 	}
656dd52495fSSaurabh Misra 
657dd52495fSSaurabh Misra 	if (bmsr & MII_STATUS_CANAUTONEG) {
658dd52495fSSaurabh Misra 		bfe->bfe_cap_aneg = 1;
659dd52495fSSaurabh Misra 		if (s == 0) {
660dd52495fSSaurabh Misra 			bfe->bfe_adv_aneg = 1;
661dd52495fSSaurabh Misra 		}
662dd52495fSSaurabh Misra 	}
663dd52495fSSaurabh Misra 
664dd52495fSSaurabh Misra 	if (prog == 0) {
665dd52495fSSaurabh Misra 		if (s == 0) {
666dd52495fSSaurabh Misra 			bfe_error(bfe->bfe_dip,
667dd52495fSSaurabh Misra 			    "No valid link mode selected. Powering down PHY");
668dd52495fSSaurabh Misra 			bfe_stop_phy(bfe);
669dd52495fSSaurabh Misra 			bfe_report_link(bfe);
670dd52495fSSaurabh Misra 			return (BFE_FAILURE);
671dd52495fSSaurabh Misra 		}
672dd52495fSSaurabh Misra 
673dd52495fSSaurabh Misra 		/*
674dd52495fSSaurabh Misra 		 * If property is set then user would have goofed up. So we
675dd52495fSSaurabh Misra 		 * go back to default properties.
676dd52495fSSaurabh Misra 		 */
677dd52495fSSaurabh Misra 		bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_SETPROP;
678dd52495fSSaurabh Misra 		goto again;
679dd52495fSSaurabh Misra 	}
680dd52495fSSaurabh Misra 
681dd52495fSSaurabh Misra 	if (bfe->bfe_adv_aneg && (bmsr & MII_STATUS_CANAUTONEG)) {
682dd52495fSSaurabh Misra 		bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
683dd52495fSSaurabh Misra 	} else {
684dd52495fSSaurabh Misra 		if (bfe->bfe_adv_100fdx)
685dd52495fSSaurabh Misra 			bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
686dd52495fSSaurabh Misra 		else if (bfe->bfe_adv_100hdx)
687dd52495fSSaurabh Misra 			bmcr = MII_CONTROL_100MB;
688dd52495fSSaurabh Misra 		else if (bfe->bfe_adv_10fdx)
689dd52495fSSaurabh Misra 			bmcr = MII_CONTROL_FDUPLEX;
690dd52495fSSaurabh Misra 		else
691dd52495fSSaurabh Misra 			bmcr = 0;		/* 10HDX */
692dd52495fSSaurabh Misra 	}
693dd52495fSSaurabh Misra 
694dd52495fSSaurabh Misra 	if (prog)
695dd52495fSSaurabh Misra 		bfe_write_phy(bfe, MII_AN_ADVERT, anar);
696dd52495fSSaurabh Misra 
697dd52495fSSaurabh Misra 	if (bmcr)
698dd52495fSSaurabh Misra 		bfe_write_phy(bfe, MII_CONTROL, bmcr);
699dd52495fSSaurabh Misra 
700dd52495fSSaurabh Misra 	bfe->bfe_mii_anar = anar;
701dd52495fSSaurabh Misra 	bfe->bfe_mii_bmcr = bmcr;
702dd52495fSSaurabh Misra 	bfe->bfe_phy_state = BFE_PHY_STARTED;
703dd52495fSSaurabh Misra 
704dd52495fSSaurabh Misra 	if (bfe->bfe_periodic_id == NULL) {
705dd52495fSSaurabh Misra 		bfe->bfe_periodic_id = ddi_periodic_add(bfe_timeout,
706dd52495fSSaurabh Misra 		    (void *)bfe, BFE_TIMEOUT_INTERVAL, DDI_IPL_0);
707dd52495fSSaurabh Misra 
708dd52495fSSaurabh Misra 		DTRACE_PROBE1(first__timeout, int, bfe->bfe_unit);
709dd52495fSSaurabh Misra 	}
710dd52495fSSaurabh Misra 
711dd52495fSSaurabh Misra 	DTRACE_PROBE4(phy_started, int, bfe->bfe_unit,
712dd52495fSSaurabh Misra 	    int, bmsr, int, bmcr, int, anar);
713dd52495fSSaurabh Misra 
714dd52495fSSaurabh Misra 	return (BFE_SUCCESS);
715dd52495fSSaurabh Misra }
716dd52495fSSaurabh Misra 
717dd52495fSSaurabh Misra /*
718dd52495fSSaurabh Misra  * Reports link status back to MAC Layer.
719dd52495fSSaurabh Misra  */
720dd52495fSSaurabh Misra static void
bfe_report_link(bfe_t * bfe)721dd52495fSSaurabh Misra bfe_report_link(bfe_t *bfe)
722dd52495fSSaurabh Misra {
723dd52495fSSaurabh Misra 	mac_link_update(bfe->bfe_machdl, bfe->bfe_chip.link);
724dd52495fSSaurabh Misra }
725dd52495fSSaurabh Misra 
726dd52495fSSaurabh Misra /*
727dd52495fSSaurabh Misra  * Reads PHY/MII registers and get the link status for us.
728dd52495fSSaurabh Misra  */
729dd52495fSSaurabh Misra static int
bfe_check_link(bfe_t * bfe)730dd52495fSSaurabh Misra bfe_check_link(bfe_t *bfe)
731dd52495fSSaurabh Misra {
732dd52495fSSaurabh Misra 	uint16_t bmsr, bmcr, anar, anlpar;
733dd52495fSSaurabh Misra 	int speed, duplex, link;
734dd52495fSSaurabh Misra 
735dd52495fSSaurabh Misra 	speed = bfe->bfe_chip.speed;
736dd52495fSSaurabh Misra 	duplex = bfe->bfe_chip.duplex;
737dd52495fSSaurabh Misra 	link = bfe->bfe_chip.link;
738dd52495fSSaurabh Misra 
739dd52495fSSaurabh Misra 	bmsr = bfe_read_phy(bfe, MII_STATUS);
740dd52495fSSaurabh Misra 	bfe->bfe_mii_bmsr = bmsr;
741dd52495fSSaurabh Misra 
742dd52495fSSaurabh Misra 	bmcr = bfe_read_phy(bfe, MII_CONTROL);
743dd52495fSSaurabh Misra 
744dd52495fSSaurabh Misra 	anar = bfe_read_phy(bfe, MII_AN_ADVERT);
745dd52495fSSaurabh Misra 	bfe->bfe_mii_anar = anar;
746dd52495fSSaurabh Misra 
747dd52495fSSaurabh Misra 	anlpar = bfe_read_phy(bfe, MII_AN_LPABLE);
748dd52495fSSaurabh Misra 	bfe->bfe_mii_anlpar = anlpar;
749dd52495fSSaurabh Misra 
750dd52495fSSaurabh Misra 	bfe->bfe_mii_exp = bfe_read_phy(bfe, MII_AN_EXPANSION);
751dd52495fSSaurabh Misra 
752dd52495fSSaurabh Misra 	/*
753dd52495fSSaurabh Misra 	 * If exp register is not present in PHY.
754dd52495fSSaurabh Misra 	 */
755dd52495fSSaurabh Misra 	if (bfe->bfe_mii_exp == 0xffff) {
756dd52495fSSaurabh Misra 		bfe->bfe_mii_exp = 0;
757dd52495fSSaurabh Misra 	}
758dd52495fSSaurabh Misra 
759dd52495fSSaurabh Misra 	if ((bmsr & MII_STATUS_LINKUP) == 0) {
760dd52495fSSaurabh Misra 		bfe->bfe_chip.link = LINK_STATE_DOWN;
761dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 0;
762dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
763dd52495fSSaurabh Misra 		goto done;
764dd52495fSSaurabh Misra 	}
765dd52495fSSaurabh Misra 
766dd52495fSSaurabh Misra 	bfe->bfe_chip.link = LINK_STATE_UP;
767dd52495fSSaurabh Misra 
768dd52495fSSaurabh Misra 	if (!(bmcr & MII_CONTROL_ANE)) {
769dd52495fSSaurabh Misra 		/* Forced mode */
770dd52495fSSaurabh Misra 		if (bmcr & MII_CONTROL_100MB)
771dd52495fSSaurabh Misra 			bfe->bfe_chip.speed = 100000000;
772dd52495fSSaurabh Misra 		else
773dd52495fSSaurabh Misra 			bfe->bfe_chip.speed = 10000000;
774dd52495fSSaurabh Misra 
775dd52495fSSaurabh Misra 		if (bmcr & MII_CONTROL_FDUPLEX)
776dd52495fSSaurabh Misra 			bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
777dd52495fSSaurabh Misra 		else
778dd52495fSSaurabh Misra 			bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
779dd52495fSSaurabh Misra 
780dd52495fSSaurabh Misra 	} else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
781dd52495fSSaurabh Misra 	    (!(bmsr & MII_STATUS_ANDONE))) {
782dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 0;
783dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
784dd52495fSSaurabh Misra 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
785dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 100000000;
786dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
787dd52495fSSaurabh Misra 	} else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
788dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 100000000;
789dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
790dd52495fSSaurabh Misra 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
791dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 100000000;
792dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
793dd52495fSSaurabh Misra 	} else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
794dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 10000000;
795dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
796dd52495fSSaurabh Misra 	} else if (anar & anlpar & MII_ABILITY_10BASE_T) {
797dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 10000000;
798dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
799dd52495fSSaurabh Misra 	} else {
800dd52495fSSaurabh Misra 		bfe->bfe_chip.speed = 0;
801dd52495fSSaurabh Misra 		bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
802dd52495fSSaurabh Misra 	}
803dd52495fSSaurabh Misra 
804dd52495fSSaurabh Misra done:
805dd52495fSSaurabh Misra 	/*
806dd52495fSSaurabh Misra 	 * If speed or link status or duplex mode changed then report to
807dd52495fSSaurabh Misra 	 * MAC layer which is done by the caller.
808dd52495fSSaurabh Misra 	 */
809dd52495fSSaurabh Misra 	if (speed != bfe->bfe_chip.speed ||
810dd52495fSSaurabh Misra 	    duplex != bfe->bfe_chip.duplex ||
811dd52495fSSaurabh Misra 	    link != bfe->bfe_chip.link) {
812dd52495fSSaurabh Misra 		return (1);
813dd52495fSSaurabh Misra 	}
814dd52495fSSaurabh Misra 
815dd52495fSSaurabh Misra 	return (0);
816dd52495fSSaurabh Misra }
817dd52495fSSaurabh Misra 
818dd52495fSSaurabh Misra static void
bfe_cam_write(bfe_t * bfe,uchar_t * d,int index)819dd52495fSSaurabh Misra bfe_cam_write(bfe_t *bfe, uchar_t *d, int index)
820dd52495fSSaurabh Misra {
821dd52495fSSaurabh Misra 	uint32_t v;
822dd52495fSSaurabh Misra 
823dd52495fSSaurabh Misra 	v = ((uint32_t)d[2] << 24);
824dd52495fSSaurabh Misra 	v |= ((uint32_t)d[3] << 16);
825dd52495fSSaurabh Misra 	v |= ((uint32_t)d[4] << 8);
826dd52495fSSaurabh Misra 	v |= (uint32_t)d[5];
827dd52495fSSaurabh Misra 
828dd52495fSSaurabh Misra 	OUTL(bfe, BFE_CAM_DATA_LO, v);
829dd52495fSSaurabh Misra 	v = (BFE_CAM_HI_VALID |
830dd52495fSSaurabh Misra 	    (((uint32_t)d[0]) << 8) |
831dd52495fSSaurabh Misra 	    (((uint32_t)d[1])));
832dd52495fSSaurabh Misra 
833dd52495fSSaurabh Misra 	OUTL(bfe, BFE_CAM_DATA_HI, v);
834dd52495fSSaurabh Misra 	OUTL(bfe, BFE_CAM_CTRL, (BFE_CAM_WRITE |
835dd52495fSSaurabh Misra 	    ((uint32_t)index << BFE_CAM_INDEX_SHIFT)));
836dd52495fSSaurabh Misra 	(void) bfe_wait_bit(bfe, BFE_CAM_CTRL, BFE_CAM_BUSY, 10, 1);
837dd52495fSSaurabh Misra }
838dd52495fSSaurabh Misra 
839dd52495fSSaurabh Misra /*
840dd52495fSSaurabh Misra  * Chip related functions (halt, reset, start).
841dd52495fSSaurabh Misra  */
842dd52495fSSaurabh Misra static void
bfe_chip_halt(bfe_t * bfe)843dd52495fSSaurabh Misra bfe_chip_halt(bfe_t *bfe)
844dd52495fSSaurabh Misra {
845dd52495fSSaurabh Misra 	/*
846dd52495fSSaurabh Misra 	 * Disables interrupts.
847dd52495fSSaurabh Misra 	 */
848dd52495fSSaurabh Misra 	OUTL(bfe, BFE_INTR_MASK, 0);
849dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_INTR_MASK);
850dd52495fSSaurabh Misra 
851dd52495fSSaurabh Misra 	OUTL(bfe,  BFE_ENET_CTRL, BFE_ENET_DISABLE);
852dd52495fSSaurabh Misra 
853dd52495fSSaurabh Misra 	/*
854dd52495fSSaurabh Misra 	 * Wait until TX and RX finish their job.
855dd52495fSSaurabh Misra 	 */
856dd52495fSSaurabh Misra 	(void) bfe_wait_bit(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE, 20, 1);
857dd52495fSSaurabh Misra 
858dd52495fSSaurabh Misra 	/*
859dd52495fSSaurabh Misra 	 * Disables DMA engine.
860dd52495fSSaurabh Misra 	 */
861dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMARX_CTRL, 0);
862dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMATX_CTRL, 0);
863dd52495fSSaurabh Misra 
864dd52495fSSaurabh Misra 	drv_usecwait(10);
865dd52495fSSaurabh Misra 
866dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_HALT;
867dd52495fSSaurabh Misra }
868dd52495fSSaurabh Misra 
869dd52495fSSaurabh Misra static void
bfe_chip_restart(bfe_t * bfe)870dd52495fSSaurabh Misra bfe_chip_restart(bfe_t *bfe)
871dd52495fSSaurabh Misra {
872dd52495fSSaurabh Misra 	DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit,
873dd52495fSSaurabh Misra 	    int, bfe->bfe_chip_action);
874dd52495fSSaurabh Misra 
875dd52495fSSaurabh Misra 	/*
876dd52495fSSaurabh Misra 	 * Halt chip and PHY.
877dd52495fSSaurabh Misra 	 */
878dd52495fSSaurabh Misra 	bfe_chip_halt(bfe);
879dd52495fSSaurabh Misra 	bfe_stop_phy(bfe);
880dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_STOPPED;
881dd52495fSSaurabh Misra 
882dd52495fSSaurabh Misra 	/*
883dd52495fSSaurabh Misra 	 * Init variables.
884dd52495fSSaurabh Misra 	 */
885dd52495fSSaurabh Misra 	bfe_init_vars(bfe);
886dd52495fSSaurabh Misra 
887dd52495fSSaurabh Misra 	/*
888dd52495fSSaurabh Misra 	 * Reset chip and start PHY.
889dd52495fSSaurabh Misra 	 */
890dd52495fSSaurabh Misra 	bfe_chip_reset(bfe);
891dd52495fSSaurabh Misra 
892dd52495fSSaurabh Misra 	/*
893dd52495fSSaurabh Misra 	 * DMA descriptor rings.
894dd52495fSSaurabh Misra 	 */
895dd52495fSSaurabh Misra 	bfe_tx_desc_init(&bfe->bfe_tx_ring);
896dd52495fSSaurabh Misra 	bfe_rx_desc_init(&bfe->bfe_rx_ring);
897dd52495fSSaurabh Misra 
898dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_ACTIVE;
899dd52495fSSaurabh Misra 	bfe_set_rx_mode(bfe);
900dd52495fSSaurabh Misra 	bfe_enable_chip_intrs(bfe);
901dd52495fSSaurabh Misra }
902dd52495fSSaurabh Misra 
903dd52495fSSaurabh Misra /*
904dd52495fSSaurabh Misra  * Disables core by stopping the clock.
905dd52495fSSaurabh Misra  */
906dd52495fSSaurabh Misra static void
bfe_core_disable(bfe_t * bfe)907dd52495fSSaurabh Misra bfe_core_disable(bfe_t *bfe)
908dd52495fSSaurabh Misra {
909dd52495fSSaurabh Misra 	if ((INL(bfe, BFE_SBTMSLOW) & BFE_RESET))
910dd52495fSSaurabh Misra 		return;
911dd52495fSSaurabh Misra 
912dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK));
913dd52495fSSaurabh Misra 	(void) bfe_wait_bit(bfe, BFE_SBTMSLOW, BFE_REJECT, 100, 0);
914dd52495fSSaurabh Misra 	(void) bfe_wait_bit(bfe, BFE_SBTMSHIGH, BFE_BUSY, 100, 1);
915dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | BFE_RESET));
916dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_SBTMSLOW);
917dd52495fSSaurabh Misra 	drv_usecwait(10);
918dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET));
919dd52495fSSaurabh Misra 	drv_usecwait(10);
920dd52495fSSaurabh Misra }
921dd52495fSSaurabh Misra 
922dd52495fSSaurabh Misra /*
923dd52495fSSaurabh Misra  * Resets core.
924dd52495fSSaurabh Misra  */
925dd52495fSSaurabh Misra static void
bfe_core_reset(bfe_t * bfe)926dd52495fSSaurabh Misra bfe_core_reset(bfe_t *bfe)
927dd52495fSSaurabh Misra {
928dd52495fSSaurabh Misra 	uint32_t val;
929dd52495fSSaurabh Misra 
930dd52495fSSaurabh Misra 	/*
931dd52495fSSaurabh Misra 	 * First disable the core.
932dd52495fSSaurabh Misra 	 */
933dd52495fSSaurabh Misra 	bfe_core_disable(bfe);
934dd52495fSSaurabh Misra 
935dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
936dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_SBTMSLOW);
937dd52495fSSaurabh Misra 	drv_usecwait(1);
938dd52495fSSaurabh Misra 
939dd52495fSSaurabh Misra 	if (INL(bfe, BFE_SBTMSHIGH) & BFE_SERR)
940dd52495fSSaurabh Misra 		OUTL(bfe, BFE_SBTMSHIGH, 0);
941dd52495fSSaurabh Misra 
942dd52495fSSaurabh Misra 	val = INL(bfe, BFE_SBIMSTATE);
943dd52495fSSaurabh Misra 	if (val & (BFE_IBE | BFE_TO))
944dd52495fSSaurabh Misra 		OUTL(bfe, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO));
945dd52495fSSaurabh Misra 
946dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
947dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_SBTMSLOW);
948dd52495fSSaurabh Misra 	drv_usecwait(1);
949dd52495fSSaurabh Misra 
950dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBTMSLOW, BFE_CLOCK);
951dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_SBTMSLOW);
952dd52495fSSaurabh Misra 	drv_usecwait(1);
953dd52495fSSaurabh Misra }
954dd52495fSSaurabh Misra 
955dd52495fSSaurabh Misra static void
bfe_setup_config(bfe_t * bfe,uint32_t cores)956dd52495fSSaurabh Misra bfe_setup_config(bfe_t *bfe, uint32_t cores)
957dd52495fSSaurabh Misra {
958dd52495fSSaurabh Misra 	uint32_t bar_orig, val;
959dd52495fSSaurabh Misra 
960dd52495fSSaurabh Misra 	/*
961dd52495fSSaurabh Misra 	 * Change bar0 window to map sbtopci registers.
962dd52495fSSaurabh Misra 	 */
963dd52495fSSaurabh Misra 	bar_orig = pci_config_get32(bfe->bfe_conf_handle, BFE_BAR0_WIN);
964dd52495fSSaurabh Misra 	pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, BFE_REG_PCI);
965dd52495fSSaurabh Misra 
966dd52495fSSaurabh Misra 	/* Just read it and don't do anything */
967dd52495fSSaurabh Misra 	val = INL(bfe, BFE_SBIDHIGH) & BFE_IDH_CORE;
968dd52495fSSaurabh Misra 
969dd52495fSSaurabh Misra 	val = INL(bfe, BFE_SBINTVEC);
970dd52495fSSaurabh Misra 	val |= cores;
971dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SBINTVEC, val);
972dd52495fSSaurabh Misra 
973dd52495fSSaurabh Misra 	val = INL(bfe, BFE_SSB_PCI_TRANS_2);
974dd52495fSSaurabh Misra 	val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST;
975dd52495fSSaurabh Misra 	OUTL(bfe, BFE_SSB_PCI_TRANS_2, val);
976dd52495fSSaurabh Misra 
977dd52495fSSaurabh Misra 	/*
978dd52495fSSaurabh Misra 	 * Restore bar0 window mapping.
979dd52495fSSaurabh Misra 	 */
980dd52495fSSaurabh Misra 	pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, bar_orig);
981dd52495fSSaurabh Misra }
982dd52495fSSaurabh Misra 
983dd52495fSSaurabh Misra /*
984dd52495fSSaurabh Misra  * Resets chip and starts PHY.
985dd52495fSSaurabh Misra  */
986dd52495fSSaurabh Misra static void
bfe_chip_reset(bfe_t * bfe)987dd52495fSSaurabh Misra bfe_chip_reset(bfe_t *bfe)
988dd52495fSSaurabh Misra {
989dd52495fSSaurabh Misra 	uint32_t val;
990dd52495fSSaurabh Misra 
991dd52495fSSaurabh Misra 	/* Set the interrupt vector for the enet core */
992dd52495fSSaurabh Misra 	bfe_setup_config(bfe, BFE_INTVEC_ENET0);
993dd52495fSSaurabh Misra 
994dd52495fSSaurabh Misra 	/* check if core is up */
995dd52495fSSaurabh Misra 	val = INL(bfe, BFE_SBTMSLOW) &
996dd52495fSSaurabh Misra 	    (BFE_RESET | BFE_REJECT | BFE_CLOCK);
997dd52495fSSaurabh Misra 
998dd52495fSSaurabh Misra 	if (val == BFE_CLOCK) {
999dd52495fSSaurabh Misra 		OUTL(bfe, BFE_RCV_LAZY, 0);
1000dd52495fSSaurabh Misra 		OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE);
1001dd52495fSSaurabh Misra 		(void) bfe_wait_bit(bfe, BFE_ENET_CTRL,
1002dd52495fSSaurabh Misra 		    BFE_ENET_DISABLE, 10, 1);
1003dd52495fSSaurabh Misra 		OUTL(bfe, BFE_DMATX_CTRL, 0);
1004dd52495fSSaurabh Misra 		FLUSH(bfe, BFE_DMARX_STAT);
1005dd52495fSSaurabh Misra 		drv_usecwait(20000);	/* 20 milli seconds */
1006dd52495fSSaurabh Misra 		if (INL(bfe, BFE_DMARX_STAT) & BFE_STAT_EMASK) {
1007dd52495fSSaurabh Misra 			(void) bfe_wait_bit(bfe, BFE_DMARX_STAT, BFE_STAT_SIDLE,
1008dd52495fSSaurabh Misra 			    10, 0);
1009dd52495fSSaurabh Misra 		}
1010dd52495fSSaurabh Misra 		OUTL(bfe, BFE_DMARX_CTRL, 0);
1011dd52495fSSaurabh Misra 	}
1012dd52495fSSaurabh Misra 
1013dd52495fSSaurabh Misra 	bfe_core_reset(bfe);
1014dd52495fSSaurabh Misra 	bfe_clear_stats(bfe);
1015dd52495fSSaurabh Misra 
1016dd52495fSSaurabh Misra 	OUTL(bfe, BFE_MDIO_CTRL, 0x8d);
1017dd52495fSSaurabh Misra 	val = INL(bfe, BFE_DEVCTRL);
1018dd52495fSSaurabh Misra 	if (!(val & BFE_IPP))
1019dd52495fSSaurabh Misra 		OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_EPSEL);
1020dd52495fSSaurabh Misra 	else if (INL(bfe, BFE_DEVCTRL & BFE_EPR)) {
1021dd52495fSSaurabh Misra 		OUTL_AND(bfe, BFE_DEVCTRL, ~BFE_EPR);
1022dd52495fSSaurabh Misra 		drv_usecwait(20000);    /* 20 milli seconds */
1023dd52495fSSaurabh Misra 	}
1024dd52495fSSaurabh Misra 
1025dd52495fSSaurabh Misra 	OUTL_OR(bfe, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED);
1026dd52495fSSaurabh Misra 
1027dd52495fSSaurabh Misra 	OUTL_AND(bfe, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN);
1028dd52495fSSaurabh Misra 
1029dd52495fSSaurabh Misra 	OUTL(bfe, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) &
1030dd52495fSSaurabh Misra 	    BFE_LAZY_FC_MASK));
1031dd52495fSSaurabh Misra 
1032dd52495fSSaurabh Misra 	OUTL_OR(bfe, BFE_RCV_LAZY, 0);
1033dd52495fSSaurabh Misra 
1034dd52495fSSaurabh Misra 	OUTL(bfe, BFE_RXMAXLEN, bfe->bfe_rx_ring.r_buf_len);
1035dd52495fSSaurabh Misra 	OUTL(bfe, BFE_TXMAXLEN, bfe->bfe_tx_ring.r_buf_len);
1036dd52495fSSaurabh Misra 
1037dd52495fSSaurabh Misra 	OUTL(bfe, BFE_TX_WMARK, 56);
1038dd52495fSSaurabh Misra 
1039dd52495fSSaurabh Misra 	/* Program DMA channels */
1040dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE);
1041dd52495fSSaurabh Misra 
1042dd52495fSSaurabh Misra 	/*
1043dd52495fSSaurabh Misra 	 * DMA addresses need to be added to BFE_PCI_DMA
1044dd52495fSSaurabh Misra 	 */
1045dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMATX_ADDR,
1046dd52495fSSaurabh Misra 	    bfe->bfe_tx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA);
1047dd52495fSSaurabh Misra 
1048dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT)
1049dd52495fSSaurabh Misra 	    | BFE_RX_CTRL_ENABLE);
1050dd52495fSSaurabh Misra 
1051dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMARX_ADDR,
1052dd52495fSSaurabh Misra 	    bfe->bfe_rx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA);
1053dd52495fSSaurabh Misra 
1054dd52495fSSaurabh Misra 	(void) bfe_startup_phy(bfe);
1055dd52495fSSaurabh Misra 
1056dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_INITIALIZED;
1057dd52495fSSaurabh Misra }
1058dd52495fSSaurabh Misra 
1059dd52495fSSaurabh Misra /*
1060dd52495fSSaurabh Misra  * It enables interrupts. Should be the last step while starting chip.
1061dd52495fSSaurabh Misra  */
1062dd52495fSSaurabh Misra static void
bfe_enable_chip_intrs(bfe_t * bfe)1063dd52495fSSaurabh Misra bfe_enable_chip_intrs(bfe_t *bfe)
1064dd52495fSSaurabh Misra {
1065dd52495fSSaurabh Misra 	/* Enable the chip and core */
1066dd52495fSSaurabh Misra 	OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_ENABLE);
1067dd52495fSSaurabh Misra 
1068dd52495fSSaurabh Misra 	/* Enable interrupts */
1069dd52495fSSaurabh Misra 	OUTL(bfe, BFE_INTR_MASK, BFE_IMASK_DEF);
1070dd52495fSSaurabh Misra }
1071dd52495fSSaurabh Misra 
1072dd52495fSSaurabh Misra /*
1073dd52495fSSaurabh Misra  * Common code to take care of setting RX side mode (filter).
1074dd52495fSSaurabh Misra  */
1075dd52495fSSaurabh Misra static void
bfe_set_rx_mode(bfe_t * bfe)1076dd52495fSSaurabh Misra bfe_set_rx_mode(bfe_t *bfe)
1077dd52495fSSaurabh Misra {
1078dd52495fSSaurabh Misra 	uint32_t val;
1079dd52495fSSaurabh Misra 	int i;
1080dd52495fSSaurabh Misra 	ether_addr_t mac[ETHERADDRL] = {0, 0, 0, 0, 0, 0};
1081dd52495fSSaurabh Misra 
1082dd52495fSSaurabh Misra 	/*
1083dd52495fSSaurabh Misra 	 * We don't touch RX filter if we were asked to suspend. It's fine
1084dd52495fSSaurabh Misra 	 * if chip is not active (no interface is plumbed on us).
1085dd52495fSSaurabh Misra 	 */
1086dd52495fSSaurabh Misra 	if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED)
1087dd52495fSSaurabh Misra 		return;
1088dd52495fSSaurabh Misra 
1089dd52495fSSaurabh Misra 	val = INL(bfe, BFE_RXCONF);
1090dd52495fSSaurabh Misra 
1091dd52495fSSaurabh Misra 	val &= ~BFE_RXCONF_PROMISC;
1092dd52495fSSaurabh Misra 	val &= ~BFE_RXCONF_DBCAST;
1093dd52495fSSaurabh Misra 
1094dd52495fSSaurabh Misra 	if ((bfe->bfe_chip_mode & BFE_RX_MODE_ENABLE) == 0) {
1095dd52495fSSaurabh Misra 		OUTL(bfe, BFE_CAM_CTRL, 0);
1096dd52495fSSaurabh Misra 		FLUSH(bfe, BFE_CAM_CTRL);
1097dd52495fSSaurabh Misra 	} else if (bfe->bfe_chip_mode & BFE_RX_MODE_PROMISC) {
1098dd52495fSSaurabh Misra 		val |= BFE_RXCONF_PROMISC;
1099dd52495fSSaurabh Misra 		val &= ~BFE_RXCONF_DBCAST;
1100dd52495fSSaurabh Misra 	} else {
1101dd52495fSSaurabh Misra 		if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
1102dd52495fSSaurabh Misra 			/* Flush everything */
1103dd52495fSSaurabh Misra 			OUTL(bfe, BFE_RXCONF, val |
1104dd52495fSSaurabh Misra 			    BFE_RXCONF_PROMISC | BFE_RXCONF_ALLMULTI);
1105dd52495fSSaurabh Misra 			FLUSH(bfe, BFE_RXCONF);
1106dd52495fSSaurabh Misra 		}
1107dd52495fSSaurabh Misra 
1108dd52495fSSaurabh Misra 		/* Disable CAM */
1109dd52495fSSaurabh Misra 		OUTL(bfe, BFE_CAM_CTRL, 0);
1110dd52495fSSaurabh Misra 		FLUSH(bfe, BFE_CAM_CTRL);
1111dd52495fSSaurabh Misra 
1112dd52495fSSaurabh Misra 		/*
1113dd52495fSSaurabh Misra 		 * We receive all multicast packets.
1114dd52495fSSaurabh Misra 		 */
1115dd52495fSSaurabh Misra 		val |= BFE_RXCONF_ALLMULTI;
1116dd52495fSSaurabh Misra 
1117dd52495fSSaurabh Misra 		for (i = 0; i < BFE_MAX_MULTICAST_TABLE - 1; i++) {
1118dd52495fSSaurabh Misra 			bfe_cam_write(bfe, (uchar_t *)mac, i);
1119dd52495fSSaurabh Misra 		}
1120dd52495fSSaurabh Misra 
1121dd52495fSSaurabh Misra 		bfe_cam_write(bfe, bfe->bfe_ether_addr, i);
1122dd52495fSSaurabh Misra 
1123dd52495fSSaurabh Misra 		/* Enable CAM */
1124dd52495fSSaurabh Misra 		OUTL_OR(bfe, BFE_CAM_CTRL, BFE_CAM_ENABLE);
1125dd52495fSSaurabh Misra 		FLUSH(bfe, BFE_CAM_CTRL);
1126dd52495fSSaurabh Misra 	}
1127dd52495fSSaurabh Misra 
1128dd52495fSSaurabh Misra 	DTRACE_PROBE2(rx__mode__filter, int, bfe->bfe_unit,
1129dd52495fSSaurabh Misra 	    int, val);
1130dd52495fSSaurabh Misra 
1131dd52495fSSaurabh Misra 	OUTL(bfe, BFE_RXCONF, val);
1132dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_RXCONF);
1133dd52495fSSaurabh Misra }
1134dd52495fSSaurabh Misra 
1135dd52495fSSaurabh Misra /*
1136dd52495fSSaurabh Misra  * Reset various variable values to initial state.
1137dd52495fSSaurabh Misra  */
1138dd52495fSSaurabh Misra static void
bfe_init_vars(bfe_t * bfe)1139dd52495fSSaurabh Misra bfe_init_vars(bfe_t *bfe)
1140dd52495fSSaurabh Misra {
1141dd52495fSSaurabh Misra 	bfe->bfe_chip_mode = BFE_RX_MODE_ENABLE;
1142dd52495fSSaurabh Misra 
1143dd52495fSSaurabh Misra 	/* Initial assumption */
1144dd52495fSSaurabh Misra 	bfe->bfe_chip.link = LINK_STATE_UNKNOWN;
1145dd52495fSSaurabh Misra 	bfe->bfe_chip.speed = 0;
1146dd52495fSSaurabh Misra 	bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
1147dd52495fSSaurabh Misra 
1148dd52495fSSaurabh Misra 	bfe->bfe_periodic_id = NULL;
1149dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_UNINITIALIZED;
1150dd52495fSSaurabh Misra 
1151dd52495fSSaurabh Misra 	bfe->bfe_tx_stall_time = 0;
1152dd52495fSSaurabh Misra }
1153dd52495fSSaurabh Misra 
1154dd52495fSSaurabh Misra /*
1155dd52495fSSaurabh Misra  * Initializes TX side descriptor entries (bfe_desc_t). Each descriptor entry
1156dd52495fSSaurabh Misra  * has control (desc_ctl) and address (desc_addr) member.
1157dd52495fSSaurabh Misra  */
1158dd52495fSSaurabh Misra static void
bfe_tx_desc_init(bfe_ring_t * r)1159dd52495fSSaurabh Misra bfe_tx_desc_init(bfe_ring_t *r)
1160dd52495fSSaurabh Misra {
1161dd52495fSSaurabh Misra 	int i;
1162dd52495fSSaurabh Misra 	uint32_t v;
1163dd52495fSSaurabh Misra 
1164dd52495fSSaurabh Misra 	for (i = 0; i < r->r_ndesc; i++) {
1165dd52495fSSaurabh Misra 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl),
1166dd52495fSSaurabh Misra 		    (r->r_buf_dma[i].len & BFE_DESC_LEN));
1167dd52495fSSaurabh Misra 
1168dd52495fSSaurabh Misra 		/*
1169dd52495fSSaurabh Misra 		 * DMA addresses need to be added to BFE_PCI_DMA
1170dd52495fSSaurabh Misra 		 */
1171dd52495fSSaurabh Misra 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr),
1172dd52495fSSaurabh Misra 		    (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA));
1173dd52495fSSaurabh Misra 	}
1174dd52495fSSaurabh Misra 
1175dd52495fSSaurabh Misra 	v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl));
1176dd52495fSSaurabh Misra 	PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl),
1177dd52495fSSaurabh Misra 	    v | BFE_DESC_EOT);
1178dd52495fSSaurabh Misra 
1179dd52495fSSaurabh Misra 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
1180dd52495fSSaurabh Misra 
1181dd52495fSSaurabh Misra 	r->r_curr_desc = 0;
1182dd52495fSSaurabh Misra 	r->r_avail_desc = TX_NUM_DESC;
1183dd52495fSSaurabh Misra 	r->r_cons_desc = 0;
1184dd52495fSSaurabh Misra }
1185dd52495fSSaurabh Misra 
1186dd52495fSSaurabh Misra /*
1187dd52495fSSaurabh Misra  * Initializes RX side descriptor entries (bfe_desc_t). Each descriptor entry
1188dd52495fSSaurabh Misra  * has control (desc_ctl) and address (desc_addr) member.
1189dd52495fSSaurabh Misra  */
1190dd52495fSSaurabh Misra static void
bfe_rx_desc_init(bfe_ring_t * r)1191dd52495fSSaurabh Misra bfe_rx_desc_init(bfe_ring_t *r)
1192dd52495fSSaurabh Misra {
1193dd52495fSSaurabh Misra 	int i;
1194dd52495fSSaurabh Misra 	uint32_t v;
1195dd52495fSSaurabh Misra 
1196dd52495fSSaurabh Misra 	for (i = 0; i < r->r_ndesc; i++) {
1197dd52495fSSaurabh Misra 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl),
1198dd52495fSSaurabh Misra 		    (r->r_buf_dma[i].len& BFE_DESC_LEN));
1199dd52495fSSaurabh Misra 
1200dd52495fSSaurabh Misra 		PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr),
1201dd52495fSSaurabh Misra 		    (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA));
1202dd52495fSSaurabh Misra 
1203dd52495fSSaurabh Misra 		/* Initialize rx header (len, flags) */
1204dd52495fSSaurabh Misra 		bzero(r->r_buf_dma[i].addr, sizeof (bfe_rx_header_t));
1205dd52495fSSaurabh Misra 
1206dd52495fSSaurabh Misra 		(void) SYNC_BUF(r, i, 0, sizeof (bfe_rx_header_t),
1207dd52495fSSaurabh Misra 		    DDI_DMA_SYNC_FORDEV);
1208dd52495fSSaurabh Misra 	}
1209dd52495fSSaurabh Misra 
1210dd52495fSSaurabh Misra 	v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl));
1211dd52495fSSaurabh Misra 	PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl),
1212dd52495fSSaurabh Misra 	    v | BFE_DESC_EOT);
1213dd52495fSSaurabh Misra 
1214dd52495fSSaurabh Misra 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
1215dd52495fSSaurabh Misra 
1216dd52495fSSaurabh Misra 	/* TAIL of RX Descriptor */
1217dd52495fSSaurabh Misra 	OUTL(r->r_bfe, BFE_DMARX_PTR, ((i) * sizeof (bfe_desc_t)));
1218dd52495fSSaurabh Misra 
1219dd52495fSSaurabh Misra 	r->r_curr_desc = 0;
1220dd52495fSSaurabh Misra 	r->r_avail_desc = RX_NUM_DESC;
1221dd52495fSSaurabh Misra }
1222dd52495fSSaurabh Misra 
1223dd52495fSSaurabh Misra static int
bfe_chip_start(bfe_t * bfe)1224dd52495fSSaurabh Misra bfe_chip_start(bfe_t *bfe)
1225dd52495fSSaurabh Misra {
1226954c6b5eSSaurabh Misra 	ASSERT_ALL_LOCKS(bfe);
1227dd52495fSSaurabh Misra 
1228dd52495fSSaurabh Misra 	/*
1229dd52495fSSaurabh Misra 	 * Stop the chip first & then Reset the chip. At last enable interrupts.
1230dd52495fSSaurabh Misra 	 */
1231dd52495fSSaurabh Misra 	bfe_chip_halt(bfe);
1232dd52495fSSaurabh Misra 	bfe_stop_phy(bfe);
1233dd52495fSSaurabh Misra 
1234dd52495fSSaurabh Misra 	/*
1235dd52495fSSaurabh Misra 	 * Reset chip and start PHY.
1236dd52495fSSaurabh Misra 	 */
1237dd52495fSSaurabh Misra 	bfe_chip_reset(bfe);
1238dd52495fSSaurabh Misra 
1239dd52495fSSaurabh Misra 	/*
1240dd52495fSSaurabh Misra 	 * Initailize Descriptor Rings.
1241dd52495fSSaurabh Misra 	 */
1242dd52495fSSaurabh Misra 	bfe_tx_desc_init(&bfe->bfe_tx_ring);
1243dd52495fSSaurabh Misra 	bfe_rx_desc_init(&bfe->bfe_rx_ring);
1244dd52495fSSaurabh Misra 
1245dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_ACTIVE;
1246dd52495fSSaurabh Misra 	bfe->bfe_chip_mode |= BFE_RX_MODE_ENABLE;
1247dd52495fSSaurabh Misra 	bfe_set_rx_mode(bfe);
1248dd52495fSSaurabh Misra 	bfe_enable_chip_intrs(bfe);
1249dd52495fSSaurabh Misra 
1250dd52495fSSaurabh Misra 	/* Check link, speed and duplex mode */
1251dd52495fSSaurabh Misra 	(void) bfe_check_link(bfe);
1252dd52495fSSaurabh Misra 
1253dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
1254dd52495fSSaurabh Misra }
1255dd52495fSSaurabh Misra 
1256dd52495fSSaurabh Misra 
1257dd52495fSSaurabh Misra /*
1258dd52495fSSaurabh Misra  * Clear chip statistics.
1259dd52495fSSaurabh Misra  */
1260dd52495fSSaurabh Misra static void
bfe_clear_stats(bfe_t * bfe)1261dd52495fSSaurabh Misra bfe_clear_stats(bfe_t *bfe)
1262dd52495fSSaurabh Misra {
1263dd52495fSSaurabh Misra 	ulong_t r;
1264dd52495fSSaurabh Misra 
1265dd52495fSSaurabh Misra 	OUTL(bfe, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ);
1266dd52495fSSaurabh Misra 
1267dd52495fSSaurabh Misra 	/*
1268dd52495fSSaurabh Misra 	 * Stat registers are cleared by reading.
1269dd52495fSSaurabh Misra 	 */
1270dd52495fSSaurabh Misra 	for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4)
1271dd52495fSSaurabh Misra 		(void) INL(bfe, r);
1272dd52495fSSaurabh Misra 
1273dd52495fSSaurabh Misra 	for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4)
1274dd52495fSSaurabh Misra 		(void) INL(bfe, r);
1275dd52495fSSaurabh Misra }
1276dd52495fSSaurabh Misra 
1277dd52495fSSaurabh Misra /*
1278dd52495fSSaurabh Misra  * Collect chip statistics.
1279dd52495fSSaurabh Misra  */
1280dd52495fSSaurabh Misra static void
bfe_gather_stats(bfe_t * bfe)1281dd52495fSSaurabh Misra bfe_gather_stats(bfe_t *bfe)
1282dd52495fSSaurabh Misra {
1283dd52495fSSaurabh Misra 	ulong_t r;
1284dd52495fSSaurabh Misra 	uint32_t *v;
1285dd52495fSSaurabh Misra 	uint32_t txerr = 0, rxerr = 0, coll = 0;
1286dd52495fSSaurabh Misra 
1287dd52495fSSaurabh Misra 	v = &bfe->bfe_hw_stats.tx_good_octets;
1288dd52495fSSaurabh Misra 	for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4) {
1289dd52495fSSaurabh Misra 		*v += INL(bfe, r);
1290dd52495fSSaurabh Misra 		v++;
1291dd52495fSSaurabh Misra 	}
1292dd52495fSSaurabh Misra 
1293dd52495fSSaurabh Misra 	v = &bfe->bfe_hw_stats.rx_good_octets;
1294dd52495fSSaurabh Misra 	for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4) {
1295dd52495fSSaurabh Misra 		*v += INL(bfe, r);
1296dd52495fSSaurabh Misra 		v++;
1297dd52495fSSaurabh Misra 	}
1298dd52495fSSaurabh Misra 
1299dd52495fSSaurabh Misra 	/*
1300dd52495fSSaurabh Misra 	 * TX :
1301dd52495fSSaurabh Misra 	 * -------
1302dd52495fSSaurabh Misra 	 * tx_good_octets, tx_good_pkts, tx_octets
1303dd52495fSSaurabh Misra 	 * tx_pkts, tx_broadcast_pkts, tx_multicast_pkts
1304dd52495fSSaurabh Misra 	 * tx_len_64, tx_len_65_to_127, tx_len_128_to_255
1305dd52495fSSaurabh Misra 	 * tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max
1306dd52495fSSaurabh Misra 	 * tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts
1307dd52495fSSaurabh Misra 	 * tx_underruns, tx_total_cols, tx_single_cols
1308dd52495fSSaurabh Misra 	 * tx_multiple_cols, tx_excessive_cols, tx_late_cols
1309dd52495fSSaurabh Misra 	 * tx_defered, tx_carrier_lost, tx_pause_pkts
1310dd52495fSSaurabh Misra 	 *
1311dd52495fSSaurabh Misra 	 * RX :
1312dd52495fSSaurabh Misra 	 * -------
1313dd52495fSSaurabh Misra 	 * rx_good_octets, rx_good_pkts, rx_octets
1314dd52495fSSaurabh Misra 	 * rx_pkts, rx_broadcast_pkts, rx_multicast_pkts
1315dd52495fSSaurabh Misra 	 * rx_len_64, rx_len_65_to_127, rx_len_128_to_255
1316dd52495fSSaurabh Misra 	 * rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max
1317dd52495fSSaurabh Misra 	 * rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts
1318dd52495fSSaurabh Misra 	 * rx_missed_pkts, rx_crc_align_errs, rx_undersize
1319dd52495fSSaurabh Misra 	 * rx_crc_errs, rx_align_errs, rx_symbol_errs
1320dd52495fSSaurabh Misra 	 * rx_pause_pkts, rx_nonpause_pkts
1321dd52495fSSaurabh Misra 	 */
1322dd52495fSSaurabh Misra 
1323dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_carrier_errors =
1324dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.tx_carrier_lost;
1325dd52495fSSaurabh Misra 
1326dd52495fSSaurabh Misra 	/* txerr += bfe->bfe_hw_stats.tx_carrier_lost; */
1327dd52495fSSaurabh Misra 
1328dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_ex_collisions =
1329dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.tx_excessive_cols;
1330dd52495fSSaurabh Misra 	txerr += bfe->bfe_hw_stats.tx_excessive_cols;
1331dd52495fSSaurabh Misra 	coll += bfe->bfe_hw_stats.tx_excessive_cols;
1332dd52495fSSaurabh Misra 
1333dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_fcs_errors =
1334dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.rx_crc_errs;
1335dd52495fSSaurabh Misra 	rxerr += bfe->bfe_hw_stats.rx_crc_errs;
1336dd52495fSSaurabh Misra 
1337dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_first_collisions =
1338dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.tx_single_cols;
1339dd52495fSSaurabh Misra 	coll += bfe->bfe_hw_stats.tx_single_cols;
1340dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_multi_collisions =
1341dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.tx_multiple_cols;
1342dd52495fSSaurabh Misra 	coll += bfe->bfe_hw_stats.tx_multiple_cols;
1343dd52495fSSaurabh Misra 
1344dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_toolong_errors =
1345dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.rx_oversize_pkts;
1346dd52495fSSaurabh Misra 	rxerr += bfe->bfe_hw_stats.rx_oversize_pkts;
1347dd52495fSSaurabh Misra 
1348dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_tooshort_errors =
1349dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.rx_undersize;
1350dd52495fSSaurabh Misra 	rxerr += bfe->bfe_hw_stats.rx_undersize;
1351dd52495fSSaurabh Misra 
1352dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_tx_late_collisions +=
1353dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.tx_late_cols;
1354dd52495fSSaurabh Misra 
1355dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_defer_xmts +=
1356dd52495fSSaurabh Misra 	    bfe->bfe_hw_stats.tx_defered;
1357dd52495fSSaurabh Misra 
1358dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_macrcv_errors += rxerr;
1359dd52495fSSaurabh Misra 	bfe->bfe_stats.ether_stat_macxmt_errors += txerr;
1360dd52495fSSaurabh Misra 
1361dd52495fSSaurabh Misra 	bfe->bfe_stats.collisions += coll;
1362dd52495fSSaurabh Misra }
1363dd52495fSSaurabh Misra 
1364dd52495fSSaurabh Misra /*
1365dd52495fSSaurabh Misra  * Gets the state for dladm command and all.
1366dd52495fSSaurabh Misra  */
1367dd52495fSSaurabh Misra int
bfe_mac_getstat(void * arg,uint_t stat,uint64_t * val)1368dd52495fSSaurabh Misra bfe_mac_getstat(void *arg, uint_t stat, uint64_t *val)
1369dd52495fSSaurabh Misra {
1370dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
1371dd52495fSSaurabh Misra 	uint64_t	v;
1372dd52495fSSaurabh Misra 	int err = 0;
1373dd52495fSSaurabh Misra 
1374dd52495fSSaurabh Misra 	rw_enter(&bfe->bfe_rwlock, RW_READER);
1375dd52495fSSaurabh Misra 
1376dd52495fSSaurabh Misra 
1377dd52495fSSaurabh Misra 	switch (stat) {
1378dd52495fSSaurabh Misra 	default:
1379dd52495fSSaurabh Misra 		err = ENOTSUP;
1380dd52495fSSaurabh Misra 		break;
1381dd52495fSSaurabh Misra 
1382dd52495fSSaurabh Misra 	case MAC_STAT_IFSPEED:
1383dd52495fSSaurabh Misra 		/*
1384dd52495fSSaurabh Misra 		 * MAC layer will ask for IFSPEED first and hence we
1385dd52495fSSaurabh Misra 		 * collect it only once.
1386dd52495fSSaurabh Misra 		 */
1387dd52495fSSaurabh Misra 		if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
1388dd52495fSSaurabh Misra 			/*
1389dd52495fSSaurabh Misra 			 * Update stats from the hardware.
1390dd52495fSSaurabh Misra 			 */
1391dd52495fSSaurabh Misra 			bfe_gather_stats(bfe);
1392dd52495fSSaurabh Misra 		}
1393dd52495fSSaurabh Misra 		v = bfe->bfe_chip.speed;
1394dd52495fSSaurabh Misra 		break;
1395dd52495fSSaurabh Misra 
1396dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_100T4:
1397dd52495fSSaurabh Misra 		v = bfe->bfe_adv_100T4;
1398dd52495fSSaurabh Misra 		break;
1399dd52495fSSaurabh Misra 
1400dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_100FDX:
1401dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX_FD) != 0;
1402dd52495fSSaurabh Misra 		break;
1403dd52495fSSaurabh Misra 
1404dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_100HDX:
1405dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX) != 0;
1406dd52495fSSaurabh Misra 		break;
1407dd52495fSSaurabh Misra 
1408dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_10FDX:
1409dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T_FD) != 0;
1410dd52495fSSaurabh Misra 		break;
1411dd52495fSSaurabh Misra 
1412dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_10HDX:
1413dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T) != 0;
1414dd52495fSSaurabh Misra 		break;
1415dd52495fSSaurabh Misra 
1416dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
1417dd52495fSSaurabh Misra 		v = 0;
1418dd52495fSSaurabh Misra 		break;
1419dd52495fSSaurabh Misra 
1420dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_AUTONEG:
1421dd52495fSSaurabh Misra 		v = bfe->bfe_adv_aneg;
1422dd52495fSSaurabh Misra 		break;
1423dd52495fSSaurabh Misra 
1424dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_CAP_PAUSE:
1425dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anar & MII_ABILITY_PAUSE) != 0;
1426dd52495fSSaurabh Misra 		break;
1427dd52495fSSaurabh Misra 
1428dd52495fSSaurabh Misra 	case ETHER_STAT_ADV_REMFAULT:
1429dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anar & MII_AN_ADVERT_REMFAULT) != 0;
1430dd52495fSSaurabh Misra 		break;
1431dd52495fSSaurabh Misra 
1432dd52495fSSaurabh Misra 	case ETHER_STAT_ALIGN_ERRORS:
1433dd52495fSSaurabh Misra 		/* MIB */
1434dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_align_errors;
1435dd52495fSSaurabh Misra 		break;
1436dd52495fSSaurabh Misra 
1437dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_100T4:
1438dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASE_T4) != 0;
1439dd52495fSSaurabh Misra 		break;
1440dd52495fSSaurabh Misra 
1441dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_100FDX:
1442dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX_FD) != 0;
1443dd52495fSSaurabh Misra 		break;
1444dd52495fSSaurabh Misra 
1445dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_100HDX:
1446dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX) != 0;
1447dd52495fSSaurabh Misra 		break;
1448dd52495fSSaurabh Misra 
1449dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_10FDX:
1450dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmsr & MII_STATUS_10_FD) != 0;
1451dd52495fSSaurabh Misra 		break;
1452dd52495fSSaurabh Misra 
1453dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_10HDX:
1454dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmsr & MII_STATUS_10) != 0;
1455dd52495fSSaurabh Misra 		break;
1456dd52495fSSaurabh Misra 
1457dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_ASMPAUSE:
1458dd52495fSSaurabh Misra 		v = 0;
1459dd52495fSSaurabh Misra 		break;
1460dd52495fSSaurabh Misra 
1461dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_AUTONEG:
1462dd52495fSSaurabh Misra 		v = ((bfe->bfe_mii_bmsr & MII_STATUS_CANAUTONEG) != 0);
1463dd52495fSSaurabh Misra 		break;
1464dd52495fSSaurabh Misra 
1465dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_PAUSE:
1466dd52495fSSaurabh Misra 		v = 1;
1467dd52495fSSaurabh Misra 		break;
1468dd52495fSSaurabh Misra 
1469dd52495fSSaurabh Misra 	case ETHER_STAT_CAP_REMFAULT:
1470dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmsr & MII_STATUS_REMFAULT) != 0;
1471dd52495fSSaurabh Misra 		break;
1472dd52495fSSaurabh Misra 
1473dd52495fSSaurabh Misra 	case ETHER_STAT_CARRIER_ERRORS:
1474dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_carrier_errors;
1475dd52495fSSaurabh Misra 		break;
1476dd52495fSSaurabh Misra 
1477dd52495fSSaurabh Misra 	case ETHER_STAT_JABBER_ERRORS:
1478dd52495fSSaurabh Misra 		err = ENOTSUP;
1479dd52495fSSaurabh Misra 		break;
1480dd52495fSSaurabh Misra 
1481dd52495fSSaurabh Misra 	case ETHER_STAT_DEFER_XMTS:
1482dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_defer_xmts;
1483dd52495fSSaurabh Misra 		break;
1484dd52495fSSaurabh Misra 
1485dd52495fSSaurabh Misra 	case ETHER_STAT_EX_COLLISIONS:
1486dd52495fSSaurabh Misra 		/* MIB */
1487dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_ex_collisions;
1488dd52495fSSaurabh Misra 		break;
1489dd52495fSSaurabh Misra 
1490dd52495fSSaurabh Misra 	case ETHER_STAT_FCS_ERRORS:
1491dd52495fSSaurabh Misra 		/* MIB */
1492dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_fcs_errors;
1493dd52495fSSaurabh Misra 		break;
1494dd52495fSSaurabh Misra 
1495dd52495fSSaurabh Misra 	case ETHER_STAT_FIRST_COLLISIONS:
1496dd52495fSSaurabh Misra 		/* MIB */
1497dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_first_collisions;
1498dd52495fSSaurabh Misra 		break;
1499dd52495fSSaurabh Misra 
1500dd52495fSSaurabh Misra 	case ETHER_STAT_LINK_ASMPAUSE:
1501dd52495fSSaurabh Misra 		v = 0;
1502dd52495fSSaurabh Misra 		break;
1503dd52495fSSaurabh Misra 
1504dd52495fSSaurabh Misra 	case ETHER_STAT_LINK_AUTONEG:
1505dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_bmcr & MII_CONTROL_ANE) != 0 &&
1506dd52495fSSaurabh Misra 		    (bfe->bfe_mii_bmsr & MII_STATUS_ANDONE) != 0;
1507dd52495fSSaurabh Misra 		break;
1508dd52495fSSaurabh Misra 
1509dd52495fSSaurabh Misra 	case ETHER_STAT_LINK_DUPLEX:
1510dd52495fSSaurabh Misra 		v = bfe->bfe_chip.duplex;
1511dd52495fSSaurabh Misra 		break;
1512dd52495fSSaurabh Misra 
1513dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_100T4:
1514dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_T4) != 0;
1515dd52495fSSaurabh Misra 		break;
1516dd52495fSSaurabh Misra 
1517dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_100FDX:
1518dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX_FD) != 0;
1519dd52495fSSaurabh Misra 		break;
1520dd52495fSSaurabh Misra 
1521dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_100HDX:
1522dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX) != 0;
1523dd52495fSSaurabh Misra 		break;
1524dd52495fSSaurabh Misra 
1525dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_10FDX:
1526dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T_FD) != 0;
1527dd52495fSSaurabh Misra 		break;
1528dd52495fSSaurabh Misra 
1529dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_10HDX:
1530dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T) != 0;
1531dd52495fSSaurabh Misra 		break;
1532dd52495fSSaurabh Misra 
1533dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_ASMPAUSE:
1534dd52495fSSaurabh Misra 		v = 0;
1535dd52495fSSaurabh Misra 		break;
1536dd52495fSSaurabh Misra 
1537dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_AUTONEG:
1538dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_exp & MII_AN_EXP_LPCANAN) != 0;
1539dd52495fSSaurabh Misra 		break;
1540dd52495fSSaurabh Misra 
1541dd52495fSSaurabh Misra 	case ETHER_STAT_LP_CAP_PAUSE:
1542dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_ABILITY_PAUSE) != 0;
1543dd52495fSSaurabh Misra 		break;
1544dd52495fSSaurabh Misra 
1545dd52495fSSaurabh Misra 	case ETHER_STAT_LP_REMFAULT:
1546dd52495fSSaurabh Misra 		v = (bfe->bfe_mii_anlpar & MII_STATUS_REMFAULT) != 0;
1547dd52495fSSaurabh Misra 		break;
1548dd52495fSSaurabh Misra 
1549dd52495fSSaurabh Misra 	case ETHER_STAT_MACRCV_ERRORS:
1550dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_macrcv_errors;
1551dd52495fSSaurabh Misra 		break;
1552dd52495fSSaurabh Misra 
1553dd52495fSSaurabh Misra 	case ETHER_STAT_MACXMT_ERRORS:
1554dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_macxmt_errors;
1555dd52495fSSaurabh Misra 		break;
1556dd52495fSSaurabh Misra 
1557dd52495fSSaurabh Misra 	case ETHER_STAT_MULTI_COLLISIONS:
1558dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_multi_collisions;
1559dd52495fSSaurabh Misra 		break;
1560dd52495fSSaurabh Misra 
1561dd52495fSSaurabh Misra 	case ETHER_STAT_SQE_ERRORS:
1562dd52495fSSaurabh Misra 		err = ENOTSUP;
1563dd52495fSSaurabh Misra 		break;
1564dd52495fSSaurabh Misra 
1565dd52495fSSaurabh Misra 	case ETHER_STAT_TOOLONG_ERRORS:
1566dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_toolong_errors;
1567dd52495fSSaurabh Misra 		break;
1568dd52495fSSaurabh Misra 
1569dd52495fSSaurabh Misra 	case ETHER_STAT_TOOSHORT_ERRORS:
1570dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_tooshort_errors;
1571dd52495fSSaurabh Misra 		break;
1572dd52495fSSaurabh Misra 
1573dd52495fSSaurabh Misra 	case ETHER_STAT_TX_LATE_COLLISIONS:
1574dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_tx_late_collisions;
1575dd52495fSSaurabh Misra 		break;
1576dd52495fSSaurabh Misra 
1577dd52495fSSaurabh Misra 	case ETHER_STAT_XCVR_ADDR:
1578dd52495fSSaurabh Misra 		v = bfe->bfe_phy_addr;
1579dd52495fSSaurabh Misra 		break;
1580dd52495fSSaurabh Misra 
1581dd52495fSSaurabh Misra 	case ETHER_STAT_XCVR_ID:
1582dd52495fSSaurabh Misra 		v = bfe->bfe_phy_id;
1583dd52495fSSaurabh Misra 		break;
1584dd52495fSSaurabh Misra 
1585dd52495fSSaurabh Misra 	case MAC_STAT_BRDCSTRCV:
1586dd52495fSSaurabh Misra 		v = bfe->bfe_stats.brdcstrcv;
1587dd52495fSSaurabh Misra 		break;
1588dd52495fSSaurabh Misra 
1589dd52495fSSaurabh Misra 	case MAC_STAT_BRDCSTXMT:
1590dd52495fSSaurabh Misra 		v = bfe->bfe_stats.brdcstxmt;
1591dd52495fSSaurabh Misra 		break;
1592dd52495fSSaurabh Misra 
1593dd52495fSSaurabh Misra 	case MAC_STAT_MULTIXMT:
1594dd52495fSSaurabh Misra 		v = bfe->bfe_stats.multixmt;
1595dd52495fSSaurabh Misra 		break;
1596dd52495fSSaurabh Misra 
1597dd52495fSSaurabh Misra 	case MAC_STAT_COLLISIONS:
1598dd52495fSSaurabh Misra 		v = bfe->bfe_stats.collisions;
1599dd52495fSSaurabh Misra 		break;
1600dd52495fSSaurabh Misra 
1601dd52495fSSaurabh Misra 	case MAC_STAT_IERRORS:
1602dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ierrors;
1603dd52495fSSaurabh Misra 		break;
1604dd52495fSSaurabh Misra 
1605dd52495fSSaurabh Misra 	case MAC_STAT_IPACKETS:
1606dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ipackets;
1607dd52495fSSaurabh Misra 		break;
1608dd52495fSSaurabh Misra 
1609dd52495fSSaurabh Misra 	case MAC_STAT_MULTIRCV:
1610dd52495fSSaurabh Misra 		v = bfe->bfe_stats.multircv;
1611dd52495fSSaurabh Misra 		break;
1612dd52495fSSaurabh Misra 
1613dd52495fSSaurabh Misra 	case MAC_STAT_NORCVBUF:
1614dd52495fSSaurabh Misra 		v = bfe->bfe_stats.norcvbuf;
1615dd52495fSSaurabh Misra 		break;
1616dd52495fSSaurabh Misra 
1617dd52495fSSaurabh Misra 	case MAC_STAT_NOXMTBUF:
1618dd52495fSSaurabh Misra 		v = bfe->bfe_stats.noxmtbuf;
1619dd52495fSSaurabh Misra 		break;
1620dd52495fSSaurabh Misra 
1621dd52495fSSaurabh Misra 	case MAC_STAT_OBYTES:
1622dd52495fSSaurabh Misra 		v = bfe->bfe_stats.obytes;
1623dd52495fSSaurabh Misra 		break;
1624dd52495fSSaurabh Misra 
1625dd52495fSSaurabh Misra 	case MAC_STAT_OERRORS:
1626dd52495fSSaurabh Misra 		/* MIB */
1627dd52495fSSaurabh Misra 		v = bfe->bfe_stats.ether_stat_macxmt_errors;
1628dd52495fSSaurabh Misra 		break;
1629dd52495fSSaurabh Misra 
1630dd52495fSSaurabh Misra 	case MAC_STAT_OPACKETS:
1631dd52495fSSaurabh Misra 		v = bfe->bfe_stats.opackets;
1632dd52495fSSaurabh Misra 		break;
1633dd52495fSSaurabh Misra 
1634dd52495fSSaurabh Misra 	case MAC_STAT_RBYTES:
1635dd52495fSSaurabh Misra 		v = bfe->bfe_stats.rbytes;
1636dd52495fSSaurabh Misra 		break;
1637dd52495fSSaurabh Misra 
1638dd52495fSSaurabh Misra 	case MAC_STAT_UNDERFLOWS:
1639dd52495fSSaurabh Misra 		v = bfe->bfe_stats.underflows;
1640dd52495fSSaurabh Misra 		break;
1641dd52495fSSaurabh Misra 
1642dd52495fSSaurabh Misra 	case MAC_STAT_OVERFLOWS:
1643dd52495fSSaurabh Misra 		v = bfe->bfe_stats.overflows;
1644dd52495fSSaurabh Misra 		break;
1645dd52495fSSaurabh Misra 	}
1646dd52495fSSaurabh Misra 
1647dd52495fSSaurabh Misra 	rw_exit(&bfe->bfe_rwlock);
1648dd52495fSSaurabh Misra 
1649dd52495fSSaurabh Misra 	*val = v;
1650dd52495fSSaurabh Misra 	return (err);
1651dd52495fSSaurabh Misra }
1652dd52495fSSaurabh Misra 
1653dd52495fSSaurabh Misra int
bfe_mac_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)16540dc2366fSVenugopal Iyer bfe_mac_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
16550dc2366fSVenugopal Iyer     void *val)
1656dd52495fSSaurabh Misra {
1657dd52495fSSaurabh Misra 	bfe_t		*bfe = (bfe_t *)arg;
1658dd52495fSSaurabh Misra 	int		err = 0;
1659dd52495fSSaurabh Misra 
1660dd52495fSSaurabh Misra 	switch (num) {
1661dd52495fSSaurabh Misra 	case MAC_PROP_DUPLEX:
16620dc2366fSVenugopal Iyer 		ASSERT(sz >= sizeof (link_duplex_t));
16630dc2366fSVenugopal Iyer 		bcopy(&bfe->bfe_chip.duplex, val, sizeof (link_duplex_t));
1664dd52495fSSaurabh Misra 		break;
1665dd52495fSSaurabh Misra 
1666dd52495fSSaurabh Misra 	case MAC_PROP_SPEED:
16670dc2366fSVenugopal Iyer 		ASSERT(sz >= sizeof (uint64_t));
16680dc2366fSVenugopal Iyer 		bcopy(&bfe->bfe_chip.speed, val, sizeof (uint64_t));
1669dd52495fSSaurabh Misra 		break;
1670dd52495fSSaurabh Misra 
1671dd52495fSSaurabh Misra 	case MAC_PROP_AUTONEG:
16720dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_aneg;
1673dd52495fSSaurabh Misra 		break;
1674dd52495fSSaurabh Misra 
1675dd52495fSSaurabh Misra 	case MAC_PROP_ADV_100FDX_CAP:
16760dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_100fdx;
1677dd52495fSSaurabh Misra 		break;
16780dc2366fSVenugopal Iyer 
1679dd52495fSSaurabh Misra 	case MAC_PROP_EN_100FDX_CAP:
16800dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_100fdx;
1681dd52495fSSaurabh Misra 		break;
1682dd52495fSSaurabh Misra 
1683dd52495fSSaurabh Misra 	case MAC_PROP_ADV_100HDX_CAP:
16840dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_100hdx;
1685dd52495fSSaurabh Misra 		break;
16860dc2366fSVenugopal Iyer 
1687dd52495fSSaurabh Misra 	case MAC_PROP_EN_100HDX_CAP:
16880dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_100hdx;
1689dd52495fSSaurabh Misra 		break;
1690dd52495fSSaurabh Misra 
1691dd52495fSSaurabh Misra 	case MAC_PROP_ADV_10FDX_CAP:
16920dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_10fdx;
1693dd52495fSSaurabh Misra 		break;
16940dc2366fSVenugopal Iyer 
1695dd52495fSSaurabh Misra 	case MAC_PROP_EN_10FDX_CAP:
16960dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_10fdx;
1697dd52495fSSaurabh Misra 		break;
1698dd52495fSSaurabh Misra 
1699dd52495fSSaurabh Misra 	case MAC_PROP_ADV_10HDX_CAP:
17000dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_10hdx;
1701dd52495fSSaurabh Misra 		break;
17020dc2366fSVenugopal Iyer 
1703dd52495fSSaurabh Misra 	case MAC_PROP_EN_10HDX_CAP:
17040dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_10hdx;
1705dd52495fSSaurabh Misra 		break;
1706dd52495fSSaurabh Misra 
1707dd52495fSSaurabh Misra 	case MAC_PROP_ADV_100T4_CAP:
17080dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_100T4;
1709dd52495fSSaurabh Misra 		break;
17100dc2366fSVenugopal Iyer 
1711dd52495fSSaurabh Misra 	case MAC_PROP_EN_100T4_CAP:
17120dc2366fSVenugopal Iyer 		*(uint8_t *)val = bfe->bfe_adv_100T4;
1713dd52495fSSaurabh Misra 		break;
1714dd52495fSSaurabh Misra 
1715dd52495fSSaurabh Misra 	default:
1716dd52495fSSaurabh Misra 		err = ENOTSUP;
1717dd52495fSSaurabh Misra 	}
1718dd52495fSSaurabh Misra 
1719dd52495fSSaurabh Misra 	return (err);
1720dd52495fSSaurabh Misra }
1721dd52495fSSaurabh Misra 
17220dc2366fSVenugopal Iyer 
17230dc2366fSVenugopal Iyer static void
bfe_mac_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t prh)17240dc2366fSVenugopal Iyer bfe_mac_propinfo(void *arg, const char *name, mac_prop_id_t num,
17250dc2366fSVenugopal Iyer     mac_prop_info_handle_t prh)
17260dc2366fSVenugopal Iyer {
17270dc2366fSVenugopal Iyer 	bfe_t		*bfe = (bfe_t *)arg;
17280dc2366fSVenugopal Iyer 
17290dc2366fSVenugopal Iyer 	switch (num) {
17300dc2366fSVenugopal Iyer 	case MAC_PROP_DUPLEX:
17310dc2366fSVenugopal Iyer 	case MAC_PROP_SPEED:
17320dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100FDX_CAP:
17330dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100HDX_CAP:
17340dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10FDX_CAP:
17350dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10HDX_CAP:
17360dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100T4_CAP:
17377a0c1e29SCrisson Guanghao Hu 	case MAC_PROP_EN_100T4_CAP:
17380dc2366fSVenugopal Iyer 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
17390dc2366fSVenugopal Iyer 		break;
17400dc2366fSVenugopal Iyer 
17410dc2366fSVenugopal Iyer 	case MAC_PROP_AUTONEG:
17420dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_aneg);
17430dc2366fSVenugopal Iyer 		break;
17440dc2366fSVenugopal Iyer 
17450dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100FDX_CAP:
17460dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100fdx);
17470dc2366fSVenugopal Iyer 		break;
17480dc2366fSVenugopal Iyer 
17490dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100HDX_CAP:
17500dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100hdx);
17510dc2366fSVenugopal Iyer 		break;
17520dc2366fSVenugopal Iyer 
17530dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10FDX_CAP:
17540dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10fdx);
17550dc2366fSVenugopal Iyer 		break;
17560dc2366fSVenugopal Iyer 
17570dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10HDX_CAP:
17580dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10hdx);
17590dc2366fSVenugopal Iyer 		break;
17600dc2366fSVenugopal Iyer 	}
17610dc2366fSVenugopal Iyer }
17620dc2366fSVenugopal Iyer 
17630dc2366fSVenugopal Iyer 
1764dd52495fSSaurabh Misra /*ARGSUSED*/
1765dd52495fSSaurabh Misra int
bfe_mac_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)1766dd52495fSSaurabh Misra bfe_mac_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1767dd52495fSSaurabh Misra     const void *val)
1768dd52495fSSaurabh Misra {
1769dd52495fSSaurabh Misra 	bfe_t		*bfe = (bfe_t *)arg;
1770dd52495fSSaurabh Misra 	uint8_t		*advp;
1771dd52495fSSaurabh Misra 	uint8_t		*capp;
1772dd52495fSSaurabh Misra 	int 		r = 0;
1773dd52495fSSaurabh Misra 
1774dd52495fSSaurabh Misra 	switch (num) {
1775dd52495fSSaurabh Misra 	case MAC_PROP_EN_100FDX_CAP:
1776dd52495fSSaurabh Misra 		advp = &bfe->bfe_adv_100fdx;
1777dd52495fSSaurabh Misra 		capp = &bfe->bfe_cap_100fdx;
1778dd52495fSSaurabh Misra 		break;
1779dd52495fSSaurabh Misra 
1780dd52495fSSaurabh Misra 	case MAC_PROP_EN_100HDX_CAP:
1781dd52495fSSaurabh Misra 		advp = &bfe->bfe_adv_100hdx;
1782dd52495fSSaurabh Misra 		capp = &bfe->bfe_cap_100hdx;
1783dd52495fSSaurabh Misra 		break;
1784dd52495fSSaurabh Misra 
1785dd52495fSSaurabh Misra 	case MAC_PROP_EN_10FDX_CAP:
1786dd52495fSSaurabh Misra 		advp = &bfe->bfe_adv_10fdx;
1787dd52495fSSaurabh Misra 		capp = &bfe->bfe_cap_10fdx;
1788dd52495fSSaurabh Misra 		break;
1789dd52495fSSaurabh Misra 
1790dd52495fSSaurabh Misra 	case MAC_PROP_EN_10HDX_CAP:
1791dd52495fSSaurabh Misra 		advp = &bfe->bfe_adv_10hdx;
1792dd52495fSSaurabh Misra 		capp = &bfe->bfe_cap_10hdx;
1793dd52495fSSaurabh Misra 		break;
1794dd52495fSSaurabh Misra 
1795dd52495fSSaurabh Misra 	case MAC_PROP_AUTONEG:
1796dd52495fSSaurabh Misra 		advp = &bfe->bfe_adv_aneg;
1797dd52495fSSaurabh Misra 		capp = &bfe->bfe_cap_aneg;
1798dd52495fSSaurabh Misra 		break;
1799dd52495fSSaurabh Misra 
1800dd52495fSSaurabh Misra 	default:
1801dd52495fSSaurabh Misra 		return (ENOTSUP);
1802dd52495fSSaurabh Misra 	}
1803dd52495fSSaurabh Misra 
1804dd52495fSSaurabh Misra 	if (*capp == 0)
1805dd52495fSSaurabh Misra 		return (ENOTSUP);
1806dd52495fSSaurabh Misra 
1807dd52495fSSaurabh Misra 	bfe_grab_locks(bfe);
1808dd52495fSSaurabh Misra 
1809dd52495fSSaurabh Misra 	if (*advp != *(const uint8_t *)val) {
1810dd52495fSSaurabh Misra 		*advp = *(const uint8_t *)val;
1811dd52495fSSaurabh Misra 
1812dd52495fSSaurabh Misra 		bfe->bfe_chip_action = BFE_ACTION_RESTART_SETPROP;
1813dd52495fSSaurabh Misra 		if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
1814dd52495fSSaurabh Misra 			/*
1815dd52495fSSaurabh Misra 			 * We need to stop the timer before grabbing locks
1816dd52495fSSaurabh Misra 			 * otherwise we can land-up in deadlock with untimeout.
1817dd52495fSSaurabh Misra 			 */
1818dd52495fSSaurabh Misra 			bfe_stop_timer(bfe);
1819dd52495fSSaurabh Misra 
1820dd52495fSSaurabh Misra 			bfe->bfe_chip_action |= BFE_ACTION_RESTART;
1821dd52495fSSaurabh Misra 
1822dd52495fSSaurabh Misra 			bfe_chip_restart(bfe);
1823dd52495fSSaurabh Misra 
1824dd52495fSSaurabh Misra 			/*
1825dd52495fSSaurabh Misra 			 * We leave SETPROP because properties can be
1826dd52495fSSaurabh Misra 			 * temporary.
1827dd52495fSSaurabh Misra 			 */
1828dd52495fSSaurabh Misra 			bfe->bfe_chip_action &= ~(BFE_ACTION_RESTART);
1829dd52495fSSaurabh Misra 			r = 1;
1830dd52495fSSaurabh Misra 		}
1831dd52495fSSaurabh Misra 	}
1832dd52495fSSaurabh Misra 
1833dd52495fSSaurabh Misra 	bfe_release_locks(bfe);
1834dd52495fSSaurabh Misra 
1835dd52495fSSaurabh Misra 	/* kick-off a potential stopped downstream */
1836dd52495fSSaurabh Misra 	if (r)
1837dd52495fSSaurabh Misra 		mac_tx_update(bfe->bfe_machdl);
1838dd52495fSSaurabh Misra 
1839dd52495fSSaurabh Misra 	return (0);
1840dd52495fSSaurabh Misra }
1841dd52495fSSaurabh Misra 
1842dd52495fSSaurabh Misra 
1843dd52495fSSaurabh Misra int
bfe_mac_set_ether_addr(void * arg,const uint8_t * ea)1844dd52495fSSaurabh Misra bfe_mac_set_ether_addr(void *arg, const uint8_t *ea)
1845dd52495fSSaurabh Misra {
1846dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
1847dd52495fSSaurabh Misra 
1848dd52495fSSaurabh Misra 	bfe_grab_locks(bfe);
1849dd52495fSSaurabh Misra 	bcopy(ea, bfe->bfe_ether_addr, ETHERADDRL);
1850dd52495fSSaurabh Misra 	bfe_set_rx_mode(bfe);
1851dd52495fSSaurabh Misra 	bfe_release_locks(bfe);
1852dd52495fSSaurabh Misra 	return (0);
1853dd52495fSSaurabh Misra }
1854dd52495fSSaurabh Misra 
1855dd52495fSSaurabh Misra int
bfe_mac_start(void * arg)1856dd52495fSSaurabh Misra bfe_mac_start(void *arg)
1857dd52495fSSaurabh Misra {
1858dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
1859dd52495fSSaurabh Misra 
1860954c6b5eSSaurabh Misra 	bfe_grab_locks(bfe);
1861954c6b5eSSaurabh Misra 	if (bfe_chip_start(bfe) == DDI_FAILURE) {
1862954c6b5eSSaurabh Misra 		bfe_release_locks(bfe);
1863dd52495fSSaurabh Misra 		return (EINVAL);
1864954c6b5eSSaurabh Misra 	}
1865954c6b5eSSaurabh Misra 
1866954c6b5eSSaurabh Misra 	bfe_release_locks(bfe);
1867954c6b5eSSaurabh Misra 
1868954c6b5eSSaurabh Misra 	mac_tx_update(bfe->bfe_machdl);
1869dd52495fSSaurabh Misra 
1870dd52495fSSaurabh Misra 	return (0);
1871dd52495fSSaurabh Misra }
1872dd52495fSSaurabh Misra 
1873dd52495fSSaurabh Misra void
bfe_mac_stop(void * arg)1874dd52495fSSaurabh Misra bfe_mac_stop(void *arg)
1875dd52495fSSaurabh Misra {
1876dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
1877dd52495fSSaurabh Misra 
1878dd52495fSSaurabh Misra 	/*
1879dd52495fSSaurabh Misra 	 * We need to stop the timer before grabbing locks otherwise
1880dd52495fSSaurabh Misra 	 * we can land-up in deadlock with untimeout.
1881dd52495fSSaurabh Misra 	 */
1882dd52495fSSaurabh Misra 	bfe_stop_timer(bfe);
1883dd52495fSSaurabh Misra 
1884dd52495fSSaurabh Misra 	bfe_grab_locks(bfe);
1885dd52495fSSaurabh Misra 
1886dd52495fSSaurabh Misra 	/*
1887dd52495fSSaurabh Misra 	 * First halt the chip by disabling interrupts.
1888dd52495fSSaurabh Misra 	 */
1889dd52495fSSaurabh Misra 	bfe_chip_halt(bfe);
1890dd52495fSSaurabh Misra 	bfe_stop_phy(bfe);
1891dd52495fSSaurabh Misra 
1892dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_STOPPED;
1893dd52495fSSaurabh Misra 
1894dd52495fSSaurabh Misra 	/*
1895dd52495fSSaurabh Misra 	 * This will leave the PHY running.
1896dd52495fSSaurabh Misra 	 */
1897dd52495fSSaurabh Misra 	bfe_chip_reset(bfe);
1898dd52495fSSaurabh Misra 
1899dd52495fSSaurabh Misra 	/*
1900dd52495fSSaurabh Misra 	 * Disable RX register.
1901dd52495fSSaurabh Misra 	 */
1902dd52495fSSaurabh Misra 	bfe->bfe_chip_mode &= ~BFE_RX_MODE_ENABLE;
1903dd52495fSSaurabh Misra 	bfe_set_rx_mode(bfe);
1904dd52495fSSaurabh Misra 
1905dd52495fSSaurabh Misra 	bfe_release_locks(bfe);
1906dd52495fSSaurabh Misra }
1907dd52495fSSaurabh Misra 
1908dd52495fSSaurabh Misra /*
1909dd52495fSSaurabh Misra  * Send a packet down the wire.
1910dd52495fSSaurabh Misra  */
1911dd52495fSSaurabh Misra static int
bfe_send_a_packet(bfe_t * bfe,mblk_t * mp)1912dd52495fSSaurabh Misra bfe_send_a_packet(bfe_t *bfe, mblk_t *mp)
1913dd52495fSSaurabh Misra {
1914dd52495fSSaurabh Misra 	bfe_ring_t *r = &bfe->bfe_tx_ring;
1915dd52495fSSaurabh Misra 	uint32_t cur = r->r_curr_desc;
1916dd52495fSSaurabh Misra 	uint32_t next;
1917dd52495fSSaurabh Misra 	size_t	pktlen = msgsize(mp);
1918dd52495fSSaurabh Misra 	uchar_t *buf;
1919dd52495fSSaurabh Misra 	uint32_t v;
1920dd52495fSSaurabh Misra 
1921dd52495fSSaurabh Misra 	ASSERT(MUTEX_HELD(&r->r_lock));
1922dd52495fSSaurabh Misra 	ASSERT(mp != NULL);
1923dd52495fSSaurabh Misra 
1924dd52495fSSaurabh Misra 	if (pktlen > r->r_buf_len) {
1925dd52495fSSaurabh Misra 		freemsg(mp);
1926dd52495fSSaurabh Misra 		return (BFE_SUCCESS);
1927dd52495fSSaurabh Misra 	}
1928dd52495fSSaurabh Misra 
1929dd52495fSSaurabh Misra 	/*
1930dd52495fSSaurabh Misra 	 * There is a big reason why we don't check for '0'. It becomes easy
1931dd52495fSSaurabh Misra 	 * for us to not roll over the ring since we are based on producer (tx)
1932dd52495fSSaurabh Misra 	 * and consumer (reclaim by an interrupt) model. Especially when we
1933dd52495fSSaurabh Misra 	 * run out of TX descriptor, chip will send a single interrupt and
1934dd52495fSSaurabh Misra 	 * both producer and consumer counter will be same. So we keep a
1935dd52495fSSaurabh Misra 	 * difference of 1 always.
1936dd52495fSSaurabh Misra 	 */
1937dd52495fSSaurabh Misra 	if (r->r_avail_desc <= 1) {
1938dd52495fSSaurabh Misra 		bfe->bfe_stats.noxmtbuf++;
1939dd52495fSSaurabh Misra 		bfe->bfe_tx_resched = 1;
1940dd52495fSSaurabh Misra 		return (BFE_FAILURE);
1941dd52495fSSaurabh Misra 	}
1942dd52495fSSaurabh Misra 
1943dd52495fSSaurabh Misra 	/*
1944dd52495fSSaurabh Misra 	 * Get the DMA buffer to hold packet.
1945dd52495fSSaurabh Misra 	 */
1946dd52495fSSaurabh Misra 	buf = (uchar_t *)r->r_buf_dma[cur].addr;
1947dd52495fSSaurabh Misra 
1948dd52495fSSaurabh Misra 	mcopymsg(mp, buf);	/* it also frees mp */
1949dd52495fSSaurabh Misra 
1950dd52495fSSaurabh Misra 	/*
1951dd52495fSSaurabh Misra 	 * Gather statistics.
1952dd52495fSSaurabh Misra 	 */
1953dd52495fSSaurabh Misra 	if (buf[0] & 0x1) {
1954dd52495fSSaurabh Misra 		if (bcmp(buf, bfe_broadcast, ETHERADDRL) != 0)
1955dd52495fSSaurabh Misra 			bfe->bfe_stats.multixmt++;
1956dd52495fSSaurabh Misra 		else
1957dd52495fSSaurabh Misra 			bfe->bfe_stats.brdcstxmt++;
1958dd52495fSSaurabh Misra 	}
1959dd52495fSSaurabh Misra 	bfe->bfe_stats.opackets++;
1960dd52495fSSaurabh Misra 	bfe->bfe_stats.obytes += pktlen;
1961dd52495fSSaurabh Misra 
1962dd52495fSSaurabh Misra 
1963dd52495fSSaurabh Misra 	/*
1964dd52495fSSaurabh Misra 	 * Program the DMA descriptor (start and end of frame are same).
1965dd52495fSSaurabh Misra 	 */
1966dd52495fSSaurabh Misra 	next = cur;
1967dd52495fSSaurabh Misra 	v = (pktlen & BFE_DESC_LEN) | BFE_DESC_IOC | BFE_DESC_SOF |
1968dd52495fSSaurabh Misra 	    BFE_DESC_EOF;
1969dd52495fSSaurabh Misra 
1970dd52495fSSaurabh Misra 	if (cur == (TX_NUM_DESC - 1))
1971dd52495fSSaurabh Misra 		v |= BFE_DESC_EOT;
1972dd52495fSSaurabh Misra 
1973dd52495fSSaurabh Misra 	PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_ctl), v);
1974dd52495fSSaurabh Misra 
1975dd52495fSSaurabh Misra 	/*
1976dd52495fSSaurabh Misra 	 * DMA addresses need to be added to BFE_PCI_DMA
1977dd52495fSSaurabh Misra 	 */
1978dd52495fSSaurabh Misra 	PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_addr),
1979dd52495fSSaurabh Misra 	    (r->r_buf_dma[cur].cookie.dmac_laddress + BFE_PCI_DMA));
1980dd52495fSSaurabh Misra 
1981dd52495fSSaurabh Misra 	/*
1982dd52495fSSaurabh Misra 	 * Sync the packet data for the device.
1983dd52495fSSaurabh Misra 	 */
1984dd52495fSSaurabh Misra 	(void) SYNC_BUF(r, cur, 0, pktlen, DDI_DMA_SYNC_FORDEV);
1985dd52495fSSaurabh Misra 
1986dd52495fSSaurabh Misra 	/* Move to next descriptor slot */
1987dd52495fSSaurabh Misra 	BFE_INC_SLOT(next, TX_NUM_DESC);
1988dd52495fSSaurabh Misra 
1989dd52495fSSaurabh Misra 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
1990dd52495fSSaurabh Misra 
1991dd52495fSSaurabh Misra 	r->r_curr_desc = next;
1992dd52495fSSaurabh Misra 
1993dd52495fSSaurabh Misra 	/*
1994dd52495fSSaurabh Misra 	 * The order should be 1,2,3,... for BFE_DMATX_PTR if 0,1,2,3,...
1995dd52495fSSaurabh Misra 	 * descriptor slot are being programmed.
1996dd52495fSSaurabh Misra 	 */
1997dd52495fSSaurabh Misra 	OUTL(bfe, BFE_DMATX_PTR, next * sizeof (bfe_desc_t));
1998dd52495fSSaurabh Misra 	FLUSH(bfe, BFE_DMATX_PTR);
1999dd52495fSSaurabh Misra 
2000dd52495fSSaurabh Misra 	r->r_avail_desc--;
2001dd52495fSSaurabh Misra 
2002dd52495fSSaurabh Misra 	/*
2003dd52495fSSaurabh Misra 	 * Let timeout know that it must reset the chip if a
2004dd52495fSSaurabh Misra 	 * packet is not sent down the wire for more than 5 seconds.
2005dd52495fSSaurabh Misra 	 */
2006dd52495fSSaurabh Misra 	bfe->bfe_tx_stall_time = gethrtime() + (5 * 1000000000ULL);
2007dd52495fSSaurabh Misra 
2008dd52495fSSaurabh Misra 	return (BFE_SUCCESS);
2009dd52495fSSaurabh Misra }
2010dd52495fSSaurabh Misra 
2011dd52495fSSaurabh Misra mblk_t *
bfe_mac_transmit_packet(void * arg,mblk_t * mp)2012dd52495fSSaurabh Misra bfe_mac_transmit_packet(void *arg, mblk_t *mp)
2013dd52495fSSaurabh Misra {
2014dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
2015dd52495fSSaurabh Misra 	bfe_ring_t *r = &bfe->bfe_tx_ring;
2016dd52495fSSaurabh Misra 	mblk_t	*nmp;
2017dd52495fSSaurabh Misra 
2018dd52495fSSaurabh Misra 	mutex_enter(&r->r_lock);
2019dd52495fSSaurabh Misra 
2020dd52495fSSaurabh Misra 	if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
2021954c6b5eSSaurabh Misra 		DTRACE_PROBE1(tx__chip__not__active, int, bfe->bfe_unit);
2022dd52495fSSaurabh Misra 
2023dd52495fSSaurabh Misra 		freemsgchain(mp);
2024dd52495fSSaurabh Misra 		mutex_exit(&r->r_lock);
2025dd52495fSSaurabh Misra 		return (NULL);
2026dd52495fSSaurabh Misra 	}
2027dd52495fSSaurabh Misra 
2028dd52495fSSaurabh Misra 
2029dd52495fSSaurabh Misra 	while (mp != NULL) {
2030dd52495fSSaurabh Misra 		nmp = mp->b_next;
2031dd52495fSSaurabh Misra 		mp->b_next = NULL;
2032dd52495fSSaurabh Misra 
2033dd52495fSSaurabh Misra 		if (bfe_send_a_packet(bfe, mp) == BFE_FAILURE) {
2034dd52495fSSaurabh Misra 			mp->b_next = nmp;
2035dd52495fSSaurabh Misra 			break;
2036dd52495fSSaurabh Misra 		}
2037dd52495fSSaurabh Misra 		mp = nmp;
2038dd52495fSSaurabh Misra 	}
2039dd52495fSSaurabh Misra 
2040dd52495fSSaurabh Misra 	mutex_exit(&r->r_lock);
2041dd52495fSSaurabh Misra 
2042dd52495fSSaurabh Misra 	return (mp);
2043dd52495fSSaurabh Misra }
2044dd52495fSSaurabh Misra 
2045dd52495fSSaurabh Misra int
bfe_mac_set_promisc(void * arg,boolean_t promiscflag)2046dd52495fSSaurabh Misra bfe_mac_set_promisc(void *arg, boolean_t promiscflag)
2047dd52495fSSaurabh Misra {
2048dd52495fSSaurabh Misra 	bfe_t *bfe = (bfe_t *)arg;
2049dd52495fSSaurabh Misra 
2050dd52495fSSaurabh Misra 	bfe_grab_locks(bfe);
2051dd52495fSSaurabh Misra 	if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
2052dd52495fSSaurabh Misra 		bfe_release_locks(bfe);
2053dd52495fSSaurabh Misra 		return (EIO);
2054dd52495fSSaurabh Misra 	}
2055dd52495fSSaurabh Misra 
2056dd52495fSSaurabh Misra 	if (promiscflag) {
2057dd52495fSSaurabh Misra 		/* Set Promiscous on */
2058dd52495fSSaurabh Misra 		bfe->bfe_chip_mode |= BFE_RX_MODE_PROMISC;
2059dd52495fSSaurabh Misra 	} else {
2060dd52495fSSaurabh Misra 		bfe->bfe_chip_mode &= ~BFE_RX_MODE_PROMISC;
2061dd52495fSSaurabh Misra 	}
2062dd52495fSSaurabh Misra 
2063dd52495fSSaurabh Misra 	bfe_set_rx_mode(bfe);
2064dd52495fSSaurabh Misra 	bfe_release_locks(bfe);
2065dd52495fSSaurabh Misra 
2066dd52495fSSaurabh Misra 	return (0);
2067dd52495fSSaurabh Misra }
2068dd52495fSSaurabh Misra 
2069dd52495fSSaurabh Misra int
bfe_mac_set_multicast(void * arg,boolean_t add,const uint8_t * macaddr)2070dd52495fSSaurabh Misra bfe_mac_set_multicast(void *arg, boolean_t add, const uint8_t *macaddr)
2071dd52495fSSaurabh Misra {
2072dd52495fSSaurabh Misra 	/*
2073dd52495fSSaurabh Misra 	 * It was too much of pain to implement multicast in CAM. Instead
2074dd52495fSSaurabh Misra 	 * we never disable multicast filter.
2075dd52495fSSaurabh Misra 	 */
2076dd52495fSSaurabh Misra 	return (0);
2077dd52495fSSaurabh Misra }
2078dd52495fSSaurabh Misra 
2079dd52495fSSaurabh Misra static mac_callbacks_t bfe_mac_callbacks = {
20800dc2366fSVenugopal Iyer 	MC_SETPROP | MC_GETPROP | MC_PROPINFO,
2081dd52495fSSaurabh Misra 	bfe_mac_getstat,	/* gets stats */
2082dd52495fSSaurabh Misra 	bfe_mac_start,		/* starts mac */
2083dd52495fSSaurabh Misra 	bfe_mac_stop,		/* stops mac */
2084dd52495fSSaurabh Misra 	bfe_mac_set_promisc,	/* sets promisc mode for snoop */
2085dd52495fSSaurabh Misra 	bfe_mac_set_multicast,	/* multicast implementation */
2086dd52495fSSaurabh Misra 	bfe_mac_set_ether_addr,	/* sets ethernet address (unicast) */
2087dd52495fSSaurabh Misra 	bfe_mac_transmit_packet, /* transmits packet */
20880dc2366fSVenugopal Iyer 	NULL,
2089dd52495fSSaurabh Misra 	NULL,			/* ioctl */
2090dd52495fSSaurabh Misra 	NULL,			/* getcap */
2091dd52495fSSaurabh Misra 	NULL,			/* open */
2092dd52495fSSaurabh Misra 	NULL,			/* close */
2093dd52495fSSaurabh Misra 	bfe_mac_setprop,
2094dd52495fSSaurabh Misra 	bfe_mac_getprop,
20950dc2366fSVenugopal Iyer 	bfe_mac_propinfo
2096dd52495fSSaurabh Misra };
2097dd52495fSSaurabh Misra 
2098dd52495fSSaurabh Misra static void
bfe_error_handler(bfe_t * bfe,int intr_mask)2099dd52495fSSaurabh Misra bfe_error_handler(bfe_t *bfe, int intr_mask)
2100dd52495fSSaurabh Misra {
2101dd52495fSSaurabh Misra 	uint32_t v;
2102dd52495fSSaurabh Misra 
2103dd52495fSSaurabh Misra 	if (intr_mask & BFE_ISTAT_RFO) {
2104dd52495fSSaurabh Misra 		bfe->bfe_stats.overflows++;
2105954c6b5eSSaurabh Misra 		bfe->bfe_chip_action |=
2106954c6b5eSSaurabh Misra 		    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2107954c6b5eSSaurabh Misra 		goto action;
2108dd52495fSSaurabh Misra 	}
2109dd52495fSSaurabh Misra 
2110dd52495fSSaurabh Misra 	if (intr_mask & BFE_ISTAT_TFU) {
2111dd52495fSSaurabh Misra 		bfe->bfe_stats.underflows++;
2112dd52495fSSaurabh Misra 		return;
2113dd52495fSSaurabh Misra 	}
2114dd52495fSSaurabh Misra 
2115dd52495fSSaurabh Misra 	/* Descriptor Protocol Error */
2116dd52495fSSaurabh Misra 	if (intr_mask & BFE_ISTAT_DPE) {
2117dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip,
2118dd52495fSSaurabh Misra 		    "Descriptor Protocol Error. Halting Chip");
2119dd52495fSSaurabh Misra 		bfe->bfe_chip_action |=
2120dd52495fSSaurabh Misra 		    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2121dd52495fSSaurabh Misra 		goto action;
2122dd52495fSSaurabh Misra 	}
2123dd52495fSSaurabh Misra 
2124dd52495fSSaurabh Misra 	/* Descriptor Error */
2125*00d1eed8SRichard Lowe 	if (intr_mask & BFE_ISTAT_DSCE) {
2126dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "Descriptor Error. Restarting Chip");
2127dd52495fSSaurabh Misra 		goto action;
2128dd52495fSSaurabh Misra 	}
2129dd52495fSSaurabh Misra 
2130dd52495fSSaurabh Misra 	/* Receive Descr. Underflow */
2131dd52495fSSaurabh Misra 	if (intr_mask & BFE_ISTAT_RDU) {
2132dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip,
2133dd52495fSSaurabh Misra 		    "Receive Descriptor Underflow. Restarting Chip");
2134dd52495fSSaurabh Misra 		bfe->bfe_stats.ether_stat_macrcv_errors++;
2135dd52495fSSaurabh Misra 		bfe->bfe_chip_action |=
2136dd52495fSSaurabh Misra 		    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2137dd52495fSSaurabh Misra 		goto action;
2138dd52495fSSaurabh Misra 	}
2139dd52495fSSaurabh Misra 
2140dd52495fSSaurabh Misra 	v = INL(bfe, BFE_DMATX_STAT);
2141dd52495fSSaurabh Misra 
2142dd52495fSSaurabh Misra 	/* Error while sending a packet */
2143dd52495fSSaurabh Misra 	if (v & BFE_STAT_EMASK) {
2144dd52495fSSaurabh Misra 		bfe->bfe_stats.ether_stat_macxmt_errors++;
2145dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip,
2146dd52495fSSaurabh Misra 		    "Error while sending a packet. Restarting Chip");
2147dd52495fSSaurabh Misra 	}
2148dd52495fSSaurabh Misra 
2149dd52495fSSaurabh Misra 	/* Error while receiving a packet */
2150dd52495fSSaurabh Misra 	v = INL(bfe, BFE_DMARX_STAT);
2151dd52495fSSaurabh Misra 	if (v & BFE_RX_FLAG_ERRORS) {
2152dd52495fSSaurabh Misra 		bfe->bfe_stats.ierrors++;
2153dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip,
2154dd52495fSSaurabh Misra 		    "Error while receiving a packet. Restarting Chip");
2155dd52495fSSaurabh Misra 	}
2156dd52495fSSaurabh Misra 
2157dd52495fSSaurabh Misra 
2158dd52495fSSaurabh Misra 	bfe->bfe_chip_action |=
2159dd52495fSSaurabh Misra 	    (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2160dd52495fSSaurabh Misra 
2161dd52495fSSaurabh Misra action:
2162dd52495fSSaurabh Misra 	bfe_chip_halt(bfe);
2163dd52495fSSaurabh Misra }
2164dd52495fSSaurabh Misra 
2165dd52495fSSaurabh Misra /*
2166dd52495fSSaurabh Misra  * It will recycle a RX descriptor slot.
2167dd52495fSSaurabh Misra  */
2168dd52495fSSaurabh Misra static void
bfe_rx_desc_buf_reinit(bfe_t * bfe,uint_t slot)2169dd52495fSSaurabh Misra bfe_rx_desc_buf_reinit(bfe_t *bfe, uint_t slot)
2170dd52495fSSaurabh Misra {
2171dd52495fSSaurabh Misra 	bfe_ring_t *r = &bfe->bfe_rx_ring;
2172dd52495fSSaurabh Misra 	uint32_t v;
2173dd52495fSSaurabh Misra 
2174dd52495fSSaurabh Misra 	slot %= RX_NUM_DESC;
2175dd52495fSSaurabh Misra 
2176dd52495fSSaurabh Misra 	bzero(r->r_buf_dma[slot].addr, sizeof (bfe_rx_header_t));
2177dd52495fSSaurabh Misra 
2178dd52495fSSaurabh Misra 	(void) SYNC_BUF(r, slot, 0, BFE_RX_OFFSET, DDI_DMA_SYNC_FORDEV);
2179dd52495fSSaurabh Misra 
2180dd52495fSSaurabh Misra 	v = r->r_buf_dma[slot].len  & BFE_DESC_LEN;
2181dd52495fSSaurabh Misra 	if (slot == (RX_NUM_DESC - 1))
2182dd52495fSSaurabh Misra 		v |= BFE_DESC_EOT;
2183dd52495fSSaurabh Misra 
2184dd52495fSSaurabh Misra 	PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_ctl), v);
2185dd52495fSSaurabh Misra 
2186dd52495fSSaurabh Misra 	/*
2187dd52495fSSaurabh Misra 	 * DMA addresses need to be added to BFE_PCI_DMA
2188dd52495fSSaurabh Misra 	 */
2189dd52495fSSaurabh Misra 	PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_addr),
2190dd52495fSSaurabh Misra 	    (r->r_buf_dma[slot].cookie.dmac_laddress + BFE_PCI_DMA));
2191dd52495fSSaurabh Misra }
2192dd52495fSSaurabh Misra 
2193dd52495fSSaurabh Misra /*
2194dd52495fSSaurabh Misra  * Gets called from interrupt context to handle RX interrupt.
2195dd52495fSSaurabh Misra  */
2196dd52495fSSaurabh Misra static mblk_t *
bfe_receive(bfe_t * bfe,int intr_mask)2197dd52495fSSaurabh Misra bfe_receive(bfe_t *bfe, int intr_mask)
2198dd52495fSSaurabh Misra {
2199dd52495fSSaurabh Misra 	int rxstat, current;
2200dd52495fSSaurabh Misra 	mblk_t	*mp = NULL, *rx_head, *rx_tail;
2201dd52495fSSaurabh Misra 	uchar_t	*rx_header;
2202dd52495fSSaurabh Misra 	uint16_t len;
2203dd52495fSSaurabh Misra 	uchar_t	*bp;
2204dd52495fSSaurabh Misra 	bfe_ring_t *r = &bfe->bfe_rx_ring;
2205dd52495fSSaurabh Misra 	int i;
2206dd52495fSSaurabh Misra 
2207dd52495fSSaurabh Misra 	rxstat = INL(bfe, BFE_DMARX_STAT);
2208dd52495fSSaurabh Misra 	current = (rxstat & BFE_STAT_CDMASK) / sizeof (bfe_desc_t);
2209dd52495fSSaurabh Misra 	i = r->r_curr_desc;
2210dd52495fSSaurabh Misra 
2211dd52495fSSaurabh Misra 	rx_head = rx_tail = NULL;
2212dd52495fSSaurabh Misra 
2213dd52495fSSaurabh Misra 	DTRACE_PROBE3(receive, int, bfe->bfe_unit,
2214dd52495fSSaurabh Misra 	    int, r->r_curr_desc,
2215dd52495fSSaurabh Misra 	    int, current);
2216dd52495fSSaurabh Misra 
2217dd52495fSSaurabh Misra 	for (i = r->r_curr_desc; i != current;
2218dd52495fSSaurabh Misra 	    BFE_INC_SLOT(i, RX_NUM_DESC)) {
2219dd52495fSSaurabh Misra 
2220dd52495fSSaurabh Misra 		/*
2221dd52495fSSaurabh Misra 		 * Sync the buffer associated with the descriptor table entry.
2222dd52495fSSaurabh Misra 		 */
2223dd52495fSSaurabh Misra 		(void) SYNC_BUF(r, i, 0, r->r_buf_dma[i].len,
2224dd52495fSSaurabh Misra 		    DDI_DMA_SYNC_FORKERNEL);
2225dd52495fSSaurabh Misra 
2226dd52495fSSaurabh Misra 		rx_header = (void *)r->r_buf_dma[i].addr;
2227dd52495fSSaurabh Misra 
2228dd52495fSSaurabh Misra 		/*
2229dd52495fSSaurabh Misra 		 * We do this to make sure we are endian neutral. Chip is
2230dd52495fSSaurabh Misra 		 * big endian.
2231dd52495fSSaurabh Misra 		 *
2232dd52495fSSaurabh Misra 		 * The header looks like :-
2233dd52495fSSaurabh Misra 		 *
2234dd52495fSSaurabh Misra 		 *  Offset 0  -> uint16_t len
2235dd52495fSSaurabh Misra 		 *  Offset 2  -> uint16_t flags
2236dd52495fSSaurabh Misra 		 *  Offset 4  -> uint16_t pad[12]
2237dd52495fSSaurabh Misra 		 */
2238dd52495fSSaurabh Misra 		len = (rx_header[1] << 8) | rx_header[0];
2239dd52495fSSaurabh Misra 		len -= 4;	/* CRC bytes need to be removed */
2240dd52495fSSaurabh Misra 
2241dd52495fSSaurabh Misra 		/*
2242dd52495fSSaurabh Misra 		 * Don't receive this packet if pkt length is greater than
2243dd52495fSSaurabh Misra 		 * MTU + VLAN_TAGSZ.
2244dd52495fSSaurabh Misra 		 */
2245dd52495fSSaurabh Misra 		if (len > r->r_buf_len) {
2246dd52495fSSaurabh Misra 			/* Recycle slot for later use */
2247dd52495fSSaurabh Misra 			bfe_rx_desc_buf_reinit(bfe, i);
2248dd52495fSSaurabh Misra 			continue;
2249dd52495fSSaurabh Misra 		}
2250dd52495fSSaurabh Misra 
2251dd52495fSSaurabh Misra 		if ((mp = allocb(len + VLAN_TAGSZ, BPRI_MED)) != NULL) {
2252dd52495fSSaurabh Misra 			mp->b_rptr += VLAN_TAGSZ;
2253dd52495fSSaurabh Misra 			bp = mp->b_rptr;
2254dd52495fSSaurabh Misra 			mp->b_wptr = bp + len;
2255dd52495fSSaurabh Misra 
2256dd52495fSSaurabh Misra 			/* sizeof (bfe_rx_header_t) + 2 */
2257dd52495fSSaurabh Misra 			bcopy(r->r_buf_dma[i].addr +
2258dd52495fSSaurabh Misra 			    BFE_RX_OFFSET, bp, len);
2259dd52495fSSaurabh Misra 
2260dd52495fSSaurabh Misra 			mp->b_next = NULL;
2261dd52495fSSaurabh Misra 			if (rx_tail == NULL)
2262dd52495fSSaurabh Misra 				rx_head = rx_tail = mp;
2263dd52495fSSaurabh Misra 			else {
2264dd52495fSSaurabh Misra 				rx_tail->b_next = mp;
2265dd52495fSSaurabh Misra 				rx_tail = mp;
2266dd52495fSSaurabh Misra 			}
2267dd52495fSSaurabh Misra 
2268dd52495fSSaurabh Misra 			/* Number of packets received so far */
2269dd52495fSSaurabh Misra 			bfe->bfe_stats.ipackets++;
2270dd52495fSSaurabh Misra 
2271dd52495fSSaurabh Misra 			/* Total bytes of packets received so far */
2272dd52495fSSaurabh Misra 			bfe->bfe_stats.rbytes += len;
2273dd52495fSSaurabh Misra 
2274dd52495fSSaurabh Misra 			if (bcmp(mp->b_rptr, bfe_broadcast, ETHERADDRL) == 0)
2275dd52495fSSaurabh Misra 				bfe->bfe_stats.brdcstrcv++;
2276dd52495fSSaurabh Misra 			else
2277dd52495fSSaurabh Misra 				bfe->bfe_stats.multircv++;
2278dd52495fSSaurabh Misra 		} else {
2279dd52495fSSaurabh Misra 			bfe->bfe_stats.norcvbuf++;
2280dd52495fSSaurabh Misra 			/* Recycle the slot for later use */
2281dd52495fSSaurabh Misra 			bfe_rx_desc_buf_reinit(bfe, i);
2282dd52495fSSaurabh Misra 			break;
2283dd52495fSSaurabh Misra 		}
2284dd52495fSSaurabh Misra 
2285dd52495fSSaurabh Misra 		/*
2286dd52495fSSaurabh Misra 		 * Reinitialize the current descriptor slot's buffer so that
2287dd52495fSSaurabh Misra 		 * it can be reused.
2288dd52495fSSaurabh Misra 		 */
2289dd52495fSSaurabh Misra 		bfe_rx_desc_buf_reinit(bfe, i);
2290dd52495fSSaurabh Misra 	}
2291dd52495fSSaurabh Misra 
2292dd52495fSSaurabh Misra 	r->r_curr_desc = i;
2293dd52495fSSaurabh Misra 
2294dd52495fSSaurabh Misra 	(void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
2295dd52495fSSaurabh Misra 
2296dd52495fSSaurabh Misra 	return (rx_head);
2297dd52495fSSaurabh Misra }
2298dd52495fSSaurabh Misra 
2299dd52495fSSaurabh Misra static int
bfe_tx_reclaim(bfe_ring_t * r)2300dd52495fSSaurabh Misra bfe_tx_reclaim(bfe_ring_t *r)
2301dd52495fSSaurabh Misra {
2302dd52495fSSaurabh Misra 	uint32_t cur, start;
2303dd52495fSSaurabh Misra 	uint32_t v;
2304dd52495fSSaurabh Misra 
2305dd52495fSSaurabh Misra 	cur = INL(r->r_bfe, BFE_DMATX_STAT) & BFE_STAT_CDMASK;
2306dd52495fSSaurabh Misra 	cur = cur / sizeof (bfe_desc_t);
2307dd52495fSSaurabh Misra 
2308dd52495fSSaurabh Misra 	/*
2309dd52495fSSaurabh Misra 	 * Start with the last descriptor consumed by the chip.
2310dd52495fSSaurabh Misra 	 */
2311dd52495fSSaurabh Misra 	start = r->r_cons_desc;
2312dd52495fSSaurabh Misra 
2313dd52495fSSaurabh Misra 	DTRACE_PROBE3(tx__reclaim, int, r->r_bfe->bfe_unit,
2314dd52495fSSaurabh Misra 	    int, start,
2315dd52495fSSaurabh Misra 	    int, cur);
2316dd52495fSSaurabh Misra 
2317dd52495fSSaurabh Misra 	/*
2318dd52495fSSaurabh Misra 	 * There will be at least one descriptor to process.
2319dd52495fSSaurabh Misra 	 */
2320dd52495fSSaurabh Misra 	while (start != cur) {
2321dd52495fSSaurabh Misra 		r->r_avail_desc++;
2322dd52495fSSaurabh Misra 		v = r->r_buf_dma[start].len  & BFE_DESC_LEN;
2323dd52495fSSaurabh Misra 		if (start == (TX_NUM_DESC - 1))
2324dd52495fSSaurabh Misra 			v |= BFE_DESC_EOT;
2325dd52495fSSaurabh Misra 
2326dd52495fSSaurabh Misra 		PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_ctl), v);
2327dd52495fSSaurabh Misra 		PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_addr),
2328dd52495fSSaurabh Misra 		    (r->r_buf_dma[start].cookie.dmac_laddress + BFE_PCI_DMA));
2329dd52495fSSaurabh Misra 
2330dd52495fSSaurabh Misra 		/* Move to next descriptor in TX ring */
2331dd52495fSSaurabh Misra 		BFE_INC_SLOT(start, TX_NUM_DESC);
2332dd52495fSSaurabh Misra 	}
2333dd52495fSSaurabh Misra 
2334dd52495fSSaurabh Misra 	(void) ddi_dma_sync(r->r_desc_dma_handle,
2335dd52495fSSaurabh Misra 	    0, (r->r_ndesc * sizeof (bfe_desc_t)),
2336dd52495fSSaurabh Misra 	    DDI_DMA_SYNC_FORDEV);
2337dd52495fSSaurabh Misra 
2338dd52495fSSaurabh Misra 	r->r_cons_desc = start; 	/* consumed pointer */
2339dd52495fSSaurabh Misra 	r->r_bfe->bfe_tx_stall_time = 0;
2340dd52495fSSaurabh Misra 
2341dd52495fSSaurabh Misra 	return (cur);
2342dd52495fSSaurabh Misra }
2343dd52495fSSaurabh Misra 
2344dd52495fSSaurabh Misra static int
bfe_tx_done(bfe_t * bfe,int intr_mask)2345dd52495fSSaurabh Misra bfe_tx_done(bfe_t *bfe, int intr_mask)
2346dd52495fSSaurabh Misra {
2347dd52495fSSaurabh Misra 	bfe_ring_t *r = &bfe->bfe_tx_ring;
2348dd52495fSSaurabh Misra 	int resched = 0;
2349dd52495fSSaurabh Misra 
2350dd52495fSSaurabh Misra 	mutex_enter(&r->r_lock);
2351dd52495fSSaurabh Misra 	(void) bfe_tx_reclaim(r);
2352dd52495fSSaurabh Misra 
2353dd52495fSSaurabh Misra 	if (bfe->bfe_tx_resched) {
2354dd52495fSSaurabh Misra 		resched = 1;
2355dd52495fSSaurabh Misra 		bfe->bfe_tx_resched = 0;
2356dd52495fSSaurabh Misra 	}
2357dd52495fSSaurabh Misra 	mutex_exit(&r->r_lock);
2358dd52495fSSaurabh Misra 
2359dd52495fSSaurabh Misra 	return (resched);
2360dd52495fSSaurabh Misra }
2361dd52495fSSaurabh Misra 
2362dd52495fSSaurabh Misra /*
2363dd52495fSSaurabh Misra  * ISR for interrupt handling
2364dd52495fSSaurabh Misra  */
2365dd52495fSSaurabh Misra static uint_t
bfe_interrupt(caddr_t arg1,caddr_t arg2)2366dd52495fSSaurabh Misra bfe_interrupt(caddr_t arg1, caddr_t arg2)
2367dd52495fSSaurabh Misra {
2368dd52495fSSaurabh Misra 	bfe_t *bfe =  (void *)arg1;
2369dd52495fSSaurabh Misra 	uint32_t	intr_stat;
2370dd52495fSSaurabh Misra 	mblk_t *rx_head = NULL;
2371dd52495fSSaurabh Misra 	int resched = 0;
2372dd52495fSSaurabh Misra 
2373dd52495fSSaurabh Misra 	/*
2374dd52495fSSaurabh Misra 	 * Grab the lock to avoid stopping the chip while this interrupt
2375dd52495fSSaurabh Misra 	 * is handled.
2376dd52495fSSaurabh Misra 	 */
2377dd52495fSSaurabh Misra 	rw_enter(&bfe->bfe_rwlock, RW_READER);
2378dd52495fSSaurabh Misra 
2379dd52495fSSaurabh Misra 	/*
2380dd52495fSSaurabh Misra 	 * It's necessary to read intr stat again because masking interrupt
2381dd52495fSSaurabh Misra 	 * register does not really mask interrupts coming from the chip.
2382dd52495fSSaurabh Misra 	 */
2383dd52495fSSaurabh Misra 	intr_stat = INL(bfe, BFE_INTR_STAT);
2384dd52495fSSaurabh Misra 	intr_stat &= BFE_IMASK_DEF;
2385dd52495fSSaurabh Misra 	OUTL(bfe, BFE_INTR_STAT, intr_stat);
2386dd52495fSSaurabh Misra 	(void) INL(bfe, BFE_INTR_STAT);
2387dd52495fSSaurabh Misra 
2388dd52495fSSaurabh Misra 	if (intr_stat == 0) {
2389dd52495fSSaurabh Misra 		rw_exit(&bfe->bfe_rwlock);
2390dd52495fSSaurabh Misra 		return (DDI_INTR_UNCLAIMED);
2391dd52495fSSaurabh Misra 	}
2392dd52495fSSaurabh Misra 
2393954c6b5eSSaurabh Misra 	DTRACE_PROBE2(bfe__interrupt, int, bfe->bfe_unit,
2394954c6b5eSSaurabh Misra 	    int, intr_stat);
2395954c6b5eSSaurabh Misra 
2396dd52495fSSaurabh Misra 	if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
2397dd52495fSSaurabh Misra 		/*
2398dd52495fSSaurabh Misra 		 * If chip is suspended then we just return.
2399dd52495fSSaurabh Misra 		 */
2400dd52495fSSaurabh Misra 		if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED) {
2401dd52495fSSaurabh Misra 			rw_exit(&bfe->bfe_rwlock);
2402dd52495fSSaurabh Misra 			DTRACE_PROBE1(interrupt__chip__is__suspend, int,
2403dd52495fSSaurabh Misra 			    bfe->bfe_unit);
2404dd52495fSSaurabh Misra 			return (DDI_INTR_CLAIMED);
2405dd52495fSSaurabh Misra 		}
2406dd52495fSSaurabh Misra 
2407dd52495fSSaurabh Misra 		/*
2408dd52495fSSaurabh Misra 		 * Halt the chip again i.e basically disable interrupts.
2409dd52495fSSaurabh Misra 		 */
2410dd52495fSSaurabh Misra 		bfe_chip_halt(bfe);
2411dd52495fSSaurabh Misra 		rw_exit(&bfe->bfe_rwlock);
2412dd52495fSSaurabh Misra 		DTRACE_PROBE1(interrupt__chip__not__active, int,
2413dd52495fSSaurabh Misra 		    bfe->bfe_unit);
2414dd52495fSSaurabh Misra 		return (DDI_INTR_CLAIMED);
2415dd52495fSSaurabh Misra 	}
2416dd52495fSSaurabh Misra 
2417dd52495fSSaurabh Misra 	/* A packet was received */
2418dd52495fSSaurabh Misra 	if (intr_stat & BFE_ISTAT_RX) {
2419dd52495fSSaurabh Misra 		rx_head = bfe_receive(bfe, intr_stat);
2420dd52495fSSaurabh Misra 	}
2421dd52495fSSaurabh Misra 
2422dd52495fSSaurabh Misra 	/* A packet was sent down the wire */
2423dd52495fSSaurabh Misra 	if (intr_stat & BFE_ISTAT_TX) {
2424dd52495fSSaurabh Misra 		resched = bfe_tx_done(bfe, intr_stat);
2425dd52495fSSaurabh Misra 	}
2426dd52495fSSaurabh Misra 
2427dd52495fSSaurabh Misra 	/* There was an error */
2428dd52495fSSaurabh Misra 	if (intr_stat & BFE_ISTAT_ERRORS) {
2429dd52495fSSaurabh Misra 		bfe_error_handler(bfe, intr_stat);
2430dd52495fSSaurabh Misra 	}
2431dd52495fSSaurabh Misra 
2432dd52495fSSaurabh Misra 	rw_exit(&bfe->bfe_rwlock);
2433dd52495fSSaurabh Misra 
2434dd52495fSSaurabh Misra 	/*
2435dd52495fSSaurabh Misra 	 * Pass the list of packets received from chip to MAC layer.
2436dd52495fSSaurabh Misra 	 */
2437dd52495fSSaurabh Misra 	if (rx_head) {
2438dd52495fSSaurabh Misra 		mac_rx(bfe->bfe_machdl, 0, rx_head);
2439dd52495fSSaurabh Misra 	}
2440dd52495fSSaurabh Misra 
2441dd52495fSSaurabh Misra 	/*
2442dd52495fSSaurabh Misra 	 * Let the MAC start sending pkts to a potential stopped stream.
2443dd52495fSSaurabh Misra 	 */
2444dd52495fSSaurabh Misra 	if (resched)
2445dd52495fSSaurabh Misra 		mac_tx_update(bfe->bfe_machdl);
2446dd52495fSSaurabh Misra 
2447dd52495fSSaurabh Misra 	return (DDI_INTR_CLAIMED);
2448dd52495fSSaurabh Misra }
2449dd52495fSSaurabh Misra 
2450dd52495fSSaurabh Misra /*
2451dd52495fSSaurabh Misra  * Removes registered interrupt handler.
2452dd52495fSSaurabh Misra  */
2453dd52495fSSaurabh Misra static void
bfe_remove_intr(bfe_t * bfe)2454dd52495fSSaurabh Misra bfe_remove_intr(bfe_t *bfe)
2455dd52495fSSaurabh Misra {
2456dd52495fSSaurabh Misra 	(void) ddi_intr_remove_handler(bfe->bfe_intrhdl);
2457dd52495fSSaurabh Misra 	(void) ddi_intr_free(bfe->bfe_intrhdl);
2458dd52495fSSaurabh Misra }
2459dd52495fSSaurabh Misra 
2460dd52495fSSaurabh Misra /*
2461dd52495fSSaurabh Misra  * Add an interrupt for the driver.
2462dd52495fSSaurabh Misra  */
2463dd52495fSSaurabh Misra static int
bfe_add_intr(bfe_t * bfe)2464dd52495fSSaurabh Misra bfe_add_intr(bfe_t *bfe)
2465dd52495fSSaurabh Misra {
2466dd52495fSSaurabh Misra 	int	nintrs = 1;
2467dd52495fSSaurabh Misra 	int ret;
2468dd52495fSSaurabh Misra 
2469dd52495fSSaurabh Misra 	ret = ddi_intr_alloc(bfe->bfe_dip, &bfe->bfe_intrhdl,
2470dd52495fSSaurabh Misra 	    DDI_INTR_TYPE_FIXED,	/* type */
2471dd52495fSSaurabh Misra 	    0,	/* inumber */
2472dd52495fSSaurabh Misra 	    1,	/* count */
2473dd52495fSSaurabh Misra 	    &nintrs,	/* actual nintrs */
2474dd52495fSSaurabh Misra 	    DDI_INTR_ALLOC_STRICT);
2475dd52495fSSaurabh Misra 
2476dd52495fSSaurabh Misra 	if (ret != DDI_SUCCESS) {
2477dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "ddi_intr_alloc() failed"
2478dd52495fSSaurabh Misra 		    " : ret : %d", ret);
2479dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2480dd52495fSSaurabh Misra 	}
2481dd52495fSSaurabh Misra 
2482dd52495fSSaurabh Misra 	ret = ddi_intr_add_handler(bfe->bfe_intrhdl, bfe_interrupt, bfe, NULL);
2483dd52495fSSaurabh Misra 	if (ret != DDI_SUCCESS) {
2484dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "ddi_intr_add_handler() failed");
2485dd52495fSSaurabh Misra 		(void) ddi_intr_free(bfe->bfe_intrhdl);
2486dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2487dd52495fSSaurabh Misra 	}
2488dd52495fSSaurabh Misra 
2489dd52495fSSaurabh Misra 	ret = ddi_intr_get_pri(bfe->bfe_intrhdl, &bfe->bfe_intrpri);
2490dd52495fSSaurabh Misra 	if (ret != DDI_SUCCESS) {
2491dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "ddi_intr_get_pri() failed");
2492dd52495fSSaurabh Misra 		bfe_remove_intr(bfe);
2493dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2494dd52495fSSaurabh Misra 	}
2495dd52495fSSaurabh Misra 
2496dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2497dd52495fSSaurabh Misra }
2498dd52495fSSaurabh Misra 
2499dd52495fSSaurabh Misra 
2500dd52495fSSaurabh Misra /*
2501dd52495fSSaurabh Misra  * Identify chipset family.
2502dd52495fSSaurabh Misra  */
2503dd52495fSSaurabh Misra static int
bfe_identify_hardware(bfe_t * bfe)2504dd52495fSSaurabh Misra bfe_identify_hardware(bfe_t *bfe)
2505dd52495fSSaurabh Misra {
2506dd52495fSSaurabh Misra 	uint16_t	vid, did;
2507dd52495fSSaurabh Misra 	int i;
2508dd52495fSSaurabh Misra 
2509dd52495fSSaurabh Misra 	vid = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_VENID);
2510dd52495fSSaurabh Misra 	did = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_DEVID);
2511dd52495fSSaurabh Misra 
2512dd52495fSSaurabh Misra 	for (i = 0; i < (sizeof (bfe_cards) / sizeof (bfe_cards_t)); i++) {
2513dd52495fSSaurabh Misra 		if (bfe_cards[i].vendor_id == vid &&
2514dd52495fSSaurabh Misra 		    bfe_cards[i].device_id == did) {
2515dd52495fSSaurabh Misra 			return (BFE_SUCCESS);
2516dd52495fSSaurabh Misra 		}
2517dd52495fSSaurabh Misra 	}
2518dd52495fSSaurabh Misra 
2519dd52495fSSaurabh Misra 	bfe_error(bfe->bfe_dip, "bfe driver is attaching to unknown pci%d,%d"
2520dd52495fSSaurabh Misra 	    " vendor/device-id card", vid, did);
2521dd52495fSSaurabh Misra 
2522dd52495fSSaurabh Misra 	return (BFE_SUCCESS);
2523dd52495fSSaurabh Misra }
2524dd52495fSSaurabh Misra 
2525dd52495fSSaurabh Misra /*
2526dd52495fSSaurabh Misra  * Maps device registers.
2527dd52495fSSaurabh Misra  */
2528dd52495fSSaurabh Misra static int
bfe_regs_map(bfe_t * bfe)2529dd52495fSSaurabh Misra bfe_regs_map(bfe_t *bfe)
2530dd52495fSSaurabh Misra {
2531dd52495fSSaurabh Misra 	dev_info_t *dip = bfe->bfe_dip;
2532dd52495fSSaurabh Misra 	int ret;
2533dd52495fSSaurabh Misra 
2534dd52495fSSaurabh Misra 	ret = ddi_regs_map_setup(dip, 1, &bfe->bfe_mem_regset.addr, 0, 0,
2535dd52495fSSaurabh Misra 	    &bfe_dev_attr, &bfe->bfe_mem_regset.hdl);
2536dd52495fSSaurabh Misra 
2537dd52495fSSaurabh Misra 	if (ret != DDI_SUCCESS) {
2538dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "ddi_regs_map_setup failed");
2539dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2540dd52495fSSaurabh Misra 	}
2541dd52495fSSaurabh Misra 
2542dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2543dd52495fSSaurabh Misra }
2544dd52495fSSaurabh Misra 
2545dd52495fSSaurabh Misra static void
bfe_unmap_regs(bfe_t * bfe)2546dd52495fSSaurabh Misra bfe_unmap_regs(bfe_t *bfe)
2547dd52495fSSaurabh Misra {
2548dd52495fSSaurabh Misra 	ddi_regs_map_free(&bfe->bfe_mem_regset.hdl);
2549dd52495fSSaurabh Misra }
2550dd52495fSSaurabh Misra 
2551dd52495fSSaurabh Misra static int
bfe_get_chip_config(bfe_t * bfe)2552dd52495fSSaurabh Misra bfe_get_chip_config(bfe_t *bfe)
2553dd52495fSSaurabh Misra {
2554dd52495fSSaurabh Misra 
2555dd52495fSSaurabh Misra 	bfe->bfe_dev_addr[0] = bfe->bfe_ether_addr[0] =
2556dd52495fSSaurabh Misra 	    INB(bfe, BFE_EEPROM_BASE + 79);
2557dd52495fSSaurabh Misra 
2558dd52495fSSaurabh Misra 	bfe->bfe_dev_addr[1] = bfe->bfe_ether_addr[1] =
2559dd52495fSSaurabh Misra 	    INB(bfe, BFE_EEPROM_BASE + 78);
2560dd52495fSSaurabh Misra 
2561dd52495fSSaurabh Misra 	bfe->bfe_dev_addr[2] = bfe->bfe_ether_addr[2] =
2562dd52495fSSaurabh Misra 	    INB(bfe, BFE_EEPROM_BASE + 81);
2563dd52495fSSaurabh Misra 
2564dd52495fSSaurabh Misra 	bfe->bfe_dev_addr[3] = bfe->bfe_ether_addr[3] =
2565dd52495fSSaurabh Misra 	    INB(bfe, BFE_EEPROM_BASE + 80);
2566dd52495fSSaurabh Misra 
2567dd52495fSSaurabh Misra 	bfe->bfe_dev_addr[4] = bfe->bfe_ether_addr[4] =
2568dd52495fSSaurabh Misra 	    INB(bfe, BFE_EEPROM_BASE + 83);
2569dd52495fSSaurabh Misra 
2570dd52495fSSaurabh Misra 	bfe->bfe_dev_addr[5] = bfe->bfe_ether_addr[5] =
2571dd52495fSSaurabh Misra 	    INB(bfe, BFE_EEPROM_BASE + 82);
2572dd52495fSSaurabh Misra 
2573dd52495fSSaurabh Misra 	bfe->bfe_phy_addr = -1;
2574dd52495fSSaurabh Misra 
2575dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2576dd52495fSSaurabh Misra }
2577dd52495fSSaurabh Misra 
2578dd52495fSSaurabh Misra /*
2579dd52495fSSaurabh Misra  * Ring Management routines
2580dd52495fSSaurabh Misra  */
2581dd52495fSSaurabh Misra static int
bfe_ring_buf_alloc(bfe_t * bfe,bfe_ring_t * r,int slot,int d)2582dd52495fSSaurabh Misra bfe_ring_buf_alloc(bfe_t *bfe, bfe_ring_t *r, int slot, int d)
2583dd52495fSSaurabh Misra {
2584dd52495fSSaurabh Misra 	int err;
2585dd52495fSSaurabh Misra 	uint_t count = 0;
2586dd52495fSSaurabh Misra 
2587dd52495fSSaurabh Misra 	err = ddi_dma_alloc_handle(bfe->bfe_dip,
2588dd52495fSSaurabh Misra 	    &bfe_dma_attr_buf, DDI_DMA_SLEEP, NULL,
2589dd52495fSSaurabh Misra 	    &r->r_buf_dma[slot].handle);
2590dd52495fSSaurabh Misra 
2591dd52495fSSaurabh Misra 	if (err != DDI_SUCCESS) {
2592dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2593dd52495fSSaurabh Misra 		    " alloc_handle failed");
2594dd52495fSSaurabh Misra 		goto fail0;
2595dd52495fSSaurabh Misra 	}
2596dd52495fSSaurabh Misra 
2597dd52495fSSaurabh Misra 	err = ddi_dma_mem_alloc(r->r_buf_dma[slot].handle,
2598dd52495fSSaurabh Misra 	    r->r_buf_len, &bfe_buf_attr, DDI_DMA_STREAMING,
2599dd52495fSSaurabh Misra 	    DDI_DMA_SLEEP, NULL, &r->r_buf_dma[slot].addr,
2600dd52495fSSaurabh Misra 	    &r->r_buf_dma[slot].len,
2601dd52495fSSaurabh Misra 	    &r->r_buf_dma[slot].acchdl);
2602dd52495fSSaurabh Misra 
2603dd52495fSSaurabh Misra 	if (err != DDI_SUCCESS) {
2604dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2605dd52495fSSaurabh Misra 		    " mem_alloc failed :%d", err);
2606dd52495fSSaurabh Misra 		goto fail1;
2607dd52495fSSaurabh Misra 	}
2608dd52495fSSaurabh Misra 
2609dd52495fSSaurabh Misra 	err = ddi_dma_addr_bind_handle(r->r_buf_dma[slot].handle,
2610dd52495fSSaurabh Misra 	    NULL, r->r_buf_dma[slot].addr,
2611dd52495fSSaurabh Misra 	    r->r_buf_dma[slot].len,
2612dd52495fSSaurabh Misra 	    (DDI_DMA_RDWR | DDI_DMA_STREAMING),
2613dd52495fSSaurabh Misra 	    DDI_DMA_SLEEP, NULL,
2614dd52495fSSaurabh Misra 	    &r->r_buf_dma[slot].cookie,
2615dd52495fSSaurabh Misra 	    &count);
2616dd52495fSSaurabh Misra 
2617dd52495fSSaurabh Misra 	if (err != DDI_DMA_MAPPED) {
2618dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2619dd52495fSSaurabh Misra 		    " bind_handle failed");
2620dd52495fSSaurabh Misra 		goto fail2;
2621dd52495fSSaurabh Misra 	}
2622dd52495fSSaurabh Misra 
2623dd52495fSSaurabh Misra 	if (count > 1) {
2624dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2625dd52495fSSaurabh Misra 		    " more than one DMA cookie");
2626dd52495fSSaurabh Misra 		(void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle);
2627dd52495fSSaurabh Misra 		goto fail2;
2628dd52495fSSaurabh Misra 	}
2629dd52495fSSaurabh Misra 
2630dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2631dd52495fSSaurabh Misra fail2:
2632dd52495fSSaurabh Misra 	ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl);
2633dd52495fSSaurabh Misra fail1:
2634dd52495fSSaurabh Misra 	ddi_dma_free_handle(&r->r_buf_dma[slot].handle);
2635dd52495fSSaurabh Misra fail0:
2636dd52495fSSaurabh Misra 	return (DDI_FAILURE);
2637dd52495fSSaurabh Misra }
2638dd52495fSSaurabh Misra 
2639dd52495fSSaurabh Misra static void
bfe_ring_buf_free(bfe_ring_t * r,int slot)2640dd52495fSSaurabh Misra bfe_ring_buf_free(bfe_ring_t *r, int slot)
2641dd52495fSSaurabh Misra {
2642dd52495fSSaurabh Misra 	if (r->r_buf_dma == NULL)
2643dd52495fSSaurabh Misra 		return;
2644dd52495fSSaurabh Misra 
2645dd52495fSSaurabh Misra 	(void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle);
2646dd52495fSSaurabh Misra 	ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl);
2647dd52495fSSaurabh Misra 	ddi_dma_free_handle(&r->r_buf_dma[slot].handle);
2648dd52495fSSaurabh Misra }
2649dd52495fSSaurabh Misra 
2650dd52495fSSaurabh Misra static void
bfe_buffer_free(bfe_ring_t * r)2651dd52495fSSaurabh Misra bfe_buffer_free(bfe_ring_t *r)
2652dd52495fSSaurabh Misra {
2653dd52495fSSaurabh Misra 	int i;
2654dd52495fSSaurabh Misra 
2655dd52495fSSaurabh Misra 	for (i = 0; i < r->r_ndesc; i++) {
2656dd52495fSSaurabh Misra 		bfe_ring_buf_free(r, i);
2657dd52495fSSaurabh Misra 	}
2658dd52495fSSaurabh Misra }
2659dd52495fSSaurabh Misra 
2660dd52495fSSaurabh Misra static void
bfe_ring_desc_free(bfe_ring_t * r)2661dd52495fSSaurabh Misra bfe_ring_desc_free(bfe_ring_t *r)
2662dd52495fSSaurabh Misra {
2663dd52495fSSaurabh Misra 	(void) ddi_dma_unbind_handle(r->r_desc_dma_handle);
2664dd52495fSSaurabh Misra 	ddi_dma_mem_free(&r->r_desc_acc_handle);
2665dd52495fSSaurabh Misra 	ddi_dma_free_handle(&r->r_desc_dma_handle);
2666dd52495fSSaurabh Misra 	kmem_free(r->r_buf_dma, r->r_ndesc * sizeof (bfe_dma_t));
2667dd52495fSSaurabh Misra 
2668dd52495fSSaurabh Misra 	r->r_buf_dma = NULL;
2669dd52495fSSaurabh Misra 	r->r_desc = NULL;
2670dd52495fSSaurabh Misra }
2671dd52495fSSaurabh Misra 
2672dd52495fSSaurabh Misra 
2673dd52495fSSaurabh Misra static int
bfe_ring_desc_alloc(bfe_t * bfe,bfe_ring_t * r,int d)2674dd52495fSSaurabh Misra bfe_ring_desc_alloc(bfe_t *bfe, bfe_ring_t *r, int d)
2675dd52495fSSaurabh Misra {
2676dd52495fSSaurabh Misra 	int err, i, fail = 0;
2677dd52495fSSaurabh Misra 	caddr_t	ring;
2678dd52495fSSaurabh Misra 	size_t	size_krnl = 0, size_dma = 0, ring_len = 0;
2679dd52495fSSaurabh Misra 	ddi_dma_cookie_t cookie;
2680dd52495fSSaurabh Misra 	uint_t	count = 0;
2681dd52495fSSaurabh Misra 
2682dd52495fSSaurabh Misra 	ASSERT(bfe != NULL);
2683dd52495fSSaurabh Misra 
2684dd52495fSSaurabh Misra 	size_krnl = r->r_ndesc * sizeof (bfe_dma_t);
2685dd52495fSSaurabh Misra 	size_dma = r->r_ndesc * sizeof (bfe_desc_t);
2686dd52495fSSaurabh Misra 	r->r_buf_dma = kmem_zalloc(size_krnl, KM_SLEEP);
2687dd52495fSSaurabh Misra 
2688dd52495fSSaurabh Misra 
2689dd52495fSSaurabh Misra 	err = ddi_dma_alloc_handle(bfe->bfe_dip, &bfe_dma_attr_desc,
2690dd52495fSSaurabh Misra 	    DDI_DMA_SLEEP, NULL, &r->r_desc_dma_handle);
2691dd52495fSSaurabh Misra 
2692dd52495fSSaurabh Misra 	if (err != DDI_SUCCESS) {
2693dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
2694dd52495fSSaurabh Misra 		    " ddi_dma_alloc_handle()");
2695dd52495fSSaurabh Misra 		kmem_free(r->r_buf_dma, size_krnl);
2696dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2697dd52495fSSaurabh Misra 	}
2698dd52495fSSaurabh Misra 
2699dd52495fSSaurabh Misra 
2700dd52495fSSaurabh Misra 	err = ddi_dma_mem_alloc(r->r_desc_dma_handle,
2701dd52495fSSaurabh Misra 	    size_dma, &bfe_buf_attr,
2702dd52495fSSaurabh Misra 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
2703dd52495fSSaurabh Misra 	    &ring, &ring_len, &r->r_desc_acc_handle);
2704dd52495fSSaurabh Misra 
2705dd52495fSSaurabh Misra 	if (err != DDI_SUCCESS) {
2706dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
2707dd52495fSSaurabh Misra 		    " ddi_dma_mem_alloc()");
2708dd52495fSSaurabh Misra 		ddi_dma_free_handle(&r->r_desc_dma_handle);
2709dd52495fSSaurabh Misra 		kmem_free(r->r_buf_dma, size_krnl);
2710dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2711dd52495fSSaurabh Misra 	}
2712dd52495fSSaurabh Misra 
2713dd52495fSSaurabh Misra 	err = ddi_dma_addr_bind_handle(r->r_desc_dma_handle,
2714dd52495fSSaurabh Misra 	    NULL, ring, ring_len,
2715dd52495fSSaurabh Misra 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2716dd52495fSSaurabh Misra 	    DDI_DMA_SLEEP, NULL,
2717dd52495fSSaurabh Misra 	    &cookie, &count);
2718dd52495fSSaurabh Misra 
2719dd52495fSSaurabh Misra 	if (err != DDI_SUCCESS) {
2720dd52495fSSaurabh Misra 		bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
2721dd52495fSSaurabh Misra 		    " ddi_dma_addr_bind_handle()");
2722dd52495fSSaurabh Misra 		ddi_dma_mem_free(&r->r_desc_acc_handle);
2723dd52495fSSaurabh Misra 		ddi_dma_free_handle(&r->r_desc_dma_handle);
2724dd52495fSSaurabh Misra 		kmem_free(r->r_buf_dma, size_krnl);
2725dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2726dd52495fSSaurabh Misra 	}
2727dd52495fSSaurabh Misra 
2728dd52495fSSaurabh Misra 	/*
2729dd52495fSSaurabh Misra 	 * We don't want to have multiple cookies. Descriptor should be
2730dd52495fSSaurabh Misra 	 * aligned to PAGESIZE boundary.
2731dd52495fSSaurabh Misra 	 */
2732dd52495fSSaurabh Misra 	ASSERT(count == 1);
2733dd52495fSSaurabh Misra 
2734dd52495fSSaurabh Misra 	/* The actual descriptor for the ring */
2735dd52495fSSaurabh Misra 	r->r_desc_len = ring_len;
2736dd52495fSSaurabh Misra 	r->r_desc_cookie = cookie;
2737dd52495fSSaurabh Misra 
2738dd52495fSSaurabh Misra 	r->r_desc = (void *)ring;
2739dd52495fSSaurabh Misra 
2740dd52495fSSaurabh Misra 	bzero(r->r_desc, size_dma);
2741dd52495fSSaurabh Misra 	bzero(r->r_desc, ring_len);
2742dd52495fSSaurabh Misra 
2743dd52495fSSaurabh Misra 	/* For each descriptor, allocate a DMA buffer */
2744dd52495fSSaurabh Misra 	fail = 0;
2745dd52495fSSaurabh Misra 	for (i = 0; i < r->r_ndesc; i++) {
2746dd52495fSSaurabh Misra 		if (bfe_ring_buf_alloc(bfe, r, i, d) != DDI_SUCCESS) {
2747dd52495fSSaurabh Misra 			i--;
2748dd52495fSSaurabh Misra 			fail = 1;
2749dd52495fSSaurabh Misra 			break;
2750dd52495fSSaurabh Misra 		}
2751dd52495fSSaurabh Misra 	}
2752dd52495fSSaurabh Misra 
2753dd52495fSSaurabh Misra 	if (fail) {
2754dd52495fSSaurabh Misra 		while (i-- >= 0) {
2755dd52495fSSaurabh Misra 			bfe_ring_buf_free(r, i);
2756dd52495fSSaurabh Misra 		}
2757dd52495fSSaurabh Misra 
2758dd52495fSSaurabh Misra 		/* We don't need the descriptor anymore */
2759dd52495fSSaurabh Misra 		bfe_ring_desc_free(r);
2760dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2761dd52495fSSaurabh Misra 	}
2762dd52495fSSaurabh Misra 
2763dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2764dd52495fSSaurabh Misra }
2765dd52495fSSaurabh Misra 
2766dd52495fSSaurabh Misra static int
bfe_rings_alloc(bfe_t * bfe)2767dd52495fSSaurabh Misra bfe_rings_alloc(bfe_t *bfe)
2768dd52495fSSaurabh Misra {
2769dd52495fSSaurabh Misra 	/* TX */
2770dd52495fSSaurabh Misra 	mutex_init(&bfe->bfe_tx_ring.r_lock, NULL, MUTEX_DRIVER, NULL);
2771dd52495fSSaurabh Misra 	bfe->bfe_tx_ring.r_lockp = &bfe->bfe_tx_ring.r_lock;
2772dd52495fSSaurabh Misra 	bfe->bfe_tx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) +
2773dd52495fSSaurabh Misra 	    VLAN_TAGSZ + ETHERFCSL;
2774dd52495fSSaurabh Misra 	bfe->bfe_tx_ring.r_ndesc = TX_NUM_DESC;
2775dd52495fSSaurabh Misra 	bfe->bfe_tx_ring.r_bfe = bfe;
2776dd52495fSSaurabh Misra 	bfe->bfe_tx_ring.r_avail_desc = TX_NUM_DESC;
2777dd52495fSSaurabh Misra 
2778dd52495fSSaurabh Misra 	/* RX */
2779dd52495fSSaurabh Misra 	mutex_init(&bfe->bfe_rx_ring.r_lock, NULL, MUTEX_DRIVER, NULL);
2780dd52495fSSaurabh Misra 	bfe->bfe_rx_ring.r_lockp = &bfe->bfe_rx_ring.r_lock;
2781dd52495fSSaurabh Misra 	bfe->bfe_rx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) +
2782dd52495fSSaurabh Misra 	    VLAN_TAGSZ + ETHERFCSL + RX_HEAD_ROOM;
2783dd52495fSSaurabh Misra 	bfe->bfe_rx_ring.r_ndesc = RX_NUM_DESC;
2784dd52495fSSaurabh Misra 	bfe->bfe_rx_ring.r_bfe = bfe;
2785dd52495fSSaurabh Misra 	bfe->bfe_rx_ring.r_avail_desc = RX_NUM_DESC;
2786dd52495fSSaurabh Misra 
2787dd52495fSSaurabh Misra 	/* Allocate TX Ring */
2788dd52495fSSaurabh Misra 	if (bfe_ring_desc_alloc(bfe, &bfe->bfe_tx_ring,
2789dd52495fSSaurabh Misra 	    DDI_DMA_WRITE) != DDI_SUCCESS)
2790dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2791dd52495fSSaurabh Misra 
2792dd52495fSSaurabh Misra 	/* Allocate RX Ring */
2793dd52495fSSaurabh Misra 	if (bfe_ring_desc_alloc(bfe, &bfe->bfe_rx_ring,
2794dd52495fSSaurabh Misra 	    DDI_DMA_READ) != DDI_SUCCESS) {
2795dd52495fSSaurabh Misra 		cmn_err(CE_NOTE, "RX ring allocation failed");
2796dd52495fSSaurabh Misra 		bfe_ring_desc_free(&bfe->bfe_tx_ring);
2797dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2798dd52495fSSaurabh Misra 	}
2799dd52495fSSaurabh Misra 
2800dd52495fSSaurabh Misra 	bfe->bfe_tx_ring.r_flags = BFE_RING_ALLOCATED;
2801dd52495fSSaurabh Misra 	bfe->bfe_rx_ring.r_flags = BFE_RING_ALLOCATED;
2802dd52495fSSaurabh Misra 
2803dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2804dd52495fSSaurabh Misra }
2805dd52495fSSaurabh Misra 
2806dd52495fSSaurabh Misra static int
bfe_resume(dev_info_t * dip)2807dd52495fSSaurabh Misra bfe_resume(dev_info_t *dip)
2808dd52495fSSaurabh Misra {
2809dd52495fSSaurabh Misra 	bfe_t *bfe;
2810dd52495fSSaurabh Misra 	int err = DDI_SUCCESS;
2811dd52495fSSaurabh Misra 
2812dd52495fSSaurabh Misra 	if ((bfe = ddi_get_driver_private(dip)) == NULL) {
2813dd52495fSSaurabh Misra 		bfe_error(dip, "Unexpected error (no driver private data)"
2814dd52495fSSaurabh Misra 		    " while resume");
2815dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2816dd52495fSSaurabh Misra 	}
2817dd52495fSSaurabh Misra 
2818dd52495fSSaurabh Misra 	/*
2819dd52495fSSaurabh Misra 	 * Grab all the locks first.
2820dd52495fSSaurabh Misra 	 */
2821dd52495fSSaurabh Misra 	bfe_grab_locks(bfe);
2822dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_RESUME;
2823dd52495fSSaurabh Misra 
2824dd52495fSSaurabh Misra 	bfe_init_vars(bfe);
2825dd52495fSSaurabh Misra 	/* PHY will also start running */
2826dd52495fSSaurabh Misra 	bfe_chip_reset(bfe);
2827dd52495fSSaurabh Misra 	if (bfe_chip_start(bfe) == DDI_FAILURE) {
2828dd52495fSSaurabh Misra 		bfe_error(dip, "Could not resume chip");
2829dd52495fSSaurabh Misra 		err = DDI_FAILURE;
2830dd52495fSSaurabh Misra 	}
2831954c6b5eSSaurabh Misra 
2832dd52495fSSaurabh Misra 	bfe_release_locks(bfe);
2833954c6b5eSSaurabh Misra 
2834954c6b5eSSaurabh Misra 	if (err == DDI_SUCCESS)
2835954c6b5eSSaurabh Misra 		mac_tx_update(bfe->bfe_machdl);
2836954c6b5eSSaurabh Misra 
2837dd52495fSSaurabh Misra 	return (err);
2838dd52495fSSaurabh Misra }
2839dd52495fSSaurabh Misra 
2840dd52495fSSaurabh Misra static int
bfe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2841dd52495fSSaurabh Misra bfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2842dd52495fSSaurabh Misra {
2843dd52495fSSaurabh Misra 	int	unit;
2844dd52495fSSaurabh Misra 	bfe_t	*bfe;
2845dd52495fSSaurabh Misra 	mac_register_t	*macreg;
2846dd52495fSSaurabh Misra 	int	ret;
2847dd52495fSSaurabh Misra 
2848dd52495fSSaurabh Misra 	switch (cmd) {
2849dd52495fSSaurabh Misra 	case DDI_RESUME:
2850dd52495fSSaurabh Misra 		return (bfe_resume(dip));
2851dd52495fSSaurabh Misra 
2852dd52495fSSaurabh Misra 	case DDI_ATTACH:
2853dd52495fSSaurabh Misra 		break;
2854dd52495fSSaurabh Misra 
2855dd52495fSSaurabh Misra 	default:
2856dd52495fSSaurabh Misra 		return (DDI_FAILURE);
2857dd52495fSSaurabh Misra 	}
2858dd52495fSSaurabh Misra 
2859dd52495fSSaurabh Misra 
2860dd52495fSSaurabh Misra 	unit = ddi_get_instance(dip);
2861dd52495fSSaurabh Misra 
2862dd52495fSSaurabh Misra 	bfe = kmem_zalloc(sizeof (bfe_t), KM_SLEEP);
2863dd52495fSSaurabh Misra 	bfe->bfe_dip = dip;
2864dd52495fSSaurabh Misra 	bfe->bfe_unit = unit;
2865dd52495fSSaurabh Misra 
2866dd52495fSSaurabh Misra 	if (pci_config_setup(dip, &bfe->bfe_conf_handle) != DDI_SUCCESS) {
2867dd52495fSSaurabh Misra 		bfe_error(dip, "pci_config_setup failed");
2868dd52495fSSaurabh Misra 		goto fail0;
2869dd52495fSSaurabh Misra 	}
2870dd52495fSSaurabh Misra 
2871dd52495fSSaurabh Misra 	/*
2872dd52495fSSaurabh Misra 	 * Enable IO space, Bus Master and Memory Space accessess.
2873dd52495fSSaurabh Misra 	 */
2874dd52495fSSaurabh Misra 	ret = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_COMM);
2875dd52495fSSaurabh Misra 	pci_config_put16(bfe->bfe_conf_handle, PCI_CONF_COMM,
2876dd52495fSSaurabh Misra 	    PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | ret);
2877dd52495fSSaurabh Misra 
2878dd52495fSSaurabh Misra 	ddi_set_driver_private(dip, bfe);
2879dd52495fSSaurabh Misra 
2880dd52495fSSaurabh Misra 	/* Identify hardware */
2881dd52495fSSaurabh Misra 	if (bfe_identify_hardware(bfe) == BFE_FAILURE) {
2882dd52495fSSaurabh Misra 		bfe_error(dip, "Could not identify device");
2883dd52495fSSaurabh Misra 		goto fail1;
2884dd52495fSSaurabh Misra 	}
2885dd52495fSSaurabh Misra 
2886dd52495fSSaurabh Misra 	if (bfe_regs_map(bfe) != DDI_SUCCESS) {
2887dd52495fSSaurabh Misra 		bfe_error(dip, "Could not map device registers");
2888dd52495fSSaurabh Misra 		goto fail1;
2889dd52495fSSaurabh Misra 	}
2890dd52495fSSaurabh Misra 
2891dd52495fSSaurabh Misra 	(void) bfe_get_chip_config(bfe);
2892dd52495fSSaurabh Misra 
2893dd52495fSSaurabh Misra 	/*
2894dd52495fSSaurabh Misra 	 * Register with MAC layer
2895dd52495fSSaurabh Misra 	 */
2896dd52495fSSaurabh Misra 	if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
2897dd52495fSSaurabh Misra 		bfe_error(dip, "mac_alloc() failed");
2898dd52495fSSaurabh Misra 		goto fail2;
2899dd52495fSSaurabh Misra 	}
2900dd52495fSSaurabh Misra 
2901dd52495fSSaurabh Misra 	macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2902dd52495fSSaurabh Misra 	macreg->m_driver = bfe;
2903dd52495fSSaurabh Misra 	macreg->m_dip = dip;
2904dd52495fSSaurabh Misra 	macreg->m_instance = unit;
2905dd52495fSSaurabh Misra 	macreg->m_src_addr = bfe->bfe_ether_addr;
2906dd52495fSSaurabh Misra 	macreg->m_callbacks = &bfe_mac_callbacks;
2907dd52495fSSaurabh Misra 	macreg->m_min_sdu = 0;
2908dd52495fSSaurabh Misra 	macreg->m_max_sdu = ETHERMTU;
2909dd52495fSSaurabh Misra 	macreg->m_margin = VLAN_TAGSZ;
2910dd52495fSSaurabh Misra 
2911dd52495fSSaurabh Misra 	if ((ret = mac_register(macreg, &bfe->bfe_machdl)) != 0) {
2912dd52495fSSaurabh Misra 		bfe_error(dip, "mac_register() failed with %d error", ret);
2913dd52495fSSaurabh Misra 		mac_free(macreg);
2914dd52495fSSaurabh Misra 		goto fail2;
2915dd52495fSSaurabh Misra 	}
2916dd52495fSSaurabh Misra 
2917dd52495fSSaurabh Misra 	mac_free(macreg);
2918dd52495fSSaurabh Misra 
2919dd52495fSSaurabh Misra 	rw_init(&bfe->bfe_rwlock, NULL, RW_DRIVER,
2920dd52495fSSaurabh Misra 	    DDI_INTR_PRI(bfe->bfe_intrpri));
2921dd52495fSSaurabh Misra 
2922dd52495fSSaurabh Misra 	if (bfe_add_intr(bfe) != DDI_SUCCESS) {
2923dd52495fSSaurabh Misra 		bfe_error(dip, "Could not add interrupt");
2924dd52495fSSaurabh Misra 		goto fail3;
2925dd52495fSSaurabh Misra 	}
2926dd52495fSSaurabh Misra 
2927dd52495fSSaurabh Misra 	if (bfe_rings_alloc(bfe) != DDI_SUCCESS) {
2928dd52495fSSaurabh Misra 		bfe_error(dip, "Could not allocate TX/RX Ring");
2929dd52495fSSaurabh Misra 		goto fail4;
2930dd52495fSSaurabh Misra 	}
2931dd52495fSSaurabh Misra 
2932dd52495fSSaurabh Misra 	/* Init and then reset the chip */
2933dd52495fSSaurabh Misra 	bfe->bfe_chip_action = 0;
2934dd52495fSSaurabh Misra 	bfe_init_vars(bfe);
2935dd52495fSSaurabh Misra 
2936dd52495fSSaurabh Misra 	/* PHY will also start running */
2937dd52495fSSaurabh Misra 	bfe_chip_reset(bfe);
2938dd52495fSSaurabh Misra 
2939dd52495fSSaurabh Misra 	/*
2940dd52495fSSaurabh Misra 	 * Even though we enable the interrupts here but chip's interrupt
2941dd52495fSSaurabh Misra 	 * is not enabled yet. It will be enabled once we plumb the interface.
2942dd52495fSSaurabh Misra 	 */
2943dd52495fSSaurabh Misra 	if (ddi_intr_enable(bfe->bfe_intrhdl) != DDI_SUCCESS) {
2944dd52495fSSaurabh Misra 		bfe_error(dip, "Could not enable interrupt");
2945dd52495fSSaurabh Misra 		goto fail4;
2946dd52495fSSaurabh Misra 	}
2947dd52495fSSaurabh Misra 
2948dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
2949dd52495fSSaurabh Misra 
2950dd52495fSSaurabh Misra fail4:
2951dd52495fSSaurabh Misra 	bfe_remove_intr(bfe);
2952dd52495fSSaurabh Misra fail3:
2953c1374a13SSurya Prakki 	(void) mac_unregister(bfe->bfe_machdl);
2954dd52495fSSaurabh Misra fail2:
2955dd52495fSSaurabh Misra 	bfe_unmap_regs(bfe);
2956dd52495fSSaurabh Misra fail1:
2957dd52495fSSaurabh Misra 	pci_config_teardown(&bfe->bfe_conf_handle);
2958dd52495fSSaurabh Misra fail0:
2959dd52495fSSaurabh Misra 	kmem_free(bfe, sizeof (bfe_t));
2960dd52495fSSaurabh Misra 	return (DDI_FAILURE);
2961dd52495fSSaurabh Misra }
2962dd52495fSSaurabh Misra 
2963dd52495fSSaurabh Misra static int
bfe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)2964dd52495fSSaurabh Misra bfe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
2965dd52495fSSaurabh Misra {
2966dd52495fSSaurabh Misra 	bfe_t *bfe;
2967dd52495fSSaurabh Misra 
2968dd52495fSSaurabh Misra 	bfe = ddi_get_driver_private(devinfo);
2969dd52495fSSaurabh Misra 
2970dd52495fSSaurabh Misra 	switch (cmd) {
2971dd52495fSSaurabh Misra 	case DDI_DETACH:
2972dd52495fSSaurabh Misra 		/*
2973dd52495fSSaurabh Misra 		 * We need to stop the timer before grabbing locks otherwise
2974dd52495fSSaurabh Misra 		 * we can land-up in deadlock with untimeout.
2975dd52495fSSaurabh Misra 		 */
2976dd52495fSSaurabh Misra 		bfe_stop_timer(bfe);
2977dd52495fSSaurabh Misra 
2978dd52495fSSaurabh Misra 		/*
2979dd52495fSSaurabh Misra 		 * First unregister with MAC layer before stopping DMA
2980dd52495fSSaurabh Misra 		 * engine.
2981dd52495fSSaurabh Misra 		 */
2982dd52495fSSaurabh Misra 		if (mac_unregister(bfe->bfe_machdl) != DDI_SUCCESS)
2983dd52495fSSaurabh Misra 			return (DDI_FAILURE);
2984dd52495fSSaurabh Misra 
2985dd52495fSSaurabh Misra 		bfe->bfe_machdl = NULL;
2986dd52495fSSaurabh Misra 
2987dd52495fSSaurabh Misra 		/*
2988dd52495fSSaurabh Misra 		 * Quiesce the chip first.
2989dd52495fSSaurabh Misra 		 */
2990dd52495fSSaurabh Misra 		bfe_grab_locks(bfe);
2991dd52495fSSaurabh Misra 		bfe_chip_halt(bfe);
2992dd52495fSSaurabh Misra 		bfe_stop_phy(bfe);
2993dd52495fSSaurabh Misra 		bfe_release_locks(bfe);
2994dd52495fSSaurabh Misra 
2995dd52495fSSaurabh Misra 		(void) ddi_intr_disable(bfe->bfe_intrhdl);
2996dd52495fSSaurabh Misra 
2997dd52495fSSaurabh Misra 		/* Make sure timer is gone. */
2998dd52495fSSaurabh Misra 		bfe_stop_timer(bfe);
2999dd52495fSSaurabh Misra 
3000dd52495fSSaurabh Misra 		/*
3001dd52495fSSaurabh Misra 		 * Free the DMA resources for buffer and then descriptors
3002dd52495fSSaurabh Misra 		 */
3003dd52495fSSaurabh Misra 		if (bfe->bfe_tx_ring.r_flags == BFE_RING_ALLOCATED) {
3004dd52495fSSaurabh Misra 			/* TX */
3005dd52495fSSaurabh Misra 			bfe_buffer_free(&bfe->bfe_tx_ring);
3006dd52495fSSaurabh Misra 			bfe_ring_desc_free(&bfe->bfe_tx_ring);
3007dd52495fSSaurabh Misra 		}
3008dd52495fSSaurabh Misra 
3009dd52495fSSaurabh Misra 		if (bfe->bfe_rx_ring.r_flags == BFE_RING_ALLOCATED) {
3010dd52495fSSaurabh Misra 			/* RX */
3011dd52495fSSaurabh Misra 			bfe_buffer_free(&bfe->bfe_rx_ring);
3012dd52495fSSaurabh Misra 			bfe_ring_desc_free(&bfe->bfe_rx_ring);
3013dd52495fSSaurabh Misra 		}
3014dd52495fSSaurabh Misra 
3015dd52495fSSaurabh Misra 		bfe_remove_intr(bfe);
3016dd52495fSSaurabh Misra 		bfe_unmap_regs(bfe);
3017dd52495fSSaurabh Misra 		pci_config_teardown(&bfe->bfe_conf_handle);
3018dd52495fSSaurabh Misra 
3019dd52495fSSaurabh Misra 		mutex_destroy(&bfe->bfe_tx_ring.r_lock);
3020dd52495fSSaurabh Misra 		mutex_destroy(&bfe->bfe_rx_ring.r_lock);
3021dd52495fSSaurabh Misra 		rw_destroy(&bfe->bfe_rwlock);
3022dd52495fSSaurabh Misra 
3023dd52495fSSaurabh Misra 		kmem_free(bfe, sizeof (bfe_t));
3024dd52495fSSaurabh Misra 
3025dd52495fSSaurabh Misra 		ddi_set_driver_private(devinfo, NULL);
3026dd52495fSSaurabh Misra 		return (DDI_SUCCESS);
3027dd52495fSSaurabh Misra 
3028dd52495fSSaurabh Misra 	case DDI_SUSPEND:
3029dd52495fSSaurabh Misra 		/*
3030dd52495fSSaurabh Misra 		 * We need to stop the timer before grabbing locks otherwise
3031dd52495fSSaurabh Misra 		 * we can land-up in deadlock with untimeout.
3032dd52495fSSaurabh Misra 		 */
3033dd52495fSSaurabh Misra 		bfe_stop_timer(bfe);
3034dd52495fSSaurabh Misra 
3035dd52495fSSaurabh Misra 		/*
3036dd52495fSSaurabh Misra 		 * Grab all the locks first.
3037dd52495fSSaurabh Misra 		 */
3038dd52495fSSaurabh Misra 		bfe_grab_locks(bfe);
3039dd52495fSSaurabh Misra 		bfe_chip_halt(bfe);
3040dd52495fSSaurabh Misra 		bfe_stop_phy(bfe);
3041dd52495fSSaurabh Misra 		bfe->bfe_chip_state = BFE_CHIP_SUSPENDED;
3042dd52495fSSaurabh Misra 		bfe_release_locks(bfe);
3043dd52495fSSaurabh Misra 
3044dd52495fSSaurabh Misra 		return (DDI_SUCCESS);
3045dd52495fSSaurabh Misra 
3046dd52495fSSaurabh Misra 	default:
3047dd52495fSSaurabh Misra 		return (DDI_FAILURE);
3048dd52495fSSaurabh Misra 	}
3049dd52495fSSaurabh Misra }
3050dd52495fSSaurabh Misra 
3051dd52495fSSaurabh Misra /*
3052dd52495fSSaurabh Misra  * Quiesce the card for fast reboot
3053dd52495fSSaurabh Misra  */
3054dd52495fSSaurabh Misra int
bfe_quiesce(dev_info_t * dev_info)3055dd52495fSSaurabh Misra bfe_quiesce(dev_info_t *dev_info)
3056dd52495fSSaurabh Misra {
3057dd52495fSSaurabh Misra 	bfe_t *bfe;
3058dd52495fSSaurabh Misra 
3059dd52495fSSaurabh Misra 	bfe = ddi_get_driver_private(dev_info);
3060dd52495fSSaurabh Misra 
3061dd52495fSSaurabh Misra 	bfe_chip_halt(bfe);
3062dd52495fSSaurabh Misra 	bfe_stop_phy(bfe);
3063dd52495fSSaurabh Misra 	bfe->bfe_chip_state = BFE_CHIP_QUIESCED;
3064dd52495fSSaurabh Misra 
3065dd52495fSSaurabh Misra 	return (DDI_SUCCESS);
3066dd52495fSSaurabh Misra }
3067dd52495fSSaurabh Misra 
3068dd52495fSSaurabh Misra static struct cb_ops bfe_cb_ops = {
3069dd52495fSSaurabh Misra 	nulldev,		/* cb_open */
3070dd52495fSSaurabh Misra 	nulldev,		/* cb_close */
3071dd52495fSSaurabh Misra 	nodev,			/* cb_strategy */
3072dd52495fSSaurabh Misra 	nodev,			/* cb_print */
3073dd52495fSSaurabh Misra 	nodev,			/* cb_dump */
3074dd52495fSSaurabh Misra 	nodev,			/* cb_read */
3075dd52495fSSaurabh Misra 	nodev,			/* cb_write */
3076dd52495fSSaurabh Misra 	nodev,			/* cb_ioctl */
3077dd52495fSSaurabh Misra 	nodev,			/* cb_devmap */
3078dd52495fSSaurabh Misra 	nodev,			/* cb_mmap */
3079dd52495fSSaurabh Misra 	nodev,			/* cb_segmap */
3080dd52495fSSaurabh Misra 	nochpoll,		/* cb_chpoll */
3081dd52495fSSaurabh Misra 	ddi_prop_op,		/* cb_prop_op */
3082dd52495fSSaurabh Misra 	NULL,			/* cb_stream */
3083dd52495fSSaurabh Misra 	D_MP | D_HOTPLUG,	/* cb_flag */
3084dd52495fSSaurabh Misra 	CB_REV,			/* cb_rev */
3085dd52495fSSaurabh Misra 	nodev,			/* cb_aread */
3086dd52495fSSaurabh Misra 	nodev			/* cb_awrite */
3087dd52495fSSaurabh Misra };
3088dd52495fSSaurabh Misra 
3089dd52495fSSaurabh Misra static struct dev_ops bfe_dev_ops = {
3090dd52495fSSaurabh Misra 	DEVO_REV,	/* devo_rev */
3091dd52495fSSaurabh Misra 	0,		/* devo_refcnt */
3092dd52495fSSaurabh Misra 	NULL,		/* devo_getinfo */
3093dd52495fSSaurabh Misra 	nulldev,	/* devo_identify */
3094dd52495fSSaurabh Misra 	nulldev,	/* devo_probe */
3095dd52495fSSaurabh Misra 	bfe_attach,	/* devo_attach */
3096dd52495fSSaurabh Misra 	bfe_detach,	/* devo_detach */
3097dd52495fSSaurabh Misra 	nodev,		/* devo_reset */
3098dd52495fSSaurabh Misra 	&bfe_cb_ops,	/* devo_cb_ops */
3099dd52495fSSaurabh Misra 	NULL,		/* devo_bus_ops */
3100dd52495fSSaurabh Misra 	ddi_power,	/* devo_power */
3101dd52495fSSaurabh Misra 	bfe_quiesce	/* devo_quiesce */
3102dd52495fSSaurabh Misra };
3103dd52495fSSaurabh Misra 
3104dd52495fSSaurabh Misra static struct modldrv bfe_modldrv = {
3105dd52495fSSaurabh Misra 	&mod_driverops,
3106dd52495fSSaurabh Misra 	bfe_ident,
3107dd52495fSSaurabh Misra 	&bfe_dev_ops
3108dd52495fSSaurabh Misra };
3109dd52495fSSaurabh Misra 
3110dd52495fSSaurabh Misra static struct modlinkage modlinkage = {
3111dd52495fSSaurabh Misra 	MODREV_1, (void *)&bfe_modldrv, NULL
3112dd52495fSSaurabh Misra };
3113dd52495fSSaurabh Misra 
3114dd52495fSSaurabh Misra int
_info(struct modinfo * modinfop)3115dd52495fSSaurabh Misra _info(struct modinfo *modinfop)
3116dd52495fSSaurabh Misra {
3117dd52495fSSaurabh Misra 	return (mod_info(&modlinkage, modinfop));
3118dd52495fSSaurabh Misra }
3119dd52495fSSaurabh Misra 
3120dd52495fSSaurabh Misra int
_init(void)3121dd52495fSSaurabh Misra _init(void)
3122dd52495fSSaurabh Misra {
3123dd52495fSSaurabh Misra 	int	status;
3124dd52495fSSaurabh Misra 
3125dd52495fSSaurabh Misra 	mac_init_ops(&bfe_dev_ops, MODULE_NAME);
3126dd52495fSSaurabh Misra 	status = mod_install(&modlinkage);
3127dd52495fSSaurabh Misra 	if (status == DDI_FAILURE)
3128dd52495fSSaurabh Misra 		mac_fini_ops(&bfe_dev_ops);
3129dd52495fSSaurabh Misra 	return (status);
3130dd52495fSSaurabh Misra }
3131dd52495fSSaurabh Misra 
3132dd52495fSSaurabh Misra int
_fini(void)3133dd52495fSSaurabh Misra _fini(void)
3134dd52495fSSaurabh Misra {
3135dd52495fSSaurabh Misra 	int status;
3136dd52495fSSaurabh Misra 
3137dd52495fSSaurabh Misra 	status = mod_remove(&modlinkage);
3138dd52495fSSaurabh Misra 	if (status == 0) {
3139dd52495fSSaurabh Misra 		mac_fini_ops(&bfe_dev_ops);
3140dd52495fSSaurabh Misra 	}
3141dd52495fSSaurabh Misra 	return (status);
3142dd52495fSSaurabh Misra }
3143