xref: /illumos-gate/usr/src/uts/common/io/dmfe/dmfe_main.c (revision 0dc2366f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5605445d5Sdg  * Common Development and Distribution License (the "License").
6605445d5Sdg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
27dd4eeefdSeota #include <sys/types.h>
28dd4eeefdSeota #include <sys/sunddi.h>
29bdb9230aSGarrett D'Amore #include <sys/policy.h>
30bdb9230aSGarrett D'Amore #include <sys/sdt.h>
315c1d0199Sgd #include "dmfe_impl.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * This is the string displayed by modinfo, etc.
357c478bd9Sstevel@tonic-gate  */
36cc291a4cSgd static char dmfe_ident[] = "Davicom DM9102 Ethernet";
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * NOTES:
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * #defines:
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  *	DMFE_PCI_RNUMBER is the register-set number to use for the operating
457c478bd9Sstevel@tonic-gate  *	registers.  On an OBP-based machine, regset 0 refers to CONFIG space,
467c478bd9Sstevel@tonic-gate  *	regset 1 will be the operating registers in I/O space, and regset 2
477c478bd9Sstevel@tonic-gate  *	will be the operating registers in MEMORY space (preferred).  If an
487c478bd9Sstevel@tonic-gate  *	expansion ROM is fitted, it may appear as a further register set.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  *	DMFE_SLOP defines the amount by which the chip may read beyond
517c478bd9Sstevel@tonic-gate  *	the end of a buffer or descriptor, apparently 6-8 dwords :(
527c478bd9Sstevel@tonic-gate  *	We have to make sure this doesn't cause it to access unallocated
537c478bd9Sstevel@tonic-gate  *	or unmapped memory.
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  *	DMFE_BUF_SIZE must be at least (ETHERMAX + ETHERFCSL + DMFE_SLOP)
567c478bd9Sstevel@tonic-gate  *	rounded up to a multiple of 4.  Here we choose a power of two for
577c478bd9Sstevel@tonic-gate  *	speed & simplicity at the cost of a bit more memory.
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  *	However, the buffer length field in the TX/RX descriptors is only
607c478bd9Sstevel@tonic-gate  *	eleven bits, so even though we allocate DMFE_BUF_SIZE (2048) bytes
617c478bd9Sstevel@tonic-gate  *	per buffer, we tell the chip that they're only DMFE_BUF_SIZE_1
627c478bd9Sstevel@tonic-gate  *	(2000) bytes each.
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  *	DMFE_DMA_MODE defines the mode (STREAMING/CONSISTENT) used for
657c478bd9Sstevel@tonic-gate  *	the data buffers.  The descriptors are always set up in CONSISTENT
667c478bd9Sstevel@tonic-gate  *	mode.
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  *	DMFE_HEADROOM defines how much space we'll leave in allocated
697c478bd9Sstevel@tonic-gate  *	mblks before the first valid data byte.  This should be chosen
707c478bd9Sstevel@tonic-gate  *	to be 2 modulo 4, so that once the ethernet header (14 bytes)
717c478bd9Sstevel@tonic-gate  *	has been stripped off, the packet data will be 4-byte aligned.
727c478bd9Sstevel@tonic-gate  *	The remaining space can be used by upstream modules to prepend
737c478bd9Sstevel@tonic-gate  *	any headers required.
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * Patchable globals:
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  *	dmfe_bus_modes: the bus mode bits to be put into CSR0.
787c478bd9Sstevel@tonic-gate  *		Setting READ_MULTIPLE in this register seems to cause
797c478bd9Sstevel@tonic-gate  *		the chip to generate a READ LINE command with a parity
807c478bd9Sstevel@tonic-gate  *		error!  Don't do it!
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  *	dmfe_setup_desc1: the value to be put into descriptor word 1
837c478bd9Sstevel@tonic-gate  *		when sending a SETUP packet.
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  *		Setting TX_LAST_DESC in desc1 in a setup packet seems
867c478bd9Sstevel@tonic-gate  *		to make the chip spontaneously reset internally - it
877c478bd9Sstevel@tonic-gate  *		attempts to give back the setup packet descriptor by
887c478bd9Sstevel@tonic-gate  *		writing to PCI address 00000000 - which may or may not
897c478bd9Sstevel@tonic-gate  *		get a MASTER ABORT - after which most of its registers
907c478bd9Sstevel@tonic-gate  *		seem to have either default values or garbage!
917c478bd9Sstevel@tonic-gate  *
927c478bd9Sstevel@tonic-gate  *		TX_FIRST_DESC doesn't seem to have the same effect but
937c478bd9Sstevel@tonic-gate  *		it isn't needed on a setup packet so we'll leave it out
947c478bd9Sstevel@tonic-gate  *		too, just in case it has some other wierd side-effect.
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  *		The default hardware packet filtering mode is now
977c478bd9Sstevel@tonic-gate  *		HASH_AND_PERFECT (imperfect filtering of multicast
987c478bd9Sstevel@tonic-gate  *		packets and perfect filtering of unicast packets).
997c478bd9Sstevel@tonic-gate  *		If this is found not to work reliably, setting the
1007c478bd9Sstevel@tonic-gate  *		TX_FILTER_TYPE1 bit will cause a switchover to using
1017c478bd9Sstevel@tonic-gate  *		HASH_ONLY mode (imperfect filtering of *all* packets).
1027c478bd9Sstevel@tonic-gate  *		Software will then perform the additional filtering
1037c478bd9Sstevel@tonic-gate  *		as required.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate #define	DMFE_PCI_RNUMBER	2
1077c478bd9Sstevel@tonic-gate #define	DMFE_SLOP		(8*sizeof (uint32_t))
1087c478bd9Sstevel@tonic-gate #define	DMFE_BUF_SIZE		2048
1097c478bd9Sstevel@tonic-gate #define	DMFE_BUF_SIZE_1		2000
1107c478bd9Sstevel@tonic-gate #define	DMFE_DMA_MODE		DDI_DMA_STREAMING
1117c478bd9Sstevel@tonic-gate #define	DMFE_HEADROOM		34
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static uint32_t dmfe_bus_modes = TX_POLL_INTVL | CACHE_ALIGN;
1147c478bd9Sstevel@tonic-gate static uint32_t dmfe_setup_desc1 = TX_SETUP_PACKET | SETUPBUF_SIZE |
1157c478bd9Sstevel@tonic-gate 					TX_FILTER_TYPE0;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * Some tunable parameters ...
1195c1d0199Sgd  *	Number of RX/TX ring entries (128/128)
1207c478bd9Sstevel@tonic-gate  *	Minimum number of TX ring slots to keep free (1)
1217c478bd9Sstevel@tonic-gate  *	Low-water mark at which to try to reclaim TX ring slots (1)
1227c478bd9Sstevel@tonic-gate  *	How often to take a TX-done interrupt (twice per ring cycle)
1237c478bd9Sstevel@tonic-gate  *	Whether to reclaim TX ring entries on a TX-done interrupt (no)
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate 
1265c1d0199Sgd #define	DMFE_TX_DESC		128	/* Should be a multiple of 4 <= 256 */
1275c1d0199Sgd #define	DMFE_RX_DESC		128	/* Should be a multiple of 4 <= 256 */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static uint32_t dmfe_rx_desc = DMFE_RX_DESC;
1307c478bd9Sstevel@tonic-gate static uint32_t dmfe_tx_desc = DMFE_TX_DESC;
1317c478bd9Sstevel@tonic-gate static uint32_t dmfe_tx_min_free = 1;
1327c478bd9Sstevel@tonic-gate static uint32_t dmfe_tx_reclaim_level = 1;
1337c478bd9Sstevel@tonic-gate static uint32_t dmfe_tx_int_factor = (DMFE_TX_DESC / 2) - 1;
1347c478bd9Sstevel@tonic-gate static boolean_t dmfe_reclaim_on_done = B_FALSE;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * Time-related parameters:
1387c478bd9Sstevel@tonic-gate  *
1397c478bd9Sstevel@tonic-gate  *	We use a cyclic to provide a periodic callback; this is then used
1407c478bd9Sstevel@tonic-gate  * 	to check for TX-stall and poll the link status register.
1417c478bd9Sstevel@tonic-gate  *
1427c478bd9Sstevel@tonic-gate  *	DMFE_TICK is the interval between cyclic callbacks, in microseconds.
1437c478bd9Sstevel@tonic-gate  *
1447c478bd9Sstevel@tonic-gate  *	TX_STALL_TIME_100 is the timeout in microseconds between passing
1457c478bd9Sstevel@tonic-gate  *	a packet to the chip for transmission and seeing that it's gone,
1467c478bd9Sstevel@tonic-gate  *	when running at 100Mb/s.  If we haven't reclaimed at least one
1477c478bd9Sstevel@tonic-gate  *	descriptor in this time we assume the transmitter has stalled
1487c478bd9Sstevel@tonic-gate  *	and reset the chip.
1497c478bd9Sstevel@tonic-gate  *
1507c478bd9Sstevel@tonic-gate  *	TX_STALL_TIME_10 is the equivalent timeout when running at 10Mb/s.
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  * Patchable globals:
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  *	dmfe_tick_us:		DMFE_TICK
1557c478bd9Sstevel@tonic-gate  *	dmfe_tx100_stall_us:	TX_STALL_TIME_100
1567c478bd9Sstevel@tonic-gate  *	dmfe_tx10_stall_us:	TX_STALL_TIME_10
1577c478bd9Sstevel@tonic-gate  *
1587c478bd9Sstevel@tonic-gate  * These are then used in _init() to calculate:
1597c478bd9Sstevel@tonic-gate  *
1607c478bd9Sstevel@tonic-gate  *	stall_100_tix[]: number of consecutive cyclic callbacks without a
1617c478bd9Sstevel@tonic-gate  *			 reclaim before the TX process is considered stalled,
1627c478bd9Sstevel@tonic-gate  *			 when running at 100Mb/s.  The elements are indexed
1637c478bd9Sstevel@tonic-gate  *			 by transmit-engine-state.
1647c478bd9Sstevel@tonic-gate  *	stall_10_tix[]:	 number of consecutive cyclic callbacks without a
1657c478bd9Sstevel@tonic-gate  *			 reclaim before the TX process is considered stalled,
1667c478bd9Sstevel@tonic-gate  *			 when running at 10Mb/s.  The elements are indexed
1677c478bd9Sstevel@tonic-gate  *			 by transmit-engine-state.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate #define	DMFE_TICK		25000		/* microseconds		*/
1717c478bd9Sstevel@tonic-gate #define	TX_STALL_TIME_100	50000		/* microseconds		*/
1727c478bd9Sstevel@tonic-gate #define	TX_STALL_TIME_10	200000		/* microseconds		*/
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate static uint32_t dmfe_tick_us = DMFE_TICK;
1757c478bd9Sstevel@tonic-gate static uint32_t dmfe_tx100_stall_us = TX_STALL_TIME_100;
1767c478bd9Sstevel@tonic-gate static uint32_t dmfe_tx10_stall_us = TX_STALL_TIME_10;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate  * Calculated from above in _init()
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate static uint32_t stall_100_tix[TX_PROCESS_MAX_STATE+1];
1837c478bd9Sstevel@tonic-gate static uint32_t stall_10_tix[TX_PROCESS_MAX_STATE+1];
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * Property names
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate static char localmac_propname[] = "local-mac-address";
1897c478bd9Sstevel@tonic-gate static char opmode_propname[] = "opmode-reg-value";
1907c478bd9Sstevel@tonic-gate 
191cc291a4cSgd static int		dmfe_m_start(void *);
192cc291a4cSgd static void		dmfe_m_stop(void *);
193cc291a4cSgd static int		dmfe_m_promisc(void *, boolean_t);
194cc291a4cSgd static int		dmfe_m_multicst(void *, boolean_t, const uint8_t *);
195cc291a4cSgd static int		dmfe_m_unicst(void *, const uint8_t *);
196cc291a4cSgd static void		dmfe_m_ioctl(void *, queue_t *, mblk_t *);
197cc291a4cSgd static mblk_t		*dmfe_m_tx(void *, mblk_t *);
198cc291a4cSgd static int 		dmfe_m_stat(void *, uint_t, uint64_t *);
199bdb9230aSGarrett D'Amore static int		dmfe_m_getprop(void *, const char *, mac_prop_id_t,
200*0dc2366fSVenugopal Iyer     uint_t, void *);
201bdb9230aSGarrett D'Amore static int		dmfe_m_setprop(void *, const char *, mac_prop_id_t,
202bdb9230aSGarrett D'Amore     uint_t,  const void *);
203*0dc2366fSVenugopal Iyer static void		dmfe_m_propinfo(void *, const char *, mac_prop_id_t,
204*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
205cc291a4cSgd 
206cc291a4cSgd static mac_callbacks_t dmfe_m_callbacks = {
207*0dc2366fSVenugopal Iyer 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
208cc291a4cSgd 	dmfe_m_stat,
209cc291a4cSgd 	dmfe_m_start,
210cc291a4cSgd 	dmfe_m_stop,
211cc291a4cSgd 	dmfe_m_promisc,
212cc291a4cSgd 	dmfe_m_multicst,
213cc291a4cSgd 	dmfe_m_unicst,
214cc291a4cSgd 	dmfe_m_tx,
215*0dc2366fSVenugopal Iyer 	NULL,
216cc291a4cSgd 	dmfe_m_ioctl,
217bdb9230aSGarrett D'Amore 	NULL,	/* getcapab */
218bdb9230aSGarrett D'Amore 	NULL,	/* open */
219bdb9230aSGarrett D'Amore 	NULL,	/* close */
220bdb9230aSGarrett D'Amore 	dmfe_m_setprop,
221*0dc2366fSVenugopal Iyer 	dmfe_m_getprop,
222*0dc2366fSVenugopal Iyer 	dmfe_m_propinfo
223cc291a4cSgd };
224cc291a4cSgd 
225cc291a4cSgd 
2267c478bd9Sstevel@tonic-gate /*
2277c478bd9Sstevel@tonic-gate  * Describes the chip's DMA engine
2287c478bd9Sstevel@tonic-gate  */
2297c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_attr = {
2307c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* dma_attr version */
2317c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_addr_lo */
2327c478bd9Sstevel@tonic-gate 	(uint32_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
2337c478bd9Sstevel@tonic-gate 	0x0FFFFFF,		/* dma_attr_count_max */
2347c478bd9Sstevel@tonic-gate 	0x20,			/* dma_attr_align */
2357c478bd9Sstevel@tonic-gate 	0x7F,			/* dma_attr_burstsizes */
2367c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_minxfer */
2377c478bd9Sstevel@tonic-gate 	(uint32_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
2387c478bd9Sstevel@tonic-gate 	(uint32_t)0xFFFFFFFF,	/* dma_attr_seg */
2397c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_sgllen */
2407c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_granular */
2417c478bd9Sstevel@tonic-gate 	0			/* dma_attr_flags */
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /*
2457c478bd9Sstevel@tonic-gate  * DMA access attributes for registers and descriptors
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t dmfe_reg_accattr = {
2487c478bd9Sstevel@tonic-gate 	DDI_DEVICE_ATTR_V0,
2497c478bd9Sstevel@tonic-gate 	DDI_STRUCTURE_LE_ACC,
2507c478bd9Sstevel@tonic-gate 	DDI_STRICTORDER_ACC
2517c478bd9Sstevel@tonic-gate };
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * DMA access attributes for data: NOT to be byte swapped.
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t dmfe_data_accattr = {
2577c478bd9Sstevel@tonic-gate 	DDI_DEVICE_ATTR_V0,
2587c478bd9Sstevel@tonic-gate 	DDI_NEVERSWAP_ACC,
2597c478bd9Sstevel@tonic-gate 	DDI_STRICTORDER_ACC
2607c478bd9Sstevel@tonic-gate };
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate static uchar_t dmfe_broadcast_addr[ETHERADDRL] = {
2637c478bd9Sstevel@tonic-gate 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2647c478bd9Sstevel@tonic-gate };
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate  * ========== Lowest-level chip register & ring access routines ==========
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * I/O register get/put routines
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate uint32_t
dmfe_chip_get32(dmfe_t * dmfep,off_t offset)2757c478bd9Sstevel@tonic-gate dmfe_chip_get32(dmfe_t *dmfep, off_t offset)
2767c478bd9Sstevel@tonic-gate {
27722eb7cb5Sgd 	uint32_t *addr;
2787c478bd9Sstevel@tonic-gate 
27922eb7cb5Sgd 	addr = (void *)(dmfep->io_reg + offset);
28022eb7cb5Sgd 	return (ddi_get32(dmfep->io_handle, addr));
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate void
dmfe_chip_put32(dmfe_t * dmfep,off_t offset,uint32_t value)2847c478bd9Sstevel@tonic-gate dmfe_chip_put32(dmfe_t *dmfep, off_t offset, uint32_t value)
2857c478bd9Sstevel@tonic-gate {
28622eb7cb5Sgd 	uint32_t *addr;
2877c478bd9Sstevel@tonic-gate 
28822eb7cb5Sgd 	addr = (void *)(dmfep->io_reg + offset);
28922eb7cb5Sgd 	ddi_put32(dmfep->io_handle, addr, value);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * TX/RX ring get/put routines
2947c478bd9Sstevel@tonic-gate  */
2957c478bd9Sstevel@tonic-gate static uint32_t
dmfe_ring_get32(dma_area_t * dma_p,uint_t index,uint_t offset)2967c478bd9Sstevel@tonic-gate dmfe_ring_get32(dma_area_t *dma_p, uint_t index, uint_t offset)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	uint32_t *addr;
2997c478bd9Sstevel@tonic-gate 
30022eb7cb5Sgd 	addr = (void *)dma_p->mem_va;
3017c478bd9Sstevel@tonic-gate 	return (ddi_get32(dma_p->acc_hdl, addr + index*DESC_SIZE + offset));
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate static void
dmfe_ring_put32(dma_area_t * dma_p,uint_t index,uint_t offset,uint32_t value)3057c478bd9Sstevel@tonic-gate dmfe_ring_put32(dma_area_t *dma_p, uint_t index, uint_t offset, uint32_t value)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	uint32_t *addr;
3087c478bd9Sstevel@tonic-gate 
30922eb7cb5Sgd 	addr = (void *)dma_p->mem_va;
3107c478bd9Sstevel@tonic-gate 	ddi_put32(dma_p->acc_hdl, addr + index*DESC_SIZE + offset, value);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate  * Setup buffer get/put routines
3157c478bd9Sstevel@tonic-gate  */
3167c478bd9Sstevel@tonic-gate static uint32_t
dmfe_setup_get32(dma_area_t * dma_p,uint_t index)3177c478bd9Sstevel@tonic-gate dmfe_setup_get32(dma_area_t *dma_p, uint_t index)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	uint32_t *addr;
3207c478bd9Sstevel@tonic-gate 
32122eb7cb5Sgd 	addr = (void *)dma_p->setup_va;
3227c478bd9Sstevel@tonic-gate 	return (ddi_get32(dma_p->acc_hdl, addr + index));
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate static void
dmfe_setup_put32(dma_area_t * dma_p,uint_t index,uint32_t value)3267c478bd9Sstevel@tonic-gate dmfe_setup_put32(dma_area_t *dma_p, uint_t index, uint32_t value)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	uint32_t *addr;
3297c478bd9Sstevel@tonic-gate 
33022eb7cb5Sgd 	addr = (void *)dma_p->setup_va;
3317c478bd9Sstevel@tonic-gate 	ddi_put32(dma_p->acc_hdl, addr + index, value);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * ========== Low-level chip & ring buffer manipulation ==========
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * dmfe_set_opmode() -- function to set operating mode
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static void
dmfe_set_opmode(dmfe_t * dmfep)3437c478bd9Sstevel@tonic-gate dmfe_set_opmode(dmfe_t *dmfep)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, OPN_MODE_REG, dmfep->opmode);
3487c478bd9Sstevel@tonic-gate 	drv_usecwait(10);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate /*
3527c478bd9Sstevel@tonic-gate  * dmfe_stop_chip() -- stop all chip processing & optionally reset the h/w
3537c478bd9Sstevel@tonic-gate  */
3547c478bd9Sstevel@tonic-gate static void
dmfe_stop_chip(dmfe_t * dmfep,enum chip_state newstate)3557c478bd9Sstevel@tonic-gate dmfe_stop_chip(dmfe_t *dmfep, enum chip_state newstate)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/*
3607c478bd9Sstevel@tonic-gate 	 * Stop the chip:
3617c478bd9Sstevel@tonic-gate 	 *	disable all interrupts
3627c478bd9Sstevel@tonic-gate 	 *	stop TX/RX processes
3637c478bd9Sstevel@tonic-gate 	 *	clear the status bits for TX/RX stopped
3647c478bd9Sstevel@tonic-gate 	 * If required, reset the chip
3657c478bd9Sstevel@tonic-gate 	 * Record the new state
3667c478bd9Sstevel@tonic-gate 	 */
3677c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, INT_MASK_REG, 0);
3687c478bd9Sstevel@tonic-gate 	dmfep->opmode &= ~(START_TRANSMIT | START_RECEIVE);
3697c478bd9Sstevel@tonic-gate 	dmfe_set_opmode(dmfep);
3707c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, STATUS_REG, TX_STOPPED_INT | RX_STOPPED_INT);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	switch (newstate) {
3737c478bd9Sstevel@tonic-gate 	default:
3747c478bd9Sstevel@tonic-gate 		ASSERT(!"can't get here");
3757c478bd9Sstevel@tonic-gate 		return;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	case CHIP_STOPPED:
3787c478bd9Sstevel@tonic-gate 	case CHIP_ERROR:
3797c478bd9Sstevel@tonic-gate 		break;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	case CHIP_RESET:
3827c478bd9Sstevel@tonic-gate 		dmfe_chip_put32(dmfep, BUS_MODE_REG, SW_RESET);
3837c478bd9Sstevel@tonic-gate 		drv_usecwait(10);
3847c478bd9Sstevel@tonic-gate 		dmfe_chip_put32(dmfep, BUS_MODE_REG, 0);
3857c478bd9Sstevel@tonic-gate 		drv_usecwait(10);
3867c478bd9Sstevel@tonic-gate 		dmfe_chip_put32(dmfep, BUS_MODE_REG, dmfe_bus_modes);
3877c478bd9Sstevel@tonic-gate 		break;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	dmfep->chip_state = newstate;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate  * Initialize transmit and receive descriptor rings, and
3957c478bd9Sstevel@tonic-gate  * set the chip to point to the first entry in each ring
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate static void
dmfe_init_rings(dmfe_t * dmfep)3987c478bd9Sstevel@tonic-gate dmfe_init_rings(dmfe_t *dmfep)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	dma_area_t *descp;
4017c478bd9Sstevel@tonic-gate 	uint32_t pstart;
4027c478bd9Sstevel@tonic-gate 	uint32_t pnext;
4037c478bd9Sstevel@tonic-gate 	uint32_t pbuff;
4047c478bd9Sstevel@tonic-gate 	uint32_t desc1;
4057c478bd9Sstevel@tonic-gate 	int i;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	/*
4087c478bd9Sstevel@tonic-gate 	 * You need all the locks in order to rewrite the descriptor rings
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
4117c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->rxlock));
4127c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->txlock));
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/*
4157c478bd9Sstevel@tonic-gate 	 * Program the RX ring entries
4167c478bd9Sstevel@tonic-gate 	 */
4177c478bd9Sstevel@tonic-gate 	descp = &dmfep->rx_desc;
4187c478bd9Sstevel@tonic-gate 	pstart = descp->mem_dvma;
4197c478bd9Sstevel@tonic-gate 	pnext = pstart + sizeof (struct rx_desc_type);
4207c478bd9Sstevel@tonic-gate 	pbuff = dmfep->rx_buff.mem_dvma;
4217c478bd9Sstevel@tonic-gate 	desc1 = RX_CHAINING | DMFE_BUF_SIZE_1;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	for (i = 0; i < dmfep->rx.n_desc; ++i) {
4247c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, RD_NEXT, pnext);
4257c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, BUFFER1, pbuff);
4267c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, DESC1, desc1);
4277c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, DESC0, RX_OWN);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 		pnext += sizeof (struct rx_desc_type);
4307c478bd9Sstevel@tonic-gate 		pbuff += DMFE_BUF_SIZE;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/*
4347c478bd9Sstevel@tonic-gate 	 * Fix up last entry & sync
4357c478bd9Sstevel@tonic-gate 	 */
4367c478bd9Sstevel@tonic-gate 	dmfe_ring_put32(descp, --i, RD_NEXT, pstart);
4377c478bd9Sstevel@tonic-gate 	DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV);
4387c478bd9Sstevel@tonic-gate 	dmfep->rx.next_free = 0;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/*
4417c478bd9Sstevel@tonic-gate 	 * Set the base address of the RX descriptor list in CSR3
4427c478bd9Sstevel@tonic-gate 	 */
4437c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, RX_BASE_ADDR_REG, descp->mem_dvma);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/*
4467c478bd9Sstevel@tonic-gate 	 * Program the TX ring entries
4477c478bd9Sstevel@tonic-gate 	 */
4487c478bd9Sstevel@tonic-gate 	descp = &dmfep->tx_desc;
4497c478bd9Sstevel@tonic-gate 	pstart = descp->mem_dvma;
4507c478bd9Sstevel@tonic-gate 	pnext = pstart + sizeof (struct tx_desc_type);
4517c478bd9Sstevel@tonic-gate 	pbuff = dmfep->tx_buff.mem_dvma;
4527c478bd9Sstevel@tonic-gate 	desc1 = TX_CHAINING;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	for (i = 0; i < dmfep->tx.n_desc; ++i) {
4557c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, TD_NEXT, pnext);
4567c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, BUFFER1, pbuff);
4577c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, DESC1, desc1);
4587c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, i, DESC0, 0);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		pnext += sizeof (struct tx_desc_type);
4617c478bd9Sstevel@tonic-gate 		pbuff += DMFE_BUF_SIZE;
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/*
4657c478bd9Sstevel@tonic-gate 	 * Fix up last entry & sync
4667c478bd9Sstevel@tonic-gate 	 */
4677c478bd9Sstevel@tonic-gate 	dmfe_ring_put32(descp, --i, TD_NEXT, pstart);
4687c478bd9Sstevel@tonic-gate 	DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV);
4697c478bd9Sstevel@tonic-gate 	dmfep->tx.n_free = dmfep->tx.n_desc;
4707c478bd9Sstevel@tonic-gate 	dmfep->tx.next_free = dmfep->tx.next_busy = 0;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * Set the base address of the TX descrptor list in CSR4
4747c478bd9Sstevel@tonic-gate 	 */
4757c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, TX_BASE_ADDR_REG, descp->mem_dvma);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * dmfe_start_chip() -- start the chip transmitting and/or receiving
4807c478bd9Sstevel@tonic-gate  */
4817c478bd9Sstevel@tonic-gate static void
dmfe_start_chip(dmfe_t * dmfep,int mode)4827c478bd9Sstevel@tonic-gate dmfe_start_chip(dmfe_t *dmfep, int mode)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	dmfep->opmode |= mode;
4877c478bd9Sstevel@tonic-gate 	dmfe_set_opmode(dmfep);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, W_J_TIMER_REG, 0);
4907c478bd9Sstevel@tonic-gate 	/*
4917c478bd9Sstevel@tonic-gate 	 * Enable VLAN length mode (allows packets to be 4 bytes Longer).
4927c478bd9Sstevel@tonic-gate 	 */
493cc291a4cSgd 	dmfe_chip_put32(dmfep, W_J_TIMER_REG, VLAN_ENABLE);
494cc291a4cSgd 
4957c478bd9Sstevel@tonic-gate 	/*
4967c478bd9Sstevel@tonic-gate 	 * Clear any pending process-stopped interrupts
4977c478bd9Sstevel@tonic-gate 	 */
4987c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, STATUS_REG, TX_STOPPED_INT | RX_STOPPED_INT);
4997c478bd9Sstevel@tonic-gate 	dmfep->chip_state = mode & START_RECEIVE ? CHIP_TX_RX :
500dd4eeefdSeota 	    mode & START_TRANSMIT ? CHIP_TX_ONLY : CHIP_STOPPED;
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate  * dmfe_enable_interrupts() -- enable our favourite set of interrupts.
5057c478bd9Sstevel@tonic-gate  *
5067c478bd9Sstevel@tonic-gate  * Normal interrupts:
5077c478bd9Sstevel@tonic-gate  *	We always enable:
5087c478bd9Sstevel@tonic-gate  *		RX_PKTDONE_INT		(packet received)
5097c478bd9Sstevel@tonic-gate  *		TX_PKTDONE_INT		(TX complete)
5107c478bd9Sstevel@tonic-gate  *	We never enable:
5117c478bd9Sstevel@tonic-gate  *		TX_ALLDONE_INT		(next TX buffer not ready)
5127c478bd9Sstevel@tonic-gate  *
5137c478bd9Sstevel@tonic-gate  * Abnormal interrupts:
5147c478bd9Sstevel@tonic-gate  *	We always enable:
5157c478bd9Sstevel@tonic-gate  *		RX_STOPPED_INT
5167c478bd9Sstevel@tonic-gate  *		TX_STOPPED_INT
5177c478bd9Sstevel@tonic-gate  *		SYSTEM_ERR_INT
5187c478bd9Sstevel@tonic-gate  *		RX_UNAVAIL_INT
5197c478bd9Sstevel@tonic-gate  *	We never enable:
5207c478bd9Sstevel@tonic-gate  *		RX_EARLY_INT
5217c478bd9Sstevel@tonic-gate  *		RX_WATCHDOG_INT
5227c478bd9Sstevel@tonic-gate  *		TX_JABBER_INT
5237c478bd9Sstevel@tonic-gate  *		TX_EARLY_INT
5247c478bd9Sstevel@tonic-gate  *		TX_UNDERFLOW_INT
5257c478bd9Sstevel@tonic-gate  *		GP_TIMER_INT		(not valid in -9 chips)
5267c478bd9Sstevel@tonic-gate  *		LINK_STATUS_INT		(not valid in -9 chips)
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate static void
dmfe_enable_interrupts(dmfe_t * dmfep)5297c478bd9Sstevel@tonic-gate dmfe_enable_interrupts(dmfe_t *dmfep)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/*
5347c478bd9Sstevel@tonic-gate 	 * Put 'the standard set of interrupts' in the interrupt mask register
5357c478bd9Sstevel@tonic-gate 	 */
5367c478bd9Sstevel@tonic-gate 	dmfep->imask =	RX_PKTDONE_INT | TX_PKTDONE_INT |
5375c1d0199Sgd 	    RX_STOPPED_INT | TX_STOPPED_INT | RX_UNAVAIL_INT | SYSTEM_ERR_INT;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, INT_MASK_REG,
540dd4eeefdSeota 	    NORMAL_SUMMARY_INT | ABNORMAL_SUMMARY_INT | dmfep->imask);
5417c478bd9Sstevel@tonic-gate 	dmfep->chip_state = CHIP_RUNNING;
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * ========== RX side routines ==========
5467c478bd9Sstevel@tonic-gate  */
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate  * Function to update receive statistics on various errors
5507c478bd9Sstevel@tonic-gate  */
5517c478bd9Sstevel@tonic-gate static void
dmfe_update_rx_stats(dmfe_t * dmfep,uint32_t desc0)5527c478bd9Sstevel@tonic-gate dmfe_update_rx_stats(dmfe_t *dmfep, uint32_t desc0)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->rxlock));
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/*
5577c478bd9Sstevel@tonic-gate 	 * The error summary bit and the error bits that it summarises
5587c478bd9Sstevel@tonic-gate 	 * are only valid if this is the last fragment.  Therefore, a
5597c478bd9Sstevel@tonic-gate 	 * fragment only contributes to the error statistics if both
5607c478bd9Sstevel@tonic-gate 	 * the last-fragment and error summary bits are set.
5617c478bd9Sstevel@tonic-gate 	 */
5627c478bd9Sstevel@tonic-gate 	if (((RX_LAST_DESC | RX_ERR_SUMMARY) & ~desc0) == 0) {
563cc291a4cSgd 		dmfep->rx_stats_ierrors += 1;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 		/*
5667c478bd9Sstevel@tonic-gate 		 * There are some other error bits in the descriptor for
567cc291a4cSgd 		 * which there don't seem to be appropriate MAC statistics,
5687c478bd9Sstevel@tonic-gate 		 * notably RX_COLLISION and perhaps RX_DESC_ERR.  The
5697c478bd9Sstevel@tonic-gate 		 * latter may not be possible if it is supposed to indicate
5707c478bd9Sstevel@tonic-gate 		 * that one buffer has been filled with a partial packet
5717c478bd9Sstevel@tonic-gate 		 * and the next buffer required for the rest of the packet
5727c478bd9Sstevel@tonic-gate 		 * was not available, as all our buffers are more than large
5737c478bd9Sstevel@tonic-gate 		 * enough for a whole packet without fragmenting.
5747c478bd9Sstevel@tonic-gate 		 */
5757c478bd9Sstevel@tonic-gate 
576cc291a4cSgd 		if (desc0 & RX_OVERFLOW) {
5777c478bd9Sstevel@tonic-gate 			dmfep->rx_stats_overflow += 1;
578cc291a4cSgd 
579cc291a4cSgd 		} else if (desc0 & RX_RUNT_FRAME)
5807c478bd9Sstevel@tonic-gate 			dmfep->rx_stats_short += 1;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		if (desc0 & RX_CRC)
583cc291a4cSgd 			dmfep->rx_stats_fcs += 1;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		if (desc0 & RX_FRAME2LONG)
586cc291a4cSgd 			dmfep->rx_stats_toolong += 1;
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/*
5907c478bd9Sstevel@tonic-gate 	 * A receive watchdog timeout is counted as a MAC-level receive
5917c478bd9Sstevel@tonic-gate 	 * error.  Strangely, it doesn't set the packet error summary bit,
5927c478bd9Sstevel@tonic-gate 	 * according to the chip data sheet :-?
5937c478bd9Sstevel@tonic-gate 	 */
5947c478bd9Sstevel@tonic-gate 	if (desc0 & RX_RCV_WD_TO)
595cc291a4cSgd 		dmfep->rx_stats_macrcv_errors += 1;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if (desc0 & RX_DRIBBLING)
598cc291a4cSgd 		dmfep->rx_stats_align += 1;
599cc291a4cSgd 
6007c478bd9Sstevel@tonic-gate 	if (desc0 & RX_MII_ERR)
601cc291a4cSgd 		dmfep->rx_stats_macrcv_errors += 1;
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate  * Receive incoming packet(s) and pass them up ...
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate static mblk_t *
dmfe_getp(dmfe_t * dmfep)6087c478bd9Sstevel@tonic-gate dmfe_getp(dmfe_t *dmfep)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	dma_area_t *descp;
6117c478bd9Sstevel@tonic-gate 	mblk_t **tail;
6127c478bd9Sstevel@tonic-gate 	mblk_t *head;
6137c478bd9Sstevel@tonic-gate 	mblk_t *mp;
6147c478bd9Sstevel@tonic-gate 	char *rxb;
6157c478bd9Sstevel@tonic-gate 	uchar_t *dp;
6167c478bd9Sstevel@tonic-gate 	uint32_t desc0;
6177c478bd9Sstevel@tonic-gate 	uint32_t misses;
6187c478bd9Sstevel@tonic-gate 	int packet_length;
6197c478bd9Sstevel@tonic-gate 	int index;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->rxlock);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	/*
6247c478bd9Sstevel@tonic-gate 	 * Update the missed frame statistic from the on-chip counter.
6257c478bd9Sstevel@tonic-gate 	 */
6267c478bd9Sstevel@tonic-gate 	misses = dmfe_chip_get32(dmfep, MISSED_FRAME_REG);
627cc291a4cSgd 	dmfep->rx_stats_norcvbuf += (misses & MISSED_FRAME_MASK);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * sync (all) receive descriptors before inspecting them
6317c478bd9Sstevel@tonic-gate 	 */
6327c478bd9Sstevel@tonic-gate 	descp = &dmfep->rx_desc;
6337c478bd9Sstevel@tonic-gate 	DMA_SYNC(descp, DDI_DMA_SYNC_FORKERNEL);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	/*
6367c478bd9Sstevel@tonic-gate 	 * We should own at least one RX entry, since we've had a
6377c478bd9Sstevel@tonic-gate 	 * receive interrupt, but let's not be dogmatic about it.
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	index = dmfep->rx.next_free;
6407c478bd9Sstevel@tonic-gate 	desc0 = dmfe_ring_get32(descp, index, DESC0);
6417c478bd9Sstevel@tonic-gate 
642bdb9230aSGarrett D'Amore 	DTRACE_PROBE1(rx__start, uint32_t, desc0);
6437c478bd9Sstevel@tonic-gate 	for (head = NULL, tail = &head; (desc0 & RX_OWN) == 0; ) {
6447c478bd9Sstevel@tonic-gate 		/*
6457c478bd9Sstevel@tonic-gate 		 * Maintain statistics for every descriptor returned
6467c478bd9Sstevel@tonic-gate 		 * to us by the chip ...
6477c478bd9Sstevel@tonic-gate 		 */
6487c478bd9Sstevel@tonic-gate 		dmfe_update_rx_stats(dmfep, desc0);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		/*
6517c478bd9Sstevel@tonic-gate 		 * Check that the entry has both "packet start" and
6527c478bd9Sstevel@tonic-gate 		 * "packet end" flags.  We really shouldn't get packet
6537c478bd9Sstevel@tonic-gate 		 * fragments, 'cos all the RX buffers are bigger than
6547c478bd9Sstevel@tonic-gate 		 * the largest valid packet.  So we'll just drop any
6557c478bd9Sstevel@tonic-gate 		 * fragments we find & skip on to the next entry.
6567c478bd9Sstevel@tonic-gate 		 */
6577c478bd9Sstevel@tonic-gate 		if (((RX_FIRST_DESC | RX_LAST_DESC) & ~desc0) != 0) {
658bdb9230aSGarrett D'Amore 			DTRACE_PROBE1(rx__frag, uint32_t, desc0);
6597c478bd9Sstevel@tonic-gate 			goto skip;
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		/*
6637c478bd9Sstevel@tonic-gate 		 * A whole packet in one buffer.  We have to check error
6647c478bd9Sstevel@tonic-gate 		 * status and packet length before forwarding it upstream.
6657c478bd9Sstevel@tonic-gate 		 */
6667c478bd9Sstevel@tonic-gate 		if (desc0 & RX_ERR_SUMMARY) {
667bdb9230aSGarrett D'Amore 			DTRACE_PROBE1(rx__err, uint32_t, desc0);
6687c478bd9Sstevel@tonic-gate 			goto skip;
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		packet_length = (desc0 >> 16) & 0x3fff;
6727c478bd9Sstevel@tonic-gate 		if (packet_length > DMFE_MAX_PKT_SIZE) {
673bdb9230aSGarrett D'Amore 			DTRACE_PROBE1(rx__toobig, int, packet_length);
6747c478bd9Sstevel@tonic-gate 			goto skip;
6757c478bd9Sstevel@tonic-gate 		} else if (packet_length < ETHERMIN) {
676cc291a4cSgd 			/*
677cc291a4cSgd 			 * Note that VLAN packet would be even larger,
678cc291a4cSgd 			 * but we don't worry about dropping runt VLAN
679cc291a4cSgd 			 * frames.
680cc291a4cSgd 			 *
681cc291a4cSgd 			 * This check is probably redundant, as well,
682cc291a4cSgd 			 * since the hardware should drop RUNT frames.
683cc291a4cSgd 			 */
684bdb9230aSGarrett D'Amore 			DTRACE_PROBE1(rx__runt, int, packet_length);
6857c478bd9Sstevel@tonic-gate 			goto skip;
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		/*
6897c478bd9Sstevel@tonic-gate 		 * Sync the data, so we can examine it; then check that
6907c478bd9Sstevel@tonic-gate 		 * the packet is really intended for us (remember that
6917c478bd9Sstevel@tonic-gate 		 * if we're using Imperfect Filtering, then the chip will
6927c478bd9Sstevel@tonic-gate 		 * receive unicast packets sent to stations whose addresses
6937c478bd9Sstevel@tonic-gate 		 * just happen to hash to the same value as our own; we
6947c478bd9Sstevel@tonic-gate 		 * discard these here so they don't get sent upstream ...)
6957c478bd9Sstevel@tonic-gate 		 */
6967c478bd9Sstevel@tonic-gate 		(void) ddi_dma_sync(dmfep->rx_buff.dma_hdl,
6975c1d0199Sgd 		    index * DMFE_BUF_SIZE, DMFE_BUF_SIZE,
698dd4eeefdSeota 		    DDI_DMA_SYNC_FORKERNEL);
6997c478bd9Sstevel@tonic-gate 		rxb = &dmfep->rx_buff.mem_va[index*DMFE_BUF_SIZE];
700cc291a4cSgd 
701cc291a4cSgd 
702cc291a4cSgd 		/*
703cc291a4cSgd 		 * We do not bother to check that the packet is really for
704cc291a4cSgd 		 * us, we let the MAC framework make that check instead.
705cc291a4cSgd 		 * This is especially important if we ever want to support
706cc291a4cSgd 		 * multiple MAC addresses.
707cc291a4cSgd 		 */
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 		/*
7107c478bd9Sstevel@tonic-gate 		 * Packet looks good; get a buffer to copy it into.  We
7117c478bd9Sstevel@tonic-gate 		 * allow some space at the front of the allocated buffer
7127c478bd9Sstevel@tonic-gate 		 * (HEADROOM) in case any upstream modules want to prepend
7137c478bd9Sstevel@tonic-gate 		 * some sort of header.  The value has been carefully chosen
7147c478bd9Sstevel@tonic-gate 		 * So that it also has the side-effect of making the packet
7157c478bd9Sstevel@tonic-gate 		 * *contents* 4-byte aligned, as required by NCA!
7167c478bd9Sstevel@tonic-gate 		 */
7177c478bd9Sstevel@tonic-gate 		mp = allocb(DMFE_HEADROOM + packet_length, 0);
7187c478bd9Sstevel@tonic-gate 		if (mp == NULL) {
719bdb9230aSGarrett D'Amore 			DTRACE_PROBE(rx__no__buf);
7207c478bd9Sstevel@tonic-gate 			dmfep->rx_stats_norcvbuf += 1;
7217c478bd9Sstevel@tonic-gate 			goto skip;
7227c478bd9Sstevel@tonic-gate 		}
7237c478bd9Sstevel@tonic-gate 
724cc291a4cSgd 		/*
725cc291a4cSgd 		 * Account for statistics of good packets.
726cc291a4cSgd 		 */
727cc291a4cSgd 		dmfep->rx_stats_ipackets += 1;
728cc291a4cSgd 		dmfep->rx_stats_rbytes += packet_length;
729cc291a4cSgd 		if (desc0 & RX_MULTI_FRAME) {
730cc291a4cSgd 			if (bcmp(rxb, dmfe_broadcast_addr, ETHERADDRL)) {
731cc291a4cSgd 				dmfep->rx_stats_multi += 1;
732cc291a4cSgd 			} else {
733cc291a4cSgd 				dmfep->rx_stats_bcast += 1;
734cc291a4cSgd 			}
735cc291a4cSgd 		}
736cc291a4cSgd 
7377c478bd9Sstevel@tonic-gate 		/*
7387c478bd9Sstevel@tonic-gate 		 * Copy the packet into the STREAMS buffer
7397c478bd9Sstevel@tonic-gate 		 */
7407c478bd9Sstevel@tonic-gate 		dp = mp->b_rptr += DMFE_HEADROOM;
7417c478bd9Sstevel@tonic-gate 		mp->b_cont = mp->b_next = NULL;
7427c478bd9Sstevel@tonic-gate 
743cc291a4cSgd 		/*
744cc291a4cSgd 		 * Don't worry about stripping the vlan tag, the MAC
745cc291a4cSgd 		 * layer will take care of that for us.
746cc291a4cSgd 		 */
747cc291a4cSgd 		bcopy(rxb, dp, packet_length);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 		/*
7507c478bd9Sstevel@tonic-gate 		 * Fix up the packet length, and link it to the chain
7517c478bd9Sstevel@tonic-gate 		 */
7527c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + packet_length - ETHERFCSL;
7537c478bd9Sstevel@tonic-gate 		*tail = mp;
7547c478bd9Sstevel@tonic-gate 		tail = &mp->b_next;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	skip:
7577c478bd9Sstevel@tonic-gate 		/*
7587c478bd9Sstevel@tonic-gate 		 * Return ownership of ring entry & advance to next
7597c478bd9Sstevel@tonic-gate 		 */
7607c478bd9Sstevel@tonic-gate 		dmfe_ring_put32(descp, index, DESC0, RX_OWN);
7617c478bd9Sstevel@tonic-gate 		index = NEXT(index, dmfep->rx.n_desc);
7627c478bd9Sstevel@tonic-gate 		desc0 = dmfe_ring_get32(descp, index, DESC0);
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	/*
7667c478bd9Sstevel@tonic-gate 	 * Remember where to start looking next time ...
7677c478bd9Sstevel@tonic-gate 	 */
7687c478bd9Sstevel@tonic-gate 	dmfep->rx.next_free = index;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/*
7717c478bd9Sstevel@tonic-gate 	 * sync the receive descriptors that we've given back
7727c478bd9Sstevel@tonic-gate 	 * (actually, we sync all of them for simplicity), and
7737c478bd9Sstevel@tonic-gate 	 * wake the chip in case it had suspended receive
7747c478bd9Sstevel@tonic-gate 	 */
7757c478bd9Sstevel@tonic-gate 	DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV);
7767c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, RX_POLL_REG, 0);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->rxlock);
7797c478bd9Sstevel@tonic-gate 	return (head);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate  * ========== Primary TX side routines ==========
7847c478bd9Sstevel@tonic-gate  */
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate /*
7877c478bd9Sstevel@tonic-gate  *	TX ring management:
7887c478bd9Sstevel@tonic-gate  *
7897c478bd9Sstevel@tonic-gate  *	There are <tx.n_desc> entries in the ring, of which those from
7907c478bd9Sstevel@tonic-gate  *	<tx.next_free> round to but not including <tx.next_busy> must
7917c478bd9Sstevel@tonic-gate  *	be owned by the CPU.  The number of such entries should equal
7927c478bd9Sstevel@tonic-gate  *	<tx.n_free>; but there may also be some more entries which the
7937c478bd9Sstevel@tonic-gate  *	chip has given back but which we haven't yet accounted for.
7947c478bd9Sstevel@tonic-gate  *	The routine dmfe_reclaim_tx_desc() adjusts the indexes & counts
7957c478bd9Sstevel@tonic-gate  *	as it discovers such entries.
7967c478bd9Sstevel@tonic-gate  *
7977c478bd9Sstevel@tonic-gate  *	Initially, or when the ring is entirely free:
7987c478bd9Sstevel@tonic-gate  *		C = Owned by CPU
7997c478bd9Sstevel@tonic-gate  *		D = Owned by Davicom (DMFE) chip
8007c478bd9Sstevel@tonic-gate  *
8017c478bd9Sstevel@tonic-gate  *	tx.next_free					tx.n_desc = 16
8027c478bd9Sstevel@tonic-gate  *	  |
8037c478bd9Sstevel@tonic-gate  *	  v
8047c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8057c478bd9Sstevel@tonic-gate  *	| C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C |
8067c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8077c478bd9Sstevel@tonic-gate  *	  ^
8087c478bd9Sstevel@tonic-gate  *	  |
8097c478bd9Sstevel@tonic-gate  *	tx.next_busy					tx.n_free = 16
8107c478bd9Sstevel@tonic-gate  *
8117c478bd9Sstevel@tonic-gate  *	On entry to reclaim() during normal use:
8127c478bd9Sstevel@tonic-gate  *
8137c478bd9Sstevel@tonic-gate  *					tx.next_free	tx.n_desc = 16
8147c478bd9Sstevel@tonic-gate  *					      |
8157c478bd9Sstevel@tonic-gate  *					      v
8167c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8177c478bd9Sstevel@tonic-gate  *	| C | C | C | C | C | C | D | D | D | C | C | C | C | C | C | C |
8187c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8197c478bd9Sstevel@tonic-gate  *		  ^
8207c478bd9Sstevel@tonic-gate  *		  |
8217c478bd9Sstevel@tonic-gate  *		tx.next_busy				tx.n_free = 9
8227c478bd9Sstevel@tonic-gate  *
8237c478bd9Sstevel@tonic-gate  *	On exit from reclaim():
8247c478bd9Sstevel@tonic-gate  *
8257c478bd9Sstevel@tonic-gate  *					tx.next_free	tx.n_desc = 16
8267c478bd9Sstevel@tonic-gate  *					      |
8277c478bd9Sstevel@tonic-gate  *					      v
8287c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8297c478bd9Sstevel@tonic-gate  *	| C | C | C | C | C | C | D | D | D | C | C | C | C | C | C | C |
8307c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8317c478bd9Sstevel@tonic-gate  *				  ^
8327c478bd9Sstevel@tonic-gate  *				  |
8337c478bd9Sstevel@tonic-gate  *			     tx.next_busy		tx.n_free = 13
8347c478bd9Sstevel@tonic-gate  *
8357c478bd9Sstevel@tonic-gate  *	The ring is considered "full" when only one entry is owned by
8367c478bd9Sstevel@tonic-gate  *	the CPU; thus <tx.n_free> should always be >= 1.
8377c478bd9Sstevel@tonic-gate  *
8387c478bd9Sstevel@tonic-gate  *			tx.next_free			tx.n_desc = 16
8397c478bd9Sstevel@tonic-gate  *			      |
8407c478bd9Sstevel@tonic-gate  *			      v
8417c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8427c478bd9Sstevel@tonic-gate  *	| D | D | D | D | D | C | D | D | D | D | D | D | D | D | D | D |
8437c478bd9Sstevel@tonic-gate  *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8447c478bd9Sstevel@tonic-gate  *				  ^
8457c478bd9Sstevel@tonic-gate  *				  |
8467c478bd9Sstevel@tonic-gate  *			     tx.next_busy		tx.n_free = 1
8477c478bd9Sstevel@tonic-gate  */
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate /*
8507c478bd9Sstevel@tonic-gate  * Function to update transmit statistics on various errors
8517c478bd9Sstevel@tonic-gate  */
8527c478bd9Sstevel@tonic-gate static void
dmfe_update_tx_stats(dmfe_t * dmfep,int index,uint32_t desc0,uint32_t desc1)853cc291a4cSgd dmfe_update_tx_stats(dmfe_t *dmfep, int index, uint32_t desc0, uint32_t desc1)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate 	uint32_t collisions;
8567c478bd9Sstevel@tonic-gate 	uint32_t errbits;
8577c478bd9Sstevel@tonic-gate 	uint32_t errsum;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->txlock));
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	collisions = ((desc0 >> 3) & 0x0f);
8627c478bd9Sstevel@tonic-gate 	errsum = desc0 & TX_ERR_SUMMARY;
8637c478bd9Sstevel@tonic-gate 	errbits = desc0 & (TX_UNDERFLOW | TX_LATE_COLL | TX_CARRIER_LOSS |
864dd4eeefdSeota 	    TX_NO_CARRIER | TX_EXCESS_COLL | TX_JABBER_TO);
8657c478bd9Sstevel@tonic-gate 	if ((errsum == 0) != (errbits == 0)) {
8667c478bd9Sstevel@tonic-gate 		dmfe_log(dmfep, "dubious TX error status 0x%x", desc0);
8677c478bd9Sstevel@tonic-gate 		desc0 |= TX_ERR_SUMMARY;
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if (desc0 & TX_ERR_SUMMARY) {
871cc291a4cSgd 		dmfep->tx_stats_oerrors += 1;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 		/*
8747c478bd9Sstevel@tonic-gate 		 * If we ever see a transmit jabber timeout, we count it
8757c478bd9Sstevel@tonic-gate 		 * as a MAC-level transmit error; but we probably won't
8767c478bd9Sstevel@tonic-gate 		 * see it as it causes an Abnormal interrupt and we reset
8777c478bd9Sstevel@tonic-gate 		 * the chip in order to recover
8787c478bd9Sstevel@tonic-gate 		 */
8790d2a8e5eSgd 		if (desc0 & TX_JABBER_TO) {
880cc291a4cSgd 			dmfep->tx_stats_macxmt_errors += 1;
8810d2a8e5eSgd 			dmfep->tx_stats_jabber += 1;
8820d2a8e5eSgd 		}
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 		if (desc0 & TX_UNDERFLOW)
8857c478bd9Sstevel@tonic-gate 			dmfep->tx_stats_underflow += 1;
8867c478bd9Sstevel@tonic-gate 		else if (desc0 & TX_LATE_COLL)
8877c478bd9Sstevel@tonic-gate 			dmfep->tx_stats_xmtlatecoll += 1;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 		if (desc0 & (TX_CARRIER_LOSS | TX_NO_CARRIER))
8907c478bd9Sstevel@tonic-gate 			dmfep->tx_stats_nocarrier += 1;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 		if (desc0 & TX_EXCESS_COLL) {
8937c478bd9Sstevel@tonic-gate 			dmfep->tx_stats_excoll += 1;
8947c478bd9Sstevel@tonic-gate 			collisions = 16;
8957c478bd9Sstevel@tonic-gate 		}
896cc291a4cSgd 	} else {
897cc291a4cSgd 		int	bit = index % NBBY;
898cc291a4cSgd 		int	byt = index / NBBY;
899cc291a4cSgd 
900cc291a4cSgd 		if (dmfep->tx_mcast[byt] & bit) {
901cc291a4cSgd 			dmfep->tx_mcast[byt] &= ~bit;
902cc291a4cSgd 			dmfep->tx_stats_multi += 1;
903cc291a4cSgd 
904cc291a4cSgd 		} else if (dmfep->tx_bcast[byt] & bit) {
905cc291a4cSgd 			dmfep->tx_bcast[byt] &= ~bit;
906cc291a4cSgd 			dmfep->tx_stats_bcast += 1;
907cc291a4cSgd 		}
908cc291a4cSgd 
909cc291a4cSgd 		dmfep->tx_stats_opackets += 1;
910cc291a4cSgd 		dmfep->tx_stats_obytes += desc1 & TX_BUFFER_SIZE1;
9117c478bd9Sstevel@tonic-gate 	}
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	if (collisions == 1)
9147c478bd9Sstevel@tonic-gate 		dmfep->tx_stats_first_coll += 1;
9157c478bd9Sstevel@tonic-gate 	else if (collisions != 0)
9167c478bd9Sstevel@tonic-gate 		dmfep->tx_stats_multi_coll += 1;
9177c478bd9Sstevel@tonic-gate 	dmfep->tx_stats_collisions += collisions;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	if (desc0 & TX_DEFERRED)
9207c478bd9Sstevel@tonic-gate 		dmfep->tx_stats_defer += 1;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate /*
9247c478bd9Sstevel@tonic-gate  * Reclaim all the ring entries that the chip has returned to us ...
9257c478bd9Sstevel@tonic-gate  *
9267c478bd9Sstevel@tonic-gate  * Returns B_FALSE if no entries could be reclaimed.  Otherwise, reclaims
9277c478bd9Sstevel@tonic-gate  * as many as possible, restarts the TX stall timeout, and returns B_TRUE.
9287c478bd9Sstevel@tonic-gate  */
9297c478bd9Sstevel@tonic-gate static boolean_t
dmfe_reclaim_tx_desc(dmfe_t * dmfep)9307c478bd9Sstevel@tonic-gate dmfe_reclaim_tx_desc(dmfe_t *dmfep)
9317c478bd9Sstevel@tonic-gate {
9327c478bd9Sstevel@tonic-gate 	dma_area_t *descp;
9337c478bd9Sstevel@tonic-gate 	uint32_t desc0;
9347c478bd9Sstevel@tonic-gate 	uint32_t desc1;
9357c478bd9Sstevel@tonic-gate 	int i;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->txlock));
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/*
9407c478bd9Sstevel@tonic-gate 	 * sync transmit descriptor ring before looking at it
9417c478bd9Sstevel@tonic-gate 	 */
9427c478bd9Sstevel@tonic-gate 	descp = &dmfep->tx_desc;
9437c478bd9Sstevel@tonic-gate 	DMA_SYNC(descp, DDI_DMA_SYNC_FORKERNEL);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/*
9467c478bd9Sstevel@tonic-gate 	 * Early exit if there are no descriptors to reclaim, either
9477c478bd9Sstevel@tonic-gate 	 * because they're all reclaimed already, or because the next
9487c478bd9Sstevel@tonic-gate 	 * one is still owned by the chip ...
9497c478bd9Sstevel@tonic-gate 	 */
9507c478bd9Sstevel@tonic-gate 	i = dmfep->tx.next_busy;
9517c478bd9Sstevel@tonic-gate 	if (i == dmfep->tx.next_free)
9527c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9537c478bd9Sstevel@tonic-gate 	desc0 = dmfe_ring_get32(descp, i, DESC0);
9547c478bd9Sstevel@tonic-gate 	if (desc0 & TX_OWN)
9557c478bd9Sstevel@tonic-gate 		return (B_FALSE);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	/*
9587c478bd9Sstevel@tonic-gate 	 * Reclaim as many descriptors as possible ...
9597c478bd9Sstevel@tonic-gate 	 */
9607c478bd9Sstevel@tonic-gate 	for (;;) {
9617c478bd9Sstevel@tonic-gate 		desc1 = dmfe_ring_get32(descp, i, DESC1);
9627c478bd9Sstevel@tonic-gate 		ASSERT((desc1 & (TX_SETUP_PACKET | TX_LAST_DESC)) != 0);
9637c478bd9Sstevel@tonic-gate 
964bdb9230aSGarrett D'Amore 		if ((desc1 & TX_SETUP_PACKET) == 0) {
9657c478bd9Sstevel@tonic-gate 			/*
9667c478bd9Sstevel@tonic-gate 			 * Regular packet - just update stats
9677c478bd9Sstevel@tonic-gate 			 */
968cc291a4cSgd 			dmfe_update_tx_stats(dmfep, i, desc0, desc1);
9697c478bd9Sstevel@tonic-gate 		}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		/*
9727c478bd9Sstevel@tonic-gate 		 * Update count & index; we're all done if the ring is
9737c478bd9Sstevel@tonic-gate 		 * now fully reclaimed, or the next entry if still owned
9747c478bd9Sstevel@tonic-gate 		 * by the chip ...
9757c478bd9Sstevel@tonic-gate 		 */
9767c478bd9Sstevel@tonic-gate 		dmfep->tx.n_free += 1;
9777c478bd9Sstevel@tonic-gate 		i = NEXT(i, dmfep->tx.n_desc);
9787c478bd9Sstevel@tonic-gate 		if (i == dmfep->tx.next_free)
9797c478bd9Sstevel@tonic-gate 			break;
9807c478bd9Sstevel@tonic-gate 		desc0 = dmfe_ring_get32(descp, i, DESC0);
9817c478bd9Sstevel@tonic-gate 		if (desc0 & TX_OWN)
9827c478bd9Sstevel@tonic-gate 			break;
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	dmfep->tx.next_busy = i;
9867c478bd9Sstevel@tonic-gate 	dmfep->tx_pending_tix = 0;
9877c478bd9Sstevel@tonic-gate 	return (B_TRUE);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate  * Send the message in the message block chain <mp>.
9927c478bd9Sstevel@tonic-gate  *
9937c478bd9Sstevel@tonic-gate  * The message is freed if and only if its contents are successfully copied
994cc291a4cSgd  * and queued for transmission (so that the return value is B_TRUE).
995cc291a4cSgd  * If we can't queue the message, the return value is B_FALSE and
9967c478bd9Sstevel@tonic-gate  * the message is *not* freed.
9977c478bd9Sstevel@tonic-gate  *
9987c478bd9Sstevel@tonic-gate  * This routine handles the special case of <mp> == NULL, which indicates
9997c478bd9Sstevel@tonic-gate  * that we want to "send" the special "setup packet" allocated during
10007c478bd9Sstevel@tonic-gate  * startup.  We have to use some different flags in the packet descriptor
10017c478bd9Sstevel@tonic-gate  * to say its a setup packet (from the global <dmfe_setup_desc1>), and the
10027c478bd9Sstevel@tonic-gate  * setup packet *isn't* freed after use.
10037c478bd9Sstevel@tonic-gate  */
1004cc291a4cSgd static boolean_t
dmfe_send_msg(dmfe_t * dmfep,mblk_t * mp)1005cc291a4cSgd dmfe_send_msg(dmfe_t *dmfep, mblk_t *mp)
10067c478bd9Sstevel@tonic-gate {
10077c478bd9Sstevel@tonic-gate 	dma_area_t *descp;
10087c478bd9Sstevel@tonic-gate 	mblk_t *bp;
10097c478bd9Sstevel@tonic-gate 	char *txb;
10107c478bd9Sstevel@tonic-gate 	uint32_t desc1;
10117c478bd9Sstevel@tonic-gate 	uint32_t index;
10127c478bd9Sstevel@tonic-gate 	size_t totlen;
10137c478bd9Sstevel@tonic-gate 	size_t mblen;
1014bdb9230aSGarrett D'Amore 	uint32_t paddr;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	/*
10177c478bd9Sstevel@tonic-gate 	 * If the number of free slots is below the reclaim threshold
10187c478bd9Sstevel@tonic-gate 	 * (soft limit), we'll try to reclaim some.  If we fail, and
10197c478bd9Sstevel@tonic-gate 	 * the number of free slots is also below the minimum required
10207c478bd9Sstevel@tonic-gate 	 * (the hard limit, usually 1), then we can't send the packet.
10217c478bd9Sstevel@tonic-gate 	 */
10227c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->txlock);
1023bdb9230aSGarrett D'Amore 	if (dmfep->suspended)
1024bdb9230aSGarrett D'Amore 		return (B_FALSE);
1025bdb9230aSGarrett D'Amore 
10267c478bd9Sstevel@tonic-gate 	if (dmfep->tx.n_free <= dmfe_tx_reclaim_level &&
10277c478bd9Sstevel@tonic-gate 	    dmfe_reclaim_tx_desc(dmfep) == B_FALSE &&
10287c478bd9Sstevel@tonic-gate 	    dmfep->tx.n_free <= dmfe_tx_min_free) {
10297c478bd9Sstevel@tonic-gate 		/*
1030cc291a4cSgd 		 * Resource shortage - return B_FALSE so the packet
1031cc291a4cSgd 		 * will be queued for retry after the next TX-done
1032cc291a4cSgd 		 * interrupt.
10337c478bd9Sstevel@tonic-gate 		 */
10347c478bd9Sstevel@tonic-gate 		mutex_exit(dmfep->txlock);
1035bdb9230aSGarrett D'Amore 		DTRACE_PROBE(tx__no__desc);
1036cc291a4cSgd 		return (B_FALSE);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	/*
10407c478bd9Sstevel@tonic-gate 	 * There's a slot available, so claim it by incrementing
10417c478bd9Sstevel@tonic-gate 	 * the next-free index and decrementing the free count.
10427c478bd9Sstevel@tonic-gate 	 * If the ring is currently empty, we also restart the
10437c478bd9Sstevel@tonic-gate 	 * stall-detect timer.  The ASSERTions check that our
10447c478bd9Sstevel@tonic-gate 	 * invariants still hold:
10457c478bd9Sstevel@tonic-gate 	 *	the next-free index must not match the next-busy index
10467c478bd9Sstevel@tonic-gate 	 *	there must still be at least one free entry
10477c478bd9Sstevel@tonic-gate 	 * After this, we now have exclusive ownership of the ring
10487c478bd9Sstevel@tonic-gate 	 * entry (and matching buffer) indicated by <index>, so we
10497c478bd9Sstevel@tonic-gate 	 * don't need to hold the TX lock any longer
10507c478bd9Sstevel@tonic-gate 	 */
10517c478bd9Sstevel@tonic-gate 	index = dmfep->tx.next_free;
10527c478bd9Sstevel@tonic-gate 	dmfep->tx.next_free = NEXT(index, dmfep->tx.n_desc);
10537c478bd9Sstevel@tonic-gate 	ASSERT(dmfep->tx.next_free != dmfep->tx.next_busy);
10547c478bd9Sstevel@tonic-gate 	if (dmfep->tx.n_free-- == dmfep->tx.n_desc)
10557c478bd9Sstevel@tonic-gate 		dmfep->tx_pending_tix = 0;
10567c478bd9Sstevel@tonic-gate 	ASSERT(dmfep->tx.n_free >= 1);
10577c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->txlock);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/*
10607c478bd9Sstevel@tonic-gate 	 * Check the ownership of the ring entry ...
10617c478bd9Sstevel@tonic-gate 	 */
10627c478bd9Sstevel@tonic-gate 	descp = &dmfep->tx_desc;
10637c478bd9Sstevel@tonic-gate 	ASSERT((dmfe_ring_get32(descp, index, DESC0) & TX_OWN) == 0);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
10667c478bd9Sstevel@tonic-gate 		/*
10677c478bd9Sstevel@tonic-gate 		 * Indicates we should send a SETUP packet, which we do by
10687c478bd9Sstevel@tonic-gate 		 * temporarily switching the BUFFER1 pointer in the ring
10697c478bd9Sstevel@tonic-gate 		 * entry.  The reclaim routine will restore BUFFER1 to its
10707c478bd9Sstevel@tonic-gate 		 * usual value.
10717c478bd9Sstevel@tonic-gate 		 *
10727c478bd9Sstevel@tonic-gate 		 * Note that as the setup packet is tagged on the end of
10737c478bd9Sstevel@tonic-gate 		 * the TX ring, when we sync the descriptor we're also
10747c478bd9Sstevel@tonic-gate 		 * implicitly syncing the setup packet - hence, we don't
10757c478bd9Sstevel@tonic-gate 		 * need a separate ddi_dma_sync() call here.
10767c478bd9Sstevel@tonic-gate 		 */
10777c478bd9Sstevel@tonic-gate 		desc1 = dmfe_setup_desc1;
1078bdb9230aSGarrett D'Amore 		paddr = descp->setup_dvma;
10797c478bd9Sstevel@tonic-gate 	} else {
10807c478bd9Sstevel@tonic-gate 		/*
10817c478bd9Sstevel@tonic-gate 		 * A regular packet; we copy the data into a pre-mapped
10827c478bd9Sstevel@tonic-gate 		 * buffer, which avoids the overhead (and complication)
10837c478bd9Sstevel@tonic-gate 		 * of mapping/unmapping STREAMS buffers and keeping hold
10847c478bd9Sstevel@tonic-gate 		 * of them until the DMA has completed.
10857c478bd9Sstevel@tonic-gate 		 *
10867c478bd9Sstevel@tonic-gate 		 * Because all buffers are the same size, and larger
10877c478bd9Sstevel@tonic-gate 		 * than the longest single valid message, we don't have
10887c478bd9Sstevel@tonic-gate 		 * to bother about splitting the message across multiple
10897c478bd9Sstevel@tonic-gate 		 * buffers.
10907c478bd9Sstevel@tonic-gate 		 */
10917c478bd9Sstevel@tonic-gate 		txb = &dmfep->tx_buff.mem_va[index*DMFE_BUF_SIZE];
10927c478bd9Sstevel@tonic-gate 		totlen = 0;
10937c478bd9Sstevel@tonic-gate 		bp = mp;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 		/*
10967c478bd9Sstevel@tonic-gate 		 * Copy all (remaining) mblks in the message ...
10977c478bd9Sstevel@tonic-gate 		 */
10987c478bd9Sstevel@tonic-gate 		for (; bp != NULL; bp = bp->b_cont) {
109922eb7cb5Sgd 			mblen = MBLKL(bp);
11007c478bd9Sstevel@tonic-gate 			if ((totlen += mblen) <= DMFE_MAX_PKT_SIZE) {
11017c478bd9Sstevel@tonic-gate 				bcopy(bp->b_rptr, txb, mblen);
11027c478bd9Sstevel@tonic-gate 				txb += mblen;
11037c478bd9Sstevel@tonic-gate 			}
11047c478bd9Sstevel@tonic-gate 		}
11057c478bd9Sstevel@tonic-gate 
1106cc291a4cSgd 		/*
1107cc291a4cSgd 		 * Is this a multicast or broadcast packet?  We do
1108cc291a4cSgd 		 * this so that we can track statistics accurately
1109cc291a4cSgd 		 * when we reclaim it.
1110cc291a4cSgd 		 */
1111cc291a4cSgd 		txb = &dmfep->tx_buff.mem_va[index*DMFE_BUF_SIZE];
1112cc291a4cSgd 		if (txb[0] & 0x1) {
1113cc291a4cSgd 			if (bcmp(txb, dmfe_broadcast_addr, ETHERADDRL) == 0) {
1114cc291a4cSgd 				dmfep->tx_bcast[index / NBBY] |=
1115cc291a4cSgd 				    (1 << (index % NBBY));
1116cc291a4cSgd 			} else {
1117cc291a4cSgd 				dmfep->tx_mcast[index / NBBY] |=
1118cc291a4cSgd 				    (1 << (index % NBBY));
1119cc291a4cSgd 			}
1120cc291a4cSgd 		}
1121cc291a4cSgd 
11227c478bd9Sstevel@tonic-gate 		/*
11237c478bd9Sstevel@tonic-gate 		 * We'e reached the end of the chain; and we should have
11247c478bd9Sstevel@tonic-gate 		 * collected no more than DMFE_MAX_PKT_SIZE bytes into our
11257c478bd9Sstevel@tonic-gate 		 * buffer.  Note that the <size> field in the descriptor is
11267c478bd9Sstevel@tonic-gate 		 * only 11 bits, so bigger packets would be a problem!
11277c478bd9Sstevel@tonic-gate 		 */
11287c478bd9Sstevel@tonic-gate 		ASSERT(bp == NULL);
11297c478bd9Sstevel@tonic-gate 		ASSERT(totlen <= DMFE_MAX_PKT_SIZE);
11307c478bd9Sstevel@tonic-gate 		totlen &= TX_BUFFER_SIZE1;
11317c478bd9Sstevel@tonic-gate 		desc1 = TX_FIRST_DESC | TX_LAST_DESC | totlen;
1132bdb9230aSGarrett D'Amore 		paddr = dmfep->tx_buff.mem_dvma + index*DMFE_BUF_SIZE;
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 		(void) ddi_dma_sync(dmfep->tx_buff.dma_hdl,
11355c1d0199Sgd 		    index * DMFE_BUF_SIZE, DMFE_BUF_SIZE, DDI_DMA_SYNC_FORDEV);
11367c478bd9Sstevel@tonic-gate 	}
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	/*
11397c478bd9Sstevel@tonic-gate 	 * Update ring descriptor entries, sync them, and wake up the
11407c478bd9Sstevel@tonic-gate 	 * transmit process
11417c478bd9Sstevel@tonic-gate 	 */
11427c478bd9Sstevel@tonic-gate 	if ((index & dmfe_tx_int_factor) == 0)
11437c478bd9Sstevel@tonic-gate 		desc1 |= TX_INT_ON_COMP;
11447c478bd9Sstevel@tonic-gate 	desc1 |= TX_CHAINING;
1145bdb9230aSGarrett D'Amore 	dmfe_ring_put32(descp, index, BUFFER1, paddr);
11467c478bd9Sstevel@tonic-gate 	dmfe_ring_put32(descp, index, DESC1, desc1);
11477c478bd9Sstevel@tonic-gate 	dmfe_ring_put32(descp, index, DESC0, TX_OWN);
11487c478bd9Sstevel@tonic-gate 	DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV);
11497c478bd9Sstevel@tonic-gate 	dmfe_chip_put32(dmfep, TX_POLL_REG, 0);
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	/*
11527c478bd9Sstevel@tonic-gate 	 * Finally, free the message & return success
11537c478bd9Sstevel@tonic-gate 	 */
11547c478bd9Sstevel@tonic-gate 	if (mp)
11557c478bd9Sstevel@tonic-gate 		freemsg(mp);
1156cc291a4cSgd 	return (B_TRUE);
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate /*
1160cc291a4cSgd  *	dmfe_m_tx() -- send a chain of packets
11617c478bd9Sstevel@tonic-gate  *
1162cc291a4cSgd  *	Called when packet(s) are ready to be transmitted. A pointer to an
11637c478bd9Sstevel@tonic-gate  *	M_DATA message that contains the packet is passed to this routine.
11647c478bd9Sstevel@tonic-gate  *	The complete LLC header is contained in the message's first message
11657c478bd9Sstevel@tonic-gate  *	block, and the remainder of the packet is contained within
11667c478bd9Sstevel@tonic-gate  *	additional M_DATA message blocks linked to the first message block.
11677c478bd9Sstevel@tonic-gate  *
1168cc291a4cSgd  *	Additional messages may be passed by linking with b_next.
11697c478bd9Sstevel@tonic-gate  */
1170cc291a4cSgd static mblk_t *
dmfe_m_tx(void * arg,mblk_t * mp)1171cc291a4cSgd dmfe_m_tx(void *arg, mblk_t *mp)
11727c478bd9Sstevel@tonic-gate {
1173cc291a4cSgd 	dmfe_t *dmfep = arg;			/* private device info	*/
1174cc291a4cSgd 	mblk_t *next;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1177cc291a4cSgd 	ASSERT(dmfep->mac_state == DMFE_MAC_STARTED);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	if (dmfep->chip_state != CHIP_RUNNING)
1180cc291a4cSgd 		return (mp);
11817c478bd9Sstevel@tonic-gate 
1182cc291a4cSgd 	while (mp != NULL) {
1183cc291a4cSgd 		next = mp->b_next;
1184cc291a4cSgd 		mp->b_next = NULL;
1185cc291a4cSgd 		if (!dmfe_send_msg(dmfep, mp)) {
1186cc291a4cSgd 			mp->b_next = next;
1187cc291a4cSgd 			break;
1188cc291a4cSgd 		}
1189cc291a4cSgd 		mp = next;
1190cc291a4cSgd 	}
11917c478bd9Sstevel@tonic-gate 
1192cc291a4cSgd 	return (mp);
1193cc291a4cSgd }
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate /*
11967c478bd9Sstevel@tonic-gate  * ========== Address-setting routines (TX-side) ==========
11977c478bd9Sstevel@tonic-gate  */
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate /*
12007c478bd9Sstevel@tonic-gate  * Find the index of the relevant bit in the setup packet.
12017c478bd9Sstevel@tonic-gate  * This must mirror the way the hardware will actually calculate it!
12027c478bd9Sstevel@tonic-gate  */
12037c478bd9Sstevel@tonic-gate static uint32_t
dmfe_hash_index(const uint8_t * address)1204cc291a4cSgd dmfe_hash_index(const uint8_t *address)
12057c478bd9Sstevel@tonic-gate {
12067c478bd9Sstevel@tonic-gate 	uint32_t const POLY = HASH_POLY;
12077c478bd9Sstevel@tonic-gate 	uint32_t crc = HASH_CRC;
12087c478bd9Sstevel@tonic-gate 	uint32_t index;
12097c478bd9Sstevel@tonic-gate 	uint32_t msb;
12107c478bd9Sstevel@tonic-gate 	uchar_t currentbyte;
12117c478bd9Sstevel@tonic-gate 	int byteslength;
12127c478bd9Sstevel@tonic-gate 	int shift;
12137c478bd9Sstevel@tonic-gate 	int bit;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	for (byteslength = 0; byteslength < ETHERADDRL; ++byteslength) {
12167c478bd9Sstevel@tonic-gate 		currentbyte = address[byteslength];
12177c478bd9Sstevel@tonic-gate 		for (bit = 0; bit < 8; ++bit) {
12187c478bd9Sstevel@tonic-gate 			msb = crc >> 31;
12197c478bd9Sstevel@tonic-gate 			crc <<= 1;
12207c478bd9Sstevel@tonic-gate 			if (msb ^ (currentbyte & 1)) {
12217c478bd9Sstevel@tonic-gate 				crc ^= POLY;
12227c478bd9Sstevel@tonic-gate 				crc |= 0x00000001;
12237c478bd9Sstevel@tonic-gate 			}
12247c478bd9Sstevel@tonic-gate 			currentbyte >>= 1;
12257c478bd9Sstevel@tonic-gate 		}
12267c478bd9Sstevel@tonic-gate 	}
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	for (index = 0, bit = 23, shift = 8; shift >= 0; ++bit, --shift)
12297c478bd9Sstevel@tonic-gate 		index |= (((crc >> bit) & 1) << shift);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	return (index);
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate /*
12357c478bd9Sstevel@tonic-gate  * Find and set/clear the relevant bit in the setup packet hash table
12367c478bd9Sstevel@tonic-gate  * This must mirror the way the hardware will actually interpret it!
12377c478bd9Sstevel@tonic-gate  */
12387c478bd9Sstevel@tonic-gate static void
dmfe_update_hash(dmfe_t * dmfep,uint32_t index,boolean_t val)12397c478bd9Sstevel@tonic-gate dmfe_update_hash(dmfe_t *dmfep, uint32_t index, boolean_t val)
12407c478bd9Sstevel@tonic-gate {
12417c478bd9Sstevel@tonic-gate 	dma_area_t *descp;
12427c478bd9Sstevel@tonic-gate 	uint32_t tmp;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	descp = &dmfep->tx_desc;
12477c478bd9Sstevel@tonic-gate 	tmp = dmfe_setup_get32(descp, index/16);
12487c478bd9Sstevel@tonic-gate 	if (val)
12497c478bd9Sstevel@tonic-gate 		tmp |= 1 << (index%16);
12507c478bd9Sstevel@tonic-gate 	else
12517c478bd9Sstevel@tonic-gate 		tmp &= ~(1 << (index%16));
12527c478bd9Sstevel@tonic-gate 	dmfe_setup_put32(descp, index/16, tmp);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate /*
12567c478bd9Sstevel@tonic-gate  * Update the refcount for the bit in the setup packet corresponding
12577c478bd9Sstevel@tonic-gate  * to the specified address; if it changes between zero & nonzero,
12587c478bd9Sstevel@tonic-gate  * also update the bitmap itself & return B_TRUE, so that the caller
12597c478bd9Sstevel@tonic-gate  * knows to re-send the setup packet.  Otherwise (only the refcount
12607c478bd9Sstevel@tonic-gate  * changed), return B_FALSE
12617c478bd9Sstevel@tonic-gate  */
12627c478bd9Sstevel@tonic-gate static boolean_t
dmfe_update_mcast(dmfe_t * dmfep,const uint8_t * mca,boolean_t val)1263cc291a4cSgd dmfe_update_mcast(dmfe_t *dmfep, const uint8_t *mca, boolean_t val)
12647c478bd9Sstevel@tonic-gate {
12657c478bd9Sstevel@tonic-gate 	uint32_t index;
12667c478bd9Sstevel@tonic-gate 	uint8_t *refp;
12677c478bd9Sstevel@tonic-gate 	boolean_t change;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	index = dmfe_hash_index(mca);
12707c478bd9Sstevel@tonic-gate 	refp = &dmfep->mcast_refs[index];
12717c478bd9Sstevel@tonic-gate 	change = (val ? (*refp)++ : --(*refp)) == 0;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	if (change)
12747c478bd9Sstevel@tonic-gate 		dmfe_update_hash(dmfep, index, val);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	return (change);
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate /*
12807c478bd9Sstevel@tonic-gate  * "Transmit" the (possibly updated) magic setup packet
12817c478bd9Sstevel@tonic-gate  */
12827c478bd9Sstevel@tonic-gate static int
dmfe_send_setup(dmfe_t * dmfep)12837c478bd9Sstevel@tonic-gate dmfe_send_setup(dmfe_t *dmfep)
12847c478bd9Sstevel@tonic-gate {
12857c478bd9Sstevel@tonic-gate 	int status;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
12887c478bd9Sstevel@tonic-gate 
1289bdb9230aSGarrett D'Amore 	if (dmfep->suspended)
1290bdb9230aSGarrett D'Amore 		return (0);
1291bdb9230aSGarrett D'Amore 
12927c478bd9Sstevel@tonic-gate 	/*
12937c478bd9Sstevel@tonic-gate 	 * If the chip isn't running, we can't really send the setup frame
12947c478bd9Sstevel@tonic-gate 	 * now but it doesn't matter, 'cos it will be sent when the transmit
1295cc291a4cSgd 	 * process is restarted (see dmfe_start()).
12967c478bd9Sstevel@tonic-gate 	 */
12977c478bd9Sstevel@tonic-gate 	if ((dmfep->opmode & START_TRANSMIT) == 0)
1298cc291a4cSgd 		return (0);
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	/*
13017c478bd9Sstevel@tonic-gate 	 * "Send" the setup frame.  If it fails (e.g. no resources),
13027c478bd9Sstevel@tonic-gate 	 * set a flag; then the factotum will retry the "send".  Once
13037c478bd9Sstevel@tonic-gate 	 * it works, we can clear the flag no matter how many attempts
13047c478bd9Sstevel@tonic-gate 	 * had previously failed.  We tell the caller that it worked
13057c478bd9Sstevel@tonic-gate 	 * whether it did or not; after all, it *will* work eventually.
13067c478bd9Sstevel@tonic-gate 	 */
1307cc291a4cSgd 	status = dmfe_send_msg(dmfep, NULL);
1308cc291a4cSgd 	dmfep->need_setup = status ? B_FALSE : B_TRUE;
1309cc291a4cSgd 	return (0);
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate /*
1313cc291a4cSgd  *	dmfe_m_unicst() -- set the physical network address
13147c478bd9Sstevel@tonic-gate  */
13157c478bd9Sstevel@tonic-gate static int
dmfe_m_unicst(void * arg,const uint8_t * macaddr)1316cc291a4cSgd dmfe_m_unicst(void *arg, const uint8_t *macaddr)
13177c478bd9Sstevel@tonic-gate {
1318cc291a4cSgd 	dmfe_t *dmfep = arg;
13197c478bd9Sstevel@tonic-gate 	int status;
13207c478bd9Sstevel@tonic-gate 	int index;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	/*
13237c478bd9Sstevel@tonic-gate 	 * Update our current address and send out a new setup packet
13247c478bd9Sstevel@tonic-gate 	 *
13257c478bd9Sstevel@tonic-gate 	 * Here we accommodate the use of HASH_ONLY or HASH_AND_PERFECT
13267c478bd9Sstevel@tonic-gate 	 * filtering modes (we don't support PERFECT_ONLY or INVERSE modes).
13277c478bd9Sstevel@tonic-gate 	 *
13287c478bd9Sstevel@tonic-gate 	 * It is said that there is a bug in the 21140 where it fails to
13297c478bd9Sstevel@tonic-gate 	 * receive packes addresses to the specified perfect filter address.
13307c478bd9Sstevel@tonic-gate 	 * If the same bug is present in the DM9102A, the TX_FILTER_TYPE1
13317c478bd9Sstevel@tonic-gate 	 * bit should be set in the module variable dmfe_setup_desc1.
13327c478bd9Sstevel@tonic-gate 	 *
13337c478bd9Sstevel@tonic-gate 	 * If TX_FILTER_TYPE1 is set, we will use HASH_ONLY filtering.
13347c478bd9Sstevel@tonic-gate 	 * In this mode, *all* incoming addresses are hashed and looked
13357c478bd9Sstevel@tonic-gate 	 * up in the bitmap described by the setup packet.  Therefore,
13367c478bd9Sstevel@tonic-gate 	 * the bit representing the station address has to be added to
13377c478bd9Sstevel@tonic-gate 	 * the table before sending it out.  If the address is changed,
13387c478bd9Sstevel@tonic-gate 	 * the old entry should be removed before the new entry is made.
13397c478bd9Sstevel@tonic-gate 	 *
13407c478bd9Sstevel@tonic-gate 	 * NOTE: in this mode, unicast packets that are not intended for
13417c478bd9Sstevel@tonic-gate 	 * this station may be received; it is up to software to filter
13427c478bd9Sstevel@tonic-gate 	 * them out afterwards!
13437c478bd9Sstevel@tonic-gate 	 *
13447c478bd9Sstevel@tonic-gate 	 * If TX_FILTER_TYPE1 is *not* set, we will use HASH_AND_PERFECT
13457c478bd9Sstevel@tonic-gate 	 * filtering.  In this mode, multicast addresses are hashed and
13467c478bd9Sstevel@tonic-gate 	 * checked against the bitmap, while unicast addresses are simply
13477c478bd9Sstevel@tonic-gate 	 * matched against the one physical address specified in the setup
13487c478bd9Sstevel@tonic-gate 	 * packet.  This means that we shouldn't receive unicast packets
13497c478bd9Sstevel@tonic-gate 	 * that aren't intended for us (but software still has to filter
13507c478bd9Sstevel@tonic-gate 	 * multicast packets just the same).
13517c478bd9Sstevel@tonic-gate 	 *
13527c478bd9Sstevel@tonic-gate 	 * Whichever mode we're using, we have to enter the broadcast
13537c478bd9Sstevel@tonic-gate 	 * address into the multicast filter map too, so we do this on
13547c478bd9Sstevel@tonic-gate 	 * the first time through after attach or reset.
13557c478bd9Sstevel@tonic-gate 	 */
13567c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	if (dmfep->addr_set && dmfe_setup_desc1 & TX_FILTER_TYPE1)
1359cc291a4cSgd 		(void) dmfe_update_mcast(dmfep, dmfep->curr_addr, B_FALSE);
13607c478bd9Sstevel@tonic-gate 	if (dmfe_setup_desc1 & TX_FILTER_TYPE1)
1361cc291a4cSgd 		(void) dmfe_update_mcast(dmfep, macaddr, B_TRUE);
13627c478bd9Sstevel@tonic-gate 	if (!dmfep->addr_set)
1363cc291a4cSgd 		(void) dmfe_update_mcast(dmfep, dmfe_broadcast_addr, B_TRUE);
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	/*
13667c478bd9Sstevel@tonic-gate 	 * Remember the new current address
13677c478bd9Sstevel@tonic-gate 	 */
13687c478bd9Sstevel@tonic-gate 	ethaddr_copy(macaddr, dmfep->curr_addr);
13697c478bd9Sstevel@tonic-gate 	dmfep->addr_set = B_TRUE;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	/*
13727c478bd9Sstevel@tonic-gate 	 * Install the new physical address into the proper position in
13737c478bd9Sstevel@tonic-gate 	 * the setup frame; this is only used if we select hash+perfect
13747c478bd9Sstevel@tonic-gate 	 * filtering, but we'll put it in anyway.  The ugliness here is
13757c478bd9Sstevel@tonic-gate 	 * down to the usual war of the egg :(
13767c478bd9Sstevel@tonic-gate 	 */
13777c478bd9Sstevel@tonic-gate 	for (index = 0; index < ETHERADDRL; index += 2)
13787c478bd9Sstevel@tonic-gate 		dmfe_setup_put32(&dmfep->tx_desc, SETUPBUF_PHYS+index/2,
1379dd4eeefdSeota 		    (macaddr[index+1] << 8) | macaddr[index]);
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	/*
13827c478bd9Sstevel@tonic-gate 	 * Finally, we're ready to "transmit" the setup frame
13837c478bd9Sstevel@tonic-gate 	 */
13847c478bd9Sstevel@tonic-gate 	status = dmfe_send_setup(dmfep);
13857c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	return (status);
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate /*
1391cc291a4cSgd  *	dmfe_m_multicst() -- enable or disable a multicast address
13927c478bd9Sstevel@tonic-gate  *
13937c478bd9Sstevel@tonic-gate  *	Program the hardware to enable/disable the multicast address
1394cc291a4cSgd  *	in "mca" (enable if add is true, otherwise disable it.)
13957c478bd9Sstevel@tonic-gate  *	We keep a refcount for each bit in the map, so that it still
13967c478bd9Sstevel@tonic-gate  *	works out properly if multiple addresses hash to the same bit.
13977c478bd9Sstevel@tonic-gate  *	dmfe_update_mcast() tells us whether the map actually changed;
13987c478bd9Sstevel@tonic-gate  *	if so, we have to re-"transmit" the magic setup packet.
13997c478bd9Sstevel@tonic-gate  */
14007c478bd9Sstevel@tonic-gate static int
dmfe_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1401cc291a4cSgd dmfe_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
14027c478bd9Sstevel@tonic-gate {
1403cc291a4cSgd 	dmfe_t *dmfep = arg;			/* private device info	*/
1404cc291a4cSgd 	int status = 0;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
1407cc291a4cSgd 	if (dmfe_update_mcast(dmfep, mca, add))
14087c478bd9Sstevel@tonic-gate 		status = dmfe_send_setup(dmfep);
14097c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	return (status);
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate /*
14167c478bd9Sstevel@tonic-gate  * ========== Internal state management entry points ==========
14177c478bd9Sstevel@tonic-gate  */
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate /*
14207c478bd9Sstevel@tonic-gate  * These routines provide all the functionality required by the
1421cc291a4cSgd  * corresponding MAC layer entry points, but don't update the MAC layer state
14227c478bd9Sstevel@tonic-gate  * so they can be called internally without disturbing our record
1423cc291a4cSgd  * of what MAC layer thinks we should be doing ...
14247c478bd9Sstevel@tonic-gate  */
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate /*
14277c478bd9Sstevel@tonic-gate  *	dmfe_stop() -- stop processing, don't reset h/w or rings
14287c478bd9Sstevel@tonic-gate  */
14297c478bd9Sstevel@tonic-gate static void
dmfe_stop(dmfe_t * dmfep)14307c478bd9Sstevel@tonic-gate dmfe_stop(dmfe_t *dmfep)
14317c478bd9Sstevel@tonic-gate {
14327c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	dmfe_stop_chip(dmfep, CHIP_STOPPED);
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate /*
14387c478bd9Sstevel@tonic-gate  *	dmfe_reset() -- stop processing, reset h/w & rings to initial state
14397c478bd9Sstevel@tonic-gate  */
14407c478bd9Sstevel@tonic-gate static void
dmfe_reset(dmfe_t * dmfep)14417c478bd9Sstevel@tonic-gate dmfe_reset(dmfe_t *dmfep)
14427c478bd9Sstevel@tonic-gate {
14437c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
14447c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->rxlock));
14457c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->txlock));
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	dmfe_stop_chip(dmfep, CHIP_RESET);
14487c478bd9Sstevel@tonic-gate 	dmfe_init_rings(dmfep);
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate /*
14527c478bd9Sstevel@tonic-gate  *	dmfe_start() -- start transmitting/receiving
14537c478bd9Sstevel@tonic-gate  */
14547c478bd9Sstevel@tonic-gate static void
dmfe_start(dmfe_t * dmfep)14557c478bd9Sstevel@tonic-gate dmfe_start(dmfe_t *dmfep)
14567c478bd9Sstevel@tonic-gate {
14577c478bd9Sstevel@tonic-gate 	uint32_t gpsr;
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	ASSERT(dmfep->chip_state == CHIP_RESET ||
1462dd4eeefdSeota 	    dmfep->chip_state == CHIP_STOPPED);
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	/*
14657c478bd9Sstevel@tonic-gate 	 * Make opmode consistent with PHY duplex setting
14667c478bd9Sstevel@tonic-gate 	 */
14677c478bd9Sstevel@tonic-gate 	gpsr = dmfe_chip_get32(dmfep, PHY_STATUS_REG);
14687c478bd9Sstevel@tonic-gate 	if (gpsr & GPS_FULL_DUPLEX)
14697c478bd9Sstevel@tonic-gate 		dmfep->opmode |= FULL_DUPLEX;
14707c478bd9Sstevel@tonic-gate 	else
14717c478bd9Sstevel@tonic-gate 		dmfep->opmode &= ~FULL_DUPLEX;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	/*
14747c478bd9Sstevel@tonic-gate 	 * Start transmit processing
14757c478bd9Sstevel@tonic-gate 	 * Set up the address filters
14767c478bd9Sstevel@tonic-gate 	 * Start receive processing
14777c478bd9Sstevel@tonic-gate 	 * Enable interrupts
14787c478bd9Sstevel@tonic-gate 	 */
14797c478bd9Sstevel@tonic-gate 	dmfe_start_chip(dmfep, START_TRANSMIT);
14807c478bd9Sstevel@tonic-gate 	(void) dmfe_send_setup(dmfep);
14817c478bd9Sstevel@tonic-gate 	drv_usecwait(10);
14827c478bd9Sstevel@tonic-gate 	dmfe_start_chip(dmfep, START_RECEIVE);
14837c478bd9Sstevel@tonic-gate 	dmfe_enable_interrupts(dmfep);
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate /*
14877c478bd9Sstevel@tonic-gate  * dmfe_restart - restart transmitting/receiving after error or suspend
14887c478bd9Sstevel@tonic-gate  */
14897c478bd9Sstevel@tonic-gate static void
dmfe_restart(dmfe_t * dmfep)14907c478bd9Sstevel@tonic-gate dmfe_restart(dmfe_t *dmfep)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	/*
14957c478bd9Sstevel@tonic-gate 	 * You need not only <oplock>, but also <rxlock> AND <txlock>
14967c478bd9Sstevel@tonic-gate 	 * in order to reset the rings, but then <txlock> *mustn't*
14977c478bd9Sstevel@tonic-gate 	 * be held across the call to dmfe_start()
14987c478bd9Sstevel@tonic-gate 	 */
14997c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->rxlock);
15007c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->txlock);
15017c478bd9Sstevel@tonic-gate 	dmfe_reset(dmfep);
15027c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->txlock);
15037c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->rxlock);
1504bdb9230aSGarrett D'Amore 	if (dmfep->mac_state == DMFE_MAC_STARTED) {
15057c478bd9Sstevel@tonic-gate 		dmfe_start(dmfep);
1506bdb9230aSGarrett D'Amore 	}
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate /*
1511cc291a4cSgd  * ========== MAC-required management entry points ==========
15127c478bd9Sstevel@tonic-gate  */
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate /*
1515cc291a4cSgd  *	dmfe_m_stop() -- stop transmitting/receiving
15167c478bd9Sstevel@tonic-gate  */
1517cc291a4cSgd static void
dmfe_m_stop(void * arg)1518cc291a4cSgd dmfe_m_stop(void *arg)
15197c478bd9Sstevel@tonic-gate {
1520cc291a4cSgd 	dmfe_t *dmfep = arg;			/* private device info	*/
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	/*
1523cc291a4cSgd 	 * Just stop processing, then record new MAC state
15247c478bd9Sstevel@tonic-gate 	 */
1525bdb9230aSGarrett D'Amore 	mii_stop(dmfep->mii);
1526bdb9230aSGarrett D'Amore 
15277c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
1528bdb9230aSGarrett D'Amore 	if (!dmfep->suspended)
1529bdb9230aSGarrett D'Amore 		dmfe_stop(dmfep);
1530cc291a4cSgd 	dmfep->mac_state = DMFE_MAC_STOPPED;
15317c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
15327c478bd9Sstevel@tonic-gate }
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate /*
1535cc291a4cSgd  *	dmfe_m_start() -- start transmitting/receiving
15367c478bd9Sstevel@tonic-gate  */
15377c478bd9Sstevel@tonic-gate static int
dmfe_m_start(void * arg)1538cc291a4cSgd dmfe_m_start(void *arg)
15397c478bd9Sstevel@tonic-gate {
1540cc291a4cSgd 	dmfe_t *dmfep = arg;			/* private device info	*/
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	/*
1543cc291a4cSgd 	 * Start processing and record new MAC state
15447c478bd9Sstevel@tonic-gate 	 */
15457c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
1546bdb9230aSGarrett D'Amore 	if (!dmfep->suspended)
1547bdb9230aSGarrett D'Amore 		dmfe_start(dmfep);
1548cc291a4cSgd 	dmfep->mac_state = DMFE_MAC_STARTED;
15497c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
15507c478bd9Sstevel@tonic-gate 
1551bdb9230aSGarrett D'Amore 	mii_start(dmfep->mii);
1552bdb9230aSGarrett D'Amore 
15537c478bd9Sstevel@tonic-gate 	return (0);
15547c478bd9Sstevel@tonic-gate }
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate /*
1557cc291a4cSgd  * dmfe_m_promisc() -- set or reset promiscuous mode on the board
15587c478bd9Sstevel@tonic-gate  *
15597c478bd9Sstevel@tonic-gate  *	Program the hardware to enable/disable promiscuous and/or
15607c478bd9Sstevel@tonic-gate  *	receive-all-multicast modes.  Davicom don't document this
15617c478bd9Sstevel@tonic-gate  *	clearly, but it looks like we can do this on-the-fly (i.e.
15627c478bd9Sstevel@tonic-gate  *	without stopping & restarting the TX/RX processes).
15637c478bd9Sstevel@tonic-gate  */
15647c478bd9Sstevel@tonic-gate static int
dmfe_m_promisc(void * arg,boolean_t on)1565cc291a4cSgd dmfe_m_promisc(void *arg, boolean_t on)
15667c478bd9Sstevel@tonic-gate {
1567cc291a4cSgd 	dmfe_t *dmfep = arg;
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
15707c478bd9Sstevel@tonic-gate 	dmfep->opmode &= ~(PROMISC_MODE | PASS_MULTICAST);
1571cc291a4cSgd 	if (on)
1572cc291a4cSgd 		dmfep->opmode |= PROMISC_MODE;
1573bdb9230aSGarrett D'Amore 	if (!dmfep->suspended)
1574bdb9230aSGarrett D'Amore 		dmfe_set_opmode(dmfep);
15757c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
15767c478bd9Sstevel@tonic-gate 
1577cc291a4cSgd 	return (0);
1578cc291a4cSgd }
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate  * ========== Factotum, implemented as a softint handler ==========
15827c478bd9Sstevel@tonic-gate  */
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate /*
15857c478bd9Sstevel@tonic-gate  * The factotum is woken up when there's something to do that we'd rather
15867c478bd9Sstevel@tonic-gate  * not do from inside a (high-level?) hardware interrupt handler.  Its
15877c478bd9Sstevel@tonic-gate  * two main tasks are:
15887c478bd9Sstevel@tonic-gate  *	reset & restart the chip after an error
15897c478bd9Sstevel@tonic-gate  *	update & restart the chip after a link status change
15907c478bd9Sstevel@tonic-gate  */
15917c478bd9Sstevel@tonic-gate static uint_t
dmfe_factotum(caddr_t arg)15927c478bd9Sstevel@tonic-gate dmfe_factotum(caddr_t arg)
15937c478bd9Sstevel@tonic-gate {
15947c478bd9Sstevel@tonic-gate 	dmfe_t *dmfep;
15957c478bd9Sstevel@tonic-gate 
159622eb7cb5Sgd 	dmfep = (void *)arg;
15977c478bd9Sstevel@tonic-gate 	ASSERT(dmfep->dmfe_guard == DMFE_GUARD);
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
1600bdb9230aSGarrett D'Amore 	if (dmfep->suspended) {
1601bdb9230aSGarrett D'Amore 		mutex_exit(dmfep->oplock);
1602bdb9230aSGarrett D'Amore 		return (DDI_INTR_CLAIMED);
1603bdb9230aSGarrett D'Amore 	}
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	dmfep->factotum_flag = 0;
16067c478bd9Sstevel@tonic-gate 	DRV_KS_INC(dmfep, KS_FACTOTUM_RUN);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	/*
16097c478bd9Sstevel@tonic-gate 	 * Check for chip error ...
16107c478bd9Sstevel@tonic-gate 	 */
16117c478bd9Sstevel@tonic-gate 	if (dmfep->chip_state == CHIP_ERROR) {
16127c478bd9Sstevel@tonic-gate 		/*
16137c478bd9Sstevel@tonic-gate 		 * Error recovery required: reset the chip and the rings,
16147c478bd9Sstevel@tonic-gate 		 * then, if it's supposed to be running, kick it off again.
16157c478bd9Sstevel@tonic-gate 		 */
16167c478bd9Sstevel@tonic-gate 		DRV_KS_INC(dmfep, KS_RECOVERY);
16177c478bd9Sstevel@tonic-gate 		dmfe_restart(dmfep);
1618bdb9230aSGarrett D'Amore 		mutex_exit(dmfep->oplock);
1619bdb9230aSGarrett D'Amore 
1620bdb9230aSGarrett D'Amore 		mii_reset(dmfep->mii);
1621bdb9230aSGarrett D'Amore 
16227c478bd9Sstevel@tonic-gate 	} else if (dmfep->need_setup) {
16237c478bd9Sstevel@tonic-gate 		(void) dmfe_send_setup(dmfep);
16247c478bd9Sstevel@tonic-gate 		mutex_exit(dmfep->oplock);
16257c478bd9Sstevel@tonic-gate 	}
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
16287c478bd9Sstevel@tonic-gate }
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate static void
dmfe_wake_factotum(dmfe_t * dmfep,int ks_id,const char * why)16317c478bd9Sstevel@tonic-gate dmfe_wake_factotum(dmfe_t *dmfep, int ks_id, const char *why)
16327c478bd9Sstevel@tonic-gate {
1633bdb9230aSGarrett D'Amore 	_NOTE(ARGUNUSED(why));
16347c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
16357c478bd9Sstevel@tonic-gate 	DRV_KS_INC(dmfep, ks_id);
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	if (dmfep->factotum_flag++ == 0)
16387c478bd9Sstevel@tonic-gate 		ddi_trigger_softintr(dmfep->factotum_id);
16397c478bd9Sstevel@tonic-gate }
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate /*
16437c478bd9Sstevel@tonic-gate  * ========== Periodic Tasks (Cyclic handler & friends) ==========
16447c478bd9Sstevel@tonic-gate  */
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate /*
16477c478bd9Sstevel@tonic-gate  * Periodic tick tasks, run from the cyclic handler
16487c478bd9Sstevel@tonic-gate  *
16497c478bd9Sstevel@tonic-gate  * Check for TX stall; flag an error and wake the factotum if so.
16507c478bd9Sstevel@tonic-gate  */
16517c478bd9Sstevel@tonic-gate static void
dmfe_tick_stall_check(dmfe_t * dmfep,uint32_t gpsr,uint32_t istat)16527c478bd9Sstevel@tonic-gate dmfe_tick_stall_check(dmfe_t *dmfep, uint32_t gpsr, uint32_t istat)
16537c478bd9Sstevel@tonic-gate {
16547c478bd9Sstevel@tonic-gate 	boolean_t tx_stall;
16557c478bd9Sstevel@tonic-gate 	uint32_t tx_state;
16567c478bd9Sstevel@tonic-gate 	uint32_t limit;
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(dmfep->oplock));
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	/*
16617c478bd9Sstevel@tonic-gate 	 * Check for transmit stall ...
16627c478bd9Sstevel@tonic-gate 	 *
16637c478bd9Sstevel@tonic-gate 	 * IF there's at least one packet in the ring, AND the timeout
16647c478bd9Sstevel@tonic-gate 	 * has elapsed, AND we can't reclaim any descriptors, THEN we've
16657c478bd9Sstevel@tonic-gate 	 * stalled; we return B_TRUE to trigger a reset-and-recover cycle.
16667c478bd9Sstevel@tonic-gate 	 *
16677c478bd9Sstevel@tonic-gate 	 * Note that the timeout limit is based on the transmit engine
16687c478bd9Sstevel@tonic-gate 	 * state; we allow the transmitter longer to make progress in
16697c478bd9Sstevel@tonic-gate 	 * some states than in others, based on observations of this
16707c478bd9Sstevel@tonic-gate 	 * chip's actual behaviour in the lab.
16717c478bd9Sstevel@tonic-gate 	 *
16727c478bd9Sstevel@tonic-gate 	 * By observation, we find that on about 1 in 10000 passes through
16737c478bd9Sstevel@tonic-gate 	 * here, the TX lock is already held.  In that case, we'll skip
16747c478bd9Sstevel@tonic-gate 	 * the check on this pass rather than wait.  Most likely, the send
16757c478bd9Sstevel@tonic-gate 	 * routine was holding the lock when the interrupt happened, and
16767c478bd9Sstevel@tonic-gate 	 * we'll succeed next time through.  In the event of a real stall,
16777c478bd9Sstevel@tonic-gate 	 * the TX ring will fill up, after which the send routine won't be
16787c478bd9Sstevel@tonic-gate 	 * called any more and then we're sure to get in.
16797c478bd9Sstevel@tonic-gate 	 */
16807c478bd9Sstevel@tonic-gate 	tx_stall = B_FALSE;
16817c478bd9Sstevel@tonic-gate 	if (mutex_tryenter(dmfep->txlock)) {
16827c478bd9Sstevel@tonic-gate 		if (dmfep->tx.n_free < dmfep->tx.n_desc) {
16837c478bd9Sstevel@tonic-gate 			tx_state = TX_PROCESS_STATE(istat);
16847c478bd9Sstevel@tonic-gate 			if (gpsr & GPS_LINK_100)
16857c478bd9Sstevel@tonic-gate 				limit = stall_100_tix[tx_state];
16867c478bd9Sstevel@tonic-gate 			else
16877c478bd9Sstevel@tonic-gate 				limit = stall_10_tix[tx_state];
16887c478bd9Sstevel@tonic-gate 			if (++dmfep->tx_pending_tix >= limit &&
16897c478bd9Sstevel@tonic-gate 			    dmfe_reclaim_tx_desc(dmfep) == B_FALSE) {
16907c478bd9Sstevel@tonic-gate 				dmfe_log(dmfep, "TX stall detected "
16917c478bd9Sstevel@tonic-gate 				    "after %d ticks in state %d; "
16927c478bd9Sstevel@tonic-gate 				    "automatic recovery initiated",
1693dd4eeefdSeota 				    dmfep->tx_pending_tix, tx_state);
16947c478bd9Sstevel@tonic-gate 				tx_stall = B_TRUE;
16957c478bd9Sstevel@tonic-gate 			}
16967c478bd9Sstevel@tonic-gate 		}
16977c478bd9Sstevel@tonic-gate 		mutex_exit(dmfep->txlock);
16987c478bd9Sstevel@tonic-gate 	}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	if (tx_stall) {
17017c478bd9Sstevel@tonic-gate 		dmfe_stop_chip(dmfep, CHIP_ERROR);
17027c478bd9Sstevel@tonic-gate 		dmfe_wake_factotum(dmfep, KS_TX_STALL, "tick (TX stall)");
17037c478bd9Sstevel@tonic-gate 	}
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate /*
17077c478bd9Sstevel@tonic-gate  * Cyclic callback handler
17087c478bd9Sstevel@tonic-gate  */
17097c478bd9Sstevel@tonic-gate static void
dmfe_cyclic(void * arg)17107c478bd9Sstevel@tonic-gate dmfe_cyclic(void *arg)
17117c478bd9Sstevel@tonic-gate {
17127c478bd9Sstevel@tonic-gate 	dmfe_t *dmfep = arg;			/* private device info */
17137c478bd9Sstevel@tonic-gate 	uint32_t istat;
17147c478bd9Sstevel@tonic-gate 	uint32_t gpsr;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	/*
17177c478bd9Sstevel@tonic-gate 	 * If the chip's not RUNNING, there's nothing to do.
17187c478bd9Sstevel@tonic-gate 	 * If we can't get the mutex straight away, we'll just
17197c478bd9Sstevel@tonic-gate 	 * skip this pass; we'll back back soon enough anyway.
17207c478bd9Sstevel@tonic-gate 	 */
17217c478bd9Sstevel@tonic-gate 	if (mutex_tryenter(dmfep->oplock) == 0)
17227c478bd9Sstevel@tonic-gate 		return;
1723bdb9230aSGarrett D'Amore 	if ((dmfep->suspended) || (dmfep->chip_state != CHIP_RUNNING)) {
1724bdb9230aSGarrett D'Amore 		mutex_exit(dmfep->oplock);
1725bdb9230aSGarrett D'Amore 		return;
1726bdb9230aSGarrett D'Amore 	}
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	/*
17297c478bd9Sstevel@tonic-gate 	 * Recheck chip state (it might have been stopped since we
17307c478bd9Sstevel@tonic-gate 	 * checked above).  If still running, call each of the *tick*
17317c478bd9Sstevel@tonic-gate 	 * tasks.  They will check for link change, TX stall, etc ...
17327c478bd9Sstevel@tonic-gate 	 */
17337c478bd9Sstevel@tonic-gate 	if (dmfep->chip_state == CHIP_RUNNING) {
17347c478bd9Sstevel@tonic-gate 		istat = dmfe_chip_get32(dmfep, STATUS_REG);
17357c478bd9Sstevel@tonic-gate 		gpsr = dmfe_chip_get32(dmfep, PHY_STATUS_REG);
17367c478bd9Sstevel@tonic-gate 		dmfe_tick_stall_check(dmfep, gpsr, istat);
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	DRV_KS_INC(dmfep, KS_CYCLIC_RUN);
17407c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate /*
17447c478bd9Sstevel@tonic-gate  * ========== Hardware interrupt handler ==========
17457c478bd9Sstevel@tonic-gate  */
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate /*
17487c478bd9Sstevel@tonic-gate  *	dmfe_interrupt() -- handle chip interrupts
17497c478bd9Sstevel@tonic-gate  */
17507c478bd9Sstevel@tonic-gate static uint_t
dmfe_interrupt(caddr_t arg)17517c478bd9Sstevel@tonic-gate dmfe_interrupt(caddr_t arg)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate 	dmfe_t *dmfep;			/* private device info */
17547c478bd9Sstevel@tonic-gate 	uint32_t interrupts;
17557c478bd9Sstevel@tonic-gate 	uint32_t istat;
17567c478bd9Sstevel@tonic-gate 	const char *msg;
17577c478bd9Sstevel@tonic-gate 	mblk_t *mp;
17587c478bd9Sstevel@tonic-gate 	boolean_t warning_msg = B_TRUE;
17597c478bd9Sstevel@tonic-gate 
176022eb7cb5Sgd 	dmfep = (void *)arg;
17617c478bd9Sstevel@tonic-gate 
1762bdb9230aSGarrett D'Amore 	mutex_enter(dmfep->oplock);
1763bdb9230aSGarrett D'Amore 	if (dmfep->suspended) {
1764bdb9230aSGarrett D'Amore 		mutex_exit(dmfep->oplock);
1765bdb9230aSGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
1766bdb9230aSGarrett D'Amore 	}
1767bdb9230aSGarrett D'Amore 
17687c478bd9Sstevel@tonic-gate 	/*
17697c478bd9Sstevel@tonic-gate 	 * A quick check as to whether the interrupt was from this
17707c478bd9Sstevel@tonic-gate 	 * device, before we even finish setting up all our local
17717c478bd9Sstevel@tonic-gate 	 * variables.  Note that reading the interrupt status register
17727c478bd9Sstevel@tonic-gate 	 * doesn't have any unpleasant side effects such as clearing
17737c478bd9Sstevel@tonic-gate 	 * the bits read, so it's quite OK to re-read it once we have
17747c478bd9Sstevel@tonic-gate 	 * determined that we are going to service this interrupt and
17757c478bd9Sstevel@tonic-gate 	 * grabbed the mutexen.
17767c478bd9Sstevel@tonic-gate 	 */
17777c478bd9Sstevel@tonic-gate 	istat = dmfe_chip_get32(dmfep, STATUS_REG);
1778bdb9230aSGarrett D'Amore 	if ((istat & (NORMAL_SUMMARY_INT | ABNORMAL_SUMMARY_INT)) == 0) {
17797c478bd9Sstevel@tonic-gate 
1780bdb9230aSGarrett D'Amore 		mutex_exit(dmfep->oplock);
1781bdb9230aSGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
17827c478bd9Sstevel@tonic-gate 	}
17837c478bd9Sstevel@tonic-gate 
1784cc291a4cSgd 	DRV_KS_INC(dmfep, KS_INTERRUPT);
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	/*
17877c478bd9Sstevel@tonic-gate 	 * Identify bits that represent enabled interrupts ...
17887c478bd9Sstevel@tonic-gate 	 */
17897c478bd9Sstevel@tonic-gate 	istat |= dmfe_chip_get32(dmfep, STATUS_REG);
17907c478bd9Sstevel@tonic-gate 	interrupts = istat & dmfep->imask;
17917c478bd9Sstevel@tonic-gate 	ASSERT(interrupts != 0);
17927c478bd9Sstevel@tonic-gate 
1793bdb9230aSGarrett D'Amore 	DTRACE_PROBE1(intr, uint32_t, istat);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	/*
17967c478bd9Sstevel@tonic-gate 	 * Check for any interrupts other than TX/RX done.
17977c478bd9Sstevel@tonic-gate 	 * If there are any, they are considered Abnormal
17987c478bd9Sstevel@tonic-gate 	 * and will cause the chip to be reset.
17997c478bd9Sstevel@tonic-gate 	 */
18007c478bd9Sstevel@tonic-gate 	if (interrupts & ~(RX_PKTDONE_INT | TX_PKTDONE_INT)) {
18017c478bd9Sstevel@tonic-gate 		if (istat & ABNORMAL_SUMMARY_INT) {
18027c478bd9Sstevel@tonic-gate 			/*
18037c478bd9Sstevel@tonic-gate 			 * Any Abnormal interrupts will lead to us
18047c478bd9Sstevel@tonic-gate 			 * resetting the chip, so we don't bother
18057c478bd9Sstevel@tonic-gate 			 * to clear each interrupt individually.
18067c478bd9Sstevel@tonic-gate 			 *
18077c478bd9Sstevel@tonic-gate 			 * Our main task here is to identify the problem,
18087c478bd9Sstevel@tonic-gate 			 * by pointing out the most significant unexpected
18097c478bd9Sstevel@tonic-gate 			 * bit.  Additional bits may well be consequences
18107c478bd9Sstevel@tonic-gate 			 * of the first problem, so we consider the possible
18117c478bd9Sstevel@tonic-gate 			 * causes in order of severity.
18127c478bd9Sstevel@tonic-gate 			 */
18137c478bd9Sstevel@tonic-gate 			if (interrupts & SYSTEM_ERR_INT) {
18147c478bd9Sstevel@tonic-gate 				switch (istat & SYSTEM_ERR_BITS) {
18157c478bd9Sstevel@tonic-gate 				case SYSTEM_ERR_M_ABORT:
18167c478bd9Sstevel@tonic-gate 					msg = "Bus Master Abort";
18177c478bd9Sstevel@tonic-gate 					break;
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 				case SYSTEM_ERR_T_ABORT:
18207c478bd9Sstevel@tonic-gate 					msg = "Bus Target Abort";
18217c478bd9Sstevel@tonic-gate 					break;
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 				case SYSTEM_ERR_PARITY:
18247c478bd9Sstevel@tonic-gate 					msg = "Parity Error";
18257c478bd9Sstevel@tonic-gate 					break;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 				default:
18287c478bd9Sstevel@tonic-gate 					msg = "Unknown System Bus Error";
18297c478bd9Sstevel@tonic-gate 					break;
18307c478bd9Sstevel@tonic-gate 				}
18317c478bd9Sstevel@tonic-gate 			} else if (interrupts & RX_STOPPED_INT) {
18327c478bd9Sstevel@tonic-gate 				msg = "RX process stopped";
18337c478bd9Sstevel@tonic-gate 			} else if (interrupts & RX_UNAVAIL_INT) {
18347c478bd9Sstevel@tonic-gate 				msg = "RX buffer unavailable";
18357c478bd9Sstevel@tonic-gate 				warning_msg = B_FALSE;
18367c478bd9Sstevel@tonic-gate 			} else if (interrupts & RX_WATCHDOG_INT) {
18377c478bd9Sstevel@tonic-gate 				msg = "RX watchdog timeout?";
18387c478bd9Sstevel@tonic-gate 			} else if (interrupts & RX_EARLY_INT) {
18397c478bd9Sstevel@tonic-gate 				msg = "RX early interrupt?";
18407c478bd9Sstevel@tonic-gate 			} else if (interrupts & TX_STOPPED_INT) {
18417c478bd9Sstevel@tonic-gate 				msg = "TX process stopped";
18427c478bd9Sstevel@tonic-gate 			} else if (interrupts & TX_JABBER_INT) {
18437c478bd9Sstevel@tonic-gate 				msg = "TX jabber timeout";
18447c478bd9Sstevel@tonic-gate 			} else if (interrupts & TX_UNDERFLOW_INT) {
18457c478bd9Sstevel@tonic-gate 				msg = "TX underflow?";
18467c478bd9Sstevel@tonic-gate 			} else if (interrupts & TX_EARLY_INT) {
18477c478bd9Sstevel@tonic-gate 				msg = "TX early interrupt?";
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 			} else if (interrupts & LINK_STATUS_INT) {
18507c478bd9Sstevel@tonic-gate 				msg = "Link status change?";
18517c478bd9Sstevel@tonic-gate 			} else if (interrupts & GP_TIMER_INT) {
18527c478bd9Sstevel@tonic-gate 				msg = "Timer expired?";
18537c478bd9Sstevel@tonic-gate 			}
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 			if (warning_msg)
18567c478bd9Sstevel@tonic-gate 				dmfe_warning(dmfep, "abnormal interrupt, "
1857dd4eeefdSeota 				    "status 0x%x: %s", istat, msg);
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 			/*
18607c478bd9Sstevel@tonic-gate 			 * We don't want to run the entire reinitialisation
18617c478bd9Sstevel@tonic-gate 			 * code out of this (high-level?) interrupt, so we
18627c478bd9Sstevel@tonic-gate 			 * simply STOP the chip, and wake up the factotum
18637c478bd9Sstevel@tonic-gate 			 * to reinitalise it ...
18647c478bd9Sstevel@tonic-gate 			 */
18657c478bd9Sstevel@tonic-gate 			dmfe_stop_chip(dmfep, CHIP_ERROR);
18667c478bd9Sstevel@tonic-gate 			dmfe_wake_factotum(dmfep, KS_CHIP_ERROR,
18677c478bd9Sstevel@tonic-gate 			    "interrupt (error)");
18687c478bd9Sstevel@tonic-gate 		} else {
18697c478bd9Sstevel@tonic-gate 			/*
18707c478bd9Sstevel@tonic-gate 			 * We shouldn't really get here (it would mean
18717c478bd9Sstevel@tonic-gate 			 * there were some unprocessed enabled bits but
18727c478bd9Sstevel@tonic-gate 			 * they weren't Abnormal?), but we'll check just
18737c478bd9Sstevel@tonic-gate 			 * in case ...
18747c478bd9Sstevel@tonic-gate 			 */
1875bdb9230aSGarrett D'Amore 			DTRACE_PROBE1(intr__unexpected, uint32_t, istat);
18767c478bd9Sstevel@tonic-gate 		}
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/*
18807c478bd9Sstevel@tonic-gate 	 * Acknowledge all the original bits - except in the case of an
18817c478bd9Sstevel@tonic-gate 	 * error, when we leave them unacknowledged so that the recovery
18827c478bd9Sstevel@tonic-gate 	 * code can see what was going on when the problem occurred ...
18837c478bd9Sstevel@tonic-gate 	 */
18847c478bd9Sstevel@tonic-gate 	if (dmfep->chip_state != CHIP_ERROR) {
18857c478bd9Sstevel@tonic-gate 		(void) dmfe_chip_put32(dmfep, STATUS_REG, istat);
18867c478bd9Sstevel@tonic-gate 		/*
18877c478bd9Sstevel@tonic-gate 		 * Read-after-write forces completion on PCI bus.
18887c478bd9Sstevel@tonic-gate 		 *
18897c478bd9Sstevel@tonic-gate 		 */
18907c478bd9Sstevel@tonic-gate 		(void) dmfe_chip_get32(dmfep, STATUS_REG);
18917c478bd9Sstevel@tonic-gate 	}
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	/*
18957c478bd9Sstevel@tonic-gate 	 * We've finished talking to the chip, so we can drop <oplock>
18967c478bd9Sstevel@tonic-gate 	 * before handling the normal interrupts, which only involve
18977c478bd9Sstevel@tonic-gate 	 * manipulation of descriptors ...
18987c478bd9Sstevel@tonic-gate 	 */
18997c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	if (interrupts & RX_PKTDONE_INT)
19027c478bd9Sstevel@tonic-gate 		if ((mp = dmfe_getp(dmfep)) != NULL)
1903cc291a4cSgd 			mac_rx(dmfep->mh, NULL, mp);
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	if (interrupts & TX_PKTDONE_INT) {
19067c478bd9Sstevel@tonic-gate 		/*
19077c478bd9Sstevel@tonic-gate 		 * The only reason for taking this interrupt is to give
1908cc291a4cSgd 		 * MAC a chance to schedule queued packets after a
19097c478bd9Sstevel@tonic-gate 		 * ring-full condition.  To minimise the number of
19107c478bd9Sstevel@tonic-gate 		 * redundant TX-Done interrupts, we only mark two of the
19117c478bd9Sstevel@tonic-gate 		 * ring descriptors as 'interrupt-on-complete' - all the
19127c478bd9Sstevel@tonic-gate 		 * others are simply handed back without an interrupt.
19137c478bd9Sstevel@tonic-gate 		 */
19147c478bd9Sstevel@tonic-gate 		if (dmfe_reclaim_on_done && mutex_tryenter(dmfep->txlock)) {
19157c478bd9Sstevel@tonic-gate 			(void) dmfe_reclaim_tx_desc(dmfep);
19167c478bd9Sstevel@tonic-gate 			mutex_exit(dmfep->txlock);
19177c478bd9Sstevel@tonic-gate 		}
1918cc291a4cSgd 		mac_tx_update(dmfep->mh);
19197c478bd9Sstevel@tonic-gate 	}
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
19227c478bd9Sstevel@tonic-gate }
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate /*
19257c478bd9Sstevel@tonic-gate  * ========== Statistics update handler ==========
19267c478bd9Sstevel@tonic-gate  */
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate static int
dmfe_m_stat(void * arg,uint_t stat,uint64_t * val)1929cc291a4cSgd dmfe_m_stat(void *arg, uint_t stat, uint64_t *val)
19307c478bd9Sstevel@tonic-gate {
1931cc291a4cSgd 	dmfe_t *dmfep = arg;
1932cc291a4cSgd 	int rv = 0;
19337c478bd9Sstevel@tonic-gate 
1934bdb9230aSGarrett D'Amore 	/* Let MII handle its own stats. */
1935bdb9230aSGarrett D'Amore 	if (mii_m_getstat(dmfep->mii, stat, val) == 0) {
1936bdb9230aSGarrett D'Amore 		return (0);
1937bdb9230aSGarrett D'Amore 	}
1938bdb9230aSGarrett D'Amore 
19397c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
19407c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->rxlock);
19417c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->txlock);
19427c478bd9Sstevel@tonic-gate 
1943cc291a4cSgd 	/* make sure we have all the stats collected */
1944cc291a4cSgd 	(void) dmfe_reclaim_tx_desc(dmfep);
1945cc291a4cSgd 
1946cc291a4cSgd 	switch (stat) {
1947cc291a4cSgd 
1948cc291a4cSgd 	case MAC_STAT_IPACKETS:
1949cc291a4cSgd 		*val = dmfep->rx_stats_ipackets;
1950cc291a4cSgd 		break;
1951cc291a4cSgd 
1952cc291a4cSgd 	case MAC_STAT_MULTIRCV:
1953cc291a4cSgd 		*val = dmfep->rx_stats_multi;
1954cc291a4cSgd 		break;
1955cc291a4cSgd 
1956cc291a4cSgd 	case MAC_STAT_BRDCSTRCV:
1957cc291a4cSgd 		*val = dmfep->rx_stats_bcast;
1958cc291a4cSgd 		break;
1959cc291a4cSgd 
1960cc291a4cSgd 	case MAC_STAT_RBYTES:
1961cc291a4cSgd 		*val = dmfep->rx_stats_rbytes;
1962cc291a4cSgd 		break;
1963cc291a4cSgd 
1964cc291a4cSgd 	case MAC_STAT_IERRORS:
1965cc291a4cSgd 		*val = dmfep->rx_stats_ierrors;
1966cc291a4cSgd 		break;
1967cc291a4cSgd 
1968cc291a4cSgd 	case MAC_STAT_NORCVBUF:
1969cc291a4cSgd 		*val = dmfep->rx_stats_norcvbuf;
1970cc291a4cSgd 		break;
1971cc291a4cSgd 
1972cc291a4cSgd 	case MAC_STAT_COLLISIONS:
1973cc291a4cSgd 		*val = dmfep->tx_stats_collisions;
1974cc291a4cSgd 		break;
1975cc291a4cSgd 
1976cc291a4cSgd 	case MAC_STAT_OERRORS:
1977cc291a4cSgd 		*val = dmfep->tx_stats_oerrors;
1978cc291a4cSgd 		break;
1979cc291a4cSgd 
1980cc291a4cSgd 	case MAC_STAT_OPACKETS:
1981cc291a4cSgd 		*val = dmfep->tx_stats_opackets;
1982cc291a4cSgd 		break;
1983cc291a4cSgd 
1984cc291a4cSgd 	case MAC_STAT_MULTIXMT:
1985cc291a4cSgd 		*val = dmfep->tx_stats_multi;
1986cc291a4cSgd 		break;
1987cc291a4cSgd 
1988cc291a4cSgd 	case MAC_STAT_BRDCSTXMT:
1989cc291a4cSgd 		*val = dmfep->tx_stats_bcast;
1990cc291a4cSgd 		break;
1991cc291a4cSgd 
1992cc291a4cSgd 	case MAC_STAT_OBYTES:
1993cc291a4cSgd 		*val = dmfep->tx_stats_obytes;
1994cc291a4cSgd 		break;
1995cc291a4cSgd 
1996cc291a4cSgd 	case MAC_STAT_OVERFLOWS:
1997cc291a4cSgd 		*val = dmfep->rx_stats_overflow;
1998cc291a4cSgd 		break;
1999cc291a4cSgd 
2000cc291a4cSgd 	case MAC_STAT_UNDERFLOWS:
2001cc291a4cSgd 		*val = dmfep->tx_stats_underflow;
2002cc291a4cSgd 		break;
2003cc291a4cSgd 
2004cc291a4cSgd 	case ETHER_STAT_ALIGN_ERRORS:
2005cc291a4cSgd 		*val = dmfep->rx_stats_align;
2006cc291a4cSgd 		break;
2007cc291a4cSgd 
2008cc291a4cSgd 	case ETHER_STAT_FCS_ERRORS:
2009cc291a4cSgd 		*val = dmfep->rx_stats_fcs;
2010cc291a4cSgd 		break;
2011cc291a4cSgd 
2012cc291a4cSgd 	case ETHER_STAT_TOOLONG_ERRORS:
2013cc291a4cSgd 		*val = dmfep->rx_stats_toolong;
2014cc291a4cSgd 		break;
2015cc291a4cSgd 
2016cc291a4cSgd 	case ETHER_STAT_TOOSHORT_ERRORS:
2017cc291a4cSgd 		*val = dmfep->rx_stats_short;
2018cc291a4cSgd 		break;
2019cc291a4cSgd 
2020cc291a4cSgd 	case ETHER_STAT_MACRCV_ERRORS:
2021cc291a4cSgd 		*val = dmfep->rx_stats_macrcv_errors;
2022cc291a4cSgd 		break;
2023cc291a4cSgd 
2024cc291a4cSgd 	case ETHER_STAT_MACXMT_ERRORS:
2025cc291a4cSgd 		*val = dmfep->tx_stats_macxmt_errors;
2026cc291a4cSgd 		break;
2027cc291a4cSgd 
20280d2a8e5eSgd 	case ETHER_STAT_JABBER_ERRORS:
20290d2a8e5eSgd 		*val = dmfep->tx_stats_jabber;
20300d2a8e5eSgd 		break;
20310d2a8e5eSgd 
2032cc291a4cSgd 	case ETHER_STAT_CARRIER_ERRORS:
2033cc291a4cSgd 		*val = dmfep->tx_stats_nocarrier;
2034cc291a4cSgd 		break;
2035cc291a4cSgd 
2036cc291a4cSgd 	case ETHER_STAT_TX_LATE_COLLISIONS:
2037cc291a4cSgd 		*val = dmfep->tx_stats_xmtlatecoll;
2038cc291a4cSgd 		break;
2039cc291a4cSgd 
2040cc291a4cSgd 	case ETHER_STAT_EX_COLLISIONS:
2041cc291a4cSgd 		*val = dmfep->tx_stats_excoll;
2042cc291a4cSgd 		break;
2043cc291a4cSgd 
2044cc291a4cSgd 	case ETHER_STAT_DEFER_XMTS:
2045cc291a4cSgd 		*val = dmfep->tx_stats_defer;
2046cc291a4cSgd 		break;
2047cc291a4cSgd 
2048cc291a4cSgd 	case ETHER_STAT_FIRST_COLLISIONS:
2049cc291a4cSgd 		*val = dmfep->tx_stats_first_coll;
2050cc291a4cSgd 		break;
2051cc291a4cSgd 
2052cc291a4cSgd 	case ETHER_STAT_MULTI_COLLISIONS:
2053cc291a4cSgd 		*val = dmfep->tx_stats_multi_coll;
2054cc291a4cSgd 		break;
2055cc291a4cSgd 
2056cc291a4cSgd 	default:
2057cc291a4cSgd 		rv = ENOTSUP;
2058cc291a4cSgd 	}
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->txlock);
20617c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->rxlock);
20627c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
20637c478bd9Sstevel@tonic-gate 
2064cc291a4cSgd 	return (rv);
20657c478bd9Sstevel@tonic-gate }
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate /*
20687c478bd9Sstevel@tonic-gate  * ========== Ioctl handler & subfunctions ==========
20697c478bd9Sstevel@tonic-gate  */
20707c478bd9Sstevel@tonic-gate 
2071bdb9230aSGarrett D'Amore static lb_property_t dmfe_loopmodes[] = {
2072bdb9230aSGarrett D'Amore 	{ normal,	"normal",	0 },
2073bdb9230aSGarrett D'Amore 	{ internal,	"Internal",	1 },
2074bdb9230aSGarrett D'Amore 	{ external,	"External",	2 },
2075bdb9230aSGarrett D'Amore };
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate /*
2078cc291a4cSgd  * Specific dmfe IOCTLs, the mac module handles the generic ones.
2079bdb9230aSGarrett D'Amore  * Unfortunately, the DM9102 doesn't seem to work well with MII based
2080bdb9230aSGarrett D'Amore  * loopback, so we have to do something special for it.
20817c478bd9Sstevel@tonic-gate  */
2082bdb9230aSGarrett D'Amore 
2083cc291a4cSgd static void
dmfe_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)2084cc291a4cSgd dmfe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
20857c478bd9Sstevel@tonic-gate {
2086bdb9230aSGarrett D'Amore 	dmfe_t		*dmfep = arg;
2087bdb9230aSGarrett D'Amore 	struct iocblk	*iocp;
2088bdb9230aSGarrett D'Amore 	int		rv = 0;
2089bdb9230aSGarrett D'Amore 	lb_info_sz_t	sz;
2090bdb9230aSGarrett D'Amore 	int		cmd;
2091bdb9230aSGarrett D'Amore 	uint32_t	mode;
20927c478bd9Sstevel@tonic-gate 
209322eb7cb5Sgd 	iocp = (void *)mp->b_rptr;
20947c478bd9Sstevel@tonic-gate 	cmd = iocp->ioc_cmd;
2095bdb9230aSGarrett D'Amore 
2096bdb9230aSGarrett D'Amore 	if (mp->b_cont == NULL) {
2097bdb9230aSGarrett D'Amore 		/*
2098bdb9230aSGarrett D'Amore 		 * All of these ioctls need data!
2099bdb9230aSGarrett D'Amore 		 */
21007c478bd9Sstevel@tonic-gate 		miocnak(wq, mp, 0, EINVAL);
2101cc291a4cSgd 		return;
21027c478bd9Sstevel@tonic-gate 	}
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	switch (cmd) {
2105bdb9230aSGarrett D'Amore 	case LB_GET_INFO_SIZE:
2106bdb9230aSGarrett D'Amore 		if (iocp->ioc_count != sizeof (sz)) {
2107bdb9230aSGarrett D'Amore 			rv = EINVAL;
2108bdb9230aSGarrett D'Amore 		} else {
2109bdb9230aSGarrett D'Amore 			sz = sizeof (dmfe_loopmodes);
2110bdb9230aSGarrett D'Amore 			bcopy(&sz, mp->b_cont->b_rptr, sizeof (sz));
2111bdb9230aSGarrett D'Amore 		}
21127c478bd9Sstevel@tonic-gate 		break;
21137c478bd9Sstevel@tonic-gate 
2114bdb9230aSGarrett D'Amore 	case LB_GET_INFO:
2115bdb9230aSGarrett D'Amore 		if (iocp->ioc_count != sizeof (dmfe_loopmodes)) {
2116bdb9230aSGarrett D'Amore 			rv = EINVAL;
2117bdb9230aSGarrett D'Amore 		} else {
2118bdb9230aSGarrett D'Amore 			bcopy(dmfe_loopmodes, mp->b_cont->b_rptr,
2119bdb9230aSGarrett D'Amore 			    iocp->ioc_count);
2120bdb9230aSGarrett D'Amore 		}
21217c478bd9Sstevel@tonic-gate 		break;
21227c478bd9Sstevel@tonic-gate 
2123bdb9230aSGarrett D'Amore 	case LB_GET_MODE:
2124bdb9230aSGarrett D'Amore 		if (iocp->ioc_count != sizeof (mode)) {
2125bdb9230aSGarrett D'Amore 			rv = EINVAL;
2126bdb9230aSGarrett D'Amore 		} else {
2127bdb9230aSGarrett D'Amore 			mutex_enter(dmfep->oplock);
2128bdb9230aSGarrett D'Amore 			switch (dmfep->opmode & LOOPBACK_MODE_MASK) {
2129bdb9230aSGarrett D'Amore 			case LOOPBACK_OFF:
2130bdb9230aSGarrett D'Amore 				mode = 0;
2131bdb9230aSGarrett D'Amore 				break;
2132bdb9230aSGarrett D'Amore 			case LOOPBACK_INTERNAL:
2133bdb9230aSGarrett D'Amore 				mode = 1;
2134bdb9230aSGarrett D'Amore 				break;
2135bdb9230aSGarrett D'Amore 			default:
2136bdb9230aSGarrett D'Amore 				mode = 2;
2137bdb9230aSGarrett D'Amore 				break;
2138bdb9230aSGarrett D'Amore 			}
2139bdb9230aSGarrett D'Amore 			mutex_exit(dmfep->oplock);
2140bdb9230aSGarrett D'Amore 			bcopy(&mode, mp->b_cont->b_rptr, sizeof (mode));
2141bdb9230aSGarrett D'Amore 		}
21427c478bd9Sstevel@tonic-gate 		break;
21437c478bd9Sstevel@tonic-gate 
2144bdb9230aSGarrett D'Amore 	case LB_SET_MODE:
2145bdb9230aSGarrett D'Amore 		rv = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
2146bdb9230aSGarrett D'Amore 		if (rv != 0)
2147bdb9230aSGarrett D'Amore 			break;
2148bdb9230aSGarrett D'Amore 		if (iocp->ioc_count != sizeof (mode)) {
2149bdb9230aSGarrett D'Amore 			rv = EINVAL;
2150bdb9230aSGarrett D'Amore 			break;
21517c478bd9Sstevel@tonic-gate 		}
2152bdb9230aSGarrett D'Amore 		bcopy(mp->b_cont->b_rptr, &mode, sizeof (mode));
21537c478bd9Sstevel@tonic-gate 
2154bdb9230aSGarrett D'Amore 		mutex_enter(dmfep->oplock);
2155bdb9230aSGarrett D'Amore 		dmfep->opmode &= ~LOOPBACK_MODE_MASK;
2156bdb9230aSGarrett D'Amore 		switch (mode) {
2157bdb9230aSGarrett D'Amore 		case 2:
2158bdb9230aSGarrett D'Amore 			dmfep->opmode |= LOOPBACK_PHY_D;
2159bdb9230aSGarrett D'Amore 			break;
2160bdb9230aSGarrett D'Amore 		case 1:
2161bdb9230aSGarrett D'Amore 			dmfep->opmode |= LOOPBACK_INTERNAL;
2162bdb9230aSGarrett D'Amore 			break;
2163bdb9230aSGarrett D'Amore 		default:
2164bdb9230aSGarrett D'Amore 			break;
2165bdb9230aSGarrett D'Amore 		}
2166bdb9230aSGarrett D'Amore 		if (!dmfep->suspended) {
2167bdb9230aSGarrett D'Amore 			dmfe_restart(dmfep);
2168bdb9230aSGarrett D'Amore 		}
2169bdb9230aSGarrett D'Amore 		mutex_exit(dmfep->oplock);
21707c478bd9Sstevel@tonic-gate 		break;
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	default:
2173bdb9230aSGarrett D'Amore 		rv = EINVAL;
21747c478bd9Sstevel@tonic-gate 		break;
2175bdb9230aSGarrett D'Amore 	}
21767c478bd9Sstevel@tonic-gate 
2177bdb9230aSGarrett D'Amore 	if (rv == 0) {
2178bdb9230aSGarrett D'Amore 		miocack(wq, mp, iocp->ioc_count, 0);
2179bdb9230aSGarrett D'Amore 	} else {
2180bdb9230aSGarrett D'Amore 		miocnak(wq, mp, 0, rv);
2181bdb9230aSGarrett D'Amore 	}
2182bdb9230aSGarrett D'Amore }
21837c478bd9Sstevel@tonic-gate 
2184bdb9230aSGarrett D'Amore int
dmfe_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)2185*0dc2366fSVenugopal Iyer dmfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
2186*0dc2366fSVenugopal Iyer     void *val)
2187bdb9230aSGarrett D'Amore {
2188bdb9230aSGarrett D'Amore 	dmfe_t		*dmfep = arg;
21897c478bd9Sstevel@tonic-gate 
2190*0dc2366fSVenugopal Iyer 	return (mii_m_getprop(dmfep->mii, name, num, sz, val));
21917c478bd9Sstevel@tonic-gate }
21927c478bd9Sstevel@tonic-gate 
2193bdb9230aSGarrett D'Amore int
dmfe_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)2194bdb9230aSGarrett D'Amore dmfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
2195bdb9230aSGarrett D'Amore     const void *val)
2196bdb9230aSGarrett D'Amore {
2197bdb9230aSGarrett D'Amore 	dmfe_t		*dmfep = arg;
2198bdb9230aSGarrett D'Amore 
2199bdb9230aSGarrett D'Amore 	return (mii_m_setprop(dmfep->mii, name, num, sz, val));
2200bdb9230aSGarrett D'Amore }
22017c478bd9Sstevel@tonic-gate 
2202*0dc2366fSVenugopal Iyer static void
dmfe_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t mph)2203*0dc2366fSVenugopal Iyer dmfe_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
2204*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t mph)
2205*0dc2366fSVenugopal Iyer {
2206*0dc2366fSVenugopal Iyer 	dmfe_t		*dmfep = arg;
2207*0dc2366fSVenugopal Iyer 
2208*0dc2366fSVenugopal Iyer 	mii_m_propinfo(dmfep->mii, name, num, mph);
2209*0dc2366fSVenugopal Iyer }
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate /*
22127c478bd9Sstevel@tonic-gate  * ========== Per-instance setup/teardown code ==========
22137c478bd9Sstevel@tonic-gate  */
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate /*
22167c478bd9Sstevel@tonic-gate  * Determine local MAC address & broadcast address for this interface
22177c478bd9Sstevel@tonic-gate  */
22187c478bd9Sstevel@tonic-gate static void
dmfe_find_mac_address(dmfe_t * dmfep)22197c478bd9Sstevel@tonic-gate dmfe_find_mac_address(dmfe_t *dmfep)
22207c478bd9Sstevel@tonic-gate {
22217c478bd9Sstevel@tonic-gate 	uchar_t *prop;
22227c478bd9Sstevel@tonic-gate 	uint_t propsize;
22237c478bd9Sstevel@tonic-gate 	int err;
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	/*
22267c478bd9Sstevel@tonic-gate 	 * We have to find the "vendor's factory-set address".  This is
22277c478bd9Sstevel@tonic-gate 	 * the value of the property "local-mac-address", as set by OBP
22287c478bd9Sstevel@tonic-gate 	 * (or a .conf file!)
22295c1d0199Sgd 	 *
22305c1d0199Sgd 	 * If the property is not there, then we try to find the factory
22315c1d0199Sgd 	 * mac address from the devices serial EEPROM.
22327c478bd9Sstevel@tonic-gate 	 */
2233cc291a4cSgd 	bzero(dmfep->curr_addr, sizeof (dmfep->curr_addr));
22347c478bd9Sstevel@tonic-gate 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dmfep->devinfo,
2235dd4eeefdSeota 	    DDI_PROP_DONTPASS, localmac_propname, &prop, &propsize);
22367c478bd9Sstevel@tonic-gate 	if (err == DDI_PROP_SUCCESS) {
22377c478bd9Sstevel@tonic-gate 		if (propsize == ETHERADDRL)
2238cc291a4cSgd 			ethaddr_copy(prop, dmfep->curr_addr);
22397c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop);
22405c1d0199Sgd 	} else {
22415c1d0199Sgd 		/* no property set... check eeprom */
22425c1d0199Sgd 		dmfe_read_eeprom(dmfep, EEPROM_EN_ADDR, dmfep->curr_addr,
22435c1d0199Sgd 		    ETHERADDRL);
22447c478bd9Sstevel@tonic-gate 	}
22457c478bd9Sstevel@tonic-gate }
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate static int
dmfe_alloc_dma_mem(dmfe_t * dmfep,size_t memsize,size_t setup,size_t slop,ddi_device_acc_attr_t * attr_p,uint_t dma_flags,dma_area_t * dma_p)22487c478bd9Sstevel@tonic-gate dmfe_alloc_dma_mem(dmfe_t *dmfep, size_t memsize,
22497c478bd9Sstevel@tonic-gate 	size_t setup, size_t slop, ddi_device_acc_attr_t *attr_p,
22507c478bd9Sstevel@tonic-gate 	uint_t dma_flags, dma_area_t *dma_p)
22517c478bd9Sstevel@tonic-gate {
22527c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t dma_cookie;
22537c478bd9Sstevel@tonic-gate 	uint_t ncookies;
22547c478bd9Sstevel@tonic-gate 	int err;
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	/*
22577c478bd9Sstevel@tonic-gate 	 * Allocate handle
22587c478bd9Sstevel@tonic-gate 	 */
22597c478bd9Sstevel@tonic-gate 	err = ddi_dma_alloc_handle(dmfep->devinfo, &dma_attr,
2260dd4eeefdSeota 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
2261bdb9230aSGarrett D'Amore 	if (err != DDI_SUCCESS) {
2262bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "DMA handle allocation failed");
22637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2264bdb9230aSGarrett D'Amore 	}
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	/*
22677c478bd9Sstevel@tonic-gate 	 * Allocate memory
22687c478bd9Sstevel@tonic-gate 	 */
22697c478bd9Sstevel@tonic-gate 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize + setup + slop,
2270dd4eeefdSeota 	    attr_p, dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
2271dd4eeefdSeota 	    DDI_DMA_SLEEP, NULL,
2272dd4eeefdSeota 	    &dma_p->mem_va, &dma_p->alength, &dma_p->acc_hdl);
2273bdb9230aSGarrett D'Amore 	if (err != DDI_SUCCESS) {
2274bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "DMA memory allocation failed: %d", err);
22757c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2276bdb9230aSGarrett D'Amore 	}
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 	/*
22797c478bd9Sstevel@tonic-gate 	 * Bind the two together
22807c478bd9Sstevel@tonic-gate 	 */
22817c478bd9Sstevel@tonic-gate 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
2282dd4eeefdSeota 	    dma_p->mem_va, dma_p->alength, dma_flags,
2283dd4eeefdSeota 	    DDI_DMA_SLEEP, NULL, &dma_cookie, &ncookies);
2284bdb9230aSGarrett D'Amore 	if (err != DDI_DMA_MAPPED) {
2285bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "DMA mapping failed: %d", err);
22867c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2287bdb9230aSGarrett D'Amore 	}
2288bdb9230aSGarrett D'Amore 	if ((dma_p->ncookies = ncookies) != 1) {
2289bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "Too many DMA cookeis: %d", ncookies);
22907c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2291bdb9230aSGarrett D'Amore 	}
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	dma_p->mem_dvma = dma_cookie.dmac_address;
22947c478bd9Sstevel@tonic-gate 	if (setup > 0) {
22957c478bd9Sstevel@tonic-gate 		dma_p->setup_dvma = dma_p->mem_dvma + memsize;
22967c478bd9Sstevel@tonic-gate 		dma_p->setup_va = dma_p->mem_va + memsize;
22977c478bd9Sstevel@tonic-gate 	} else {
22987c478bd9Sstevel@tonic-gate 		dma_p->setup_dvma = 0;
22997c478bd9Sstevel@tonic-gate 		dma_p->setup_va = NULL;
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
23037c478bd9Sstevel@tonic-gate }
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate /*
23067c478bd9Sstevel@tonic-gate  * This function allocates the transmit and receive buffers and descriptors.
23077c478bd9Sstevel@tonic-gate  */
23087c478bd9Sstevel@tonic-gate static int
dmfe_alloc_bufs(dmfe_t * dmfep)23097c478bd9Sstevel@tonic-gate dmfe_alloc_bufs(dmfe_t *dmfep)
23107c478bd9Sstevel@tonic-gate {
23117c478bd9Sstevel@tonic-gate 	size_t memsize;
23127c478bd9Sstevel@tonic-gate 	int err;
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	/*
23157c478bd9Sstevel@tonic-gate 	 * Allocate memory & handles for TX descriptor ring
23167c478bd9Sstevel@tonic-gate 	 */
23175c1d0199Sgd 	memsize = dmfep->tx.n_desc * sizeof (struct tx_desc_type);
23187c478bd9Sstevel@tonic-gate 	err = dmfe_alloc_dma_mem(dmfep, memsize, SETUPBUF_SIZE, DMFE_SLOP,
2319dd4eeefdSeota 	    &dmfe_reg_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2320dd4eeefdSeota 	    &dmfep->tx_desc);
2321bdb9230aSGarrett D'Amore 	if (err != DDI_SUCCESS) {
2322bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "TX descriptor allocation failed");
23237c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2324bdb9230aSGarrett D'Amore 	}
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	/*
23277c478bd9Sstevel@tonic-gate 	 * Allocate memory & handles for TX buffers
23287c478bd9Sstevel@tonic-gate 	 */
23295c1d0199Sgd 	memsize = dmfep->tx.n_desc * DMFE_BUF_SIZE;
23305c1d0199Sgd 	err = dmfe_alloc_dma_mem(dmfep, memsize, 0, 0,
2331dd4eeefdSeota 	    &dmfe_data_accattr, DDI_DMA_WRITE | DMFE_DMA_MODE,
2332dd4eeefdSeota 	    &dmfep->tx_buff);
2333bdb9230aSGarrett D'Amore 	if (err != DDI_SUCCESS) {
2334bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "TX buffer allocation failed");
23357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2336bdb9230aSGarrett D'Amore 	}
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	/*
23397c478bd9Sstevel@tonic-gate 	 * Allocate memory & handles for RX descriptor ring
23407c478bd9Sstevel@tonic-gate 	 */
23415c1d0199Sgd 	memsize = dmfep->rx.n_desc * sizeof (struct rx_desc_type);
23427c478bd9Sstevel@tonic-gate 	err = dmfe_alloc_dma_mem(dmfep, memsize, 0, DMFE_SLOP,
2343dd4eeefdSeota 	    &dmfe_reg_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2344dd4eeefdSeota 	    &dmfep->rx_desc);
2345bdb9230aSGarrett D'Amore 	if (err != DDI_SUCCESS) {
2346bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "RX descriptor allocation failed");
23477c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2348bdb9230aSGarrett D'Amore 	}
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	/*
23517c478bd9Sstevel@tonic-gate 	 * Allocate memory & handles for RX buffers
23527c478bd9Sstevel@tonic-gate 	 */
23535c1d0199Sgd 	memsize = dmfep->rx.n_desc * DMFE_BUF_SIZE;
23545c1d0199Sgd 	err = dmfe_alloc_dma_mem(dmfep, memsize, 0, 0,
23555c1d0199Sgd 	    &dmfe_data_accattr, DDI_DMA_READ | DMFE_DMA_MODE, &dmfep->rx_buff);
2356bdb9230aSGarrett D'Amore 	if (err != DDI_SUCCESS) {
2357bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "RX buffer allocation failed");
23587c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2359bdb9230aSGarrett D'Amore 	}
23607c478bd9Sstevel@tonic-gate 
2361cc291a4cSgd 	/*
2362cc291a4cSgd 	 * Allocate bitmasks for tx packet type tracking
2363cc291a4cSgd 	 */
2364cc291a4cSgd 	dmfep->tx_mcast = kmem_zalloc(dmfep->tx.n_desc / NBBY, KM_SLEEP);
2365cc291a4cSgd 	dmfep->tx_bcast = kmem_zalloc(dmfep->tx.n_desc / NBBY, KM_SLEEP);
2366cc291a4cSgd 
23677c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
23687c478bd9Sstevel@tonic-gate }
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate static void
dmfe_free_dma_mem(dma_area_t * dma_p)23717c478bd9Sstevel@tonic-gate dmfe_free_dma_mem(dma_area_t *dma_p)
23727c478bd9Sstevel@tonic-gate {
23737c478bd9Sstevel@tonic-gate 	if (dma_p->dma_hdl != NULL) {
23747c478bd9Sstevel@tonic-gate 		if (dma_p->ncookies) {
23757c478bd9Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
23767c478bd9Sstevel@tonic-gate 			dma_p->ncookies = 0;
23777c478bd9Sstevel@tonic-gate 		}
23787c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&dma_p->dma_hdl);
23797c478bd9Sstevel@tonic-gate 		dma_p->dma_hdl = NULL;
23807c478bd9Sstevel@tonic-gate 		dma_p->mem_dvma = 0;
23817c478bd9Sstevel@tonic-gate 		dma_p->setup_dvma = 0;
23827c478bd9Sstevel@tonic-gate 	}
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	if (dma_p->acc_hdl != NULL) {
23857c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&dma_p->acc_hdl);
23867c478bd9Sstevel@tonic-gate 		dma_p->acc_hdl = NULL;
23877c478bd9Sstevel@tonic-gate 		dma_p->mem_va = NULL;
23887c478bd9Sstevel@tonic-gate 		dma_p->setup_va = NULL;
23897c478bd9Sstevel@tonic-gate 	}
23907c478bd9Sstevel@tonic-gate }
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate /*
23937c478bd9Sstevel@tonic-gate  * This routine frees the transmit and receive buffers and descriptors.
23947c478bd9Sstevel@tonic-gate  * Make sure the chip is stopped before calling it!
23957c478bd9Sstevel@tonic-gate  */
23967c478bd9Sstevel@tonic-gate static void
dmfe_free_bufs(dmfe_t * dmfep)23977c478bd9Sstevel@tonic-gate dmfe_free_bufs(dmfe_t *dmfep)
23987c478bd9Sstevel@tonic-gate {
23997c478bd9Sstevel@tonic-gate 	dmfe_free_dma_mem(&dmfep->rx_buff);
24007c478bd9Sstevel@tonic-gate 	dmfe_free_dma_mem(&dmfep->rx_desc);
24017c478bd9Sstevel@tonic-gate 	dmfe_free_dma_mem(&dmfep->tx_buff);
24027c478bd9Sstevel@tonic-gate 	dmfe_free_dma_mem(&dmfep->tx_desc);
2403bdb9230aSGarrett D'Amore 	if (dmfep->tx_mcast)
2404bdb9230aSGarrett D'Amore 		kmem_free(dmfep->tx_mcast, dmfep->tx.n_desc / NBBY);
2405bdb9230aSGarrett D'Amore 	if (dmfep->tx_bcast)
2406bdb9230aSGarrett D'Amore 		kmem_free(dmfep->tx_bcast, dmfep->tx.n_desc / NBBY);
24077c478bd9Sstevel@tonic-gate }
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate static void
dmfe_unattach(dmfe_t * dmfep)24107c478bd9Sstevel@tonic-gate dmfe_unattach(dmfe_t *dmfep)
24117c478bd9Sstevel@tonic-gate {
24127c478bd9Sstevel@tonic-gate 	/*
24137c478bd9Sstevel@tonic-gate 	 * Clean up and free all DMFE data structures
24147c478bd9Sstevel@tonic-gate 	 */
2415dd4eeefdSeota 	if (dmfep->cycid != NULL) {
2416dd4eeefdSeota 		ddi_periodic_delete(dmfep->cycid);
2417dd4eeefdSeota 		dmfep->cycid = NULL;
24187c478bd9Sstevel@tonic-gate 	}
2419dd4eeefdSeota 
24207c478bd9Sstevel@tonic-gate 	if (dmfep->ksp_drv != NULL)
24217c478bd9Sstevel@tonic-gate 		kstat_delete(dmfep->ksp_drv);
24227c478bd9Sstevel@tonic-gate 	if (dmfep->progress & PROGRESS_HWINT) {
24237c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dmfep->devinfo, 0, dmfep->iblk);
2424bdb9230aSGarrett D'Amore 	}
2425bdb9230aSGarrett D'Amore 	if (dmfep->progress & PROGRESS_SOFTINT)
2426bdb9230aSGarrett D'Amore 		ddi_remove_softintr(dmfep->factotum_id);
2427bdb9230aSGarrett D'Amore 	if (dmfep->mii != NULL)
2428bdb9230aSGarrett D'Amore 		mii_free(dmfep->mii);
2429bdb9230aSGarrett D'Amore 	if (dmfep->progress & PROGRESS_MUTEX) {
24307c478bd9Sstevel@tonic-gate 		mutex_destroy(dmfep->txlock);
24317c478bd9Sstevel@tonic-gate 		mutex_destroy(dmfep->rxlock);
24327c478bd9Sstevel@tonic-gate 		mutex_destroy(dmfep->oplock);
24337c478bd9Sstevel@tonic-gate 	}
2434bdb9230aSGarrett D'Amore 	dmfe_free_bufs(dmfep);
2435bdb9230aSGarrett D'Amore 	if (dmfep->io_handle != NULL)
24367c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&dmfep->io_handle);
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	kmem_free(dmfep, sizeof (*dmfep));
24397c478bd9Sstevel@tonic-gate }
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate static int
dmfe_config_init(dmfe_t * dmfep,chip_id_t * idp)24427c478bd9Sstevel@tonic-gate dmfe_config_init(dmfe_t *dmfep, chip_id_t *idp)
24437c478bd9Sstevel@tonic-gate {
24447c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
24457c478bd9Sstevel@tonic-gate 	uint32_t regval;
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 	if (pci_config_setup(dmfep->devinfo, &handle) != DDI_SUCCESS)
24487c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	/*
24517c478bd9Sstevel@tonic-gate 	 * Get vendor/device/revision.  We expect (but don't check) that
24527c478bd9Sstevel@tonic-gate 	 * (vendorid == DAVICOM_VENDOR_ID) && (deviceid == DEVICE_ID_9102)
24537c478bd9Sstevel@tonic-gate 	 */
24547c478bd9Sstevel@tonic-gate 	idp->vendor = pci_config_get16(handle, PCI_CONF_VENID);
24557c478bd9Sstevel@tonic-gate 	idp->device = pci_config_get16(handle, PCI_CONF_DEVID);
24567c478bd9Sstevel@tonic-gate 	idp->revision = pci_config_get8(handle, PCI_CONF_REVID);
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	/*
24597c478bd9Sstevel@tonic-gate 	 * Turn on Bus Master Enable bit and ensure the device is not asleep
24607c478bd9Sstevel@tonic-gate 	 */
24617c478bd9Sstevel@tonic-gate 	regval = pci_config_get32(handle, PCI_CONF_COMM);
24627c478bd9Sstevel@tonic-gate 	pci_config_put32(handle, PCI_CONF_COMM, (regval | PCI_COMM_ME));
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 	regval = pci_config_get32(handle, PCI_DMFE_CONF_CFDD);
24657c478bd9Sstevel@tonic-gate 	pci_config_put32(handle, PCI_DMFE_CONF_CFDD,
2466dd4eeefdSeota 	    regval & ~(CFDD_SLEEP | CFDD_SNOOZE));
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	pci_config_teardown(&handle);
24697c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
24707c478bd9Sstevel@tonic-gate }
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate struct ks_index {
24737c478bd9Sstevel@tonic-gate 	int index;
24747c478bd9Sstevel@tonic-gate 	char *name;
24757c478bd9Sstevel@tonic-gate };
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate static const struct ks_index ks_drv_names[] = {
2478cc291a4cSgd 	{	KS_INTERRUPT,			"intr"			},
24797c478bd9Sstevel@tonic-gate 	{	KS_CYCLIC_RUN,			"cyclic_run"		},
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	{	KS_TX_STALL,			"tx_stall_detect"	},
24827c478bd9Sstevel@tonic-gate 	{	KS_CHIP_ERROR,			"chip_error_interrupt"	},
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	{	KS_FACTOTUM_RUN,		"factotum_run"		},
24857c478bd9Sstevel@tonic-gate 	{	KS_RECOVERY,			"factotum_recover"	},
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 	{	-1,				NULL			}
24887c478bd9Sstevel@tonic-gate };
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate static void
dmfe_init_kstats(dmfe_t * dmfep,int instance)24917c478bd9Sstevel@tonic-gate dmfe_init_kstats(dmfe_t *dmfep, int instance)
24927c478bd9Sstevel@tonic-gate {
24937c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
24947c478bd9Sstevel@tonic-gate 	kstat_named_t *knp;
24957c478bd9Sstevel@tonic-gate 	const struct ks_index *ksip;
24967c478bd9Sstevel@tonic-gate 
2497cc291a4cSgd 	/* no need to create MII stats, the mac module already does it */
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	/* Create and initialise driver-defined kstats */
25007c478bd9Sstevel@tonic-gate 	ksp = kstat_create(DRIVER_NAME, instance, "dmfe_events", "net",
2501dd4eeefdSeota 	    KSTAT_TYPE_NAMED, KS_DRV_COUNT, KSTAT_FLAG_PERSISTENT);
25027c478bd9Sstevel@tonic-gate 	if (ksp != NULL) {
25037c478bd9Sstevel@tonic-gate 		for (knp = ksp->ks_data, ksip = ks_drv_names;
2504dd4eeefdSeota 		    ksip->name != NULL; ++ksip) {
25057c478bd9Sstevel@tonic-gate 			kstat_named_init(&knp[ksip->index], ksip->name,
2506dd4eeefdSeota 			    KSTAT_DATA_UINT64);
25077c478bd9Sstevel@tonic-gate 		}
25087c478bd9Sstevel@tonic-gate 		dmfep->ksp_drv = ksp;
25097c478bd9Sstevel@tonic-gate 		dmfep->knp_drv = knp;
25107c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
25117c478bd9Sstevel@tonic-gate 	} else {
25127c478bd9Sstevel@tonic-gate 		dmfe_error(dmfep, "kstat_create() for dmfe_events failed");
25137c478bd9Sstevel@tonic-gate 	}
25147c478bd9Sstevel@tonic-gate }
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate static int
dmfe_resume(dev_info_t * devinfo)25177c478bd9Sstevel@tonic-gate dmfe_resume(dev_info_t *devinfo)
25187c478bd9Sstevel@tonic-gate {
25197c478bd9Sstevel@tonic-gate 	dmfe_t *dmfep;				/* Our private data	*/
25207c478bd9Sstevel@tonic-gate 	chip_id_t chipid;
2521bdb9230aSGarrett D'Amore 	boolean_t restart = B_FALSE;
25227c478bd9Sstevel@tonic-gate 
2523cc291a4cSgd 	dmfep = ddi_get_driver_private(devinfo);
2524cc291a4cSgd 	if (dmfep == NULL)
25257c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	/*
25287c478bd9Sstevel@tonic-gate 	 * Refuse to resume if the data structures aren't consistent
25297c478bd9Sstevel@tonic-gate 	 */
2530cc291a4cSgd 	if (dmfep->devinfo != devinfo)
25317c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	/*
25347c478bd9Sstevel@tonic-gate 	 * Refuse to resume if the chip's changed its identity (*boggle*)
25357c478bd9Sstevel@tonic-gate 	 */
25367c478bd9Sstevel@tonic-gate 	if (dmfe_config_init(dmfep, &chipid) != DDI_SUCCESS)
25377c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25387c478bd9Sstevel@tonic-gate 	if (chipid.vendor != dmfep->chipid.vendor)
25397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25407c478bd9Sstevel@tonic-gate 	if (chipid.device != dmfep->chipid.device)
25417c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25427c478bd9Sstevel@tonic-gate 	if (chipid.revision != dmfep->chipid.revision)
25437c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25447c478bd9Sstevel@tonic-gate 
2545bdb9230aSGarrett D'Amore 	mutex_enter(dmfep->oplock);
2546bdb9230aSGarrett D'Amore 	mutex_enter(dmfep->txlock);
2547bdb9230aSGarrett D'Amore 	dmfep->suspended = B_FALSE;
2548bdb9230aSGarrett D'Amore 	mutex_exit(dmfep->txlock);
2549bdb9230aSGarrett D'Amore 
25507c478bd9Sstevel@tonic-gate 	/*
2551cc291a4cSgd 	 * All OK, reinitialise h/w & kick off MAC scheduling
25527c478bd9Sstevel@tonic-gate 	 */
2553bdb9230aSGarrett D'Amore 	if (dmfep->mac_state == DMFE_MAC_STARTED) {
2554bdb9230aSGarrett D'Amore 		dmfe_restart(dmfep);
2555bdb9230aSGarrett D'Amore 		restart = B_TRUE;
2556bdb9230aSGarrett D'Amore 	}
25577c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
2558bdb9230aSGarrett D'Amore 
2559bdb9230aSGarrett D'Amore 	if (restart) {
2560bdb9230aSGarrett D'Amore 		mii_resume(dmfep->mii);
2561bdb9230aSGarrett D'Amore 		mac_tx_update(dmfep->mh);
2562bdb9230aSGarrett D'Amore 	}
25637c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
25647c478bd9Sstevel@tonic-gate }
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate /*
25677c478bd9Sstevel@tonic-gate  * attach(9E) -- Attach a device to the system
25687c478bd9Sstevel@tonic-gate  *
25697c478bd9Sstevel@tonic-gate  * Called once for each board successfully probed.
25707c478bd9Sstevel@tonic-gate  */
25717c478bd9Sstevel@tonic-gate static int
dmfe_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)25727c478bd9Sstevel@tonic-gate dmfe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
25737c478bd9Sstevel@tonic-gate {
2574cc291a4cSgd 	mac_register_t *macp;
25757c478bd9Sstevel@tonic-gate 	dmfe_t *dmfep;				/* Our private data	*/
25767c478bd9Sstevel@tonic-gate 	uint32_t csr6;
25777c478bd9Sstevel@tonic-gate 	int instance;
25787c478bd9Sstevel@tonic-gate 	int err;
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(devinfo);
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 	switch (cmd) {
25837c478bd9Sstevel@tonic-gate 	default:
25847c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
25877c478bd9Sstevel@tonic-gate 		return (dmfe_resume(devinfo));
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
25907c478bd9Sstevel@tonic-gate 		break;
25917c478bd9Sstevel@tonic-gate 	}
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	dmfep = kmem_zalloc(sizeof (*dmfep), KM_SLEEP);
2594cc291a4cSgd 	ddi_set_driver_private(devinfo, dmfep);
25957c478bd9Sstevel@tonic-gate 	dmfep->devinfo = devinfo;
2596cc291a4cSgd 	dmfep->dmfe_guard = DMFE_GUARD;
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate 	/*
25997c478bd9Sstevel@tonic-gate 	 * Initialize more fields in DMFE private data
26007c478bd9Sstevel@tonic-gate 	 * Determine the local MAC address
26017c478bd9Sstevel@tonic-gate 	 */
26027c478bd9Sstevel@tonic-gate #if	DMFEDEBUG
26037c478bd9Sstevel@tonic-gate 	dmfep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 0,
2604dd4eeefdSeota 	    debug_propname, dmfe_debug);
26057c478bd9Sstevel@tonic-gate #endif	/* DMFEDEBUG */
2606dd4eeefdSeota 	dmfep->cycid = NULL;
26077c478bd9Sstevel@tonic-gate 	(void) snprintf(dmfep->ifname, sizeof (dmfep->ifname), "dmfe%d",
2608dd4eeefdSeota 	    instance);
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 	/*
26117c478bd9Sstevel@tonic-gate 	 * Check for custom "opmode-reg-value" property;
26127c478bd9Sstevel@tonic-gate 	 * if none, use the defaults below for CSR6 ...
26137c478bd9Sstevel@tonic-gate 	 */
26147c478bd9Sstevel@tonic-gate 	csr6 = TX_THRESHOLD_HI | STORE_AND_FORWARD | EXT_MII_IF | OPN_25_MB1;
26157c478bd9Sstevel@tonic-gate 	dmfep->opmode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
2616dd4eeefdSeota 	    DDI_PROP_DONTPASS, opmode_propname, csr6);
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	/*
26197c478bd9Sstevel@tonic-gate 	 * Read chip ID & set up config space command register(s)
26207c478bd9Sstevel@tonic-gate 	 */
26217c478bd9Sstevel@tonic-gate 	if (dmfe_config_init(dmfep, &dmfep->chipid) != DDI_SUCCESS) {
26227c478bd9Sstevel@tonic-gate 		dmfe_error(dmfep, "dmfe_config_init() failed");
26237c478bd9Sstevel@tonic-gate 		goto attach_fail;
26247c478bd9Sstevel@tonic-gate 	}
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	/*
26277c478bd9Sstevel@tonic-gate 	 * Map operating registers
26287c478bd9Sstevel@tonic-gate 	 */
26297c478bd9Sstevel@tonic-gate 	err = ddi_regs_map_setup(devinfo, DMFE_PCI_RNUMBER,
2630dd4eeefdSeota 	    &dmfep->io_reg, 0, 0, &dmfe_reg_accattr, &dmfep->io_handle);
26317c478bd9Sstevel@tonic-gate 	if (err != DDI_SUCCESS) {
26327c478bd9Sstevel@tonic-gate 		dmfe_error(dmfep, "ddi_regs_map_setup() failed");
26337c478bd9Sstevel@tonic-gate 		goto attach_fail;
26347c478bd9Sstevel@tonic-gate 	}
26357c478bd9Sstevel@tonic-gate 
26365c1d0199Sgd 	/*
26375c1d0199Sgd 	 * Get our MAC address.
26385c1d0199Sgd 	 */
26395c1d0199Sgd 	dmfe_find_mac_address(dmfep);
26405c1d0199Sgd 
26417c478bd9Sstevel@tonic-gate 	/*
26427c478bd9Sstevel@tonic-gate 	 * Allocate the TX and RX descriptors/buffers.
26437c478bd9Sstevel@tonic-gate 	 */
26447c478bd9Sstevel@tonic-gate 	dmfep->tx.n_desc = dmfe_tx_desc;
26457c478bd9Sstevel@tonic-gate 	dmfep->rx.n_desc = dmfe_rx_desc;
26467c478bd9Sstevel@tonic-gate 	err = dmfe_alloc_bufs(dmfep);
26477c478bd9Sstevel@tonic-gate 	if (err != DDI_SUCCESS) {
26487c478bd9Sstevel@tonic-gate 		goto attach_fail;
26497c478bd9Sstevel@tonic-gate 	}
26507c478bd9Sstevel@tonic-gate 
26517c478bd9Sstevel@tonic-gate 	/*
26527c478bd9Sstevel@tonic-gate 	 * Add the softint handler
26537c478bd9Sstevel@tonic-gate 	 */
26547c478bd9Sstevel@tonic-gate 	if (ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &dmfep->factotum_id,
2655dd4eeefdSeota 	    NULL, NULL, dmfe_factotum, (caddr_t)dmfep) != DDI_SUCCESS) {
26567c478bd9Sstevel@tonic-gate 		dmfe_error(dmfep, "ddi_add_softintr() failed");
26577c478bd9Sstevel@tonic-gate 		goto attach_fail;
26587c478bd9Sstevel@tonic-gate 	}
26597c478bd9Sstevel@tonic-gate 	dmfep->progress |= PROGRESS_SOFTINT;
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 	/*
26627c478bd9Sstevel@tonic-gate 	 * Add the h/w interrupt handler & initialise mutexen
26637c478bd9Sstevel@tonic-gate 	 */
2664bdb9230aSGarrett D'Amore 	if (ddi_get_iblock_cookie(devinfo, 0, &dmfep->iblk) != DDI_SUCCESS) {
2665bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "ddi_get_iblock_cookie() failed");
26667c478bd9Sstevel@tonic-gate 		goto attach_fail;
26677c478bd9Sstevel@tonic-gate 	}
2668bdb9230aSGarrett D'Amore 
26697c478bd9Sstevel@tonic-gate 	mutex_init(dmfep->milock, NULL, MUTEX_DRIVER, NULL);
26707c478bd9Sstevel@tonic-gate 	mutex_init(dmfep->oplock, NULL, MUTEX_DRIVER, dmfep->iblk);
26717c478bd9Sstevel@tonic-gate 	mutex_init(dmfep->rxlock, NULL, MUTEX_DRIVER, dmfep->iblk);
26727c478bd9Sstevel@tonic-gate 	mutex_init(dmfep->txlock, NULL, MUTEX_DRIVER, dmfep->iblk);
2673bdb9230aSGarrett D'Amore 	dmfep->progress |= PROGRESS_MUTEX;
2674bdb9230aSGarrett D'Amore 
2675bdb9230aSGarrett D'Amore 	if (ddi_add_intr(devinfo, 0, NULL, NULL,
2676bdb9230aSGarrett D'Amore 	    dmfe_interrupt, (caddr_t)dmfep) != DDI_SUCCESS) {
2677bdb9230aSGarrett D'Amore 		dmfe_error(dmfep, "ddi_add_intr() failed");
2678bdb9230aSGarrett D'Amore 		goto attach_fail;
2679bdb9230aSGarrett D'Amore 	}
26807c478bd9Sstevel@tonic-gate 	dmfep->progress |= PROGRESS_HWINT;
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 	/*
26837c478bd9Sstevel@tonic-gate 	 * Create & initialise named kstats
26847c478bd9Sstevel@tonic-gate 	 */
26857c478bd9Sstevel@tonic-gate 	dmfe_init_kstats(dmfep, instance);
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 	/*
26887c478bd9Sstevel@tonic-gate 	 * Reset & initialise the chip and the ring buffers
26897c478bd9Sstevel@tonic-gate 	 * Initialise the (internal) PHY
26907c478bd9Sstevel@tonic-gate 	 */
2691cc291a4cSgd 	mutex_enter(dmfep->oplock);
2692cc291a4cSgd 	mutex_enter(dmfep->rxlock);
2693cc291a4cSgd 	mutex_enter(dmfep->txlock);
2694cc291a4cSgd 
2695cc291a4cSgd 	dmfe_reset(dmfep);
2696cc291a4cSgd 
2697cc291a4cSgd 	/*
2698cc291a4cSgd 	 * Prepare the setup packet
2699cc291a4cSgd 	 */
2700cc291a4cSgd 	bzero(dmfep->tx_desc.setup_va, SETUPBUF_SIZE);
2701cc291a4cSgd 	bzero(dmfep->mcast_refs, MCASTBUF_SIZE);
2702cc291a4cSgd 	dmfep->addr_set = B_FALSE;
2703cc291a4cSgd 	dmfep->opmode &= ~(PROMISC_MODE | PASS_MULTICAST);
2704cc291a4cSgd 	dmfep->mac_state = DMFE_MAC_RESET;
2705cc291a4cSgd 
2706cc291a4cSgd 	mutex_exit(dmfep->txlock);
2707cc291a4cSgd 	mutex_exit(dmfep->rxlock);
2708cc291a4cSgd 	mutex_exit(dmfep->oplock);
2709cc291a4cSgd 
27107c478bd9Sstevel@tonic-gate 	if (dmfe_init_phy(dmfep) != B_TRUE)
27117c478bd9Sstevel@tonic-gate 		goto attach_fail;
27127c478bd9Sstevel@tonic-gate 
2713cc291a4cSgd 	/*
2714cc291a4cSgd 	 * Send a reasonable setup frame.  This configures our starting
2715cc291a4cSgd 	 * address and the broadcast address.
2716cc291a4cSgd 	 */
27176dfdd35cSgd 	(void) dmfe_m_unicst(dmfep, dmfep->curr_addr);
2718cc291a4cSgd 
27197c478bd9Sstevel@tonic-gate 	/*
27207c478bd9Sstevel@tonic-gate 	 * Initialize pointers to device specific functions which
27217c478bd9Sstevel@tonic-gate 	 * will be used by the generic layer.
27227c478bd9Sstevel@tonic-gate 	 */
2723cc291a4cSgd 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2724cc291a4cSgd 		goto attach_fail;
2725cc291a4cSgd 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2726cc291a4cSgd 	macp->m_driver = dmfep;
2727cc291a4cSgd 	macp->m_dip = devinfo;
2728cc291a4cSgd 	macp->m_src_addr = dmfep->curr_addr;
2729cc291a4cSgd 	macp->m_callbacks = &dmfe_m_callbacks;
2730cc291a4cSgd 	macp->m_min_sdu = 0;
2731cc291a4cSgd 	macp->m_max_sdu = ETHERMTU;
2732d62bc4baSyz 	macp->m_margin = VLAN_TAGSZ;
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	/*
2735cc291a4cSgd 	 * Finally, we're ready to register ourselves with the MAC layer
27367c478bd9Sstevel@tonic-gate 	 * interface; if this succeeds, we're all ready to start()
27377c478bd9Sstevel@tonic-gate 	 */
2738cc291a4cSgd 	err = mac_register(macp, &dmfep->mh);
2739cc291a4cSgd 	mac_free(macp);
2740cc291a4cSgd 	if (err != 0)
27417c478bd9Sstevel@tonic-gate 		goto attach_fail;
27427c478bd9Sstevel@tonic-gate 	ASSERT(dmfep->dmfe_guard == DMFE_GUARD);
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate 	/*
27457c478bd9Sstevel@tonic-gate 	 * Install the cyclic callback that we use to check for link
2746dd4eeefdSeota 	 * status, transmit stall, etc. The cyclic callback (dmfe_cyclic())
2747dd4eeefdSeota 	 * is invoked in kernel context then.
2748dd4eeefdSeota 	 */
2749dd4eeefdSeota 	ASSERT(dmfep->cycid == NULL);
2750dd4eeefdSeota 	dmfep->cycid = ddi_periodic_add(dmfe_cyclic, dmfep,
2751dd4eeefdSeota 	    dmfe_tick_us * 1000, DDI_IPL_0);
27527c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
27537c478bd9Sstevel@tonic-gate 
27547c478bd9Sstevel@tonic-gate attach_fail:
27557c478bd9Sstevel@tonic-gate 	dmfe_unattach(dmfep);
27567c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
27577c478bd9Sstevel@tonic-gate }
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate /*
27607c478bd9Sstevel@tonic-gate  *	dmfe_suspend() -- suspend transmit/receive for powerdown
27617c478bd9Sstevel@tonic-gate  */
27627c478bd9Sstevel@tonic-gate static int
dmfe_suspend(dmfe_t * dmfep)27637c478bd9Sstevel@tonic-gate dmfe_suspend(dmfe_t *dmfep)
27647c478bd9Sstevel@tonic-gate {
27657c478bd9Sstevel@tonic-gate 	/*
27667c478bd9Sstevel@tonic-gate 	 * Just stop processing ...
27677c478bd9Sstevel@tonic-gate 	 */
2768bdb9230aSGarrett D'Amore 	mii_suspend(dmfep->mii);
27697c478bd9Sstevel@tonic-gate 	mutex_enter(dmfep->oplock);
27707c478bd9Sstevel@tonic-gate 	dmfe_stop(dmfep);
2771bdb9230aSGarrett D'Amore 
2772bdb9230aSGarrett D'Amore 	mutex_enter(dmfep->txlock);
2773bdb9230aSGarrett D'Amore 	dmfep->suspended = B_TRUE;
2774bdb9230aSGarrett D'Amore 	mutex_exit(dmfep->txlock);
27757c478bd9Sstevel@tonic-gate 	mutex_exit(dmfep->oplock);
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
27787c478bd9Sstevel@tonic-gate }
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate /*
27817c478bd9Sstevel@tonic-gate  * detach(9E) -- Detach a device from the system
27827c478bd9Sstevel@tonic-gate  */
27837c478bd9Sstevel@tonic-gate static int
dmfe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)27847c478bd9Sstevel@tonic-gate dmfe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
27857c478bd9Sstevel@tonic-gate {
27867c478bd9Sstevel@tonic-gate 	dmfe_t *dmfep;
27877c478bd9Sstevel@tonic-gate 
2788cc291a4cSgd 	dmfep = ddi_get_driver_private(devinfo);
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 	switch (cmd) {
27917c478bd9Sstevel@tonic-gate 	default:
27927c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
27957c478bd9Sstevel@tonic-gate 		return (dmfe_suspend(dmfep));
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
27987c478bd9Sstevel@tonic-gate 		break;
27997c478bd9Sstevel@tonic-gate 	}
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	/*
2802cc291a4cSgd 	 * Unregister from the MAC subsystem.  This can fail, in
28037c478bd9Sstevel@tonic-gate 	 * particular if there are DLPI style-2 streams still open -
28047c478bd9Sstevel@tonic-gate 	 * in which case we just return failure without shutting
28057c478bd9Sstevel@tonic-gate 	 * down chip operations.
28067c478bd9Sstevel@tonic-gate 	 */
2807cc291a4cSgd 	if (mac_unregister(dmfep->mh) != DDI_SUCCESS)
28087c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate 	/*
28117c478bd9Sstevel@tonic-gate 	 * All activity stopped, so we can clean up & exit
28127c478bd9Sstevel@tonic-gate 	 */
28137c478bd9Sstevel@tonic-gate 	dmfe_unattach(dmfep);
28147c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
28157c478bd9Sstevel@tonic-gate }
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate /*
28197c478bd9Sstevel@tonic-gate  * ========== Module Loading Data & Entry Points ==========
28207c478bd9Sstevel@tonic-gate  */
28217c478bd9Sstevel@tonic-gate 
2822cc291a4cSgd DDI_DEFINE_STREAM_OPS(dmfe_dev_ops, nulldev, nulldev, dmfe_attach, dmfe_detach,
282319397407SSherry Moore 	nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported);
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate static struct modldrv dmfe_modldrv = {
28267c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* Type of module.  This one is a driver */
28277c478bd9Sstevel@tonic-gate 	dmfe_ident,		/* short description */
28287c478bd9Sstevel@tonic-gate 	&dmfe_dev_ops		/* driver specific ops */
28297c478bd9Sstevel@tonic-gate };
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
28327c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&dmfe_modldrv, NULL
28337c478bd9Sstevel@tonic-gate };
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)28367c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
28377c478bd9Sstevel@tonic-gate {
28387c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
28397c478bd9Sstevel@tonic-gate }
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate int
_init(void)28427c478bd9Sstevel@tonic-gate _init(void)
28437c478bd9Sstevel@tonic-gate {
28447c478bd9Sstevel@tonic-gate 	uint32_t tmp100;
28457c478bd9Sstevel@tonic-gate 	uint32_t tmp10;
28467c478bd9Sstevel@tonic-gate 	int i;
28477c478bd9Sstevel@tonic-gate 	int status;
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 	/* Calculate global timing parameters */
28507c478bd9Sstevel@tonic-gate 	tmp100 = (dmfe_tx100_stall_us+dmfe_tick_us-1)/dmfe_tick_us;
28517c478bd9Sstevel@tonic-gate 	tmp10 = (dmfe_tx10_stall_us+dmfe_tick_us-1)/dmfe_tick_us;
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 	for (i = 0; i <= TX_PROCESS_MAX_STATE; ++i) {
28547c478bd9Sstevel@tonic-gate 		switch (i) {
28557c478bd9Sstevel@tonic-gate 		case TX_PROCESS_STATE(TX_PROCESS_FETCH_DATA):
28567c478bd9Sstevel@tonic-gate 		case TX_PROCESS_STATE(TX_PROCESS_WAIT_END):
28577c478bd9Sstevel@tonic-gate 			/*
28587c478bd9Sstevel@tonic-gate 			 * The chip doesn't spontaneously recover from
28597c478bd9Sstevel@tonic-gate 			 * a stall in these states, so we reset early
28607c478bd9Sstevel@tonic-gate 			 */
28617c478bd9Sstevel@tonic-gate 			stall_100_tix[i] = tmp100;
28627c478bd9Sstevel@tonic-gate 			stall_10_tix[i] = tmp10;
28637c478bd9Sstevel@tonic-gate 			break;
28647c478bd9Sstevel@tonic-gate 
28657c478bd9Sstevel@tonic-gate 		case TX_PROCESS_STATE(TX_PROCESS_SUSPEND):
28667c478bd9Sstevel@tonic-gate 		default:
28677c478bd9Sstevel@tonic-gate 			/*
28687c478bd9Sstevel@tonic-gate 			 * The chip has been seen to spontaneously recover
28697c478bd9Sstevel@tonic-gate 			 * after an apparent stall in the SUSPEND state,
28707c478bd9Sstevel@tonic-gate 			 * so we'll allow it rather longer to do so.  As
28717c478bd9Sstevel@tonic-gate 			 * stalls in other states have not been observed,
28727c478bd9Sstevel@tonic-gate 			 * we'll use long timeouts for them too ...
28737c478bd9Sstevel@tonic-gate 			 */
28747c478bd9Sstevel@tonic-gate 			stall_100_tix[i] = tmp100 * 20;
28757c478bd9Sstevel@tonic-gate 			stall_10_tix[i] = tmp10 * 20;
28767c478bd9Sstevel@tonic-gate 			break;
28777c478bd9Sstevel@tonic-gate 		}
28787c478bd9Sstevel@tonic-gate 	}
28797c478bd9Sstevel@tonic-gate 
2880cc291a4cSgd 	mac_init_ops(&dmfe_dev_ops, "dmfe");
28817c478bd9Sstevel@tonic-gate 	status = mod_install(&modlinkage);
2882cc291a4cSgd 	if (status == DDI_SUCCESS)
28837c478bd9Sstevel@tonic-gate 		dmfe_log_init();
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 	return (status);
28867c478bd9Sstevel@tonic-gate }
28877c478bd9Sstevel@tonic-gate 
28887c478bd9Sstevel@tonic-gate int
_fini(void)28897c478bd9Sstevel@tonic-gate _fini(void)
28907c478bd9Sstevel@tonic-gate {
28917c478bd9Sstevel@tonic-gate 	int status;
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 	status = mod_remove(&modlinkage);
2894cc291a4cSgd 	if (status == DDI_SUCCESS) {
2895cc291a4cSgd 		mac_fini_ops(&dmfe_dev_ops);
28967c478bd9Sstevel@tonic-gate 		dmfe_log_fini();
2897cc291a4cSgd 	}
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 	return (status);
29007c478bd9Sstevel@tonic-gate }
2901