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