xref: /onnv-gate/usr/src/uts/common/io/rtw/rtw.c (revision 11878:ac93462db6d7)
14689Sql147931 /*
2*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
34689Sql147931  * Use is subject to license terms.
44689Sql147931  */
54689Sql147931 
64689Sql147931 /*
74689Sql147931  * Copyright (c) 2004 David Young.  All rights reserved.
84689Sql147931  *
94689Sql147931  * This code was written by David Young.
104689Sql147931  *
114689Sql147931  * Redistribution and use in source and binary forms, with or without
124689Sql147931  * modification, are permitted provided that the following conditions
134689Sql147931  * are met:
144689Sql147931  * 1. Redistributions of source code must retain the above copyright
154689Sql147931  *    notice, this list of conditions and the following disclaimer.
164689Sql147931  * 2. Redistributions in binary form must reproduce the above copyright
174689Sql147931  *    notice, this list of conditions and the following disclaimer in the
184689Sql147931  *    documentation and/or other materials provided with the distribution.
194689Sql147931  * 3. Neither the name of the author nor the names of any co-contributors
204689Sql147931  *    may be used to endorse or promote products derived from this software
214689Sql147931  *    without specific prior written permission.
224689Sql147931  *
234689Sql147931  * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
244689Sql147931  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
254689Sql147931  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
264689Sql147931  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL David
274689Sql147931  * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
284689Sql147931  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
294689Sql147931  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
304689Sql147931  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
314689Sql147931  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
324689Sql147931  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334689Sql147931  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
344689Sql147931  * OF SUCH DAMAGE.
354689Sql147931  */
3610448SMikore.Li@Sun.COM #include <sys/sysmacros.h>
3710448SMikore.Li@Sun.COM #include <sys/pci.h>
384689Sql147931 #include <sys/stat.h>
3910448SMikore.Li@Sun.COM #include <sys/strsubr.h>
4010448SMikore.Li@Sun.COM #include <sys/strsun.h>
418275SEric Cheng #include <sys/mac_provider.h>
424689Sql147931 #include <sys/mac_wifi.h>
4310448SMikore.Li@Sun.COM #include <sys/net80211.h>
44*11878SVenu.Iyer@Sun.COM #include <sys/byteorder.h>
454689Sql147931 #include "rtwreg.h"
464689Sql147931 #include "rtwvar.h"
474689Sql147931 #include "smc93cx6var.h"
484689Sql147931 #include "rtwphy.h"
494689Sql147931 #include "rtwphyio.h"
504689Sql147931 
514689Sql147931 /*
524689Sql147931  * PIO access attributes for registers
534689Sql147931  */
544689Sql147931 static ddi_device_acc_attr_t rtw_reg_accattr = {
554689Sql147931 	DDI_DEVICE_ATTR_V0,
564689Sql147931 	DDI_STRUCTURE_LE_ACC,
574689Sql147931 	DDI_STRICTORDER_ACC,
584689Sql147931 	DDI_DEFAULT_ACC
594689Sql147931 };
604689Sql147931 
614689Sql147931 /*
624689Sql147931  * DMA access attributes for descriptors and bufs: NOT to be byte swapped.
634689Sql147931  */
644689Sql147931 static ddi_device_acc_attr_t rtw_desc_accattr = {
654689Sql147931 	DDI_DEVICE_ATTR_V0,
664689Sql147931 	DDI_NEVERSWAP_ACC,
674689Sql147931 	DDI_STRICTORDER_ACC,
684689Sql147931 	DDI_DEFAULT_ACC
694689Sql147931 };
704689Sql147931 static ddi_device_acc_attr_t rtw_buf_accattr = {
714689Sql147931 	DDI_DEVICE_ATTR_V0,
724689Sql147931 	DDI_NEVERSWAP_ACC,
734689Sql147931 	DDI_STRICTORDER_ACC,
744689Sql147931 	DDI_DEFAULT_ACC
754689Sql147931 };
764689Sql147931 
774689Sql147931 /*
784689Sql147931  * Describes the chip's DMA engine
794689Sql147931  */
804689Sql147931 static ddi_dma_attr_t dma_attr_desc = {
814689Sql147931 	DMA_ATTR_V0,			/* dma_attr version */
824689Sql147931 	0x0000000000000000ull,		/* dma_attr_addr_lo */
836890Sql147931 	0xFFFFFFFF,			/* dma_attr_addr_hi */
844689Sql147931 	0x00000000FFFFFFFFull,		/* dma_attr_count_max */
854689Sql147931 	0x100,				/* dma_attr_align */
864689Sql147931 	0xFFFFFFFF,			/* dma_attr_burstsizes */
874689Sql147931 	0x00000001,			/* dma_attr_minxfer */
884689Sql147931 	0x00000000FFFFull,		/* dma_attr_maxxfer */
894689Sql147931 	0xFFFFFFFFFFFFFFFFull,		/* dma_attr_seg */
904689Sql147931 	1,				/* dma_attr_sgllen */
914689Sql147931 	1,				/* dma_attr_granular */
924689Sql147931 	0				/* dma_attr_flags */
934689Sql147931 };
944689Sql147931 
954689Sql147931 static ddi_dma_attr_t dma_attr_rxbuf = {
964689Sql147931 	DMA_ATTR_V0,			/* dma_attr version */
974689Sql147931 	0x0000000000000000ull,		/* dma_attr_addr_lo */
986890Sql147931 	0xFFFFFFFF,			/* dma_attr_addr_hi */
994689Sql147931 	0x00000000FFFFFFFFull,		/* dma_attr_count_max */
1004689Sql147931 	(uint32_t)16,			/* dma_attr_align */
1014689Sql147931 	0xFFFFFFFF,			/* dma_attr_burstsizes */
1024689Sql147931 	0x00000001,			/* dma_attr_minxfer */
1034689Sql147931 	0x00000000FFFFull,		/* dma_attr_maxxfer */
1044689Sql147931 	0xFFFFFFFFFFFFFFFFull,		/* dma_attr_seg */
1054689Sql147931 	1,				/* dma_attr_sgllen */
1064689Sql147931 	1,				/* dma_attr_granular */
1074689Sql147931 	0				/* dma_attr_flags */
1084689Sql147931 };
1094689Sql147931 
1104689Sql147931 static ddi_dma_attr_t dma_attr_txbuf = {
1114689Sql147931 	DMA_ATTR_V0,			/* dma_attr version */
1124689Sql147931 	0x0000000000000000ull,		/* dma_attr_addr_lo */
1136890Sql147931 	0xFFFFFFFF,			/* dma_attr_addr_hi */
1144689Sql147931 	0x00000000FFFFFFFFull,		/* dma_attr_count_max */
1154689Sql147931 	(uint32_t)16,			/* dma_attr_align */
1164689Sql147931 	0xFFFFFFFF,			/* dma_attr_burstsizes */
1174689Sql147931 	0x00000001,			/* dma_attr_minxfer */
1184689Sql147931 	0x00000000FFFFull,		/* dma_attr_maxxfer */
1194689Sql147931 	0xFFFFFFFFFFFFFFFFull,		/* dma_attr_seg */
1204689Sql147931 	1,				/* dma_attr_sgllen */
1214689Sql147931 	1,				/* dma_attr_granular */
1224689Sql147931 	0				/* dma_attr_flags */
1234689Sql147931 };
1244689Sql147931 
1254689Sql147931 
1264689Sql147931 static void *rtw_soft_state_p = NULL;
1274689Sql147931 
12810448SMikore.Li@Sun.COM static void	rtw_stop(void *);
12910448SMikore.Li@Sun.COM static int	rtw_attach(dev_info_t *, ddi_attach_cmd_t);
13010448SMikore.Li@Sun.COM static int	rtw_detach(dev_info_t *, ddi_detach_cmd_t);
13110448SMikore.Li@Sun.COM static int	rtw_quiesce(dev_info_t *);
1324689Sql147931 static int	rtw_m_stat(void *,  uint_t, uint64_t *);
1334689Sql147931 static int	rtw_m_start(void *);
1344689Sql147931 static void	rtw_m_stop(void *);
1354689Sql147931 static int	rtw_m_promisc(void *, boolean_t);
1364689Sql147931 static int	rtw_m_multicst(void *, boolean_t, const uint8_t *);
1374689Sql147931 static int	rtw_m_unicst(void *, const uint8_t *);
1384689Sql147931 static mblk_t	*rtw_m_tx(void *, mblk_t *);
1394689Sql147931 static void	rtw_m_ioctl(void *, queue_t *, mblk_t *);
1408237SMikore.Li@Sun.COM static int	rtw_m_setprop(void *, const char *, mac_prop_id_t,
1418237SMikore.Li@Sun.COM     uint_t, const void *);
1428237SMikore.Li@Sun.COM static int	rtw_m_getprop(void *, const char *, mac_prop_id_t,
143*11878SVenu.Iyer@Sun.COM     uint_t, void *);
144*11878SVenu.Iyer@Sun.COM static void	rtw_m_propinfo(void *, const char *, mac_prop_id_t,
145*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t);
1468237SMikore.Li@Sun.COM 
1474689Sql147931 static mac_callbacks_t rtw_m_callbacks = {
148*11878SVenu.Iyer@Sun.COM 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1494689Sql147931 	rtw_m_stat,
1504689Sql147931 	rtw_m_start,
1514689Sql147931 	rtw_m_stop,
1524689Sql147931 	rtw_m_promisc,
1534689Sql147931 	rtw_m_multicst,
1544689Sql147931 	rtw_m_unicst,
1554689Sql147931 	rtw_m_tx,
156*11878SVenu.Iyer@Sun.COM 	NULL,
1578237SMikore.Li@Sun.COM 	rtw_m_ioctl,
1588237SMikore.Li@Sun.COM 	NULL,		/* mc_getcapab */
1598237SMikore.Li@Sun.COM 	NULL,
1608237SMikore.Li@Sun.COM 	NULL,
1618237SMikore.Li@Sun.COM 	rtw_m_setprop,
162*11878SVenu.Iyer@Sun.COM 	rtw_m_getprop,
163*11878SVenu.Iyer@Sun.COM 	rtw_m_propinfo
1644689Sql147931 };
1654689Sql147931 
1664689Sql147931 DDI_DEFINE_STREAM_OPS(rtw_dev_ops, nulldev, nulldev, rtw_attach, rtw_detach,
1678237SMikore.Li@Sun.COM     nodev, NULL, D_MP, NULL, rtw_quiesce);
1684689Sql147931 
1694689Sql147931 static struct modldrv rtw_modldrv = {
1704689Sql147931 	&mod_driverops,		/* Type of module.  This one is a driver */
17110448SMikore.Li@Sun.COM 	"realtek 8180L driver 1.7",	/* short description */
1724689Sql147931 	&rtw_dev_ops		/* driver specific ops */
1734689Sql147931 };
1744689Sql147931 
1754689Sql147931 static struct modlinkage modlinkage = {
1764689Sql147931 	MODREV_1, (void *)&rtw_modldrv, NULL
1774689Sql147931 };
1784689Sql147931 
1794689Sql147931 static uint32_t rtw_qlen[RTW_NTXPRI] = {
1804689Sql147931 	RTW_TXQLENLO,
1814689Sql147931 	RTW_TXQLENMD,
1824689Sql147931 	RTW_TXQLENHI,
1834689Sql147931 	RTW_TXQLENBCN
1844689Sql147931 };
1854689Sql147931 
1866890Sql147931 uint32_t rtw_dbg_flags = 0;
1874689Sql147931 	/*
1884689Sql147931 	 * RTW_DEBUG_ATTACH | RTW_DEBUG_TUNE |
1894689Sql147931 	 * RTW_DEBUG_ACCESS | RTW_DEBUG_INIT | RTW_DEBUG_PKTFILT |
1904689Sql147931 	 * RTW_DEBUG_RECV | RTW_DEBUG_XMIT | RTW_DEBUG_80211 | RTW_DEBUG_INTR |
1914689Sql147931 	 * RTW_DEBUG_PKTDUMP;
1924689Sql147931 	 */
1934689Sql147931 
1948237SMikore.Li@Sun.COM /*
1958237SMikore.Li@Sun.COM  * Supported rates for 802.11b modes (in 500Kbps unit).
1968237SMikore.Li@Sun.COM  */
1978237SMikore.Li@Sun.COM static const struct ieee80211_rateset rtw_rateset_11b =
1988237SMikore.Li@Sun.COM 	{ 4, { 2, 4, 11, 22 } };
1998237SMikore.Li@Sun.COM 
2004689Sql147931 int
_info(struct modinfo * modinfop)2014689Sql147931 _info(struct modinfo *modinfop)
2024689Sql147931 {
2034689Sql147931 	return (mod_info(&modlinkage, modinfop));
2044689Sql147931 }
2054689Sql147931 
2064689Sql147931 int
_init(void)2074689Sql147931 _init(void)
2084689Sql147931 {
2094689Sql147931 	int status;
2104689Sql147931 
2114689Sql147931 	status = ddi_soft_state_init(&rtw_soft_state_p,
2124689Sql147931 	    sizeof (rtw_softc_t), 1);
2134689Sql147931 	if (status != 0)
2144689Sql147931 		return (status);
2154689Sql147931 
2164689Sql147931 	mac_init_ops(&rtw_dev_ops, "rtw");
2174689Sql147931 	status = mod_install(&modlinkage);
2184689Sql147931 	if (status != 0) {
2194689Sql147931 		mac_fini_ops(&rtw_dev_ops);
2204689Sql147931 		ddi_soft_state_fini(&rtw_soft_state_p);
2214689Sql147931 	}
2224689Sql147931 	return (status);
2234689Sql147931 }
2244689Sql147931 
2254689Sql147931 int
_fini(void)2264689Sql147931 _fini(void)
2274689Sql147931 {
2284689Sql147931 	int status;
2294689Sql147931 
2304689Sql147931 	status = mod_remove(&modlinkage);
2314689Sql147931 	if (status == 0) {
2324689Sql147931 		mac_fini_ops(&rtw_dev_ops);
2334689Sql147931 		ddi_soft_state_fini(&rtw_soft_state_p);
2344689Sql147931 	}
2354689Sql147931 	return (status);
2364689Sql147931 }
2374689Sql147931 
2384689Sql147931 void
rtw_dbg(uint32_t dbg_flags,const int8_t * fmt,...)2394689Sql147931 rtw_dbg(uint32_t dbg_flags, const int8_t *fmt, ...)
2404689Sql147931 {
2414689Sql147931 	va_list args;
2424689Sql147931 
2434689Sql147931 	if (dbg_flags & rtw_dbg_flags) {
2444689Sql147931 		va_start(args, fmt);
2454689Sql147931 		vcmn_err(CE_CONT, fmt, args);
2464689Sql147931 		va_end(args);
2474689Sql147931 	}
2484689Sql147931 }
2494689Sql147931 
2504689Sql147931 #ifdef DEBUG
2514689Sql147931 static void
rtw_print_regs(struct rtw_regs * regs,const char * dvname,const char * where)2524689Sql147931 rtw_print_regs(struct rtw_regs *regs, const char *dvname, const char *where)
2534689Sql147931 {
2544689Sql147931 #define	PRINTREG32(sc, reg)				\
2554689Sql147931 	RTW_DPRINTF(RTW_DEBUG_REGDUMP,			\
2564689Sql147931 	    "%s: reg[ " #reg " / %03x ] = %08x\n",	\
2574689Sql147931 	    dvname, reg, RTW_READ(regs, reg))
2584689Sql147931 
2594689Sql147931 #define	PRINTREG16(sc, reg)				\
2604689Sql147931 	RTW_DPRINTF(RTW_DEBUG_REGDUMP,			\
2614689Sql147931 	    "%s: reg[ " #reg " / %03x ] = %04x\n",	\
2624689Sql147931 	    dvname, reg, RTW_READ16(regs, reg))
2634689Sql147931 
2644689Sql147931 #define	PRINTREG8(sc, reg)				\
2654689Sql147931 	RTW_DPRINTF(RTW_DEBUG_REGDUMP,			\
2664689Sql147931 	    "%s: reg[ " #reg " / %03x ] = %02x\n",	\
2674689Sql147931 	    dvname, reg, RTW_READ8(regs, reg))
2684689Sql147931 
2694689Sql147931 	RTW_DPRINTF(RTW_DEBUG_REGDUMP, "%s: %s\n", dvname, where);
2704689Sql147931 
2714689Sql147931 	PRINTREG32(regs, RTW_IDR0);
2724689Sql147931 	PRINTREG32(regs, RTW_IDR1);
2734689Sql147931 	PRINTREG32(regs, RTW_MAR0);
2744689Sql147931 	PRINTREG32(regs, RTW_MAR1);
2754689Sql147931 	PRINTREG32(regs, RTW_TSFTRL);
2764689Sql147931 	PRINTREG32(regs, RTW_TSFTRH);
2774689Sql147931 	PRINTREG32(regs, RTW_TLPDA);
2784689Sql147931 	PRINTREG32(regs, RTW_TNPDA);
2794689Sql147931 	PRINTREG32(regs, RTW_THPDA);
2804689Sql147931 	PRINTREG32(regs, RTW_TCR);
2814689Sql147931 	PRINTREG32(regs, RTW_RCR);
2824689Sql147931 	PRINTREG32(regs, RTW_TINT);
2834689Sql147931 	PRINTREG32(regs, RTW_TBDA);
2844689Sql147931 	PRINTREG32(regs, RTW_ANAPARM);
2854689Sql147931 	PRINTREG32(regs, RTW_BB);
2864689Sql147931 	PRINTREG32(regs, RTW_PHYCFG);
2874689Sql147931 	PRINTREG32(regs, RTW_WAKEUP0L);
2884689Sql147931 	PRINTREG32(regs, RTW_WAKEUP0H);
2894689Sql147931 	PRINTREG32(regs, RTW_WAKEUP1L);
2904689Sql147931 	PRINTREG32(regs, RTW_WAKEUP1H);
2914689Sql147931 	PRINTREG32(regs, RTW_WAKEUP2LL);
2924689Sql147931 	PRINTREG32(regs, RTW_WAKEUP2LH);
2934689Sql147931 	PRINTREG32(regs, RTW_WAKEUP2HL);
2944689Sql147931 	PRINTREG32(regs, RTW_WAKEUP2HH);
2954689Sql147931 	PRINTREG32(regs, RTW_WAKEUP3LL);
2964689Sql147931 	PRINTREG32(regs, RTW_WAKEUP3LH);
2974689Sql147931 	PRINTREG32(regs, RTW_WAKEUP3HL);
2984689Sql147931 	PRINTREG32(regs, RTW_WAKEUP3HH);
2994689Sql147931 	PRINTREG32(regs, RTW_WAKEUP4LL);
3004689Sql147931 	PRINTREG32(regs, RTW_WAKEUP4LH);
3014689Sql147931 	PRINTREG32(regs, RTW_WAKEUP4HL);
3024689Sql147931 	PRINTREG32(regs, RTW_WAKEUP4HH);
3034689Sql147931 	PRINTREG32(regs, RTW_DK0);
3044689Sql147931 	PRINTREG32(regs, RTW_DK1);
3054689Sql147931 	PRINTREG32(regs, RTW_DK2);
3064689Sql147931 	PRINTREG32(regs, RTW_DK3);
3074689Sql147931 	PRINTREG32(regs, RTW_RETRYCTR);
3084689Sql147931 	PRINTREG32(regs, RTW_RDSAR);
3094689Sql147931 	PRINTREG32(regs, RTW_FER);
3104689Sql147931 	PRINTREG32(regs, RTW_FEMR);
3114689Sql147931 	PRINTREG32(regs, RTW_FPSR);
3124689Sql147931 	PRINTREG32(regs, RTW_FFER);
3134689Sql147931 
3144689Sql147931 	/* 16-bit registers */
3154689Sql147931 	PRINTREG16(regs, RTW_BRSR);
3164689Sql147931 	PRINTREG16(regs, RTW_IMR);
3174689Sql147931 	PRINTREG16(regs, RTW_ISR);
3184689Sql147931 	PRINTREG16(regs, RTW_BCNITV);
3194689Sql147931 	PRINTREG16(regs, RTW_ATIMWND);
3204689Sql147931 	PRINTREG16(regs, RTW_BINTRITV);
3214689Sql147931 	PRINTREG16(regs, RTW_ATIMTRITV);
3224689Sql147931 	PRINTREG16(regs, RTW_CRC16ERR);
3234689Sql147931 	PRINTREG16(regs, RTW_CRC0);
3244689Sql147931 	PRINTREG16(regs, RTW_CRC1);
3254689Sql147931 	PRINTREG16(regs, RTW_CRC2);
3264689Sql147931 	PRINTREG16(regs, RTW_CRC3);
3274689Sql147931 	PRINTREG16(regs, RTW_CRC4);
3284689Sql147931 	PRINTREG16(regs, RTW_CWR);
3294689Sql147931 
3304689Sql147931 	/* 8-bit registers */
3314689Sql147931 	PRINTREG8(regs, RTW_CR);
3324689Sql147931 	PRINTREG8(regs, RTW_9346CR);
3334689Sql147931 	PRINTREG8(regs, RTW_CONFIG0);
3344689Sql147931 	PRINTREG8(regs, RTW_CONFIG1);
3354689Sql147931 	PRINTREG8(regs, RTW_CONFIG2);
3364689Sql147931 	PRINTREG8(regs, RTW_MSR);
3374689Sql147931 	PRINTREG8(regs, RTW_CONFIG3);
3384689Sql147931 	PRINTREG8(regs, RTW_CONFIG4);
3394689Sql147931 	PRINTREG8(regs, RTW_TESTR);
3404689Sql147931 	PRINTREG8(regs, RTW_PSR);
3414689Sql147931 	PRINTREG8(regs, RTW_SCR);
3424689Sql147931 	PRINTREG8(regs, RTW_PHYDELAY);
3434689Sql147931 	PRINTREG8(regs, RTW_CRCOUNT);
3444689Sql147931 	PRINTREG8(regs, RTW_PHYADDR);
3454689Sql147931 	PRINTREG8(regs, RTW_PHYDATAW);
3464689Sql147931 	PRINTREG8(regs, RTW_PHYDATAR);
3474689Sql147931 	PRINTREG8(regs, RTW_CONFIG5);
3484689Sql147931 	PRINTREG8(regs, RTW_TPPOLL);
3494689Sql147931 
3504689Sql147931 	PRINTREG16(regs, RTW_BSSID16);
3514689Sql147931 	PRINTREG32(regs, RTW_BSSID32);
3524689Sql147931 #undef PRINTREG32
3534689Sql147931 #undef PRINTREG16
3544689Sql147931 #undef PRINTREG8
3554689Sql147931 }
3564689Sql147931 
3574689Sql147931 #endif /* DEBUG */
3584689Sql147931 static const char *
rtw_access_string(enum rtw_access access)3594689Sql147931 rtw_access_string(enum rtw_access access)
3604689Sql147931 {
3614689Sql147931 	switch (access) {
3624689Sql147931 	case RTW_ACCESS_NONE:
3634689Sql147931 		return ("none");
3644689Sql147931 	case RTW_ACCESS_CONFIG:
3654689Sql147931 		return ("config");
3664689Sql147931 	case RTW_ACCESS_ANAPARM:
3674689Sql147931 		return ("anaparm");
3684689Sql147931 	default:
3694689Sql147931 		return ("unknown");
3704689Sql147931 	}
3714689Sql147931 }
3724689Sql147931 
3734689Sql147931 /*
3744689Sql147931  * Enable registers, switch register banks.
3754689Sql147931  */
3764689Sql147931 void
rtw_config0123_enable(struct rtw_regs * regs,int enable)3774689Sql147931 rtw_config0123_enable(struct rtw_regs *regs, int enable)
3784689Sql147931 {
3794689Sql147931 	uint8_t ecr;
3804689Sql147931 	ecr = RTW_READ8(regs, RTW_9346CR);
3814689Sql147931 	ecr &= ~(RTW_9346CR_EEM_MASK | RTW_9346CR_EECS | RTW_9346CR_EESK);
3824689Sql147931 	if (enable)
3834689Sql147931 		ecr |= RTW_9346CR_EEM_CONFIG;
3844689Sql147931 	else {
3854689Sql147931 		RTW_WBW(regs, RTW_9346CR, MAX(RTW_CONFIG0, RTW_CONFIG3));
3864689Sql147931 		ecr |= RTW_9346CR_EEM_NORMAL;
3874689Sql147931 	}
3884689Sql147931 	RTW_WRITE8(regs, RTW_9346CR, ecr);
3894689Sql147931 	RTW_SYNC(regs, RTW_9346CR, RTW_9346CR);
3904689Sql147931 }
3914689Sql147931 
3924689Sql147931 /*
3934689Sql147931  * requires rtw_config0123_enable(, 1)
3944689Sql147931  */
3954689Sql147931 void
rtw_anaparm_enable(struct rtw_regs * regs,int enable)3964689Sql147931 rtw_anaparm_enable(struct rtw_regs *regs, int enable)
3974689Sql147931 {
3984689Sql147931 	uint8_t cfg3;
3994689Sql147931 
4004689Sql147931 	cfg3 = RTW_READ8(regs, RTW_CONFIG3);
4014689Sql147931 	cfg3 |= RTW_CONFIG3_CLKRUNEN;
4024689Sql147931 	if (enable)
4034689Sql147931 		cfg3 |= RTW_CONFIG3_PARMEN;
4044689Sql147931 	else
4054689Sql147931 		cfg3 &= ~RTW_CONFIG3_PARMEN;
4064689Sql147931 	RTW_WRITE8(regs, RTW_CONFIG3, cfg3);
4074689Sql147931 	RTW_SYNC(regs, RTW_CONFIG3, RTW_CONFIG3);
4084689Sql147931 }
4094689Sql147931 
4104689Sql147931 /*
4114689Sql147931  * requires rtw_anaparm_enable(, 1)
4124689Sql147931  */
4134689Sql147931 void
rtw_txdac_enable(rtw_softc_t * rsc,int enable)4144689Sql147931 rtw_txdac_enable(rtw_softc_t *rsc, int enable)
4154689Sql147931 {
4164689Sql147931 	uint32_t anaparm;
4174689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
4184689Sql147931 
4194689Sql147931 	anaparm = RTW_READ(regs, RTW_ANAPARM);
4204689Sql147931 	if (enable)
4214689Sql147931 		anaparm &= ~RTW_ANAPARM_TXDACOFF;
4224689Sql147931 	else
4234689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
4244689Sql147931 	RTW_WRITE(regs, RTW_ANAPARM, anaparm);
4254689Sql147931 	RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
4264689Sql147931 }
4274689Sql147931 
4284689Sql147931 static void
rtw_set_access1(struct rtw_regs * regs,enum rtw_access naccess)4294689Sql147931 rtw_set_access1(struct rtw_regs *regs, enum rtw_access naccess)
4304689Sql147931 {
4314689Sql147931 	ASSERT(naccess >= RTW_ACCESS_NONE && naccess <= RTW_ACCESS_ANAPARM);
4324689Sql147931 	ASSERT(regs->r_access >= RTW_ACCESS_NONE &&
4334689Sql147931 	    regs->r_access <= RTW_ACCESS_ANAPARM);
4344689Sql147931 
4354689Sql147931 	if (naccess == regs->r_access)
4364689Sql147931 		return;
4374689Sql147931 
4384689Sql147931 	switch (naccess) {
4394689Sql147931 	case RTW_ACCESS_NONE:
4404689Sql147931 		switch (regs->r_access) {
4414689Sql147931 		case RTW_ACCESS_ANAPARM:
4424689Sql147931 			rtw_anaparm_enable(regs, 0);
4434689Sql147931 			/*FALLTHROUGH*/
4444689Sql147931 		case RTW_ACCESS_CONFIG:
4454689Sql147931 			rtw_config0123_enable(regs, 0);
4464689Sql147931 			/*FALLTHROUGH*/
4474689Sql147931 		case RTW_ACCESS_NONE:
4484689Sql147931 			break;
4494689Sql147931 		}
4504689Sql147931 		break;
4514689Sql147931 	case RTW_ACCESS_CONFIG:
4524689Sql147931 		switch (regs->r_access) {
4534689Sql147931 		case RTW_ACCESS_NONE:
4544689Sql147931 			rtw_config0123_enable(regs, 1);
4554689Sql147931 			/*FALLTHROUGH*/
4564689Sql147931 		case RTW_ACCESS_CONFIG:
4574689Sql147931 			break;
4584689Sql147931 		case RTW_ACCESS_ANAPARM:
4594689Sql147931 			rtw_anaparm_enable(regs, 0);
4604689Sql147931 			break;
4614689Sql147931 		}
4624689Sql147931 		break;
4634689Sql147931 	case RTW_ACCESS_ANAPARM:
4644689Sql147931 		switch (regs->r_access) {
4654689Sql147931 		case RTW_ACCESS_NONE:
4664689Sql147931 			rtw_config0123_enable(regs, 1);
4674689Sql147931 			/*FALLTHROUGH*/
4684689Sql147931 		case RTW_ACCESS_CONFIG:
4694689Sql147931 			rtw_anaparm_enable(regs, 1);
4704689Sql147931 			/*FALLTHROUGH*/
4714689Sql147931 		case RTW_ACCESS_ANAPARM:
4724689Sql147931 			break;
4734689Sql147931 		}
4744689Sql147931 		break;
4754689Sql147931 	}
4764689Sql147931 }
4774689Sql147931 
4784689Sql147931 void
rtw_set_access(struct rtw_regs * regs,enum rtw_access access)4794689Sql147931 rtw_set_access(struct rtw_regs *regs, enum rtw_access access)
4804689Sql147931 {
4814689Sql147931 	rtw_set_access1(regs, access);
4824689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ACCESS,
4834689Sql147931 	    "%s: access %s -> %s\n", __func__,
4844689Sql147931 	    rtw_access_string(regs->r_access),
4854689Sql147931 	    rtw_access_string(access));
4864689Sql147931 	regs->r_access = access;
4874689Sql147931 }
4884689Sql147931 
4894689Sql147931 
4904689Sql147931 void
rtw_continuous_tx_enable(rtw_softc_t * rsc,int enable)4914689Sql147931 rtw_continuous_tx_enable(rtw_softc_t *rsc, int enable)
4924689Sql147931 {
4934689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
4944689Sql147931 
4954689Sql147931 	uint32_t tcr;
4964689Sql147931 	tcr = RTW_READ(regs, RTW_TCR);
4974689Sql147931 	tcr &= ~RTW_TCR_LBK_MASK;
4984689Sql147931 	if (enable)
4994689Sql147931 		tcr |= RTW_TCR_LBK_CONT;
5004689Sql147931 	else
5014689Sql147931 		tcr |= RTW_TCR_LBK_NORMAL;
5024689Sql147931 	RTW_WRITE(regs, RTW_TCR, tcr);
5034689Sql147931 	RTW_SYNC(regs, RTW_TCR, RTW_TCR);
5044689Sql147931 	rtw_set_access(regs, RTW_ACCESS_ANAPARM);
5054689Sql147931 	rtw_txdac_enable(rsc, !enable);
5064689Sql147931 	rtw_set_access(regs, RTW_ACCESS_ANAPARM);
5074689Sql147931 	rtw_set_access(regs, RTW_ACCESS_NONE);
5084689Sql147931 }
5094689Sql147931 
5104689Sql147931 static int
rtw_chip_reset1(struct rtw_regs * regs,const char * dvname)5114689Sql147931 rtw_chip_reset1(struct rtw_regs *regs, const char *dvname)
5124689Sql147931 {
5134689Sql147931 	uint8_t cr;
5144689Sql147931 	int i;
5154689Sql147931 
5164689Sql147931 	RTW_WRITE8(regs, RTW_CR, RTW_CR_RST);
5174689Sql147931 
5184689Sql147931 	RTW_WBR(regs, RTW_CR, RTW_CR);
5194689Sql147931 
5204689Sql147931 	for (i = 0; i < 1000; i++) {
5214689Sql147931 		cr = RTW_READ8(regs, RTW_CR);
5224689Sql147931 		if ((cr & RTW_CR_RST) == 0) {
5234689Sql147931 			RTW_DPRINTF(RTW_DEBUG_RESET,
5244689Sql147931 			    "%s: reset in %dus\n", dvname, i);
5254689Sql147931 			return (0);
5264689Sql147931 		}
5274689Sql147931 		RTW_RBR(regs, RTW_CR, RTW_CR);
5284689Sql147931 		DELAY(10); /* 10us */
5294689Sql147931 	}
5304689Sql147931 
5314689Sql147931 	cmn_err(CE_WARN, "%s: reset failed\n", dvname);
5324689Sql147931 	return (ETIMEDOUT);
5334689Sql147931 }
5344689Sql147931 
5354689Sql147931 static int
rtw_chip_reset(struct rtw_regs * regs,const char * dvname)5364689Sql147931 rtw_chip_reset(struct rtw_regs *regs, const char *dvname)
5374689Sql147931 {
5384689Sql147931 	RTW_WBW(regs, RTW_CR, RTW_TCR);
5394689Sql147931 	return (rtw_chip_reset1(regs, dvname));
5404689Sql147931 }
5414689Sql147931 
5424689Sql147931 static void
rtw_disable_interrupts(struct rtw_regs * regs)5434689Sql147931 rtw_disable_interrupts(struct rtw_regs *regs)
5444689Sql147931 {
5454689Sql147931 	RTW_WRITE16(regs, RTW_IMR, 0);
5464689Sql147931 	RTW_WRITE16(regs, RTW_ISR, 0xffff);
5474689Sql147931 	(void) RTW_READ16(regs, RTW_IMR);
5484689Sql147931 }
5494689Sql147931 
5504689Sql147931 static void
rtw_enable_interrupts(rtw_softc_t * rsc)5514689Sql147931 rtw_enable_interrupts(rtw_softc_t *rsc)
5524689Sql147931 {
5534689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
5544689Sql147931 
5554689Sql147931 	rsc->sc_inten = RTW_INTR_RX | RTW_INTR_TX | RTW_INTR_IOERROR;
5564689Sql147931 
5574689Sql147931 	RTW_WRITE16(regs, RTW_IMR, rsc->sc_inten);
5584689Sql147931 	RTW_WRITE16(regs, RTW_ISR, 0xffff);
5594689Sql147931 
5604689Sql147931 	/* XXX necessary? */
5614689Sql147931 	if (rsc->sc_intr_ack != NULL)
5624689Sql147931 		(*rsc->sc_intr_ack)(regs);
5634689Sql147931 }
5644689Sql147931 
5654689Sql147931 static int
rtw_recall_eeprom(struct rtw_regs * regs,const char * dvname)5664689Sql147931 rtw_recall_eeprom(struct rtw_regs *regs, const char *dvname)
5674689Sql147931 {
5684689Sql147931 	int i;
5694689Sql147931 	uint8_t ecr;
5704689Sql147931 
5714689Sql147931 	ecr = RTW_READ8(regs, RTW_9346CR);
5724689Sql147931 	ecr = (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_AUTOLOAD;
5734689Sql147931 	RTW_WRITE8(regs, RTW_9346CR, ecr);
5744689Sql147931 
5754689Sql147931 	RTW_WBR(regs, RTW_9346CR, RTW_9346CR);
5764689Sql147931 
5774689Sql147931 	/* wait 25ms for completion */
5784689Sql147931 	for (i = 0; i < 250; i++) {
5794689Sql147931 		ecr = RTW_READ8(regs, RTW_9346CR);
5804689Sql147931 		if ((ecr & RTW_9346CR_EEM_MASK) == RTW_9346CR_EEM_NORMAL) {
5814689Sql147931 			RTW_DPRINTF(RTW_DEBUG_RESET,
5824689Sql147931 			    "%s: recall EEPROM in %dus\n", dvname, i * 100);
5834689Sql147931 			return (0);
5844689Sql147931 		}
5854689Sql147931 		RTW_RBR(regs, RTW_9346CR, RTW_9346CR);
5864689Sql147931 		DELAY(100);
5874689Sql147931 	}
5884689Sql147931 	cmn_err(CE_WARN, "%s: recall EEPROM failed\n", dvname);
5894689Sql147931 	return (ETIMEDOUT);
5904689Sql147931 }
5914689Sql147931 
5924689Sql147931 static int
rtw_reset(rtw_softc_t * rsc)5934689Sql147931 rtw_reset(rtw_softc_t *rsc)
5944689Sql147931 {
5954689Sql147931 	int rc;
5964689Sql147931 
5974689Sql147931 	rc = rtw_chip_reset(&rsc->sc_regs, "rtw");
5984689Sql147931 	if (rc != 0)
5994689Sql147931 		return (rc);
6004689Sql147931 
6014689Sql147931 	(void) rtw_recall_eeprom(&rsc->sc_regs, "rtw");
6024689Sql147931 	return (0);
6034689Sql147931 }
6044689Sql147931 
6054689Sql147931 void
rtw_set_mode(struct rtw_regs * regs,int mode)6064689Sql147931 rtw_set_mode(struct rtw_regs *regs, int mode)
6074689Sql147931 {
6084689Sql147931 	uint8_t command;
6094689Sql147931 	command = RTW_READ8(regs, RTW_9346CR);
6104689Sql147931 	command = command &~ RTW_EPROM_CMD_OPERATING_MODE_MASK;
6114689Sql147931 	command = command | (mode<<RTW_EPROM_CMD_OPERATING_MODE_SHIFT);
6124689Sql147931 	command = command &~ (1<<RTW_EPROM_CS_SHIFT);
6134689Sql147931 	command = command &~ (1<<RTW_EPROM_CK_SHIFT);
6144689Sql147931 	RTW_WRITE8(regs, RTW_9346CR, command);
6154689Sql147931 }
6164689Sql147931 
6174689Sql147931 void
rtw_dma_start(struct rtw_regs * regs,int priority)6184689Sql147931 rtw_dma_start(struct rtw_regs *regs, int priority)
6194689Sql147931 {
6204689Sql147931 	uint8_t check = 0;
6214689Sql147931 
6224689Sql147931 	check = RTW_READ8(regs, RTW_TPPOLL);
6234689Sql147931 	switch (priority) {
6244689Sql147931 	case (0):
6254689Sql147931 		RTW_WRITE8(regs, RTW_TPPOLL,
6264689Sql147931 		    (1<< RTW_TX_DMA_POLLING_LOWPRIORITY_SHIFT) | check);
6274689Sql147931 		break;
6284689Sql147931 	case (1):
6294689Sql147931 		RTW_WRITE8(regs, RTW_TPPOLL,
6304689Sql147931 		    (1<< RTW_TX_DMA_POLLING_NORMPRIORITY_SHIFT) | check);
6314689Sql147931 		break;
6324689Sql147931 	case (2):
6334689Sql147931 		RTW_WRITE8(regs, RTW_TPPOLL,
6344689Sql147931 		    (1<< RTW_TX_DMA_POLLING_HIPRIORITY_SHIFT) | check);
6354689Sql147931 		break;
6364689Sql147931 	}
6374689Sql147931 	(void) RTW_READ8(regs, RTW_TPPOLL);
6384689Sql147931 }
6394689Sql147931 
6404689Sql147931 void
rtw_beacon_tx_disable(struct rtw_regs * regs)6414689Sql147931 rtw_beacon_tx_disable(struct rtw_regs *regs)
6424689Sql147931 {
6434689Sql147931 	uint8_t mask = 0;
6444689Sql147931 	mask |= (1 << RTW_TX_DMA_STOP_BEACON_SHIFT);
6454689Sql147931 	rtw_set_mode(regs, RTW_EPROM_CMD_CONFIG);
6464689Sql147931 	RTW_WRITE8(regs, RTW_TPPOLL, mask);
6474689Sql147931 	rtw_set_mode(regs, RTW_EPROM_CMD_NORMAL);
6484689Sql147931 }
6494689Sql147931 
6504689Sql147931 static void
6514689Sql147931 rtw_io_enable(rtw_softc_t *rsc, uint8_t flags, int enable);
6524689Sql147931 
6534689Sql147931 void
rtw_rtx_disable(rtw_softc_t * rsc)6544689Sql147931 rtw_rtx_disable(rtw_softc_t *rsc)
6554689Sql147931 {
6564689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
6574689Sql147931 
6584689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE|RTW_CR_TE, 0);
6594689Sql147931 	(void) RTW_READ8(regs, RTW_CR);
6604689Sql147931 }
6614689Sql147931 
6624689Sql147931 static void
rtw_srom_free(struct rtw_srom * sr)6634689Sql147931 rtw_srom_free(struct rtw_srom *sr)
6644689Sql147931 {
6654689Sql147931 	if (sr->sr_content == NULL)
6664689Sql147931 		return;
6674689Sql147931 	kmem_free(sr->sr_content, sr->sr_size);
6684689Sql147931 	sr->sr_size = 0;
6694689Sql147931 	sr->sr_content = NULL;
6704689Sql147931 }
6714689Sql147931 
6724689Sql147931 /*ARGSUSED*/
6734689Sql147931 static void
rtw_srom_defaults(struct rtw_srom * sr,uint32_t * flags,uint8_t * cs_threshold,enum rtw_rfchipid * rfchipid,uint32_t * rcr)6744689Sql147931 rtw_srom_defaults(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold,
6754689Sql147931     enum rtw_rfchipid *rfchipid, uint32_t *rcr)
6764689Sql147931 {
6774689Sql147931 	*flags |= (RTW_F_DIGPHY|RTW_F_ANTDIV);
6784689Sql147931 	*cs_threshold = RTW_SR_ENERGYDETTHR_DEFAULT;
6794689Sql147931 	*rcr |= RTW_RCR_ENCS1;
6804689Sql147931 	*rfchipid = RTW_RFCHIPID_PHILIPS;
6814689Sql147931 }
6824689Sql147931 
6834689Sql147931 static int
rtw_srom_parse(struct rtw_srom * sr,uint32_t * flags,uint8_t * cs_threshold,enum rtw_rfchipid * rfchipid,uint32_t * rcr,enum rtw_locale * locale,const char * dvname)6844689Sql147931 rtw_srom_parse(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold,
6854689Sql147931     enum rtw_rfchipid *rfchipid, uint32_t *rcr, enum rtw_locale *locale,
6864689Sql147931     const char *dvname)
6874689Sql147931 {
6884689Sql147931 	int i;
6894689Sql147931 	const char *rfname, *paname;
6904689Sql147931 	char scratch[sizeof ("unknown 0xXX")];
6914689Sql147931 	uint16_t version;
6924689Sql147931 	uint8_t mac[IEEE80211_ADDR_LEN];
6934689Sql147931 
6944689Sql147931 	*flags &= ~(RTW_F_DIGPHY|RTW_F_DFLANTB|RTW_F_ANTDIV);
6954689Sql147931 	*rcr &= ~(RTW_RCR_ENCS1 | RTW_RCR_ENCS2);
6964689Sql147931 
6974689Sql147931 	version = RTW_SR_GET16(sr, RTW_SR_VERSION);
6984689Sql147931 	RTW_DPRINTF(RTW_DEBUG_IOSTATE, "%s: SROM version %d.%d", dvname,
6994689Sql147931 	    version >> 8, version & 0xff);
7004689Sql147931 
7014689Sql147931 	if (version <= 0x0101) {
7024689Sql147931 		cmn_err(CE_NOTE, " is not understood, limping along "
7034689Sql147931 		    "with defaults\n");
7044689Sql147931 		rtw_srom_defaults(sr, flags, cs_threshold, rfchipid, rcr);
7054689Sql147931 		return (0);
7064689Sql147931 	}
7074689Sql147931 
7084689Sql147931 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
7094689Sql147931 		mac[i] = RTW_SR_GET(sr, RTW_SR_MAC + i);
7104689Sql147931 
7114689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH,
7124689Sql147931 	    "%s: EEPROM MAC %s\n", dvname, mac);
7134689Sql147931 
7144689Sql147931 	*cs_threshold = RTW_SR_GET(sr, RTW_SR_ENERGYDETTHR);
7154689Sql147931 
7164689Sql147931 	if ((RTW_SR_GET(sr, RTW_SR_CONFIG2) & RTW_CONFIG2_ANT) != 0)
7174689Sql147931 		*flags |= RTW_F_ANTDIV;
7184689Sql147931 
7194689Sql147931 	/*
7204689Sql147931 	 * Note well: the sense of the RTW_SR_RFPARM_DIGPHY bit seems
7214689Sql147931 	 * to be reversed.
7224689Sql147931 	 */
7234689Sql147931 	if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DIGPHY) == 0)
7244689Sql147931 		*flags |= RTW_F_DIGPHY;
7254689Sql147931 	if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DFLANTB) != 0)
7264689Sql147931 		*flags |= RTW_F_DFLANTB;
7274689Sql147931 
7284689Sql147931 	*rcr |= LSHIFT(MASK_AND_RSHIFT(RTW_SR_GET(sr, RTW_SR_RFPARM),
7294689Sql147931 	    RTW_SR_RFPARM_CS_MASK), RTW_RCR_ENCS1);
7304689Sql147931 
7314689Sql147931 	*rfchipid = RTW_SR_GET(sr, RTW_SR_RFCHIPID);
7324689Sql147931 	switch (*rfchipid) {
7334689Sql147931 	case RTW_RFCHIPID_GCT:		/* this combo seen in the wild */
7344689Sql147931 		rfname = "GCT GRF5101";
7354689Sql147931 		paname = "Winspring WS9901";
7364689Sql147931 		break;
7374689Sql147931 	case RTW_RFCHIPID_MAXIM:
7384689Sql147931 		rfname = "Maxim MAX2820";	/* guess */
7394689Sql147931 		paname = "Maxim MAX2422";	/* guess */
7404689Sql147931 		break;
7414689Sql147931 	case RTW_RFCHIPID_INTERSIL:
7424689Sql147931 		rfname = "Intersil HFA3873";	/* guess */
7434689Sql147931 		paname = "Intersil <unknown>";
7444689Sql147931 		break;
7454689Sql147931 	case RTW_RFCHIPID_PHILIPS:	/* this combo seen in the wild */
7464689Sql147931 		rfname = "Philips SA2400A";
7474689Sql147931 		paname = "Philips SA2411";
7484689Sql147931 		break;
7494689Sql147931 	case RTW_RFCHIPID_RFMD:
7504689Sql147931 		/*
7514689Sql147931 		 * this is the same front-end as an atw(4)!
7524689Sql147931 		 */
7534689Sql147931 		rfname = "RFMD RF2948B, "	/* mentioned in Realtek docs */
7544689Sql147931 		    "LNA: RFMD RF2494, "	/* mentioned in Realtek docs */
7554689Sql147931 		    "SYN: Silicon Labs Si4126";
7564689Sql147931 		paname = "RFMD RF2189";		/* mentioned in Realtek docs */
7574689Sql147931 		break;
7584689Sql147931 	case RTW_RFCHIPID_RESERVED:
7594689Sql147931 		rfname = paname = "reserved";
7604689Sql147931 		break;
7614689Sql147931 	default:
7624689Sql147931 		(void) snprintf(scratch, sizeof (scratch),
7634689Sql147931 		    "unknown 0x%02x", *rfchipid);
7644689Sql147931 		rfname = paname = scratch;
7654689Sql147931 	}
7664689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHY, "%s: RF: %s, PA: %s\n",
7674689Sql147931 	    dvname, rfname, paname);
7684689Sql147931 
7694689Sql147931 	switch (RTW_SR_GET(sr, RTW_SR_CONFIG0) & RTW_CONFIG0_GL_MASK) {
7704689Sql147931 	case RTW_CONFIG0_GL_USA:
7714689Sql147931 		*locale = RTW_LOCALE_USA;
7724689Sql147931 		break;
7734689Sql147931 	case RTW_CONFIG0_GL_EUROPE:
7744689Sql147931 		*locale = RTW_LOCALE_EUROPE;
7754689Sql147931 		break;
7764689Sql147931 	case RTW_CONFIG0_GL_JAPAN:
7774689Sql147931 		*locale = RTW_LOCALE_JAPAN;
7784689Sql147931 		break;
7794689Sql147931 	default:
7804689Sql147931 		*locale = RTW_LOCALE_UNKNOWN;
7814689Sql147931 		break;
7824689Sql147931 	}
7834689Sql147931 	return (0);
7844689Sql147931 }
7854689Sql147931 
7864689Sql147931 /*
7874689Sql147931  * Returns -1 on failure.
7884689Sql147931  */
7894689Sql147931 static int
rtw_srom_read(struct rtw_regs * regs,uint32_t flags,struct rtw_srom * sr,const char * dvname)7904689Sql147931 rtw_srom_read(struct rtw_regs *regs, uint32_t flags, struct rtw_srom *sr,
7914689Sql147931     const char *dvname)
7924689Sql147931 {
7934689Sql147931 	int rc;
7944689Sql147931 	struct seeprom_descriptor sd;
7954689Sql147931 	uint8_t ecr;
7964689Sql147931 
7974689Sql147931 	(void) memset(&sd, 0, sizeof (sd));
7984689Sql147931 
7994689Sql147931 	ecr = RTW_READ8(regs, RTW_9346CR);
8004689Sql147931 
8014689Sql147931 	if ((flags & RTW_F_9356SROM) != 0) {
8024689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: 93c56 SROM\n", dvname);
8034689Sql147931 		sr->sr_size = 256;
8044689Sql147931 		sd.sd_chip = C56_66;
8054689Sql147931 	} else {
8064689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: 93c46 SROM\n", dvname);
8074689Sql147931 		sr->sr_size = 128;
8084689Sql147931 		sd.sd_chip = C46;
8094689Sql147931 	}
8104689Sql147931 
8114689Sql147931 	ecr &= ~(RTW_9346CR_EEDI | RTW_9346CR_EEDO | RTW_9346CR_EESK |
8124689Sql147931 	    RTW_9346CR_EEM_MASK | RTW_9346CR_EECS);
8134689Sql147931 	ecr |= RTW_9346CR_EEM_PROGRAM;
8144689Sql147931 
8154689Sql147931 	RTW_WRITE8(regs, RTW_9346CR, ecr);
8164689Sql147931 
8174689Sql147931 	sr->sr_content = kmem_zalloc(sr->sr_size, KM_SLEEP);
8184689Sql147931 
8194689Sql147931 	if (sr->sr_content == NULL) {
8204689Sql147931 		cmn_err(CE_WARN, "%s: unable to allocate SROM buffer\n",
8214689Sql147931 		    dvname);
8224689Sql147931 		return (ENOMEM);
8234689Sql147931 	}
8244689Sql147931 
8254689Sql147931 	(void) memset(sr->sr_content, 0, sr->sr_size);
8264689Sql147931 
8274689Sql147931 	/*
8284689Sql147931 	 * RTL8180 has a single 8-bit register for controlling the
8294689Sql147931 	 * 93cx6 SROM.  There is no "ready" bit. The RTL8180
8304689Sql147931 	 * input/output sense is the reverse of read_seeprom's.
8314689Sql147931 	 */
8324689Sql147931 	sd.sd_handle = regs->r_handle;
8334689Sql147931 	sd.sd_base = regs->r_base;
8344689Sql147931 	sd.sd_regsize = 1;
8354689Sql147931 	sd.sd_control_offset = RTW_9346CR;
8364689Sql147931 	sd.sd_status_offset = RTW_9346CR;
8374689Sql147931 	sd.sd_dataout_offset = RTW_9346CR;
8384689Sql147931 	sd.sd_CK = RTW_9346CR_EESK;
8394689Sql147931 	sd.sd_CS = RTW_9346CR_EECS;
8404689Sql147931 	sd.sd_DI = RTW_9346CR_EEDO;
8414689Sql147931 	sd.sd_DO = RTW_9346CR_EEDI;
8424689Sql147931 	/*
8434689Sql147931 	 * make read_seeprom enter EEPROM read/write mode
8444689Sql147931 	 */
8454689Sql147931 	sd.sd_MS = ecr;
8464689Sql147931 	sd.sd_RDY = 0;
8474689Sql147931 
8484689Sql147931 	/*
8494689Sql147931 	 * TBD bus barriers
8504689Sql147931 	 */
8514689Sql147931 	if (!read_seeprom(&sd, sr->sr_content, 0, sr->sr_size/2)) {
8524689Sql147931 		cmn_err(CE_WARN, "%s: could not read SROM\n", dvname);
8534689Sql147931 		kmem_free(sr->sr_content, sr->sr_size);
8544689Sql147931 		sr->sr_content = NULL;
8554689Sql147931 		return (-1);	/* XXX */
8564689Sql147931 	}
8574689Sql147931 
8584689Sql147931 	/*
8594689Sql147931 	 * end EEPROM read/write mode
8604689Sql147931 	 */
8614689Sql147931 	RTW_WRITE8(regs, RTW_9346CR,
8624689Sql147931 	    (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_NORMAL);
8634689Sql147931 	RTW_WBRW(regs, RTW_9346CR, RTW_9346CR);
8644689Sql147931 
8654689Sql147931 	if ((rc = rtw_recall_eeprom(regs, dvname)) != 0)
8664689Sql147931 		return (rc);
8674689Sql147931 
8684689Sql147931 #ifdef SROM_DEBUG
8694689Sql147931 	{
8704689Sql147931 		int i;
8714689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH,
8724689Sql147931 		    "\n%s: serial ROM:\n\t", dvname);
8734689Sql147931 		for (i = 0; i < sr->sr_size/2; i++) {
8744689Sql147931 			RTW_DPRINTF(RTW_DEBUG_ATTACH,
8754689Sql147931 			    "offset-0x%x: %04x", 2*i, sr->sr_content[i]);
8764689Sql147931 		}
8774689Sql147931 	}
8784689Sql147931 #endif /* DEBUG */
8794689Sql147931 	return (0);
8804689Sql147931 }
8814689Sql147931 
8824689Sql147931 static void
rtw_set_rfprog(struct rtw_regs * regs,enum rtw_rfchipid rfchipid,const char * dvname)8834689Sql147931 rtw_set_rfprog(struct rtw_regs *regs, enum rtw_rfchipid rfchipid,
8844689Sql147931     const char *dvname)
8854689Sql147931 {
8864689Sql147931 	uint8_t cfg4;
8874689Sql147931 	const char *method;
8884689Sql147931 
8894689Sql147931 	cfg4 = RTW_READ8(regs, RTW_CONFIG4) & ~RTW_CONFIG4_RFTYPE_MASK;
8904689Sql147931 
8914689Sql147931 	switch (rfchipid) {
8924689Sql147931 	default:
8934689Sql147931 		cfg4 |= LSHIFT(0, RTW_CONFIG4_RFTYPE_MASK);
8944689Sql147931 		method = "fallback";
8954689Sql147931 		break;
8964689Sql147931 	case RTW_RFCHIPID_INTERSIL:
8974689Sql147931 		cfg4 |= RTW_CONFIG4_RFTYPE_INTERSIL;
8984689Sql147931 		method = "Intersil";
8994689Sql147931 		break;
9004689Sql147931 	case RTW_RFCHIPID_PHILIPS:
9014689Sql147931 		cfg4 |= RTW_CONFIG4_RFTYPE_PHILIPS;
9024689Sql147931 		method = "Philips";
9034689Sql147931 		break;
9044689Sql147931 	case RTW_RFCHIPID_GCT:	/* XXX a guess */
9054689Sql147931 	case RTW_RFCHIPID_RFMD:
9064689Sql147931 		cfg4 |= RTW_CONFIG4_RFTYPE_RFMD;
9074689Sql147931 		method = "RFMD";
9084689Sql147931 		break;
9094689Sql147931 	}
9104689Sql147931 
9114689Sql147931 	RTW_WRITE8(regs, RTW_CONFIG4, cfg4);
9124689Sql147931 
9134689Sql147931 	RTW_WBR(regs, RTW_CONFIG4, RTW_CONFIG4);
9144689Sql147931 
9154689Sql147931 	RTW_DPRINTF(RTW_DEBUG_INIT,
9164689Sql147931 	    "%s: %s RF programming method, %02x\n", dvname, method,
9174689Sql147931 	    RTW_READ8(regs, RTW_CONFIG4));
9184689Sql147931 }
9194689Sql147931 
9204689Sql147931 static void
rtw_init_channels(enum rtw_locale locale,struct ieee80211_channel (* chans)[IEEE80211_CHAN_MAX+1],const char * dvname)9214689Sql147931 rtw_init_channels(enum rtw_locale locale,
9224689Sql147931     struct ieee80211_channel (*chans)[IEEE80211_CHAN_MAX+1],
9234689Sql147931     const char *dvname)
9244689Sql147931 {
9254689Sql147931 	int i;
9264689Sql147931 	const char *name = NULL;
9274689Sql147931 #define	ADD_CHANNEL(_chans, _chan) {			\
9284689Sql147931 	(*_chans)[_chan].ich_flags = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK;\
9294689Sql147931 	(*_chans)[_chan].ich_freq =				\
9304689Sql147931 	    ieee80211_ieee2mhz(_chan, (*_chans)[_chan].ich_flags);\
9314689Sql147931 }
9324689Sql147931 
9334689Sql147931 	switch (locale) {
9344689Sql147931 	case RTW_LOCALE_USA:	/* 1-11 */
9354689Sql147931 		name = "USA";
9364689Sql147931 		for (i = 1; i <= 11; i++)
9374689Sql147931 			ADD_CHANNEL(chans, i);
9384689Sql147931 		break;
9394689Sql147931 	case RTW_LOCALE_JAPAN:	/* 1-14 */
9404689Sql147931 		name = "Japan";
9414689Sql147931 		ADD_CHANNEL(chans, 14);
9424689Sql147931 		for (i = 1; i <= 14; i++)
9434689Sql147931 			ADD_CHANNEL(chans, i);
9444689Sql147931 		break;
9454689Sql147931 	case RTW_LOCALE_EUROPE:	/* 1-13 */
9464689Sql147931 		name = "Europe";
9474689Sql147931 		for (i = 1; i <= 13; i++)
9484689Sql147931 			ADD_CHANNEL(chans, i);
9494689Sql147931 		break;
9504689Sql147931 	default:			/* 10-11 allowed by most countries */
9514689Sql147931 		name = "<unknown>";
9524689Sql147931 		for (i = 10; i <= 11; i++)
9534689Sql147931 			ADD_CHANNEL(chans, i);
9544689Sql147931 		break;
9554689Sql147931 	}
9564689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: Geographic Location %s\n",
9574689Sql147931 	    dvname, name);
9584689Sql147931 #undef ADD_CHANNEL
9594689Sql147931 }
9604689Sql147931 
9614689Sql147931 static void
rtw_set80211props(struct ieee80211com * ic)9624689Sql147931 rtw_set80211props(struct ieee80211com *ic)
9634689Sql147931 {
9644689Sql147931 	ic->ic_phytype = IEEE80211_T_DS;
9654689Sql147931 	ic->ic_opmode = IEEE80211_M_STA;
9664689Sql147931 	ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_IBSS |
9678237SMikore.Li@Sun.COM 	    IEEE80211_C_SHPREAMBLE;
9688237SMikore.Li@Sun.COM 	/* IEEE80211_C_HOSTAP | IEEE80211_C_MONITOR | IEEE80211_C_WEP */
9698237SMikore.Li@Sun.COM 
9708237SMikore.Li@Sun.COM 	ic->ic_sup_rates[IEEE80211_MODE_11B] = rtw_rateset_11b;
9714689Sql147931 }
9724689Sql147931 
9734689Sql147931 /*ARGSUSED*/
9744689Sql147931 static void
rtw_identify_country(struct rtw_regs * regs,enum rtw_locale * locale,const char * dvname)9754689Sql147931 rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale,
9764689Sql147931     const char *dvname)
9774689Sql147931 {
9784689Sql147931 	uint8_t cfg0 = RTW_READ8(regs, RTW_CONFIG0);
9794689Sql147931 
9804689Sql147931 	switch (cfg0 & RTW_CONFIG0_GL_MASK) {
9814689Sql147931 	case RTW_CONFIG0_GL_USA:
9824689Sql147931 		*locale = RTW_LOCALE_USA;
9834689Sql147931 		break;
9844689Sql147931 	case RTW_CONFIG0_GL_JAPAN:
9854689Sql147931 		*locale = RTW_LOCALE_JAPAN;
9864689Sql147931 		break;
9874689Sql147931 	case RTW_CONFIG0_GL_EUROPE:
9884689Sql147931 		*locale = RTW_LOCALE_EUROPE;
9894689Sql147931 		break;
9904689Sql147931 	default:
9914689Sql147931 		*locale = RTW_LOCALE_UNKNOWN;
9924689Sql147931 		break;
9934689Sql147931 	}
9944689Sql147931 }
9954689Sql147931 
9964689Sql147931 static int
rtw_identify_sta(struct rtw_regs * regs,uint8_t * addr,const char * dvname)9974689Sql147931 rtw_identify_sta(struct rtw_regs *regs, uint8_t *addr,
9984689Sql147931     const char *dvname)
9994689Sql147931 {
10004689Sql147931 	uint32_t idr0 = RTW_READ(regs, RTW_IDR0),
10014689Sql147931 	    idr1 = RTW_READ(regs, RTW_IDR1);
10024689Sql147931 
10034689Sql147931 	*addr = MASK_AND_RSHIFT(idr0, BITS(0,  7));
10044689Sql147931 	*(addr + 1) = MASK_AND_RSHIFT(idr0, BITS(8,  15));
10054689Sql147931 	*(addr + 2) = MASK_AND_RSHIFT(idr0, BITS(16, 23));
10064689Sql147931 	*(addr + 3) = MASK_AND_RSHIFT(idr0, BITS(24, 31));
10074689Sql147931 
10084689Sql147931 	*(addr + 4) = MASK_AND_RSHIFT(idr1, BITS(0,  7));
10094689Sql147931 	*(addr + 5) = MASK_AND_RSHIFT(idr1, BITS(8, 15));
10104689Sql147931 
10114689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH,
10124689Sql147931 	    "%s: 802.11mac address %x:%x:%x:%x:%x:%x\n", dvname,
10134689Sql147931 	    *addr, *(addr+1), *(addr+2), *(addr+3), *(addr+4), *(addr+5));
10144689Sql147931 
10154689Sql147931 	return (0);
10164689Sql147931 }
10174689Sql147931 
10184689Sql147931 static uint8_t
rtw_chan2txpower(struct rtw_srom * sr,struct ieee80211com * ic,struct ieee80211_channel * chan)10194689Sql147931 rtw_chan2txpower(struct rtw_srom *sr, struct ieee80211com *ic,
10204689Sql147931     struct ieee80211_channel *chan)
10214689Sql147931 {
10224689Sql147931 	uint32_t idx = RTW_SR_TXPOWER1 + ieee80211_chan2ieee(ic, chan) - 1;
10234689Sql147931 	return (RTW_SR_GET(sr, idx));
10244689Sql147931 }
10254689Sql147931 
10264689Sql147931 static void
rtw_rxdesc_init(rtw_softc_t * rsc,struct rtw_rxbuf * rbf,int idx,int is_last)10274689Sql147931 rtw_rxdesc_init(rtw_softc_t *rsc, struct rtw_rxbuf *rbf, int idx, int is_last)
10284689Sql147931 {
10294689Sql147931 	uint32_t ctl = 0;
10304689Sql147931 	uint8_t *buf = (uint8_t *)rbf->bf_dma.mem_va;
10314689Sql147931 
10324689Sql147931 	ASSERT(rbf != NULL);
10334689Sql147931 	rbf->rxdesc->rd_buf = (rbf->bf_dma.cookie.dmac_address);
10344689Sql147931 	bzero(buf, rbf->bf_dma.alength);
10354689Sql147931 	RTW_DMA_SYNC(rbf->bf_dma, DDI_DMA_SYNC_FORDEV);
10364689Sql147931 
10374689Sql147931 	ctl = (rbf->bf_dma.alength & 0xfff) | RTW_RXCTL_OWN;
10384689Sql147931 
10394689Sql147931 	if (is_last)
10404689Sql147931 		ctl |= RTW_RXCTL_EOR;
10414689Sql147931 
10424689Sql147931 	rbf->rxdesc->rd_ctl = (ctl);
10434689Sql147931 	/* sync the mbuf */
10444689Sql147931 
10454689Sql147931 	/* sync the descriptor */
10464689Sql147931 	RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
10474689Sql147931 	    RTW_DESC_OFFSET(hd_rx, idx),
10484689Sql147931 	    sizeof (struct rtw_rxdesc),
10494689Sql147931 	    DDI_DMA_SYNC_FORDEV);
10504689Sql147931 }
10514689Sql147931 
10524689Sql147931 static void
rtw_idle(struct rtw_regs * regs)10534689Sql147931 rtw_idle(struct rtw_regs *regs)
10544689Sql147931 {
10554689Sql147931 	int active;
10564689Sql147931 
10574689Sql147931 	/* request stop DMA; wait for packets to stop transmitting. */
10584689Sql147931 
10594689Sql147931 	RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
10604689Sql147931 
10614689Sql147931 	for (active = 0; active < 300 &&
10628237SMikore.Li@Sun.COM 	    (RTW_READ8(regs, RTW_TPPOLL) & RTW_TPPOLL_ALL) != 0; active++)
10634689Sql147931 		drv_usecwait(10);
10644689Sql147931 }
10654689Sql147931 
10664689Sql147931 static void
rtw_io_enable(rtw_softc_t * rsc,uint8_t flags,int enable)10674689Sql147931 rtw_io_enable(rtw_softc_t *rsc, uint8_t flags, int enable)
10684689Sql147931 {
10694689Sql147931 	uint8_t cr;
10704689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
10714689Sql147931 
10724689Sql147931 	RTW_DPRINTF(RTW_DEBUG_IOSTATE, "%s: %s 0x%02x\n", __func__,
10734689Sql147931 	    enable ? "enable" : "disable", flags);
10744689Sql147931 
10754689Sql147931 	cr = RTW_READ8(regs, RTW_CR);
10768237SMikore.Li@Sun.COM 
10774689Sql147931 	/* The receive engine will always start at RDSAR.  */
10784689Sql147931 	if (enable && (flags & ~cr & RTW_CR_RE)) {
10794689Sql147931 		RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
10804689Sql147931 		    RTW_DESC_OFFSET(hd_rx, 0),
10814689Sql147931 		    sizeof (struct rtw_rxdesc),
10824689Sql147931 		    DDI_DMA_SYNC_FORCPU);
10834689Sql147931 		rsc->rx_next = 0;
10844689Sql147931 		rtw_rxdesc_init(rsc, rsc->rxbuf_h, 0, 0);
10854689Sql147931 	}
10868237SMikore.Li@Sun.COM 
10874689Sql147931 	if (enable)
10884689Sql147931 		cr |= flags;
10894689Sql147931 	else
10904689Sql147931 		cr &= ~flags;
10914689Sql147931 	RTW_WRITE8(regs, RTW_CR, cr);
10924689Sql147931 	(void) RTW_READ8(regs, RTW_CR);
10934689Sql147931 }
10944689Sql147931 
10954689Sql147931 /*
10964689Sql147931  * Allocate an area of memory and a DMA handle for accessing it
10974689Sql147931  */
10984689Sql147931 static int
rtw_alloc_dma_mem(dev_info_t * devinfo,ddi_dma_attr_t * dma_attr,size_t memsize,ddi_device_acc_attr_t * attr_p,uint_t alloc_flags,uint_t bind_flags,dma_area_t * dma_p)10994689Sql147931 rtw_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr,
11004689Sql147931 	size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
11014689Sql147931 	uint_t bind_flags, dma_area_t *dma_p)
11024689Sql147931 {
11034689Sql147931 	int err;
11044689Sql147931 
11054689Sql147931 	/*
11064689Sql147931 	 * Allocate handle
11074689Sql147931 	 */
11084689Sql147931 	err = ddi_dma_alloc_handle(devinfo, dma_attr,
11094689Sql147931 	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
11104689Sql147931 	if (err != DDI_SUCCESS)
11114689Sql147931 		return (DDI_FAILURE);
11124689Sql147931 
11134689Sql147931 	/*
11144689Sql147931 	 * Allocate memory
11154689Sql147931 	 */
11164689Sql147931 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
11174689Sql147931 	    alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va,
11184689Sql147931 	    &dma_p->alength, &dma_p->acc_hdl);
11194689Sql147931 	if (err != DDI_SUCCESS)
11204689Sql147931 		return (DDI_FAILURE);
11214689Sql147931 
11224689Sql147931 	/*
11234689Sql147931 	 * Bind the two together
11244689Sql147931 	 */
11254689Sql147931 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
11264689Sql147931 	    dma_p->mem_va, dma_p->alength, bind_flags,
11274689Sql147931 	    DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies);
11284689Sql147931 	if ((dma_p->ncookies != 1) || (err != DDI_DMA_MAPPED))
11294689Sql147931 		return (DDI_FAILURE);
11304689Sql147931 
11314689Sql147931 	dma_p->nslots = ~0U;
11324689Sql147931 	dma_p->size = ~0U;
11334689Sql147931 	dma_p->token = ~0U;
11344689Sql147931 	dma_p->offset = 0;
11354689Sql147931 	return (DDI_SUCCESS);
11364689Sql147931 }
11374689Sql147931 
11384689Sql147931 /*
11394689Sql147931  * Free one allocated area of DMAable memory
11404689Sql147931  */
11414689Sql147931 static void
rtw_free_dma_mem(dma_area_t * dma_p)11424689Sql147931 rtw_free_dma_mem(dma_area_t *dma_p)
11434689Sql147931 {
11444689Sql147931 	if (dma_p->dma_hdl != NULL) {
11454689Sql147931 		(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
11464689Sql147931 		if (dma_p->acc_hdl != NULL) {
11474689Sql147931 			ddi_dma_mem_free(&dma_p->acc_hdl);
11484689Sql147931 			dma_p->acc_hdl = NULL;
11494689Sql147931 		}
11504689Sql147931 		ddi_dma_free_handle(&dma_p->dma_hdl);
11514689Sql147931 		dma_p->ncookies = 0;
11524689Sql147931 		dma_p->dma_hdl = NULL;
11534689Sql147931 	}
11544689Sql147931 }
11554689Sql147931 
11564689Sql147931 static void
rtw_dma_free(rtw_softc_t * rsc)11574689Sql147931 rtw_dma_free(rtw_softc_t *rsc)
11584689Sql147931 {
11594689Sql147931 	struct rtw_txbuf *txbf;
11604689Sql147931 	struct rtw_rxbuf *rxbf;
11614689Sql147931 	int i, j;
11624689Sql147931 
11634689Sql147931 	/* Free TX DMA buffer */
11644689Sql147931 	for (i = 0; i < RTW_NTXPRI; i++) {
11654689Sql147931 		txbf = list_head(&rsc->sc_txq[i].tx_free_list);
11664689Sql147931 		while (txbf != NULL) {
11674689Sql147931 			rtw_free_dma_mem(&txbf->bf_dma);
11684689Sql147931 			list_remove(&rsc->sc_txq[i].tx_free_list, txbf);
11694689Sql147931 			txbf = list_head(&rsc->sc_txq[i].tx_free_list);
11704689Sql147931 		}
11714689Sql147931 		list_destroy(&rsc->sc_txq[i].tx_free_list);
11724689Sql147931 		txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
11734689Sql147931 		while (txbf != NULL) {
11744689Sql147931 			rtw_free_dma_mem(&txbf->bf_dma);
11754689Sql147931 			list_remove(&rsc->sc_txq[i].tx_dirty_list, txbf);
11764689Sql147931 			txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
11774689Sql147931 		}
11784689Sql147931 		list_destroy(&rsc->sc_txq[i].tx_dirty_list);
11794689Sql147931 
11804689Sql147931 		if (rsc->sc_txq[i].txbuf_h != NULL) {
11814689Sql147931 			kmem_free(rsc->sc_txq[i].txbuf_h,
11824689Sql147931 			    sizeof (struct rtw_txbuf) * rtw_qlen[i]);
11834689Sql147931 			rsc->sc_txq[i].txbuf_h = NULL;
11844689Sql147931 		}
11854689Sql147931 	}
11864689Sql147931 
11874689Sql147931 	/* Free RX DMA buffer */
11884689Sql147931 	rxbf = rsc->rxbuf_h;
11894689Sql147931 	for (j = 0; j < RTW_RXQLEN; j++) {
11904689Sql147931 		rtw_free_dma_mem(&rxbf->bf_dma);
11914689Sql147931 		rxbf++;
11924689Sql147931 	}
11934689Sql147931 
11944689Sql147931 	if (rsc->rxbuf_h != NULL) {
11956890Sql147931 		kmem_free(rsc->rxbuf_h,
11966890Sql147931 		    sizeof (struct rtw_rxbuf) * RTW_RXQLEN);
11974689Sql147931 		rsc->rxbuf_h = NULL;
11984689Sql147931 	}
11994689Sql147931 
12004689Sql147931 	rtw_free_dma_mem(&rsc->sc_desc_dma);
12014689Sql147931 }
12024689Sql147931 
12034689Sql147931 static int
rtw_dma_init(dev_info_t * devinfo,rtw_softc_t * rsc)12044689Sql147931 rtw_dma_init(dev_info_t *devinfo, rtw_softc_t *rsc)
12054689Sql147931 {
12064689Sql147931 	int i, j, err;
12074689Sql147931 	size_t size;
12084689Sql147931 	uint32_t buflen;
12094689Sql147931 	struct rtw_txdesc *txds;
12104689Sql147931 	struct rtw_rxdesc *rxds;
12114689Sql147931 	struct rtw_txbuf *txbf;
12124689Sql147931 	struct rtw_rxbuf *rxbf;
12134689Sql147931 	uint32_t phybaseaddr, ptx[RTW_NTXPRI], prx;
12144689Sql147931 	caddr_t virbaseaddr, vtx[RTW_NTXPRI], vrx;
12154689Sql147931 
12164689Sql147931 	/* DMA buffer size for each TX/RX packet */
12174689Sql147931 	rsc->sc_dmabuf_size = roundup(sizeof (struct ieee80211_frame) + 0x100 +
12184689Sql147931 	    IEEE80211_MTU + IEEE80211_CRC_LEN + sizeof (struct ieee80211_llc) +
12194689Sql147931 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
12204689Sql147931 	    IEEE80211_WEP_CRCLEN), rsc->sc_cachelsz);
12214689Sql147931 	size = sizeof (struct rtw_descs);
12224689Sql147931 	err = rtw_alloc_dma_mem(devinfo, &dma_attr_desc, size,
12234689Sql147931 	    &rtw_desc_accattr,
12244689Sql147931 	    DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
12254689Sql147931 	    &rsc->sc_desc_dma);
12264689Sql147931 	if (err != DDI_SUCCESS)
12274689Sql147931 		goto error;
12284689Sql147931 	phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address;
12294689Sql147931 	virbaseaddr = rsc->sc_desc_dma.mem_va;
12304689Sql147931 	ptx[0] = RTW_RING_BASE(phybaseaddr, hd_txlo);
12314689Sql147931 	ptx[1] = RTW_RING_BASE(phybaseaddr, hd_txmd);
12324689Sql147931 	ptx[2] = RTW_RING_BASE(phybaseaddr, hd_txhi);
12334689Sql147931 	ptx[3] = RTW_RING_BASE(phybaseaddr, hd_bcn);
12344689Sql147931 	vtx[0] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txlo));
12354689Sql147931 	vtx[1] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txmd));
12364689Sql147931 	vtx[2] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txhi));
12374689Sql147931 	vtx[3] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_bcn));
12384689Sql147931 	for (i = 0; i < RTW_NTXPRI; i++) {
12394689Sql147931 		RTW_DPRINTF(RTW_DEBUG_DMA, "p[%d]=%x, v[%d]=%x", i, ptx[i],
12404689Sql147931 		    i, vtx[i]);
12414689Sql147931 		RTW_DPRINTF(RTW_DEBUG_DMA, "ring%d:", i);
12424689Sql147931 		list_create(&rsc->sc_txq[i].tx_free_list,
12434689Sql147931 		    sizeof (struct rtw_txbuf),
12444689Sql147931 		    offsetof(struct rtw_txbuf, bf_node));
12454689Sql147931 		list_create(&rsc->sc_txq[i].tx_dirty_list,
12464689Sql147931 		    sizeof (struct rtw_txbuf),
12474689Sql147931 		    offsetof(struct rtw_txbuf, bf_node));
12484689Sql147931 		/* virtual address of the first descriptor */
12496890Sql147931 		rsc->sc_txq[i].txdesc_h =
12506890Sql147931 		    (struct rtw_txdesc *)(uintptr_t)vtx[i];
12514689Sql147931 
12524689Sql147931 		txds = rsc->sc_txq[i].txdesc_h;
12534689Sql147931 		/* allocate data structures to describe TX DMA buffers */
12544689Sql147931 		buflen = sizeof (struct rtw_txbuf) * rtw_qlen[i];
12554689Sql147931 		txbf = (struct rtw_txbuf *)kmem_zalloc(buflen, KM_SLEEP);
12564689Sql147931 		rsc->sc_txq[i].txbuf_h = txbf;
12574689Sql147931 		for (j = 0; j < rtw_qlen[i]; j++, txbf++, txds++) {
12584689Sql147931 			txbf->txdesc = txds;
12596890Sql147931 			txbf->bf_daddr = ptx[i] + ((uintptr_t)txds -
12606890Sql147931 			    (uintptr_t)rsc->sc_txq[i].txdesc_h);
12614689Sql147931 			list_insert_tail(&rsc->sc_txq[i].tx_free_list, txbf);
12624689Sql147931 
12634689Sql147931 			/* alloc DMA memory */
12644689Sql147931 			err = rtw_alloc_dma_mem(devinfo, &dma_attr_txbuf,
12654689Sql147931 			    rsc->sc_dmabuf_size,
12664689Sql147931 			    &rtw_buf_accattr,
12674689Sql147931 			    DDI_DMA_STREAMING,
12684689Sql147931 			    DDI_DMA_WRITE | DDI_DMA_STREAMING,
12694689Sql147931 			    &txbf->bf_dma);
12704689Sql147931 			if (err != DDI_SUCCESS)
12714689Sql147931 				goto error;
12724689Sql147931 			RTW_DPRINTF(RTW_DEBUG_DMA, "pbufaddr[%d]=%x",
12734689Sql147931 			    j, txbf->bf_dma.cookie.dmac_address);
12744689Sql147931 		}
12754689Sql147931 	}
12764689Sql147931 	prx = RTW_RING_BASE(phybaseaddr, hd_rx);
12774689Sql147931 	vrx = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_rx));
12784689Sql147931 	/* virtual address of the first descriptor */
12796890Sql147931 	rsc->rxdesc_h = (struct rtw_rxdesc *)(uintptr_t)vrx;
12804689Sql147931 	rxds = rsc->rxdesc_h;
12814689Sql147931 
12824689Sql147931 	/* allocate data structures to describe RX DMA buffers */
12834689Sql147931 	buflen = sizeof (struct rtw_rxbuf) * RTW_RXQLEN;
12844689Sql147931 	rxbf = (struct rtw_rxbuf *)kmem_zalloc(buflen, KM_SLEEP);
12854689Sql147931 	rsc->rxbuf_h = rxbf;
12864689Sql147931 
12874689Sql147931 	for (j = 0; j < RTW_RXQLEN; j++, rxbf++, rxds++) {
12884689Sql147931 		rxbf->rxdesc = rxds;
12896890Sql147931 		rxbf->bf_daddr =
12906890Sql147931 		    prx + ((uintptr_t)rxds - (uintptr_t)rsc->rxdesc_h);
12914689Sql147931 
12924689Sql147931 		/* alloc DMA memory */
12934689Sql147931 		err = rtw_alloc_dma_mem(devinfo, &dma_attr_rxbuf,
12944689Sql147931 		    rsc->sc_dmabuf_size,
12954689Sql147931 		    &rtw_buf_accattr,
12964689Sql147931 		    DDI_DMA_STREAMING, DDI_DMA_READ | DDI_DMA_STREAMING,
12974689Sql147931 		    &rxbf->bf_dma);
12984689Sql147931 		if (err != DDI_SUCCESS)
12994689Sql147931 			goto error;
13004689Sql147931 	}
13014689Sql147931 
13024689Sql147931 	return (DDI_SUCCESS);
13034689Sql147931 error:
13044689Sql147931 	return (DDI_FAILURE);
13054689Sql147931 }
13064689Sql147931 
13074689Sql147931 static void
rtw_hwring_setup(rtw_softc_t * rsc)13084689Sql147931 rtw_hwring_setup(rtw_softc_t *rsc)
13094689Sql147931 {
13104689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
13114689Sql147931 	uint32_t phybaseaddr;
13124689Sql147931 
13134689Sql147931 	phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address;
13144689Sql147931 
13154689Sql147931 	RTW_WRITE(regs, RTW_RDSAR, RTW_RING_BASE(phybaseaddr, hd_rx));
13164689Sql147931 	RTW_WRITE(regs, RTW_TLPDA, RTW_RING_BASE(phybaseaddr, hd_txlo));
13174689Sql147931 	RTW_WRITE(regs, RTW_TNPDA, RTW_RING_BASE(phybaseaddr, hd_txmd));
13184689Sql147931 	RTW_WRITE(regs, RTW_THPDA, RTW_RING_BASE(phybaseaddr, hd_txhi));
13194689Sql147931 	RTW_WRITE(regs, RTW_TBDA, RTW_RING_BASE(phybaseaddr, hd_bcn));
13204689Sql147931 	rsc->hw_start = RTW_READ(regs, RTW_TNPDA);
13214689Sql147931 	rsc->hw_go = RTW_READ(regs, RTW_TNPDA);
13224689Sql147931 }
13234689Sql147931 
13244689Sql147931 static void
rtw_swring_setup(rtw_softc_t * rsc,int flag)13254689Sql147931 rtw_swring_setup(rtw_softc_t *rsc, int flag)
13264689Sql147931 {
13274689Sql147931 	int i, j;
13284689Sql147931 	int is_last;
13294689Sql147931 	struct rtw_txbuf *txbf;
13304689Sql147931 	struct rtw_rxbuf *rxbf;
13314689Sql147931 	uint32_t phybaseaddr, ptx[RTW_NTXPRI], baddr_desc, taddr_desc;
13324689Sql147931 
13334689Sql147931 	phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address;
13344689Sql147931 	ptx[0] = RTW_RING_BASE(phybaseaddr, hd_txlo);
13354689Sql147931 	ptx[1] = RTW_RING_BASE(phybaseaddr, hd_txmd);
13364689Sql147931 	ptx[2] = RTW_RING_BASE(phybaseaddr, hd_txhi);
13374689Sql147931 	ptx[3] = RTW_RING_BASE(phybaseaddr, hd_bcn);
13384689Sql147931 	RTW_DMA_SYNC(rsc->sc_desc_dma, DDI_DMA_SYNC_FORDEV);
13394689Sql147931 	/* sync tx desc and tx buf */
13404689Sql147931 	for (i = 0; i < RTW_NTXPRI; i++) {
13414689Sql147931 		rsc->sc_txq[i].tx_prod = rsc->sc_txq[i].tx_cons = 0;
13424689Sql147931 		rsc->sc_txq[i].tx_nfree = rtw_qlen[i];
13434689Sql147931 		txbf = list_head(&rsc->sc_txq[i].tx_free_list);
13444689Sql147931 		while (txbf != NULL) {
13454689Sql147931 			list_remove(&rsc->sc_txq[i].tx_free_list, txbf);
13464689Sql147931 			txbf = list_head(&rsc->sc_txq[i].tx_free_list);
13474689Sql147931 		}
13484689Sql147931 		txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
13494689Sql147931 		while (txbf != NULL) {
13504689Sql147931 			list_remove(&rsc->sc_txq[i].tx_dirty_list, txbf);
13514689Sql147931 			txbf = list_head(&rsc->sc_txq[i].tx_dirty_list);
13524689Sql147931 		}
13534689Sql147931 		txbf = rsc->sc_txq[i].txbuf_h;
13544689Sql147931 		baddr_desc = ptx[i];
13554689Sql147931 		taddr_desc = baddr_desc + sizeof (struct rtw_txdesc);
13564689Sql147931 		for (j = 0; j < rtw_qlen[i]; j++) {
13574689Sql147931 			list_insert_tail(&rsc->sc_txq[i].tx_free_list, txbf);
13584689Sql147931 			if (j == (rtw_qlen[i] - 1)) {
13594689Sql147931 				is_last = 1;
13604689Sql147931 			} else {
13614689Sql147931 				is_last = 0;
13624689Sql147931 			}
13634689Sql147931 
13644689Sql147931 			if (is_last) {
13654689Sql147931 				txbf->txdesc->td_next = baddr_desc;
13664689Sql147931 			} else {
13674689Sql147931 				txbf->txdesc->td_next = taddr_desc;
13684689Sql147931 			}
13694689Sql147931 			txbf->next_bf_daddr = txbf->txdesc->td_next;
13704689Sql147931 			RTW_DMA_SYNC(txbf->bf_dma, DDI_DMA_SYNC_FORDEV);
13714689Sql147931 			txbf->order = j;
13724689Sql147931 			txbf++;
13734689Sql147931 			taddr_desc += sizeof (struct rtw_txdesc);
13744689Sql147931 		}
13754689Sql147931 	}
13764689Sql147931 	if (!flag)
13774689Sql147931 		return;
13784689Sql147931 
13794689Sql147931 	/* sync rx desc and rx buf */
13804689Sql147931 	rsc->rx_next = 0;
13814689Sql147931 	rxbf = rsc->rxbuf_h;
13824689Sql147931 	for (j = 0; j < RTW_RXQLEN; j++) {
13834689Sql147931 		RTW_DMA_SYNC(rxbf->bf_dma, DDI_DMA_SYNC_FORCPU);
13844689Sql147931 		if (j == (RTW_RXQLEN - 1))
13854689Sql147931 			is_last = 1;
13864689Sql147931 		else
13874689Sql147931 			is_last = 0;
13884689Sql147931 		rtw_rxdesc_init(rsc, rxbf, j, is_last);
13894689Sql147931 		rxbf++;
13904689Sql147931 	}
13914689Sql147931 }
13924689Sql147931 
13934689Sql147931 static void
rtw_resume_ticks(rtw_softc_t * rsc)13944689Sql147931 rtw_resume_ticks(rtw_softc_t *rsc)
13954689Sql147931 {
13964689Sql147931 	RTW_WRITE(&rsc->sc_regs, RTW_TINT, 0xffffffff);
13974689Sql147931 }
13984689Sql147931 
13994689Sql147931 const char *
rtw_pwrstate_string(enum rtw_pwrstate power)14004689Sql147931 rtw_pwrstate_string(enum rtw_pwrstate power)
14014689Sql147931 {
14024689Sql147931 	switch (power) {
14034689Sql147931 	case RTW_ON:
14044689Sql147931 		return ("on");
14054689Sql147931 	case RTW_SLEEP:
14064689Sql147931 		return ("sleep");
14074689Sql147931 	case RTW_OFF:
14084689Sql147931 		return ("off");
14094689Sql147931 	default:
14104689Sql147931 		return ("unknown");
14114689Sql147931 	}
14124689Sql147931 }
14134689Sql147931 
14144689Sql147931 /*
14154689Sql147931  * XXX For Maxim, I am using the RFMD settings gleaned from the
14164689Sql147931  * reference driver, plus a magic Maxim "ON" value that comes from
14174689Sql147931  * the Realtek document "Windows PG for Rtl8180."
14184689Sql147931  */
14194689Sql147931 /*ARGSUSED*/
14204689Sql147931 static void
rtw_maxim_pwrstate(struct rtw_regs * regs,enum rtw_pwrstate power,int before_rf,int digphy)14214689Sql147931 rtw_maxim_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
14224689Sql147931     int before_rf, int digphy)
14234689Sql147931 {
14244689Sql147931 	uint32_t anaparm;
14254689Sql147931 
14264689Sql147931 	anaparm = RTW_READ(regs, RTW_ANAPARM);
14274689Sql147931 	anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
14284689Sql147931 
14294689Sql147931 	switch (power) {
14304689Sql147931 	case RTW_OFF:
14314689Sql147931 		if (before_rf)
14324689Sql147931 			return;
14334689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_MAXIM_OFF;
14344689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
14354689Sql147931 		break;
14364689Sql147931 	case RTW_SLEEP:
14374689Sql147931 		if (!before_rf)
14384689Sql147931 			return;
14394689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_MAXIM_SLEEP;
14404689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
14414689Sql147931 		break;
14424689Sql147931 	case RTW_ON:
14434689Sql147931 		if (!before_rf)
14444689Sql147931 			return;
14454689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_MAXIM_ON;
14464689Sql147931 		break;
14474689Sql147931 	}
14484689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PWR,
14494689Sql147931 	    "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
14504689Sql147931 	    __func__, rtw_pwrstate_string(power),
14514689Sql147931 	    (before_rf) ? "before" : "after", anaparm);
14524689Sql147931 
14534689Sql147931 	RTW_WRITE(regs, RTW_ANAPARM, anaparm);
14544689Sql147931 	RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
14554689Sql147931 }
14564689Sql147931 
14574689Sql147931 /*
14584689Sql147931  * XXX I am using the RFMD settings gleaned from the reference
14594689Sql147931  * driver.  They agree
14604689Sql147931  */
14614689Sql147931 /*ARGSUSED*/
14624689Sql147931 static void
rtw_rfmd_pwrstate(struct rtw_regs * regs,enum rtw_pwrstate power,int before_rf,int digphy)14634689Sql147931 rtw_rfmd_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
14644689Sql147931     int before_rf, int digphy)
14654689Sql147931 {
14664689Sql147931 	uint32_t anaparm;
14674689Sql147931 
14684689Sql147931 	anaparm = RTW_READ(regs, RTW_ANAPARM);
14694689Sql147931 	anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
14704689Sql147931 
14714689Sql147931 	switch (power) {
14724689Sql147931 	case RTW_OFF:
14734689Sql147931 		if (before_rf)
14744689Sql147931 			return;
14754689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_RFMD_OFF;
14764689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
14774689Sql147931 		break;
14784689Sql147931 	case RTW_SLEEP:
14794689Sql147931 		if (!before_rf)
14804689Sql147931 			return;
14814689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_RFMD_SLEEP;
14824689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
14834689Sql147931 		break;
14844689Sql147931 	case RTW_ON:
14854689Sql147931 		if (!before_rf)
14864689Sql147931 			return;
14874689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_RFMD_ON;
14884689Sql147931 		break;
14894689Sql147931 	}
14904689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PWR,
14914689Sql147931 	    "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
14924689Sql147931 	    __func__, rtw_pwrstate_string(power),
14934689Sql147931 	    (before_rf) ? "before" : "after", anaparm);
14944689Sql147931 
14954689Sql147931 	RTW_WRITE(regs, RTW_ANAPARM, anaparm);
14964689Sql147931 	RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
14974689Sql147931 }
14984689Sql147931 
14994689Sql147931 static void
rtw_philips_pwrstate(struct rtw_regs * regs,enum rtw_pwrstate power,int before_rf,int digphy)15004689Sql147931 rtw_philips_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
15014689Sql147931     int before_rf, int digphy)
15024689Sql147931 {
15034689Sql147931 	uint32_t anaparm;
15044689Sql147931 
15054689Sql147931 	anaparm = RTW_READ(regs, RTW_ANAPARM);
15064689Sql147931 	anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
15074689Sql147931 
15084689Sql147931 	switch (power) {
15094689Sql147931 	case RTW_OFF:
15104689Sql147931 		if (before_rf)
15114689Sql147931 			return;
15124689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_OFF;
15134689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
15144689Sql147931 		break;
15154689Sql147931 	case RTW_SLEEP:
15164689Sql147931 		if (!before_rf)
15174689Sql147931 			return;
15184689Sql147931 		anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_SLEEP;
15194689Sql147931 		anaparm |= RTW_ANAPARM_TXDACOFF;
15204689Sql147931 		break;
15214689Sql147931 	case RTW_ON:
15224689Sql147931 		if (!before_rf)
15234689Sql147931 			return;
15244689Sql147931 		if (digphy) {
15254689Sql147931 			anaparm |= RTW_ANAPARM_RFPOW_DIG_PHILIPS_ON;
15264689Sql147931 			/* XXX guess */
15274689Sql147931 			anaparm |= RTW_ANAPARM_TXDACOFF;
15284689Sql147931 		} else
15294689Sql147931 			anaparm |= RTW_ANAPARM_RFPOW_ANA_PHILIPS_ON;
15304689Sql147931 		break;
15314689Sql147931 	}
15324689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PWR,
15334689Sql147931 	    "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
15344689Sql147931 	    __func__, rtw_pwrstate_string(power),
15354689Sql147931 	    (before_rf) ? "before" : "after", anaparm);
15364689Sql147931 
15374689Sql147931 	RTW_WRITE(regs, RTW_ANAPARM, anaparm);
15384689Sql147931 	RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM);
15394689Sql147931 }
15404689Sql147931 
15414689Sql147931 static void
rtw_pwrstate0(rtw_softc_t * rsc,enum rtw_pwrstate power,int before_rf,int digphy)15424689Sql147931 rtw_pwrstate0(rtw_softc_t *rsc, enum rtw_pwrstate power, int before_rf,
15434689Sql147931     int digphy)
15444689Sql147931 {
15454689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
15464689Sql147931 
15474689Sql147931 	rtw_set_access(regs, RTW_ACCESS_ANAPARM);
15484689Sql147931 
15494689Sql147931 	(*rsc->sc_pwrstate_cb)(regs, power, before_rf, digphy);
15504689Sql147931 
15514689Sql147931 	rtw_set_access(regs, RTW_ACCESS_NONE);
15524689Sql147931 }
15534689Sql147931 
15544689Sql147931 static void
rtw_rf_destroy(struct rtw_rf * rf)15554689Sql147931 rtw_rf_destroy(struct rtw_rf *rf)
15564689Sql147931 {
15574689Sql147931 	(*rf->rf_destroy)(rf);
15584689Sql147931 }
15594689Sql147931 
15604689Sql147931 static int
rtw_rf_pwrstate(struct rtw_rf * rf,enum rtw_pwrstate power)15614689Sql147931 rtw_rf_pwrstate(struct rtw_rf *rf, enum rtw_pwrstate power)
15624689Sql147931 {
15634689Sql147931 	return (*rf->rf_pwrstate)(rf, power);
15644689Sql147931 }
15654689Sql147931 
15664689Sql147931 static int
rtw_pwrstate(rtw_softc_t * rsc,enum rtw_pwrstate power)15674689Sql147931 rtw_pwrstate(rtw_softc_t *rsc, enum rtw_pwrstate power)
15684689Sql147931 {
15694689Sql147931 	int rc;
15704689Sql147931 
15714689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PWR,
15724689Sql147931 	    "%s: %s->%s\n", __func__,
15734689Sql147931 	    rtw_pwrstate_string(rsc->sc_pwrstate), rtw_pwrstate_string(power));
15744689Sql147931 
15754689Sql147931 	if (rsc->sc_pwrstate == power)
15764689Sql147931 		return (0);
15774689Sql147931 
15784689Sql147931 	rtw_pwrstate0(rsc, power, 1, rsc->sc_flags & RTW_F_DIGPHY);
15794689Sql147931 	rc = rtw_rf_pwrstate(rsc->sc_rf, power);
15804689Sql147931 	rtw_pwrstate0(rsc, power, 0, rsc->sc_flags & RTW_F_DIGPHY);
15814689Sql147931 
15824689Sql147931 	switch (power) {
15834689Sql147931 	case RTW_ON:
15844689Sql147931 		/* TBD set LEDs */
15854689Sql147931 		break;
15864689Sql147931 	case RTW_SLEEP:
15874689Sql147931 		/* TBD */
15884689Sql147931 		break;
15894689Sql147931 	case RTW_OFF:
15904689Sql147931 		/* TBD */
15914689Sql147931 		break;
15924689Sql147931 	}
15934689Sql147931 	if (rc == 0)
15944689Sql147931 		rsc->sc_pwrstate = power;
15954689Sql147931 	else
15964689Sql147931 		rsc->sc_pwrstate = RTW_OFF;
15974689Sql147931 	return (rc);
15984689Sql147931 }
15994689Sql147931 
16004689Sql147931 void
rtw_disable(rtw_softc_t * rsc)16014689Sql147931 rtw_disable(rtw_softc_t *rsc)
16024689Sql147931 {
16034689Sql147931 	int rc;
16044689Sql147931 
16054689Sql147931 	if ((rsc->sc_flags & RTW_F_ENABLED) == 0)
16064689Sql147931 		return;
16074689Sql147931 
16084689Sql147931 	/* turn off PHY */
16094689Sql147931 	if ((rsc->sc_flags & RTW_F_INVALID) == 0 &&
16104689Sql147931 	    (rc = rtw_pwrstate(rsc, RTW_OFF)) != 0) {
16114689Sql147931 		cmn_err(CE_WARN, "failed to turn off PHY (%d)\n", rc);
16124689Sql147931 	}
16134689Sql147931 
16144689Sql147931 	if (rsc->sc_disable != NULL)
16154689Sql147931 		(*rsc->sc_disable)(rsc);
16164689Sql147931 
16174689Sql147931 	rsc->sc_flags &= ~RTW_F_ENABLED;
16184689Sql147931 }
16194689Sql147931 
16204689Sql147931 int
rtw_enable(rtw_softc_t * rsc)16214689Sql147931 rtw_enable(rtw_softc_t *rsc)
16224689Sql147931 {
16234689Sql147931 	if ((rsc->sc_flags & RTW_F_ENABLED) == 0) {
16244689Sql147931 		if (rsc->sc_enable != NULL && (*rsc->sc_enable)(rsc) != 0) {
16254689Sql147931 			cmn_err(CE_WARN, "device enable failed\n");
16264689Sql147931 			return (EIO);
16274689Sql147931 		}
16284689Sql147931 		rsc->sc_flags |= RTW_F_ENABLED;
16294689Sql147931 		if (rtw_pwrstate(rsc, RTW_ON) != 0)
16304689Sql147931 			cmn_err(CE_WARN, "PHY turn on failed\n");
16314689Sql147931 	}
16324689Sql147931 	return (0);
16334689Sql147931 }
16344689Sql147931 
16354689Sql147931 static void
rtw_set_nettype(rtw_softc_t * rsc,enum ieee80211_opmode opmode)16364689Sql147931 rtw_set_nettype(rtw_softc_t *rsc, enum ieee80211_opmode opmode)
16374689Sql147931 {
16384689Sql147931 	uint8_t msr;
16394689Sql147931 
16404689Sql147931 	/* I'm guessing that MSR is protected as CONFIG[0123] are. */
16414689Sql147931 	rtw_set_access(&rsc->sc_regs, RTW_ACCESS_CONFIG);
16424689Sql147931 
16434689Sql147931 	msr = RTW_READ8(&rsc->sc_regs, RTW_MSR) & ~RTW_MSR_NETYPE_MASK;
16444689Sql147931 
16454689Sql147931 	switch (opmode) {
16464689Sql147931 	case IEEE80211_M_AHDEMO:
16474689Sql147931 	case IEEE80211_M_IBSS:
16484689Sql147931 		msr |= RTW_MSR_NETYPE_ADHOC_OK;
16494689Sql147931 		break;
16504689Sql147931 	case IEEE80211_M_HOSTAP:
16514689Sql147931 		msr |= RTW_MSR_NETYPE_AP_OK;
16524689Sql147931 		break;
16534689Sql147931 	case IEEE80211_M_STA:
16544689Sql147931 		msr |= RTW_MSR_NETYPE_INFRA_OK;
16554689Sql147931 		break;
16564689Sql147931 	}
16574689Sql147931 	RTW_WRITE8(&rsc->sc_regs, RTW_MSR, msr);
16584689Sql147931 
16594689Sql147931 	rtw_set_access(&rsc->sc_regs, RTW_ACCESS_NONE);
16604689Sql147931 }
16614689Sql147931 
16624689Sql147931 static void
rtw_pktfilt_load(rtw_softc_t * rsc)16634689Sql147931 rtw_pktfilt_load(rtw_softc_t *rsc)
16644689Sql147931 {
16654689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
16664689Sql147931 	struct ieee80211com *ic = &rsc->sc_ic;
16674689Sql147931 
16684689Sql147931 	/* XXX might be necessary to stop Rx/Tx engines while setting filters */
16694689Sql147931 	rsc->sc_rcr &= ~RTW_RCR_PKTFILTER_MASK;
16704689Sql147931 	rsc->sc_rcr &= ~(RTW_RCR_MXDMA_MASK | RTW_RCR_RXFTH_MASK);
16714689Sql147931 
16724689Sql147931 	rsc->sc_rcr |= RTW_RCR_PKTFILTER_DEFAULT;
16734689Sql147931 	/* MAC auto-reset PHY (huh?) */
16744689Sql147931 	rsc->sc_rcr |= RTW_RCR_ENMARP;
16754689Sql147931 	/* DMA whole Rx packets, only.  Set Tx DMA burst size to 1024 bytes. */
16764689Sql147931 	rsc->sc_rcr |= RTW_RCR_RXFTH_WHOLE |RTW_RCR_MXDMA_1024;
16774689Sql147931 
16784689Sql147931 	switch (ic->ic_opmode) {
16794689Sql147931 	case IEEE80211_M_AHDEMO:
16804689Sql147931 	case IEEE80211_M_IBSS:
16814689Sql147931 		/* receive broadcasts in our BSS */
16824689Sql147931 		rsc->sc_rcr |= RTW_RCR_ADD3;
16834689Sql147931 		break;
16844689Sql147931 	default:
16854689Sql147931 		break;
16864689Sql147931 	}
16874689Sql147931 #if 0
16884689Sql147931 	/* XXX accept all broadcast if scanning */
16894689Sql147931 	rsc->sc_rcr |= RTW_RCR_AB;	/* accept all broadcast */
16904689Sql147931 #endif
16914689Sql147931 	RTW_WRITE(regs, RTW_MAR0, 0xffffffff);
16924689Sql147931 	RTW_WRITE(regs, RTW_MAR1, 0xffffffff);
16934689Sql147931 	rsc->sc_rcr |= RTW_RCR_AM;
16944689Sql147931 	RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
16954689Sql147931 	RTW_SYNC(regs, RTW_MAR0, RTW_RCR); /* RTW_MAR0 < RTW_MAR1 < RTW_RCR */
16964689Sql147931 
16974689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PKTFILT,
16984689Sql147931 	    "RTW_MAR0 %08x RTW_MAR1 %08x RTW_RCR %08x\n",
16994689Sql147931 	    RTW_READ(regs, RTW_MAR0),
17004689Sql147931 	    RTW_READ(regs, RTW_MAR1), RTW_READ(regs, RTW_RCR));
17014689Sql147931 	RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
17024689Sql147931 }
17034689Sql147931 
17044689Sql147931 static void
rtw_transmit_config(struct rtw_regs * regs)17054689Sql147931 rtw_transmit_config(struct rtw_regs *regs)
17064689Sql147931 {
17074689Sql147931 	uint32_t tcr;
17084689Sql147931 
17094689Sql147931 	tcr = RTW_READ(regs, RTW_TCR);
17104689Sql147931 
17114689Sql147931 	tcr |= RTW_TCR_CWMIN;
17124689Sql147931 	tcr &= ~RTW_TCR_MXDMA_MASK;
17134689Sql147931 	tcr |= RTW_TCR_MXDMA_1024;
17144689Sql147931 	tcr |= RTW_TCR_SAT;		/* send ACK as fast as possible */
17154689Sql147931 	tcr &= ~RTW_TCR_LBK_MASK;
17164689Sql147931 	tcr |= RTW_TCR_LBK_NORMAL;	/* normal operating mode */
17174689Sql147931 
17184689Sql147931 	/* set short/long retry limits */
17194689Sql147931 	tcr &= ~(RTW_TCR_SRL_MASK|RTW_TCR_LRL_MASK);
17204689Sql147931 	tcr |= LSHIFT(0x4, RTW_TCR_SRL_MASK) | LSHIFT(0x4, RTW_TCR_LRL_MASK);
17214689Sql147931 
17224689Sql147931 	tcr &= ~RTW_TCR_CRC;	/* NIC appends CRC32 */
17234689Sql147931 	RTW_WRITE(regs, RTW_TCR, tcr);
17244689Sql147931 	RTW_SYNC(regs, RTW_TCR, RTW_TCR);
17254689Sql147931 }
17264689Sql147931 
17274689Sql147931 int
rtw_refine_setting(rtw_softc_t * rsc)17284689Sql147931 rtw_refine_setting(rtw_softc_t *rsc)
17294689Sql147931 {
17304689Sql147931 	struct rtw_regs *regs;
17314689Sql147931 	int rc = 0;
17324689Sql147931 
17334689Sql147931 	regs = &rsc->sc_regs;
17344689Sql147931 	rc = rtw_reset(rsc);
17354689Sql147931 	if (rc != 0)
17364689Sql147931 		return (-1);
17374689Sql147931 
17384689Sql147931 	rtw_beacon_tx_disable(regs);
17394689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE|RTW_CR_TE, 1);
17404689Sql147931 	rtw_set_mode(regs, RTW_EPROM_CMD_CONFIG);
17414689Sql147931 
17424689Sql147931 	rtw_transmit_config(regs);
17434689Sql147931 	rtw_pktfilt_load(rsc);
17444689Sql147931 	rtw_set_access(regs, RTW_ACCESS_CONFIG);
17454689Sql147931 	RTW_WRITE(regs, RTW_TINT, 0xffffffff);
17464689Sql147931 	RTW_WRITE8(regs, RTW_MSR, 0x0);	/* no link */
17474689Sql147931 	RTW_WRITE16(regs, RTW_BRSR, 0);
17484689Sql147931 
17494689Sql147931 	rtw_set_access(regs, RTW_ACCESS_ANAPARM);
17504689Sql147931 	rtw_set_access(regs, RTW_ACCESS_NONE);
17514689Sql147931 	RTW_WRITE(regs, RTW_FEMR, 0xffff);
17524689Sql147931 	RTW_SYNC(regs, RTW_FEMR, RTW_FEMR);
17534689Sql147931 	rtw_set_rfprog(regs, rsc->sc_rfchipid, "rtw");
17544689Sql147931 
17554689Sql147931 	RTW_WRITE8(regs, RTW_PHYDELAY, rsc->sc_phydelay);
17564689Sql147931 	RTW_WRITE8(regs, RTW_CRCOUNT, RTW_CRCOUNT_MAGIC);
17574689Sql147931 	rtw_set_mode(regs, RTW_EPROM_CMD_NORMAL);
17584689Sql147931 	return (0);
17594689Sql147931 }
17604689Sql147931 
17614689Sql147931 static int
rtw_tune(rtw_softc_t * rsc)17624689Sql147931 rtw_tune(rtw_softc_t *rsc)
17634689Sql147931 {
17644689Sql147931 	struct ieee80211com *ic = &rsc->sc_ic;
17654689Sql147931 	uint32_t chan;
17664689Sql147931 	int rc;
17674689Sql147931 	int antdiv = rsc->sc_flags & RTW_F_ANTDIV,
17684689Sql147931 	    dflantb = rsc->sc_flags & RTW_F_DFLANTB;
17694689Sql147931 
17704689Sql147931 	ASSERT(ic->ic_curchan != NULL);
17714689Sql147931 
17724689Sql147931 	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
17734689Sql147931 	RTW_DPRINTF(RTW_DEBUG_TUNE, "rtw: chan no = %x", chan);
17744689Sql147931 
17754689Sql147931 	if (chan == IEEE80211_CHAN_ANY) {
17764689Sql147931 		cmn_err(CE_WARN, "%s: chan == IEEE80211_CHAN_ANY\n", __func__);
17774689Sql147931 		return (-1);
17784689Sql147931 	}
17794689Sql147931 
17804689Sql147931 	if (chan == rsc->sc_cur_chan) {
17814689Sql147931 		RTW_DPRINTF(RTW_DEBUG_TUNE,
17824689Sql147931 		    "%s: already tuned chan %d\n", __func__, chan);
17834689Sql147931 		return (0);
17844689Sql147931 	}
17854689Sql147931 	rtw_idle(&rsc->sc_regs);
17864689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
17874689Sql147931 	ASSERT((rsc->sc_flags & RTW_F_ENABLED) != 0);
17884689Sql147931 
17894689Sql147931 	if ((rc = rtw_phy_init(&rsc->sc_regs, rsc->sc_rf,
17904689Sql147931 	    rtw_chan2txpower(&rsc->sc_srom, ic, ic->ic_curchan),
17914689Sql147931 	    rsc->sc_csthr, ic->ic_curchan->ich_freq, antdiv,
17924689Sql147931 	    dflantb, RTW_ON)) != 0) {
17934689Sql147931 		/* XXX condition on powersaving */
17944689Sql147931 		cmn_err(CE_NOTE, "phy init failed\n");
17954689Sql147931 	}
17964689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 1);
17974689Sql147931 	rtw_resume_ticks(rsc);
17984689Sql147931 	rsc->sc_cur_chan = chan;
17994689Sql147931 	return (rc);
18004689Sql147931 }
18014689Sql147931 
18024689Sql147931 static int
rtw_init(rtw_softc_t * rsc)18034689Sql147931 rtw_init(rtw_softc_t *rsc)
18044689Sql147931 {
18054689Sql147931 	struct ieee80211com *ic = &rsc->sc_ic;
18064689Sql147931 	int rc = 0;
18074689Sql147931 
180810448SMikore.Li@Sun.COM 	rtw_stop(rsc);
180910448SMikore.Li@Sun.COM 	mutex_enter(&rsc->sc_genlock);
18104689Sql147931 	if ((rc = rtw_enable(rsc)) != 0)
18114689Sql147931 		goto out;
18124689Sql147931 	rc = rtw_refine_setting(rsc);
181310448SMikore.Li@Sun.COM 	if (rc != 0) {
181410448SMikore.Li@Sun.COM 		mutex_exit(&rsc->sc_genlock);
18154689Sql147931 		return (rc);
181610448SMikore.Li@Sun.COM 	}
18174689Sql147931 	rtw_swring_setup(rsc, 1);
18184689Sql147931 	rtw_hwring_setup(rsc);
18194689Sql147931 	RTW_WRITE16(&rsc->sc_regs, RTW_BSSID16, 0x0);
18204689Sql147931 	RTW_WRITE(&rsc->sc_regs, RTW_BSSID32, 0x0);
18214689Sql147931 	rtw_enable_interrupts(rsc);
18224689Sql147931 
18234689Sql147931 	ic->ic_ibss_chan = &ic->ic_sup_channels[1];
18244689Sql147931 	ic->ic_curchan = ic->ic_ibss_chan;
18254689Sql147931 	RTW_DPRINTF(RTW_DEBUG_TUNE, "%s: channel %d freq %d flags 0x%04x\n",
18264689Sql147931 	    __func__, ieee80211_chan2ieee(ic, ic->ic_curchan),
18274689Sql147931 	    ic->ic_curchan->ich_freq, ic->ic_curchan->ich_flags);
182810448SMikore.Li@Sun.COM 	rsc->sc_invalid = 0;
18294689Sql147931 out:
183010448SMikore.Li@Sun.COM 	mutex_exit(&rsc->sc_genlock);
18314689Sql147931 	return (rc);
18324689Sql147931 }
18334689Sql147931 
18344689Sql147931 static struct rtw_rf *
rtw_rf_attach(rtw_softc_t * rsc,enum rtw_rfchipid rfchipid,int digphy)18354689Sql147931 rtw_rf_attach(rtw_softc_t *rsc, enum rtw_rfchipid rfchipid, int digphy)
18364689Sql147931 {
18374689Sql147931 	rtw_rf_write_t rf_write;
18384689Sql147931 	struct rtw_rf *rf;
18394689Sql147931 	int rtw_host_rfio;
18404689Sql147931 
18414689Sql147931 	switch (rfchipid) {
18424689Sql147931 	default:
18434689Sql147931 		rf_write = rtw_rf_hostwrite;
18444689Sql147931 		break;
18454689Sql147931 	case RTW_RFCHIPID_INTERSIL:
18464689Sql147931 	case RTW_RFCHIPID_PHILIPS:
18474689Sql147931 	case RTW_RFCHIPID_GCT:	/* XXX a guess */
18484689Sql147931 	case RTW_RFCHIPID_RFMD:
18494689Sql147931 		rtw_host_rfio = 1;
18504689Sql147931 		rf_write = (rtw_host_rfio) ? rtw_rf_hostwrite : rtw_rf_macwrite;
18514689Sql147931 		break;
18524689Sql147931 	}
18534689Sql147931 
18544689Sql147931 	switch (rfchipid) {
18554689Sql147931 	case RTW_RFCHIPID_MAXIM:
18564689Sql147931 		rf = rtw_max2820_create(&rsc->sc_regs, rf_write, 0);
18574689Sql147931 		rsc->sc_pwrstate_cb = rtw_maxim_pwrstate;
18584689Sql147931 		break;
18594689Sql147931 	case RTW_RFCHIPID_PHILIPS:
18604689Sql147931 		rf = rtw_sa2400_create(&rsc->sc_regs, rf_write, digphy);
18614689Sql147931 		rsc->sc_pwrstate_cb = rtw_philips_pwrstate;
18624689Sql147931 		break;
18634689Sql147931 	case RTW_RFCHIPID_RFMD:
18644689Sql147931 		/* XXX RFMD has no RF constructor */
18654689Sql147931 		rsc->sc_pwrstate_cb = rtw_rfmd_pwrstate;
18664689Sql147931 		/*FALLTHROUGH*/
18674689Sql147931 	default:
18684689Sql147931 		return (NULL);
18694689Sql147931 	}
18704689Sql147931 	if (rf != NULL) {
18714689Sql147931 		rf->rf_continuous_tx_cb =
18724689Sql147931 		    (rtw_continuous_tx_cb_t)rtw_continuous_tx_enable;
18734689Sql147931 		rf->rf_continuous_tx_arg = (void *)rsc;
18744689Sql147931 	}
18754689Sql147931 	return (rf);
18764689Sql147931 }
18774689Sql147931 
18784689Sql147931 /*
18794689Sql147931  * Revision C and later use a different PHY delay setting than
18804689Sql147931  * revisions A and B.
18814689Sql147931  */
18824689Sql147931 static uint8_t
rtw_check_phydelay(struct rtw_regs * regs,uint32_t rcr0)18834689Sql147931 rtw_check_phydelay(struct rtw_regs *regs, uint32_t rcr0)
18844689Sql147931 {
18854689Sql147931 #define	REVAB (RTW_RCR_MXDMA_UNLIMITED | RTW_RCR_AICV)
18864689Sql147931 #define	REVC (REVAB | RTW_RCR_RXFTH_WHOLE)
18874689Sql147931 
18884689Sql147931 	uint8_t phydelay = LSHIFT(0x6, RTW_PHYDELAY_PHYDELAY);
18894689Sql147931 
18904689Sql147931 	RTW_WRITE(regs, RTW_RCR, REVAB);
18914689Sql147931 	RTW_WBW(regs, RTW_RCR, RTW_RCR);
18924689Sql147931 	RTW_WRITE(regs, RTW_RCR, REVC);
18934689Sql147931 
18944689Sql147931 	RTW_WBR(regs, RTW_RCR, RTW_RCR);
18954689Sql147931 	if ((RTW_READ(regs, RTW_RCR) & REVC) == REVC)
18964689Sql147931 		phydelay |= RTW_PHYDELAY_REVC_MAGIC;
18974689Sql147931 
18984689Sql147931 	RTW_WRITE(regs, RTW_RCR, rcr0);	/* restore RCR */
18994689Sql147931 	RTW_SYNC(regs, RTW_RCR, RTW_RCR);
19004689Sql147931 
19014689Sql147931 	return (phydelay);
19024689Sql147931 #undef REVC
19034689Sql147931 }
19044689Sql147931 
19054689Sql147931 static void rtw_intr_rx(rtw_softc_t *rsc);
19064689Sql147931 static void rtw_ring_recycling(rtw_softc_t *rsc, uint16_t isr, uint32_t pri);
19074689Sql147931 
19084689Sql147931 static int
rtw_get_rate(struct ieee80211com * ic)19094689Sql147931 rtw_get_rate(struct ieee80211com *ic)
19104689Sql147931 {
19114689Sql147931 	uint8_t (*rates)[IEEE80211_RATE_MAXSIZE];
19124689Sql147931 	int rate;
19134689Sql147931 
19144689Sql147931 	rates = &ic->ic_bss->in_rates.ir_rates;
19154689Sql147931 
19164689Sql147931 	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
19174689Sql147931 		rate = ic->ic_fixed_rate;
19184689Sql147931 	else if (ic->ic_state == IEEE80211_S_RUN)
19194689Sql147931 		rate = (*rates)[ic->ic_bss->in_txrate];
19204689Sql147931 	else
19214689Sql147931 		rate = 0;
19224689Sql147931 	return (rate & IEEE80211_RATE_VAL);
19234689Sql147931 }
19244689Sql147931 
19254689Sql147931 /*
19264689Sql147931  * Arguments in:
19274689Sql147931  *
19284689Sql147931  * paylen:  payload length (no FCS, no WEP header)
19294689Sql147931  *
19304689Sql147931  * hdrlen:  header length
19314689Sql147931  *
19324689Sql147931  * rate:    MSDU speed, units 500kb/s
19334689Sql147931  *
19344689Sql147931  * flags:   IEEE80211_F_SHPREAMBLE (use short preamble),
19354689Sql147931  *          IEEE80211_F_SHSLOT (use short slot length)
19364689Sql147931  *
19374689Sql147931  * Arguments out:
19384689Sql147931  *
19394689Sql147931  * d:       802.11 Duration field for RTS,
19404689Sql147931  *          802.11 Duration field for data frame,
19414689Sql147931  *          PLCP Length for data frame,
19424689Sql147931  *          residual octets at end of data slot
19434689Sql147931  */
19444689Sql147931 static int
rtw_compute_duration1(int len,int use_ack,uint32_t flags,int rate,struct rtw_ieee80211_duration * d)19454689Sql147931 rtw_compute_duration1(int len, int use_ack, uint32_t flags, int rate,
19464689Sql147931     struct rtw_ieee80211_duration *d)
19474689Sql147931 {
19484689Sql147931 	int pre, ctsrate;
19494689Sql147931 	uint16_t ack, bitlen, data_dur, remainder;
19504689Sql147931 
19514689Sql147931 	/*
19524689Sql147931 	 * RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK
19534689Sql147931 	 * DATA reserves medium for SIFS | ACK
19544689Sql147931 	 *
19554689Sql147931 	 * XXXMYC: no ACK on multicast/broadcast or control packets
19564689Sql147931 	 */
19574689Sql147931 
19584689Sql147931 	bitlen = len * 8;
19594689Sql147931 
19604689Sql147931 	pre = IEEE80211_DUR_DS_SIFS;
19614689Sql147931 	if ((flags & IEEE80211_F_SHPREAMBLE) != 0)
19624689Sql147931 		pre += IEEE80211_DUR_DS_SHORT_PREAMBLE +
19634689Sql147931 		    IEEE80211_DUR_DS_FAST_PLCPHDR;
19644689Sql147931 	else
19654689Sql147931 		pre += IEEE80211_DUR_DS_LONG_PREAMBLE +
19664689Sql147931 		    IEEE80211_DUR_DS_SLOW_PLCPHDR;
19674689Sql147931 
19684689Sql147931 	d->d_residue = 0;
19694689Sql147931 	data_dur = (bitlen * 2) / rate;
19704689Sql147931 	remainder = (bitlen * 2) % rate;
19714689Sql147931 	if (remainder != 0) {
19724689Sql147931 		if (rate == 22)
19734689Sql147931 			d->d_residue = (rate - remainder) / 16;
19744689Sql147931 		data_dur++;
19754689Sql147931 	}
19764689Sql147931 
19774689Sql147931 	switch (rate) {
19784689Sql147931 	case 2:		/* 1 Mb/s */
19794689Sql147931 	case 4:		/* 2 Mb/s */
19804689Sql147931 		/* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */
19814689Sql147931 		ctsrate = 2;
19824689Sql147931 		break;
19834689Sql147931 	case 11:	/* 5.5 Mb/s */
19844689Sql147931 	case 22:	/* 11  Mb/s */
19854689Sql147931 	case 44:	/* 22  Mb/s */
19864689Sql147931 		/* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */
19874689Sql147931 		ctsrate = 4;
19884689Sql147931 		break;
19894689Sql147931 	default:
19904689Sql147931 		/* TBD */
19914689Sql147931 		return (-1);
19924689Sql147931 	}
19934689Sql147931 
19944689Sql147931 	d->d_plcp_len = data_dur;
19954689Sql147931 
19964689Sql147931 	ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0;
19974689Sql147931 
19984689Sql147931 	d->d_rts_dur =
19994689Sql147931 	    pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate +
20004689Sql147931 	    pre + data_dur +
20014689Sql147931 	    ack;
20024689Sql147931 
20034689Sql147931 	d->d_data_dur = ack;
20044689Sql147931 
20054689Sql147931 	return (0);
20064689Sql147931 }
20074689Sql147931 
20084689Sql147931 /*
20094689Sql147931  * Arguments in:
20104689Sql147931  *
20114689Sql147931  * wh:      802.11 header
20124689Sql147931  *
20134689Sql147931  * paylen:  payload length (no FCS, no WEP header)
20144689Sql147931  *
20154689Sql147931  * rate:    MSDU speed, units 500kb/s
20164689Sql147931  *
20174689Sql147931  * fraglen: fragment length, set to maximum (or higher) for no
20184689Sql147931  *          fragmentation
20194689Sql147931  *
20204689Sql147931  * flags:   IEEE80211_F_PRIVACY (hardware adds WEP),
20214689Sql147931  *          IEEE80211_F_SHPREAMBLE (use short preamble),
20224689Sql147931  *          IEEE80211_F_SHSLOT (use short slot length)
20234689Sql147931  *
20244689Sql147931  * Arguments out:
20254689Sql147931  *
20264689Sql147931  * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
20274689Sql147931  *     of first/only fragment
20284689Sql147931  *
20294689Sql147931  * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
20304689Sql147931  *     of first/only fragment
20314689Sql147931  */
20324689Sql147931 static int
rtw_compute_duration(struct ieee80211_frame * wh,int len,uint32_t flags,int fraglen,int rate,struct rtw_ieee80211_duration * d0,struct rtw_ieee80211_duration * dn,int * npktp)20334689Sql147931 rtw_compute_duration(struct ieee80211_frame *wh, int len,
20344689Sql147931     uint32_t flags, int fraglen, int rate, struct rtw_ieee80211_duration *d0,
20354689Sql147931     struct rtw_ieee80211_duration *dn, int *npktp)
20364689Sql147931 {
20374689Sql147931 	int ack, rc;
20384689Sql147931 	int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen;
20394689Sql147931 
20404689Sql147931 	/* don't think about addr4 here */
20414689Sql147931 	hdrlen = sizeof (struct ieee80211_frame);
20424689Sql147931 
20434689Sql147931 	paylen = len - hdrlen;
20444689Sql147931 
20454689Sql147931 	if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0) {
20464689Sql147931 		overlen = 8 + IEEE80211_CRC_LEN;
20474689Sql147931 		paylen -= 8;
20484689Sql147931 	} else
20494689Sql147931 		overlen = IEEE80211_CRC_LEN;
20504689Sql147931 
20514689Sql147931 	npkt = paylen / fraglen;
20524689Sql147931 	lastlen0 = paylen % fraglen;
20534689Sql147931 
20544689Sql147931 	if (npkt == 0)			/* no fragments */
20554689Sql147931 		lastlen = paylen + overlen;
20564689Sql147931 	else if (lastlen0 != 0) {	/* a short "tail" fragment */
20574689Sql147931 		lastlen = lastlen0 + overlen;
20584689Sql147931 		npkt++;
20594689Sql147931 	} else			/* full-length "tail" fragment */
20604689Sql147931 		lastlen = fraglen + overlen;
20614689Sql147931 
20624689Sql147931 	if (npktp != NULL)
20634689Sql147931 		*npktp = npkt;
20644689Sql147931 
20654689Sql147931 	if (npkt > 1)
20664689Sql147931 		firstlen = fraglen + overlen;
20674689Sql147931 	else
20684689Sql147931 		firstlen = paylen + overlen;
20694689Sql147931 
20704689Sql147931 	ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
20714689Sql147931 	    (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) !=
20724689Sql147931 	    IEEE80211_FC0_TYPE_CTL;
20734689Sql147931 
20744689Sql147931 	rc = rtw_compute_duration1(firstlen + hdrlen,
20754689Sql147931 	    ack, flags, rate, d0);
20764689Sql147931 	if (rc == -1)
20774689Sql147931 		return (rc);
20784689Sql147931 
20794689Sql147931 	if (npkt <= 1) {
20804689Sql147931 		*dn = *d0;
20814689Sql147931 		return (0);
20824689Sql147931 	}
20834689Sql147931 	return (rtw_compute_duration1(lastlen + hdrlen, ack, flags,
20844689Sql147931 	    rate, dn));
20854689Sql147931 }
20864689Sql147931 
20874689Sql147931 static int
rtw_assembly_80211(rtw_softc_t * rsc,struct rtw_txbuf * bf,mblk_t * mp)20884689Sql147931 rtw_assembly_80211(rtw_softc_t *rsc, struct rtw_txbuf *bf,
20894689Sql147931     mblk_t *mp)
20904689Sql147931 {
20914689Sql147931 	ieee80211com_t *ic;
20924689Sql147931 	struct rtw_txdesc *ds;
20934689Sql147931 	struct ieee80211_frame *wh;
20944689Sql147931 	uint8_t *buf;
20954689Sql147931 	uint32_t ctl0 = 0, ctl1 = 0;
20964689Sql147931 	int npkt, rate;
20974689Sql147931 	struct rtw_ieee80211_duration d0, dn;
20984689Sql147931 	int32_t iswep, pktlen, mblen;
20994689Sql147931 	mblk_t *mp0;
21004689Sql147931 
21014689Sql147931 	ic = &rsc->sc_ic;
21024689Sql147931 	ds = bf->txdesc;
21034689Sql147931 	buf = (uint8_t *)bf->bf_dma.mem_va;
21044689Sql147931 	bzero(buf, bf->bf_dma.alength);
21054689Sql147931 	bzero((uint8_t *)ds, sizeof (struct rtw_txdesc));
21064689Sql147931 	wh = (struct ieee80211_frame *)mp->b_rptr;
21074689Sql147931 	iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
21084689Sql147931 
21094689Sql147931 	/* ieee80211_crypto_encap() needs a single mblk */
21104689Sql147931 	mp0 = allocb(bf->bf_dma.alength, BPRI_MED);
21114689Sql147931 	if (mp0 == NULL) {
21124689Sql147931 		cmn_err(CE_WARN, "%s: allocb(mp) error", __func__);
21134689Sql147931 		return (-1);
21144689Sql147931 	}
21154689Sql147931 	for (; mp != NULL; mp = mp->b_cont) {
21166890Sql147931 			mblen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
21174689Sql147931 			bcopy(mp->b_rptr, mp0->b_wptr, mblen);
21184689Sql147931 			mp0->b_wptr += mblen;
21194689Sql147931 	}
21204689Sql147931 
21214689Sql147931 	if (iswep) {
21224689Sql147931 		struct ieee80211_key *k;
21234689Sql147931 
21244689Sql147931 		k = ieee80211_crypto_encap(ic, mp0);
21254689Sql147931 		if (k == NULL) {
21264689Sql147931 			cmn_err(CE_WARN, "%s: ieee80211_crypto_encap() error",
21274689Sql147931 			    __func__);
21284689Sql147931 			freemsg(mp0);
21294689Sql147931 			return (-1);
21304689Sql147931 		}
21314689Sql147931 	}
21324689Sql147931 	pktlen = msgdsize(mp0);
21334689Sql147931 
21344689Sql147931 #if 0
21354689Sql147931 	RTW_DPRINTF(RTW_DEBUG_XMIT, "-----------send------begin--------");
21364689Sql147931 	ieee80211_dump_pkt((uint8_t *)(mp0->b_rptr), pktlen, 0, 0);
21374689Sql147931 	RTW_DPRINTF(RTW_DEBUG_XMIT, "-----------send------end--------");
21384689Sql147931 #endif
21394689Sql147931 	/* RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); */
21404689Sql147931 	if (pktlen > bf->bf_dma.alength) {
21414689Sql147931 		cmn_err(CE_WARN, "%s: overlength packet pktlen = %d\n",
21424689Sql147931 		    __func__, pktlen);
21434689Sql147931 		freemsg(mp0);
21444689Sql147931 		return (-1);
21454689Sql147931 	}
21464689Sql147931 	bcopy(mp0->b_rptr, buf, pktlen);
21474689Sql147931 	RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV);
21484689Sql147931 
21494689Sql147931 	/* setup descriptor */
21504689Sql147931 	ctl0 = RTW_TXCTL0_RTSRATE_1MBPS;
21514689Sql147931 
21524689Sql147931 	if (((ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0) &&
21534689Sql147931 	    (ic->ic_bss->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
21544689Sql147931 		ctl0 |= RTW_TXCTL0_SPLCP;
21554689Sql147931 	}
21564689Sql147931 	/* XXX do real rate control */
21574689Sql147931 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
21584689Sql147931 	    IEEE80211_FC0_TYPE_MGT)
21594689Sql147931 		rate = 2;
21604689Sql147931 	else {
21614689Sql147931 		rate = MAX(2, rtw_get_rate(ic));
21624689Sql147931 	}
21634689Sql147931 	ctl0 = ctl0 |
21644689Sql147931 	    LSHIFT(pktlen, RTW_TXCTL0_TPKTSIZE_MASK);
21654689Sql147931 
21664689Sql147931 	RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: rate = %d", __func__, rate);
21674689Sql147931 
21684689Sql147931 	switch (rate) {
21694689Sql147931 	default:
21704689Sql147931 	case 2:
21714689Sql147931 		ctl0 |= RTW_TXCTL0_RATE_1MBPS;
21724689Sql147931 		break;
21734689Sql147931 	case 4:
21744689Sql147931 		ctl0 |= RTW_TXCTL0_RATE_2MBPS;
21754689Sql147931 		break;
21764689Sql147931 	case 11:
21774689Sql147931 		ctl0 |= RTW_TXCTL0_RATE_5MBPS;
21784689Sql147931 		break;
21794689Sql147931 	case 22:
21804689Sql147931 		ctl0 |= RTW_TXCTL0_RATE_11MBPS;
21814689Sql147931 		break;
21824689Sql147931 	}
21834689Sql147931 
21844689Sql147931 	/* XXX >= ? Compare after fragmentation? */
21854689Sql147931 	if (pktlen > ic->ic_rtsthreshold) {
21864689Sql147931 		ctl0 |= RTW_TXCTL0_RTSEN;
21874689Sql147931 		cmn_err(CE_NOTE, "%s: fragmentation: pktlen = %d",
21884689Sql147931 		    __func__, pktlen);
21894689Sql147931 	}
21904689Sql147931 
21914689Sql147931 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
21924689Sql147931 	    IEEE80211_FC0_TYPE_MGT) {
21934689Sql147931 		ctl0 &= ~(RTW_TXCTL0_SPLCP | RTW_TXCTL0_RTSEN);
21944689Sql147931 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
21954689Sql147931 		    IEEE80211_FC0_SUBTYPE_BEACON)
21964689Sql147931 			ctl0 |= RTW_TXCTL0_BEACON;
21974689Sql147931 	}
21984689Sql147931 
21994689Sql147931 	if (rtw_compute_duration(wh, pktlen,
22004689Sql147931 	    ic->ic_flags, ic->ic_fragthreshold,
22014689Sql147931 	    rate, &d0, &dn, &npkt) == -1) {
22024689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT,
22034689Sql147931 		    "%s: fail compute duration\n", __func__);
22044689Sql147931 		freemsg(mp0);
22054689Sql147931 		return (-1);
22064689Sql147931 	}
22076890Sql147931 	*(uint16_t *)(uintptr_t)wh->i_dur = (d0.d_data_dur);
22084689Sql147931 
22094689Sql147931 	ctl1 = LSHIFT(d0.d_plcp_len, RTW_TXCTL1_LENGTH_MASK) |
22104689Sql147931 	    LSHIFT(d0.d_rts_dur, RTW_TXCTL1_RTSDUR_MASK);
22114689Sql147931 
22124689Sql147931 	if (d0.d_residue)
22134689Sql147931 		ctl1 |= RTW_TXCTL1_LENGEXT;
22144689Sql147931 
22154689Sql147931 	RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: duration=%x, ctl1=%x", __func__,
22166890Sql147931 	    *(uint16_t *)(uintptr_t)wh->i_dur, ctl1);
22174689Sql147931 
22184689Sql147931 	if (bf->bf_dma.alength > RTW_TXLEN_LENGTH_MASK) {
22194689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT,
22204689Sql147931 		    "%s: seg too long\n", __func__);
22214689Sql147931 		freemsg(mp0);
22224689Sql147931 		return (-1);
22234689Sql147931 	}
22244689Sql147931 	ds->td_ctl0 = ctl0;
22254689Sql147931 	ds->td_ctl0 |= RTW_TXCTL0_OWN | RTW_TXCTL0_LS | RTW_TXCTL0_FS;
22264689Sql147931 	ds->td_ctl1 = ctl1;
22274689Sql147931 	ds->td_buf = bf->bf_dma.cookie.dmac_address;
22284689Sql147931 	ds->td_len = pktlen & 0xfff;
22294689Sql147931 	ds->td_next = bf->next_bf_daddr;
22304689Sql147931 
22314689Sql147931 	RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
22324689Sql147931 	    RTW_DESC_OFFSET(hd_txmd, bf->order),
22334689Sql147931 	    sizeof (struct rtw_txdesc),
22344689Sql147931 	    DDI_DMA_SYNC_FORDEV);
22354689Sql147931 
22364689Sql147931 	RTW_DPRINTF(RTW_DEBUG_XMIT,
22374689Sql147931 	    "descriptor: order = %d, phy_addr=%x, ctl0=%x,"
22384689Sql147931 	    " ctl1=%x, buf=%x, len=%x, next=%x", bf->order,
22394689Sql147931 	    bf->bf_daddr, ds->td_ctl0, ds->td_ctl1,
22404689Sql147931 	    ds->td_buf, ds->td_len, ds->td_next);
22414689Sql147931 	rsc->sc_pktxmt64++;
22424689Sql147931 	rsc->sc_bytexmt64 += pktlen;
22434689Sql147931 
22444689Sql147931 	freemsg(mp0);
22454689Sql147931 	return (0);
22464689Sql147931 }
22474689Sql147931 
22484689Sql147931 static int
rtw_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)22494689Sql147931 rtw_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
22504689Sql147931 {
22514689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)ic;
22524689Sql147931 	struct ieee80211_node *in = ic->ic_bss;
22534689Sql147931 	struct rtw_txbuf *bf = NULL;
22544689Sql147931 	int ret, i = RTW_TXPRIMD;
22554689Sql147931 
22564689Sql147931 	mutex_enter(&rsc->sc_txlock);
22574689Sql147931 	mutex_enter(&rsc->sc_txq[i].txbuf_lock);
22584689Sql147931 	bf = list_head(&rsc->sc_txq[i].tx_free_list);
22594689Sql147931 
22604689Sql147931 	if ((bf == NULL) || (rsc->sc_txq[i].tx_nfree <= 4)) {
22614689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: no tx buf\n", __func__);
22624689Sql147931 		rsc->sc_noxmtbuf++;
22634689Sql147931 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
22644689Sql147931 		    IEEE80211_FC0_TYPE_DATA) {
22654689Sql147931 			RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: need reschedule\n",
22664689Sql147931 			    __func__);
22674689Sql147931 			rsc->sc_need_reschedule = 1;
22684689Sql147931 		} else {
22694689Sql147931 			freemsg(mp);
22704689Sql147931 		}
22714689Sql147931 		mutex_exit(&rsc->sc_txq[i].txbuf_lock);
22724689Sql147931 		mutex_exit(&rsc->sc_txlock);
22734689Sql147931 		return (1);
22744689Sql147931 	}
22754689Sql147931 	list_remove(&rsc->sc_txq[i].tx_free_list, bf);
22764689Sql147931 	rsc->sc_txq[i].tx_nfree--;
22774689Sql147931 
22784689Sql147931 	/* assemble 802.11 frame here */
22794689Sql147931 	ret = rtw_assembly_80211(rsc, bf, mp);
22804689Sql147931 	if (ret != 0) {
22814689Sql147931 		cmn_err(CE_WARN, "%s assembly frame error\n", __func__);
22824689Sql147931 		mutex_exit(&rsc->sc_txq[i].txbuf_lock);
22834689Sql147931 		mutex_exit(&rsc->sc_txlock);
22844689Sql147931 		if ((type & IEEE80211_FC0_TYPE_MASK) !=
22854689Sql147931 		    IEEE80211_FC0_TYPE_DATA) {
22864689Sql147931 			freemsg(mp);
22874689Sql147931 		}
22884689Sql147931 		return (1);
22894689Sql147931 	}
22904689Sql147931 	list_insert_tail(&rsc->sc_txq[i].tx_dirty_list, bf);
22914689Sql147931 	bf->bf_in = in;
22924689Sql147931 	rtw_dma_start(&rsc->sc_regs, i);
22934689Sql147931 
22944689Sql147931 	mutex_exit(&rsc->sc_txq[i].txbuf_lock);
22954689Sql147931 	mutex_exit(&rsc->sc_txlock);
22964689Sql147931 
22974689Sql147931 	freemsg(mp);
22984689Sql147931 	return (0);
22994689Sql147931 }
23004689Sql147931 
23014689Sql147931 static mblk_t *
rtw_m_tx(void * arg,mblk_t * mp)23024689Sql147931 rtw_m_tx(void *arg, mblk_t *mp)
23034689Sql147931 {
23044689Sql147931 	rtw_softc_t *rsc = arg;
23054689Sql147931 	ieee80211com_t *ic = (ieee80211com_t *)rsc;
23064689Sql147931 	mblk_t *next;
23074689Sql147931 
23084689Sql147931 	if (ic->ic_state != IEEE80211_S_RUN) {
23094689Sql147931 		freemsgchain(mp);
23104689Sql147931 		return (NULL);
23114689Sql147931 	}
23124689Sql147931 
23134689Sql147931 	while (mp != NULL) {
23144689Sql147931 		next = mp->b_next;
23154689Sql147931 		mp->b_next = NULL;
23164689Sql147931 
23174689Sql147931 		if (rtw_send(ic, mp, IEEE80211_FC0_TYPE_DATA)) {
23184689Sql147931 			mp->b_next = next;
23194689Sql147931 			break;
23204689Sql147931 		}
23214689Sql147931 		mp = next;
23224689Sql147931 	}
23234689Sql147931 
23244689Sql147931 	return (mp);
23254689Sql147931 
23264689Sql147931 }
23274689Sql147931 
23284689Sql147931 static void
rtw_next_scan(void * arg)23294689Sql147931 rtw_next_scan(void *arg)
23304689Sql147931 {
23314689Sql147931 	ieee80211com_t *ic = arg;
23324689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
23334689Sql147931 
23344689Sql147931 	rsc->sc_scan_id = 0;
23354689Sql147931 	if (ic->ic_state == IEEE80211_S_SCAN) {
23364689Sql147931 		RTW_DPRINTF(RTW_DEBUG_TUNE, "rtw_next_scan\n");
23374689Sql147931 		(void) ieee80211_next_scan(ic);
23384689Sql147931 	}
23394689Sql147931 
23404689Sql147931 }
23414689Sql147931 
23424689Sql147931 static void
rtw_join_bss(rtw_softc_t * rsc,uint8_t * bssid,uint16_t intval0)23434689Sql147931 rtw_join_bss(rtw_softc_t *rsc, uint8_t *bssid, uint16_t intval0)
23444689Sql147931 {
23454689Sql147931 	uint16_t bcnitv, intval;
23464689Sql147931 	int i;
23474689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
23484689Sql147931 
23494689Sql147931 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
23504689Sql147931 		RTW_WRITE8(regs, RTW_BSSID + i, bssid[i]);
23514689Sql147931 
23524689Sql147931 	RTW_SYNC(regs, RTW_BSSID16, RTW_BSSID32);
23534689Sql147931 	rtw_set_access(regs, RTW_ACCESS_CONFIG);
23544689Sql147931 
23554689Sql147931 	RTW_WRITE8(regs, RTW_MSR, 0x8);	/* sta mode link ok */
23564689Sql147931 	intval = MIN(intval0, PRESHIFT(RTW_BCNITV_BCNITV_MASK));
23574689Sql147931 
23584689Sql147931 	bcnitv = RTW_READ16(regs, RTW_BCNITV) & ~RTW_BCNITV_BCNITV_MASK;
23594689Sql147931 	bcnitv |= LSHIFT(intval, RTW_BCNITV_BCNITV_MASK);
23604689Sql147931 	RTW_WRITE16(regs, RTW_BCNITV, bcnitv);
23614689Sql147931 	RTW_WRITE16(regs, RTW_ATIMWND, LSHIFT(1, RTW_ATIMWND_ATIMWND));
23624689Sql147931 	RTW_WRITE16(regs, RTW_ATIMTRITV, LSHIFT(2, RTW_ATIMTRITV_ATIMTRITV));
23634689Sql147931 
23644689Sql147931 	rtw_set_access(regs, RTW_ACCESS_NONE);
23654689Sql147931 
23664689Sql147931 	/* TBD WEP */
23674689Sql147931 	/* RTW_WRITE8(regs, RTW_SCR, 0); */
23684689Sql147931 
23694689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 1);
23704689Sql147931 }
23714689Sql147931 
23724689Sql147931 /*
23734689Sql147931  * Set the starting transmit rate for a node.
23744689Sql147931  */
23754689Sql147931 static void
rtw_rate_ctl_start(rtw_softc_t * rsc,struct ieee80211_node * in)23764689Sql147931 rtw_rate_ctl_start(rtw_softc_t *rsc, struct ieee80211_node *in)
23774689Sql147931 {
23784689Sql147931 	ieee80211com_t *ic = (ieee80211com_t *)rsc;
23794689Sql147931 	int32_t srate;
23804689Sql147931 
23814689Sql147931 	if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
23824689Sql147931 		/*
23834689Sql147931 		 * No fixed rate is requested. For 11b start with
23844689Sql147931 		 * the highest negotiated rate; otherwise, for 11g
23854689Sql147931 		 * and 11a, we start "in the middle" at 24Mb or 36Mb.
23864689Sql147931 		 */
23874689Sql147931 		srate = in->in_rates.ir_nrates - 1;
23884689Sql147931 		if (ic->ic_curmode != IEEE80211_MODE_11B) {
23894689Sql147931 			/*
23904689Sql147931 			 * Scan the negotiated rate set to find the
23914689Sql147931 			 * closest rate.
23924689Sql147931 			 */
23934689Sql147931 			/* NB: the rate set is assumed sorted */
23944689Sql147931 			for (; srate >= 0 && IEEE80211_RATE(srate) > 72;
23954689Sql147931 			    srate--)
23964689Sql147931 				;
23974689Sql147931 		}
23984689Sql147931 	} else {
23994689Sql147931 		/*
24004689Sql147931 		 * A fixed rate is to be used;  We know the rate is
24014689Sql147931 		 * there because the rate set is checked when the
24024689Sql147931 		 * station associates.
24034689Sql147931 		 */
24044689Sql147931 		/* NB: the rate set is assumed sorted */
24054689Sql147931 		srate = in->in_rates.ir_nrates - 1;
24064689Sql147931 		for (; srate >= 0 && IEEE80211_RATE(srate) != ic->ic_fixed_rate;
24074689Sql147931 		    srate--)
24084689Sql147931 			;
24094689Sql147931 	}
24104689Sql147931 	in->in_txrate = srate;
24114689Sql147931 }
24124689Sql147931 
24134689Sql147931 
24144689Sql147931 /*
24154689Sql147931  * Reset the rate control state for each 802.11 state transition.
24164689Sql147931  */
24174689Sql147931 static void
rtw_rate_ctl_reset(rtw_softc_t * rsc,enum ieee80211_state state)24184689Sql147931 rtw_rate_ctl_reset(rtw_softc_t *rsc, enum ieee80211_state state)
24194689Sql147931 {
24204689Sql147931 	ieee80211com_t *ic = &rsc->sc_ic;
24214689Sql147931 	ieee80211_node_t *in;
24224689Sql147931 
24234689Sql147931 	if (ic->ic_opmode == IEEE80211_M_STA) {
24244689Sql147931 		/*
24254689Sql147931 		 * Reset local xmit state; this is really only
24264689Sql147931 		 * meaningful when operating in station mode.
24274689Sql147931 		 */
24284689Sql147931 		in = (struct ieee80211_node *)ic->ic_bss;
24294689Sql147931 
24304689Sql147931 		if (state == IEEE80211_S_RUN) {
24314689Sql147931 			rtw_rate_ctl_start(rsc, in);
24324689Sql147931 		} else {
24334689Sql147931 			in->in_txrate = 0;
24344689Sql147931 		}
24354689Sql147931 	}
24364689Sql147931 }
24374689Sql147931 
24384689Sql147931 /*
24394689Sql147931  * Examine and potentially adjust the transmit rate.
24404689Sql147931  */
24414689Sql147931 static void
rtw_rate_ctl(void * arg)24424689Sql147931 rtw_rate_ctl(void *arg)
24434689Sql147931 {
24444689Sql147931 	ieee80211com_t	*ic = (ieee80211com_t *)arg;
24454689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)ic;
24464689Sql147931 	struct ieee80211_node *in = ic->ic_bss;
24474689Sql147931 	struct ieee80211_rateset *rs = &in->in_rates;
244810448SMikore.Li@Sun.COM 	int32_t mod = 1, nrate, enough;
24494689Sql147931 
24504689Sql147931 	mutex_enter(&rsc->sc_genlock);
245110448SMikore.Li@Sun.COM 	enough = (rsc->sc_tx_ok + rsc->sc_tx_err) >= 600? 1 : 0;
245210448SMikore.Li@Sun.COM 
245310448SMikore.Li@Sun.COM 	/* err ratio is high -> down */
24544689Sql147931 	if (enough && rsc->sc_tx_ok < rsc->sc_tx_err)
24554689Sql147931 		mod = -1;
24564689Sql147931 
24574689Sql147931 	nrate = in->in_txrate;
24584689Sql147931 	switch (mod) {
24594689Sql147931 	case -1:
24604689Sql147931 		if (nrate > 0) {
24614689Sql147931 			nrate--;
24624689Sql147931 		}
24634689Sql147931 		break;
24644689Sql147931 	case 1:
24654689Sql147931 		if (nrate + 1 < rs->ir_nrates) {
24664689Sql147931 			nrate++;
24674689Sql147931 		}
24684689Sql147931 		break;
24694689Sql147931 	}
24704689Sql147931 
247110448SMikore.Li@Sun.COM 	if (nrate != in->in_txrate)
24724689Sql147931 		in->in_txrate = nrate;
247310448SMikore.Li@Sun.COM 	rsc->sc_tx_ok = rsc->sc_tx_err = rsc->sc_tx_retr = 0;
24744689Sql147931 	mutex_exit(&rsc->sc_genlock);
24754689Sql147931 	if (ic->ic_state == IEEE80211_S_RUN)
24764689Sql147931 		rsc->sc_ratectl_id = timeout(rtw_rate_ctl, ic,
24774689Sql147931 		    drv_usectohz(1000000));
24784689Sql147931 }
24794689Sql147931 
24804689Sql147931 static int32_t
rtw_new_state(ieee80211com_t * ic,enum ieee80211_state nstate,int arg)24814689Sql147931 rtw_new_state(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
24824689Sql147931 {
24834689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)ic;
24844689Sql147931 	int error;
24854689Sql147931 	enum ieee80211_state ostate;
24864689Sql147931 
24874689Sql147931 	ostate = ic->ic_state;
24884689Sql147931 
24894689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH,
24904689Sql147931 	    "rtw_new_state: ostate:0x%x, nstate:0x%x, opmode:0x%x\n",
24914689Sql147931 	    ostate, nstate, ic->ic_opmode);
24924689Sql147931 
24934689Sql147931 
24944689Sql147931 	mutex_enter(&rsc->sc_genlock);
24954689Sql147931 	if (rsc->sc_scan_id != 0) {
24964689Sql147931 		(void) untimeout(rsc->sc_scan_id);
24974689Sql147931 		rsc->sc_scan_id = 0;
24984689Sql147931 	}
24994689Sql147931 	if (rsc->sc_ratectl_id != 0) {
25004689Sql147931 		(void) untimeout(rsc->sc_ratectl_id);
25014689Sql147931 		rsc->sc_ratectl_id = 0;
25024689Sql147931 	}
25034689Sql147931 	rtw_rate_ctl_reset(rsc, nstate);
25044689Sql147931 	if (ostate == IEEE80211_S_INIT && nstate != IEEE80211_S_INIT)
25054689Sql147931 		(void) rtw_pwrstate(rsc, RTW_ON);
250610448SMikore.Li@Sun.COM 	if (nstate != IEEE80211_S_INIT) {
250710448SMikore.Li@Sun.COM 		if ((error = rtw_tune(rsc)) != 0) {
250810448SMikore.Li@Sun.COM 			mutex_exit(&rsc->sc_genlock);
250910448SMikore.Li@Sun.COM 			return (error);
251010448SMikore.Li@Sun.COM 		}
25114689Sql147931 	}
25124689Sql147931 	switch (nstate) {
25134689Sql147931 	case IEEE80211_S_INIT:
25144689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_INIT\n");
25154689Sql147931 		break;
25164689Sql147931 	case IEEE80211_S_SCAN:
25174689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_SCAN\n");
25184689Sql147931 		rsc->sc_scan_id = timeout(rtw_next_scan, ic,
25194689Sql147931 		    drv_usectohz(200000));
25204689Sql147931 		rtw_set_nettype(rsc, IEEE80211_M_MONITOR);
25214689Sql147931 		break;
25224689Sql147931 	case IEEE80211_S_RUN:
25234689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_RUN\n");
25244689Sql147931 		switch (ic->ic_opmode) {
25254689Sql147931 		case IEEE80211_M_HOSTAP:
25264689Sql147931 		case IEEE80211_M_IBSS:
25274689Sql147931 			rtw_set_nettype(rsc, IEEE80211_M_MONITOR);
25284689Sql147931 			/* TBD */
25294689Sql147931 			/*FALLTHROUGH*/
25304689Sql147931 		case IEEE80211_M_AHDEMO:
25314689Sql147931 		case IEEE80211_M_STA:
25324689Sql147931 			RTW_DPRINTF(RTW_DEBUG_ATTACH,
25334689Sql147931 			    "rtw_new_state: sta\n");
25344689Sql147931 			rtw_join_bss(rsc, ic->ic_bss->in_bssid, 0);
25354689Sql147931 			rsc->sc_ratectl_id = timeout(rtw_rate_ctl, ic,
25364689Sql147931 			    drv_usectohz(1000000));
25374689Sql147931 			break;
25384689Sql147931 		case IEEE80211_M_MONITOR:
25394689Sql147931 			break;
25404689Sql147931 		}
25414689Sql147931 		rtw_set_nettype(rsc, ic->ic_opmode);
25424689Sql147931 		break;
25434689Sql147931 	case IEEE80211_S_ASSOC:
25444689Sql147931 	case IEEE80211_S_AUTH:
25454689Sql147931 		break;
25464689Sql147931 	}
25474689Sql147931 
25484689Sql147931 	mutex_exit(&rsc->sc_genlock);
25494689Sql147931 	/*
25504689Sql147931 	 * Invoke the parent method to complete the work.
25514689Sql147931 	 */
25524689Sql147931 	error = rsc->sc_newstate(ic, nstate, arg);
25534689Sql147931 
25544689Sql147931 	return (error);
25554689Sql147931 }
25564689Sql147931 
25574689Sql147931 static void
rtw_intr_rx(rtw_softc_t * rsc)25584689Sql147931 rtw_intr_rx(rtw_softc_t *rsc)
25594689Sql147931 {
25604689Sql147931 #define	IS_BEACON(__fc0)						\
25614689Sql147931 	((__fc0 & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==\
25624689Sql147931 	(IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON))
25634689Sql147931 	/*
25644689Sql147931 	 * ratetbl[4] = {2, 4, 11, 22};
25654689Sql147931 	 */
25664689Sql147931 	struct rtw_rxbuf *bf;
25674689Sql147931 	struct rtw_rxdesc *ds;
25684689Sql147931 	int hwrate, len, rssi;
25694689Sql147931 	uint32_t hstat, hrssi, htsftl;
25704689Sql147931 	int is_last, next, n = 0, i;
25714689Sql147931 	struct ieee80211_frame *wh;
25724689Sql147931 	ieee80211com_t *ic = (ieee80211com_t *)rsc;
25734689Sql147931 	mblk_t *mp;
25744689Sql147931 
25754689Sql147931 	RTW_DPRINTF(RTW_DEBUG_RECV, "%s rtw_intr_rx: enter ic_state=%x\n",
25764689Sql147931 	    __func__, rsc->sc_ic.ic_state);
25774689Sql147931 	mutex_enter(&rsc->rxbuf_lock);
25784689Sql147931 	next = rsc->rx_next;
25794689Sql147931 	mutex_exit(&rsc->rxbuf_lock);
25804689Sql147931 	for (i = 0; i < RTW_RXQLEN; i++) {
25814689Sql147931 		RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
25824689Sql147931 		    RTW_DESC_OFFSET(hd_rx, next),
25834689Sql147931 		    sizeof (struct rtw_rxdesc),
25844689Sql147931 		    DDI_DMA_SYNC_FORKERNEL);
25854689Sql147931 		n++;
25864689Sql147931 		bf = rsc->rxbuf_h + next;
25874689Sql147931 		ds = bf->rxdesc;
25884689Sql147931 		hstat = (ds->rd_stat);
25894689Sql147931 		hrssi = ds->rd_rssi;
25904689Sql147931 		htsftl = ds->rd_tsftl;
25914689Sql147931 		/* htsfth = ds->rd_tsfth; */
25924689Sql147931 		RTW_DPRINTF(RTW_DEBUG_RECV, "%s: stat=%x\n", __func__, hstat);
25934689Sql147931 		/* still belongs to NIC */
25944689Sql147931 		if ((hstat & RTW_RXSTAT_OWN) != 0) {
25954689Sql147931 			if (n > 1) {
25964689Sql147931 				RTW_DPRINTF(RTW_DEBUG_RECV,
25974689Sql147931 				    "%s: n > 1\n", __func__);
25984689Sql147931 				break;
25994689Sql147931 			}
26004689Sql147931 			RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
26014689Sql147931 			    RTW_DESC_OFFSET(hd_rx, 0),
26024689Sql147931 			    sizeof (struct rtw_rxdesc),
26034689Sql147931 			    DDI_DMA_SYNC_FORCPU);
26044689Sql147931 			bf = rsc->rxbuf_h;
26054689Sql147931 			ds = bf->rxdesc;
26064689Sql147931 			hstat = (ds->rd_stat);
26074689Sql147931 			if ((hstat & RTW_RXSTAT_OWN) != 0)
26084689Sql147931 				break;
26094689Sql147931 			next = 0 /* RTW_RXQLEN - 1 */;
26104689Sql147931 			continue;
26114689Sql147931 		}
26124689Sql147931 
26134689Sql147931 		rsc->sc_pktrcv64++;
26144689Sql147931 		if ((hstat & RTW_RXSTAT_IOERROR) != 0) {
26154689Sql147931 			RTW_DPRINTF(RTW_DEBUG_RECV,
26164689Sql147931 			    "rtw: DMA error/FIFO overflow %08x, "
26174689Sql147931 			    "rx descriptor %d\n",
26184689Sql147931 			    hstat & RTW_RXSTAT_IOERROR, next);
26194689Sql147931 			goto next;
26204689Sql147931 		}
26214689Sql147931 
26224689Sql147931 		len = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_LENGTH_MASK);
26234689Sql147931 		rsc->sc_bytercv64 += len;
26244689Sql147931 
26254689Sql147931 		/* CRC is included with the packet; trim it off. */
26264689Sql147931 		/* len -= IEEE80211_CRC_LEN; */
26274689Sql147931 
26284689Sql147931 		hwrate = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_RATE_MASK);
26294689Sql147931 		if (hwrate >= 4) {
26304689Sql147931 			goto next;
26314689Sql147931 		}
26324689Sql147931 
26334689Sql147931 		if ((hstat & RTW_RXSTAT_RES) != 0 &&
26344689Sql147931 		    rsc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) {
26354689Sql147931 			goto next;
26364689Sql147931 		}
26374689Sql147931 
26384689Sql147931 		/* if bad flags, skip descriptor */
26394689Sql147931 		if ((hstat & RTW_RXSTAT_ONESEG) != RTW_RXSTAT_ONESEG) {
26404689Sql147931 			RTW_DPRINTF(RTW_DEBUG_RECV,
26414689Sql147931 			    "rtw too many rx segments\n");
26424689Sql147931 			goto next;
26434689Sql147931 		}
26444689Sql147931 
26454689Sql147931 		if (rsc->sc_rfchipid == RTW_RFCHIPID_PHILIPS)
26464689Sql147931 			rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_RSSI);
26474689Sql147931 		else {
26484689Sql147931 			rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_IMR_RSSI);
26494689Sql147931 			/*
26504689Sql147931 			 * TBD find out each front-end's LNA gain in the
26514689Sql147931 			 * front-end's units
26524689Sql147931 			 */
26534689Sql147931 			if ((hrssi & RTW_RXRSSI_IMR_LNA) == 0)
26544689Sql147931 				rssi |= 0x80;
26554689Sql147931 		}
26564689Sql147931 		/* sq = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_SQ); */
26574689Sql147931 
26584689Sql147931 
26594689Sql147931 		/* deal with the frame itself here */
26604689Sql147931 		mp = allocb(rsc->sc_dmabuf_size, BPRI_MED);
26614689Sql147931 		if (mp == NULL) {
26624689Sql147931 			cmn_err(CE_WARN, "rtw: alloc mblk error");
26634689Sql147931 			rsc->sc_norcvbuf++;
26644689Sql147931 			return;
26654689Sql147931 		}
26664689Sql147931 		len -= IEEE80211_CRC_LEN;
26674689Sql147931 		RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORKERNEL);
26684689Sql147931 		bcopy(bf->bf_dma.mem_va, mp->b_rptr, len);
26694689Sql147931 		mp->b_wptr += len;
26704689Sql147931 		wh = (struct ieee80211_frame *)mp->b_rptr;
26714689Sql147931 		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
26724689Sql147931 		    IEEE80211_FC0_TYPE_CTL) {
26734689Sql147931 			cmn_err(CE_WARN, "TYPE CTL !!\n");
26744689Sql147931 			freemsg(mp);
26754689Sql147931 			goto next;
26764689Sql147931 		}
26774689Sql147931 		(void) ieee80211_input(ic, mp, ic->ic_bss, rssi, htsftl);
26784689Sql147931 next:
26794689Sql147931 		if (next == 63)
26804689Sql147931 			is_last = 1;
26814689Sql147931 		else
26824689Sql147931 			is_last = 0;
26834689Sql147931 		rtw_rxdesc_init(rsc, bf, next, is_last);
26844689Sql147931 
26854689Sql147931 		next = (next + 1)%RTW_RXQLEN;
26864689Sql147931 		RTW_DPRINTF(RTW_DEBUG_RECV, "%s: next = %d\n", __func__, next);
26874689Sql147931 	}
26884689Sql147931 	mutex_enter(&rsc->rxbuf_lock);
26894689Sql147931 	rsc->rx_next = next;
26904689Sql147931 	mutex_exit(&rsc->rxbuf_lock);
26914689Sql147931 }
26924689Sql147931 
26934689Sql147931 static void
rtw_ring_recycling(rtw_softc_t * rsc,uint16_t isr,uint32_t pri)26944689Sql147931 rtw_ring_recycling(rtw_softc_t *rsc, uint16_t isr, uint32_t pri)
26954689Sql147931 {
26964689Sql147931 	struct rtw_txbuf *bf;
26974689Sql147931 	struct rtw_txdesc *ds;
26984689Sql147931 	uint32_t hstat;
26994689Sql147931 	uint32_t  head = 0;
27004689Sql147931 	uint32_t  cnt = 0, idx = 0;
27014689Sql147931 
27024689Sql147931 	mutex_enter(&rsc->sc_txq[pri].txbuf_lock);
27034689Sql147931 	head = RTW_READ(&rsc->sc_regs, RTW_TNPDA);
27044689Sql147931 	if (head == rsc->hw_go) {
27054689Sql147931 		mutex_exit(&rsc->sc_txq[pri].txbuf_lock);
27064689Sql147931 		return;
27074689Sql147931 	}
27084689Sql147931 	RTW_DPRINTF(RTW_DEBUG_XMIT, "rtw_ring_recycling: enter ic_state=%x\n",
27094689Sql147931 	    rsc->sc_ic.ic_state);
27104689Sql147931 
27114689Sql147931 	bf = list_head(&rsc->sc_txq[pri].tx_dirty_list);
27124689Sql147931 	if (bf == NULL) {
27134689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT,
27144689Sql147931 		    "rtw_ring_recycling: dirty bf[%d] NULL\n", pri);
27154689Sql147931 		mutex_exit(&rsc->sc_txq[pri].txbuf_lock);
27164689Sql147931 		return;
27174689Sql147931 	}
27184689Sql147931 
27194689Sql147931 	while ((bf != NULL) && (rsc->hw_go != head)) {
27204689Sql147931 		cnt++;
27214689Sql147931 		idx = (rsc->hw_go - rsc->hw_start) / sizeof (struct rtw_txdesc);
27224689Sql147931 		if (idx == 63)
27234689Sql147931 			rsc->hw_go = rsc->hw_start;
27244689Sql147931 		else
27254689Sql147931 			rsc->hw_go += sizeof (struct rtw_txdesc);
27264689Sql147931 		RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
27274689Sql147931 		    RTW_DESC_OFFSET(hd_txmd, idx),
27284689Sql147931 		    sizeof (struct rtw_txdesc),
27294689Sql147931 		    DDI_DMA_SYNC_FORCPU);
27304689Sql147931 
27314689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT, "Head = 0x%x\n", head);
27324689Sql147931 		ds = bf->txdesc;
27334689Sql147931 		hstat = (ds->td_stat);
27344689Sql147931 		ds->td_len = ds->td_len & 0xfff;
27354689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT,
27364689Sql147931 		    "%s rtw_ring_recycling: stat=%x, pri=%x\n",
27374689Sql147931 		    __func__, hstat, pri);
27384689Sql147931 		if (hstat & RTW_TXSTAT_TOK)
27394689Sql147931 			rsc->sc_tx_ok++;
27404689Sql147931 		else {
27414689Sql147931 			RTW_DPRINTF(RTW_DEBUG_XMIT,
27424689Sql147931 			    "TX err @%d, o %d, retry[%d], isr[0x%x], cnt %d\n",
27434689Sql147931 			    idx, (hstat & RTW_TXSTAT_OWN)?1:0,
27444689Sql147931 			    (hstat & RTW_TXSTAT_DRC_MASK), isr, cnt);
27454689Sql147931 			if ((hstat & RTW_TXSTAT_DRC_MASK) <= 4) {
27464689Sql147931 				rsc->sc_tx_ok++;
27474689Sql147931 			} else {
27484689Sql147931 				rsc->sc_tx_err++;
27494689Sql147931 			}
27504689Sql147931 		}
27514689Sql147931 		rsc->sc_tx_retr +=
27524689Sql147931 		    (hstat & RTW_TXSTAT_DRC_MASK);
27534689Sql147931 		rsc->sc_xmtretry +=
27544689Sql147931 		    (hstat & RTW_TXSTAT_DRC_MASK);
27554689Sql147931 		list_remove(&rsc->sc_txq[pri].tx_dirty_list, bf);
27564689Sql147931 		list_insert_tail(&rsc->sc_txq[pri].tx_free_list,
27574689Sql147931 		    bf);
27584689Sql147931 		(rsc->sc_txq[pri].tx_nfree)++;
27594689Sql147931 		if (rsc->sc_need_reschedule == 1) {
27604689Sql147931 			mac_tx_update(rsc->sc_ic.ic_mach);
27614689Sql147931 			rsc->sc_need_reschedule = 0;
27624689Sql147931 		}
27634689Sql147931 		RTW_DPRINTF(RTW_DEBUG_XMIT,
27644689Sql147931 		    "rtw_ring_recycling: nfree[%d]=%d\n",
27654689Sql147931 		    pri, rsc->sc_txq[pri].tx_nfree);
27664689Sql147931 		bzero((uint8_t *)ds, sizeof (struct rtw_txdesc));
27674689Sql147931 		RTW_DMA_SYNC_DESC(rsc->sc_desc_dma,
27684689Sql147931 		    RTW_DESC_OFFSET(hd_txmd, idx),
27694689Sql147931 		    sizeof (struct rtw_txdesc),
27704689Sql147931 		    DDI_DMA_SYNC_FORDEV);
27714689Sql147931 		bf = list_head(&rsc->sc_txq[pri].tx_dirty_list);
27724689Sql147931 	}
27734689Sql147931 	mutex_exit(&rsc->sc_txq[pri].txbuf_lock);
27744689Sql147931 }
27754689Sql147931 
27764689Sql147931 static void
rtw_intr_timeout(rtw_softc_t * rsc)27774689Sql147931 rtw_intr_timeout(rtw_softc_t *rsc)
27784689Sql147931 {
27794689Sql147931 	rtw_resume_ticks(rsc);
27804689Sql147931 }
27814689Sql147931 
27824689Sql147931 static uint_t
rtw_intr(caddr_t arg)27834689Sql147931 rtw_intr(caddr_t arg)
27844689Sql147931 {
27856890Sql147931 	/* LINTED E_BAD_PTR_CAST_ALIGN */
27864689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
27874689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
27884689Sql147931 	uint16_t isr = 0;
27894689Sql147931 
27904689Sql147931 	mutex_enter(&rsc->sc_genlock);
27914689Sql147931 	isr = RTW_READ16(regs, RTW_ISR);
27924689Sql147931 	RTW_WRITE16(regs, RTW_ISR, isr);
27934689Sql147931 
27944689Sql147931 	if (isr == 0) {
27954689Sql147931 		mutex_exit(&rsc->sc_genlock);
27964689Sql147931 		return (DDI_INTR_UNCLAIMED);
27974689Sql147931 	}
27984689Sql147931 
27994689Sql147931 #ifdef DEBUG
28004689Sql147931 #define	PRINTINTR(flag) { \
28014689Sql147931 	if ((isr & flag) != 0) { \
28024689Sql147931 		RTW_DPRINTF(RTW_DEBUG_INTR, "|" #flag); \
28034689Sql147931 	} \
28044689Sql147931 }
28054689Sql147931 
28064689Sql147931 	if ((rtw_dbg_flags & RTW_DEBUG_INTR) != 0 && isr != 0) {
28074689Sql147931 
28084689Sql147931 		RTW_DPRINTF(RTW_DEBUG_INTR, "rtw: reg[ISR] = %x", isr);
28094689Sql147931 
28104689Sql147931 		PRINTINTR(RTW_INTR_TXFOVW);
28114689Sql147931 		PRINTINTR(RTW_INTR_TIMEOUT);
28124689Sql147931 		PRINTINTR(RTW_INTR_BCNINT);
28134689Sql147931 		PRINTINTR(RTW_INTR_ATIMINT);
28144689Sql147931 		PRINTINTR(RTW_INTR_TBDER);
28154689Sql147931 		PRINTINTR(RTW_INTR_TBDOK);
28164689Sql147931 		PRINTINTR(RTW_INTR_THPDER);
28174689Sql147931 		PRINTINTR(RTW_INTR_THPDOK);
28184689Sql147931 		PRINTINTR(RTW_INTR_TNPDER);
28194689Sql147931 		PRINTINTR(RTW_INTR_TNPDOK);
28204689Sql147931 		PRINTINTR(RTW_INTR_RXFOVW);
28214689Sql147931 		PRINTINTR(RTW_INTR_RDU);
28224689Sql147931 		PRINTINTR(RTW_INTR_TLPDER);
28234689Sql147931 		PRINTINTR(RTW_INTR_TLPDOK);
28244689Sql147931 		PRINTINTR(RTW_INTR_RER);
28254689Sql147931 		PRINTINTR(RTW_INTR_ROK);
28264689Sql147931 	}
28274689Sql147931 #undef PRINTINTR
28284689Sql147931 #endif /* DEBUG */
28294689Sql147931 
28304689Sql147931 	rsc->sc_intr++;
28314689Sql147931 
28324689Sql147931 	if ((isr & RTW_INTR_RX) != 0) {
28334689Sql147931 		mutex_exit(&rsc->sc_genlock);
28344689Sql147931 		rtw_intr_rx(rsc);
28354689Sql147931 		mutex_enter(&rsc->sc_genlock);
28364689Sql147931 	}
28374689Sql147931 	if ((isr & RTW_INTR_TIMEOUT) != 0)
28384689Sql147931 		rtw_intr_timeout(rsc);
28394689Sql147931 
28404689Sql147931 	if ((isr & RTW_INTR_TX) != 0)
28414689Sql147931 		rtw_ring_recycling(rsc, isr, 1);
28424689Sql147931 	mutex_exit(&rsc->sc_genlock);
28434689Sql147931 	return (DDI_INTR_CLAIMED);
28444689Sql147931 }
28454689Sql147931 
28464689Sql147931 static void
rtw_stop(void * arg)284710448SMikore.Li@Sun.COM rtw_stop(void *arg)
28484689Sql147931 {
28494689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
28504689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
28514689Sql147931 
28524689Sql147931 	mutex_enter(&rsc->sc_genlock);
28534689Sql147931 	rtw_disable_interrupts(regs);
28544689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
28554689Sql147931 	RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
285610448SMikore.Li@Sun.COM 	rsc->sc_invalid = 1;
28574689Sql147931 	mutex_exit(&rsc->sc_genlock);
285810448SMikore.Li@Sun.COM }
285910448SMikore.Li@Sun.COM 
286010448SMikore.Li@Sun.COM static void
rtw_m_stop(void * arg)286110448SMikore.Li@Sun.COM rtw_m_stop(void *arg)
286210448SMikore.Li@Sun.COM {
286310448SMikore.Li@Sun.COM 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
286410448SMikore.Li@Sun.COM 
286510448SMikore.Li@Sun.COM 	(void) ieee80211_new_state(&rsc->sc_ic, IEEE80211_S_INIT, -1);
286610448SMikore.Li@Sun.COM 	rtw_stop(rsc);
28674689Sql147931 }
28684689Sql147931 
28698237SMikore.Li@Sun.COM /*
28708237SMikore.Li@Sun.COM  * quiesce(9E) entry point.
28718237SMikore.Li@Sun.COM  *
28728237SMikore.Li@Sun.COM  * This function is called when the system is single-threaded at high
28738237SMikore.Li@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
28748237SMikore.Li@Sun.COM  * blocked.
28758237SMikore.Li@Sun.COM  *
28768237SMikore.Li@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
28778237SMikore.Li@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
28788237SMikore.Li@Sun.COM  */
28798237SMikore.Li@Sun.COM int
rtw_quiesce(dev_info_t * dip)28808237SMikore.Li@Sun.COM rtw_quiesce(dev_info_t *dip)
28818237SMikore.Li@Sun.COM {
28828237SMikore.Li@Sun.COM 	rtw_softc_t  *rsc = NULL;
28838237SMikore.Li@Sun.COM 	struct rtw_regs *regs;
28848237SMikore.Li@Sun.COM 
28858237SMikore.Li@Sun.COM 	rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(dip));
28868237SMikore.Li@Sun.COM 	ASSERT(rsc != NULL);
28878237SMikore.Li@Sun.COM 	regs = &rsc->sc_regs;
28888237SMikore.Li@Sun.COM 
28898237SMikore.Li@Sun.COM 	rtw_dbg_flags = 0;
28908237SMikore.Li@Sun.COM 	rtw_disable_interrupts(regs);
28918237SMikore.Li@Sun.COM 	rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
28928237SMikore.Li@Sun.COM 	RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
28938237SMikore.Li@Sun.COM 
28948237SMikore.Li@Sun.COM 	return (DDI_SUCCESS);
28958237SMikore.Li@Sun.COM }
28968237SMikore.Li@Sun.COM 
28978237SMikore.Li@Sun.COM /*
28988237SMikore.Li@Sun.COM  * callback functions for /get/set properties
28998237SMikore.Li@Sun.COM  */
29008237SMikore.Li@Sun.COM static int
rtw_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)29018237SMikore.Li@Sun.COM rtw_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
29028237SMikore.Li@Sun.COM     uint_t wldp_length, const void *wldp_buf)
29038237SMikore.Li@Sun.COM {
290410448SMikore.Li@Sun.COM 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
290510448SMikore.Li@Sun.COM 	struct ieee80211com *ic = &rsc->sc_ic;
29068237SMikore.Li@Sun.COM 	int err;
29078237SMikore.Li@Sun.COM 
290810448SMikore.Li@Sun.COM 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
29098237SMikore.Li@Sun.COM 	    wldp_length, wldp_buf);
29108237SMikore.Li@Sun.COM 	if (err == ENETRESET) {
291110448SMikore.Li@Sun.COM 		if (ic->ic_des_esslen && (rsc->sc_invalid == 0)) {
291210448SMikore.Li@Sun.COM 			(void) rtw_init(rsc);
291310448SMikore.Li@Sun.COM 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
29148237SMikore.Li@Sun.COM 		}
29158237SMikore.Li@Sun.COM 		err = 0;
29168237SMikore.Li@Sun.COM 	}
29178237SMikore.Li@Sun.COM 	return (err);
29188237SMikore.Li@Sun.COM }
29198237SMikore.Li@Sun.COM 
29208237SMikore.Li@Sun.COM static int
rtw_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)29218237SMikore.Li@Sun.COM rtw_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2922*11878SVenu.Iyer@Sun.COM     uint_t wldp_length, void *wldp_buf)
29238237SMikore.Li@Sun.COM {
29248237SMikore.Li@Sun.COM 	rtw_softc_t *rsc = arg;
29258237SMikore.Li@Sun.COM 	int err;
29268237SMikore.Li@Sun.COM 
29278237SMikore.Li@Sun.COM 	err = ieee80211_getprop(&rsc->sc_ic, pr_name, wldp_pr_num,
2928*11878SVenu.Iyer@Sun.COM 	    wldp_length, wldp_buf);
29298237SMikore.Li@Sun.COM 
29308237SMikore.Li@Sun.COM 	return (err);
29318237SMikore.Li@Sun.COM }
29328237SMikore.Li@Sun.COM 
2933*11878SVenu.Iyer@Sun.COM static void
rtw_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t prh)2934*11878SVenu.Iyer@Sun.COM rtw_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2935*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t prh)
2936*11878SVenu.Iyer@Sun.COM {
2937*11878SVenu.Iyer@Sun.COM 	rtw_softc_t *rsc = arg;
2938*11878SVenu.Iyer@Sun.COM 
2939*11878SVenu.Iyer@Sun.COM 	ieee80211_propinfo(&rsc->sc_ic, pr_name, wldp_pr_num, prh);
2940*11878SVenu.Iyer@Sun.COM }
29414689Sql147931 
29424689Sql147931 static int
rtw_m_start(void * arg)29434689Sql147931 rtw_m_start(void *arg)
29444689Sql147931 {
29454689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
29464689Sql147931 	ieee80211com_t *ic = (ieee80211com_t *)rsc;
29474689Sql147931 	int ret;
29484689Sql147931 #ifdef DEBUG
29494689Sql147931 	rtw_print_regs(&rsc->sc_regs, "rtw", "rtw_start");
29504689Sql147931 #endif
295110448SMikore.Li@Sun.COM 
29524689Sql147931 	ret = rtw_init(rsc);
29534689Sql147931 	if (ret) {
29544689Sql147931 		cmn_err(CE_WARN, "rtw: failed to do rtw_init\n");
295510448SMikore.Li@Sun.COM 		return (EIO);
29564689Sql147931 	}
29574689Sql147931 	(void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
29584689Sql147931 	return (0);
29594689Sql147931 }
29604689Sql147931 
29614689Sql147931 
29624689Sql147931 static int
rtw_m_unicst(void * arg,const uint8_t * macaddr)29634689Sql147931 rtw_m_unicst(void *arg, const uint8_t *macaddr)
29644689Sql147931 {
29654689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
29664689Sql147931 	ieee80211com_t *ic = (ieee80211com_t *)rsc;
29674689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
29684689Sql147931 	uint32_t t;
29694689Sql147931 
29704689Sql147931 	mutex_enter(&rsc->sc_genlock);
29714689Sql147931 	bcopy(macaddr, ic->ic_macaddr, 6);
29724689Sql147931 	t = ((*macaddr)<<24) | ((*(macaddr + 1))<<16) |
29734689Sql147931 	    ((*(macaddr + 2))<<8) | (*(macaddr + 3));
29744689Sql147931 	RTW_WRITE(regs, RTW_IDR0, ntohl(t));
29754689Sql147931 	t = ((*(macaddr + 4))<<24) | ((*(macaddr + 5))<<16);
29764689Sql147931 	RTW_WRITE(regs, RTW_IDR1, ntohl(t));
29774689Sql147931 	mutex_exit(&rsc->sc_genlock);
29784689Sql147931 	return (0);
29794689Sql147931 }
29804689Sql147931 
29814689Sql147931 static int
rtw_m_promisc(void * arg,boolean_t on)29824689Sql147931 rtw_m_promisc(void *arg, boolean_t on)
29834689Sql147931 {
29844689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
29854689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
29864689Sql147931 
29874689Sql147931 	mutex_enter(&rsc->sc_genlock);
29884689Sql147931 
29894689Sql147931 	if (on)
29904689Sql147931 		rsc->sc_rcr |= RTW_RCR_PROMIC;
29914689Sql147931 	else
29924689Sql147931 		rsc->sc_rcr &= ~RTW_RCR_PROMIC;
29934689Sql147931 
29944689Sql147931 	RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
29954689Sql147931 
29964689Sql147931 	mutex_exit(&rsc->sc_genlock);
29974689Sql147931 	return (0);
29984689Sql147931 }
29994689Sql147931 
30004689Sql147931 static int
rtw_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)30014689Sql147931 rtw_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
30024689Sql147931 {
30034689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
30044689Sql147931 	struct rtw_regs *regs = &rsc->sc_regs;
30054689Sql147931 	uint32_t t;
30064689Sql147931 
30074689Sql147931 	mutex_enter(&rsc->sc_genlock);
30084689Sql147931 	if (add) {
30094689Sql147931 		rsc->sc_rcr |= RTW_RCR_AM;
30104689Sql147931 		t = ((*macaddr)<<24) | ((*(macaddr + 1))<<16) |
30114689Sql147931 		    ((*(macaddr + 2))<<8) | (*(macaddr + 3));
30124689Sql147931 		RTW_WRITE(regs, RTW_MAR0, ntohl(t));
30134689Sql147931 		t = ((*(macaddr + 4))<<24) | ((*(macaddr + 5))<<16);
30144689Sql147931 		RTW_WRITE(regs, RTW_MAR1, ntohl(t));
30154689Sql147931 		RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
30164689Sql147931 		RTW_SYNC(regs, RTW_MAR0, RTW_RCR);
30174689Sql147931 	} else {
30184689Sql147931 		rsc->sc_rcr &= ~RTW_RCR_AM;
30194689Sql147931 		RTW_WRITE(regs, RTW_MAR0, 0);
30204689Sql147931 		RTW_WRITE(regs, RTW_MAR1, 0);
30214689Sql147931 		RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr);
30224689Sql147931 		RTW_SYNC(regs, RTW_MAR0, RTW_RCR);
30234689Sql147931 	}
30244689Sql147931 	mutex_exit(&rsc->sc_genlock);
30254689Sql147931 	return (0);
30264689Sql147931 }
30274689Sql147931 
30284689Sql147931 static void
rtw_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)302910448SMikore.Li@Sun.COM rtw_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
30304689Sql147931 {
30314689Sql147931 	rtw_softc_t *rsc = arg;
303210448SMikore.Li@Sun.COM 	struct ieee80211com *ic = &rsc->sc_ic;
303310448SMikore.Li@Sun.COM 	int err;
303410448SMikore.Li@Sun.COM 
303510448SMikore.Li@Sun.COM 	err = ieee80211_ioctl(ic, wq, mp);
30364689Sql147931 	if (err == ENETRESET) {
303710448SMikore.Li@Sun.COM 		if (ic->ic_des_esslen && (rsc->sc_invalid == 0)) {
303810448SMikore.Li@Sun.COM 			(void) rtw_init(rsc);
303910448SMikore.Li@Sun.COM 			(void) ieee80211_new_state(ic,
30404689Sql147931 			    IEEE80211_S_SCAN, -1);
30414689Sql147931 		}
30424689Sql147931 	}
30434689Sql147931 }
30444689Sql147931 
30454689Sql147931 static int
rtw_m_stat(void * arg,uint_t stat,uint64_t * val)30464689Sql147931 rtw_m_stat(void *arg, uint_t stat, uint64_t *val)
30474689Sql147931 {
30484689Sql147931 	rtw_softc_t *rsc = (rtw_softc_t *)arg;
304910448SMikore.Li@Sun.COM 	ieee80211com_t *ic = &rsc->sc_ic;
305010448SMikore.Li@Sun.COM 	struct ieee80211_node *in = 0;
305110448SMikore.Li@Sun.COM 	struct ieee80211_rateset *rs = 0;
30524689Sql147931 
30534689Sql147931 	mutex_enter(&rsc->sc_genlock);
30544689Sql147931 	switch (stat) {
30554689Sql147931 	case MAC_STAT_IFSPEED:
305610448SMikore.Li@Sun.COM 		in = ic->ic_bss;
305710448SMikore.Li@Sun.COM 		rs = &in->in_rates;
305810448SMikore.Li@Sun.COM 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
305910448SMikore.Li@Sun.COM 		    (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL)
306010448SMikore.Li@Sun.COM 		    : ic->ic_fixed_rate) / 2 * 1000000;
30614689Sql147931 		break;
30624689Sql147931 	case MAC_STAT_NOXMTBUF:
30634689Sql147931 		*val = rsc->sc_noxmtbuf;
30644689Sql147931 		break;
30654689Sql147931 	case MAC_STAT_NORCVBUF:
30664689Sql147931 		*val = rsc->sc_norcvbuf;
30674689Sql147931 		break;
30684689Sql147931 	case MAC_STAT_RBYTES:
30694689Sql147931 		*val = rsc->sc_bytercv64;
30704689Sql147931 		break;
30714689Sql147931 	case MAC_STAT_IPACKETS:
30724689Sql147931 		*val = rsc->sc_pktrcv64;
30734689Sql147931 		break;
30744689Sql147931 	case MAC_STAT_OBYTES:
30754689Sql147931 		*val = rsc->sc_bytexmt64;
30764689Sql147931 		break;
30774689Sql147931 	case MAC_STAT_OPACKETS:
30784689Sql147931 		*val = rsc->sc_pktxmt64;
30794689Sql147931 		break;
30804689Sql147931 	case WIFI_STAT_TX_RETRANS:
30814689Sql147931 		*val = rsc->sc_xmtretry;
30824689Sql147931 		break;
30834689Sql147931 	case WIFI_STAT_TX_FRAGS:
30844689Sql147931 	case WIFI_STAT_MCAST_TX:
30854689Sql147931 	case WIFI_STAT_RTS_SUCCESS:
30864689Sql147931 	case WIFI_STAT_RTS_FAILURE:
30874689Sql147931 	case WIFI_STAT_ACK_FAILURE:
30884689Sql147931 	case WIFI_STAT_RX_FRAGS:
30894689Sql147931 	case WIFI_STAT_MCAST_RX:
30904689Sql147931 	case WIFI_STAT_RX_DUPS:
30914689Sql147931 		mutex_exit(&rsc->sc_genlock);
30924689Sql147931 		return (ieee80211_stat(ic, stat, val));
30934689Sql147931 	default:
30944689Sql147931 		*val = 0;
30954689Sql147931 		break;
30964689Sql147931 	}
30974689Sql147931 	mutex_exit(&rsc->sc_genlock);
30984689Sql147931 
30994689Sql147931 	return (0);
31004689Sql147931 }
31014689Sql147931 
31024689Sql147931 
31034689Sql147931 static void
rtw_mutex_destroy(rtw_softc_t * rsc)31044689Sql147931 rtw_mutex_destroy(rtw_softc_t *rsc)
31054689Sql147931 {
31064689Sql147931 	int i;
31074689Sql147931 
31084689Sql147931 	mutex_destroy(&rsc->rxbuf_lock);
31094689Sql147931 	mutex_destroy(&rsc->sc_txlock);
31104689Sql147931 	for (i = 0; i < RTW_NTXPRI; i++) {
31114689Sql147931 		mutex_destroy(&rsc->sc_txq[RTW_NTXPRI - 1 - i].txbuf_lock);
31124689Sql147931 	}
31134689Sql147931 	mutex_destroy(&rsc->sc_genlock);
31144689Sql147931 }
31154689Sql147931 
31164689Sql147931 static int
rtw_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)31174689Sql147931 rtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
31184689Sql147931 {
31194689Sql147931 	rtw_softc_t *rsc;
31204689Sql147931 	ieee80211com_t *ic;
31214689Sql147931 	uint8_t csz;
31224689Sql147931 	uint32_t i;
31234689Sql147931 	uint16_t vendor_id, device_id, command;
31244689Sql147931 	int32_t err;
31254689Sql147931 	char strbuf[32];
31264689Sql147931 	wifi_data_t wd = { 0 };
31274689Sql147931 	mac_register_t *macp;
31284689Sql147931 	int instance = ddi_get_instance(devinfo);
31294689Sql147931 
31304689Sql147931 	switch (cmd) {
31314689Sql147931 	case DDI_ATTACH:
31324689Sql147931 		break;
313310448SMikore.Li@Sun.COM 	case DDI_RESUME:
313410448SMikore.Li@Sun.COM 		rsc = ddi_get_soft_state(rtw_soft_state_p,
313510448SMikore.Li@Sun.COM 		    ddi_get_instance(devinfo));
313610448SMikore.Li@Sun.COM 		ASSERT(rsc != NULL);
313710448SMikore.Li@Sun.COM 		mutex_enter(&rsc->sc_genlock);
313810448SMikore.Li@Sun.COM 		rsc->sc_flags &= ~RTW_F_SUSPEND;
313910448SMikore.Li@Sun.COM 		mutex_exit(&rsc->sc_genlock);
314010448SMikore.Li@Sun.COM 		if ((rsc->sc_flags & RTW_F_PLUMBED)) {
314110448SMikore.Li@Sun.COM 			err = rtw_init(rsc);
314210448SMikore.Li@Sun.COM 			if (err == 0) {
314310448SMikore.Li@Sun.COM 				mutex_enter(&rsc->sc_genlock);
314410448SMikore.Li@Sun.COM 				rsc->sc_flags &= ~RTW_F_PLUMBED;
314510448SMikore.Li@Sun.COM 				mutex_exit(&rsc->sc_genlock);
314610448SMikore.Li@Sun.COM 			}
314710448SMikore.Li@Sun.COM 		}
314810448SMikore.Li@Sun.COM 		return (DDI_SUCCESS);
31494689Sql147931 	default:
31504689Sql147931 		return (DDI_FAILURE);
31514689Sql147931 	}
31524689Sql147931 
31534689Sql147931 	if (ddi_soft_state_zalloc(rtw_soft_state_p,
31544689Sql147931 	    ddi_get_instance(devinfo)) != DDI_SUCCESS) {
31554689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
31564689Sql147931 		    "Unable to alloc softstate\n");
31574689Sql147931 		return (DDI_FAILURE);
31584689Sql147931 	}
31594689Sql147931 
31604689Sql147931 	rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(devinfo));
31614689Sql147931 	ic = &rsc->sc_ic;
31624689Sql147931 	rsc->sc_dev = devinfo;
31634689Sql147931 
31644689Sql147931 	err = ddi_regs_map_setup(devinfo, 0, (caddr_t *)&rsc->sc_cfg_base, 0, 0,
31654689Sql147931 	    &rtw_reg_accattr, &rsc->sc_cfg_handle);
31664689Sql147931 	if (err != DDI_SUCCESS) {
31674689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
31684689Sql147931 		    "ddi_regs_map_setup() failed");
31694689Sql147931 		goto attach_fail0;
31704689Sql147931 	}
31714689Sql147931 	csz = ddi_get8(rsc->sc_cfg_handle,
31724689Sql147931 	    (uint8_t *)(rsc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
31734689Sql147931 	if (!csz)
31744689Sql147931 		csz = 16;
31754689Sql147931 	rsc->sc_cachelsz = csz << 2;
31764689Sql147931 	vendor_id = ddi_get16(rsc->sc_cfg_handle,
31776890Sql147931 	    (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_VENID));
31784689Sql147931 	device_id = ddi_get16(rsc->sc_cfg_handle,
31796890Sql147931 	    (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_DEVID));
31804689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): vendor 0x%x, "
31814689Sql147931 	    "device id 0x%x, cache size %d\n", vendor_id, device_id, csz);
31824689Sql147931 
31834689Sql147931 	/*
31844689Sql147931 	 * Enable response to memory space accesses,
31854689Sql147931 	 * and enabe bus master.
31864689Sql147931 	 */
31874689Sql147931 	command = PCI_COMM_MAE | PCI_COMM_ME;
31884689Sql147931 	ddi_put16(rsc->sc_cfg_handle,
31896890Sql147931 	    (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_COMM), command);
31904689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
31914689Sql147931 	    "set command reg to 0x%x \n", command);
31924689Sql147931 
31934689Sql147931 	ddi_put8(rsc->sc_cfg_handle,
31944689Sql147931 	    (uint8_t *)(rsc->sc_cfg_base + PCI_CONF_LATENCY_TIMER), 0xa8);
31954689Sql147931 
31964689Sql147931 	ddi_regs_map_free(&rsc->sc_cfg_handle);
31974689Sql147931 
31984689Sql147931 	err = ddi_regs_map_setup(devinfo, 2, (caddr_t *)&rsc->sc_regs.r_base,
31994689Sql147931 	    0, 0, &rtw_reg_accattr, &rsc->sc_regs.r_handle);
32004689Sql147931 	if (err != DDI_SUCCESS) {
32014689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
32024689Sql147931 		    "ddi_regs_map_setup() failed");
32034689Sql147931 		goto attach_fail0;
32044689Sql147931 	}
32054689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: r_base=%x, r_handle=%x\n",
32064689Sql147931 	    rsc->sc_regs.r_base, rsc->sc_regs.r_handle);
32074689Sql147931 
32084689Sql147931 	err = rtw_dma_init(devinfo, rsc);
32094689Sql147931 	if (err != DDI_SUCCESS) {
32104689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
32114689Sql147931 		    "failed to init dma: %d\n", err);
32124689Sql147931 		goto attach_fail1;
32134689Sql147931 	}
32144689Sql147931 
32154689Sql147931 	/*
32164689Sql147931 	 * Stop the transmit and receive processes. First stop DMA,
32174689Sql147931 	 * then disable receiver and transmitter.
32184689Sql147931 	 */
32194689Sql147931 	RTW_WRITE8(&rsc->sc_regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
32204689Sql147931 	rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0);
32214689Sql147931 
32224689Sql147931 	/* Reset the chip to a known state. */
32234689Sql147931 	if (rtw_reset(rsc) != 0) {
32244689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
32254689Sql147931 		    "failed to reset\n");
32264689Sql147931 		goto attach_fail2;
32274689Sql147931 	}
32284689Sql147931 	rsc->sc_rcr = RTW_READ(&rsc->sc_regs, RTW_RCR);
32294689Sql147931 
32304689Sql147931 	if ((rsc->sc_rcr & RTW_RCR_9356SEL) != 0)
32314689Sql147931 		rsc->sc_flags |= RTW_F_9356SROM;
32324689Sql147931 
32334689Sql147931 	if (rtw_srom_read(&rsc->sc_regs, rsc->sc_flags, &rsc->sc_srom,
32344689Sql147931 	    "rtw") != 0) {
32354689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
32364689Sql147931 		    "failed to read srom\n");
32374689Sql147931 		goto attach_fail2;
32384689Sql147931 	}
32394689Sql147931 
32404689Sql147931 	if (rtw_srom_parse(&rsc->sc_srom, &rsc->sc_flags, &rsc->sc_csthr,
32414689Sql147931 	    &rsc->sc_rfchipid, &rsc->sc_rcr, &rsc->sc_locale,
32424689Sql147931 	    "rtw") != 0) {
32434689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_attach():"
32444689Sql147931 		    " malformed serial ROM\n");
32454689Sql147931 		goto attach_fail3;
32464689Sql147931 	}
32474689Sql147931 
32484689Sql147931 	RTW_DPRINTF(RTW_DEBUG_PHY, "rtw: %s PHY\n",
32494689Sql147931 	    ((rsc->sc_flags & RTW_F_DIGPHY) != 0) ? "digital" : "analog");
32504689Sql147931 
32514689Sql147931 
32524689Sql147931 	rsc->sc_rf = rtw_rf_attach(rsc, rsc->sc_rfchipid,
32534689Sql147931 	    rsc->sc_flags & RTW_F_DIGPHY);
32544689Sql147931 
32554689Sql147931 	if (rsc->sc_rf == NULL) {
32564689Sql147931 		cmn_err(CE_WARN, "rtw: rtw_attach(): could not attach RF\n");
32574689Sql147931 		goto attach_fail3;
32584689Sql147931 	}
32594689Sql147931 	rsc->sc_phydelay = rtw_check_phydelay(&rsc->sc_regs, rsc->sc_rcr);
32604689Sql147931 
32614689Sql147931 	RTW_DPRINTF(RTW_DEBUG_ATTACH,
32624689Sql147931 	    "rtw: PHY delay %d\n", rsc->sc_phydelay);
32634689Sql147931 
32644689Sql147931 	if (rsc->sc_locale == RTW_LOCALE_UNKNOWN)
32654689Sql147931 		rtw_identify_country(&rsc->sc_regs, &rsc->sc_locale,
32664689Sql147931 		    "rtw");
32674689Sql147931 
32684689Sql147931 	rtw_init_channels(rsc->sc_locale, &rsc->sc_ic.ic_sup_channels,
32694689Sql147931 	    "rtw");
32704689Sql147931 
32714689Sql147931 	rtw_set80211props(ic);
32724689Sql147931 
32734689Sql147931 	if (rtw_identify_sta(&rsc->sc_regs, ic->ic_macaddr,
32744689Sql147931 	    "rtw") != 0)
32754689Sql147931 		goto attach_fail4;
32764689Sql147931 
32774689Sql147931 	ic->ic_xmit = rtw_send;
32784689Sql147931 	ieee80211_attach(ic);
32794689Sql147931 
32804689Sql147931 	rsc->sc_newstate = ic->ic_newstate;
32814689Sql147931 	ic->ic_newstate = rtw_new_state;
32824689Sql147931 	ieee80211_media_init(ic);
32834689Sql147931 	ic->ic_def_txkey = 0;
32844689Sql147931 
32854689Sql147931 	if (ddi_get_iblock_cookie(devinfo, 0, &(rsc->sc_iblock))
32864689Sql147931 	    != DDI_SUCCESS) {
32874689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
32884689Sql147931 		    "Can not get iblock cookie for INT\n");
32894689Sql147931 		goto attach_fail5;
32904689Sql147931 	}
32914689Sql147931 
32924689Sql147931 	mutex_init(&rsc->sc_genlock, NULL, MUTEX_DRIVER, rsc->sc_iblock);
32934689Sql147931 	for (i = 0; i < RTW_NTXPRI; i++) {
32944689Sql147931 		mutex_init(&rsc->sc_txq[i].txbuf_lock, NULL, MUTEX_DRIVER,
32954689Sql147931 		    rsc->sc_iblock);
32964689Sql147931 	}
32974689Sql147931 	mutex_init(&rsc->rxbuf_lock, NULL, MUTEX_DRIVER, rsc->sc_iblock);
32984689Sql147931 	mutex_init(&rsc->sc_txlock, NULL, MUTEX_DRIVER, rsc->sc_iblock);
32994689Sql147931 
33004689Sql147931 	if (ddi_add_intr(devinfo, 0, &rsc->sc_iblock, NULL, rtw_intr,
33014689Sql147931 	    (caddr_t)(rsc)) != DDI_SUCCESS) {
33024689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
33034689Sql147931 		    "Can not add intr for rtw driver\n");
33044689Sql147931 		goto attach_fail7;
33054689Sql147931 	}
33064689Sql147931 
33074689Sql147931 	/*
33084689Sql147931 	 * Provide initial settings for the WiFi plugin; whenever this
33094689Sql147931 	 * information changes, we need to call mac_plugindata_update()
33104689Sql147931 	 */
33114689Sql147931 	wd.wd_opmode = ic->ic_opmode;
33124689Sql147931 	wd.wd_secalloc = WIFI_SEC_NONE;
33134689Sql147931 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
33144689Sql147931 
33154689Sql147931 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
33164689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
33174689Sql147931 		    "MAC version mismatch\n");
33184689Sql147931 		goto attach_fail8;
33194689Sql147931 	}
33204689Sql147931 
33214689Sql147931 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
33224689Sql147931 	macp->m_driver		= rsc;
33234689Sql147931 	macp->m_dip		= devinfo;
33244689Sql147931 	macp->m_src_addr	= ic->ic_macaddr;
33254689Sql147931 	macp->m_callbacks	= &rtw_m_callbacks;
33264689Sql147931 	macp->m_min_sdu		= 0;
33274689Sql147931 	macp->m_max_sdu		= IEEE80211_MTU;
33284689Sql147931 	macp->m_pdata		= &wd;
33294689Sql147931 	macp->m_pdata_size	= sizeof (wd);
33304689Sql147931 
33314689Sql147931 	err = mac_register(macp, &ic->ic_mach);
33324689Sql147931 	mac_free(macp);
33334689Sql147931 	if (err != 0) {
33344689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): "
33354689Sql147931 		    "mac_register err %x\n", err);
33364689Sql147931 		goto attach_fail8;
33374689Sql147931 	}
33384689Sql147931 
33394689Sql147931 	/* Create minor node of type DDI_NT_NET_WIFI */
33404689Sql147931 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
33414689Sql147931 	    "rtw", instance);
33424689Sql147931 	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
33434689Sql147931 	    instance + 1, DDI_NT_NET_WIFI, 0);
33444689Sql147931 	if (err != DDI_SUCCESS) {
33454689Sql147931 		RTW_DPRINTF(RTW_DEBUG_ATTACH, "WARN: rtw: rtw_attach(): "
33464689Sql147931 		    "Create minor node failed - %d\n", err);
33474689Sql147931 		goto attach_fail9;
33484689Sql147931 	}
33494689Sql147931 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
33504689Sql147931 	rsc->sc_flags |= RTW_F_ATTACHED;
33514689Sql147931 	rsc->sc_need_reschedule = 0;
33524689Sql147931 	rsc->sc_invalid = 1;
33534689Sql147931 	return (DDI_SUCCESS);
33544689Sql147931 attach_fail9:
335510448SMikore.Li@Sun.COM 	(void) mac_disable(ic->ic_mach);
33564689Sql147931 	(void) mac_unregister(ic->ic_mach);
33574689Sql147931 attach_fail8:
33584689Sql147931 	ddi_remove_intr(devinfo, 0, rsc->sc_iblock);
33594689Sql147931 attach_fail7:
33604689Sql147931 attach_fail6:
33614689Sql147931 	rtw_mutex_destroy(rsc);
33624689Sql147931 attach_fail5:
33634689Sql147931 	ieee80211_detach(ic);
33644689Sql147931 attach_fail4:
33654689Sql147931 	rtw_rf_destroy(rsc->sc_rf);
33664689Sql147931 attach_fail3:
33674689Sql147931 	rtw_srom_free(&rsc->sc_srom);
33684689Sql147931 attach_fail2:
33694689Sql147931 	rtw_dma_free(rsc);
33704689Sql147931 attach_fail1:
33714689Sql147931 	ddi_regs_map_free(&rsc->sc_regs.r_handle);
33724689Sql147931 attach_fail0:
33734689Sql147931 	ddi_soft_state_free(rtw_soft_state_p, ddi_get_instance(devinfo));
33744689Sql147931 	return (DDI_FAILURE);
33754689Sql147931 }
33764689Sql147931 
33774689Sql147931 static int32_t
rtw_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)33784689Sql147931 rtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
33794689Sql147931 {
33804689Sql147931 	rtw_softc_t *rsc;
33814689Sql147931 
33824689Sql147931 	rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(devinfo));
33834689Sql147931 	ASSERT(rsc != NULL);
33844689Sql147931 
33854689Sql147931 	switch (cmd) {
33864689Sql147931 	case DDI_DETACH:
33874689Sql147931 		break;
338810448SMikore.Li@Sun.COM 	case DDI_SUSPEND:
338910448SMikore.Li@Sun.COM 		ieee80211_new_state(&rsc->sc_ic, IEEE80211_S_INIT, -1);
339010448SMikore.Li@Sun.COM 		mutex_enter(&rsc->sc_genlock);
339110448SMikore.Li@Sun.COM 		rsc->sc_flags |= RTW_F_SUSPEND;
339210448SMikore.Li@Sun.COM 		mutex_exit(&rsc->sc_genlock);
339310448SMikore.Li@Sun.COM 		if (rsc->sc_invalid == 0) {
339410448SMikore.Li@Sun.COM 			rtw_stop(rsc);
339510448SMikore.Li@Sun.COM 			mutex_enter(&rsc->sc_genlock);
339610448SMikore.Li@Sun.COM 			rsc->sc_flags |= RTW_F_PLUMBED;
339710448SMikore.Li@Sun.COM 			mutex_exit(&rsc->sc_genlock);
339810448SMikore.Li@Sun.COM 		}
339910448SMikore.Li@Sun.COM 		return (DDI_SUCCESS);
34004689Sql147931 	default:
34014689Sql147931 		return (DDI_FAILURE);
34024689Sql147931 	}
34034689Sql147931 	if (!(rsc->sc_flags & RTW_F_ATTACHED))
34044689Sql147931 		return (DDI_FAILURE);
34054689Sql147931 
34067507SXinghua.Wen@Sun.COM 	if (mac_disable(rsc->sc_ic.ic_mach) != 0)
34077507SXinghua.Wen@Sun.COM 		return (DDI_FAILURE);
34087507SXinghua.Wen@Sun.COM 
34094689Sql147931 	/* free intterrupt resources */
34104689Sql147931 	ddi_remove_intr(devinfo, 0, rsc->sc_iblock);
34114689Sql147931 
34124689Sql147931 	rtw_mutex_destroy(rsc);
34134689Sql147931 	ieee80211_detach((ieee80211com_t *)rsc);
34144689Sql147931 	/*
34154689Sql147931 	 * Unregister from the MAC layer subsystem
34164689Sql147931 	 */
34174689Sql147931 	(void) mac_unregister(rsc->sc_ic.ic_mach);
34184689Sql147931 
34194689Sql147931 	rtw_rf_destroy(rsc->sc_rf);
34204689Sql147931 	rtw_srom_free(&rsc->sc_srom);
34214689Sql147931 	rtw_dma_free(rsc);
34224689Sql147931 	ddi_remove_minor_node(devinfo, NULL);
34234689Sql147931 	ddi_regs_map_free(&rsc->sc_regs.r_handle);
34244689Sql147931 
34254689Sql147931 	ddi_soft_state_free(rtw_soft_state_p, ddi_get_instance(devinfo));
34264689Sql147931 
34274689Sql147931 	return (DDI_SUCCESS);
34284689Sql147931 }
3429