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