xref: /onnv-gate/usr/src/uts/common/io/rtls/rtls.c (revision 11453:080c87e308c2)
19286SGarrett.Damore@Sun.COM /*
29286SGarrett.Damore@Sun.COM  * CDDL HEADER START
39286SGarrett.Damore@Sun.COM  *
49286SGarrett.Damore@Sun.COM  * The contents of this file are subject to the terms of the
59286SGarrett.Damore@Sun.COM  * Common Development and Distribution License (the "License").
69286SGarrett.Damore@Sun.COM  * You may not use this file except in compliance with the License.
79286SGarrett.Damore@Sun.COM  *
89286SGarrett.Damore@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99286SGarrett.Damore@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109286SGarrett.Damore@Sun.COM  * See the License for the specific language governing permissions
119286SGarrett.Damore@Sun.COM  * and limitations under the License.
129286SGarrett.Damore@Sun.COM  *
139286SGarrett.Damore@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149286SGarrett.Damore@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159286SGarrett.Damore@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169286SGarrett.Damore@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179286SGarrett.Damore@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189286SGarrett.Damore@Sun.COM  *
199286SGarrett.Damore@Sun.COM  * CDDL HEADER END
209286SGarrett.Damore@Sun.COM  */
219286SGarrett.Damore@Sun.COM 
229286SGarrett.Damore@Sun.COM /*
23*11453Sgdamore@opensolaris.org  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
249286SGarrett.Damore@Sun.COM  * Use is subject to license terms.
259286SGarrett.Damore@Sun.COM  */
269286SGarrett.Damore@Sun.COM 
279286SGarrett.Damore@Sun.COM /*
289286SGarrett.Damore@Sun.COM  * rtls -- REALTEK 8139-serials PCI Fast Ethernet Driver, Depends on the
299286SGarrett.Damore@Sun.COM  * Generic LAN Driver utility functions in /kernel/misc/mac
309286SGarrett.Damore@Sun.COM  *
319286SGarrett.Damore@Sun.COM  * This product is covered by one or more of the following patents:
329286SGarrett.Damore@Sun.COM  * US5,307,459, US5,434,872, US5,732,094, US6,570,884, US6,115,776, and
339286SGarrett.Damore@Sun.COM  * US6,327,625.
349286SGarrett.Damore@Sun.COM  *
359286SGarrett.Damore@Sun.COM  * Currently supports:
369286SGarrett.Damore@Sun.COM  *	RTL8139
379286SGarrett.Damore@Sun.COM  */
389286SGarrett.Damore@Sun.COM 
399286SGarrett.Damore@Sun.COM #include <sys/types.h>
409286SGarrett.Damore@Sun.COM #include <sys/debug.h>
419286SGarrett.Damore@Sun.COM #include <sys/errno.h>
429286SGarrett.Damore@Sun.COM 
439286SGarrett.Damore@Sun.COM #include <sys/stropts.h>
449286SGarrett.Damore@Sun.COM #include <sys/stream.h>
459286SGarrett.Damore@Sun.COM #include <sys/kmem.h>
469286SGarrett.Damore@Sun.COM #include <sys/conf.h>
479286SGarrett.Damore@Sun.COM #include <sys/ddi.h>
489286SGarrett.Damore@Sun.COM #include <sys/devops.h>
499286SGarrett.Damore@Sun.COM #include <sys/ksynch.h>
509286SGarrett.Damore@Sun.COM #include <sys/stat.h>
519286SGarrett.Damore@Sun.COM #include <sys/conf.h>
529286SGarrett.Damore@Sun.COM #include <sys/modctl.h>
539286SGarrett.Damore@Sun.COM #include <sys/dlpi.h>
549286SGarrett.Damore@Sun.COM #include <sys/ethernet.h>
559286SGarrett.Damore@Sun.COM #include <sys/vlan.h>
569286SGarrett.Damore@Sun.COM #include <sys/strsun.h>
579286SGarrett.Damore@Sun.COM #include <sys/pci.h>
589286SGarrett.Damore@Sun.COM #include <sys/sunddi.h>
59*11453Sgdamore@opensolaris.org #include <sys/mii.h>
60*11453Sgdamore@opensolaris.org #include <sys/miiregs.h>
619286SGarrett.Damore@Sun.COM #include <sys/mac_provider.h>
629286SGarrett.Damore@Sun.COM #include <sys/mac_ether.h>
639286SGarrett.Damore@Sun.COM 
649286SGarrett.Damore@Sun.COM #include "rtls.h"
659286SGarrett.Damore@Sun.COM 
669286SGarrett.Damore@Sun.COM /*
679286SGarrett.Damore@Sun.COM  * Declarations and Module Linkage
689286SGarrett.Damore@Sun.COM  */
699286SGarrett.Damore@Sun.COM 
709286SGarrett.Damore@Sun.COM /*
719286SGarrett.Damore@Sun.COM  * This is the string displayed by modinfo, etc.
729286SGarrett.Damore@Sun.COM  */
739286SGarrett.Damore@Sun.COM static char rtls_ident[] = "RealTek 8139 Ethernet driver";
749286SGarrett.Damore@Sun.COM 
759286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
769286SGarrett.Damore@Sun.COM int rtls_debug = 0;
779286SGarrett.Damore@Sun.COM #endif
789286SGarrett.Damore@Sun.COM 
799286SGarrett.Damore@Sun.COM /*
809286SGarrett.Damore@Sun.COM  * Required system entry points
819286SGarrett.Damore@Sun.COM  */
829286SGarrett.Damore@Sun.COM static int rtls_attach(dev_info_t *, ddi_attach_cmd_t);
839286SGarrett.Damore@Sun.COM static int rtls_detach(dev_info_t *, ddi_detach_cmd_t);
849286SGarrett.Damore@Sun.COM static int rtls_quiesce(dev_info_t *);
859286SGarrett.Damore@Sun.COM 
869286SGarrett.Damore@Sun.COM /*
879286SGarrett.Damore@Sun.COM  * Required driver entry points for MAC
889286SGarrett.Damore@Sun.COM  */
899286SGarrett.Damore@Sun.COM static int rtls_m_start(void *);
909286SGarrett.Damore@Sun.COM static void rtls_m_stop(void *);
919286SGarrett.Damore@Sun.COM static int rtls_m_unicst(void *, const uint8_t *);
929286SGarrett.Damore@Sun.COM static int rtls_m_multicst(void *, boolean_t, const uint8_t *);
939286SGarrett.Damore@Sun.COM static int rtls_m_promisc(void *, boolean_t);
949286SGarrett.Damore@Sun.COM static mblk_t *rtls_m_tx(void *, mblk_t *);
959286SGarrett.Damore@Sun.COM static int rtls_m_stat(void *, uint_t, uint64_t *);
96*11453Sgdamore@opensolaris.org static int rtls_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
97*11453Sgdamore@opensolaris.org     uint_t, void *, uint_t *);
98*11453Sgdamore@opensolaris.org static int rtls_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
99*11453Sgdamore@opensolaris.org     const void *);
1009286SGarrett.Damore@Sun.COM 
1019286SGarrett.Damore@Sun.COM static uint_t rtls_intr(caddr_t);
1029286SGarrett.Damore@Sun.COM 
1039286SGarrett.Damore@Sun.COM /*
104*11453Sgdamore@opensolaris.org  * MII entry points
105*11453Sgdamore@opensolaris.org  */
106*11453Sgdamore@opensolaris.org static uint16_t rtls_mii_read(void *, uint8_t, uint8_t);
107*11453Sgdamore@opensolaris.org static void rtls_mii_write(void *, uint8_t, uint8_t, uint16_t);
108*11453Sgdamore@opensolaris.org static void rtls_mii_notify(void *, link_state_t);
109*11453Sgdamore@opensolaris.org 
110*11453Sgdamore@opensolaris.org /*
1119286SGarrett.Damore@Sun.COM  * Internal functions used by the above entry points
1129286SGarrett.Damore@Sun.COM  */
1139286SGarrett.Damore@Sun.COM static int rtls_chip_reset(rtls_t *, boolean_t);
1149286SGarrett.Damore@Sun.COM static void rtls_chip_init(rtls_t *);
1159286SGarrett.Damore@Sun.COM static void rtls_chip_stop(rtls_t *rtlsp);
1169286SGarrett.Damore@Sun.COM static void rtls_chip_start(rtls_t *rtlsp);
1179286SGarrett.Damore@Sun.COM static void rtls_chip_restart(rtls_t *rtlsp);
1189286SGarrett.Damore@Sun.COM static void rtls_get_mac_addr(rtls_t *, uint8_t *);
1199286SGarrett.Damore@Sun.COM static void rtls_set_mac_addr(rtls_t *, const uint8_t *);
1209286SGarrett.Damore@Sun.COM static uint_t rtls_hash_index(const uint8_t *);
1219286SGarrett.Damore@Sun.COM static boolean_t rtls_send(rtls_t *, mblk_t *);
1229286SGarrett.Damore@Sun.COM static void rtls_receive(rtls_t *);
1239286SGarrett.Damore@Sun.COM 
1249286SGarrett.Damore@Sun.COM /*
1259286SGarrett.Damore@Sun.COM  * Buffer Management Routines
1269286SGarrett.Damore@Sun.COM  */
1279286SGarrett.Damore@Sun.COM static int rtls_alloc_bufs(rtls_t *);
1289286SGarrett.Damore@Sun.COM static void rtls_free_bufs(rtls_t *);
1299286SGarrett.Damore@Sun.COM static int rtls_alloc_dma_mem(rtls_t *, size_t,	ddi_device_acc_attr_t *,
1309286SGarrett.Damore@Sun.COM 	uint_t, dma_area_t *);
1319286SGarrett.Damore@Sun.COM static void rtls_free_dma_mem(dma_area_t *);
1329286SGarrett.Damore@Sun.COM 
1339286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
1349286SGarrett.Damore@Sun.COM static void rtls_reg_print(rtls_t *);	/* debug routine */
1359286SGarrett.Damore@Sun.COM #endif
1369286SGarrett.Damore@Sun.COM 
1379286SGarrett.Damore@Sun.COM #define	RTLS_DRIVER_NAME	"rtls"
1389286SGarrett.Damore@Sun.COM 
1399286SGarrett.Damore@Sun.COM /*
1409286SGarrett.Damore@Sun.COM  * Used for buffers allocated by ddi_dma_mem_alloc()
1419286SGarrett.Damore@Sun.COM  */
1429286SGarrett.Damore@Sun.COM static ddi_dma_attr_t dma_attr = {
1439286SGarrett.Damore@Sun.COM 	DMA_ATTR_V0,		/* dma_attr version */
1449286SGarrett.Damore@Sun.COM 	0,			/* dma_attr_addr_lo */
1459286SGarrett.Damore@Sun.COM 	(uint_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
1469286SGarrett.Damore@Sun.COM 	0x7FFFFFFF,		/* dma_attr_count_max */
1479286SGarrett.Damore@Sun.COM 	4,			/* dma_attr_align */
1489286SGarrett.Damore@Sun.COM 	0x3F,			/* dma_attr_burstsizes */
1499286SGarrett.Damore@Sun.COM 	1,			/* dma_attr_minxfer */
1509286SGarrett.Damore@Sun.COM 	(uint_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
1519286SGarrett.Damore@Sun.COM 	(uint_t)0xFFFFFFFF,	/* dma_attr_seg */
1529286SGarrett.Damore@Sun.COM 	1,			/* dma_attr_sgllen */
1539286SGarrett.Damore@Sun.COM 	1,			/* dma_attr_granular */
1549286SGarrett.Damore@Sun.COM 	0,			/* dma_attr_flags */
1559286SGarrett.Damore@Sun.COM };
1569286SGarrett.Damore@Sun.COM 
1579286SGarrett.Damore@Sun.COM /*
1589286SGarrett.Damore@Sun.COM  * PIO access attributes for registers
1599286SGarrett.Damore@Sun.COM  */
1609286SGarrett.Damore@Sun.COM static ddi_device_acc_attr_t rtls_reg_accattr = {
1619286SGarrett.Damore@Sun.COM 	DDI_DEVICE_ATTR_V0,
1629286SGarrett.Damore@Sun.COM 	DDI_STRUCTURE_LE_ACC,
1639286SGarrett.Damore@Sun.COM 	DDI_STRICTORDER_ACC
1649286SGarrett.Damore@Sun.COM };
1659286SGarrett.Damore@Sun.COM 
1669286SGarrett.Damore@Sun.COM /*
1679286SGarrett.Damore@Sun.COM  * DMA access attributes for data
1689286SGarrett.Damore@Sun.COM  */
1699286SGarrett.Damore@Sun.COM static ddi_device_acc_attr_t rtls_buf_accattr = {
1709286SGarrett.Damore@Sun.COM 	DDI_DEVICE_ATTR_V0,
1719286SGarrett.Damore@Sun.COM 	DDI_NEVERSWAP_ACC,
1729286SGarrett.Damore@Sun.COM 	DDI_STRICTORDER_ACC
1739286SGarrett.Damore@Sun.COM };
1749286SGarrett.Damore@Sun.COM 
1759286SGarrett.Damore@Sun.COM uchar_t rtls_broadcastaddr[] = {
1769286SGarrett.Damore@Sun.COM 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1779286SGarrett.Damore@Sun.COM };
1789286SGarrett.Damore@Sun.COM 
1799286SGarrett.Damore@Sun.COM static mac_callbacks_t rtls_m_callbacks = {
180*11453Sgdamore@opensolaris.org 	MC_SETPROP | MC_GETPROP,
1819286SGarrett.Damore@Sun.COM 	rtls_m_stat,
1829286SGarrett.Damore@Sun.COM 	rtls_m_start,
1839286SGarrett.Damore@Sun.COM 	rtls_m_stop,
1849286SGarrett.Damore@Sun.COM 	rtls_m_promisc,
1859286SGarrett.Damore@Sun.COM 	rtls_m_multicst,
1869286SGarrett.Damore@Sun.COM 	rtls_m_unicst,
1879286SGarrett.Damore@Sun.COM 	rtls_m_tx,
1889286SGarrett.Damore@Sun.COM 	NULL,		/* mc_ioctl */
189*11453Sgdamore@opensolaris.org 	NULL,		/* mc_getcapab */
190*11453Sgdamore@opensolaris.org 	NULL,		/* mc_open */
191*11453Sgdamore@opensolaris.org 	NULL,		/* mc_close */
192*11453Sgdamore@opensolaris.org 	rtls_m_setprop,
193*11453Sgdamore@opensolaris.org 	rtls_m_getprop,
194*11453Sgdamore@opensolaris.org };
195*11453Sgdamore@opensolaris.org 
196*11453Sgdamore@opensolaris.org static mii_ops_t rtls_mii_ops = {
197*11453Sgdamore@opensolaris.org 	MII_OPS_VERSION,
198*11453Sgdamore@opensolaris.org 	rtls_mii_read,
199*11453Sgdamore@opensolaris.org 	rtls_mii_write,
200*11453Sgdamore@opensolaris.org 	rtls_mii_notify,	/* notify */
201*11453Sgdamore@opensolaris.org 	NULL,			/* reset */
2029286SGarrett.Damore@Sun.COM };
2039286SGarrett.Damore@Sun.COM 
2049286SGarrett.Damore@Sun.COM DDI_DEFINE_STREAM_OPS(rtls_dev_ops, nulldev, nulldev, rtls_attach, rtls_detach,
2059286SGarrett.Damore@Sun.COM     nodev, NULL, D_MP, NULL, rtls_quiesce);
2069286SGarrett.Damore@Sun.COM 
2079286SGarrett.Damore@Sun.COM /*
2089286SGarrett.Damore@Sun.COM  * Standard module linkage initialization for a MAC driver
2099286SGarrett.Damore@Sun.COM  */
2109286SGarrett.Damore@Sun.COM static struct modldrv rtls_modldrv = {
2119286SGarrett.Damore@Sun.COM 	&mod_driverops,	/* type of module. This one is a driver */
2129286SGarrett.Damore@Sun.COM 	rtls_ident,	/* short description */
2139286SGarrett.Damore@Sun.COM 	&rtls_dev_ops	/* driver specific ops */
2149286SGarrett.Damore@Sun.COM };
2159286SGarrett.Damore@Sun.COM 
2169286SGarrett.Damore@Sun.COM static struct modlinkage modlinkage = {
2179286SGarrett.Damore@Sun.COM 	MODREV_1, { (void *)&rtls_modldrv, NULL }
2189286SGarrett.Damore@Sun.COM };
2199286SGarrett.Damore@Sun.COM 
2209286SGarrett.Damore@Sun.COM /*
2219286SGarrett.Damore@Sun.COM  *    ========== RealTek chip register access Routines ==========
2229286SGarrett.Damore@Sun.COM  */
2239286SGarrett.Damore@Sun.COM static uint8_t rtls_reg_get8(rtls_t *rtlsp, uint32_t reg);
2249286SGarrett.Damore@Sun.COM #pragma	inline(rtls_reg_get8)
2259286SGarrett.Damore@Sun.COM static uint8_t
2269286SGarrett.Damore@Sun.COM rtls_reg_get8(rtls_t *rtlsp, uint32_t reg)
2279286SGarrett.Damore@Sun.COM {
2289286SGarrett.Damore@Sun.COM 	uint8_t *addr;
2299286SGarrett.Damore@Sun.COM 
2309286SGarrett.Damore@Sun.COM 	addr = REG8(rtlsp->io_reg, reg);
2319286SGarrett.Damore@Sun.COM 	return (ddi_get8(rtlsp->io_handle, addr));
2329286SGarrett.Damore@Sun.COM }
2339286SGarrett.Damore@Sun.COM 
2349286SGarrett.Damore@Sun.COM static uint16_t rtls_reg_get16(rtls_t *rtlsp, uint32_t reg);
2359286SGarrett.Damore@Sun.COM #pragma	inline(rtls_reg_get16)
2369286SGarrett.Damore@Sun.COM static uint16_t
2379286SGarrett.Damore@Sun.COM rtls_reg_get16(rtls_t *rtlsp, uint32_t reg)
2389286SGarrett.Damore@Sun.COM {
2399286SGarrett.Damore@Sun.COM 	uint16_t *addr;
2409286SGarrett.Damore@Sun.COM 
2419286SGarrett.Damore@Sun.COM 	addr = REG16(rtlsp->io_reg, reg);
2429286SGarrett.Damore@Sun.COM 	return (ddi_get16(rtlsp->io_handle, addr));
2439286SGarrett.Damore@Sun.COM }
2449286SGarrett.Damore@Sun.COM 
2459286SGarrett.Damore@Sun.COM static uint32_t rtls_reg_get32(rtls_t *rtlsp, uint32_t reg);
2469286SGarrett.Damore@Sun.COM #pragma	inline(rtls_reg_get32)
2479286SGarrett.Damore@Sun.COM static uint32_t
2489286SGarrett.Damore@Sun.COM rtls_reg_get32(rtls_t *rtlsp, uint32_t reg)
2499286SGarrett.Damore@Sun.COM {
2509286SGarrett.Damore@Sun.COM 	uint32_t *addr;
2519286SGarrett.Damore@Sun.COM 
2529286SGarrett.Damore@Sun.COM 	addr = REG32(rtlsp->io_reg, reg);
2539286SGarrett.Damore@Sun.COM 	return (ddi_get32(rtlsp->io_handle, addr));
2549286SGarrett.Damore@Sun.COM }
2559286SGarrett.Damore@Sun.COM 
2569286SGarrett.Damore@Sun.COM static void rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value);
2579286SGarrett.Damore@Sun.COM #pragma	inline(rtls_reg_set8)
2589286SGarrett.Damore@Sun.COM static void
2599286SGarrett.Damore@Sun.COM rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value)
2609286SGarrett.Damore@Sun.COM {
2619286SGarrett.Damore@Sun.COM 	uint8_t *addr;
2629286SGarrett.Damore@Sun.COM 
2639286SGarrett.Damore@Sun.COM 	addr = REG8(rtlsp->io_reg, reg);
2649286SGarrett.Damore@Sun.COM 	ddi_put8(rtlsp->io_handle, addr, value);
2659286SGarrett.Damore@Sun.COM }
2669286SGarrett.Damore@Sun.COM 
2679286SGarrett.Damore@Sun.COM static void rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value);
2689286SGarrett.Damore@Sun.COM #pragma	inline(rtls_reg_set16)
2699286SGarrett.Damore@Sun.COM static void
2709286SGarrett.Damore@Sun.COM rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value)
2719286SGarrett.Damore@Sun.COM {
2729286SGarrett.Damore@Sun.COM 	uint16_t *addr;
2739286SGarrett.Damore@Sun.COM 
2749286SGarrett.Damore@Sun.COM 	addr = REG16(rtlsp->io_reg, reg);
2759286SGarrett.Damore@Sun.COM 	ddi_put16(rtlsp->io_handle, addr, value);
2769286SGarrett.Damore@Sun.COM }
2779286SGarrett.Damore@Sun.COM 
2789286SGarrett.Damore@Sun.COM static void rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value);
2799286SGarrett.Damore@Sun.COM #pragma	inline(rtls_reg_set32)
2809286SGarrett.Damore@Sun.COM static void
2819286SGarrett.Damore@Sun.COM rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value)
2829286SGarrett.Damore@Sun.COM {
2839286SGarrett.Damore@Sun.COM 	uint32_t *addr;
2849286SGarrett.Damore@Sun.COM 
2859286SGarrett.Damore@Sun.COM 	addr = REG32(rtlsp->io_reg, reg);
2869286SGarrett.Damore@Sun.COM 	ddi_put32(rtlsp->io_handle, addr, value);
2879286SGarrett.Damore@Sun.COM }
2889286SGarrett.Damore@Sun.COM 
2899286SGarrett.Damore@Sun.COM /*
2909286SGarrett.Damore@Sun.COM  *    ========== Module Loading Entry Points ==========
2919286SGarrett.Damore@Sun.COM  */
2929286SGarrett.Damore@Sun.COM int
2939286SGarrett.Damore@Sun.COM _init(void)
2949286SGarrett.Damore@Sun.COM {
2959286SGarrett.Damore@Sun.COM 	int	rv;
2969286SGarrett.Damore@Sun.COM 
2979286SGarrett.Damore@Sun.COM 	mac_init_ops(&rtls_dev_ops, RTLS_DRIVER_NAME);
2989286SGarrett.Damore@Sun.COM 	if ((rv = mod_install(&modlinkage)) != DDI_SUCCESS) {
2999286SGarrett.Damore@Sun.COM 		mac_fini_ops(&rtls_dev_ops);
3009286SGarrett.Damore@Sun.COM 	}
3019286SGarrett.Damore@Sun.COM 	return (rv);
3029286SGarrett.Damore@Sun.COM }
3039286SGarrett.Damore@Sun.COM 
3049286SGarrett.Damore@Sun.COM int
3059286SGarrett.Damore@Sun.COM _fini(void)
3069286SGarrett.Damore@Sun.COM {
3079286SGarrett.Damore@Sun.COM 	int	rv;
3089286SGarrett.Damore@Sun.COM 
3099286SGarrett.Damore@Sun.COM 	if ((rv = mod_remove(&modlinkage)) == DDI_SUCCESS) {
3109286SGarrett.Damore@Sun.COM 		mac_fini_ops(&rtls_dev_ops);
3119286SGarrett.Damore@Sun.COM 	}
3129286SGarrett.Damore@Sun.COM 	return (rv);
3139286SGarrett.Damore@Sun.COM }
3149286SGarrett.Damore@Sun.COM 
3159286SGarrett.Damore@Sun.COM int
3169286SGarrett.Damore@Sun.COM _info(struct modinfo *modinfop)
3179286SGarrett.Damore@Sun.COM {
3189286SGarrett.Damore@Sun.COM 	return (mod_info(&modlinkage, modinfop));
3199286SGarrett.Damore@Sun.COM }
3209286SGarrett.Damore@Sun.COM 
3219286SGarrett.Damore@Sun.COM 
3229286SGarrett.Damore@Sun.COM /*
3239286SGarrett.Damore@Sun.COM  *    ========== DDI Entry Points ==========
3249286SGarrett.Damore@Sun.COM  */
3259286SGarrett.Damore@Sun.COM 
3269286SGarrett.Damore@Sun.COM /*
3279286SGarrett.Damore@Sun.COM  * attach(9E) -- Attach a device to the system
3289286SGarrett.Damore@Sun.COM  *
3299286SGarrett.Damore@Sun.COM  * Called once for each board successfully probed.
3309286SGarrett.Damore@Sun.COM  */
3319286SGarrett.Damore@Sun.COM static int
3329286SGarrett.Damore@Sun.COM rtls_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3339286SGarrett.Damore@Sun.COM {
3349286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp;			/* Our private device info */
3359286SGarrett.Damore@Sun.COM 	ddi_acc_handle_t pci_handle;
3369286SGarrett.Damore@Sun.COM 	uint16_t pci_commond;
3379286SGarrett.Damore@Sun.COM 	uint16_t vendorid;
3389286SGarrett.Damore@Sun.COM 	uint16_t deviceid;
3399286SGarrett.Damore@Sun.COM 	uint32_t device;
3409286SGarrett.Damore@Sun.COM 	mac_register_t *macp;
3419286SGarrett.Damore@Sun.COM 	int err;
3429286SGarrett.Damore@Sun.COM 
3439286SGarrett.Damore@Sun.COM 	switch (cmd) {
3449286SGarrett.Damore@Sun.COM 	case DDI_ATTACH:
3459286SGarrett.Damore@Sun.COM 		break;
3469286SGarrett.Damore@Sun.COM 	case DDI_RESUME:
3479286SGarrett.Damore@Sun.COM 		if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) {
3489286SGarrett.Damore@Sun.COM 			return (DDI_FAILURE);
3499286SGarrett.Damore@Sun.COM 		}
3509286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_io_lock);
3519286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_rx_lock);
3529286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_tx_lock);
3539286SGarrett.Damore@Sun.COM 		/*
3549286SGarrett.Damore@Sun.COM 		 * Turn on Master Enable (DMA) and IO Enable bits.
3559286SGarrett.Damore@Sun.COM 		 * Enable PCI Memory Space accesses
3569286SGarrett.Damore@Sun.COM 		 * Disable Memory Write/Invalidate
3579286SGarrett.Damore@Sun.COM 		 */
3589286SGarrett.Damore@Sun.COM 		if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) {
3599286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_tx_lock);
3609286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_rx_lock);
3619286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_io_lock);
3629286SGarrett.Damore@Sun.COM 			return (DDI_FAILURE);
3639286SGarrett.Damore@Sun.COM 		}
3649286SGarrett.Damore@Sun.COM 		pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM);
3659286SGarrett.Damore@Sun.COM 		pci_commond &= ~PCI_COMM_MEMWR_INVAL;
3669286SGarrett.Damore@Sun.COM 		pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
3679286SGarrett.Damore@Sun.COM 		pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond);
3689286SGarrett.Damore@Sun.COM 		pci_config_teardown(&pci_handle);
3699286SGarrett.Damore@Sun.COM 
3709286SGarrett.Damore@Sun.COM 		rtls_chip_restart(rtlsp);
3719286SGarrett.Damore@Sun.COM 		rtlsp->chip_error = B_FALSE;
3729286SGarrett.Damore@Sun.COM 		rtlsp->tx_retry = 0;
3739286SGarrett.Damore@Sun.COM 		rtlsp->rtls_suspended = B_FALSE;
3749286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
3759286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_rx_lock);
3769286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_io_lock);
3779286SGarrett.Damore@Sun.COM 
378*11453Sgdamore@opensolaris.org 		mii_resume(rtlsp->mii);
379*11453Sgdamore@opensolaris.org 
3809286SGarrett.Damore@Sun.COM 		mac_tx_update(rtlsp->mh);
3819286SGarrett.Damore@Sun.COM 		return (DDI_SUCCESS);
3829286SGarrett.Damore@Sun.COM 	default:
3839286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
3849286SGarrett.Damore@Sun.COM 	}
3859286SGarrett.Damore@Sun.COM 
3869286SGarrett.Damore@Sun.COM 	/*
3879286SGarrett.Damore@Sun.COM 	 * we don't support high level interrupts in the driver
3889286SGarrett.Damore@Sun.COM 	 */
3899286SGarrett.Damore@Sun.COM 	if (ddi_intr_hilevel(devinfo, 0) != 0) {
390*11453Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "unsupported high level interrupt");
3919286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
3929286SGarrett.Damore@Sun.COM 	}
3939286SGarrett.Damore@Sun.COM 
3949286SGarrett.Damore@Sun.COM 	/*
3959286SGarrett.Damore@Sun.COM 	 * Get handle to access pci configuration space
3969286SGarrett.Damore@Sun.COM 	 */
3979286SGarrett.Damore@Sun.COM 	if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) {
398*11453Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "pci_config_setup fail.");
3999286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
4009286SGarrett.Damore@Sun.COM 	}
4019286SGarrett.Damore@Sun.COM 
4029286SGarrett.Damore@Sun.COM 	/*
4039286SGarrett.Damore@Sun.COM 	 * Make sure we support this particular vendor/device
4049286SGarrett.Damore@Sun.COM 	 */
4059286SGarrett.Damore@Sun.COM 	vendorid = pci_config_get16(pci_handle, PCI_CONF_VENID);
4069286SGarrett.Damore@Sun.COM 	deviceid = pci_config_get16(pci_handle, PCI_CONF_DEVID);
4079286SGarrett.Damore@Sun.COM 	device = vendorid;
4089286SGarrett.Damore@Sun.COM 	device = (device << 16) | deviceid;	/* combine two id together */
4099286SGarrett.Damore@Sun.COM 
4109286SGarrett.Damore@Sun.COM 	/*
4119286SGarrett.Damore@Sun.COM 	 * See if we support this device
4129286SGarrett.Damore@Sun.COM 	 * We do not return for wrong device id. It's user risk.
4139286SGarrett.Damore@Sun.COM 	 */
4149286SGarrett.Damore@Sun.COM 	switch (device) {
4159286SGarrett.Damore@Sun.COM 	default:
4169286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
417*11453Sgdamore@opensolaris.org 		    "RTLS doesn't support this device: "
4189286SGarrett.Damore@Sun.COM 		    "vendorID = 0x%x, deviceID = 0x%x",
4199286SGarrett.Damore@Sun.COM 		    vendorid, deviceid);
4209286SGarrett.Damore@Sun.COM 		break;
4219286SGarrett.Damore@Sun.COM 	case RTLS_SUPPORT_DEVICE_1:
4229286SGarrett.Damore@Sun.COM 	case RTLS_SUPPORT_DEVICE_2:
4239286SGarrett.Damore@Sun.COM 	case RTLS_SUPPORT_DEVICE_3:
424*11453Sgdamore@opensolaris.org 	case RTLS_SUPPORT_DEVICE_4:
4259286SGarrett.Damore@Sun.COM 		break;
4269286SGarrett.Damore@Sun.COM 	}
4279286SGarrett.Damore@Sun.COM 
4289286SGarrett.Damore@Sun.COM 	/*
4299286SGarrett.Damore@Sun.COM 	 * Turn on Master Enable (DMA) and IO Enable bits.
4309286SGarrett.Damore@Sun.COM 	 * Enable PCI Memory Space accesses
4319286SGarrett.Damore@Sun.COM 	 * Disable Memory Write/Invalidate
4329286SGarrett.Damore@Sun.COM 	 */
4339286SGarrett.Damore@Sun.COM 	pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM);
4349286SGarrett.Damore@Sun.COM 	pci_commond &= ~PCI_COMM_MEMWR_INVAL;
4359286SGarrett.Damore@Sun.COM 	pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
4369286SGarrett.Damore@Sun.COM 	pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond);
4379286SGarrett.Damore@Sun.COM 
4389286SGarrett.Damore@Sun.COM 	/*
4399286SGarrett.Damore@Sun.COM 	 * Free handle to access pci configuration space
4409286SGarrett.Damore@Sun.COM 	 */
4419286SGarrett.Damore@Sun.COM 	pci_config_teardown(&pci_handle);
4429286SGarrett.Damore@Sun.COM 
4439286SGarrett.Damore@Sun.COM 	rtlsp = kmem_zalloc(sizeof (rtls_t), KM_SLEEP);
4449286SGarrett.Damore@Sun.COM 
4459286SGarrett.Damore@Sun.COM 	ddi_set_driver_private(devinfo, rtlsp);
4469286SGarrett.Damore@Sun.COM 	rtlsp->devinfo			= devinfo;
4479286SGarrett.Damore@Sun.COM 	rtlsp->instance			= ddi_get_instance(devinfo);
4489286SGarrett.Damore@Sun.COM 
4499286SGarrett.Damore@Sun.COM 	/*
4509286SGarrett.Damore@Sun.COM 	 * Map operating register
4519286SGarrett.Damore@Sun.COM 	 */
4529286SGarrett.Damore@Sun.COM 	err = ddi_regs_map_setup(devinfo, 1, &rtlsp->io_reg,
4539286SGarrett.Damore@Sun.COM 	    (offset_t)0, 0, &rtls_reg_accattr, &rtlsp->io_handle);
4549286SGarrett.Damore@Sun.COM 	if (err != DDI_SUCCESS) {
4559286SGarrett.Damore@Sun.COM 		kmem_free((caddr_t)rtlsp, sizeof (rtls_t));
456*11453Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "ddi_regs_map_setup fail.");
4579286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
4589286SGarrett.Damore@Sun.COM 	}
4599286SGarrett.Damore@Sun.COM 
4609286SGarrett.Damore@Sun.COM 	/*
4619286SGarrett.Damore@Sun.COM 	 * Allocate the TX and RX descriptors/buffers
4629286SGarrett.Damore@Sun.COM 	 */
4639286SGarrett.Damore@Sun.COM 	if (rtls_alloc_bufs(rtlsp) == DDI_FAILURE) {
464*11453Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "DMA buffer allocation fail.");
4659286SGarrett.Damore@Sun.COM 		goto fail;
4669286SGarrett.Damore@Sun.COM 	}
4679286SGarrett.Damore@Sun.COM 
4689286SGarrett.Damore@Sun.COM 	/*
4699286SGarrett.Damore@Sun.COM 	 * Reset the chip
4709286SGarrett.Damore@Sun.COM 	 */
4719286SGarrett.Damore@Sun.COM 	err = rtls_chip_reset(rtlsp, B_FALSE);
4729286SGarrett.Damore@Sun.COM 	if (err != DDI_SUCCESS)
4739286SGarrett.Damore@Sun.COM 		goto fail;
4749286SGarrett.Damore@Sun.COM 
4759286SGarrett.Damore@Sun.COM 	/*
4769286SGarrett.Damore@Sun.COM 	 * Init rtls_t structure
4779286SGarrett.Damore@Sun.COM 	 */
4789286SGarrett.Damore@Sun.COM 	rtls_get_mac_addr(rtlsp, rtlsp->netaddr);
4799286SGarrett.Damore@Sun.COM 
4809286SGarrett.Damore@Sun.COM 	/*
4819286SGarrett.Damore@Sun.COM 	 * Add the interrupt handler
4829286SGarrett.Damore@Sun.COM 	 *
4839286SGarrett.Damore@Sun.COM 	 * This will prevent receiving interrupts before device is ready, as
4849286SGarrett.Damore@Sun.COM 	 * we are initializing device after setting the interrupts. So we
4859286SGarrett.Damore@Sun.COM 	 * will not get our interrupt handler invoked by OS while our device
4869286SGarrett.Damore@Sun.COM 	 * is still coming up or timer routines will not start till we are
4879286SGarrett.Damore@Sun.COM 	 * all set to process...
4889286SGarrett.Damore@Sun.COM 	 */
4899286SGarrett.Damore@Sun.COM 
4909286SGarrett.Damore@Sun.COM 	if (ddi_add_intr(devinfo, 0, &rtlsp->iblk, NULL, rtls_intr,
4919286SGarrett.Damore@Sun.COM 	    (caddr_t)rtlsp) != DDI_SUCCESS) {
492*11453Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "ddi_add_intr fail.");
4939286SGarrett.Damore@Sun.COM 		goto late_fail;
4949286SGarrett.Damore@Sun.COM 	}
4959286SGarrett.Damore@Sun.COM 
496*11453Sgdamore@opensolaris.org 	if ((rtlsp->mii = mii_alloc(rtlsp, devinfo, &rtls_mii_ops)) == NULL) {
497*11453Sgdamore@opensolaris.org 		ddi_remove_intr(devinfo, 0, rtlsp->iblk);
498*11453Sgdamore@opensolaris.org 		goto late_fail;
499*11453Sgdamore@opensolaris.org 	}
500*11453Sgdamore@opensolaris.org 	/*
501*11453Sgdamore@opensolaris.org 	 * Note: Some models of 8139 can support pause, but we have
502*11453Sgdamore@opensolaris.org 	 * not implemented support for it at this time.  This might be
503*11453Sgdamore@opensolaris.org 	 * an interesting feature to add later.
504*11453Sgdamore@opensolaris.org 	 */
505*11453Sgdamore@opensolaris.org 	mii_set_pauseable(rtlsp->mii, B_FALSE, B_FALSE);
506*11453Sgdamore@opensolaris.org 
5079286SGarrett.Damore@Sun.COM 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
508*11453Sgdamore@opensolaris.org 		cmn_err(CE_WARN, "mac_alloc fail.");
5099286SGarrett.Damore@Sun.COM 		ddi_remove_intr(devinfo, 0, rtlsp->iblk);
5109286SGarrett.Damore@Sun.COM 		goto late_fail;
5119286SGarrett.Damore@Sun.COM 	}
5129286SGarrett.Damore@Sun.COM 
5139286SGarrett.Damore@Sun.COM 	/*
5149286SGarrett.Damore@Sun.COM 	 * Init mutex
5159286SGarrett.Damore@Sun.COM 	 */
5169286SGarrett.Damore@Sun.COM 	mutex_init(&rtlsp->rtls_io_lock, NULL, MUTEX_DRIVER, rtlsp->iblk);
5179286SGarrett.Damore@Sun.COM 	mutex_init(&rtlsp->rtls_tx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk);
5189286SGarrett.Damore@Sun.COM 	mutex_init(&rtlsp->rtls_rx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk);
5199286SGarrett.Damore@Sun.COM 
5209286SGarrett.Damore@Sun.COM 	/*
5219286SGarrett.Damore@Sun.COM 	 * Initialize pointers to device specific functions which will be
5229286SGarrett.Damore@Sun.COM 	 * used by the generic layer.
5239286SGarrett.Damore@Sun.COM 	 */
5249286SGarrett.Damore@Sun.COM 	macp->m_type_ident		= MAC_PLUGIN_IDENT_ETHER;
5259286SGarrett.Damore@Sun.COM 	macp->m_driver			= rtlsp;
5269286SGarrett.Damore@Sun.COM 	macp->m_dip			= devinfo;
5279286SGarrett.Damore@Sun.COM 	macp->m_src_addr		= rtlsp->netaddr;
5289286SGarrett.Damore@Sun.COM 	macp->m_callbacks		= &rtls_m_callbacks;
5299286SGarrett.Damore@Sun.COM 	macp->m_min_sdu			= 0;
5309286SGarrett.Damore@Sun.COM 	macp->m_max_sdu			= ETHERMTU;
5319286SGarrett.Damore@Sun.COM 	macp->m_margin			= VLAN_TAGSZ;
5329286SGarrett.Damore@Sun.COM 
5339286SGarrett.Damore@Sun.COM 	if (mac_register(macp, &rtlsp->mh) != 0) {
5349286SGarrett.Damore@Sun.COM 		ddi_remove_intr(devinfo, 0, rtlsp->iblk);
5359286SGarrett.Damore@Sun.COM 		mutex_destroy(&rtlsp->rtls_io_lock);
5369286SGarrett.Damore@Sun.COM 		mutex_destroy(&rtlsp->rtls_tx_lock);
5379286SGarrett.Damore@Sun.COM 		mutex_destroy(&rtlsp->rtls_rx_lock);
5389286SGarrett.Damore@Sun.COM 		goto late_fail;
5399286SGarrett.Damore@Sun.COM 	}
5409286SGarrett.Damore@Sun.COM 
5419286SGarrett.Damore@Sun.COM 	mac_free(macp);
5429286SGarrett.Damore@Sun.COM 
5439286SGarrett.Damore@Sun.COM 	return (DDI_SUCCESS);
5449286SGarrett.Damore@Sun.COM 
5459286SGarrett.Damore@Sun.COM late_fail:
5469286SGarrett.Damore@Sun.COM 	if (macp)
5479286SGarrett.Damore@Sun.COM 		mac_free(macp);
548*11453Sgdamore@opensolaris.org 	if (rtlsp->mii)
549*11453Sgdamore@opensolaris.org 		mii_free(rtlsp->mii);
5509286SGarrett.Damore@Sun.COM 
5519286SGarrett.Damore@Sun.COM fail:
5529286SGarrett.Damore@Sun.COM 	ddi_regs_map_free(&rtlsp->io_handle);
5539286SGarrett.Damore@Sun.COM 	rtls_free_bufs(rtlsp);
5549286SGarrett.Damore@Sun.COM 	kmem_free(rtlsp, sizeof (rtls_t));
5559286SGarrett.Damore@Sun.COM 
5569286SGarrett.Damore@Sun.COM 	return (DDI_FAILURE);
5579286SGarrett.Damore@Sun.COM }
5589286SGarrett.Damore@Sun.COM 
5599286SGarrett.Damore@Sun.COM /*
5609286SGarrett.Damore@Sun.COM  * detach(9E) -- Detach a device from the system
5619286SGarrett.Damore@Sun.COM  */
5629286SGarrett.Damore@Sun.COM static int
5639286SGarrett.Damore@Sun.COM rtls_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
5649286SGarrett.Damore@Sun.COM {
5659286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp;			/* our private device info */
5669286SGarrett.Damore@Sun.COM 
5679286SGarrett.Damore@Sun.COM 	/*
5689286SGarrett.Damore@Sun.COM 	 * Get the driver private structure
5699286SGarrett.Damore@Sun.COM 	 */
5709286SGarrett.Damore@Sun.COM 	if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) {
5719286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
5729286SGarrett.Damore@Sun.COM 	}
5739286SGarrett.Damore@Sun.COM 
5749286SGarrett.Damore@Sun.COM 	switch (cmd) {
5759286SGarrett.Damore@Sun.COM 	case DDI_DETACH:
5769286SGarrett.Damore@Sun.COM 		break;
5779286SGarrett.Damore@Sun.COM 
5789286SGarrett.Damore@Sun.COM 	case DDI_SUSPEND:
579*11453Sgdamore@opensolaris.org 		mii_suspend(rtlsp->mii);
580*11453Sgdamore@opensolaris.org 
5819286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_io_lock);
5829286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_rx_lock);
5839286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_tx_lock);
5849286SGarrett.Damore@Sun.COM 
5859286SGarrett.Damore@Sun.COM 		rtlsp->rtls_suspended = B_TRUE;
5869286SGarrett.Damore@Sun.COM 		rtls_chip_stop(rtlsp);
5879286SGarrett.Damore@Sun.COM 
5889286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
5899286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_rx_lock);
5909286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_io_lock);
5919286SGarrett.Damore@Sun.COM 		return (DDI_SUCCESS);
5929286SGarrett.Damore@Sun.COM 
5939286SGarrett.Damore@Sun.COM 	default:
5949286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
5959286SGarrett.Damore@Sun.COM 	}
5969286SGarrett.Damore@Sun.COM 
5979286SGarrett.Damore@Sun.COM 	if (mac_unregister(rtlsp->mh) != 0) {
5989286SGarrett.Damore@Sun.COM 		/* device busy */
5999286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
6009286SGarrett.Damore@Sun.COM 	}
6019286SGarrett.Damore@Sun.COM 
6029286SGarrett.Damore@Sun.COM 	ddi_remove_intr(devinfo, 0, rtlsp->iblk);
6039286SGarrett.Damore@Sun.COM 
604*11453Sgdamore@opensolaris.org 	mii_free(rtlsp->mii);
6059286SGarrett.Damore@Sun.COM 
6069286SGarrett.Damore@Sun.COM 	mutex_destroy(&rtlsp->rtls_io_lock);
6079286SGarrett.Damore@Sun.COM 	mutex_destroy(&rtlsp->rtls_tx_lock);
6089286SGarrett.Damore@Sun.COM 	mutex_destroy(&rtlsp->rtls_rx_lock);
6099286SGarrett.Damore@Sun.COM 
6109286SGarrett.Damore@Sun.COM 	ddi_regs_map_free(&rtlsp->io_handle);
6119286SGarrett.Damore@Sun.COM 	rtls_free_bufs(rtlsp);
6129286SGarrett.Damore@Sun.COM 	kmem_free(rtlsp, sizeof (rtls_t));
6139286SGarrett.Damore@Sun.COM 
6149286SGarrett.Damore@Sun.COM 	return (DDI_SUCCESS);
6159286SGarrett.Damore@Sun.COM }
6169286SGarrett.Damore@Sun.COM 
6179286SGarrett.Damore@Sun.COM /*
6189286SGarrett.Damore@Sun.COM  * quiesce(9E) entry point.
6199286SGarrett.Damore@Sun.COM  *
6209286SGarrett.Damore@Sun.COM  * This function is called when the system is single-threaded at high
6219286SGarrett.Damore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
6229286SGarrett.Damore@Sun.COM  * blocked.
6239286SGarrett.Damore@Sun.COM  *
6249286SGarrett.Damore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
6259286SGarrett.Damore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
6269286SGarrett.Damore@Sun.COM  */
6279286SGarrett.Damore@Sun.COM static int
6289286SGarrett.Damore@Sun.COM rtls_quiesce(dev_info_t *devinfo)
6299286SGarrett.Damore@Sun.COM {
6309286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp;			/* our private device info */
6319286SGarrett.Damore@Sun.COM 
6329286SGarrett.Damore@Sun.COM 	/*
6339286SGarrett.Damore@Sun.COM 	 * Get the driver private structure
6349286SGarrett.Damore@Sun.COM 	 */
6359286SGarrett.Damore@Sun.COM 	if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) {
6369286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
6379286SGarrett.Damore@Sun.COM 	}
6389286SGarrett.Damore@Sun.COM 	return (rtls_chip_reset(rtlsp, B_TRUE));
6399286SGarrett.Damore@Sun.COM }
6409286SGarrett.Damore@Sun.COM 
6419286SGarrett.Damore@Sun.COM /*
6429286SGarrett.Damore@Sun.COM  *    ========== MAC Entry Points ==========
6439286SGarrett.Damore@Sun.COM  */
6449286SGarrett.Damore@Sun.COM 
6459286SGarrett.Damore@Sun.COM /*
6469286SGarrett.Damore@Sun.COM  * rtls_m_start() -- start the board receiving and allow transmits
6479286SGarrett.Damore@Sun.COM  */
6489286SGarrett.Damore@Sun.COM static int
6499286SGarrett.Damore@Sun.COM rtls_m_start(void *arg)
6509286SGarrett.Damore@Sun.COM {
6519286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = (rtls_t *)arg;
6529286SGarrett.Damore@Sun.COM 
6539286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_io_lock);
6549286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_rx_lock);
6559286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_tx_lock);
6569286SGarrett.Damore@Sun.COM 
6579286SGarrett.Damore@Sun.COM 	if (!rtlsp->rtls_suspended)
6589286SGarrett.Damore@Sun.COM 		rtls_chip_restart(rtlsp);
6599286SGarrett.Damore@Sun.COM 
6609286SGarrett.Damore@Sun.COM 	rtlsp->rtls_running = B_TRUE;
6619286SGarrett.Damore@Sun.COM 
6629286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_tx_lock);
6639286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_rx_lock);
6649286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_io_lock);
6659286SGarrett.Damore@Sun.COM 
666*11453Sgdamore@opensolaris.org 	drv_usecwait(100);
667*11453Sgdamore@opensolaris.org 
668*11453Sgdamore@opensolaris.org 	mii_start(rtlsp->mii);
669*11453Sgdamore@opensolaris.org 
6709286SGarrett.Damore@Sun.COM 	return (0);
6719286SGarrett.Damore@Sun.COM }
6729286SGarrett.Damore@Sun.COM 
6739286SGarrett.Damore@Sun.COM /*
6749286SGarrett.Damore@Sun.COM  * rtls_m_stop() -- stop board receiving and transmits
6759286SGarrett.Damore@Sun.COM  */
6769286SGarrett.Damore@Sun.COM static void
6779286SGarrett.Damore@Sun.COM rtls_m_stop(void *arg)
6789286SGarrett.Damore@Sun.COM {
6799286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = (rtls_t *)arg;
6809286SGarrett.Damore@Sun.COM 
681*11453Sgdamore@opensolaris.org 	mii_stop(rtlsp->mii);
682*11453Sgdamore@opensolaris.org 
6839286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_io_lock);
6849286SGarrett.Damore@Sun.COM 
6859286SGarrett.Damore@Sun.COM 	if (!rtlsp->rtls_suspended)
6869286SGarrett.Damore@Sun.COM 		rtls_chip_stop(rtlsp);
6879286SGarrett.Damore@Sun.COM 	rtlsp->rtls_running = B_FALSE;
6889286SGarrett.Damore@Sun.COM 
6899286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_io_lock);
6909286SGarrett.Damore@Sun.COM }
6919286SGarrett.Damore@Sun.COM 
6929286SGarrett.Damore@Sun.COM /*
6939286SGarrett.Damore@Sun.COM  * rtls_m_unicst() -- set the physical network address
6949286SGarrett.Damore@Sun.COM  * on the board
6959286SGarrett.Damore@Sun.COM  */
6969286SGarrett.Damore@Sun.COM static int
6979286SGarrett.Damore@Sun.COM rtls_m_unicst(void *arg, const uint8_t *macaddr)
6989286SGarrett.Damore@Sun.COM {
6999286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = arg;
7009286SGarrett.Damore@Sun.COM 
7019286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_io_lock);
7029286SGarrett.Damore@Sun.COM 	bcopy(macaddr, rtlsp->netaddr, ETHERADDRL);
7039286SGarrett.Damore@Sun.COM 	if (!rtlsp->rtls_suspended)
7049286SGarrett.Damore@Sun.COM 		rtls_set_mac_addr(rtlsp, rtlsp->netaddr);
7059286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_io_lock);
7069286SGarrett.Damore@Sun.COM 	return (0);
7079286SGarrett.Damore@Sun.COM }
7089286SGarrett.Damore@Sun.COM 
7099286SGarrett.Damore@Sun.COM /*
7109286SGarrett.Damore@Sun.COM  * rtls_m_multicst() -- set(enable) or disable a multicast address
7119286SGarrett.Damore@Sun.COM  *
7129286SGarrett.Damore@Sun.COM  * Program the hardware to enable/disable the multicast address in "mcast".
7139286SGarrett.Damore@Sun.COM  */
7149286SGarrett.Damore@Sun.COM static int
7159286SGarrett.Damore@Sun.COM rtls_m_multicst(void *arg, boolean_t enable, const uint8_t *mcast)
7169286SGarrett.Damore@Sun.COM {
7179286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = (rtls_t *)arg;
7189286SGarrett.Damore@Sun.COM 	uint_t index;
7199286SGarrett.Damore@Sun.COM 	uint32_t *hashp;
7209286SGarrett.Damore@Sun.COM 
7219286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_io_lock);
7229286SGarrett.Damore@Sun.COM 	hashp = rtlsp->multi_hash;
7239286SGarrett.Damore@Sun.COM 	index = rtls_hash_index(mcast);
7249286SGarrett.Damore@Sun.COM 			/* index value is between 0 and 63 */
7259286SGarrett.Damore@Sun.COM 
7269286SGarrett.Damore@Sun.COM 	if (enable) {
7279286SGarrett.Damore@Sun.COM 		if (rtlsp->multicast_cnt[index]++) {
7289286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_io_lock);
7299286SGarrett.Damore@Sun.COM 			return (0);
7309286SGarrett.Damore@Sun.COM 		}
7319286SGarrett.Damore@Sun.COM 		hashp[index/32] |= 1<< (index % 32);
7329286SGarrett.Damore@Sun.COM 	} else {
7339286SGarrett.Damore@Sun.COM 		if (--rtlsp->multicast_cnt[index]) {
7349286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_io_lock);
7359286SGarrett.Damore@Sun.COM 			return (0);
7369286SGarrett.Damore@Sun.COM 		}
7379286SGarrett.Damore@Sun.COM 		hashp[index/32] &= ~(1<< (index % 32));
7389286SGarrett.Damore@Sun.COM 	}
7399286SGarrett.Damore@Sun.COM 
7409286SGarrett.Damore@Sun.COM 	/*
7419286SGarrett.Damore@Sun.COM 	 * Set multicast register
7429286SGarrett.Damore@Sun.COM 	 */
7439286SGarrett.Damore@Sun.COM 	if (!rtlsp->rtls_suspended) {
7449286SGarrett.Damore@Sun.COM 		rtls_reg_set32(rtlsp, MULTICAST_0_REG, hashp[0]);
7459286SGarrett.Damore@Sun.COM 		rtls_reg_set32(rtlsp, MULTICAST_4_REG, hashp[1]);
7469286SGarrett.Damore@Sun.COM 	}
7479286SGarrett.Damore@Sun.COM 
7489286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_io_lock);
7499286SGarrett.Damore@Sun.COM 
7509286SGarrett.Damore@Sun.COM 	return (0);
7519286SGarrett.Damore@Sun.COM }
7529286SGarrett.Damore@Sun.COM 
7539286SGarrett.Damore@Sun.COM /*
7549286SGarrett.Damore@Sun.COM  * rtls_hash_index() -- a hashing function used for setting the
7559286SGarrett.Damore@Sun.COM  * node address or a multicast address
7569286SGarrett.Damore@Sun.COM  */
7579286SGarrett.Damore@Sun.COM static uint_t
7589286SGarrett.Damore@Sun.COM rtls_hash_index(const uint8_t *address)
7599286SGarrett.Damore@Sun.COM {
7609286SGarrett.Damore@Sun.COM 	uint32_t crc = (ulong_t)RTLS_HASH_CRC;
7619286SGarrett.Damore@Sun.COM 	uint32_t const POLY = RTLS_HASH_POLY;
7629286SGarrett.Damore@Sun.COM 	uint32_t msb;
7639286SGarrett.Damore@Sun.COM 	int bytes;
7649286SGarrett.Damore@Sun.COM 	uchar_t currentbyte;
7659286SGarrett.Damore@Sun.COM 	uint_t index;
7669286SGarrett.Damore@Sun.COM 	int bit;
7679286SGarrett.Damore@Sun.COM 
7689286SGarrett.Damore@Sun.COM 	for (bytes = 0; bytes < ETHERADDRL; bytes++) {
7699286SGarrett.Damore@Sun.COM 		currentbyte = address[bytes];
7709286SGarrett.Damore@Sun.COM 		for (bit = 0; bit < 8; bit++) {
7719286SGarrett.Damore@Sun.COM 			msb = crc >> 31;
7729286SGarrett.Damore@Sun.COM 			crc <<= 1;
7739286SGarrett.Damore@Sun.COM 			if (msb ^ (currentbyte & 1)) {
7749286SGarrett.Damore@Sun.COM 				crc ^= POLY;
7759286SGarrett.Damore@Sun.COM 				crc |= 0x00000001;
7769286SGarrett.Damore@Sun.COM 			}
7779286SGarrett.Damore@Sun.COM 			currentbyte >>= 1;
7789286SGarrett.Damore@Sun.COM 		}
7799286SGarrett.Damore@Sun.COM 	}
7809286SGarrett.Damore@Sun.COM 
7819286SGarrett.Damore@Sun.COM 	index = crc >> 26;
7829286SGarrett.Damore@Sun.COM 
7839286SGarrett.Damore@Sun.COM 	return (index);
7849286SGarrett.Damore@Sun.COM }
7859286SGarrett.Damore@Sun.COM 
7869286SGarrett.Damore@Sun.COM /*
7879286SGarrett.Damore@Sun.COM  * rtls_m_promisc() -- set or reset promiscuous mode on the board
7889286SGarrett.Damore@Sun.COM  */
7899286SGarrett.Damore@Sun.COM static int
7909286SGarrett.Damore@Sun.COM rtls_m_promisc(void *arg, boolean_t on)
7919286SGarrett.Damore@Sun.COM {
7929286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = arg;
7939286SGarrett.Damore@Sun.COM 
7949286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_io_lock);
7959286SGarrett.Damore@Sun.COM 
7969286SGarrett.Damore@Sun.COM 	rtlsp->promisc = on;
7979286SGarrett.Damore@Sun.COM 	if (!rtlsp->rtls_suspended) {
7989286SGarrett.Damore@Sun.COM 		uint32_t val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG);
7999286SGarrett.Damore@Sun.COM 		if (on) {
8009286SGarrett.Damore@Sun.COM 			val32 |= RX_ACCEPT_ALL_PACKET;
8019286SGarrett.Damore@Sun.COM 		} else {
8029286SGarrett.Damore@Sun.COM 			val32 &= ~RX_ACCEPT_ALL_PACKET;
8039286SGarrett.Damore@Sun.COM 		}
8049286SGarrett.Damore@Sun.COM 		rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32);
8059286SGarrett.Damore@Sun.COM 	}
8069286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_io_lock);
8079286SGarrett.Damore@Sun.COM 
8089286SGarrett.Damore@Sun.COM 	return (0);
8099286SGarrett.Damore@Sun.COM }
8109286SGarrett.Damore@Sun.COM 
8119286SGarrett.Damore@Sun.COM /*
8129286SGarrett.Damore@Sun.COM  * rtls_m_stat() -- retrieve statistic
8139286SGarrett.Damore@Sun.COM  *
8149286SGarrett.Damore@Sun.COM  * MAC calls this routine just before it reads the driver's statistics
8159286SGarrett.Damore@Sun.COM  * structure.  If your board maintains statistics, this is the time to
8169286SGarrett.Damore@Sun.COM  * read them in and update the values in the structure. If the driver
8179286SGarrett.Damore@Sun.COM  * maintains statistics continuously, this routine need do nothing.
8189286SGarrett.Damore@Sun.COM  */
8199286SGarrett.Damore@Sun.COM static int
8209286SGarrett.Damore@Sun.COM rtls_m_stat(void *arg, uint_t stat, uint64_t *val)
8219286SGarrett.Damore@Sun.COM {
8229286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = arg;
8239286SGarrett.Damore@Sun.COM 
824*11453Sgdamore@opensolaris.org 	if (mii_m_getstat(rtlsp->mii, stat, val) == 0) {
825*11453Sgdamore@opensolaris.org 		return (0);
8269286SGarrett.Damore@Sun.COM 	}
8279286SGarrett.Damore@Sun.COM 
8289286SGarrett.Damore@Sun.COM 	switch (stat) {
8299286SGarrett.Damore@Sun.COM 	case MAC_STAT_IPACKETS:
8309286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.ipackets;
8319286SGarrett.Damore@Sun.COM 		break;
8329286SGarrett.Damore@Sun.COM 	case MAC_STAT_RBYTES:
8339286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.rbytes;
8349286SGarrett.Damore@Sun.COM 		break;
8359286SGarrett.Damore@Sun.COM 	case MAC_STAT_OPACKETS:
8369286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.opackets;
8379286SGarrett.Damore@Sun.COM 		break;
8389286SGarrett.Damore@Sun.COM 	case MAC_STAT_OBYTES:
8399286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.obytes;
8409286SGarrett.Damore@Sun.COM 		break;
8419286SGarrett.Damore@Sun.COM 	case MAC_STAT_IERRORS:
8429286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.rcv_err;
8439286SGarrett.Damore@Sun.COM 		break;
8449286SGarrett.Damore@Sun.COM 	case MAC_STAT_OERRORS:
8459286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.xmt_err;
8469286SGarrett.Damore@Sun.COM 		break;
8479286SGarrett.Damore@Sun.COM 	case MAC_STAT_MULTIRCV:
8489286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.multi_rcv;
8499286SGarrett.Damore@Sun.COM 		break;
8509286SGarrett.Damore@Sun.COM 	case MAC_STAT_BRDCSTRCV:
8519286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.brdcst_rcv;
8529286SGarrett.Damore@Sun.COM 		break;
8539286SGarrett.Damore@Sun.COM 	case MAC_STAT_MULTIXMT:
8549286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.multi_xmt;
8559286SGarrett.Damore@Sun.COM 		break;
8569286SGarrett.Damore@Sun.COM 	case MAC_STAT_BRDCSTXMT:
8579286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.brdcst_xmt;
8589286SGarrett.Damore@Sun.COM 		break;
8599286SGarrett.Damore@Sun.COM 	case MAC_STAT_UNDERFLOWS:
8609286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.underflow;
8619286SGarrett.Damore@Sun.COM 		break;
8629286SGarrett.Damore@Sun.COM 	case MAC_STAT_OVERFLOWS:
8639286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.overflow;
8649286SGarrett.Damore@Sun.COM 		break;
8659286SGarrett.Damore@Sun.COM 	case MAC_STAT_NORCVBUF:
8669286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.no_rcvbuf;
8679286SGarrett.Damore@Sun.COM 		break;
8689286SGarrett.Damore@Sun.COM 	case MAC_STAT_COLLISIONS:
8699286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.collisions;
8709286SGarrett.Damore@Sun.COM 		break;
8719286SGarrett.Damore@Sun.COM 	case ETHER_STAT_FCS_ERRORS:
8729286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.crc_err;
8739286SGarrett.Damore@Sun.COM 		break;
8749286SGarrett.Damore@Sun.COM 	case ETHER_STAT_ALIGN_ERRORS:
8759286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.frame_err;
8769286SGarrett.Damore@Sun.COM 		break;
8779286SGarrett.Damore@Sun.COM 	case ETHER_STAT_DEFER_XMTS:
8789286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.defer;
8799286SGarrett.Damore@Sun.COM 		break;
8809286SGarrett.Damore@Sun.COM 	case ETHER_STAT_TX_LATE_COLLISIONS:
8819286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.xmt_latecoll;
8829286SGarrett.Damore@Sun.COM 		break;
8839286SGarrett.Damore@Sun.COM 	case ETHER_STAT_TOOLONG_ERRORS:
8849286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.too_long;
8859286SGarrett.Damore@Sun.COM 		break;
8869286SGarrett.Damore@Sun.COM 	case ETHER_STAT_TOOSHORT_ERRORS:
8879286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.in_short;
8889286SGarrett.Damore@Sun.COM 		break;
8899286SGarrett.Damore@Sun.COM 	case ETHER_STAT_CARRIER_ERRORS:
8909286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.no_carrier;
8919286SGarrett.Damore@Sun.COM 		break;
8929286SGarrett.Damore@Sun.COM 	case ETHER_STAT_FIRST_COLLISIONS:
8939286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.firstcol;
8949286SGarrett.Damore@Sun.COM 		break;
8959286SGarrett.Damore@Sun.COM 	case ETHER_STAT_MULTI_COLLISIONS:
8969286SGarrett.Damore@Sun.COM 		*val = rtlsp->stats.multicol;
8979286SGarrett.Damore@Sun.COM 		break;
8989286SGarrett.Damore@Sun.COM 	default:
8999286SGarrett.Damore@Sun.COM 		return (ENOTSUP);
9009286SGarrett.Damore@Sun.COM 	}
9019286SGarrett.Damore@Sun.COM 
9029286SGarrett.Damore@Sun.COM 	/*
9039286SGarrett.Damore@Sun.COM 	 * RTL8139 don't support MII statistics,
9049286SGarrett.Damore@Sun.COM 	 * these values are maintained by the driver software.
9059286SGarrett.Damore@Sun.COM 	 */
9069286SGarrett.Damore@Sun.COM 
9079286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
9089286SGarrett.Damore@Sun.COM 	if (rtls_debug & RTLS_TRACE)
9099286SGarrett.Damore@Sun.COM 		rtls_reg_print(rtlsp);
9109286SGarrett.Damore@Sun.COM #endif
9119286SGarrett.Damore@Sun.COM 
9129286SGarrett.Damore@Sun.COM 	return (0);
9139286SGarrett.Damore@Sun.COM }
9149286SGarrett.Damore@Sun.COM 
915*11453Sgdamore@opensolaris.org int
916*11453Sgdamore@opensolaris.org rtls_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags,
917*11453Sgdamore@opensolaris.org     uint_t sz, void *val, uint_t *perm)
918*11453Sgdamore@opensolaris.org {
919*11453Sgdamore@opensolaris.org 	rtls_t	*rtlsp = arg;
920*11453Sgdamore@opensolaris.org 
921*11453Sgdamore@opensolaris.org 	return (mii_m_getprop(rtlsp->mii, name, num, flags, sz, val, perm));
922*11453Sgdamore@opensolaris.org }
923*11453Sgdamore@opensolaris.org 
924*11453Sgdamore@opensolaris.org int
925*11453Sgdamore@opensolaris.org rtls_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
926*11453Sgdamore@opensolaris.org     const void *val)
927*11453Sgdamore@opensolaris.org {
928*11453Sgdamore@opensolaris.org 	rtls_t	*rtlsp = arg;
929*11453Sgdamore@opensolaris.org 
930*11453Sgdamore@opensolaris.org 	return (mii_m_setprop(rtlsp->mii, name, num, sz, val));
931*11453Sgdamore@opensolaris.org }
932*11453Sgdamore@opensolaris.org 
9339286SGarrett.Damore@Sun.COM /*
9349286SGarrett.Damore@Sun.COM  * rtls_send() -- send a packet
9359286SGarrett.Damore@Sun.COM  *
9369286SGarrett.Damore@Sun.COM  * Called when a packet is ready to be transmitted. A pointer to an
9379286SGarrett.Damore@Sun.COM  * M_DATA message that contains the packet is passed to this routine.
9389286SGarrett.Damore@Sun.COM  * The complete LLC header is contained in the message's first message
9399286SGarrett.Damore@Sun.COM  * block, and the remainder of the packet is contained within
9409286SGarrett.Damore@Sun.COM  * additional M_DATA message blocks linked to the first message block.
9419286SGarrett.Damore@Sun.COM  *
9429286SGarrett.Damore@Sun.COM  * Returns B_TRUE if the packet was properly disposed of, or B_FALSE if
9439286SGarrett.Damore@Sun.COM  * if the packet is being deferred and should be tried again later.
9449286SGarrett.Damore@Sun.COM  */
9459286SGarrett.Damore@Sun.COM 
9469286SGarrett.Damore@Sun.COM static boolean_t
9479286SGarrett.Damore@Sun.COM rtls_send(rtls_t *rtlsp, mblk_t *mp)
9489286SGarrett.Damore@Sun.COM {
9499286SGarrett.Damore@Sun.COM 	int totlen;
9509286SGarrett.Damore@Sun.COM 	int ncc;
9519286SGarrett.Damore@Sun.COM 	uint16_t cur_desc;
9529286SGarrett.Damore@Sun.COM 	uint32_t tx_status;
9539286SGarrett.Damore@Sun.COM 
9549286SGarrett.Damore@Sun.COM 	ASSERT(mp != NULL);
9559286SGarrett.Damore@Sun.COM 	ASSERT(rtlsp->rtls_running);
9569286SGarrett.Damore@Sun.COM 
9579286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_tx_lock);
9589286SGarrett.Damore@Sun.COM 
9599286SGarrett.Damore@Sun.COM 	if (rtlsp->rtls_suspended) {
9609286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
9619286SGarrett.Damore@Sun.COM 		return (B_FALSE);
9629286SGarrett.Damore@Sun.COM 	}
9639286SGarrett.Damore@Sun.COM 
9649286SGarrett.Damore@Sun.COM 	/*
9659286SGarrett.Damore@Sun.COM 	 * If chip error ...
9669286SGarrett.Damore@Sun.COM 	 */
9679286SGarrett.Damore@Sun.COM 	if (rtlsp->chip_error) {
9689286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
9699286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
9709286SGarrett.Damore@Sun.COM 		    "%s: send fail--CHIP ERROR!",
9719286SGarrett.Damore@Sun.COM 		    rtlsp->ifname);
9729286SGarrett.Damore@Sun.COM #endif
9739286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
9749286SGarrett.Damore@Sun.COM 		freemsg(mp);
9759286SGarrett.Damore@Sun.COM 		return (B_TRUE);
9769286SGarrett.Damore@Sun.COM 	}
9779286SGarrett.Damore@Sun.COM 
9789286SGarrett.Damore@Sun.COM 	/*
979*11453Sgdamore@opensolaris.org 	 * If chip link down ...  Note that experimentation shows that
980*11453Sgdamore@opensolaris.org 	 * the device seems not to care about whether or not we have
981*11453Sgdamore@opensolaris.org 	 * this check, but if we don't add the check here, it might
982*11453Sgdamore@opensolaris.org 	 * not be properly reported as a carrier error.
9839286SGarrett.Damore@Sun.COM 	 */
984*11453Sgdamore@opensolaris.org 	if (rtls_reg_get8(rtlsp, MEDIA_STATUS_REG) & MEDIA_STATUS_LINK) {
9859286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
9869286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
9879286SGarrett.Damore@Sun.COM 		    "%s: send fail--LINK DOWN!",
9889286SGarrett.Damore@Sun.COM 		    rtlsp->ifname);
9899286SGarrett.Damore@Sun.COM #endif
9909286SGarrett.Damore@Sun.COM 		rtlsp->stats.no_carrier++;
9919286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
9929286SGarrett.Damore@Sun.COM 		freemsg(mp);
9939286SGarrett.Damore@Sun.COM 		return (B_TRUE);
9949286SGarrett.Damore@Sun.COM 	}
9959286SGarrett.Damore@Sun.COM 
9969286SGarrett.Damore@Sun.COM 	/*
9979286SGarrett.Damore@Sun.COM 	 * Current transmit descriptor
9989286SGarrett.Damore@Sun.COM 	 */
9999286SGarrett.Damore@Sun.COM 	cur_desc = rtlsp->tx_current_desc;
10009286SGarrett.Damore@Sun.COM 	ASSERT(cur_desc < RTLS_MAX_TX_DESC);
10019286SGarrett.Damore@Sun.COM 
10029286SGarrett.Damore@Sun.COM 	/*
10039286SGarrett.Damore@Sun.COM 	 * RealTek 8139 has 4 tx descriptor for transmit. In the first tx loop
10049286SGarrett.Damore@Sun.COM 	 * of transmit,we needn't judge transmit status.
10059286SGarrett.Damore@Sun.COM 	 */
10069286SGarrett.Damore@Sun.COM 	if (rtlsp->tx_first_loop < RTLS_MAX_TX_DESC) {
10079286SGarrett.Damore@Sun.COM 		rtlsp->tx_first_loop++;
10089286SGarrett.Damore@Sun.COM 		goto tx_ready;
10099286SGarrett.Damore@Sun.COM 	}
10109286SGarrett.Damore@Sun.COM 
10119286SGarrett.Damore@Sun.COM 	/*
10129286SGarrett.Damore@Sun.COM 	 * If it's not the first tx loop, we need judge whether the chip is
10139286SGarrett.Damore@Sun.COM 	 * busy or not. Otherwise, we have to reschedule send and wait...
10149286SGarrett.Damore@Sun.COM 	 */
10159286SGarrett.Damore@Sun.COM 	tx_status = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc);
10169286SGarrett.Damore@Sun.COM 
10179286SGarrett.Damore@Sun.COM 	/*
10189286SGarrett.Damore@Sun.COM 	 * H/W doesn't complete packet transmit
10199286SGarrett.Damore@Sun.COM 	 */
10209286SGarrett.Damore@Sun.COM 	if (!(tx_status & TX_COMPLETE_FLAG)) {
10219286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
10229286SGarrett.Damore@Sun.COM 		if (rtls_debug & RTLS_SEND) {
10239286SGarrett.Damore@Sun.COM 			cmn_err(CE_NOTE,
10249286SGarrett.Damore@Sun.COM 			    "%s: rtls_send: need_sched", rtlsp->ifname);
10259286SGarrett.Damore@Sun.COM 		}
10269286SGarrett.Damore@Sun.COM #endif
10279286SGarrett.Damore@Sun.COM 		/*
10289286SGarrett.Damore@Sun.COM 		 * Through test, we find RTL8139 tx status might be
10299286SGarrett.Damore@Sun.COM 		 * not-completing all along. We have to reset chip
10309286SGarrett.Damore@Sun.COM 		 * to make RTL8139 tansmit re-work.
10319286SGarrett.Damore@Sun.COM 		 */
10329286SGarrett.Damore@Sun.COM 		if (rtlsp->tx_retry++ > RTLS_TX_RETRY_NUM) {
10339286SGarrett.Damore@Sun.COM 
10349286SGarrett.Damore@Sun.COM 			/*
10359286SGarrett.Damore@Sun.COM 			 * Wait transmit h/w more time...
10369286SGarrett.Damore@Sun.COM 			 */
10379286SGarrett.Damore@Sun.COM 			RTLS_TX_WAIT_TIMEOUT;	/* 100 ms */
10389286SGarrett.Damore@Sun.COM 
10399286SGarrett.Damore@Sun.COM 			/*
10409286SGarrett.Damore@Sun.COM 			 * Judge tx status again, if it remains not-completing,
10419286SGarrett.Damore@Sun.COM 			 * we can confirm RTL8139 is in chip error state
10429286SGarrett.Damore@Sun.COM 			 * and must reset it.
10439286SGarrett.Damore@Sun.COM 			 */
10449286SGarrett.Damore@Sun.COM 			tx_status = rtls_reg_get32(rtlsp,
10459286SGarrett.Damore@Sun.COM 			    TX_STATUS_DESC0_REG + 4 * cur_desc);
10469286SGarrett.Damore@Sun.COM 			if (!(tx_status & TX_COMPLETE_FLAG)) {
10479286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
10489286SGarrett.Damore@Sun.COM 				cmn_err(CE_NOTE, "%s: tx chip_error = 0x%x",
10499286SGarrett.Damore@Sun.COM 				    rtlsp->ifname, tx_status);
10509286SGarrett.Damore@Sun.COM #endif
10519286SGarrett.Damore@Sun.COM 				rtlsp->tx_retry = 0;
10529286SGarrett.Damore@Sun.COM 				rtlsp->chip_error = B_TRUE;
10539286SGarrett.Damore@Sun.COM 				rtlsp->stats.xmt_err++;
10549286SGarrett.Damore@Sun.COM 				rtlsp->stats.mac_xmt_err++;
10559286SGarrett.Damore@Sun.COM 				mutex_exit(&rtlsp->rtls_tx_lock);
10569286SGarrett.Damore@Sun.COM 				freemsg(mp);
10579286SGarrett.Damore@Sun.COM 				return (B_TRUE);
10589286SGarrett.Damore@Sun.COM 			}
10599286SGarrett.Damore@Sun.COM 		} else {
10609286SGarrett.Damore@Sun.COM 			rtlsp->stats.defer++;
10619286SGarrett.Damore@Sun.COM 			rtlsp->need_sched = B_TRUE;
10629286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_tx_lock);
10639286SGarrett.Damore@Sun.COM 			return (B_FALSE);
10649286SGarrett.Damore@Sun.COM 		}
10659286SGarrett.Damore@Sun.COM 	}
10669286SGarrett.Damore@Sun.COM 
10679286SGarrett.Damore@Sun.COM 	/*
10689286SGarrett.Damore@Sun.COM 	 * Transmit error?
10699286SGarrett.Damore@Sun.COM 	 */
10709286SGarrett.Damore@Sun.COM 	if (tx_status & TX_ERR_FLAG) {
10719286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
10729286SGarrett.Damore@Sun.COM 		if (rtls_debug & RTLS_SEND) {
10739286SGarrett.Damore@Sun.COM 			cmn_err(CE_NOTE, "%s: transmit error, status = 0x%x",
10749286SGarrett.Damore@Sun.COM 			    rtlsp->ifname, tx_status);
10759286SGarrett.Damore@Sun.COM 		}
10769286SGarrett.Damore@Sun.COM #endif
10779286SGarrett.Damore@Sun.COM 		rtlsp->stats.xmt_err++;
10789286SGarrett.Damore@Sun.COM 		if (tx_status & TX_STATUS_TX_UNDERRUN)
10799286SGarrett.Damore@Sun.COM 			rtlsp->stats.underflow++;
10809286SGarrett.Damore@Sun.COM 		if (tx_status & TX_STATUS_CS_LOST)
10819286SGarrett.Damore@Sun.COM 			rtlsp->stats.no_carrier++;
10829286SGarrett.Damore@Sun.COM 		if (tx_status & TX_STATUS_OWC)
10839286SGarrett.Damore@Sun.COM 			rtlsp->stats.xmt_latecoll++;
10849286SGarrett.Damore@Sun.COM 	}
10859286SGarrett.Damore@Sun.COM 	ncc = ((tx_status & TX_STATUS_NCC) >> TX_STATUS_NCC_SHIFT);
10869286SGarrett.Damore@Sun.COM 	if (ncc != 0) {
10879286SGarrett.Damore@Sun.COM 		rtlsp->stats.collisions += ncc;
10889286SGarrett.Damore@Sun.COM 		rtlsp->stats.firstcol++;
10899286SGarrett.Damore@Sun.COM 		rtlsp->stats.multicol += ncc - 1;
10909286SGarrett.Damore@Sun.COM 	}
10919286SGarrett.Damore@Sun.COM 
10929286SGarrett.Damore@Sun.COM tx_ready:
10939286SGarrett.Damore@Sun.COM 	/*
10949286SGarrett.Damore@Sun.COM 	 * Initialize variable
10959286SGarrett.Damore@Sun.COM 	 */
10969286SGarrett.Damore@Sun.COM 	rtlsp->tx_retry = 0;
10979286SGarrett.Damore@Sun.COM 	totlen = 0;
10989286SGarrett.Damore@Sun.COM 
10999286SGarrett.Damore@Sun.COM 	/*
11009286SGarrett.Damore@Sun.COM 	 * Copy packet to tx descriptor buffer
11019286SGarrett.Damore@Sun.COM 	 */
11029286SGarrett.Damore@Sun.COM 	totlen = msgsize(mp);
11039286SGarrett.Damore@Sun.COM 	if (totlen > (ETHERMAX + 4)) {	/* 4 bytes for VLAN header */
11049286SGarrett.Damore@Sun.COM 		cmn_err(CE_NOTE,
11059286SGarrett.Damore@Sun.COM 		    "%s: rtls_send: try to send large %d packet",
11069286SGarrett.Damore@Sun.COM 		    rtlsp->ifname, totlen);
11079286SGarrett.Damore@Sun.COM 		rtlsp->stats.mac_xmt_err++;
11089286SGarrett.Damore@Sun.COM 		rtlsp->stats.xmt_err++;
11099286SGarrett.Damore@Sun.COM 		freemsg(mp);
11109286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
11119286SGarrett.Damore@Sun.COM 		return (B_TRUE);
11129286SGarrett.Damore@Sun.COM 	}
11139286SGarrett.Damore@Sun.COM 
11149286SGarrett.Damore@Sun.COM 	/* this will free the mblk */
11159286SGarrett.Damore@Sun.COM 	mcopymsg(mp, rtlsp->tx_buf[cur_desc]);
11169286SGarrett.Damore@Sun.COM 
11179286SGarrett.Damore@Sun.COM 	/* update stats */
11189286SGarrett.Damore@Sun.COM 	if (*rtlsp->tx_buf[cur_desc] & 0x1)  {
11199286SGarrett.Damore@Sun.COM 		uint16_t	*ptr = (void *)rtlsp->tx_buf[cur_desc];
11209286SGarrett.Damore@Sun.COM 		if ((ptr[0] == 0xffff) &&
11219286SGarrett.Damore@Sun.COM 		    (ptr[1] == 0xffff) &&
11229286SGarrett.Damore@Sun.COM 		    (ptr[2] == 0xffff)) {
11239286SGarrett.Damore@Sun.COM 			rtlsp->stats.brdcst_xmt++;
11249286SGarrett.Damore@Sun.COM 		} else {
11259286SGarrett.Damore@Sun.COM 			rtlsp->stats.multi_xmt++;
11269286SGarrett.Damore@Sun.COM 		}
11279286SGarrett.Damore@Sun.COM 	}
11289286SGarrett.Damore@Sun.COM 	rtlsp->stats.opackets++;
11299286SGarrett.Damore@Sun.COM 	rtlsp->stats.obytes += totlen;
11309286SGarrett.Damore@Sun.COM 
11319286SGarrett.Damore@Sun.COM 	if (totlen < ETHERMIN) {
11329286SGarrett.Damore@Sun.COM 		bzero(rtlsp->tx_buf[cur_desc] + totlen, ETHERMIN - totlen);
11339286SGarrett.Damore@Sun.COM 		totlen = ETHERMIN;
11349286SGarrett.Damore@Sun.COM 	}
11359286SGarrett.Damore@Sun.COM 
11369286SGarrett.Damore@Sun.COM 	/* make sure caches are flushed */
11379286SGarrett.Damore@Sun.COM 	(void) ddi_dma_sync(rtlsp->dma_area_tx[cur_desc].dma_hdl, 0, totlen,
11389286SGarrett.Damore@Sun.COM 	    DDI_DMA_SYNC_FORDEV);
11399286SGarrett.Damore@Sun.COM 
11409286SGarrett.Damore@Sun.COM 	/*
11419286SGarrett.Damore@Sun.COM 	 * Start transmit
11429286SGarrett.Damore@Sun.COM 	 * set transmit FIFO threshhold to 0x30*32 = 1536 bytes
11439286SGarrett.Damore@Sun.COM 	 * to avoid tx underrun.
11449286SGarrett.Damore@Sun.COM 	 */
11459286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc,
11469286SGarrett.Damore@Sun.COM 	    totlen | (0x30 << TX_STATUS_TX_THRESHOLD_SHIFT));
11479286SGarrett.Damore@Sun.COM 
11489286SGarrett.Damore@Sun.COM 	/*
11499286SGarrett.Damore@Sun.COM 	 * Update the value of current tx descriptor
11509286SGarrett.Damore@Sun.COM 	 */
11519286SGarrett.Damore@Sun.COM 	cur_desc++;
11529286SGarrett.Damore@Sun.COM 	cur_desc %= RTLS_MAX_TX_DESC;
11539286SGarrett.Damore@Sun.COM 	rtlsp->tx_current_desc = cur_desc;
11549286SGarrett.Damore@Sun.COM 
11559286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_tx_lock);
11569286SGarrett.Damore@Sun.COM 
11579286SGarrett.Damore@Sun.COM 	return (B_TRUE);
11589286SGarrett.Damore@Sun.COM }
11599286SGarrett.Damore@Sun.COM 
11609286SGarrett.Damore@Sun.COM /*
11619286SGarrett.Damore@Sun.COM  * rtls_m_tx() -- send a chain of packets, linked by mp->b_next.
11629286SGarrett.Damore@Sun.COM  */
11639286SGarrett.Damore@Sun.COM static mblk_t *
11649286SGarrett.Damore@Sun.COM rtls_m_tx(void *arg, mblk_t *mp)
11659286SGarrett.Damore@Sun.COM {
11669286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = arg;
11679286SGarrett.Damore@Sun.COM 	mblk_t *next;
11689286SGarrett.Damore@Sun.COM 
11699286SGarrett.Damore@Sun.COM 	while (mp != NULL) {
11709286SGarrett.Damore@Sun.COM 		next = mp->b_next;
11719286SGarrett.Damore@Sun.COM 		mp->b_next = NULL;
11729286SGarrett.Damore@Sun.COM 		if (!rtls_send(rtlsp, mp)) {
11739286SGarrett.Damore@Sun.COM 			mp->b_next = next;
11749286SGarrett.Damore@Sun.COM 			break;
11759286SGarrett.Damore@Sun.COM 		}
11769286SGarrett.Damore@Sun.COM 		mp = next;
11779286SGarrett.Damore@Sun.COM 	}
11789286SGarrett.Damore@Sun.COM 	return (mp);
11799286SGarrett.Damore@Sun.COM }
11809286SGarrett.Damore@Sun.COM 
11819286SGarrett.Damore@Sun.COM /*
11829286SGarrett.Damore@Sun.COM  * rtls_receive() -- receive packets
11839286SGarrett.Damore@Sun.COM  *
11849286SGarrett.Damore@Sun.COM  * Called when receive interrupts detected
11859286SGarrett.Damore@Sun.COM  */
11869286SGarrett.Damore@Sun.COM static void
11879286SGarrett.Damore@Sun.COM rtls_receive(rtls_t *rtlsp)
11889286SGarrett.Damore@Sun.COM {
11899286SGarrett.Damore@Sun.COM 	mblk_t *head = NULL;
11909286SGarrett.Damore@Sun.COM 	mblk_t **mpp;
11919286SGarrett.Damore@Sun.COM 	mblk_t *mp;
11929286SGarrett.Damore@Sun.COM 	uint16_t rx_status;
11939286SGarrett.Damore@Sun.COM 	uint16_t packet_len;
11949286SGarrett.Damore@Sun.COM 	int wrap_size;
11959286SGarrett.Damore@Sun.COM 	uint32_t cur_rx;
11969286SGarrett.Damore@Sun.COM 	uint8_t *rx_ptr;
11979286SGarrett.Damore@Sun.COM 
11989286SGarrett.Damore@Sun.COM 	mpp = &head;
11999286SGarrett.Damore@Sun.COM 
12009286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_rx_lock);
12019286SGarrett.Damore@Sun.COM 
12029286SGarrett.Damore@Sun.COM 	if (rtlsp->rtls_suspended) {
12039286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_rx_lock);
12049286SGarrett.Damore@Sun.COM 		return;
12059286SGarrett.Damore@Sun.COM 	}
12069286SGarrett.Damore@Sun.COM 
12079286SGarrett.Damore@Sun.COM 	while ((rtls_reg_get8(rtlsp, RT_COMMAND_REG)
12089286SGarrett.Damore@Sun.COM 	    & RT_COMMAND_BUFF_EMPTY) == 0) {
12099286SGarrett.Damore@Sun.COM 
12109286SGarrett.Damore@Sun.COM 		/*
12119286SGarrett.Damore@Sun.COM 		 * Chip error state
12129286SGarrett.Damore@Sun.COM 		 */
12139286SGarrett.Damore@Sun.COM 		if (rtlsp->chip_error) {
12149286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
12159286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
12169286SGarrett.Damore@Sun.COM 		    "%s: receive fail--CHIP ERROR!",
12179286SGarrett.Damore@Sun.COM 		    rtlsp->ifname);
12189286SGarrett.Damore@Sun.COM #endif
12199286SGarrett.Damore@Sun.COM 			break;
12209286SGarrett.Damore@Sun.COM 		}
12219286SGarrett.Damore@Sun.COM 
12229286SGarrett.Damore@Sun.COM 		cur_rx = rtlsp->cur_rx;
12239286SGarrett.Damore@Sun.COM 		rx_ptr = rtlsp->rx_ring + cur_rx;
12249286SGarrett.Damore@Sun.COM 		packet_len = (rx_ptr[3] << 8) | (rx_ptr[2]);
12259286SGarrett.Damore@Sun.COM 		rx_status = rx_ptr[0];
12269286SGarrett.Damore@Sun.COM 
12279286SGarrett.Damore@Sun.COM 		/*
12289286SGarrett.Damore@Sun.COM 		 * DMA still in progress
12299286SGarrett.Damore@Sun.COM 		 */
12309286SGarrett.Damore@Sun.COM 		if (packet_len == RX_STATUS_DMA_BUSY) {
12319286SGarrett.Damore@Sun.COM 			cmn_err(CE_NOTE, "%s: Rx DMA still in progress",
12329286SGarrett.Damore@Sun.COM 			    rtlsp->ifname);
12339286SGarrett.Damore@Sun.COM 			break;
12349286SGarrett.Damore@Sun.COM 		}
12359286SGarrett.Damore@Sun.COM 
12369286SGarrett.Damore@Sun.COM 		/*
12379286SGarrett.Damore@Sun.COM 		 * Check receive status
12389286SGarrett.Damore@Sun.COM 		 */
12399286SGarrett.Damore@Sun.COM 		if ((rx_status & RX_ERR_FLAGS) ||
12409286SGarrett.Damore@Sun.COM 		    (!(rx_status & RX_HEADER_STATUS_ROK)) ||
12419286SGarrett.Damore@Sun.COM 		    (packet_len < (ETHERMIN + ETHERFCSL)) ||
12429286SGarrett.Damore@Sun.COM 		    (packet_len > (ETHERMAX + ETHERFCSL + 4))) {
12439286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
12449286SGarrett.Damore@Sun.COM 			cmn_err(CE_NOTE,
12459286SGarrett.Damore@Sun.COM 			    "%s: receive error, status = 0x%x, length = %d",
12469286SGarrett.Damore@Sun.COM 			    rtlsp->ifname, rx_status, packet_len);
12479286SGarrett.Damore@Sun.COM #endif
12489286SGarrett.Damore@Sun.COM 			/*
12499286SGarrett.Damore@Sun.COM 			 * Rx error statistics
12509286SGarrett.Damore@Sun.COM 			 */
12519286SGarrett.Damore@Sun.COM 			if ((rx_status & RX_HEADER_STATUS_RUNT) ||
12529286SGarrett.Damore@Sun.COM 			    (packet_len < (ETHERMIN + ETHERFCSL)))
12539286SGarrett.Damore@Sun.COM 				rtlsp->stats.in_short++;
12549286SGarrett.Damore@Sun.COM 			else if (packet_len > (ETHERMAX + ETHERFCSL + 4))
12559286SGarrett.Damore@Sun.COM 				rtlsp->stats.too_long++;
12569286SGarrett.Damore@Sun.COM 			else if (rx_status & RX_HEADER_STATUS_CRC)
12579286SGarrett.Damore@Sun.COM 				rtlsp->stats.crc_err++;
12589286SGarrett.Damore@Sun.COM 			else if (rx_status & RX_HEADER_STATUS_FAE)
12599286SGarrett.Damore@Sun.COM 				rtlsp->stats.frame_err++;
12609286SGarrett.Damore@Sun.COM 
12619286SGarrett.Damore@Sun.COM 			/*
12629286SGarrett.Damore@Sun.COM 			 * Set chip_error flag to reset chip:
12639286SGarrett.Damore@Sun.COM 			 * (suggested in RealTek programming guide.)
12649286SGarrett.Damore@Sun.COM 			 */
12659286SGarrett.Damore@Sun.COM 			rtlsp->chip_error = B_TRUE;
12669286SGarrett.Damore@Sun.COM 			mutex_exit(&rtlsp->rtls_rx_lock);
12679286SGarrett.Damore@Sun.COM 			return;
12689286SGarrett.Damore@Sun.COM 		}
12699286SGarrett.Damore@Sun.COM 
12709286SGarrett.Damore@Sun.COM 		/*
12719286SGarrett.Damore@Sun.COM 		 * We need not up-send ETHERFCSL bytes of receive packet
12729286SGarrett.Damore@Sun.COM 		 */
12739286SGarrett.Damore@Sun.COM 		packet_len -= ETHERFCSL;
12749286SGarrett.Damore@Sun.COM 
12759286SGarrett.Damore@Sun.COM 		/*
12769286SGarrett.Damore@Sun.COM 		 * Allocate buffer to receive this good packet
12779286SGarrett.Damore@Sun.COM 		 */
12789286SGarrett.Damore@Sun.COM 		mp = allocb(packet_len, 0);
12799286SGarrett.Damore@Sun.COM 
12809286SGarrett.Damore@Sun.COM 		/*
12819286SGarrett.Damore@Sun.COM 		 * Copy the data found into the new cluster, we have (+4)
12829286SGarrett.Damore@Sun.COM 		 * to get us past the packet head data that the rtl chip
12839286SGarrett.Damore@Sun.COM 		 * places at the start of the message
12849286SGarrett.Damore@Sun.COM 		 */
12859286SGarrett.Damore@Sun.COM 		if ((cur_rx + packet_len + RX_HEADER_SIZE)
12869286SGarrett.Damore@Sun.COM 		    > RTLS_RX_BUF_RING) {
12879286SGarrett.Damore@Sun.COM 			wrap_size = cur_rx + packet_len + RX_HEADER_SIZE
12889286SGarrett.Damore@Sun.COM 			    - RTLS_RX_BUF_RING;
12899286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
12909286SGarrett.Damore@Sun.COM 			if (rtls_debug & RTLS_RECV) {
12919286SGarrett.Damore@Sun.COM 				cmn_err(CE_NOTE,
12929286SGarrett.Damore@Sun.COM 				    "%s: Rx: packet_len = %d, wrap_size = %d",
12939286SGarrett.Damore@Sun.COM 				    rtlsp->ifname, packet_len, wrap_size);
12949286SGarrett.Damore@Sun.COM 			}
12959286SGarrett.Damore@Sun.COM #endif
12969286SGarrett.Damore@Sun.COM 
12979286SGarrett.Damore@Sun.COM 			if (mp != NULL) {
12989286SGarrett.Damore@Sun.COM 				/* Flush caches */
12999286SGarrett.Damore@Sun.COM 				(void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl,
13009286SGarrett.Damore@Sun.COM 				    cur_rx + RX_HEADER_SIZE,
13019286SGarrett.Damore@Sun.COM 				    packet_len - wrap_size,
13029286SGarrett.Damore@Sun.COM 				    DDI_DMA_SYNC_FORKERNEL);
13039286SGarrett.Damore@Sun.COM 				(void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl,
13049286SGarrett.Damore@Sun.COM 				    0, wrap_size,
13059286SGarrett.Damore@Sun.COM 				    DDI_DMA_SYNC_FORKERNEL);
13069286SGarrett.Damore@Sun.COM 
13079286SGarrett.Damore@Sun.COM 				/*
13089286SGarrett.Damore@Sun.COM 				 * Copy in first section of message as stored
13099286SGarrett.Damore@Sun.COM 				 * at the end of the ring buffer
13109286SGarrett.Damore@Sun.COM 				 */
13119286SGarrett.Damore@Sun.COM 				bcopy(rx_ptr + RX_HEADER_SIZE,
13129286SGarrett.Damore@Sun.COM 				    mp->b_wptr, packet_len - wrap_size);
13139286SGarrett.Damore@Sun.COM 				mp->b_wptr += packet_len - wrap_size;
13149286SGarrett.Damore@Sun.COM 				bcopy(rtlsp->rx_ring, mp->b_wptr, wrap_size);
13159286SGarrett.Damore@Sun.COM 				mp->b_wptr += wrap_size;
13169286SGarrett.Damore@Sun.COM 				*mpp = mp;
13179286SGarrett.Damore@Sun.COM 				mpp = &mp->b_next;
13189286SGarrett.Damore@Sun.COM 
13199286SGarrett.Damore@Sun.COM 				rtlsp->stats.ipackets++;
13209286SGarrett.Damore@Sun.COM 				if (rx_status & RX_HEADER_STATUS_BCAST)
13219286SGarrett.Damore@Sun.COM 					rtlsp->stats.brdcst_rcv++;
13229286SGarrett.Damore@Sun.COM 				if (rx_status & RX_HEADER_STATUS_MULTI)
13239286SGarrett.Damore@Sun.COM 					rtlsp->stats.multi_rcv++;
13249286SGarrett.Damore@Sun.COM 				rtlsp->stats.rbytes += packet_len;
13259286SGarrett.Damore@Sun.COM 			} else  {
13269286SGarrett.Damore@Sun.COM 				rtlsp->stats.no_rcvbuf++;
13279286SGarrett.Damore@Sun.COM 			}
13289286SGarrett.Damore@Sun.COM 
13299286SGarrett.Damore@Sun.COM 			cur_rx = RTLS_RX_ADDR_ALIGNED(wrap_size + ETHERFCSL);
13309286SGarrett.Damore@Sun.COM 							/* 4-byte aligned */
13319286SGarrett.Damore@Sun.COM 		} else {
13329286SGarrett.Damore@Sun.COM 
13339286SGarrett.Damore@Sun.COM 			if (mp != NULL) {
13349286SGarrett.Damore@Sun.COM 				/* Flush caches */
13359286SGarrett.Damore@Sun.COM 				(void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl,
13369286SGarrett.Damore@Sun.COM 				    cur_rx + RX_HEADER_SIZE, packet_len,
13379286SGarrett.Damore@Sun.COM 				    DDI_DMA_SYNC_FORKERNEL);
13389286SGarrett.Damore@Sun.COM 				bcopy(rx_ptr + RX_HEADER_SIZE, mp->b_wptr,
13399286SGarrett.Damore@Sun.COM 				    packet_len);
13409286SGarrett.Damore@Sun.COM 				mp->b_wptr += packet_len;
13419286SGarrett.Damore@Sun.COM 				*mpp = mp;
13429286SGarrett.Damore@Sun.COM 				mpp = &mp->b_next;
13439286SGarrett.Damore@Sun.COM 
13449286SGarrett.Damore@Sun.COM 				rtlsp->stats.ipackets++;
13459286SGarrett.Damore@Sun.COM 				if (rx_status & RX_HEADER_STATUS_BCAST)
13469286SGarrett.Damore@Sun.COM 					rtlsp->stats.brdcst_rcv++;
13479286SGarrett.Damore@Sun.COM 				if (rx_status & RX_HEADER_STATUS_MULTI)
13489286SGarrett.Damore@Sun.COM 					rtlsp->stats.multi_rcv++;
13499286SGarrett.Damore@Sun.COM 				rtlsp->stats.rbytes += packet_len;
13509286SGarrett.Damore@Sun.COM 			} else {
13519286SGarrett.Damore@Sun.COM 				rtlsp->stats.no_rcvbuf++;
13529286SGarrett.Damore@Sun.COM 			}
13539286SGarrett.Damore@Sun.COM 			cur_rx += packet_len + RX_HEADER_SIZE + ETHERFCSL;
13549286SGarrett.Damore@Sun.COM 
13559286SGarrett.Damore@Sun.COM 			cur_rx = RTLS_RX_ADDR_ALIGNED(cur_rx);
13569286SGarrett.Damore@Sun.COM 							/* 4-byte aligned */
13579286SGarrett.Damore@Sun.COM 		}
13589286SGarrett.Damore@Sun.COM 
13599286SGarrett.Damore@Sun.COM 		/*
13609286SGarrett.Damore@Sun.COM 		 * Update rx buffer ring read pointer:
13619286SGarrett.Damore@Sun.COM 		 * give us a little leeway to ensure no overflow
13629286SGarrett.Damore@Sun.COM 		 */
13639286SGarrett.Damore@Sun.COM 		rtlsp->cur_rx = cur_rx;
13649286SGarrett.Damore@Sun.COM 		rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG,
13659286SGarrett.Damore@Sun.COM 		    cur_rx - READ_ADDR_GAP);
13669286SGarrett.Damore@Sun.COM 	}
13679286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_rx_lock);
13689286SGarrett.Damore@Sun.COM 
13699286SGarrett.Damore@Sun.COM 	/*
13709286SGarrett.Damore@Sun.COM 	 * Upsend packet
13719286SGarrett.Damore@Sun.COM 	 */
13729286SGarrett.Damore@Sun.COM 	if (head) {
13739286SGarrett.Damore@Sun.COM 		mac_rx(rtlsp->mh, NULL, head);
13749286SGarrett.Damore@Sun.COM 	}
13759286SGarrett.Damore@Sun.COM }
13769286SGarrett.Damore@Sun.COM 
13779286SGarrett.Damore@Sun.COM /*
13789286SGarrett.Damore@Sun.COM  * rtls_intr() -- interrupt from board to inform us that a receive or
13799286SGarrett.Damore@Sun.COM  * link change.
13809286SGarrett.Damore@Sun.COM  */
13819286SGarrett.Damore@Sun.COM static uint_t
13829286SGarrett.Damore@Sun.COM rtls_intr(caddr_t arg)
13839286SGarrett.Damore@Sun.COM {
13849286SGarrett.Damore@Sun.COM 	rtls_t *rtlsp = (void *)arg;
13859286SGarrett.Damore@Sun.COM 	uint32_t int_status;
13869286SGarrett.Damore@Sun.COM 	uint32_t val32;
1387*11453Sgdamore@opensolaris.org 	boolean_t	resched = B_FALSE;
13889286SGarrett.Damore@Sun.COM 
13899286SGarrett.Damore@Sun.COM 	mutex_enter(&rtlsp->rtls_io_lock);
1390*11453Sgdamore@opensolaris.org 	if (rtlsp->rtls_suspended) {
1391*11453Sgdamore@opensolaris.org 		mutex_exit(&rtlsp->rtls_io_lock);
1392*11453Sgdamore@opensolaris.org 		return (DDI_INTR_UNCLAIMED);
1393*11453Sgdamore@opensolaris.org 	}
13949286SGarrett.Damore@Sun.COM 
13959286SGarrett.Damore@Sun.COM 	/*
13969286SGarrett.Damore@Sun.COM 	 * Was this interrupt caused by our device...
13979286SGarrett.Damore@Sun.COM 	 */
13989286SGarrett.Damore@Sun.COM 	int_status = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
13999286SGarrett.Damore@Sun.COM 	if (!(int_status & rtlsp->int_mask)) {
14009286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_io_lock);
14019286SGarrett.Damore@Sun.COM 		return (DDI_INTR_UNCLAIMED);
14029286SGarrett.Damore@Sun.COM 				/* indicate it wasn't our interrupt */
14039286SGarrett.Damore@Sun.COM 	}
14049286SGarrett.Damore@Sun.COM 
14059286SGarrett.Damore@Sun.COM 	/*
14069286SGarrett.Damore@Sun.COM 	 * Clear interrupt
14079286SGarrett.Damore@Sun.COM 	 */
14089286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, int_status);
14099286SGarrett.Damore@Sun.COM 
14109286SGarrett.Damore@Sun.COM 	/*
14119286SGarrett.Damore@Sun.COM 	 * If chip error, restart chip...
14129286SGarrett.Damore@Sun.COM 	 */
14139286SGarrett.Damore@Sun.COM 	if (rtlsp->chip_error) {
14149286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_rx_lock);
14159286SGarrett.Damore@Sun.COM 		mutex_enter(&rtlsp->rtls_tx_lock);
14169286SGarrett.Damore@Sun.COM 		rtls_chip_restart(rtlsp);
14179286SGarrett.Damore@Sun.COM 		rtlsp->chip_error = B_FALSE;
14189286SGarrett.Damore@Sun.COM 		rtlsp->tx_retry = 0;
14199286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_tx_lock);
14209286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_rx_lock);
14219286SGarrett.Damore@Sun.COM 		mutex_exit(&rtlsp->rtls_io_lock);
14229286SGarrett.Damore@Sun.COM 		return (DDI_INTR_CLAIMED);
14239286SGarrett.Damore@Sun.COM 			/* no need to hand other interrupts */
14249286SGarrett.Damore@Sun.COM 	}
14259286SGarrett.Damore@Sun.COM 
14269286SGarrett.Damore@Sun.COM 	/*
14279286SGarrett.Damore@Sun.COM 	 * Transmit error interrupt
14289286SGarrett.Damore@Sun.COM 	 */
14299286SGarrett.Damore@Sun.COM 	if (int_status & TX_ERR_INT) {
14309286SGarrett.Damore@Sun.COM 		val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG);
14319286SGarrett.Damore@Sun.COM 		val32 |= TX_CLEAR_ABORT;
14329286SGarrett.Damore@Sun.COM 		rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32);
14339286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN, "%s: transmit abort!!!", rtlsp->ifname);
14349286SGarrett.Damore@Sun.COM 	}
14359286SGarrett.Damore@Sun.COM 
14369286SGarrett.Damore@Sun.COM 	/*
14379286SGarrett.Damore@Sun.COM 	 * Trigger mac_tx_update
14389286SGarrett.Damore@Sun.COM 	 */
1439*11453Sgdamore@opensolaris.org 	if (rtlsp->need_sched) {
1440*11453Sgdamore@opensolaris.org 		rtlsp->need_sched = B_FALSE;
1441*11453Sgdamore@opensolaris.org 		resched = B_TRUE;
14429286SGarrett.Damore@Sun.COM 	}
14439286SGarrett.Damore@Sun.COM 
14449286SGarrett.Damore@Sun.COM 	mutex_exit(&rtlsp->rtls_io_lock);
14459286SGarrett.Damore@Sun.COM 
14469286SGarrett.Damore@Sun.COM 	/*
14479286SGarrett.Damore@Sun.COM 	 * Receive interrupt
14489286SGarrett.Damore@Sun.COM 	 */
14499286SGarrett.Damore@Sun.COM 	if (int_status & RTLS_RX_INT) {
14509286SGarrett.Damore@Sun.COM 		if (int_status & RX_OVERFLOW_INT) {
14519286SGarrett.Damore@Sun.COM 			rtlsp->stats.overflow++;
14529286SGarrett.Damore@Sun.COM 			rtlsp->stats.rcv_err++;
14539286SGarrett.Damore@Sun.COM 		}
14549286SGarrett.Damore@Sun.COM 		rtls_receive(rtlsp);
14559286SGarrett.Damore@Sun.COM 	}
14569286SGarrett.Damore@Sun.COM 
1457*11453Sgdamore@opensolaris.org 	/*
1458*11453Sgdamore@opensolaris.org 	 * Link change interrupt.
1459*11453Sgdamore@opensolaris.org 	 */
1460*11453Sgdamore@opensolaris.org 	if (int_status & LINK_CHANGE_INT) {
1461*11453Sgdamore@opensolaris.org 		mii_check(rtlsp->mii);
14629286SGarrett.Damore@Sun.COM 	}
14639286SGarrett.Damore@Sun.COM 
1464*11453Sgdamore@opensolaris.org 	if (resched) {
14659286SGarrett.Damore@Sun.COM 		mac_tx_update(rtlsp->mh);
14669286SGarrett.Damore@Sun.COM 	}
14679286SGarrett.Damore@Sun.COM 
1468*11453Sgdamore@opensolaris.org 	return (DDI_INTR_CLAIMED);	/* indicate it was our interrupt */
14699286SGarrett.Damore@Sun.COM }
14709286SGarrett.Damore@Sun.COM 
14719286SGarrett.Damore@Sun.COM /*
14729286SGarrett.Damore@Sun.COM  *    ========== Buffer Management Routines ==========
14739286SGarrett.Damore@Sun.COM  */
14749286SGarrett.Damore@Sun.COM 
14759286SGarrett.Damore@Sun.COM /*
14769286SGarrett.Damore@Sun.COM  * rtls_alloc_dma_mem() -- allocate an area of memory and a DMA handle
14779286SGarrett.Damore@Sun.COM  * for accessing it
14789286SGarrett.Damore@Sun.COM  */
14799286SGarrett.Damore@Sun.COM static int
14809286SGarrett.Damore@Sun.COM rtls_alloc_dma_mem(rtls_t *rtlsp, size_t memsize,
14819286SGarrett.Damore@Sun.COM 	ddi_device_acc_attr_t *attr_p, uint_t dma_flags, dma_area_t *dma_p)
14829286SGarrett.Damore@Sun.COM {
14839286SGarrett.Damore@Sun.COM 	caddr_t vaddr;
14849286SGarrett.Damore@Sun.COM 	int err;
14859286SGarrett.Damore@Sun.COM 
14869286SGarrett.Damore@Sun.COM 	/*
14879286SGarrett.Damore@Sun.COM 	 * Allocate handle
14889286SGarrett.Damore@Sun.COM 	 */
14899286SGarrett.Damore@Sun.COM 	err = ddi_dma_alloc_handle(rtlsp->devinfo, &dma_attr,
14909286SGarrett.Damore@Sun.COM 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
14919286SGarrett.Damore@Sun.COM 	if (err != DDI_SUCCESS) {
14929286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
14939286SGarrett.Damore@Sun.COM 		    "%s: rtls_alloc_dma_mem: ddi_dma_alloc_handle failed: %d",
14949286SGarrett.Damore@Sun.COM 		    rtlsp->ifname, err);
14959286SGarrett.Damore@Sun.COM 		dma_p->dma_hdl = NULL;
14969286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
14979286SGarrett.Damore@Sun.COM 	}
14989286SGarrett.Damore@Sun.COM 
14999286SGarrett.Damore@Sun.COM 	/*
15009286SGarrett.Damore@Sun.COM 	 * Allocate memory
15019286SGarrett.Damore@Sun.COM 	 */
15029286SGarrett.Damore@Sun.COM 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
15039286SGarrett.Damore@Sun.COM 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
15049286SGarrett.Damore@Sun.COM 	    DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
15059286SGarrett.Damore@Sun.COM 	if (err != DDI_SUCCESS) {
15069286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
15079286SGarrett.Damore@Sun.COM 		    "%s: rtls_alloc_dma_mem: ddi_dma_mem_alloc failed: %d",
15089286SGarrett.Damore@Sun.COM 		    rtlsp->ifname, err);
15099286SGarrett.Damore@Sun.COM 		ddi_dma_free_handle(&dma_p->dma_hdl);
15109286SGarrett.Damore@Sun.COM 		dma_p->dma_hdl = NULL;
15119286SGarrett.Damore@Sun.COM 		dma_p->acc_hdl = NULL;
15129286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
15139286SGarrett.Damore@Sun.COM 	}
15149286SGarrett.Damore@Sun.COM 
15159286SGarrett.Damore@Sun.COM 	/*
15169286SGarrett.Damore@Sun.COM 	 * Bind the two together
15179286SGarrett.Damore@Sun.COM 	 */
15189286SGarrett.Damore@Sun.COM 	dma_p->mem_va = vaddr;
15199286SGarrett.Damore@Sun.COM 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
15209286SGarrett.Damore@Sun.COM 	    vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
15219286SGarrett.Damore@Sun.COM 	    &dma_p->cookie, &dma_p->ncookies);
15229286SGarrett.Damore@Sun.COM 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) {
15239286SGarrett.Damore@Sun.COM 		cmn_err(CE_WARN,
15249286SGarrett.Damore@Sun.COM 		    "%s: rtls_alloc_dma_mem: "
15259286SGarrett.Damore@Sun.COM 		    "ddi_dma_addr_bind_handle failed: %d",
15269286SGarrett.Damore@Sun.COM 		    rtlsp->ifname, err);
15279286SGarrett.Damore@Sun.COM 		ddi_dma_mem_free(&dma_p->acc_hdl);
15289286SGarrett.Damore@Sun.COM 		ddi_dma_free_handle(&dma_p->dma_hdl);
15299286SGarrett.Damore@Sun.COM 		dma_p->acc_hdl = NULL;
15309286SGarrett.Damore@Sun.COM 		dma_p->dma_hdl = NULL;
15319286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
15329286SGarrett.Damore@Sun.COM 	}
15339286SGarrett.Damore@Sun.COM 
15349286SGarrett.Damore@Sun.COM 	return (DDI_SUCCESS);
15359286SGarrett.Damore@Sun.COM }
15369286SGarrett.Damore@Sun.COM 
15379286SGarrett.Damore@Sun.COM /*
15389286SGarrett.Damore@Sun.COM  * rtls_free_dma_mem() -- free one allocated area of DMAable memory
15399286SGarrett.Damore@Sun.COM  */
15409286SGarrett.Damore@Sun.COM static void
15419286SGarrett.Damore@Sun.COM rtls_free_dma_mem(dma_area_t *dma_p)
15429286SGarrett.Damore@Sun.COM {
15439286SGarrett.Damore@Sun.COM 	if (dma_p->dma_hdl != NULL) {
15449286SGarrett.Damore@Sun.COM 		if (dma_p->ncookies) {
15459286SGarrett.Damore@Sun.COM 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
15469286SGarrett.Damore@Sun.COM 			dma_p->ncookies = 0;
15479286SGarrett.Damore@Sun.COM 		}
15489286SGarrett.Damore@Sun.COM 		ddi_dma_free_handle(&dma_p->dma_hdl);
15499286SGarrett.Damore@Sun.COM 		dma_p->dma_hdl = NULL;
15509286SGarrett.Damore@Sun.COM 	}
15519286SGarrett.Damore@Sun.COM 
15529286SGarrett.Damore@Sun.COM 	if (dma_p->acc_hdl != NULL) {
15539286SGarrett.Damore@Sun.COM 		ddi_dma_mem_free(&dma_p->acc_hdl);
15549286SGarrett.Damore@Sun.COM 		dma_p->acc_hdl = NULL;
15559286SGarrett.Damore@Sun.COM 	}
15569286SGarrett.Damore@Sun.COM }
15579286SGarrett.Damore@Sun.COM 
15589286SGarrett.Damore@Sun.COM /*
15599286SGarrett.Damore@Sun.COM  * rtls_alloc_bufs() -- allocate descriptors/buffers for this device instance
15609286SGarrett.Damore@Sun.COM  */
15619286SGarrett.Damore@Sun.COM static int
15629286SGarrett.Damore@Sun.COM rtls_alloc_bufs(rtls_t *rtlsp)
15639286SGarrett.Damore@Sun.COM {
15649286SGarrett.Damore@Sun.COM 	int i;
15659286SGarrett.Damore@Sun.COM 	int err;
15669286SGarrett.Damore@Sun.COM 
15679286SGarrett.Damore@Sun.COM 	/*
15689286SGarrett.Damore@Sun.COM 	 * Allocate memory & handle for Tx buffers
15699286SGarrett.Damore@Sun.COM 	 */
15709286SGarrett.Damore@Sun.COM 	for (i = 0; i < RTLS_MAX_TX_DESC; i++) {
15719286SGarrett.Damore@Sun.COM 		err = rtls_alloc_dma_mem(rtlsp,
15729286SGarrett.Damore@Sun.COM 		    RTLS_TX_BUF_SIZE,
15739286SGarrett.Damore@Sun.COM 		    &rtls_buf_accattr,
15749286SGarrett.Damore@Sun.COM 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
15759286SGarrett.Damore@Sun.COM 		    &rtlsp->dma_area_tx[i]);
15769286SGarrett.Damore@Sun.COM 
15779286SGarrett.Damore@Sun.COM 		if (err != DDI_SUCCESS)
15789286SGarrett.Damore@Sun.COM 			return (DDI_FAILURE);
15799286SGarrett.Damore@Sun.COM 
15809286SGarrett.Damore@Sun.COM 		rtlsp->tx_buf[i] = (uint8_t *)rtlsp->dma_area_tx[i].mem_va;
15819286SGarrett.Damore@Sun.COM 	}
15829286SGarrett.Damore@Sun.COM 
15839286SGarrett.Damore@Sun.COM 	/*
15849286SGarrett.Damore@Sun.COM 	 * Allocate memory & handle for Rx buffers
15859286SGarrett.Damore@Sun.COM 	 */
15869286SGarrett.Damore@Sun.COM 	err = rtls_alloc_dma_mem(rtlsp,
15879286SGarrett.Damore@Sun.COM 	    RTLS_RX_BUF_SIZE,
15889286SGarrett.Damore@Sun.COM 	    &rtls_buf_accattr,
15899286SGarrett.Damore@Sun.COM 	    DDI_DMA_READ | DDI_DMA_STREAMING,
15909286SGarrett.Damore@Sun.COM 	    &rtlsp->dma_area_rx);
15919286SGarrett.Damore@Sun.COM 
15929286SGarrett.Damore@Sun.COM 	if (err != DDI_SUCCESS)
15939286SGarrett.Damore@Sun.COM 		return (DDI_FAILURE);
15949286SGarrett.Damore@Sun.COM 
15959286SGarrett.Damore@Sun.COM 	rtlsp->rx_ring = (uint8_t *)rtlsp->dma_area_rx.mem_va;
15969286SGarrett.Damore@Sun.COM 
15979286SGarrett.Damore@Sun.COM 	return (DDI_SUCCESS);
15989286SGarrett.Damore@Sun.COM }
15999286SGarrett.Damore@Sun.COM 
16009286SGarrett.Damore@Sun.COM /*
16019286SGarrett.Damore@Sun.COM  * rtls_free_bufs() -- free descriptors/buffers allocated for this
16029286SGarrett.Damore@Sun.COM  * device instance.
16039286SGarrett.Damore@Sun.COM  */
16049286SGarrett.Damore@Sun.COM static void
16059286SGarrett.Damore@Sun.COM rtls_free_bufs(rtls_t *rtlsp)
16069286SGarrett.Damore@Sun.COM {
16079286SGarrett.Damore@Sun.COM 	int i;
16089286SGarrett.Damore@Sun.COM 
16099286SGarrett.Damore@Sun.COM 	for (i = 0; i < RTLS_MAX_TX_DESC; i++) {
16109286SGarrett.Damore@Sun.COM 		rtls_free_dma_mem(&rtlsp->dma_area_tx[i]);
16119286SGarrett.Damore@Sun.COM 		rtlsp->tx_buf[i] = NULL;
16129286SGarrett.Damore@Sun.COM 	}
16139286SGarrett.Damore@Sun.COM 
16149286SGarrett.Damore@Sun.COM 	rtls_free_dma_mem(&rtlsp->dma_area_rx);
16159286SGarrett.Damore@Sun.COM 	rtlsp->rx_ring = NULL;
16169286SGarrett.Damore@Sun.COM }
16179286SGarrett.Damore@Sun.COM 
16189286SGarrett.Damore@Sun.COM /*
16199286SGarrett.Damore@Sun.COM  *    ========== Chip H/W Operation Routines ==========
16209286SGarrett.Damore@Sun.COM  */
16219286SGarrett.Damore@Sun.COM 
16229286SGarrett.Damore@Sun.COM /*
16239286SGarrett.Damore@Sun.COM  * rtls_chip_reset() -- reset chip
16249286SGarrett.Damore@Sun.COM  */
16259286SGarrett.Damore@Sun.COM static int
16269286SGarrett.Damore@Sun.COM rtls_chip_reset(rtls_t *rtlsp, boolean_t quiesce)
16279286SGarrett.Damore@Sun.COM {
16289286SGarrett.Damore@Sun.COM 	int i;
16299286SGarrett.Damore@Sun.COM 	uint16_t val16;
16309286SGarrett.Damore@Sun.COM 	uint8_t val8;
16319286SGarrett.Damore@Sun.COM 
16329286SGarrett.Damore@Sun.COM 	/*
16339286SGarrett.Damore@Sun.COM 	 * Chip should be in STOP state
16349286SGarrett.Damore@Sun.COM 	 */
16359286SGarrett.Damore@Sun.COM 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
16369286SGarrett.Damore@Sun.COM 	val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
16379286SGarrett.Damore@Sun.COM 	rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8);
16389286SGarrett.Damore@Sun.COM 
16399286SGarrett.Damore@Sun.COM 	/*
16409286SGarrett.Damore@Sun.COM 	 * Disable interrupt
16419286SGarrett.Damore@Sun.COM 	 */
16429286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
16439286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL));
16449286SGarrett.Damore@Sun.COM 	rtlsp->int_mask = RTLS_INT_MASK_NONE;
16459286SGarrett.Damore@Sun.COM 
16469286SGarrett.Damore@Sun.COM 	/*
16479286SGarrett.Damore@Sun.COM 	 * Clear pended interrupt
16489286SGarrett.Damore@Sun.COM 	 */
16499286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
16509286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16);
16519286SGarrett.Damore@Sun.COM 
16529286SGarrett.Damore@Sun.COM 	/*
16539286SGarrett.Damore@Sun.COM 	 * Reset chip
16549286SGarrett.Damore@Sun.COM 	 */
16559286SGarrett.Damore@Sun.COM 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
16569286SGarrett.Damore@Sun.COM 	rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8 | RT_COMMAND_RESET);
16579286SGarrett.Damore@Sun.COM 
16589286SGarrett.Damore@Sun.COM 	/*
16599286SGarrett.Damore@Sun.COM 	 * Wait for reset success
16609286SGarrett.Damore@Sun.COM 	 */
16619286SGarrett.Damore@Sun.COM 	i = 0;
16629286SGarrett.Damore@Sun.COM 	while (rtls_reg_get8(rtlsp, RT_COMMAND_REG) & RT_COMMAND_RESET) {
16639286SGarrett.Damore@Sun.COM 		if (++i > RTLS_RESET_WAIT_NUM) {
16649286SGarrett.Damore@Sun.COM 			/*
16659286SGarrett.Damore@Sun.COM 			 * At quiesce path we can't call cmn_err(), as
16669286SGarrett.Damore@Sun.COM 			 * it might block
16679286SGarrett.Damore@Sun.COM 			 */
16689286SGarrett.Damore@Sun.COM 			if (!quiesce)
16699286SGarrett.Damore@Sun.COM 				cmn_err(CE_WARN,
16709286SGarrett.Damore@Sun.COM 				    "%s: chip reset fail.", rtlsp->ifname);
16719286SGarrett.Damore@Sun.COM 			return (DDI_FAILURE);
16729286SGarrett.Damore@Sun.COM 		}
16739286SGarrett.Damore@Sun.COM 		RTLS_RESET_WAIT_INTERVAL;
16749286SGarrett.Damore@Sun.COM 	}
16759286SGarrett.Damore@Sun.COM 
16769286SGarrett.Damore@Sun.COM 	return (DDI_SUCCESS);
16779286SGarrett.Damore@Sun.COM }
16789286SGarrett.Damore@Sun.COM 
16799286SGarrett.Damore@Sun.COM /*
16809286SGarrett.Damore@Sun.COM  * rtls_chip_init() -- initialize the specified network board short of
16819286SGarrett.Damore@Sun.COM  * actually starting the board.  Call after rtls_chip_reset().
16829286SGarrett.Damore@Sun.COM  */
16839286SGarrett.Damore@Sun.COM static void
16849286SGarrett.Damore@Sun.COM rtls_chip_init(rtls_t *rtlsp)
16859286SGarrett.Damore@Sun.COM {
16869286SGarrett.Damore@Sun.COM 	uint32_t val32;
16879286SGarrett.Damore@Sun.COM 	uint16_t val16;
16889286SGarrett.Damore@Sun.COM 	uint8_t val8;
16899286SGarrett.Damore@Sun.COM 
16909286SGarrett.Damore@Sun.COM 	/*
16919286SGarrett.Damore@Sun.COM 	 * Initialize internal data structures
16929286SGarrett.Damore@Sun.COM 	 */
16939286SGarrett.Damore@Sun.COM 	rtlsp->cur_rx = 0;
16949286SGarrett.Damore@Sun.COM 	rtlsp->tx_current_desc = 0;
16959286SGarrett.Damore@Sun.COM 	rtlsp->tx_first_loop = 0;
16969286SGarrett.Damore@Sun.COM 
16979286SGarrett.Damore@Sun.COM 	/*
16989286SGarrett.Damore@Sun.COM 	 * Set DMA physical rx/tx buffer address to register
16999286SGarrett.Damore@Sun.COM 	 */
17009286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, RX_BUFF_ADDR_REG,
17019286SGarrett.Damore@Sun.COM 	    (ulong_t)rtlsp->dma_area_rx.cookie.dmac_address);
17029286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, TX_ADDR_DESC0_REG,
17039286SGarrett.Damore@Sun.COM 	    (ulong_t)rtlsp->dma_area_tx[0].cookie.dmac_address);
17049286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, TX_ADDR_DESC1_REG,
17059286SGarrett.Damore@Sun.COM 	    (ulong_t)rtlsp->dma_area_tx[1].cookie.dmac_address);
17069286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, TX_ADDR_DESC2_REG,
17079286SGarrett.Damore@Sun.COM 	    (ulong_t)rtlsp->dma_area_tx[2].cookie.dmac_address);
17089286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, TX_ADDR_DESC3_REG,
17099286SGarrett.Damore@Sun.COM 	    (ulong_t)rtlsp->dma_area_tx[3].cookie.dmac_address);
17109286SGarrett.Damore@Sun.COM 
17119286SGarrett.Damore@Sun.COM 	/*
17129286SGarrett.Damore@Sun.COM 	 * Start transmit/receive before set tx/rx configuration register
17139286SGarrett.Damore@Sun.COM 	 */
17149286SGarrett.Damore@Sun.COM 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
17159286SGarrett.Damore@Sun.COM 	rtls_reg_set8(rtlsp, RT_COMMAND_REG,
17169286SGarrett.Damore@Sun.COM 	    val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
17179286SGarrett.Damore@Sun.COM 
17189286SGarrett.Damore@Sun.COM 	/*
17199286SGarrett.Damore@Sun.COM 	 * Set transmit configuration register
17209286SGarrett.Damore@Sun.COM 	 */
17219286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG);
17229286SGarrett.Damore@Sun.COM 	val32 &= TX_CONSIG_REG_RESERVE;
17239286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32 | TX_CONFIG_DEFAULT);
17249286SGarrett.Damore@Sun.COM 
17259286SGarrett.Damore@Sun.COM 	/*
17269286SGarrett.Damore@Sun.COM 	 * Set receive configuration register
17279286SGarrett.Damore@Sun.COM 	 */
17289286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG);
17299286SGarrett.Damore@Sun.COM 	val32 &= RX_CONSIG_REG_RESERVE;
17309286SGarrett.Damore@Sun.COM 	if (rtlsp->promisc)
17319286SGarrett.Damore@Sun.COM 		val32 |= RX_ACCEPT_ALL_PACKET;
17329286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32 | RX_CONFIG_DEFAULT);
17339286SGarrett.Damore@Sun.COM 
17349286SGarrett.Damore@Sun.COM 	/*
17359286SGarrett.Damore@Sun.COM 	 * Set multicast register
17369286SGarrett.Damore@Sun.COM 	 */
17379286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, MULTICAST_0_REG, rtlsp->multi_hash[0]);
17389286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, MULTICAST_4_REG, rtlsp->multi_hash[1]);
17399286SGarrett.Damore@Sun.COM 
17409286SGarrett.Damore@Sun.COM 	/*
17419286SGarrett.Damore@Sun.COM 	 * Set unicast address
17429286SGarrett.Damore@Sun.COM 	 */
17439286SGarrett.Damore@Sun.COM 	rtls_set_mac_addr(rtlsp, rtlsp->netaddr);
17449286SGarrett.Damore@Sun.COM 
17459286SGarrett.Damore@Sun.COM 	/*
17469286SGarrett.Damore@Sun.COM 	 * Set current address of packet read
17479286SGarrett.Damore@Sun.COM 	 */
17489286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG, RX_READ_RESET_VAL);
17499286SGarrett.Damore@Sun.COM 
17509286SGarrett.Damore@Sun.COM 	/*
17519286SGarrett.Damore@Sun.COM 	 * No early-rx interrupts
17529286SGarrett.Damore@Sun.COM 	 */
17539286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_MUL_INTSEL_REG);
17549286SGarrett.Damore@Sun.COM 	val16 &= ~RT_MUL_INTSEL_BITS;
17559286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_MUL_INTSEL_REG, val16);
17569286SGarrett.Damore@Sun.COM }
17579286SGarrett.Damore@Sun.COM 
17589286SGarrett.Damore@Sun.COM /*
17599286SGarrett.Damore@Sun.COM  * rtls_chip_start() -- start chip
17609286SGarrett.Damore@Sun.COM  */
17619286SGarrett.Damore@Sun.COM static void
17629286SGarrett.Damore@Sun.COM rtls_chip_start(rtls_t *rtlsp)
17639286SGarrett.Damore@Sun.COM {
17649286SGarrett.Damore@Sun.COM 	uint16_t val16;
17659286SGarrett.Damore@Sun.COM 	uint8_t val8;
17669286SGarrett.Damore@Sun.COM 
17679286SGarrett.Damore@Sun.COM 	/*
17689286SGarrett.Damore@Sun.COM 	 * Start transmit/receive
17699286SGarrett.Damore@Sun.COM 	 */
17709286SGarrett.Damore@Sun.COM 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
17719286SGarrett.Damore@Sun.COM 	rtls_reg_set8(rtlsp, RT_COMMAND_REG,
17729286SGarrett.Damore@Sun.COM 	    val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
17739286SGarrett.Damore@Sun.COM 
17749286SGarrett.Damore@Sun.COM 	/*
17759286SGarrett.Damore@Sun.COM 	 * Enable interrupt
17769286SGarrett.Damore@Sun.COM 	 */
17779286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
17789286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 | RTLS_INT_MASK);
17799286SGarrett.Damore@Sun.COM 	rtlsp->int_mask = RTLS_INT_MASK;
17809286SGarrett.Damore@Sun.COM }
17819286SGarrett.Damore@Sun.COM 
17829286SGarrett.Damore@Sun.COM /*
17839286SGarrett.Damore@Sun.COM  * rtls_chip_restart() -- restart chip
17849286SGarrett.Damore@Sun.COM  */
17859286SGarrett.Damore@Sun.COM static void
17869286SGarrett.Damore@Sun.COM rtls_chip_restart(rtls_t *rtlsp)
17879286SGarrett.Damore@Sun.COM {
17889286SGarrett.Damore@Sun.COM 	(void) rtls_chip_reset(rtlsp, B_FALSE);
17899286SGarrett.Damore@Sun.COM 	rtls_chip_init(rtlsp);
17909286SGarrett.Damore@Sun.COM 	rtls_chip_start(rtlsp);
17919286SGarrett.Damore@Sun.COM }
17929286SGarrett.Damore@Sun.COM 
17939286SGarrett.Damore@Sun.COM /*
17949286SGarrett.Damore@Sun.COM  * rtls_chip_stop() -- stop board receiving
17959286SGarrett.Damore@Sun.COM  */
17969286SGarrett.Damore@Sun.COM static void
17979286SGarrett.Damore@Sun.COM rtls_chip_stop(rtls_t *rtlsp)
17989286SGarrett.Damore@Sun.COM {
17999286SGarrett.Damore@Sun.COM 	uint16_t val16;
18009286SGarrett.Damore@Sun.COM 	uint8_t val8;
18019286SGarrett.Damore@Sun.COM 
18029286SGarrett.Damore@Sun.COM 	/*
18039286SGarrett.Damore@Sun.COM 	 * Disable interrupt
18049286SGarrett.Damore@Sun.COM 	 */
18059286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
18069286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL));
18079286SGarrett.Damore@Sun.COM 	rtlsp->int_mask = RTLS_INT_MASK_NONE;
18089286SGarrett.Damore@Sun.COM 
18099286SGarrett.Damore@Sun.COM 	/*
18109286SGarrett.Damore@Sun.COM 	 * Clear pended interrupt
18119286SGarrett.Damore@Sun.COM 	 */
18129286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
18139286SGarrett.Damore@Sun.COM 	rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16);
18149286SGarrett.Damore@Sun.COM 
18159286SGarrett.Damore@Sun.COM 	/*
18169286SGarrett.Damore@Sun.COM 	 * Stop the board and disable transmit/receive
18179286SGarrett.Damore@Sun.COM 	 */
18189286SGarrett.Damore@Sun.COM 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
18199286SGarrett.Damore@Sun.COM 	val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
18209286SGarrett.Damore@Sun.COM 	rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8);
18219286SGarrett.Damore@Sun.COM }
18229286SGarrett.Damore@Sun.COM 
18239286SGarrett.Damore@Sun.COM /*
18249286SGarrett.Damore@Sun.COM  * rtls_get_mac_addr() -- get the physical network address on the board
18259286SGarrett.Damore@Sun.COM  */
18269286SGarrett.Damore@Sun.COM static void
18279286SGarrett.Damore@Sun.COM rtls_get_mac_addr(rtls_t *rtlsp, uint8_t *macaddr)
18289286SGarrett.Damore@Sun.COM {
18299286SGarrett.Damore@Sun.COM 	uint32_t val32;
18309286SGarrett.Damore@Sun.COM 
18319286SGarrett.Damore@Sun.COM 	/*
18329286SGarrett.Damore@Sun.COM 	 * Read first 4-byte of mac address
18339286SGarrett.Damore@Sun.COM 	 */
18349286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, ID_0_REG);
18359286SGarrett.Damore@Sun.COM 	macaddr[0] = val32 & 0xff;
18369286SGarrett.Damore@Sun.COM 	val32 = val32 >> 8;
18379286SGarrett.Damore@Sun.COM 	macaddr[1] = val32 & 0xff;
18389286SGarrett.Damore@Sun.COM 	val32 = val32 >> 8;
18399286SGarrett.Damore@Sun.COM 	macaddr[2] = val32 & 0xff;
18409286SGarrett.Damore@Sun.COM 	val32 = val32 >> 8;
18419286SGarrett.Damore@Sun.COM 	macaddr[3] = val32 & 0xff;
18429286SGarrett.Damore@Sun.COM 
18439286SGarrett.Damore@Sun.COM 	/*
18449286SGarrett.Damore@Sun.COM 	 * Read last 2-byte of mac address
18459286SGarrett.Damore@Sun.COM 	 */
18469286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, ID_4_REG);
18479286SGarrett.Damore@Sun.COM 	macaddr[4] = val32 & 0xff;
18489286SGarrett.Damore@Sun.COM 	val32 = val32 >> 8;
18499286SGarrett.Damore@Sun.COM 	macaddr[5] = val32 & 0xff;
18509286SGarrett.Damore@Sun.COM }
18519286SGarrett.Damore@Sun.COM 
18529286SGarrett.Damore@Sun.COM static void
18539286SGarrett.Damore@Sun.COM rtls_set_mac_addr(rtls_t *rtlsp, const uint8_t *macaddr)
18549286SGarrett.Damore@Sun.COM {
18559286SGarrett.Damore@Sun.COM 	uint32_t val32;
18569286SGarrett.Damore@Sun.COM 	uint8_t val8;
18579286SGarrett.Damore@Sun.COM 
18589286SGarrett.Damore@Sun.COM 	/*
18599286SGarrett.Damore@Sun.COM 	 * Change to config register write enable mode
18609286SGarrett.Damore@Sun.COM 	 */
1861*11453Sgdamore@opensolaris.org 	val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG);
18629286SGarrett.Damore@Sun.COM 	val8 |= RT_93c46_MODE_CONFIG;
1863*11453Sgdamore@opensolaris.org 	rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
18649286SGarrett.Damore@Sun.COM 
18659286SGarrett.Damore@Sun.COM 	/*
18669286SGarrett.Damore@Sun.COM 	 * Get first 4 bytes of mac address
18679286SGarrett.Damore@Sun.COM 	 */
18689286SGarrett.Damore@Sun.COM 	val32 = macaddr[3];
18699286SGarrett.Damore@Sun.COM 	val32 = val32 << 8;
18709286SGarrett.Damore@Sun.COM 	val32 |= macaddr[2];
18719286SGarrett.Damore@Sun.COM 	val32 = val32 << 8;
18729286SGarrett.Damore@Sun.COM 	val32 |= macaddr[1];
18739286SGarrett.Damore@Sun.COM 	val32 = val32 << 8;
18749286SGarrett.Damore@Sun.COM 	val32 |= macaddr[0];
18759286SGarrett.Damore@Sun.COM 
18769286SGarrett.Damore@Sun.COM 	/*
18779286SGarrett.Damore@Sun.COM 	 * Set first 4 bytes of mac address
18789286SGarrett.Damore@Sun.COM 	 */
18799286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, ID_0_REG, val32);
18809286SGarrett.Damore@Sun.COM 
18819286SGarrett.Damore@Sun.COM 	/*
18829286SGarrett.Damore@Sun.COM 	 * Get last 2 bytes of mac address
18839286SGarrett.Damore@Sun.COM 	 */
18849286SGarrett.Damore@Sun.COM 	val32 = macaddr[5];
18859286SGarrett.Damore@Sun.COM 	val32 = val32 << 8;
18869286SGarrett.Damore@Sun.COM 	val32 |= macaddr[4];
18879286SGarrett.Damore@Sun.COM 
18889286SGarrett.Damore@Sun.COM 	/*
18899286SGarrett.Damore@Sun.COM 	 * Set last 2 bytes of mac address
18909286SGarrett.Damore@Sun.COM 	 */
18919286SGarrett.Damore@Sun.COM 	val32 |= rtls_reg_get32(rtlsp, ID_4_REG) & ~0xffff;
18929286SGarrett.Damore@Sun.COM 	rtls_reg_set32(rtlsp, ID_4_REG, val32);
18939286SGarrett.Damore@Sun.COM 
18949286SGarrett.Damore@Sun.COM 	/*
18959286SGarrett.Damore@Sun.COM 	 * Return to normal network/host communication mode
18969286SGarrett.Damore@Sun.COM 	 */
18979286SGarrett.Damore@Sun.COM 	val8 &= ~RT_93c46_MODE_CONFIG;
1898*11453Sgdamore@opensolaris.org 	rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1899*11453Sgdamore@opensolaris.org }
1900*11453Sgdamore@opensolaris.org 
1901*11453Sgdamore@opensolaris.org static uint16_t
1902*11453Sgdamore@opensolaris.org rtls_mii_read(void *arg, uint8_t phy, uint8_t reg)
1903*11453Sgdamore@opensolaris.org {
1904*11453Sgdamore@opensolaris.org 	rtls_t		*rtlsp = arg;
1905*11453Sgdamore@opensolaris.org 	uint16_t	val;
1906*11453Sgdamore@opensolaris.org 
1907*11453Sgdamore@opensolaris.org 	if (phy != 1) {
1908*11453Sgdamore@opensolaris.org 		return (0xffff);
1909*11453Sgdamore@opensolaris.org 	}
1910*11453Sgdamore@opensolaris.org 	switch (reg) {
1911*11453Sgdamore@opensolaris.org 	case MII_CONTROL:
1912*11453Sgdamore@opensolaris.org 		val = rtls_reg_get16(rtlsp, BASIC_MODE_CONTROL_REG);
1913*11453Sgdamore@opensolaris.org 		break;
1914*11453Sgdamore@opensolaris.org 	case MII_STATUS:
1915*11453Sgdamore@opensolaris.org 		val = rtls_reg_get16(rtlsp, BASIC_MODE_STATUS_REG);
1916*11453Sgdamore@opensolaris.org 		break;
1917*11453Sgdamore@opensolaris.org 	case MII_AN_ADVERT:
1918*11453Sgdamore@opensolaris.org 		val = rtls_reg_get16(rtlsp, AUTO_NEGO_AD_REG);
1919*11453Sgdamore@opensolaris.org 		break;
1920*11453Sgdamore@opensolaris.org 	case MII_AN_LPABLE:
1921*11453Sgdamore@opensolaris.org 		val = rtls_reg_get16(rtlsp, AUTO_NEGO_LP_REG);
1922*11453Sgdamore@opensolaris.org 		break;
1923*11453Sgdamore@opensolaris.org 	case MII_AN_EXPANSION:
1924*11453Sgdamore@opensolaris.org 		val = rtls_reg_get16(rtlsp, AUTO_NEGO_EXP_REG);
1925*11453Sgdamore@opensolaris.org 		break;
1926*11453Sgdamore@opensolaris.org 	case MII_VENDOR(0):
1927*11453Sgdamore@opensolaris.org 		/*
1928*11453Sgdamore@opensolaris.org 		 * We "simulate" a vendor private register so that the
1929*11453Sgdamore@opensolaris.org 		 * PHY layer can access it to determine detected link
1930*11453Sgdamore@opensolaris.org 		 * speed/duplex.
1931*11453Sgdamore@opensolaris.org 		 */
1932*11453Sgdamore@opensolaris.org 		val = rtls_reg_get8(rtlsp, MEDIA_STATUS_REG);
1933*11453Sgdamore@opensolaris.org 		break;
1934*11453Sgdamore@opensolaris.org 	case MII_PHYIDH:
1935*11453Sgdamore@opensolaris.org 	case MII_PHYIDL:
1936*11453Sgdamore@opensolaris.org 	default:
1937*11453Sgdamore@opensolaris.org 		val = 0;
1938*11453Sgdamore@opensolaris.org 		break;
1939*11453Sgdamore@opensolaris.org 	}
1940*11453Sgdamore@opensolaris.org 	return (val);
19419286SGarrett.Damore@Sun.COM }
19429286SGarrett.Damore@Sun.COM 
1943*11453Sgdamore@opensolaris.org void
1944*11453Sgdamore@opensolaris.org rtls_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
19459286SGarrett.Damore@Sun.COM {
1946*11453Sgdamore@opensolaris.org 	rtls_t		*rtlsp = arg;
1947*11453Sgdamore@opensolaris.org 	uint8_t		val8;
19489286SGarrett.Damore@Sun.COM 
1949*11453Sgdamore@opensolaris.org 	if (phy != 1) {
1950*11453Sgdamore@opensolaris.org 		return;
19519286SGarrett.Damore@Sun.COM 	}
1952*11453Sgdamore@opensolaris.org 	switch (reg) {
1953*11453Sgdamore@opensolaris.org 	case MII_CONTROL:
1954*11453Sgdamore@opensolaris.org 		/* Enable writes to all bits of BMCR */
1955*11453Sgdamore@opensolaris.org 		val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG);
1956*11453Sgdamore@opensolaris.org 		val8 |= RT_93c46_MODE_CONFIG;
1957*11453Sgdamore@opensolaris.org 		rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1958*11453Sgdamore@opensolaris.org 		/* write out the value */
1959*11453Sgdamore@opensolaris.org 		rtls_reg_set16(rtlsp, BASIC_MODE_CONTROL_REG, val);
1960*11453Sgdamore@opensolaris.org 
1961*11453Sgdamore@opensolaris.org 		/* Return to normal network/host communication mode */
1962*11453Sgdamore@opensolaris.org 		val8 &= ~RT_93c46_MODE_CONFIG;
1963*11453Sgdamore@opensolaris.org 		rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8);
1964*11453Sgdamore@opensolaris.org 		return;
1965*11453Sgdamore@opensolaris.org 
1966*11453Sgdamore@opensolaris.org 	case MII_STATUS:
1967*11453Sgdamore@opensolaris.org 		rtls_reg_set16(rtlsp, BASIC_MODE_STATUS_REG, val);
19689286SGarrett.Damore@Sun.COM 		break;
1969*11453Sgdamore@opensolaris.org 	case MII_AN_ADVERT:
1970*11453Sgdamore@opensolaris.org 		rtls_reg_set16(rtlsp, AUTO_NEGO_AD_REG, val);
19719286SGarrett.Damore@Sun.COM 		break;
1972*11453Sgdamore@opensolaris.org 	case MII_AN_LPABLE:
1973*11453Sgdamore@opensolaris.org 		rtls_reg_set16(rtlsp, AUTO_NEGO_LP_REG, val);
19749286SGarrett.Damore@Sun.COM 		break;
1975*11453Sgdamore@opensolaris.org 	case MII_AN_EXPANSION:
1976*11453Sgdamore@opensolaris.org 		rtls_reg_set16(rtlsp, AUTO_NEGO_EXP_REG, val);
19779286SGarrett.Damore@Sun.COM 		break;
1978*11453Sgdamore@opensolaris.org 	case MII_PHYIDH:
1979*11453Sgdamore@opensolaris.org 	case MII_PHYIDL:
1980*11453Sgdamore@opensolaris.org 	default:
1981*11453Sgdamore@opensolaris.org 		/* these are not writable */
19829286SGarrett.Damore@Sun.COM 		break;
19839286SGarrett.Damore@Sun.COM 	}
1984*11453Sgdamore@opensolaris.org }
19859286SGarrett.Damore@Sun.COM 
1986*11453Sgdamore@opensolaris.org void
1987*11453Sgdamore@opensolaris.org rtls_mii_notify(void *arg, link_state_t link)
1988*11453Sgdamore@opensolaris.org {
1989*11453Sgdamore@opensolaris.org 	rtls_t	*rtlsp = arg;
19909286SGarrett.Damore@Sun.COM 
1991*11453Sgdamore@opensolaris.org 	mac_link_update(rtlsp->mh, link);
19929286SGarrett.Damore@Sun.COM }
19939286SGarrett.Damore@Sun.COM 
19949286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG
19959286SGarrett.Damore@Sun.COM /*
19969286SGarrett.Damore@Sun.COM  * rtls_reg_print() -- print out reg value(for debug use only)
19979286SGarrett.Damore@Sun.COM  */
19989286SGarrett.Damore@Sun.COM static void
19999286SGarrett.Damore@Sun.COM rtls_reg_print(rtls_t *rtlsp)
20009286SGarrett.Damore@Sun.COM {
20019286SGarrett.Damore@Sun.COM 	uint8_t val8;
20029286SGarrett.Damore@Sun.COM 	uint16_t val16;
20039286SGarrett.Damore@Sun.COM 	uint32_t val32;
20049286SGarrett.Damore@Sun.COM 
20059286SGarrett.Damore@Sun.COM 	val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG);
20069286SGarrett.Damore@Sun.COM 	cmn_err(CE_NOTE, "%s: RT_COMMAND_REG = 0x%x",
20079286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val8);
20089286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20099286SGarrett.Damore@Sun.COM 
20109286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG);
20119286SGarrett.Damore@Sun.COM 	cmn_err(CE_NOTE, "%s: RT_INT_STATUS_REG = 0x%x",
20129286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val16);
20139286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20149286SGarrett.Damore@Sun.COM 
20159286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG);
20169286SGarrett.Damore@Sun.COM 	cmn_err(CE_NOTE, "%s: RT_INT_MASK_REG = 0x%x",
20179286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val16);
20189286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20199286SGarrett.Damore@Sun.COM 
20209286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG);
20219286SGarrett.Damore@Sun.COM 	cmn_err(CE_NOTE, "%s: RX_CONFIG_REG = 0x%x",
20229286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val32);
20239286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20249286SGarrett.Damore@Sun.COM 
20259286SGarrett.Damore@Sun.COM 	val16 = rtls_reg_get16(rtlsp, TX_DESC_STAUS_REG);
2026*11453Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "%s: TX_DESC_STAUS_REG = 0x%x, cur_desc = %d",
20279286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val16, rtlsp->tx_current_desc);
20289286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20299286SGarrett.Damore@Sun.COM 
20309286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG);
2031*11453Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC0_REG = 0x%x",
20329286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val32);
20339286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20349286SGarrett.Damore@Sun.COM 
20359286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC1_REG);
2036*11453Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC1_REG = 0x%x",
20379286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val32);
20389286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20399286SGarrett.Damore@Sun.COM 
20409286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC2_REG);
2041*11453Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC2_REG = 0x%x",
20429286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val32);
20439286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20449286SGarrett.Damore@Sun.COM 
20459286SGarrett.Damore@Sun.COM 	val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC3_REG);
2046*11453Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "%s: TX_STATUS_DESC3_REG = 0x%x",
20479286SGarrett.Damore@Sun.COM 	    rtlsp->ifname, val32);
20489286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20499286SGarrett.Damore@Sun.COM 
2050*11453Sgdamore@opensolaris.org 	cmn_err(CE_NOTE, "%s: in  = %llu, multicast = %llu, broadcast = %llu",
20519286SGarrett.Damore@Sun.COM 	    rtlsp->ifname,
20529286SGarrett.Damore@Sun.COM 	    (unsigned long long)rtlsp->stats.ipackets,
20539286SGarrett.Damore@Sun.COM 	    (unsigned long long)rtlsp->stats.multi_rcv,
20549286SGarrett.Damore@Sun.COM 	    (unsigned long long)rtlsp->stats.brdcst_rcv);
20559286SGarrett.Damore@Sun.COM 	delay(drv_usectohz(1000));
20569286SGarrett.Damore@Sun.COM }
20579286SGarrett.Damore@Sun.COM #endif
2058