1a72f7ea6Sql /* 2020c4770Sql * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3a72f7ea6Sql * Use is subject to license terms. 4a72f7ea6Sql */ 5a72f7ea6Sql 6a72f7ea6Sql /* 7a72f7ea6Sql * Copyright (c) 2004 David Young. All rights reserved. 8a72f7ea6Sql * 9a72f7ea6Sql * This code was written by David Young. 10a72f7ea6Sql * 11a72f7ea6Sql * Redistribution and use in source and binary forms, with or without 12a72f7ea6Sql * modification, are permitted provided that the following conditions 13a72f7ea6Sql * are met: 14a72f7ea6Sql * 1. Redistributions of source code must retain the above copyright 15a72f7ea6Sql * notice, this list of conditions and the following disclaimer. 16a72f7ea6Sql * 2. Redistributions in binary form must reproduce the above copyright 17a72f7ea6Sql * notice, this list of conditions and the following disclaimer in the 18a72f7ea6Sql * documentation and/or other materials provided with the distribution. 19a72f7ea6Sql * 3. Neither the name of the author nor the names of any co-contributors 20a72f7ea6Sql * may be used to endorse or promote products derived from this software 21a72f7ea6Sql * without specific prior written permission. 22a72f7ea6Sql * 23a72f7ea6Sql * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY 24a72f7ea6Sql * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25a72f7ea6Sql * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 26a72f7ea6Sql * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David 27a72f7ea6Sql * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28a72f7ea6Sql * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29a72f7ea6Sql * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30a72f7ea6Sql * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31a72f7ea6Sql * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32a72f7ea6Sql * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33a72f7ea6Sql * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34a72f7ea6Sql * OF SUCH DAMAGE. 35a72f7ea6Sql */ 36a72f7ea6Sql 37a72f7ea6Sql #include <sys/param.h> 38a72f7ea6Sql #include <sys/types.h> 39a72f7ea6Sql #include <sys/signal.h> 40a72f7ea6Sql #include <sys/stream.h> 41a72f7ea6Sql #include <sys/termio.h> 42a72f7ea6Sql #include <sys/errno.h> 43a72f7ea6Sql #include <sys/file.h> 44a72f7ea6Sql #include <sys/cmn_err.h> 45a72f7ea6Sql #include <sys/stropts.h> 46a72f7ea6Sql #include <sys/strtty.h> 47a72f7ea6Sql #include <sys/kbio.h> 48a72f7ea6Sql #include <sys/cred.h> 49a72f7ea6Sql #include <sys/stat.h> 50a72f7ea6Sql #include <sys/consdev.h> 51a72f7ea6Sql #include <sys/kmem.h> 52a72f7ea6Sql #include <sys/modctl.h> 53a72f7ea6Sql #include <sys/ddi.h> 54a72f7ea6Sql #include <sys/sunddi.h> 55a72f7ea6Sql #include <sys/pci.h> 56a72f7ea6Sql #include <sys/errno.h> 57a72f7ea6Sql #include <sys/mac.h> 58a72f7ea6Sql #include <sys/dlpi.h> 59a72f7ea6Sql #include <sys/ethernet.h> 60a72f7ea6Sql #include <sys/list.h> 61a72f7ea6Sql #include <sys/byteorder.h> 62a72f7ea6Sql #include <sys/strsun.h> 63a72f7ea6Sql #include <sys/strsubr.h> 64a72f7ea6Sql #include <sys/policy.h> 65a72f7ea6Sql #include <inet/common.h> 66a72f7ea6Sql #include <inet/nd.h> 67a72f7ea6Sql #include <inet/mi.h> 68a72f7ea6Sql #include <inet/wifi_ioctl.h> 69a72f7ea6Sql #include <sys/mac_wifi.h> 70a72f7ea6Sql #include <sys/crypto/common.h> 71a72f7ea6Sql #include <sys/crypto/api.h> 72a72f7ea6Sql 73a72f7ea6Sql #include "rtwreg.h" 74a72f7ea6Sql #include "rtwvar.h" 75a72f7ea6Sql #include "smc93cx6var.h" 76a72f7ea6Sql #include "rtwphy.h" 77a72f7ea6Sql #include "rtwphyio.h" 78a72f7ea6Sql 79a72f7ea6Sql /* 80a72f7ea6Sql * PIO access attributes for registers 81a72f7ea6Sql */ 82a72f7ea6Sql static ddi_device_acc_attr_t rtw_reg_accattr = { 83a72f7ea6Sql DDI_DEVICE_ATTR_V0, 84a72f7ea6Sql DDI_STRUCTURE_LE_ACC, 85a72f7ea6Sql DDI_STRICTORDER_ACC, 86a72f7ea6Sql DDI_DEFAULT_ACC 87a72f7ea6Sql }; 88a72f7ea6Sql 89a72f7ea6Sql /* 90a72f7ea6Sql * DMA access attributes for descriptors and bufs: NOT to be byte swapped. 91a72f7ea6Sql */ 92a72f7ea6Sql static ddi_device_acc_attr_t rtw_desc_accattr = { 93a72f7ea6Sql DDI_DEVICE_ATTR_V0, 94a72f7ea6Sql DDI_NEVERSWAP_ACC, 95a72f7ea6Sql DDI_STRICTORDER_ACC, 96a72f7ea6Sql DDI_DEFAULT_ACC 97a72f7ea6Sql }; 98a72f7ea6Sql static ddi_device_acc_attr_t rtw_buf_accattr = { 99a72f7ea6Sql DDI_DEVICE_ATTR_V0, 100a72f7ea6Sql DDI_NEVERSWAP_ACC, 101a72f7ea6Sql DDI_STRICTORDER_ACC, 102a72f7ea6Sql DDI_DEFAULT_ACC 103a72f7ea6Sql }; 104a72f7ea6Sql 105a72f7ea6Sql /* 106a72f7ea6Sql * Describes the chip's DMA engine 107a72f7ea6Sql */ 108a72f7ea6Sql static ddi_dma_attr_t dma_attr_desc = { 109a72f7ea6Sql DMA_ATTR_V0, /* dma_attr version */ 110a72f7ea6Sql 0x0000000000000000ull, /* dma_attr_addr_lo */ 111020c4770Sql 0xFFFFFFFF, /* dma_attr_addr_hi */ 112a72f7ea6Sql 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 113a72f7ea6Sql 0x100, /* dma_attr_align */ 114a72f7ea6Sql 0xFFFFFFFF, /* dma_attr_burstsizes */ 115a72f7ea6Sql 0x00000001, /* dma_attr_minxfer */ 116a72f7ea6Sql 0x00000000FFFFull, /* dma_attr_maxxfer */ 117a72f7ea6Sql 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 118a72f7ea6Sql 1, /* dma_attr_sgllen */ 119a72f7ea6Sql 1, /* dma_attr_granular */ 120a72f7ea6Sql 0 /* dma_attr_flags */ 121a72f7ea6Sql }; 122a72f7ea6Sql 123a72f7ea6Sql static ddi_dma_attr_t dma_attr_rxbuf = { 124a72f7ea6Sql DMA_ATTR_V0, /* dma_attr version */ 125a72f7ea6Sql 0x0000000000000000ull, /* dma_attr_addr_lo */ 126020c4770Sql 0xFFFFFFFF, /* dma_attr_addr_hi */ 127a72f7ea6Sql 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 128a72f7ea6Sql (uint32_t)16, /* dma_attr_align */ 129a72f7ea6Sql 0xFFFFFFFF, /* dma_attr_burstsizes */ 130a72f7ea6Sql 0x00000001, /* dma_attr_minxfer */ 131a72f7ea6Sql 0x00000000FFFFull, /* dma_attr_maxxfer */ 132a72f7ea6Sql 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 133a72f7ea6Sql 1, /* dma_attr_sgllen */ 134a72f7ea6Sql 1, /* dma_attr_granular */ 135a72f7ea6Sql 0 /* dma_attr_flags */ 136a72f7ea6Sql }; 137a72f7ea6Sql 138a72f7ea6Sql static ddi_dma_attr_t dma_attr_txbuf = { 139a72f7ea6Sql DMA_ATTR_V0, /* dma_attr version */ 140a72f7ea6Sql 0x0000000000000000ull, /* dma_attr_addr_lo */ 141020c4770Sql 0xFFFFFFFF, /* dma_attr_addr_hi */ 142a72f7ea6Sql 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 143a72f7ea6Sql (uint32_t)16, /* dma_attr_align */ 144a72f7ea6Sql 0xFFFFFFFF, /* dma_attr_burstsizes */ 145a72f7ea6Sql 0x00000001, /* dma_attr_minxfer */ 146a72f7ea6Sql 0x00000000FFFFull, /* dma_attr_maxxfer */ 147a72f7ea6Sql 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 148a72f7ea6Sql 1, /* dma_attr_sgllen */ 149a72f7ea6Sql 1, /* dma_attr_granular */ 150a72f7ea6Sql 0 /* dma_attr_flags */ 151a72f7ea6Sql }; 152a72f7ea6Sql 153a72f7ea6Sql 154a72f7ea6Sql static void *rtw_soft_state_p = NULL; 155a72f7ea6Sql 156a72f7ea6Sql static int rtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd); 157a72f7ea6Sql static int rtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd); 158*94d05f6cSQin Michael Li static int rtw_quiesce(dev_info_t *dip); 159a72f7ea6Sql static int rtw_m_stat(void *, uint_t, uint64_t *); 160a72f7ea6Sql static int rtw_m_start(void *); 161a72f7ea6Sql static void rtw_m_stop(void *); 162a72f7ea6Sql static int rtw_m_promisc(void *, boolean_t); 163a72f7ea6Sql static int rtw_m_multicst(void *, boolean_t, const uint8_t *); 164a72f7ea6Sql static int rtw_m_unicst(void *, const uint8_t *); 165a72f7ea6Sql static mblk_t *rtw_m_tx(void *, mblk_t *); 166a72f7ea6Sql static void rtw_m_ioctl(void *, queue_t *, mblk_t *); 167*94d05f6cSQin Michael Li static int rtw_m_setprop(void *, const char *, mac_prop_id_t, 168*94d05f6cSQin Michael Li uint_t, const void *); 169*94d05f6cSQin Michael Li static int rtw_m_getprop(void *, const char *, mac_prop_id_t, 170*94d05f6cSQin Michael Li uint_t, uint_t, void *, uint_t *); 171*94d05f6cSQin Michael Li 172a72f7ea6Sql static mac_callbacks_t rtw_m_callbacks = { 173*94d05f6cSQin Michael Li MC_IOCTL | MC_SETPROP | MC_GETPROP, 174a72f7ea6Sql rtw_m_stat, 175a72f7ea6Sql rtw_m_start, 176a72f7ea6Sql rtw_m_stop, 177a72f7ea6Sql rtw_m_promisc, 178a72f7ea6Sql rtw_m_multicst, 179a72f7ea6Sql rtw_m_unicst, 180a72f7ea6Sql rtw_m_tx, 181a72f7ea6Sql NULL, 182*94d05f6cSQin Michael Li rtw_m_ioctl, 183*94d05f6cSQin Michael Li NULL, /* mc_getcapab */ 184*94d05f6cSQin Michael Li NULL, 185*94d05f6cSQin Michael Li NULL, 186*94d05f6cSQin Michael Li rtw_m_setprop, 187*94d05f6cSQin Michael Li rtw_m_getprop 188a72f7ea6Sql }; 189a72f7ea6Sql 190a72f7ea6Sql DDI_DEFINE_STREAM_OPS(rtw_dev_ops, nulldev, nulldev, rtw_attach, rtw_detach, 191*94d05f6cSQin Michael Li nodev, NULL, D_MP, NULL, rtw_quiesce); 192a72f7ea6Sql 193a72f7ea6Sql static struct modldrv rtw_modldrv = { 194a72f7ea6Sql &mod_driverops, /* Type of module. This one is a driver */ 195a72f7ea6Sql "realtek 802.11b driver", /* short description */ 196a72f7ea6Sql &rtw_dev_ops /* driver specific ops */ 197a72f7ea6Sql }; 198a72f7ea6Sql 199a72f7ea6Sql static struct modlinkage modlinkage = { 200a72f7ea6Sql MODREV_1, (void *)&rtw_modldrv, NULL 201a72f7ea6Sql }; 202a72f7ea6Sql 203a72f7ea6Sql static uint32_t rtw_qlen[RTW_NTXPRI] = { 204a72f7ea6Sql RTW_TXQLENLO, 205a72f7ea6Sql RTW_TXQLENMD, 206a72f7ea6Sql RTW_TXQLENHI, 207a72f7ea6Sql RTW_TXQLENBCN 208a72f7ea6Sql }; 209a72f7ea6Sql 210020c4770Sql uint32_t rtw_dbg_flags = 0; 211a72f7ea6Sql /* 212a72f7ea6Sql * RTW_DEBUG_ATTACH | RTW_DEBUG_TUNE | 213a72f7ea6Sql * RTW_DEBUG_ACCESS | RTW_DEBUG_INIT | RTW_DEBUG_PKTFILT | 214a72f7ea6Sql * RTW_DEBUG_RECV | RTW_DEBUG_XMIT | RTW_DEBUG_80211 | RTW_DEBUG_INTR | 215a72f7ea6Sql * RTW_DEBUG_PKTDUMP; 216a72f7ea6Sql */ 217a72f7ea6Sql 218*94d05f6cSQin Michael Li /* 219*94d05f6cSQin Michael Li * Supported rates for 802.11b modes (in 500Kbps unit). 220*94d05f6cSQin Michael Li */ 221*94d05f6cSQin Michael Li static const struct ieee80211_rateset rtw_rateset_11b = 222*94d05f6cSQin Michael Li { 4, { 2, 4, 11, 22 } }; 223*94d05f6cSQin Michael Li 224a72f7ea6Sql int 225a72f7ea6Sql _info(struct modinfo *modinfop) 226a72f7ea6Sql { 227a72f7ea6Sql return (mod_info(&modlinkage, modinfop)); 228a72f7ea6Sql } 229a72f7ea6Sql 230a72f7ea6Sql int 231a72f7ea6Sql _init(void) 232a72f7ea6Sql { 233a72f7ea6Sql int status; 234a72f7ea6Sql 235a72f7ea6Sql status = ddi_soft_state_init(&rtw_soft_state_p, 236a72f7ea6Sql sizeof (rtw_softc_t), 1); 237a72f7ea6Sql if (status != 0) 238a72f7ea6Sql return (status); 239a72f7ea6Sql 240a72f7ea6Sql mac_init_ops(&rtw_dev_ops, "rtw"); 241a72f7ea6Sql status = mod_install(&modlinkage); 242a72f7ea6Sql if (status != 0) { 243a72f7ea6Sql mac_fini_ops(&rtw_dev_ops); 244a72f7ea6Sql ddi_soft_state_fini(&rtw_soft_state_p); 245a72f7ea6Sql } 246a72f7ea6Sql return (status); 247a72f7ea6Sql } 248a72f7ea6Sql 249a72f7ea6Sql int 250a72f7ea6Sql _fini(void) 251a72f7ea6Sql { 252a72f7ea6Sql int status; 253a72f7ea6Sql 254a72f7ea6Sql status = mod_remove(&modlinkage); 255a72f7ea6Sql if (status == 0) { 256a72f7ea6Sql mac_fini_ops(&rtw_dev_ops); 257a72f7ea6Sql ddi_soft_state_fini(&rtw_soft_state_p); 258a72f7ea6Sql } 259a72f7ea6Sql return (status); 260a72f7ea6Sql } 261a72f7ea6Sql 262a72f7ea6Sql void 263a72f7ea6Sql rtw_dbg(uint32_t dbg_flags, const int8_t *fmt, ...) 264a72f7ea6Sql { 265a72f7ea6Sql va_list args; 266a72f7ea6Sql 267a72f7ea6Sql if (dbg_flags & rtw_dbg_flags) { 268a72f7ea6Sql va_start(args, fmt); 269a72f7ea6Sql vcmn_err(CE_CONT, fmt, args); 270a72f7ea6Sql va_end(args); 271a72f7ea6Sql } 272a72f7ea6Sql } 273a72f7ea6Sql 274a72f7ea6Sql #ifdef DEBUG 275a72f7ea6Sql static void 276a72f7ea6Sql rtw_print_regs(struct rtw_regs *regs, const char *dvname, const char *where) 277a72f7ea6Sql { 278a72f7ea6Sql #define PRINTREG32(sc, reg) \ 279a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_REGDUMP, \ 280a72f7ea6Sql "%s: reg[ " #reg " / %03x ] = %08x\n", \ 281a72f7ea6Sql dvname, reg, RTW_READ(regs, reg)) 282a72f7ea6Sql 283a72f7ea6Sql #define PRINTREG16(sc, reg) \ 284a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_REGDUMP, \ 285a72f7ea6Sql "%s: reg[ " #reg " / %03x ] = %04x\n", \ 286a72f7ea6Sql dvname, reg, RTW_READ16(regs, reg)) 287a72f7ea6Sql 288a72f7ea6Sql #define PRINTREG8(sc, reg) \ 289a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_REGDUMP, \ 290a72f7ea6Sql "%s: reg[ " #reg " / %03x ] = %02x\n", \ 291a72f7ea6Sql dvname, reg, RTW_READ8(regs, reg)) 292a72f7ea6Sql 293a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_REGDUMP, "%s: %s\n", dvname, where); 294a72f7ea6Sql 295a72f7ea6Sql PRINTREG32(regs, RTW_IDR0); 296a72f7ea6Sql PRINTREG32(regs, RTW_IDR1); 297a72f7ea6Sql PRINTREG32(regs, RTW_MAR0); 298a72f7ea6Sql PRINTREG32(regs, RTW_MAR1); 299a72f7ea6Sql PRINTREG32(regs, RTW_TSFTRL); 300a72f7ea6Sql PRINTREG32(regs, RTW_TSFTRH); 301a72f7ea6Sql PRINTREG32(regs, RTW_TLPDA); 302a72f7ea6Sql PRINTREG32(regs, RTW_TNPDA); 303a72f7ea6Sql PRINTREG32(regs, RTW_THPDA); 304a72f7ea6Sql PRINTREG32(regs, RTW_TCR); 305a72f7ea6Sql PRINTREG32(regs, RTW_RCR); 306a72f7ea6Sql PRINTREG32(regs, RTW_TINT); 307a72f7ea6Sql PRINTREG32(regs, RTW_TBDA); 308a72f7ea6Sql PRINTREG32(regs, RTW_ANAPARM); 309a72f7ea6Sql PRINTREG32(regs, RTW_BB); 310a72f7ea6Sql PRINTREG32(regs, RTW_PHYCFG); 311a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP0L); 312a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP0H); 313a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP1L); 314a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP1H); 315a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP2LL); 316a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP2LH); 317a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP2HL); 318a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP2HH); 319a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP3LL); 320a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP3LH); 321a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP3HL); 322a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP3HH); 323a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP4LL); 324a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP4LH); 325a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP4HL); 326a72f7ea6Sql PRINTREG32(regs, RTW_WAKEUP4HH); 327a72f7ea6Sql PRINTREG32(regs, RTW_DK0); 328a72f7ea6Sql PRINTREG32(regs, RTW_DK1); 329a72f7ea6Sql PRINTREG32(regs, RTW_DK2); 330a72f7ea6Sql PRINTREG32(regs, RTW_DK3); 331a72f7ea6Sql PRINTREG32(regs, RTW_RETRYCTR); 332a72f7ea6Sql PRINTREG32(regs, RTW_RDSAR); 333a72f7ea6Sql PRINTREG32(regs, RTW_FER); 334a72f7ea6Sql PRINTREG32(regs, RTW_FEMR); 335a72f7ea6Sql PRINTREG32(regs, RTW_FPSR); 336a72f7ea6Sql PRINTREG32(regs, RTW_FFER); 337a72f7ea6Sql 338a72f7ea6Sql /* 16-bit registers */ 339a72f7ea6Sql PRINTREG16(regs, RTW_BRSR); 340a72f7ea6Sql PRINTREG16(regs, RTW_IMR); 341a72f7ea6Sql PRINTREG16(regs, RTW_ISR); 342a72f7ea6Sql PRINTREG16(regs, RTW_BCNITV); 343a72f7ea6Sql PRINTREG16(regs, RTW_ATIMWND); 344a72f7ea6Sql PRINTREG16(regs, RTW_BINTRITV); 345a72f7ea6Sql PRINTREG16(regs, RTW_ATIMTRITV); 346a72f7ea6Sql PRINTREG16(regs, RTW_CRC16ERR); 347a72f7ea6Sql PRINTREG16(regs, RTW_CRC0); 348a72f7ea6Sql PRINTREG16(regs, RTW_CRC1); 349a72f7ea6Sql PRINTREG16(regs, RTW_CRC2); 350a72f7ea6Sql PRINTREG16(regs, RTW_CRC3); 351a72f7ea6Sql PRINTREG16(regs, RTW_CRC4); 352a72f7ea6Sql PRINTREG16(regs, RTW_CWR); 353a72f7ea6Sql 354a72f7ea6Sql /* 8-bit registers */ 355a72f7ea6Sql PRINTREG8(regs, RTW_CR); 356a72f7ea6Sql PRINTREG8(regs, RTW_9346CR); 357a72f7ea6Sql PRINTREG8(regs, RTW_CONFIG0); 358a72f7ea6Sql PRINTREG8(regs, RTW_CONFIG1); 359a72f7ea6Sql PRINTREG8(regs, RTW_CONFIG2); 360a72f7ea6Sql PRINTREG8(regs, RTW_MSR); 361a72f7ea6Sql PRINTREG8(regs, RTW_CONFIG3); 362a72f7ea6Sql PRINTREG8(regs, RTW_CONFIG4); 363a72f7ea6Sql PRINTREG8(regs, RTW_TESTR); 364a72f7ea6Sql PRINTREG8(regs, RTW_PSR); 365a72f7ea6Sql PRINTREG8(regs, RTW_SCR); 366a72f7ea6Sql PRINTREG8(regs, RTW_PHYDELAY); 367a72f7ea6Sql PRINTREG8(regs, RTW_CRCOUNT); 368a72f7ea6Sql PRINTREG8(regs, RTW_PHYADDR); 369a72f7ea6Sql PRINTREG8(regs, RTW_PHYDATAW); 370a72f7ea6Sql PRINTREG8(regs, RTW_PHYDATAR); 371a72f7ea6Sql PRINTREG8(regs, RTW_CONFIG5); 372a72f7ea6Sql PRINTREG8(regs, RTW_TPPOLL); 373a72f7ea6Sql 374a72f7ea6Sql PRINTREG16(regs, RTW_BSSID16); 375a72f7ea6Sql PRINTREG32(regs, RTW_BSSID32); 376a72f7ea6Sql #undef PRINTREG32 377a72f7ea6Sql #undef PRINTREG16 378a72f7ea6Sql #undef PRINTREG8 379a72f7ea6Sql } 380a72f7ea6Sql 381a72f7ea6Sql #endif /* DEBUG */ 382a72f7ea6Sql static const char * 383a72f7ea6Sql rtw_access_string(enum rtw_access access) 384a72f7ea6Sql { 385a72f7ea6Sql switch (access) { 386a72f7ea6Sql case RTW_ACCESS_NONE: 387a72f7ea6Sql return ("none"); 388a72f7ea6Sql case RTW_ACCESS_CONFIG: 389a72f7ea6Sql return ("config"); 390a72f7ea6Sql case RTW_ACCESS_ANAPARM: 391a72f7ea6Sql return ("anaparm"); 392a72f7ea6Sql default: 393a72f7ea6Sql return ("unknown"); 394a72f7ea6Sql } 395a72f7ea6Sql } 396a72f7ea6Sql 397a72f7ea6Sql /* 398a72f7ea6Sql * Enable registers, switch register banks. 399a72f7ea6Sql */ 400a72f7ea6Sql void 401a72f7ea6Sql rtw_config0123_enable(struct rtw_regs *regs, int enable) 402a72f7ea6Sql { 403a72f7ea6Sql uint8_t ecr; 404a72f7ea6Sql ecr = RTW_READ8(regs, RTW_9346CR); 405a72f7ea6Sql ecr &= ~(RTW_9346CR_EEM_MASK | RTW_9346CR_EECS | RTW_9346CR_EESK); 406a72f7ea6Sql if (enable) 407a72f7ea6Sql ecr |= RTW_9346CR_EEM_CONFIG; 408a72f7ea6Sql else { 409a72f7ea6Sql RTW_WBW(regs, RTW_9346CR, MAX(RTW_CONFIG0, RTW_CONFIG3)); 410a72f7ea6Sql ecr |= RTW_9346CR_EEM_NORMAL; 411a72f7ea6Sql } 412a72f7ea6Sql RTW_WRITE8(regs, RTW_9346CR, ecr); 413a72f7ea6Sql RTW_SYNC(regs, RTW_9346CR, RTW_9346CR); 414a72f7ea6Sql } 415a72f7ea6Sql 416a72f7ea6Sql /* 417a72f7ea6Sql * requires rtw_config0123_enable(, 1) 418a72f7ea6Sql */ 419a72f7ea6Sql void 420a72f7ea6Sql rtw_anaparm_enable(struct rtw_regs *regs, int enable) 421a72f7ea6Sql { 422a72f7ea6Sql uint8_t cfg3; 423a72f7ea6Sql 424a72f7ea6Sql cfg3 = RTW_READ8(regs, RTW_CONFIG3); 425a72f7ea6Sql cfg3 |= RTW_CONFIG3_CLKRUNEN; 426a72f7ea6Sql if (enable) 427a72f7ea6Sql cfg3 |= RTW_CONFIG3_PARMEN; 428a72f7ea6Sql else 429a72f7ea6Sql cfg3 &= ~RTW_CONFIG3_PARMEN; 430a72f7ea6Sql RTW_WRITE8(regs, RTW_CONFIG3, cfg3); 431a72f7ea6Sql RTW_SYNC(regs, RTW_CONFIG3, RTW_CONFIG3); 432a72f7ea6Sql } 433a72f7ea6Sql 434a72f7ea6Sql /* 435a72f7ea6Sql * requires rtw_anaparm_enable(, 1) 436a72f7ea6Sql */ 437a72f7ea6Sql void 438a72f7ea6Sql rtw_txdac_enable(rtw_softc_t *rsc, int enable) 439a72f7ea6Sql { 440a72f7ea6Sql uint32_t anaparm; 441a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 442a72f7ea6Sql 443a72f7ea6Sql anaparm = RTW_READ(regs, RTW_ANAPARM); 444a72f7ea6Sql if (enable) 445a72f7ea6Sql anaparm &= ~RTW_ANAPARM_TXDACOFF; 446a72f7ea6Sql else 447a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 448a72f7ea6Sql RTW_WRITE(regs, RTW_ANAPARM, anaparm); 449a72f7ea6Sql RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); 450a72f7ea6Sql } 451a72f7ea6Sql 452a72f7ea6Sql static void 453a72f7ea6Sql rtw_set_access1(struct rtw_regs *regs, enum rtw_access naccess) 454a72f7ea6Sql { 455a72f7ea6Sql ASSERT(naccess >= RTW_ACCESS_NONE && naccess <= RTW_ACCESS_ANAPARM); 456a72f7ea6Sql ASSERT(regs->r_access >= RTW_ACCESS_NONE && 457a72f7ea6Sql regs->r_access <= RTW_ACCESS_ANAPARM); 458a72f7ea6Sql 459a72f7ea6Sql if (naccess == regs->r_access) 460a72f7ea6Sql return; 461a72f7ea6Sql 462a72f7ea6Sql switch (naccess) { 463a72f7ea6Sql case RTW_ACCESS_NONE: 464a72f7ea6Sql switch (regs->r_access) { 465a72f7ea6Sql case RTW_ACCESS_ANAPARM: 466a72f7ea6Sql rtw_anaparm_enable(regs, 0); 467a72f7ea6Sql /*FALLTHROUGH*/ 468a72f7ea6Sql case RTW_ACCESS_CONFIG: 469a72f7ea6Sql rtw_config0123_enable(regs, 0); 470a72f7ea6Sql /*FALLTHROUGH*/ 471a72f7ea6Sql case RTW_ACCESS_NONE: 472a72f7ea6Sql break; 473a72f7ea6Sql } 474a72f7ea6Sql break; 475a72f7ea6Sql case RTW_ACCESS_CONFIG: 476a72f7ea6Sql switch (regs->r_access) { 477a72f7ea6Sql case RTW_ACCESS_NONE: 478a72f7ea6Sql rtw_config0123_enable(regs, 1); 479a72f7ea6Sql /*FALLTHROUGH*/ 480a72f7ea6Sql case RTW_ACCESS_CONFIG: 481a72f7ea6Sql break; 482a72f7ea6Sql case RTW_ACCESS_ANAPARM: 483a72f7ea6Sql rtw_anaparm_enable(regs, 0); 484a72f7ea6Sql break; 485a72f7ea6Sql } 486a72f7ea6Sql break; 487a72f7ea6Sql case RTW_ACCESS_ANAPARM: 488a72f7ea6Sql switch (regs->r_access) { 489a72f7ea6Sql case RTW_ACCESS_NONE: 490a72f7ea6Sql rtw_config0123_enable(regs, 1); 491a72f7ea6Sql /*FALLTHROUGH*/ 492a72f7ea6Sql case RTW_ACCESS_CONFIG: 493a72f7ea6Sql rtw_anaparm_enable(regs, 1); 494a72f7ea6Sql /*FALLTHROUGH*/ 495a72f7ea6Sql case RTW_ACCESS_ANAPARM: 496a72f7ea6Sql break; 497a72f7ea6Sql } 498a72f7ea6Sql break; 499a72f7ea6Sql } 500a72f7ea6Sql } 501a72f7ea6Sql 502a72f7ea6Sql void 503a72f7ea6Sql rtw_set_access(struct rtw_regs *regs, enum rtw_access access) 504a72f7ea6Sql { 505a72f7ea6Sql rtw_set_access1(regs, access); 506a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ACCESS, 507a72f7ea6Sql "%s: access %s -> %s\n", __func__, 508a72f7ea6Sql rtw_access_string(regs->r_access), 509a72f7ea6Sql rtw_access_string(access)); 510a72f7ea6Sql regs->r_access = access; 511a72f7ea6Sql } 512a72f7ea6Sql 513a72f7ea6Sql 514a72f7ea6Sql void 515a72f7ea6Sql rtw_continuous_tx_enable(rtw_softc_t *rsc, int enable) 516a72f7ea6Sql { 517a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 518a72f7ea6Sql 519a72f7ea6Sql uint32_t tcr; 520a72f7ea6Sql tcr = RTW_READ(regs, RTW_TCR); 521a72f7ea6Sql tcr &= ~RTW_TCR_LBK_MASK; 522a72f7ea6Sql if (enable) 523a72f7ea6Sql tcr |= RTW_TCR_LBK_CONT; 524a72f7ea6Sql else 525a72f7ea6Sql tcr |= RTW_TCR_LBK_NORMAL; 526a72f7ea6Sql RTW_WRITE(regs, RTW_TCR, tcr); 527a72f7ea6Sql RTW_SYNC(regs, RTW_TCR, RTW_TCR); 528a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_ANAPARM); 529a72f7ea6Sql rtw_txdac_enable(rsc, !enable); 530a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_ANAPARM); 531a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_NONE); 532a72f7ea6Sql } 533a72f7ea6Sql 534a72f7ea6Sql static int 535a72f7ea6Sql rtw_chip_reset1(struct rtw_regs *regs, const char *dvname) 536a72f7ea6Sql { 537a72f7ea6Sql uint8_t cr; 538a72f7ea6Sql int i; 539a72f7ea6Sql 540a72f7ea6Sql RTW_WRITE8(regs, RTW_CR, RTW_CR_RST); 541a72f7ea6Sql 542a72f7ea6Sql RTW_WBR(regs, RTW_CR, RTW_CR); 543a72f7ea6Sql 544a72f7ea6Sql for (i = 0; i < 1000; i++) { 545a72f7ea6Sql cr = RTW_READ8(regs, RTW_CR); 546a72f7ea6Sql if ((cr & RTW_CR_RST) == 0) { 547a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RESET, 548a72f7ea6Sql "%s: reset in %dus\n", dvname, i); 549a72f7ea6Sql return (0); 550a72f7ea6Sql } 551a72f7ea6Sql RTW_RBR(regs, RTW_CR, RTW_CR); 552a72f7ea6Sql DELAY(10); /* 10us */ 553a72f7ea6Sql } 554a72f7ea6Sql 555a72f7ea6Sql cmn_err(CE_WARN, "%s: reset failed\n", dvname); 556a72f7ea6Sql return (ETIMEDOUT); 557a72f7ea6Sql } 558a72f7ea6Sql 559a72f7ea6Sql static int 560a72f7ea6Sql rtw_chip_reset(struct rtw_regs *regs, const char *dvname) 561a72f7ea6Sql { 562a72f7ea6Sql RTW_WBW(regs, RTW_CR, RTW_TCR); 563a72f7ea6Sql return (rtw_chip_reset1(regs, dvname)); 564a72f7ea6Sql } 565a72f7ea6Sql 566a72f7ea6Sql static void 567a72f7ea6Sql rtw_disable_interrupts(struct rtw_regs *regs) 568a72f7ea6Sql { 569a72f7ea6Sql RTW_WRITE16(regs, RTW_IMR, 0); 570a72f7ea6Sql RTW_WRITE16(regs, RTW_ISR, 0xffff); 571a72f7ea6Sql (void) RTW_READ16(regs, RTW_IMR); 572a72f7ea6Sql } 573a72f7ea6Sql 574a72f7ea6Sql static void 575a72f7ea6Sql rtw_enable_interrupts(rtw_softc_t *rsc) 576a72f7ea6Sql { 577a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 578a72f7ea6Sql 579a72f7ea6Sql rsc->sc_inten = RTW_INTR_RX | RTW_INTR_TX | RTW_INTR_IOERROR; 580a72f7ea6Sql 581a72f7ea6Sql RTW_WRITE16(regs, RTW_IMR, rsc->sc_inten); 582a72f7ea6Sql RTW_WRITE16(regs, RTW_ISR, 0xffff); 583a72f7ea6Sql 584a72f7ea6Sql /* XXX necessary? */ 585a72f7ea6Sql if (rsc->sc_intr_ack != NULL) 586a72f7ea6Sql (*rsc->sc_intr_ack)(regs); 587a72f7ea6Sql } 588a72f7ea6Sql 589a72f7ea6Sql static int 590a72f7ea6Sql rtw_recall_eeprom(struct rtw_regs *regs, const char *dvname) 591a72f7ea6Sql { 592a72f7ea6Sql int i; 593a72f7ea6Sql uint8_t ecr; 594a72f7ea6Sql 595a72f7ea6Sql ecr = RTW_READ8(regs, RTW_9346CR); 596a72f7ea6Sql ecr = (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_AUTOLOAD; 597a72f7ea6Sql RTW_WRITE8(regs, RTW_9346CR, ecr); 598a72f7ea6Sql 599a72f7ea6Sql RTW_WBR(regs, RTW_9346CR, RTW_9346CR); 600a72f7ea6Sql 601a72f7ea6Sql /* wait 25ms for completion */ 602a72f7ea6Sql for (i = 0; i < 250; i++) { 603a72f7ea6Sql ecr = RTW_READ8(regs, RTW_9346CR); 604a72f7ea6Sql if ((ecr & RTW_9346CR_EEM_MASK) == RTW_9346CR_EEM_NORMAL) { 605a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RESET, 606a72f7ea6Sql "%s: recall EEPROM in %dus\n", dvname, i * 100); 607a72f7ea6Sql return (0); 608a72f7ea6Sql } 609a72f7ea6Sql RTW_RBR(regs, RTW_9346CR, RTW_9346CR); 610a72f7ea6Sql DELAY(100); 611a72f7ea6Sql } 612a72f7ea6Sql cmn_err(CE_WARN, "%s: recall EEPROM failed\n", dvname); 613a72f7ea6Sql return (ETIMEDOUT); 614a72f7ea6Sql } 615a72f7ea6Sql 616a72f7ea6Sql static int 617a72f7ea6Sql rtw_reset(rtw_softc_t *rsc) 618a72f7ea6Sql { 619a72f7ea6Sql int rc; 620a72f7ea6Sql 621a72f7ea6Sql rc = rtw_chip_reset(&rsc->sc_regs, "rtw"); 622a72f7ea6Sql if (rc != 0) 623a72f7ea6Sql return (rc); 624a72f7ea6Sql 625a72f7ea6Sql (void) rtw_recall_eeprom(&rsc->sc_regs, "rtw"); 626a72f7ea6Sql return (0); 627a72f7ea6Sql } 628a72f7ea6Sql 629a72f7ea6Sql void 630a72f7ea6Sql rtw_set_mode(struct rtw_regs *regs, int mode) 631a72f7ea6Sql { 632a72f7ea6Sql uint8_t command; 633a72f7ea6Sql command = RTW_READ8(regs, RTW_9346CR); 634a72f7ea6Sql command = command &~ RTW_EPROM_CMD_OPERATING_MODE_MASK; 635a72f7ea6Sql command = command | (mode<<RTW_EPROM_CMD_OPERATING_MODE_SHIFT); 636a72f7ea6Sql command = command &~ (1<<RTW_EPROM_CS_SHIFT); 637a72f7ea6Sql command = command &~ (1<<RTW_EPROM_CK_SHIFT); 638a72f7ea6Sql RTW_WRITE8(regs, RTW_9346CR, command); 639a72f7ea6Sql } 640a72f7ea6Sql 641a72f7ea6Sql void 642a72f7ea6Sql rtw_dma_start(struct rtw_regs *regs, int priority) 643a72f7ea6Sql { 644a72f7ea6Sql uint8_t check = 0; 645a72f7ea6Sql 646a72f7ea6Sql check = RTW_READ8(regs, RTW_TPPOLL); 647a72f7ea6Sql switch (priority) { 648a72f7ea6Sql case (0): 649a72f7ea6Sql RTW_WRITE8(regs, RTW_TPPOLL, 650a72f7ea6Sql (1<< RTW_TX_DMA_POLLING_LOWPRIORITY_SHIFT) | check); 651a72f7ea6Sql break; 652a72f7ea6Sql case (1): 653a72f7ea6Sql RTW_WRITE8(regs, RTW_TPPOLL, 654a72f7ea6Sql (1<< RTW_TX_DMA_POLLING_NORMPRIORITY_SHIFT) | check); 655a72f7ea6Sql break; 656a72f7ea6Sql case (2): 657a72f7ea6Sql RTW_WRITE8(regs, RTW_TPPOLL, 658a72f7ea6Sql (1<< RTW_TX_DMA_POLLING_HIPRIORITY_SHIFT) | check); 659a72f7ea6Sql break; 660a72f7ea6Sql } 661a72f7ea6Sql (void) RTW_READ8(regs, RTW_TPPOLL); 662a72f7ea6Sql } 663a72f7ea6Sql 664a72f7ea6Sql void 665a72f7ea6Sql rtw_beacon_tx_disable(struct rtw_regs *regs) 666a72f7ea6Sql { 667a72f7ea6Sql uint8_t mask = 0; 668a72f7ea6Sql mask |= (1 << RTW_TX_DMA_STOP_BEACON_SHIFT); 669a72f7ea6Sql rtw_set_mode(regs, RTW_EPROM_CMD_CONFIG); 670a72f7ea6Sql RTW_WRITE8(regs, RTW_TPPOLL, mask); 671a72f7ea6Sql rtw_set_mode(regs, RTW_EPROM_CMD_NORMAL); 672a72f7ea6Sql } 673a72f7ea6Sql 674a72f7ea6Sql static void 675a72f7ea6Sql rtw_io_enable(rtw_softc_t *rsc, uint8_t flags, int enable); 676a72f7ea6Sql 677a72f7ea6Sql void 678a72f7ea6Sql rtw_rtx_disable(rtw_softc_t *rsc) 679a72f7ea6Sql { 680a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 681a72f7ea6Sql 682a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE|RTW_CR_TE, 0); 683a72f7ea6Sql (void) RTW_READ8(regs, RTW_CR); 684a72f7ea6Sql } 685a72f7ea6Sql 686a72f7ea6Sql static void 687a72f7ea6Sql rtw_srom_free(struct rtw_srom *sr) 688a72f7ea6Sql { 689a72f7ea6Sql if (sr->sr_content == NULL) 690a72f7ea6Sql return; 691a72f7ea6Sql kmem_free(sr->sr_content, sr->sr_size); 692a72f7ea6Sql sr->sr_size = 0; 693a72f7ea6Sql sr->sr_content = NULL; 694a72f7ea6Sql } 695a72f7ea6Sql 696a72f7ea6Sql /*ARGSUSED*/ 697a72f7ea6Sql static void 698a72f7ea6Sql rtw_srom_defaults(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold, 699a72f7ea6Sql enum rtw_rfchipid *rfchipid, uint32_t *rcr) 700a72f7ea6Sql { 701a72f7ea6Sql *flags |= (RTW_F_DIGPHY|RTW_F_ANTDIV); 702a72f7ea6Sql *cs_threshold = RTW_SR_ENERGYDETTHR_DEFAULT; 703a72f7ea6Sql *rcr |= RTW_RCR_ENCS1; 704a72f7ea6Sql *rfchipid = RTW_RFCHIPID_PHILIPS; 705a72f7ea6Sql } 706a72f7ea6Sql 707a72f7ea6Sql static int 708a72f7ea6Sql rtw_srom_parse(struct rtw_srom *sr, uint32_t *flags, uint8_t *cs_threshold, 709a72f7ea6Sql enum rtw_rfchipid *rfchipid, uint32_t *rcr, enum rtw_locale *locale, 710a72f7ea6Sql const char *dvname) 711a72f7ea6Sql { 712a72f7ea6Sql int i; 713a72f7ea6Sql const char *rfname, *paname; 714a72f7ea6Sql char scratch[sizeof ("unknown 0xXX")]; 715a72f7ea6Sql uint16_t version; 716a72f7ea6Sql uint8_t mac[IEEE80211_ADDR_LEN]; 717a72f7ea6Sql 718a72f7ea6Sql *flags &= ~(RTW_F_DIGPHY|RTW_F_DFLANTB|RTW_F_ANTDIV); 719a72f7ea6Sql *rcr &= ~(RTW_RCR_ENCS1 | RTW_RCR_ENCS2); 720a72f7ea6Sql 721a72f7ea6Sql version = RTW_SR_GET16(sr, RTW_SR_VERSION); 722a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_IOSTATE, "%s: SROM version %d.%d", dvname, 723a72f7ea6Sql version >> 8, version & 0xff); 724a72f7ea6Sql 725a72f7ea6Sql if (version <= 0x0101) { 726a72f7ea6Sql cmn_err(CE_NOTE, " is not understood, limping along " 727a72f7ea6Sql "with defaults\n"); 728a72f7ea6Sql rtw_srom_defaults(sr, flags, cs_threshold, rfchipid, rcr); 729a72f7ea6Sql return (0); 730a72f7ea6Sql } 731a72f7ea6Sql 732a72f7ea6Sql for (i = 0; i < IEEE80211_ADDR_LEN; i++) 733a72f7ea6Sql mac[i] = RTW_SR_GET(sr, RTW_SR_MAC + i); 734a72f7ea6Sql 735a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 736a72f7ea6Sql "%s: EEPROM MAC %s\n", dvname, mac); 737a72f7ea6Sql 738a72f7ea6Sql *cs_threshold = RTW_SR_GET(sr, RTW_SR_ENERGYDETTHR); 739a72f7ea6Sql 740a72f7ea6Sql if ((RTW_SR_GET(sr, RTW_SR_CONFIG2) & RTW_CONFIG2_ANT) != 0) 741a72f7ea6Sql *flags |= RTW_F_ANTDIV; 742a72f7ea6Sql 743a72f7ea6Sql /* 744a72f7ea6Sql * Note well: the sense of the RTW_SR_RFPARM_DIGPHY bit seems 745a72f7ea6Sql * to be reversed. 746a72f7ea6Sql */ 747a72f7ea6Sql if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DIGPHY) == 0) 748a72f7ea6Sql *flags |= RTW_F_DIGPHY; 749a72f7ea6Sql if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DFLANTB) != 0) 750a72f7ea6Sql *flags |= RTW_F_DFLANTB; 751a72f7ea6Sql 752a72f7ea6Sql *rcr |= LSHIFT(MASK_AND_RSHIFT(RTW_SR_GET(sr, RTW_SR_RFPARM), 753a72f7ea6Sql RTW_SR_RFPARM_CS_MASK), RTW_RCR_ENCS1); 754a72f7ea6Sql 755a72f7ea6Sql *rfchipid = RTW_SR_GET(sr, RTW_SR_RFCHIPID); 756a72f7ea6Sql switch (*rfchipid) { 757a72f7ea6Sql case RTW_RFCHIPID_GCT: /* this combo seen in the wild */ 758a72f7ea6Sql rfname = "GCT GRF5101"; 759a72f7ea6Sql paname = "Winspring WS9901"; 760a72f7ea6Sql break; 761a72f7ea6Sql case RTW_RFCHIPID_MAXIM: 762a72f7ea6Sql rfname = "Maxim MAX2820"; /* guess */ 763a72f7ea6Sql paname = "Maxim MAX2422"; /* guess */ 764a72f7ea6Sql break; 765a72f7ea6Sql case RTW_RFCHIPID_INTERSIL: 766a72f7ea6Sql rfname = "Intersil HFA3873"; /* guess */ 767a72f7ea6Sql paname = "Intersil <unknown>"; 768a72f7ea6Sql break; 769a72f7ea6Sql case RTW_RFCHIPID_PHILIPS: /* this combo seen in the wild */ 770a72f7ea6Sql rfname = "Philips SA2400A"; 771a72f7ea6Sql paname = "Philips SA2411"; 772a72f7ea6Sql break; 773a72f7ea6Sql case RTW_RFCHIPID_RFMD: 774a72f7ea6Sql /* 775a72f7ea6Sql * this is the same front-end as an atw(4)! 776a72f7ea6Sql */ 777a72f7ea6Sql rfname = "RFMD RF2948B, " /* mentioned in Realtek docs */ 778a72f7ea6Sql "LNA: RFMD RF2494, " /* mentioned in Realtek docs */ 779a72f7ea6Sql "SYN: Silicon Labs Si4126"; 780a72f7ea6Sql paname = "RFMD RF2189"; /* mentioned in Realtek docs */ 781a72f7ea6Sql break; 782a72f7ea6Sql case RTW_RFCHIPID_RESERVED: 783a72f7ea6Sql rfname = paname = "reserved"; 784a72f7ea6Sql break; 785a72f7ea6Sql default: 786a72f7ea6Sql (void) snprintf(scratch, sizeof (scratch), 787a72f7ea6Sql "unknown 0x%02x", *rfchipid); 788a72f7ea6Sql rfname = paname = scratch; 789a72f7ea6Sql } 790a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PHY, "%s: RF: %s, PA: %s\n", 791a72f7ea6Sql dvname, rfname, paname); 792a72f7ea6Sql 793a72f7ea6Sql switch (RTW_SR_GET(sr, RTW_SR_CONFIG0) & RTW_CONFIG0_GL_MASK) { 794a72f7ea6Sql case RTW_CONFIG0_GL_USA: 795a72f7ea6Sql *locale = RTW_LOCALE_USA; 796a72f7ea6Sql break; 797a72f7ea6Sql case RTW_CONFIG0_GL_EUROPE: 798a72f7ea6Sql *locale = RTW_LOCALE_EUROPE; 799a72f7ea6Sql break; 800a72f7ea6Sql case RTW_CONFIG0_GL_JAPAN: 801a72f7ea6Sql *locale = RTW_LOCALE_JAPAN; 802a72f7ea6Sql break; 803a72f7ea6Sql default: 804a72f7ea6Sql *locale = RTW_LOCALE_UNKNOWN; 805a72f7ea6Sql break; 806a72f7ea6Sql } 807a72f7ea6Sql return (0); 808a72f7ea6Sql } 809a72f7ea6Sql 810a72f7ea6Sql /* 811a72f7ea6Sql * Returns -1 on failure. 812a72f7ea6Sql */ 813a72f7ea6Sql static int 814a72f7ea6Sql rtw_srom_read(struct rtw_regs *regs, uint32_t flags, struct rtw_srom *sr, 815a72f7ea6Sql const char *dvname) 816a72f7ea6Sql { 817a72f7ea6Sql int rc; 818a72f7ea6Sql struct seeprom_descriptor sd; 819a72f7ea6Sql uint8_t ecr; 820a72f7ea6Sql 821a72f7ea6Sql (void) memset(&sd, 0, sizeof (sd)); 822a72f7ea6Sql 823a72f7ea6Sql ecr = RTW_READ8(regs, RTW_9346CR); 824a72f7ea6Sql 825a72f7ea6Sql if ((flags & RTW_F_9356SROM) != 0) { 826a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: 93c56 SROM\n", dvname); 827a72f7ea6Sql sr->sr_size = 256; 828a72f7ea6Sql sd.sd_chip = C56_66; 829a72f7ea6Sql } else { 830a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: 93c46 SROM\n", dvname); 831a72f7ea6Sql sr->sr_size = 128; 832a72f7ea6Sql sd.sd_chip = C46; 833a72f7ea6Sql } 834a72f7ea6Sql 835a72f7ea6Sql ecr &= ~(RTW_9346CR_EEDI | RTW_9346CR_EEDO | RTW_9346CR_EESK | 836a72f7ea6Sql RTW_9346CR_EEM_MASK | RTW_9346CR_EECS); 837a72f7ea6Sql ecr |= RTW_9346CR_EEM_PROGRAM; 838a72f7ea6Sql 839a72f7ea6Sql RTW_WRITE8(regs, RTW_9346CR, ecr); 840a72f7ea6Sql 841a72f7ea6Sql sr->sr_content = kmem_zalloc(sr->sr_size, KM_SLEEP); 842a72f7ea6Sql 843a72f7ea6Sql if (sr->sr_content == NULL) { 844a72f7ea6Sql cmn_err(CE_WARN, "%s: unable to allocate SROM buffer\n", 845a72f7ea6Sql dvname); 846a72f7ea6Sql return (ENOMEM); 847a72f7ea6Sql } 848a72f7ea6Sql 849a72f7ea6Sql (void) memset(sr->sr_content, 0, sr->sr_size); 850a72f7ea6Sql 851a72f7ea6Sql /* 852a72f7ea6Sql * RTL8180 has a single 8-bit register for controlling the 853a72f7ea6Sql * 93cx6 SROM. There is no "ready" bit. The RTL8180 854a72f7ea6Sql * input/output sense is the reverse of read_seeprom's. 855a72f7ea6Sql */ 856a72f7ea6Sql sd.sd_handle = regs->r_handle; 857a72f7ea6Sql sd.sd_base = regs->r_base; 858a72f7ea6Sql sd.sd_regsize = 1; 859a72f7ea6Sql sd.sd_control_offset = RTW_9346CR; 860a72f7ea6Sql sd.sd_status_offset = RTW_9346CR; 861a72f7ea6Sql sd.sd_dataout_offset = RTW_9346CR; 862a72f7ea6Sql sd.sd_CK = RTW_9346CR_EESK; 863a72f7ea6Sql sd.sd_CS = RTW_9346CR_EECS; 864a72f7ea6Sql sd.sd_DI = RTW_9346CR_EEDO; 865a72f7ea6Sql sd.sd_DO = RTW_9346CR_EEDI; 866a72f7ea6Sql /* 867a72f7ea6Sql * make read_seeprom enter EEPROM read/write mode 868a72f7ea6Sql */ 869a72f7ea6Sql sd.sd_MS = ecr; 870a72f7ea6Sql sd.sd_RDY = 0; 871a72f7ea6Sql 872a72f7ea6Sql /* 873a72f7ea6Sql * TBD bus barriers 874a72f7ea6Sql */ 875a72f7ea6Sql if (!read_seeprom(&sd, sr->sr_content, 0, sr->sr_size/2)) { 876a72f7ea6Sql cmn_err(CE_WARN, "%s: could not read SROM\n", dvname); 877a72f7ea6Sql kmem_free(sr->sr_content, sr->sr_size); 878a72f7ea6Sql sr->sr_content = NULL; 879a72f7ea6Sql return (-1); /* XXX */ 880a72f7ea6Sql } 881a72f7ea6Sql 882a72f7ea6Sql /* 883a72f7ea6Sql * end EEPROM read/write mode 884a72f7ea6Sql */ 885a72f7ea6Sql RTW_WRITE8(regs, RTW_9346CR, 886a72f7ea6Sql (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_NORMAL); 887a72f7ea6Sql RTW_WBRW(regs, RTW_9346CR, RTW_9346CR); 888a72f7ea6Sql 889a72f7ea6Sql if ((rc = rtw_recall_eeprom(regs, dvname)) != 0) 890a72f7ea6Sql return (rc); 891a72f7ea6Sql 892a72f7ea6Sql #ifdef SROM_DEBUG 893a72f7ea6Sql { 894a72f7ea6Sql int i; 895a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 896a72f7ea6Sql "\n%s: serial ROM:\n\t", dvname); 897a72f7ea6Sql for (i = 0; i < sr->sr_size/2; i++) { 898a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 899a72f7ea6Sql "offset-0x%x: %04x", 2*i, sr->sr_content[i]); 900a72f7ea6Sql } 901a72f7ea6Sql } 902a72f7ea6Sql #endif /* DEBUG */ 903a72f7ea6Sql return (0); 904a72f7ea6Sql } 905a72f7ea6Sql 906a72f7ea6Sql static void 907a72f7ea6Sql rtw_set_rfprog(struct rtw_regs *regs, enum rtw_rfchipid rfchipid, 908a72f7ea6Sql const char *dvname) 909a72f7ea6Sql { 910a72f7ea6Sql uint8_t cfg4; 911a72f7ea6Sql const char *method; 912a72f7ea6Sql 913a72f7ea6Sql cfg4 = RTW_READ8(regs, RTW_CONFIG4) & ~RTW_CONFIG4_RFTYPE_MASK; 914a72f7ea6Sql 915a72f7ea6Sql switch (rfchipid) { 916a72f7ea6Sql default: 917a72f7ea6Sql cfg4 |= LSHIFT(0, RTW_CONFIG4_RFTYPE_MASK); 918a72f7ea6Sql method = "fallback"; 919a72f7ea6Sql break; 920a72f7ea6Sql case RTW_RFCHIPID_INTERSIL: 921a72f7ea6Sql cfg4 |= RTW_CONFIG4_RFTYPE_INTERSIL; 922a72f7ea6Sql method = "Intersil"; 923a72f7ea6Sql break; 924a72f7ea6Sql case RTW_RFCHIPID_PHILIPS: 925a72f7ea6Sql cfg4 |= RTW_CONFIG4_RFTYPE_PHILIPS; 926a72f7ea6Sql method = "Philips"; 927a72f7ea6Sql break; 928a72f7ea6Sql case RTW_RFCHIPID_GCT: /* XXX a guess */ 929a72f7ea6Sql case RTW_RFCHIPID_RFMD: 930a72f7ea6Sql cfg4 |= RTW_CONFIG4_RFTYPE_RFMD; 931a72f7ea6Sql method = "RFMD"; 932a72f7ea6Sql break; 933a72f7ea6Sql } 934a72f7ea6Sql 935a72f7ea6Sql RTW_WRITE8(regs, RTW_CONFIG4, cfg4); 936a72f7ea6Sql 937a72f7ea6Sql RTW_WBR(regs, RTW_CONFIG4, RTW_CONFIG4); 938a72f7ea6Sql 939a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_INIT, 940a72f7ea6Sql "%s: %s RF programming method, %02x\n", dvname, method, 941a72f7ea6Sql RTW_READ8(regs, RTW_CONFIG4)); 942a72f7ea6Sql } 943a72f7ea6Sql 944a72f7ea6Sql static void 945a72f7ea6Sql rtw_init_channels(enum rtw_locale locale, 946a72f7ea6Sql struct ieee80211_channel (*chans)[IEEE80211_CHAN_MAX+1], 947a72f7ea6Sql const char *dvname) 948a72f7ea6Sql { 949a72f7ea6Sql int i; 950a72f7ea6Sql const char *name = NULL; 951a72f7ea6Sql #define ADD_CHANNEL(_chans, _chan) { \ 952a72f7ea6Sql (*_chans)[_chan].ich_flags = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK;\ 953a72f7ea6Sql (*_chans)[_chan].ich_freq = \ 954a72f7ea6Sql ieee80211_ieee2mhz(_chan, (*_chans)[_chan].ich_flags);\ 955a72f7ea6Sql } 956a72f7ea6Sql 957a72f7ea6Sql switch (locale) { 958a72f7ea6Sql case RTW_LOCALE_USA: /* 1-11 */ 959a72f7ea6Sql name = "USA"; 960a72f7ea6Sql for (i = 1; i <= 11; i++) 961a72f7ea6Sql ADD_CHANNEL(chans, i); 962a72f7ea6Sql break; 963a72f7ea6Sql case RTW_LOCALE_JAPAN: /* 1-14 */ 964a72f7ea6Sql name = "Japan"; 965a72f7ea6Sql ADD_CHANNEL(chans, 14); 966a72f7ea6Sql for (i = 1; i <= 14; i++) 967a72f7ea6Sql ADD_CHANNEL(chans, i); 968a72f7ea6Sql break; 969a72f7ea6Sql case RTW_LOCALE_EUROPE: /* 1-13 */ 970a72f7ea6Sql name = "Europe"; 971a72f7ea6Sql for (i = 1; i <= 13; i++) 972a72f7ea6Sql ADD_CHANNEL(chans, i); 973a72f7ea6Sql break; 974a72f7ea6Sql default: /* 10-11 allowed by most countries */ 975a72f7ea6Sql name = "<unknown>"; 976a72f7ea6Sql for (i = 10; i <= 11; i++) 977a72f7ea6Sql ADD_CHANNEL(chans, i); 978a72f7ea6Sql break; 979a72f7ea6Sql } 980a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "%s: Geographic Location %s\n", 981a72f7ea6Sql dvname, name); 982a72f7ea6Sql #undef ADD_CHANNEL 983a72f7ea6Sql } 984a72f7ea6Sql 985a72f7ea6Sql static void 986a72f7ea6Sql rtw_set80211props(struct ieee80211com *ic) 987a72f7ea6Sql { 988a72f7ea6Sql ic->ic_phytype = IEEE80211_T_DS; 989a72f7ea6Sql ic->ic_opmode = IEEE80211_M_STA; 990a72f7ea6Sql ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_IBSS | 991*94d05f6cSQin Michael Li IEEE80211_C_SHPREAMBLE; 992*94d05f6cSQin Michael Li /* IEEE80211_C_HOSTAP | IEEE80211_C_MONITOR | IEEE80211_C_WEP */ 993a72f7ea6Sql 994*94d05f6cSQin Michael Li ic->ic_sup_rates[IEEE80211_MODE_11B] = rtw_rateset_11b; 995a72f7ea6Sql } 996a72f7ea6Sql 997a72f7ea6Sql /*ARGSUSED*/ 998a72f7ea6Sql static void 999a72f7ea6Sql rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale, 1000a72f7ea6Sql const char *dvname) 1001a72f7ea6Sql { 1002a72f7ea6Sql uint8_t cfg0 = RTW_READ8(regs, RTW_CONFIG0); 1003a72f7ea6Sql 1004a72f7ea6Sql switch (cfg0 & RTW_CONFIG0_GL_MASK) { 1005a72f7ea6Sql case RTW_CONFIG0_GL_USA: 1006a72f7ea6Sql *locale = RTW_LOCALE_USA; 1007a72f7ea6Sql break; 1008a72f7ea6Sql case RTW_CONFIG0_GL_JAPAN: 1009a72f7ea6Sql *locale = RTW_LOCALE_JAPAN; 1010a72f7ea6Sql break; 1011a72f7ea6Sql case RTW_CONFIG0_GL_EUROPE: 1012a72f7ea6Sql *locale = RTW_LOCALE_EUROPE; 1013a72f7ea6Sql break; 1014a72f7ea6Sql default: 1015a72f7ea6Sql *locale = RTW_LOCALE_UNKNOWN; 1016a72f7ea6Sql break; 1017a72f7ea6Sql } 1018a72f7ea6Sql } 1019a72f7ea6Sql 1020a72f7ea6Sql static int 1021a72f7ea6Sql rtw_identify_sta(struct rtw_regs *regs, uint8_t *addr, 1022a72f7ea6Sql const char *dvname) 1023a72f7ea6Sql { 1024a72f7ea6Sql uint32_t idr0 = RTW_READ(regs, RTW_IDR0), 1025a72f7ea6Sql idr1 = RTW_READ(regs, RTW_IDR1); 1026a72f7ea6Sql 1027a72f7ea6Sql *addr = MASK_AND_RSHIFT(idr0, BITS(0, 7)); 1028a72f7ea6Sql *(addr + 1) = MASK_AND_RSHIFT(idr0, BITS(8, 15)); 1029a72f7ea6Sql *(addr + 2) = MASK_AND_RSHIFT(idr0, BITS(16, 23)); 1030a72f7ea6Sql *(addr + 3) = MASK_AND_RSHIFT(idr0, BITS(24, 31)); 1031a72f7ea6Sql 1032a72f7ea6Sql *(addr + 4) = MASK_AND_RSHIFT(idr1, BITS(0, 7)); 1033a72f7ea6Sql *(addr + 5) = MASK_AND_RSHIFT(idr1, BITS(8, 15)); 1034a72f7ea6Sql 1035a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 1036a72f7ea6Sql "%s: 802.11mac address %x:%x:%x:%x:%x:%x\n", dvname, 1037a72f7ea6Sql *addr, *(addr+1), *(addr+2), *(addr+3), *(addr+4), *(addr+5)); 1038a72f7ea6Sql 1039a72f7ea6Sql return (0); 1040a72f7ea6Sql } 1041a72f7ea6Sql 1042a72f7ea6Sql static uint8_t 1043a72f7ea6Sql rtw_chan2txpower(struct rtw_srom *sr, struct ieee80211com *ic, 1044a72f7ea6Sql struct ieee80211_channel *chan) 1045a72f7ea6Sql { 1046a72f7ea6Sql uint32_t idx = RTW_SR_TXPOWER1 + ieee80211_chan2ieee(ic, chan) - 1; 1047a72f7ea6Sql return (RTW_SR_GET(sr, idx)); 1048a72f7ea6Sql } 1049a72f7ea6Sql 1050a72f7ea6Sql static void 1051a72f7ea6Sql rtw_rxdesc_init(rtw_softc_t *rsc, struct rtw_rxbuf *rbf, int idx, int is_last) 1052a72f7ea6Sql { 1053a72f7ea6Sql uint32_t ctl = 0; 1054a72f7ea6Sql uint8_t *buf = (uint8_t *)rbf->bf_dma.mem_va; 1055a72f7ea6Sql 1056a72f7ea6Sql ASSERT(rbf != NULL); 1057a72f7ea6Sql rbf->rxdesc->rd_buf = (rbf->bf_dma.cookie.dmac_address); 1058a72f7ea6Sql bzero(buf, rbf->bf_dma.alength); 1059a72f7ea6Sql RTW_DMA_SYNC(rbf->bf_dma, DDI_DMA_SYNC_FORDEV); 1060a72f7ea6Sql 1061a72f7ea6Sql ctl = (rbf->bf_dma.alength & 0xfff) | RTW_RXCTL_OWN; 1062a72f7ea6Sql 1063a72f7ea6Sql if (is_last) 1064a72f7ea6Sql ctl |= RTW_RXCTL_EOR; 1065a72f7ea6Sql 1066a72f7ea6Sql rbf->rxdesc->rd_ctl = (ctl); 1067a72f7ea6Sql /* sync the mbuf */ 1068a72f7ea6Sql 1069a72f7ea6Sql /* sync the descriptor */ 1070a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 1071a72f7ea6Sql RTW_DESC_OFFSET(hd_rx, idx), 1072a72f7ea6Sql sizeof (struct rtw_rxdesc), 1073a72f7ea6Sql DDI_DMA_SYNC_FORDEV); 1074a72f7ea6Sql } 1075a72f7ea6Sql 1076a72f7ea6Sql static void 1077a72f7ea6Sql rtw_idle(struct rtw_regs *regs) 1078a72f7ea6Sql { 1079a72f7ea6Sql int active; 1080a72f7ea6Sql 1081a72f7ea6Sql /* request stop DMA; wait for packets to stop transmitting. */ 1082a72f7ea6Sql 1083a72f7ea6Sql RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL); 1084a72f7ea6Sql 1085a72f7ea6Sql for (active = 0; active < 300 && 1086*94d05f6cSQin Michael Li (RTW_READ8(regs, RTW_TPPOLL) & RTW_TPPOLL_ALL) != 0; active++) 1087a72f7ea6Sql drv_usecwait(10); 1088a72f7ea6Sql } 1089a72f7ea6Sql 1090a72f7ea6Sql static void 1091a72f7ea6Sql rtw_io_enable(rtw_softc_t *rsc, uint8_t flags, int enable) 1092a72f7ea6Sql { 1093a72f7ea6Sql uint8_t cr; 1094a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 1095a72f7ea6Sql 1096a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_IOSTATE, "%s: %s 0x%02x\n", __func__, 1097a72f7ea6Sql enable ? "enable" : "disable", flags); 1098a72f7ea6Sql 1099a72f7ea6Sql cr = RTW_READ8(regs, RTW_CR); 1100*94d05f6cSQin Michael Li 1101a72f7ea6Sql /* The receive engine will always start at RDSAR. */ 1102a72f7ea6Sql if (enable && (flags & ~cr & RTW_CR_RE)) { 1103a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 1104a72f7ea6Sql RTW_DESC_OFFSET(hd_rx, 0), 1105a72f7ea6Sql sizeof (struct rtw_rxdesc), 1106a72f7ea6Sql DDI_DMA_SYNC_FORCPU); 1107a72f7ea6Sql rsc->rx_next = 0; 1108a72f7ea6Sql rtw_rxdesc_init(rsc, rsc->rxbuf_h, 0, 0); 1109a72f7ea6Sql } 1110*94d05f6cSQin Michael Li 1111a72f7ea6Sql if (enable) 1112a72f7ea6Sql cr |= flags; 1113a72f7ea6Sql else 1114a72f7ea6Sql cr &= ~flags; 1115a72f7ea6Sql RTW_WRITE8(regs, RTW_CR, cr); 1116a72f7ea6Sql (void) RTW_READ8(regs, RTW_CR); 1117a72f7ea6Sql } 1118a72f7ea6Sql 1119a72f7ea6Sql /* 1120a72f7ea6Sql * Allocate an area of memory and a DMA handle for accessing it 1121a72f7ea6Sql */ 1122a72f7ea6Sql static int 1123a72f7ea6Sql rtw_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr, 1124a72f7ea6Sql size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags, 1125a72f7ea6Sql uint_t bind_flags, dma_area_t *dma_p) 1126a72f7ea6Sql { 1127a72f7ea6Sql int err; 1128a72f7ea6Sql 1129a72f7ea6Sql /* 1130a72f7ea6Sql * Allocate handle 1131a72f7ea6Sql */ 1132a72f7ea6Sql err = ddi_dma_alloc_handle(devinfo, dma_attr, 1133a72f7ea6Sql DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 1134a72f7ea6Sql if (err != DDI_SUCCESS) 1135a72f7ea6Sql return (DDI_FAILURE); 1136a72f7ea6Sql 1137a72f7ea6Sql /* 1138a72f7ea6Sql * Allocate memory 1139a72f7ea6Sql */ 1140a72f7ea6Sql err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 1141a72f7ea6Sql alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va, 1142a72f7ea6Sql &dma_p->alength, &dma_p->acc_hdl); 1143a72f7ea6Sql if (err != DDI_SUCCESS) 1144a72f7ea6Sql return (DDI_FAILURE); 1145a72f7ea6Sql 1146a72f7ea6Sql /* 1147a72f7ea6Sql * Bind the two together 1148a72f7ea6Sql */ 1149a72f7ea6Sql err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 1150a72f7ea6Sql dma_p->mem_va, dma_p->alength, bind_flags, 1151a72f7ea6Sql DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies); 1152a72f7ea6Sql if ((dma_p->ncookies != 1) || (err != DDI_DMA_MAPPED)) 1153a72f7ea6Sql return (DDI_FAILURE); 1154a72f7ea6Sql 1155a72f7ea6Sql dma_p->nslots = ~0U; 1156a72f7ea6Sql dma_p->size = ~0U; 1157a72f7ea6Sql dma_p->token = ~0U; 1158a72f7ea6Sql dma_p->offset = 0; 1159a72f7ea6Sql return (DDI_SUCCESS); 1160a72f7ea6Sql } 1161a72f7ea6Sql 1162a72f7ea6Sql /* 1163a72f7ea6Sql * Free one allocated area of DMAable memory 1164a72f7ea6Sql */ 1165a72f7ea6Sql static void 1166a72f7ea6Sql rtw_free_dma_mem(dma_area_t *dma_p) 1167a72f7ea6Sql { 1168a72f7ea6Sql if (dma_p->dma_hdl != NULL) { 1169a72f7ea6Sql (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 1170a72f7ea6Sql if (dma_p->acc_hdl != NULL) { 1171a72f7ea6Sql ddi_dma_mem_free(&dma_p->acc_hdl); 1172a72f7ea6Sql dma_p->acc_hdl = NULL; 1173a72f7ea6Sql } 1174a72f7ea6Sql ddi_dma_free_handle(&dma_p->dma_hdl); 1175a72f7ea6Sql dma_p->ncookies = 0; 1176a72f7ea6Sql dma_p->dma_hdl = NULL; 1177a72f7ea6Sql } 1178a72f7ea6Sql } 1179a72f7ea6Sql 1180a72f7ea6Sql static void 1181a72f7ea6Sql rtw_dma_free(rtw_softc_t *rsc) 1182a72f7ea6Sql { 1183a72f7ea6Sql struct rtw_txbuf *txbf; 1184a72f7ea6Sql struct rtw_rxbuf *rxbf; 1185a72f7ea6Sql int i, j; 1186a72f7ea6Sql 1187a72f7ea6Sql /* Free TX DMA buffer */ 1188a72f7ea6Sql for (i = 0; i < RTW_NTXPRI; i++) { 1189a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_free_list); 1190a72f7ea6Sql while (txbf != NULL) { 1191a72f7ea6Sql rtw_free_dma_mem(&txbf->bf_dma); 1192a72f7ea6Sql list_remove(&rsc->sc_txq[i].tx_free_list, txbf); 1193a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_free_list); 1194a72f7ea6Sql } 1195a72f7ea6Sql list_destroy(&rsc->sc_txq[i].tx_free_list); 1196a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_dirty_list); 1197a72f7ea6Sql while (txbf != NULL) { 1198a72f7ea6Sql rtw_free_dma_mem(&txbf->bf_dma); 1199a72f7ea6Sql list_remove(&rsc->sc_txq[i].tx_dirty_list, txbf); 1200a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_dirty_list); 1201a72f7ea6Sql } 1202a72f7ea6Sql list_destroy(&rsc->sc_txq[i].tx_dirty_list); 1203a72f7ea6Sql 1204a72f7ea6Sql if (rsc->sc_txq[i].txbuf_h != NULL) { 1205a72f7ea6Sql kmem_free(rsc->sc_txq[i].txbuf_h, 1206a72f7ea6Sql sizeof (struct rtw_txbuf) * rtw_qlen[i]); 1207a72f7ea6Sql rsc->sc_txq[i].txbuf_h = NULL; 1208a72f7ea6Sql } 1209a72f7ea6Sql } 1210a72f7ea6Sql 1211a72f7ea6Sql /* Free RX DMA buffer */ 1212a72f7ea6Sql rxbf = rsc->rxbuf_h; 1213a72f7ea6Sql for (j = 0; j < RTW_RXQLEN; j++) { 1214a72f7ea6Sql rtw_free_dma_mem(&rxbf->bf_dma); 1215a72f7ea6Sql rxbf++; 1216a72f7ea6Sql } 1217a72f7ea6Sql 1218a72f7ea6Sql if (rsc->rxbuf_h != NULL) { 1219020c4770Sql kmem_free(rsc->rxbuf_h, 1220020c4770Sql sizeof (struct rtw_rxbuf) * RTW_RXQLEN); 1221a72f7ea6Sql rsc->rxbuf_h = NULL; 1222a72f7ea6Sql } 1223a72f7ea6Sql 1224a72f7ea6Sql rtw_free_dma_mem(&rsc->sc_desc_dma); 1225a72f7ea6Sql } 1226a72f7ea6Sql 1227a72f7ea6Sql static int 1228a72f7ea6Sql rtw_dma_init(dev_info_t *devinfo, rtw_softc_t *rsc) 1229a72f7ea6Sql { 1230a72f7ea6Sql int i, j, err; 1231a72f7ea6Sql size_t size; 1232a72f7ea6Sql uint32_t buflen; 1233a72f7ea6Sql struct rtw_txdesc *txds; 1234a72f7ea6Sql struct rtw_rxdesc *rxds; 1235a72f7ea6Sql struct rtw_txbuf *txbf; 1236a72f7ea6Sql struct rtw_rxbuf *rxbf; 1237a72f7ea6Sql uint32_t phybaseaddr, ptx[RTW_NTXPRI], prx; 1238a72f7ea6Sql caddr_t virbaseaddr, vtx[RTW_NTXPRI], vrx; 1239a72f7ea6Sql 1240a72f7ea6Sql /* DMA buffer size for each TX/RX packet */ 1241a72f7ea6Sql rsc->sc_dmabuf_size = roundup(sizeof (struct ieee80211_frame) + 0x100 + 1242a72f7ea6Sql IEEE80211_MTU + IEEE80211_CRC_LEN + sizeof (struct ieee80211_llc) + 1243a72f7ea6Sql (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + 1244a72f7ea6Sql IEEE80211_WEP_CRCLEN), rsc->sc_cachelsz); 1245a72f7ea6Sql size = sizeof (struct rtw_descs); 1246a72f7ea6Sql err = rtw_alloc_dma_mem(devinfo, &dma_attr_desc, size, 1247a72f7ea6Sql &rtw_desc_accattr, 1248a72f7ea6Sql DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1249a72f7ea6Sql &rsc->sc_desc_dma); 1250a72f7ea6Sql if (err != DDI_SUCCESS) 1251a72f7ea6Sql goto error; 1252a72f7ea6Sql phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address; 1253a72f7ea6Sql virbaseaddr = rsc->sc_desc_dma.mem_va; 1254a72f7ea6Sql ptx[0] = RTW_RING_BASE(phybaseaddr, hd_txlo); 1255a72f7ea6Sql ptx[1] = RTW_RING_BASE(phybaseaddr, hd_txmd); 1256a72f7ea6Sql ptx[2] = RTW_RING_BASE(phybaseaddr, hd_txhi); 1257a72f7ea6Sql ptx[3] = RTW_RING_BASE(phybaseaddr, hd_bcn); 1258a72f7ea6Sql vtx[0] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txlo)); 1259a72f7ea6Sql vtx[1] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txmd)); 1260a72f7ea6Sql vtx[2] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_txhi)); 1261a72f7ea6Sql vtx[3] = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_bcn)); 1262a72f7ea6Sql for (i = 0; i < RTW_NTXPRI; i++) { 1263a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_DMA, "p[%d]=%x, v[%d]=%x", i, ptx[i], 1264a72f7ea6Sql i, vtx[i]); 1265a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_DMA, "ring%d:", i); 1266a72f7ea6Sql list_create(&rsc->sc_txq[i].tx_free_list, 1267a72f7ea6Sql sizeof (struct rtw_txbuf), 1268a72f7ea6Sql offsetof(struct rtw_txbuf, bf_node)); 1269a72f7ea6Sql list_create(&rsc->sc_txq[i].tx_dirty_list, 1270a72f7ea6Sql sizeof (struct rtw_txbuf), 1271a72f7ea6Sql offsetof(struct rtw_txbuf, bf_node)); 1272a72f7ea6Sql /* virtual address of the first descriptor */ 1273020c4770Sql rsc->sc_txq[i].txdesc_h = 1274020c4770Sql (struct rtw_txdesc *)(uintptr_t)vtx[i]; 1275a72f7ea6Sql 1276a72f7ea6Sql txds = rsc->sc_txq[i].txdesc_h; 1277a72f7ea6Sql /* allocate data structures to describe TX DMA buffers */ 1278a72f7ea6Sql buflen = sizeof (struct rtw_txbuf) * rtw_qlen[i]; 1279a72f7ea6Sql txbf = (struct rtw_txbuf *)kmem_zalloc(buflen, KM_SLEEP); 1280a72f7ea6Sql rsc->sc_txq[i].txbuf_h = txbf; 1281a72f7ea6Sql for (j = 0; j < rtw_qlen[i]; j++, txbf++, txds++) { 1282a72f7ea6Sql txbf->txdesc = txds; 1283020c4770Sql txbf->bf_daddr = ptx[i] + ((uintptr_t)txds - 1284020c4770Sql (uintptr_t)rsc->sc_txq[i].txdesc_h); 1285a72f7ea6Sql list_insert_tail(&rsc->sc_txq[i].tx_free_list, txbf); 1286a72f7ea6Sql 1287a72f7ea6Sql /* alloc DMA memory */ 1288a72f7ea6Sql err = rtw_alloc_dma_mem(devinfo, &dma_attr_txbuf, 1289a72f7ea6Sql rsc->sc_dmabuf_size, 1290a72f7ea6Sql &rtw_buf_accattr, 1291a72f7ea6Sql DDI_DMA_STREAMING, 1292a72f7ea6Sql DDI_DMA_WRITE | DDI_DMA_STREAMING, 1293a72f7ea6Sql &txbf->bf_dma); 1294a72f7ea6Sql if (err != DDI_SUCCESS) 1295a72f7ea6Sql goto error; 1296a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_DMA, "pbufaddr[%d]=%x", 1297a72f7ea6Sql j, txbf->bf_dma.cookie.dmac_address); 1298a72f7ea6Sql } 1299a72f7ea6Sql } 1300a72f7ea6Sql prx = RTW_RING_BASE(phybaseaddr, hd_rx); 1301a72f7ea6Sql vrx = (caddr_t)(RTW_RING_BASE(virbaseaddr, hd_rx)); 1302a72f7ea6Sql /* virtual address of the first descriptor */ 1303020c4770Sql rsc->rxdesc_h = (struct rtw_rxdesc *)(uintptr_t)vrx; 1304a72f7ea6Sql rxds = rsc->rxdesc_h; 1305a72f7ea6Sql 1306a72f7ea6Sql /* allocate data structures to describe RX DMA buffers */ 1307a72f7ea6Sql buflen = sizeof (struct rtw_rxbuf) * RTW_RXQLEN; 1308a72f7ea6Sql rxbf = (struct rtw_rxbuf *)kmem_zalloc(buflen, KM_SLEEP); 1309a72f7ea6Sql rsc->rxbuf_h = rxbf; 1310a72f7ea6Sql 1311a72f7ea6Sql for (j = 0; j < RTW_RXQLEN; j++, rxbf++, rxds++) { 1312a72f7ea6Sql rxbf->rxdesc = rxds; 1313020c4770Sql rxbf->bf_daddr = 1314020c4770Sql prx + ((uintptr_t)rxds - (uintptr_t)rsc->rxdesc_h); 1315a72f7ea6Sql 1316a72f7ea6Sql /* alloc DMA memory */ 1317a72f7ea6Sql err = rtw_alloc_dma_mem(devinfo, &dma_attr_rxbuf, 1318a72f7ea6Sql rsc->sc_dmabuf_size, 1319a72f7ea6Sql &rtw_buf_accattr, 1320a72f7ea6Sql DDI_DMA_STREAMING, DDI_DMA_READ | DDI_DMA_STREAMING, 1321a72f7ea6Sql &rxbf->bf_dma); 1322a72f7ea6Sql if (err != DDI_SUCCESS) 1323a72f7ea6Sql goto error; 1324a72f7ea6Sql } 1325a72f7ea6Sql 1326a72f7ea6Sql return (DDI_SUCCESS); 1327a72f7ea6Sql error: 1328a72f7ea6Sql return (DDI_FAILURE); 1329a72f7ea6Sql } 1330a72f7ea6Sql 1331a72f7ea6Sql static void 1332a72f7ea6Sql rtw_hwring_setup(rtw_softc_t *rsc) 1333a72f7ea6Sql { 1334a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 1335a72f7ea6Sql uint32_t phybaseaddr; 1336a72f7ea6Sql 1337a72f7ea6Sql phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address; 1338a72f7ea6Sql 1339a72f7ea6Sql RTW_WRITE(regs, RTW_RDSAR, RTW_RING_BASE(phybaseaddr, hd_rx)); 1340a72f7ea6Sql RTW_WRITE(regs, RTW_TLPDA, RTW_RING_BASE(phybaseaddr, hd_txlo)); 1341a72f7ea6Sql RTW_WRITE(regs, RTW_TNPDA, RTW_RING_BASE(phybaseaddr, hd_txmd)); 1342a72f7ea6Sql RTW_WRITE(regs, RTW_THPDA, RTW_RING_BASE(phybaseaddr, hd_txhi)); 1343a72f7ea6Sql RTW_WRITE(regs, RTW_TBDA, RTW_RING_BASE(phybaseaddr, hd_bcn)); 1344a72f7ea6Sql rsc->hw_start = RTW_READ(regs, RTW_TNPDA); 1345a72f7ea6Sql rsc->hw_go = RTW_READ(regs, RTW_TNPDA); 1346a72f7ea6Sql } 1347a72f7ea6Sql 1348a72f7ea6Sql static void 1349a72f7ea6Sql rtw_swring_setup(rtw_softc_t *rsc, int flag) 1350a72f7ea6Sql { 1351a72f7ea6Sql int i, j; 1352a72f7ea6Sql int is_last; 1353a72f7ea6Sql struct rtw_txbuf *txbf; 1354a72f7ea6Sql struct rtw_rxbuf *rxbf; 1355a72f7ea6Sql uint32_t phybaseaddr, ptx[RTW_NTXPRI], baddr_desc, taddr_desc; 1356a72f7ea6Sql 1357a72f7ea6Sql phybaseaddr = rsc->sc_desc_dma.cookie.dmac_address; 1358a72f7ea6Sql ptx[0] = RTW_RING_BASE(phybaseaddr, hd_txlo); 1359a72f7ea6Sql ptx[1] = RTW_RING_BASE(phybaseaddr, hd_txmd); 1360a72f7ea6Sql ptx[2] = RTW_RING_BASE(phybaseaddr, hd_txhi); 1361a72f7ea6Sql ptx[3] = RTW_RING_BASE(phybaseaddr, hd_bcn); 1362a72f7ea6Sql RTW_DMA_SYNC(rsc->sc_desc_dma, DDI_DMA_SYNC_FORDEV); 1363a72f7ea6Sql /* sync tx desc and tx buf */ 1364a72f7ea6Sql for (i = 0; i < RTW_NTXPRI; i++) { 1365a72f7ea6Sql rsc->sc_txq[i].tx_prod = rsc->sc_txq[i].tx_cons = 0; 1366a72f7ea6Sql rsc->sc_txq[i].tx_nfree = rtw_qlen[i]; 1367a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_free_list); 1368a72f7ea6Sql while (txbf != NULL) { 1369a72f7ea6Sql list_remove(&rsc->sc_txq[i].tx_free_list, txbf); 1370a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_free_list); 1371a72f7ea6Sql } 1372a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_dirty_list); 1373a72f7ea6Sql while (txbf != NULL) { 1374a72f7ea6Sql list_remove(&rsc->sc_txq[i].tx_dirty_list, txbf); 1375a72f7ea6Sql txbf = list_head(&rsc->sc_txq[i].tx_dirty_list); 1376a72f7ea6Sql } 1377a72f7ea6Sql txbf = rsc->sc_txq[i].txbuf_h; 1378a72f7ea6Sql baddr_desc = ptx[i]; 1379a72f7ea6Sql taddr_desc = baddr_desc + sizeof (struct rtw_txdesc); 1380a72f7ea6Sql for (j = 0; j < rtw_qlen[i]; j++) { 1381a72f7ea6Sql list_insert_tail(&rsc->sc_txq[i].tx_free_list, txbf); 1382a72f7ea6Sql if (j == (rtw_qlen[i] - 1)) { 1383a72f7ea6Sql is_last = 1; 1384a72f7ea6Sql } else { 1385a72f7ea6Sql is_last = 0; 1386a72f7ea6Sql } 1387a72f7ea6Sql 1388a72f7ea6Sql if (is_last) { 1389a72f7ea6Sql txbf->txdesc->td_next = baddr_desc; 1390a72f7ea6Sql } else { 1391a72f7ea6Sql txbf->txdesc->td_next = taddr_desc; 1392a72f7ea6Sql } 1393a72f7ea6Sql txbf->next_bf_daddr = txbf->txdesc->td_next; 1394a72f7ea6Sql RTW_DMA_SYNC(txbf->bf_dma, DDI_DMA_SYNC_FORDEV); 1395a72f7ea6Sql txbf->order = j; 1396a72f7ea6Sql txbf++; 1397a72f7ea6Sql taddr_desc += sizeof (struct rtw_txdesc); 1398a72f7ea6Sql } 1399a72f7ea6Sql } 1400a72f7ea6Sql if (!flag) 1401a72f7ea6Sql return; 1402a72f7ea6Sql 1403a72f7ea6Sql /* sync rx desc and rx buf */ 1404a72f7ea6Sql rsc->rx_next = 0; 1405a72f7ea6Sql rxbf = rsc->rxbuf_h; 1406a72f7ea6Sql for (j = 0; j < RTW_RXQLEN; j++) { 1407a72f7ea6Sql RTW_DMA_SYNC(rxbf->bf_dma, DDI_DMA_SYNC_FORCPU); 1408a72f7ea6Sql if (j == (RTW_RXQLEN - 1)) 1409a72f7ea6Sql is_last = 1; 1410a72f7ea6Sql else 1411a72f7ea6Sql is_last = 0; 1412a72f7ea6Sql rtw_rxdesc_init(rsc, rxbf, j, is_last); 1413a72f7ea6Sql rxbf++; 1414a72f7ea6Sql } 1415a72f7ea6Sql } 1416a72f7ea6Sql 1417a72f7ea6Sql static void 1418a72f7ea6Sql rtw_resume_ticks(rtw_softc_t *rsc) 1419a72f7ea6Sql { 1420a72f7ea6Sql RTW_WRITE(&rsc->sc_regs, RTW_TINT, 0xffffffff); 1421a72f7ea6Sql } 1422a72f7ea6Sql 1423a72f7ea6Sql const char * 1424a72f7ea6Sql rtw_pwrstate_string(enum rtw_pwrstate power) 1425a72f7ea6Sql { 1426a72f7ea6Sql switch (power) { 1427a72f7ea6Sql case RTW_ON: 1428a72f7ea6Sql return ("on"); 1429a72f7ea6Sql case RTW_SLEEP: 1430a72f7ea6Sql return ("sleep"); 1431a72f7ea6Sql case RTW_OFF: 1432a72f7ea6Sql return ("off"); 1433a72f7ea6Sql default: 1434a72f7ea6Sql return ("unknown"); 1435a72f7ea6Sql } 1436a72f7ea6Sql } 1437a72f7ea6Sql 1438a72f7ea6Sql /* 1439a72f7ea6Sql * XXX For Maxim, I am using the RFMD settings gleaned from the 1440a72f7ea6Sql * reference driver, plus a magic Maxim "ON" value that comes from 1441a72f7ea6Sql * the Realtek document "Windows PG for Rtl8180." 1442a72f7ea6Sql */ 1443a72f7ea6Sql /*ARGSUSED*/ 1444a72f7ea6Sql static void 1445a72f7ea6Sql rtw_maxim_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power, 1446a72f7ea6Sql int before_rf, int digphy) 1447a72f7ea6Sql { 1448a72f7ea6Sql uint32_t anaparm; 1449a72f7ea6Sql 1450a72f7ea6Sql anaparm = RTW_READ(regs, RTW_ANAPARM); 1451a72f7ea6Sql anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF); 1452a72f7ea6Sql 1453a72f7ea6Sql switch (power) { 1454a72f7ea6Sql case RTW_OFF: 1455a72f7ea6Sql if (before_rf) 1456a72f7ea6Sql return; 1457a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_MAXIM_OFF; 1458a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1459a72f7ea6Sql break; 1460a72f7ea6Sql case RTW_SLEEP: 1461a72f7ea6Sql if (!before_rf) 1462a72f7ea6Sql return; 1463a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_MAXIM_SLEEP; 1464a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1465a72f7ea6Sql break; 1466a72f7ea6Sql case RTW_ON: 1467a72f7ea6Sql if (!before_rf) 1468a72f7ea6Sql return; 1469a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_MAXIM_ON; 1470a72f7ea6Sql break; 1471a72f7ea6Sql } 1472a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PWR, 1473a72f7ea6Sql "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n", 1474a72f7ea6Sql __func__, rtw_pwrstate_string(power), 1475a72f7ea6Sql (before_rf) ? "before" : "after", anaparm); 1476a72f7ea6Sql 1477a72f7ea6Sql RTW_WRITE(regs, RTW_ANAPARM, anaparm); 1478a72f7ea6Sql RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); 1479a72f7ea6Sql } 1480a72f7ea6Sql 1481a72f7ea6Sql /* 1482a72f7ea6Sql * XXX I am using the RFMD settings gleaned from the reference 1483a72f7ea6Sql * driver. They agree 1484a72f7ea6Sql */ 1485a72f7ea6Sql /*ARGSUSED*/ 1486a72f7ea6Sql static void 1487a72f7ea6Sql rtw_rfmd_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power, 1488a72f7ea6Sql int before_rf, int digphy) 1489a72f7ea6Sql { 1490a72f7ea6Sql uint32_t anaparm; 1491a72f7ea6Sql 1492a72f7ea6Sql anaparm = RTW_READ(regs, RTW_ANAPARM); 1493a72f7ea6Sql anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF); 1494a72f7ea6Sql 1495a72f7ea6Sql switch (power) { 1496a72f7ea6Sql case RTW_OFF: 1497a72f7ea6Sql if (before_rf) 1498a72f7ea6Sql return; 1499a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_RFMD_OFF; 1500a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1501a72f7ea6Sql break; 1502a72f7ea6Sql case RTW_SLEEP: 1503a72f7ea6Sql if (!before_rf) 1504a72f7ea6Sql return; 1505a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_RFMD_SLEEP; 1506a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1507a72f7ea6Sql break; 1508a72f7ea6Sql case RTW_ON: 1509a72f7ea6Sql if (!before_rf) 1510a72f7ea6Sql return; 1511a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_RFMD_ON; 1512a72f7ea6Sql break; 1513a72f7ea6Sql } 1514a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PWR, 1515a72f7ea6Sql "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n", 1516a72f7ea6Sql __func__, rtw_pwrstate_string(power), 1517a72f7ea6Sql (before_rf) ? "before" : "after", anaparm); 1518a72f7ea6Sql 1519a72f7ea6Sql RTW_WRITE(regs, RTW_ANAPARM, anaparm); 1520a72f7ea6Sql RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); 1521a72f7ea6Sql } 1522a72f7ea6Sql 1523a72f7ea6Sql static void 1524a72f7ea6Sql rtw_philips_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power, 1525a72f7ea6Sql int before_rf, int digphy) 1526a72f7ea6Sql { 1527a72f7ea6Sql uint32_t anaparm; 1528a72f7ea6Sql 1529a72f7ea6Sql anaparm = RTW_READ(regs, RTW_ANAPARM); 1530a72f7ea6Sql anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF); 1531a72f7ea6Sql 1532a72f7ea6Sql switch (power) { 1533a72f7ea6Sql case RTW_OFF: 1534a72f7ea6Sql if (before_rf) 1535a72f7ea6Sql return; 1536a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_OFF; 1537a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1538a72f7ea6Sql break; 1539a72f7ea6Sql case RTW_SLEEP: 1540a72f7ea6Sql if (!before_rf) 1541a72f7ea6Sql return; 1542a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_SLEEP; 1543a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1544a72f7ea6Sql break; 1545a72f7ea6Sql case RTW_ON: 1546a72f7ea6Sql if (!before_rf) 1547a72f7ea6Sql return; 1548a72f7ea6Sql if (digphy) { 1549a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_DIG_PHILIPS_ON; 1550a72f7ea6Sql /* XXX guess */ 1551a72f7ea6Sql anaparm |= RTW_ANAPARM_TXDACOFF; 1552a72f7ea6Sql } else 1553a72f7ea6Sql anaparm |= RTW_ANAPARM_RFPOW_ANA_PHILIPS_ON; 1554a72f7ea6Sql break; 1555a72f7ea6Sql } 1556a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PWR, 1557a72f7ea6Sql "%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n", 1558a72f7ea6Sql __func__, rtw_pwrstate_string(power), 1559a72f7ea6Sql (before_rf) ? "before" : "after", anaparm); 1560a72f7ea6Sql 1561a72f7ea6Sql RTW_WRITE(regs, RTW_ANAPARM, anaparm); 1562a72f7ea6Sql RTW_SYNC(regs, RTW_ANAPARM, RTW_ANAPARM); 1563a72f7ea6Sql } 1564a72f7ea6Sql 1565a72f7ea6Sql static void 1566a72f7ea6Sql rtw_pwrstate0(rtw_softc_t *rsc, enum rtw_pwrstate power, int before_rf, 1567a72f7ea6Sql int digphy) 1568a72f7ea6Sql { 1569a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 1570a72f7ea6Sql 1571a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_ANAPARM); 1572a72f7ea6Sql 1573a72f7ea6Sql (*rsc->sc_pwrstate_cb)(regs, power, before_rf, digphy); 1574a72f7ea6Sql 1575a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_NONE); 1576a72f7ea6Sql } 1577a72f7ea6Sql 1578a72f7ea6Sql static void 1579a72f7ea6Sql rtw_rf_destroy(struct rtw_rf *rf) 1580a72f7ea6Sql { 1581a72f7ea6Sql (*rf->rf_destroy)(rf); 1582a72f7ea6Sql } 1583a72f7ea6Sql 1584a72f7ea6Sql static int 1585a72f7ea6Sql rtw_rf_pwrstate(struct rtw_rf *rf, enum rtw_pwrstate power) 1586a72f7ea6Sql { 1587a72f7ea6Sql return (*rf->rf_pwrstate)(rf, power); 1588a72f7ea6Sql } 1589a72f7ea6Sql 1590a72f7ea6Sql static int 1591a72f7ea6Sql rtw_pwrstate(rtw_softc_t *rsc, enum rtw_pwrstate power) 1592a72f7ea6Sql { 1593a72f7ea6Sql int rc; 1594a72f7ea6Sql 1595a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PWR, 1596a72f7ea6Sql "%s: %s->%s\n", __func__, 1597a72f7ea6Sql rtw_pwrstate_string(rsc->sc_pwrstate), rtw_pwrstate_string(power)); 1598a72f7ea6Sql 1599a72f7ea6Sql if (rsc->sc_pwrstate == power) 1600a72f7ea6Sql return (0); 1601a72f7ea6Sql 1602a72f7ea6Sql rtw_pwrstate0(rsc, power, 1, rsc->sc_flags & RTW_F_DIGPHY); 1603a72f7ea6Sql rc = rtw_rf_pwrstate(rsc->sc_rf, power); 1604a72f7ea6Sql rtw_pwrstate0(rsc, power, 0, rsc->sc_flags & RTW_F_DIGPHY); 1605a72f7ea6Sql 1606a72f7ea6Sql switch (power) { 1607a72f7ea6Sql case RTW_ON: 1608a72f7ea6Sql /* TBD set LEDs */ 1609a72f7ea6Sql break; 1610a72f7ea6Sql case RTW_SLEEP: 1611a72f7ea6Sql /* TBD */ 1612a72f7ea6Sql break; 1613a72f7ea6Sql case RTW_OFF: 1614a72f7ea6Sql /* TBD */ 1615a72f7ea6Sql break; 1616a72f7ea6Sql } 1617a72f7ea6Sql if (rc == 0) 1618a72f7ea6Sql rsc->sc_pwrstate = power; 1619a72f7ea6Sql else 1620a72f7ea6Sql rsc->sc_pwrstate = RTW_OFF; 1621a72f7ea6Sql return (rc); 1622a72f7ea6Sql } 1623a72f7ea6Sql 1624a72f7ea6Sql void 1625a72f7ea6Sql rtw_disable(rtw_softc_t *rsc) 1626a72f7ea6Sql { 1627a72f7ea6Sql int rc; 1628a72f7ea6Sql 1629a72f7ea6Sql if ((rsc->sc_flags & RTW_F_ENABLED) == 0) 1630a72f7ea6Sql return; 1631a72f7ea6Sql 1632a72f7ea6Sql /* turn off PHY */ 1633a72f7ea6Sql if ((rsc->sc_flags & RTW_F_INVALID) == 0 && 1634a72f7ea6Sql (rc = rtw_pwrstate(rsc, RTW_OFF)) != 0) { 1635a72f7ea6Sql cmn_err(CE_WARN, "failed to turn off PHY (%d)\n", rc); 1636a72f7ea6Sql } 1637a72f7ea6Sql 1638a72f7ea6Sql if (rsc->sc_disable != NULL) 1639a72f7ea6Sql (*rsc->sc_disable)(rsc); 1640a72f7ea6Sql 1641a72f7ea6Sql rsc->sc_flags &= ~RTW_F_ENABLED; 1642a72f7ea6Sql } 1643a72f7ea6Sql 1644a72f7ea6Sql int 1645a72f7ea6Sql rtw_enable(rtw_softc_t *rsc) 1646a72f7ea6Sql { 1647a72f7ea6Sql if ((rsc->sc_flags & RTW_F_ENABLED) == 0) { 1648a72f7ea6Sql if (rsc->sc_enable != NULL && (*rsc->sc_enable)(rsc) != 0) { 1649a72f7ea6Sql cmn_err(CE_WARN, "device enable failed\n"); 1650a72f7ea6Sql return (EIO); 1651a72f7ea6Sql } 1652a72f7ea6Sql rsc->sc_flags |= RTW_F_ENABLED; 1653a72f7ea6Sql if (rtw_pwrstate(rsc, RTW_ON) != 0) 1654a72f7ea6Sql cmn_err(CE_WARN, "PHY turn on failed\n"); 1655a72f7ea6Sql } 1656a72f7ea6Sql return (0); 1657a72f7ea6Sql } 1658a72f7ea6Sql 1659a72f7ea6Sql static void 1660a72f7ea6Sql rtw_set_nettype(rtw_softc_t *rsc, enum ieee80211_opmode opmode) 1661a72f7ea6Sql { 1662a72f7ea6Sql uint8_t msr; 1663a72f7ea6Sql 1664a72f7ea6Sql /* I'm guessing that MSR is protected as CONFIG[0123] are. */ 1665a72f7ea6Sql rtw_set_access(&rsc->sc_regs, RTW_ACCESS_CONFIG); 1666a72f7ea6Sql 1667a72f7ea6Sql msr = RTW_READ8(&rsc->sc_regs, RTW_MSR) & ~RTW_MSR_NETYPE_MASK; 1668a72f7ea6Sql 1669a72f7ea6Sql switch (opmode) { 1670a72f7ea6Sql case IEEE80211_M_AHDEMO: 1671a72f7ea6Sql case IEEE80211_M_IBSS: 1672a72f7ea6Sql msr |= RTW_MSR_NETYPE_ADHOC_OK; 1673a72f7ea6Sql break; 1674a72f7ea6Sql case IEEE80211_M_HOSTAP: 1675a72f7ea6Sql msr |= RTW_MSR_NETYPE_AP_OK; 1676a72f7ea6Sql break; 1677a72f7ea6Sql case IEEE80211_M_STA: 1678a72f7ea6Sql msr |= RTW_MSR_NETYPE_INFRA_OK; 1679a72f7ea6Sql break; 1680a72f7ea6Sql } 1681a72f7ea6Sql RTW_WRITE8(&rsc->sc_regs, RTW_MSR, msr); 1682a72f7ea6Sql 1683a72f7ea6Sql rtw_set_access(&rsc->sc_regs, RTW_ACCESS_NONE); 1684a72f7ea6Sql } 1685a72f7ea6Sql 1686a72f7ea6Sql static void 1687a72f7ea6Sql rtw_pktfilt_load(rtw_softc_t *rsc) 1688a72f7ea6Sql { 1689a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 1690a72f7ea6Sql struct ieee80211com *ic = &rsc->sc_ic; 1691a72f7ea6Sql 1692a72f7ea6Sql /* XXX might be necessary to stop Rx/Tx engines while setting filters */ 1693a72f7ea6Sql rsc->sc_rcr &= ~RTW_RCR_PKTFILTER_MASK; 1694a72f7ea6Sql rsc->sc_rcr &= ~(RTW_RCR_MXDMA_MASK | RTW_RCR_RXFTH_MASK); 1695a72f7ea6Sql 1696a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_PKTFILTER_DEFAULT; 1697a72f7ea6Sql /* MAC auto-reset PHY (huh?) */ 1698a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_ENMARP; 1699a72f7ea6Sql /* DMA whole Rx packets, only. Set Tx DMA burst size to 1024 bytes. */ 1700a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_RXFTH_WHOLE |RTW_RCR_MXDMA_1024; 1701a72f7ea6Sql 1702a72f7ea6Sql switch (ic->ic_opmode) { 1703a72f7ea6Sql case IEEE80211_M_AHDEMO: 1704a72f7ea6Sql case IEEE80211_M_IBSS: 1705a72f7ea6Sql /* receive broadcasts in our BSS */ 1706a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_ADD3; 1707a72f7ea6Sql break; 1708a72f7ea6Sql default: 1709a72f7ea6Sql break; 1710a72f7ea6Sql } 1711a72f7ea6Sql #if 0 1712a72f7ea6Sql /* XXX accept all broadcast if scanning */ 1713a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_AB; /* accept all broadcast */ 1714a72f7ea6Sql #endif 1715a72f7ea6Sql RTW_WRITE(regs, RTW_MAR0, 0xffffffff); 1716a72f7ea6Sql RTW_WRITE(regs, RTW_MAR1, 0xffffffff); 1717a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_AM; 1718a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr); 1719a72f7ea6Sql RTW_SYNC(regs, RTW_MAR0, RTW_RCR); /* RTW_MAR0 < RTW_MAR1 < RTW_RCR */ 1720a72f7ea6Sql 1721a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PKTFILT, 1722a72f7ea6Sql "RTW_MAR0 %08x RTW_MAR1 %08x RTW_RCR %08x\n", 1723a72f7ea6Sql RTW_READ(regs, RTW_MAR0), 1724a72f7ea6Sql RTW_READ(regs, RTW_MAR1), RTW_READ(regs, RTW_RCR)); 1725a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr); 1726a72f7ea6Sql } 1727a72f7ea6Sql 1728a72f7ea6Sql static void 1729a72f7ea6Sql rtw_transmit_config(struct rtw_regs *regs) 1730a72f7ea6Sql { 1731a72f7ea6Sql uint32_t tcr; 1732a72f7ea6Sql 1733a72f7ea6Sql tcr = RTW_READ(regs, RTW_TCR); 1734a72f7ea6Sql 1735a72f7ea6Sql tcr |= RTW_TCR_CWMIN; 1736a72f7ea6Sql tcr &= ~RTW_TCR_MXDMA_MASK; 1737a72f7ea6Sql tcr |= RTW_TCR_MXDMA_1024; 1738a72f7ea6Sql tcr |= RTW_TCR_SAT; /* send ACK as fast as possible */ 1739a72f7ea6Sql tcr &= ~RTW_TCR_LBK_MASK; 1740a72f7ea6Sql tcr |= RTW_TCR_LBK_NORMAL; /* normal operating mode */ 1741a72f7ea6Sql 1742a72f7ea6Sql /* set short/long retry limits */ 1743a72f7ea6Sql tcr &= ~(RTW_TCR_SRL_MASK|RTW_TCR_LRL_MASK); 1744a72f7ea6Sql tcr |= LSHIFT(0x4, RTW_TCR_SRL_MASK) | LSHIFT(0x4, RTW_TCR_LRL_MASK); 1745a72f7ea6Sql 1746a72f7ea6Sql tcr &= ~RTW_TCR_CRC; /* NIC appends CRC32 */ 1747a72f7ea6Sql RTW_WRITE(regs, RTW_TCR, tcr); 1748a72f7ea6Sql RTW_SYNC(regs, RTW_TCR, RTW_TCR); 1749a72f7ea6Sql } 1750a72f7ea6Sql 1751a72f7ea6Sql int 1752a72f7ea6Sql rtw_refine_setting(rtw_softc_t *rsc) 1753a72f7ea6Sql { 1754a72f7ea6Sql struct rtw_regs *regs; 1755a72f7ea6Sql int rc = 0; 1756a72f7ea6Sql 1757a72f7ea6Sql regs = &rsc->sc_regs; 1758a72f7ea6Sql rc = rtw_reset(rsc); 1759a72f7ea6Sql if (rc != 0) 1760a72f7ea6Sql return (-1); 1761a72f7ea6Sql 1762a72f7ea6Sql rtw_beacon_tx_disable(regs); 1763a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE|RTW_CR_TE, 1); 1764a72f7ea6Sql rtw_set_mode(regs, RTW_EPROM_CMD_CONFIG); 1765a72f7ea6Sql 1766a72f7ea6Sql rtw_transmit_config(regs); 1767a72f7ea6Sql rtw_pktfilt_load(rsc); 1768a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_CONFIG); 1769a72f7ea6Sql RTW_WRITE(regs, RTW_TINT, 0xffffffff); 1770a72f7ea6Sql RTW_WRITE8(regs, RTW_MSR, 0x0); /* no link */ 1771a72f7ea6Sql RTW_WRITE16(regs, RTW_BRSR, 0); 1772a72f7ea6Sql 1773a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_ANAPARM); 1774a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_NONE); 1775a72f7ea6Sql RTW_WRITE(regs, RTW_FEMR, 0xffff); 1776a72f7ea6Sql RTW_SYNC(regs, RTW_FEMR, RTW_FEMR); 1777a72f7ea6Sql rtw_set_rfprog(regs, rsc->sc_rfchipid, "rtw"); 1778a72f7ea6Sql 1779a72f7ea6Sql RTW_WRITE8(regs, RTW_PHYDELAY, rsc->sc_phydelay); 1780a72f7ea6Sql RTW_WRITE8(regs, RTW_CRCOUNT, RTW_CRCOUNT_MAGIC); 1781a72f7ea6Sql rtw_set_mode(regs, RTW_EPROM_CMD_NORMAL); 1782a72f7ea6Sql return (0); 1783a72f7ea6Sql } 1784a72f7ea6Sql 1785a72f7ea6Sql static int 1786a72f7ea6Sql rtw_tune(rtw_softc_t *rsc) 1787a72f7ea6Sql { 1788a72f7ea6Sql struct ieee80211com *ic = &rsc->sc_ic; 1789a72f7ea6Sql uint32_t chan; 1790a72f7ea6Sql int rc; 1791a72f7ea6Sql int antdiv = rsc->sc_flags & RTW_F_ANTDIV, 1792a72f7ea6Sql dflantb = rsc->sc_flags & RTW_F_DFLANTB; 1793a72f7ea6Sql 1794a72f7ea6Sql ASSERT(ic->ic_curchan != NULL); 1795a72f7ea6Sql 1796a72f7ea6Sql chan = ieee80211_chan2ieee(ic, ic->ic_curchan); 1797a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_TUNE, "rtw: chan no = %x", chan); 1798a72f7ea6Sql 1799a72f7ea6Sql if (chan == IEEE80211_CHAN_ANY) { 1800a72f7ea6Sql cmn_err(CE_WARN, "%s: chan == IEEE80211_CHAN_ANY\n", __func__); 1801a72f7ea6Sql return (-1); 1802a72f7ea6Sql } 1803a72f7ea6Sql 1804a72f7ea6Sql if (chan == rsc->sc_cur_chan) { 1805a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_TUNE, 1806a72f7ea6Sql "%s: already tuned chan %d\n", __func__, chan); 1807a72f7ea6Sql return (0); 1808a72f7ea6Sql } 1809a72f7ea6Sql rtw_idle(&rsc->sc_regs); 1810a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0); 1811a72f7ea6Sql ASSERT((rsc->sc_flags & RTW_F_ENABLED) != 0); 1812a72f7ea6Sql 1813a72f7ea6Sql if ((rc = rtw_phy_init(&rsc->sc_regs, rsc->sc_rf, 1814a72f7ea6Sql rtw_chan2txpower(&rsc->sc_srom, ic, ic->ic_curchan), 1815a72f7ea6Sql rsc->sc_csthr, ic->ic_curchan->ich_freq, antdiv, 1816a72f7ea6Sql dflantb, RTW_ON)) != 0) { 1817a72f7ea6Sql /* XXX condition on powersaving */ 1818a72f7ea6Sql cmn_err(CE_NOTE, "phy init failed\n"); 1819a72f7ea6Sql } 1820a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 1); 1821a72f7ea6Sql rtw_resume_ticks(rsc); 1822a72f7ea6Sql rsc->sc_cur_chan = chan; 1823a72f7ea6Sql return (rc); 1824a72f7ea6Sql } 1825a72f7ea6Sql 1826a72f7ea6Sql static int 1827a72f7ea6Sql rtw_init(rtw_softc_t *rsc) 1828a72f7ea6Sql { 1829a72f7ea6Sql struct ieee80211com *ic = &rsc->sc_ic; 1830a72f7ea6Sql int rc = 0; 1831a72f7ea6Sql 1832a72f7ea6Sql if ((rc = rtw_enable(rsc)) != 0) 1833a72f7ea6Sql goto out; 1834a72f7ea6Sql rc = rtw_refine_setting(rsc); 1835a72f7ea6Sql if (rc != 0) 1836a72f7ea6Sql return (rc); 1837a72f7ea6Sql 1838a72f7ea6Sql rtw_swring_setup(rsc, 1); 1839a72f7ea6Sql rtw_hwring_setup(rsc); 1840a72f7ea6Sql RTW_WRITE16(&rsc->sc_regs, RTW_BSSID16, 0x0); 1841a72f7ea6Sql RTW_WRITE(&rsc->sc_regs, RTW_BSSID32, 0x0); 1842a72f7ea6Sql rtw_enable_interrupts(rsc); 1843a72f7ea6Sql 1844a72f7ea6Sql ic->ic_ibss_chan = &ic->ic_sup_channels[1]; 1845a72f7ea6Sql ic->ic_curchan = ic->ic_ibss_chan; 1846a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_TUNE, "%s: channel %d freq %d flags 0x%04x\n", 1847a72f7ea6Sql __func__, ieee80211_chan2ieee(ic, ic->ic_curchan), 1848a72f7ea6Sql ic->ic_curchan->ich_freq, ic->ic_curchan->ich_flags); 1849a72f7ea6Sql out: 1850a72f7ea6Sql return (rc); 1851a72f7ea6Sql } 1852a72f7ea6Sql 1853a72f7ea6Sql static struct rtw_rf * 1854a72f7ea6Sql rtw_rf_attach(rtw_softc_t *rsc, enum rtw_rfchipid rfchipid, int digphy) 1855a72f7ea6Sql { 1856a72f7ea6Sql rtw_rf_write_t rf_write; 1857a72f7ea6Sql struct rtw_rf *rf; 1858a72f7ea6Sql int rtw_host_rfio; 1859a72f7ea6Sql 1860a72f7ea6Sql switch (rfchipid) { 1861a72f7ea6Sql default: 1862a72f7ea6Sql rf_write = rtw_rf_hostwrite; 1863a72f7ea6Sql break; 1864a72f7ea6Sql case RTW_RFCHIPID_INTERSIL: 1865a72f7ea6Sql case RTW_RFCHIPID_PHILIPS: 1866a72f7ea6Sql case RTW_RFCHIPID_GCT: /* XXX a guess */ 1867a72f7ea6Sql case RTW_RFCHIPID_RFMD: 1868a72f7ea6Sql rtw_host_rfio = 1; 1869a72f7ea6Sql rf_write = (rtw_host_rfio) ? rtw_rf_hostwrite : rtw_rf_macwrite; 1870a72f7ea6Sql break; 1871a72f7ea6Sql } 1872a72f7ea6Sql 1873a72f7ea6Sql switch (rfchipid) { 1874a72f7ea6Sql case RTW_RFCHIPID_MAXIM: 1875a72f7ea6Sql rf = rtw_max2820_create(&rsc->sc_regs, rf_write, 0); 1876a72f7ea6Sql rsc->sc_pwrstate_cb = rtw_maxim_pwrstate; 1877a72f7ea6Sql break; 1878a72f7ea6Sql case RTW_RFCHIPID_PHILIPS: 1879a72f7ea6Sql rf = rtw_sa2400_create(&rsc->sc_regs, rf_write, digphy); 1880a72f7ea6Sql rsc->sc_pwrstate_cb = rtw_philips_pwrstate; 1881a72f7ea6Sql break; 1882a72f7ea6Sql case RTW_RFCHIPID_RFMD: 1883a72f7ea6Sql /* XXX RFMD has no RF constructor */ 1884a72f7ea6Sql rsc->sc_pwrstate_cb = rtw_rfmd_pwrstate; 1885a72f7ea6Sql /*FALLTHROUGH*/ 1886a72f7ea6Sql default: 1887a72f7ea6Sql return (NULL); 1888a72f7ea6Sql } 1889a72f7ea6Sql if (rf != NULL) { 1890a72f7ea6Sql rf->rf_continuous_tx_cb = 1891a72f7ea6Sql (rtw_continuous_tx_cb_t)rtw_continuous_tx_enable; 1892a72f7ea6Sql rf->rf_continuous_tx_arg = (void *)rsc; 1893a72f7ea6Sql } 1894a72f7ea6Sql return (rf); 1895a72f7ea6Sql } 1896a72f7ea6Sql 1897a72f7ea6Sql /* 1898a72f7ea6Sql * Revision C and later use a different PHY delay setting than 1899a72f7ea6Sql * revisions A and B. 1900a72f7ea6Sql */ 1901a72f7ea6Sql static uint8_t 1902a72f7ea6Sql rtw_check_phydelay(struct rtw_regs *regs, uint32_t rcr0) 1903a72f7ea6Sql { 1904a72f7ea6Sql #define REVAB (RTW_RCR_MXDMA_UNLIMITED | RTW_RCR_AICV) 1905a72f7ea6Sql #define REVC (REVAB | RTW_RCR_RXFTH_WHOLE) 1906a72f7ea6Sql 1907a72f7ea6Sql uint8_t phydelay = LSHIFT(0x6, RTW_PHYDELAY_PHYDELAY); 1908a72f7ea6Sql 1909a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, REVAB); 1910a72f7ea6Sql RTW_WBW(regs, RTW_RCR, RTW_RCR); 1911a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, REVC); 1912a72f7ea6Sql 1913a72f7ea6Sql RTW_WBR(regs, RTW_RCR, RTW_RCR); 1914a72f7ea6Sql if ((RTW_READ(regs, RTW_RCR) & REVC) == REVC) 1915a72f7ea6Sql phydelay |= RTW_PHYDELAY_REVC_MAGIC; 1916a72f7ea6Sql 1917a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, rcr0); /* restore RCR */ 1918a72f7ea6Sql RTW_SYNC(regs, RTW_RCR, RTW_RCR); 1919a72f7ea6Sql 1920a72f7ea6Sql return (phydelay); 1921a72f7ea6Sql #undef REVC 1922a72f7ea6Sql } 1923a72f7ea6Sql 1924a72f7ea6Sql static void rtw_intr_rx(rtw_softc_t *rsc); 1925a72f7ea6Sql static void rtw_ring_recycling(rtw_softc_t *rsc, uint16_t isr, uint32_t pri); 1926a72f7ea6Sql 1927a72f7ea6Sql static int 1928a72f7ea6Sql rtw_get_rate(struct ieee80211com *ic) 1929a72f7ea6Sql { 1930a72f7ea6Sql uint8_t (*rates)[IEEE80211_RATE_MAXSIZE]; 1931a72f7ea6Sql int rate; 1932a72f7ea6Sql 1933a72f7ea6Sql rates = &ic->ic_bss->in_rates.ir_rates; 1934a72f7ea6Sql 1935a72f7ea6Sql if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) 1936a72f7ea6Sql rate = ic->ic_fixed_rate; 1937a72f7ea6Sql else if (ic->ic_state == IEEE80211_S_RUN) 1938a72f7ea6Sql rate = (*rates)[ic->ic_bss->in_txrate]; 1939a72f7ea6Sql else 1940a72f7ea6Sql rate = 0; 1941a72f7ea6Sql return (rate & IEEE80211_RATE_VAL); 1942a72f7ea6Sql } 1943a72f7ea6Sql 1944a72f7ea6Sql /* 1945a72f7ea6Sql * Arguments in: 1946a72f7ea6Sql * 1947a72f7ea6Sql * paylen: payload length (no FCS, no WEP header) 1948a72f7ea6Sql * 1949a72f7ea6Sql * hdrlen: header length 1950a72f7ea6Sql * 1951a72f7ea6Sql * rate: MSDU speed, units 500kb/s 1952a72f7ea6Sql * 1953a72f7ea6Sql * flags: IEEE80211_F_SHPREAMBLE (use short preamble), 1954a72f7ea6Sql * IEEE80211_F_SHSLOT (use short slot length) 1955a72f7ea6Sql * 1956a72f7ea6Sql * Arguments out: 1957a72f7ea6Sql * 1958a72f7ea6Sql * d: 802.11 Duration field for RTS, 1959a72f7ea6Sql * 802.11 Duration field for data frame, 1960a72f7ea6Sql * PLCP Length for data frame, 1961a72f7ea6Sql * residual octets at end of data slot 1962a72f7ea6Sql */ 1963a72f7ea6Sql static int 1964a72f7ea6Sql rtw_compute_duration1(int len, int use_ack, uint32_t flags, int rate, 1965a72f7ea6Sql struct rtw_ieee80211_duration *d) 1966a72f7ea6Sql { 1967a72f7ea6Sql int pre, ctsrate; 1968a72f7ea6Sql uint16_t ack, bitlen, data_dur, remainder; 1969a72f7ea6Sql 1970a72f7ea6Sql /* 1971a72f7ea6Sql * RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK 1972a72f7ea6Sql * DATA reserves medium for SIFS | ACK 1973a72f7ea6Sql * 1974a72f7ea6Sql * XXXMYC: no ACK on multicast/broadcast or control packets 1975a72f7ea6Sql */ 1976a72f7ea6Sql 1977a72f7ea6Sql bitlen = len * 8; 1978a72f7ea6Sql 1979a72f7ea6Sql pre = IEEE80211_DUR_DS_SIFS; 1980a72f7ea6Sql if ((flags & IEEE80211_F_SHPREAMBLE) != 0) 1981a72f7ea6Sql pre += IEEE80211_DUR_DS_SHORT_PREAMBLE + 1982a72f7ea6Sql IEEE80211_DUR_DS_FAST_PLCPHDR; 1983a72f7ea6Sql else 1984a72f7ea6Sql pre += IEEE80211_DUR_DS_LONG_PREAMBLE + 1985a72f7ea6Sql IEEE80211_DUR_DS_SLOW_PLCPHDR; 1986a72f7ea6Sql 1987a72f7ea6Sql d->d_residue = 0; 1988a72f7ea6Sql data_dur = (bitlen * 2) / rate; 1989a72f7ea6Sql remainder = (bitlen * 2) % rate; 1990a72f7ea6Sql if (remainder != 0) { 1991a72f7ea6Sql if (rate == 22) 1992a72f7ea6Sql d->d_residue = (rate - remainder) / 16; 1993a72f7ea6Sql data_dur++; 1994a72f7ea6Sql } 1995a72f7ea6Sql 1996a72f7ea6Sql switch (rate) { 1997a72f7ea6Sql case 2: /* 1 Mb/s */ 1998a72f7ea6Sql case 4: /* 2 Mb/s */ 1999a72f7ea6Sql /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */ 2000a72f7ea6Sql ctsrate = 2; 2001a72f7ea6Sql break; 2002a72f7ea6Sql case 11: /* 5.5 Mb/s */ 2003a72f7ea6Sql case 22: /* 11 Mb/s */ 2004a72f7ea6Sql case 44: /* 22 Mb/s */ 2005a72f7ea6Sql /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */ 2006a72f7ea6Sql ctsrate = 4; 2007a72f7ea6Sql break; 2008a72f7ea6Sql default: 2009a72f7ea6Sql /* TBD */ 2010a72f7ea6Sql return (-1); 2011a72f7ea6Sql } 2012a72f7ea6Sql 2013a72f7ea6Sql d->d_plcp_len = data_dur; 2014a72f7ea6Sql 2015a72f7ea6Sql ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0; 2016a72f7ea6Sql 2017a72f7ea6Sql d->d_rts_dur = 2018a72f7ea6Sql pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate + 2019a72f7ea6Sql pre + data_dur + 2020a72f7ea6Sql ack; 2021a72f7ea6Sql 2022a72f7ea6Sql d->d_data_dur = ack; 2023a72f7ea6Sql 2024a72f7ea6Sql return (0); 2025a72f7ea6Sql } 2026a72f7ea6Sql 2027a72f7ea6Sql /* 2028a72f7ea6Sql * Arguments in: 2029a72f7ea6Sql * 2030a72f7ea6Sql * wh: 802.11 header 2031a72f7ea6Sql * 2032a72f7ea6Sql * paylen: payload length (no FCS, no WEP header) 2033a72f7ea6Sql * 2034a72f7ea6Sql * rate: MSDU speed, units 500kb/s 2035a72f7ea6Sql * 2036a72f7ea6Sql * fraglen: fragment length, set to maximum (or higher) for no 2037a72f7ea6Sql * fragmentation 2038a72f7ea6Sql * 2039a72f7ea6Sql * flags: IEEE80211_F_PRIVACY (hardware adds WEP), 2040a72f7ea6Sql * IEEE80211_F_SHPREAMBLE (use short preamble), 2041a72f7ea6Sql * IEEE80211_F_SHSLOT (use short slot length) 2042a72f7ea6Sql * 2043a72f7ea6Sql * Arguments out: 2044a72f7ea6Sql * 2045a72f7ea6Sql * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields 2046a72f7ea6Sql * of first/only fragment 2047a72f7ea6Sql * 2048a72f7ea6Sql * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields 2049a72f7ea6Sql * of first/only fragment 2050a72f7ea6Sql */ 2051a72f7ea6Sql static int 2052a72f7ea6Sql rtw_compute_duration(struct ieee80211_frame *wh, int len, 2053a72f7ea6Sql uint32_t flags, int fraglen, int rate, struct rtw_ieee80211_duration *d0, 2054a72f7ea6Sql struct rtw_ieee80211_duration *dn, int *npktp) 2055a72f7ea6Sql { 2056a72f7ea6Sql int ack, rc; 2057a72f7ea6Sql int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen; 2058a72f7ea6Sql 2059a72f7ea6Sql /* don't think about addr4 here */ 2060a72f7ea6Sql hdrlen = sizeof (struct ieee80211_frame); 2061a72f7ea6Sql 2062a72f7ea6Sql paylen = len - hdrlen; 2063a72f7ea6Sql 2064a72f7ea6Sql if ((wh->i_fc[1] & IEEE80211_FC1_WEP) != 0) { 2065a72f7ea6Sql overlen = 8 + IEEE80211_CRC_LEN; 2066a72f7ea6Sql paylen -= 8; 2067a72f7ea6Sql } else 2068a72f7ea6Sql overlen = IEEE80211_CRC_LEN; 2069a72f7ea6Sql 2070a72f7ea6Sql npkt = paylen / fraglen; 2071a72f7ea6Sql lastlen0 = paylen % fraglen; 2072a72f7ea6Sql 2073a72f7ea6Sql if (npkt == 0) /* no fragments */ 2074a72f7ea6Sql lastlen = paylen + overlen; 2075a72f7ea6Sql else if (lastlen0 != 0) { /* a short "tail" fragment */ 2076a72f7ea6Sql lastlen = lastlen0 + overlen; 2077a72f7ea6Sql npkt++; 2078a72f7ea6Sql } else /* full-length "tail" fragment */ 2079a72f7ea6Sql lastlen = fraglen + overlen; 2080a72f7ea6Sql 2081a72f7ea6Sql if (npktp != NULL) 2082a72f7ea6Sql *npktp = npkt; 2083a72f7ea6Sql 2084a72f7ea6Sql if (npkt > 1) 2085a72f7ea6Sql firstlen = fraglen + overlen; 2086a72f7ea6Sql else 2087a72f7ea6Sql firstlen = paylen + overlen; 2088a72f7ea6Sql 2089a72f7ea6Sql ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) && 2090a72f7ea6Sql (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) != 2091a72f7ea6Sql IEEE80211_FC0_TYPE_CTL; 2092a72f7ea6Sql 2093a72f7ea6Sql rc = rtw_compute_duration1(firstlen + hdrlen, 2094a72f7ea6Sql ack, flags, rate, d0); 2095a72f7ea6Sql if (rc == -1) 2096a72f7ea6Sql return (rc); 2097a72f7ea6Sql 2098a72f7ea6Sql if (npkt <= 1) { 2099a72f7ea6Sql *dn = *d0; 2100a72f7ea6Sql return (0); 2101a72f7ea6Sql } 2102a72f7ea6Sql return (rtw_compute_duration1(lastlen + hdrlen, ack, flags, 2103a72f7ea6Sql rate, dn)); 2104a72f7ea6Sql } 2105a72f7ea6Sql 2106a72f7ea6Sql static int 2107a72f7ea6Sql rtw_assembly_80211(rtw_softc_t *rsc, struct rtw_txbuf *bf, 2108a72f7ea6Sql mblk_t *mp) 2109a72f7ea6Sql { 2110a72f7ea6Sql ieee80211com_t *ic; 2111a72f7ea6Sql struct rtw_txdesc *ds; 2112a72f7ea6Sql struct ieee80211_frame *wh; 2113a72f7ea6Sql uint8_t *buf; 2114a72f7ea6Sql uint32_t ctl0 = 0, ctl1 = 0; 2115a72f7ea6Sql int npkt, rate; 2116a72f7ea6Sql struct rtw_ieee80211_duration d0, dn; 2117a72f7ea6Sql int32_t iswep, pktlen, mblen; 2118a72f7ea6Sql mblk_t *mp0; 2119a72f7ea6Sql 2120a72f7ea6Sql ic = &rsc->sc_ic; 2121a72f7ea6Sql ds = bf->txdesc; 2122a72f7ea6Sql buf = (uint8_t *)bf->bf_dma.mem_va; 2123a72f7ea6Sql bzero(buf, bf->bf_dma.alength); 2124a72f7ea6Sql bzero((uint8_t *)ds, sizeof (struct rtw_txdesc)); 2125a72f7ea6Sql wh = (struct ieee80211_frame *)mp->b_rptr; 2126a72f7ea6Sql iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; 2127a72f7ea6Sql 2128a72f7ea6Sql /* ieee80211_crypto_encap() needs a single mblk */ 2129a72f7ea6Sql mp0 = allocb(bf->bf_dma.alength, BPRI_MED); 2130a72f7ea6Sql if (mp0 == NULL) { 2131a72f7ea6Sql cmn_err(CE_WARN, "%s: allocb(mp) error", __func__); 2132a72f7ea6Sql return (-1); 2133a72f7ea6Sql } 2134a72f7ea6Sql for (; mp != NULL; mp = mp->b_cont) { 2135020c4770Sql mblen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr; 2136a72f7ea6Sql bcopy(mp->b_rptr, mp0->b_wptr, mblen); 2137a72f7ea6Sql mp0->b_wptr += mblen; 2138a72f7ea6Sql } 2139a72f7ea6Sql 2140a72f7ea6Sql if (iswep) { 2141a72f7ea6Sql struct ieee80211_key *k; 2142a72f7ea6Sql 2143a72f7ea6Sql k = ieee80211_crypto_encap(ic, mp0); 2144a72f7ea6Sql if (k == NULL) { 2145a72f7ea6Sql cmn_err(CE_WARN, "%s: ieee80211_crypto_encap() error", 2146a72f7ea6Sql __func__); 2147a72f7ea6Sql freemsg(mp0); 2148a72f7ea6Sql return (-1); 2149a72f7ea6Sql } 2150a72f7ea6Sql } 2151a72f7ea6Sql pktlen = msgdsize(mp0); 2152a72f7ea6Sql 2153a72f7ea6Sql #if 0 2154a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "-----------send------begin--------"); 2155a72f7ea6Sql ieee80211_dump_pkt((uint8_t *)(mp0->b_rptr), pktlen, 0, 0); 2156a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "-----------send------end--------"); 2157a72f7ea6Sql #endif 2158a72f7ea6Sql /* RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); */ 2159a72f7ea6Sql if (pktlen > bf->bf_dma.alength) { 2160a72f7ea6Sql cmn_err(CE_WARN, "%s: overlength packet pktlen = %d\n", 2161a72f7ea6Sql __func__, pktlen); 2162a72f7ea6Sql freemsg(mp0); 2163a72f7ea6Sql return (-1); 2164a72f7ea6Sql } 2165a72f7ea6Sql bcopy(mp0->b_rptr, buf, pktlen); 2166a72f7ea6Sql RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV); 2167a72f7ea6Sql 2168a72f7ea6Sql /* setup descriptor */ 2169a72f7ea6Sql ctl0 = RTW_TXCTL0_RTSRATE_1MBPS; 2170a72f7ea6Sql 2171a72f7ea6Sql if (((ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0) && 2172a72f7ea6Sql (ic->ic_bss->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) { 2173a72f7ea6Sql ctl0 |= RTW_TXCTL0_SPLCP; 2174a72f7ea6Sql } 2175a72f7ea6Sql /* XXX do real rate control */ 2176a72f7ea6Sql if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 2177a72f7ea6Sql IEEE80211_FC0_TYPE_MGT) 2178a72f7ea6Sql rate = 2; 2179a72f7ea6Sql else { 2180a72f7ea6Sql rate = MAX(2, rtw_get_rate(ic)); 2181a72f7ea6Sql } 2182a72f7ea6Sql ctl0 = ctl0 | 2183a72f7ea6Sql LSHIFT(pktlen, RTW_TXCTL0_TPKTSIZE_MASK); 2184a72f7ea6Sql 2185a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: rate = %d", __func__, rate); 2186a72f7ea6Sql 2187a72f7ea6Sql switch (rate) { 2188a72f7ea6Sql default: 2189a72f7ea6Sql case 2: 2190a72f7ea6Sql ctl0 |= RTW_TXCTL0_RATE_1MBPS; 2191a72f7ea6Sql break; 2192a72f7ea6Sql case 4: 2193a72f7ea6Sql ctl0 |= RTW_TXCTL0_RATE_2MBPS; 2194a72f7ea6Sql break; 2195a72f7ea6Sql case 11: 2196a72f7ea6Sql ctl0 |= RTW_TXCTL0_RATE_5MBPS; 2197a72f7ea6Sql break; 2198a72f7ea6Sql case 22: 2199a72f7ea6Sql ctl0 |= RTW_TXCTL0_RATE_11MBPS; 2200a72f7ea6Sql break; 2201a72f7ea6Sql } 2202a72f7ea6Sql 2203a72f7ea6Sql /* XXX >= ? Compare after fragmentation? */ 2204a72f7ea6Sql if (pktlen > ic->ic_rtsthreshold) { 2205a72f7ea6Sql ctl0 |= RTW_TXCTL0_RTSEN; 2206a72f7ea6Sql cmn_err(CE_NOTE, "%s: fragmentation: pktlen = %d", 2207a72f7ea6Sql __func__, pktlen); 2208a72f7ea6Sql } 2209a72f7ea6Sql 2210a72f7ea6Sql if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 2211a72f7ea6Sql IEEE80211_FC0_TYPE_MGT) { 2212a72f7ea6Sql ctl0 &= ~(RTW_TXCTL0_SPLCP | RTW_TXCTL0_RTSEN); 2213a72f7ea6Sql if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 2214a72f7ea6Sql IEEE80211_FC0_SUBTYPE_BEACON) 2215a72f7ea6Sql ctl0 |= RTW_TXCTL0_BEACON; 2216a72f7ea6Sql } 2217a72f7ea6Sql 2218a72f7ea6Sql if (rtw_compute_duration(wh, pktlen, 2219a72f7ea6Sql ic->ic_flags, ic->ic_fragthreshold, 2220a72f7ea6Sql rate, &d0, &dn, &npkt) == -1) { 2221a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2222a72f7ea6Sql "%s: fail compute duration\n", __func__); 2223a72f7ea6Sql freemsg(mp0); 2224a72f7ea6Sql return (-1); 2225a72f7ea6Sql } 2226020c4770Sql *(uint16_t *)(uintptr_t)wh->i_dur = (d0.d_data_dur); 2227a72f7ea6Sql 2228a72f7ea6Sql ctl1 = LSHIFT(d0.d_plcp_len, RTW_TXCTL1_LENGTH_MASK) | 2229a72f7ea6Sql LSHIFT(d0.d_rts_dur, RTW_TXCTL1_RTSDUR_MASK); 2230a72f7ea6Sql 2231a72f7ea6Sql if (d0.d_residue) 2232a72f7ea6Sql ctl1 |= RTW_TXCTL1_LENGEXT; 2233a72f7ea6Sql 2234a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: duration=%x, ctl1=%x", __func__, 2235020c4770Sql *(uint16_t *)(uintptr_t)wh->i_dur, ctl1); 2236a72f7ea6Sql 2237a72f7ea6Sql if (bf->bf_dma.alength > RTW_TXLEN_LENGTH_MASK) { 2238a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2239a72f7ea6Sql "%s: seg too long\n", __func__); 2240a72f7ea6Sql freemsg(mp0); 2241a72f7ea6Sql return (-1); 2242a72f7ea6Sql } 2243a72f7ea6Sql ds->td_ctl0 = ctl0; 2244a72f7ea6Sql ds->td_ctl0 |= RTW_TXCTL0_OWN | RTW_TXCTL0_LS | RTW_TXCTL0_FS; 2245a72f7ea6Sql ds->td_ctl1 = ctl1; 2246a72f7ea6Sql ds->td_buf = bf->bf_dma.cookie.dmac_address; 2247a72f7ea6Sql ds->td_len = pktlen & 0xfff; 2248a72f7ea6Sql ds->td_next = bf->next_bf_daddr; 2249a72f7ea6Sql 2250a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 2251a72f7ea6Sql RTW_DESC_OFFSET(hd_txmd, bf->order), 2252a72f7ea6Sql sizeof (struct rtw_txdesc), 2253a72f7ea6Sql DDI_DMA_SYNC_FORDEV); 2254a72f7ea6Sql 2255a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2256a72f7ea6Sql "descriptor: order = %d, phy_addr=%x, ctl0=%x," 2257a72f7ea6Sql " ctl1=%x, buf=%x, len=%x, next=%x", bf->order, 2258a72f7ea6Sql bf->bf_daddr, ds->td_ctl0, ds->td_ctl1, 2259a72f7ea6Sql ds->td_buf, ds->td_len, ds->td_next); 2260a72f7ea6Sql rsc->sc_pktxmt64++; 2261a72f7ea6Sql rsc->sc_bytexmt64 += pktlen; 2262a72f7ea6Sql 2263a72f7ea6Sql freemsg(mp0); 2264a72f7ea6Sql return (0); 2265a72f7ea6Sql } 2266a72f7ea6Sql 2267a72f7ea6Sql static int 2268a72f7ea6Sql rtw_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 2269a72f7ea6Sql { 2270a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)ic; 2271a72f7ea6Sql struct ieee80211_node *in = ic->ic_bss; 2272a72f7ea6Sql struct rtw_txbuf *bf = NULL; 2273a72f7ea6Sql int ret, i = RTW_TXPRIMD; 2274a72f7ea6Sql 2275a72f7ea6Sql mutex_enter(&rsc->sc_txlock); 2276a72f7ea6Sql mutex_enter(&rsc->sc_txq[i].txbuf_lock); 2277a72f7ea6Sql bf = list_head(&rsc->sc_txq[i].tx_free_list); 2278a72f7ea6Sql 2279a72f7ea6Sql if ((bf == NULL) || (rsc->sc_txq[i].tx_nfree <= 4)) { 2280a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: no tx buf\n", __func__); 2281a72f7ea6Sql rsc->sc_noxmtbuf++; 2282a72f7ea6Sql if ((type & IEEE80211_FC0_TYPE_MASK) == 2283a72f7ea6Sql IEEE80211_FC0_TYPE_DATA) { 2284a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "%s: need reschedule\n", 2285a72f7ea6Sql __func__); 2286a72f7ea6Sql rsc->sc_need_reschedule = 1; 2287a72f7ea6Sql } else { 2288a72f7ea6Sql freemsg(mp); 2289a72f7ea6Sql } 2290a72f7ea6Sql mutex_exit(&rsc->sc_txq[i].txbuf_lock); 2291a72f7ea6Sql mutex_exit(&rsc->sc_txlock); 2292a72f7ea6Sql return (1); 2293a72f7ea6Sql } 2294a72f7ea6Sql list_remove(&rsc->sc_txq[i].tx_free_list, bf); 2295a72f7ea6Sql rsc->sc_txq[i].tx_nfree--; 2296a72f7ea6Sql 2297a72f7ea6Sql /* assemble 802.11 frame here */ 2298a72f7ea6Sql ret = rtw_assembly_80211(rsc, bf, mp); 2299a72f7ea6Sql if (ret != 0) { 2300a72f7ea6Sql cmn_err(CE_WARN, "%s assembly frame error\n", __func__); 2301a72f7ea6Sql mutex_exit(&rsc->sc_txq[i].txbuf_lock); 2302a72f7ea6Sql mutex_exit(&rsc->sc_txlock); 2303a72f7ea6Sql if ((type & IEEE80211_FC0_TYPE_MASK) != 2304a72f7ea6Sql IEEE80211_FC0_TYPE_DATA) { 2305a72f7ea6Sql freemsg(mp); 2306a72f7ea6Sql } 2307a72f7ea6Sql return (1); 2308a72f7ea6Sql } 2309a72f7ea6Sql list_insert_tail(&rsc->sc_txq[i].tx_dirty_list, bf); 2310a72f7ea6Sql bf->bf_in = in; 2311a72f7ea6Sql rtw_dma_start(&rsc->sc_regs, i); 2312a72f7ea6Sql 2313a72f7ea6Sql mutex_exit(&rsc->sc_txq[i].txbuf_lock); 2314a72f7ea6Sql mutex_exit(&rsc->sc_txlock); 2315a72f7ea6Sql 2316a72f7ea6Sql freemsg(mp); 2317a72f7ea6Sql return (0); 2318a72f7ea6Sql } 2319a72f7ea6Sql 2320a72f7ea6Sql static mblk_t * 2321a72f7ea6Sql rtw_m_tx(void *arg, mblk_t *mp) 2322a72f7ea6Sql { 2323a72f7ea6Sql rtw_softc_t *rsc = arg; 2324a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)rsc; 2325a72f7ea6Sql mblk_t *next; 2326a72f7ea6Sql 2327a72f7ea6Sql if (ic->ic_state != IEEE80211_S_RUN) { 2328a72f7ea6Sql freemsgchain(mp); 2329a72f7ea6Sql return (NULL); 2330a72f7ea6Sql } 2331a72f7ea6Sql 2332a72f7ea6Sql while (mp != NULL) { 2333a72f7ea6Sql next = mp->b_next; 2334a72f7ea6Sql mp->b_next = NULL; 2335a72f7ea6Sql 2336a72f7ea6Sql if (rtw_send(ic, mp, IEEE80211_FC0_TYPE_DATA)) { 2337a72f7ea6Sql mp->b_next = next; 2338a72f7ea6Sql break; 2339a72f7ea6Sql } 2340a72f7ea6Sql mp = next; 2341a72f7ea6Sql } 2342a72f7ea6Sql 2343a72f7ea6Sql return (mp); 2344a72f7ea6Sql 2345a72f7ea6Sql } 2346a72f7ea6Sql 2347a72f7ea6Sql static void 2348a72f7ea6Sql rtw_next_scan(void *arg) 2349a72f7ea6Sql { 2350a72f7ea6Sql ieee80211com_t *ic = arg; 2351a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 2352a72f7ea6Sql 2353a72f7ea6Sql rsc->sc_scan_id = 0; 2354a72f7ea6Sql if (ic->ic_state == IEEE80211_S_SCAN) { 2355a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_TUNE, "rtw_next_scan\n"); 2356a72f7ea6Sql (void) ieee80211_next_scan(ic); 2357a72f7ea6Sql } 2358a72f7ea6Sql 2359a72f7ea6Sql } 2360a72f7ea6Sql 2361a72f7ea6Sql static void 2362a72f7ea6Sql rtw_join_bss(rtw_softc_t *rsc, uint8_t *bssid, uint16_t intval0) 2363a72f7ea6Sql { 2364a72f7ea6Sql uint16_t bcnitv, intval; 2365a72f7ea6Sql int i; 2366a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 2367a72f7ea6Sql 2368a72f7ea6Sql for (i = 0; i < IEEE80211_ADDR_LEN; i++) 2369a72f7ea6Sql RTW_WRITE8(regs, RTW_BSSID + i, bssid[i]); 2370a72f7ea6Sql 2371a72f7ea6Sql RTW_SYNC(regs, RTW_BSSID16, RTW_BSSID32); 2372a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_CONFIG); 2373a72f7ea6Sql 2374a72f7ea6Sql RTW_WRITE8(regs, RTW_MSR, 0x8); /* sta mode link ok */ 2375a72f7ea6Sql intval = MIN(intval0, PRESHIFT(RTW_BCNITV_BCNITV_MASK)); 2376a72f7ea6Sql 2377a72f7ea6Sql bcnitv = RTW_READ16(regs, RTW_BCNITV) & ~RTW_BCNITV_BCNITV_MASK; 2378a72f7ea6Sql bcnitv |= LSHIFT(intval, RTW_BCNITV_BCNITV_MASK); 2379a72f7ea6Sql RTW_WRITE16(regs, RTW_BCNITV, bcnitv); 2380a72f7ea6Sql RTW_WRITE16(regs, RTW_ATIMWND, LSHIFT(1, RTW_ATIMWND_ATIMWND)); 2381a72f7ea6Sql RTW_WRITE16(regs, RTW_ATIMTRITV, LSHIFT(2, RTW_ATIMTRITV_ATIMTRITV)); 2382a72f7ea6Sql 2383a72f7ea6Sql rtw_set_access(regs, RTW_ACCESS_NONE); 2384a72f7ea6Sql 2385a72f7ea6Sql /* TBD WEP */ 2386a72f7ea6Sql /* RTW_WRITE8(regs, RTW_SCR, 0); */ 2387a72f7ea6Sql 2388a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 1); 2389a72f7ea6Sql } 2390a72f7ea6Sql 2391a72f7ea6Sql /* 2392a72f7ea6Sql * Set the starting transmit rate for a node. 2393a72f7ea6Sql */ 2394a72f7ea6Sql static void 2395a72f7ea6Sql rtw_rate_ctl_start(rtw_softc_t *rsc, struct ieee80211_node *in) 2396a72f7ea6Sql { 2397a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)rsc; 2398a72f7ea6Sql int32_t srate; 2399a72f7ea6Sql 2400a72f7ea6Sql if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 2401a72f7ea6Sql /* 2402a72f7ea6Sql * No fixed rate is requested. For 11b start with 2403a72f7ea6Sql * the highest negotiated rate; otherwise, for 11g 2404a72f7ea6Sql * and 11a, we start "in the middle" at 24Mb or 36Mb. 2405a72f7ea6Sql */ 2406a72f7ea6Sql srate = in->in_rates.ir_nrates - 1; 2407a72f7ea6Sql if (ic->ic_curmode != IEEE80211_MODE_11B) { 2408a72f7ea6Sql /* 2409a72f7ea6Sql * Scan the negotiated rate set to find the 2410a72f7ea6Sql * closest rate. 2411a72f7ea6Sql */ 2412a72f7ea6Sql /* NB: the rate set is assumed sorted */ 2413a72f7ea6Sql for (; srate >= 0 && IEEE80211_RATE(srate) > 72; 2414a72f7ea6Sql srate--) 2415a72f7ea6Sql ; 2416a72f7ea6Sql } 2417a72f7ea6Sql } else { 2418a72f7ea6Sql /* 2419a72f7ea6Sql * A fixed rate is to be used; We know the rate is 2420a72f7ea6Sql * there because the rate set is checked when the 2421a72f7ea6Sql * station associates. 2422a72f7ea6Sql */ 2423a72f7ea6Sql /* NB: the rate set is assumed sorted */ 2424a72f7ea6Sql srate = in->in_rates.ir_nrates - 1; 2425a72f7ea6Sql for (; srate >= 0 && IEEE80211_RATE(srate) != ic->ic_fixed_rate; 2426a72f7ea6Sql srate--) 2427a72f7ea6Sql ; 2428a72f7ea6Sql } 2429a72f7ea6Sql in->in_txrate = srate; 2430a72f7ea6Sql } 2431a72f7ea6Sql 2432a72f7ea6Sql 2433a72f7ea6Sql /* 2434a72f7ea6Sql * Reset the rate control state for each 802.11 state transition. 2435a72f7ea6Sql */ 2436a72f7ea6Sql static void 2437a72f7ea6Sql rtw_rate_ctl_reset(rtw_softc_t *rsc, enum ieee80211_state state) 2438a72f7ea6Sql { 2439a72f7ea6Sql ieee80211com_t *ic = &rsc->sc_ic; 2440a72f7ea6Sql ieee80211_node_t *in; 2441a72f7ea6Sql 2442a72f7ea6Sql if (ic->ic_opmode == IEEE80211_M_STA) { 2443a72f7ea6Sql /* 2444a72f7ea6Sql * Reset local xmit state; this is really only 2445a72f7ea6Sql * meaningful when operating in station mode. 2446a72f7ea6Sql */ 2447a72f7ea6Sql in = (struct ieee80211_node *)ic->ic_bss; 2448a72f7ea6Sql 2449a72f7ea6Sql if (state == IEEE80211_S_RUN) { 2450a72f7ea6Sql rtw_rate_ctl_start(rsc, in); 2451a72f7ea6Sql } else { 2452a72f7ea6Sql in->in_txrate = 0; 2453a72f7ea6Sql } 2454a72f7ea6Sql } 2455a72f7ea6Sql #if 0 2456a72f7ea6Sql else { 2457a72f7ea6Sql /* 2458a72f7ea6Sql * When operating as a station the node table holds 2459a72f7ea6Sql * the AP's that were discovered during scanning. 2460a72f7ea6Sql * For any other operating mode we want to reset the 2461a72f7ea6Sql * tx rate state of each node. 2462a72f7ea6Sql */ 2463a72f7ea6Sql in = list_head(&ic->ic_in_list); 2464a72f7ea6Sql while (in != NULL) { 2465a72f7ea6Sql in->in_txrate = 0; 2466a72f7ea6Sql in = list_next(&ic->ic_in_list, in); 2467a72f7ea6Sql } 2468a72f7ea6Sql in->in_txrate = 0; 2469a72f7ea6Sql } 2470a72f7ea6Sql #endif 2471a72f7ea6Sql } 2472a72f7ea6Sql 2473a72f7ea6Sql static int startctl = 0; 2474a72f7ea6Sql 2475a72f7ea6Sql /* 2476a72f7ea6Sql * Examine and potentially adjust the transmit rate. 2477a72f7ea6Sql */ 2478a72f7ea6Sql static void 2479a72f7ea6Sql rtw_rate_ctl(void *arg) 2480a72f7ea6Sql { 2481a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)arg; 2482a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)ic; 2483a72f7ea6Sql struct ieee80211_node *in = ic->ic_bss; 2484a72f7ea6Sql struct ieee80211_rateset *rs = &in->in_rates; 2485a72f7ea6Sql int32_t mod = 0, nrate, enough; 2486a72f7ea6Sql 2487a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 2488a72f7ea6Sql 2489a72f7ea6Sql enough = (rsc->sc_tx_ok + rsc->sc_tx_err >= 10); 2490a72f7ea6Sql 2491a72f7ea6Sql /* no packet reached -> down */ 2492a72f7ea6Sql if (rsc->sc_tx_err > 0 && rsc->sc_tx_ok == 0) 2493a72f7ea6Sql mod = -1; 2494a72f7ea6Sql 2495a72f7ea6Sql /* all packets needs retry in average -> down */ 2496a72f7ea6Sql if (enough && rsc->sc_tx_ok < rsc->sc_tx_err) 2497a72f7ea6Sql mod = -1; 2498a72f7ea6Sql 2499a72f7ea6Sql /* no error and less than 10% of packets needs retry -> up */ 2500a72f7ea6Sql if (enough && 2501a72f7ea6Sql rsc->sc_tx_ok > rsc->sc_tx_err * 5) 2502a72f7ea6Sql mod = 1; 2503a72f7ea6Sql 2504a72f7ea6Sql nrate = in->in_txrate; 2505a72f7ea6Sql switch (mod) { 2506a72f7ea6Sql case 0: 2507a72f7ea6Sql if (enough && rsc->sc_tx_upper > 0) 2508a72f7ea6Sql rsc->sc_tx_upper--; 2509a72f7ea6Sql break; 2510a72f7ea6Sql case -1: 2511a72f7ea6Sql if (nrate > 0) { 2512a72f7ea6Sql nrate--; 2513a72f7ea6Sql } 2514a72f7ea6Sql rsc->sc_tx_upper = 0; 2515a72f7ea6Sql break; 2516a72f7ea6Sql case 1: 2517a72f7ea6Sql if (++rsc->sc_tx_upper < 10) 2518a72f7ea6Sql break; 2519a72f7ea6Sql rsc->sc_tx_upper = 0; 2520a72f7ea6Sql if (nrate + 1 < rs->ir_nrates) { 2521a72f7ea6Sql nrate++; 2522a72f7ea6Sql } 2523a72f7ea6Sql break; 2524a72f7ea6Sql } 2525a72f7ea6Sql 2526a72f7ea6Sql if (nrate != in->in_txrate) { 2527a72f7ea6Sql in->in_txrate = nrate; 2528a72f7ea6Sql } else if (enough) 2529a72f7ea6Sql rsc->sc_tx_ok = rsc->sc_tx_err = rsc->sc_tx_retr = 0; 2530a72f7ea6Sql if (!startctl) { 2531a72f7ea6Sql rsc->sc_tx_ok = rsc->sc_tx_err = rsc->sc_tx_retr = 0; 2532a72f7ea6Sql startctl = 1; 2533a72f7ea6Sql } 2534a72f7ea6Sql 2535a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2536a72f7ea6Sql if (ic->ic_state == IEEE80211_S_RUN) 2537a72f7ea6Sql rsc->sc_ratectl_id = timeout(rtw_rate_ctl, ic, 2538a72f7ea6Sql drv_usectohz(1000000)); 2539a72f7ea6Sql } 2540a72f7ea6Sql 2541a72f7ea6Sql static int32_t 2542a72f7ea6Sql rtw_new_state(ieee80211com_t *ic, enum ieee80211_state nstate, int arg) 2543a72f7ea6Sql { 2544a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)ic; 2545a72f7ea6Sql int error; 2546a72f7ea6Sql enum ieee80211_state ostate; 2547a72f7ea6Sql 2548a72f7ea6Sql ostate = ic->ic_state; 2549a72f7ea6Sql 2550a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 2551a72f7ea6Sql "rtw_new_state: ostate:0x%x, nstate:0x%x, opmode:0x%x\n", 2552a72f7ea6Sql ostate, nstate, ic->ic_opmode); 2553a72f7ea6Sql 2554a72f7ea6Sql 2555a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 2556a72f7ea6Sql if (rsc->sc_scan_id != 0) { 2557a72f7ea6Sql (void) untimeout(rsc->sc_scan_id); 2558a72f7ea6Sql rsc->sc_scan_id = 0; 2559a72f7ea6Sql } 2560a72f7ea6Sql if (rsc->sc_ratectl_id != 0) { 2561a72f7ea6Sql (void) untimeout(rsc->sc_ratectl_id); 2562a72f7ea6Sql rsc->sc_ratectl_id = 0; 2563a72f7ea6Sql } 2564a72f7ea6Sql rtw_rate_ctl_reset(rsc, nstate); 2565a72f7ea6Sql if (ostate == IEEE80211_S_INIT && nstate != IEEE80211_S_INIT) 2566a72f7ea6Sql (void) rtw_pwrstate(rsc, RTW_ON); 2567a72f7ea6Sql if ((error = rtw_tune(rsc)) != 0) { 2568a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2569a72f7ea6Sql return (error); 2570a72f7ea6Sql } 2571a72f7ea6Sql switch (nstate) { 2572a72f7ea6Sql case IEEE80211_S_INIT: 2573a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_INIT\n"); 2574a72f7ea6Sql startctl = 0; 2575a72f7ea6Sql break; 2576a72f7ea6Sql case IEEE80211_S_SCAN: 2577a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_SCAN\n"); 2578a72f7ea6Sql rsc->sc_scan_id = timeout(rtw_next_scan, ic, 2579a72f7ea6Sql drv_usectohz(200000)); 2580a72f7ea6Sql rtw_set_nettype(rsc, IEEE80211_M_MONITOR); 2581a72f7ea6Sql break; 2582a72f7ea6Sql case IEEE80211_S_RUN: 2583a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_new_state: S_RUN\n"); 2584a72f7ea6Sql switch (ic->ic_opmode) { 2585a72f7ea6Sql case IEEE80211_M_HOSTAP: 2586a72f7ea6Sql case IEEE80211_M_IBSS: 2587a72f7ea6Sql rtw_set_nettype(rsc, IEEE80211_M_MONITOR); 2588a72f7ea6Sql /* TBD */ 2589a72f7ea6Sql /*FALLTHROUGH*/ 2590a72f7ea6Sql case IEEE80211_M_AHDEMO: 2591a72f7ea6Sql case IEEE80211_M_STA: 2592a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 2593a72f7ea6Sql "rtw_new_state: sta\n"); 2594a72f7ea6Sql rtw_join_bss(rsc, ic->ic_bss->in_bssid, 0); 2595a72f7ea6Sql rsc->sc_ratectl_id = timeout(rtw_rate_ctl, ic, 2596a72f7ea6Sql drv_usectohz(1000000)); 2597a72f7ea6Sql break; 2598a72f7ea6Sql case IEEE80211_M_MONITOR: 2599a72f7ea6Sql break; 2600a72f7ea6Sql } 2601a72f7ea6Sql rtw_set_nettype(rsc, ic->ic_opmode); 2602a72f7ea6Sql break; 2603a72f7ea6Sql case IEEE80211_S_ASSOC: 2604a72f7ea6Sql case IEEE80211_S_AUTH: 2605a72f7ea6Sql break; 2606a72f7ea6Sql } 2607a72f7ea6Sql 2608a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2609a72f7ea6Sql /* 2610a72f7ea6Sql * Invoke the parent method to complete the work. 2611a72f7ea6Sql */ 2612a72f7ea6Sql error = rsc->sc_newstate(ic, nstate, arg); 2613a72f7ea6Sql 2614a72f7ea6Sql return (error); 2615a72f7ea6Sql } 2616a72f7ea6Sql 2617a72f7ea6Sql static void 2618a72f7ea6Sql rtw_intr_rx(rtw_softc_t *rsc) 2619a72f7ea6Sql { 2620a72f7ea6Sql #define IS_BEACON(__fc0) \ 2621a72f7ea6Sql ((__fc0 & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==\ 2622a72f7ea6Sql (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON)) 2623a72f7ea6Sql /* 2624a72f7ea6Sql * ratetbl[4] = {2, 4, 11, 22}; 2625a72f7ea6Sql */ 2626a72f7ea6Sql struct rtw_rxbuf *bf; 2627a72f7ea6Sql struct rtw_rxdesc *ds; 2628a72f7ea6Sql int hwrate, len, rssi; 2629a72f7ea6Sql uint32_t hstat, hrssi, htsftl; 2630a72f7ea6Sql int is_last, next, n = 0, i; 2631a72f7ea6Sql struct ieee80211_frame *wh; 2632a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)rsc; 2633a72f7ea6Sql mblk_t *mp; 2634a72f7ea6Sql 2635a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RECV, "%s rtw_intr_rx: enter ic_state=%x\n", 2636a72f7ea6Sql __func__, rsc->sc_ic.ic_state); 2637a72f7ea6Sql mutex_enter(&rsc->rxbuf_lock); 2638a72f7ea6Sql next = rsc->rx_next; 2639a72f7ea6Sql mutex_exit(&rsc->rxbuf_lock); 2640a72f7ea6Sql for (i = 0; i < RTW_RXQLEN; i++) { 2641a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 2642a72f7ea6Sql RTW_DESC_OFFSET(hd_rx, next), 2643a72f7ea6Sql sizeof (struct rtw_rxdesc), 2644a72f7ea6Sql DDI_DMA_SYNC_FORKERNEL); 2645a72f7ea6Sql n++; 2646a72f7ea6Sql bf = rsc->rxbuf_h + next; 2647a72f7ea6Sql ds = bf->rxdesc; 2648a72f7ea6Sql hstat = (ds->rd_stat); 2649a72f7ea6Sql hrssi = ds->rd_rssi; 2650a72f7ea6Sql htsftl = ds->rd_tsftl; 2651a72f7ea6Sql /* htsfth = ds->rd_tsfth; */ 2652a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RECV, "%s: stat=%x\n", __func__, hstat); 2653a72f7ea6Sql /* still belongs to NIC */ 2654a72f7ea6Sql if ((hstat & RTW_RXSTAT_OWN) != 0) { 2655a72f7ea6Sql if (n > 1) { 2656a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RECV, 2657a72f7ea6Sql "%s: n > 1\n", __func__); 2658a72f7ea6Sql break; 2659a72f7ea6Sql } 2660a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 2661a72f7ea6Sql RTW_DESC_OFFSET(hd_rx, 0), 2662a72f7ea6Sql sizeof (struct rtw_rxdesc), 2663a72f7ea6Sql DDI_DMA_SYNC_FORCPU); 2664a72f7ea6Sql bf = rsc->rxbuf_h; 2665a72f7ea6Sql ds = bf->rxdesc; 2666a72f7ea6Sql hstat = (ds->rd_stat); 2667a72f7ea6Sql if ((hstat & RTW_RXSTAT_OWN) != 0) 2668a72f7ea6Sql break; 2669a72f7ea6Sql next = 0 /* RTW_RXQLEN - 1 */; 2670a72f7ea6Sql continue; 2671a72f7ea6Sql } 2672a72f7ea6Sql 2673a72f7ea6Sql rsc->sc_pktrcv64++; 2674a72f7ea6Sql if ((hstat & RTW_RXSTAT_IOERROR) != 0) { 2675a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RECV, 2676a72f7ea6Sql "rtw: DMA error/FIFO overflow %08x, " 2677a72f7ea6Sql "rx descriptor %d\n", 2678a72f7ea6Sql hstat & RTW_RXSTAT_IOERROR, next); 2679a72f7ea6Sql goto next; 2680a72f7ea6Sql } 2681a72f7ea6Sql 2682a72f7ea6Sql len = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_LENGTH_MASK); 2683a72f7ea6Sql rsc->sc_bytercv64 += len; 2684a72f7ea6Sql 2685a72f7ea6Sql /* CRC is included with the packet; trim it off. */ 2686a72f7ea6Sql /* len -= IEEE80211_CRC_LEN; */ 2687a72f7ea6Sql 2688a72f7ea6Sql hwrate = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_RATE_MASK); 2689a72f7ea6Sql if (hwrate >= 4) { 2690a72f7ea6Sql goto next; 2691a72f7ea6Sql } 2692a72f7ea6Sql 2693a72f7ea6Sql if ((hstat & RTW_RXSTAT_RES) != 0 && 2694a72f7ea6Sql rsc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) { 2695a72f7ea6Sql goto next; 2696a72f7ea6Sql } 2697a72f7ea6Sql 2698a72f7ea6Sql /* if bad flags, skip descriptor */ 2699a72f7ea6Sql if ((hstat & RTW_RXSTAT_ONESEG) != RTW_RXSTAT_ONESEG) { 2700a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RECV, 2701a72f7ea6Sql "rtw too many rx segments\n"); 2702a72f7ea6Sql goto next; 2703a72f7ea6Sql } 2704a72f7ea6Sql 2705a72f7ea6Sql if (rsc->sc_rfchipid == RTW_RFCHIPID_PHILIPS) 2706a72f7ea6Sql rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_RSSI); 2707a72f7ea6Sql else { 2708a72f7ea6Sql rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_IMR_RSSI); 2709a72f7ea6Sql /* 2710a72f7ea6Sql * TBD find out each front-end's LNA gain in the 2711a72f7ea6Sql * front-end's units 2712a72f7ea6Sql */ 2713a72f7ea6Sql if ((hrssi & RTW_RXRSSI_IMR_LNA) == 0) 2714a72f7ea6Sql rssi |= 0x80; 2715a72f7ea6Sql } 2716a72f7ea6Sql /* sq = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_SQ); */ 2717a72f7ea6Sql 2718a72f7ea6Sql 2719a72f7ea6Sql /* deal with the frame itself here */ 2720a72f7ea6Sql mp = allocb(rsc->sc_dmabuf_size, BPRI_MED); 2721a72f7ea6Sql if (mp == NULL) { 2722a72f7ea6Sql cmn_err(CE_WARN, "rtw: alloc mblk error"); 2723a72f7ea6Sql rsc->sc_norcvbuf++; 2724a72f7ea6Sql return; 2725a72f7ea6Sql } 2726a72f7ea6Sql len -= IEEE80211_CRC_LEN; 2727a72f7ea6Sql RTW_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORKERNEL); 2728a72f7ea6Sql bcopy(bf->bf_dma.mem_va, mp->b_rptr, len); 2729a72f7ea6Sql mp->b_wptr += len; 2730a72f7ea6Sql wh = (struct ieee80211_frame *)mp->b_rptr; 2731a72f7ea6Sql if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 2732a72f7ea6Sql IEEE80211_FC0_TYPE_CTL) { 2733a72f7ea6Sql cmn_err(CE_WARN, "TYPE CTL !!\n"); 2734a72f7ea6Sql freemsg(mp); 2735a72f7ea6Sql goto next; 2736a72f7ea6Sql } 2737a72f7ea6Sql (void) ieee80211_input(ic, mp, ic->ic_bss, rssi, htsftl); 2738a72f7ea6Sql next: 2739a72f7ea6Sql if (next == 63) 2740a72f7ea6Sql is_last = 1; 2741a72f7ea6Sql else 2742a72f7ea6Sql is_last = 0; 2743a72f7ea6Sql rtw_rxdesc_init(rsc, bf, next, is_last); 2744a72f7ea6Sql 2745a72f7ea6Sql next = (next + 1)%RTW_RXQLEN; 2746a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_RECV, "%s: next = %d\n", __func__, next); 2747a72f7ea6Sql } 2748a72f7ea6Sql mutex_enter(&rsc->rxbuf_lock); 2749a72f7ea6Sql rsc->rx_next = next; 2750a72f7ea6Sql mutex_exit(&rsc->rxbuf_lock); 2751a72f7ea6Sql } 2752a72f7ea6Sql 2753a72f7ea6Sql static void 2754a72f7ea6Sql rtw_ring_recycling(rtw_softc_t *rsc, uint16_t isr, uint32_t pri) 2755a72f7ea6Sql { 2756a72f7ea6Sql struct rtw_txbuf *bf; 2757a72f7ea6Sql struct rtw_txdesc *ds; 2758a72f7ea6Sql uint32_t hstat; 2759a72f7ea6Sql uint32_t head = 0; 2760a72f7ea6Sql uint32_t cnt = 0, idx = 0; 2761a72f7ea6Sql 2762a72f7ea6Sql mutex_enter(&rsc->sc_txq[pri].txbuf_lock); 2763a72f7ea6Sql head = RTW_READ(&rsc->sc_regs, RTW_TNPDA); 2764a72f7ea6Sql if (head == rsc->hw_go) { 2765a72f7ea6Sql mutex_exit(&rsc->sc_txq[pri].txbuf_lock); 2766a72f7ea6Sql return; 2767a72f7ea6Sql } 2768a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "rtw_ring_recycling: enter ic_state=%x\n", 2769a72f7ea6Sql rsc->sc_ic.ic_state); 2770a72f7ea6Sql 2771a72f7ea6Sql bf = list_head(&rsc->sc_txq[pri].tx_dirty_list); 2772a72f7ea6Sql if (bf == NULL) { 2773a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2774a72f7ea6Sql "rtw_ring_recycling: dirty bf[%d] NULL\n", pri); 2775a72f7ea6Sql mutex_exit(&rsc->sc_txq[pri].txbuf_lock); 2776a72f7ea6Sql return; 2777a72f7ea6Sql } 2778a72f7ea6Sql 2779a72f7ea6Sql while ((bf != NULL) && (rsc->hw_go != head)) { 2780a72f7ea6Sql cnt++; 2781a72f7ea6Sql idx = (rsc->hw_go - rsc->hw_start) / sizeof (struct rtw_txdesc); 2782a72f7ea6Sql if (idx == 63) 2783a72f7ea6Sql rsc->hw_go = rsc->hw_start; 2784a72f7ea6Sql else 2785a72f7ea6Sql rsc->hw_go += sizeof (struct rtw_txdesc); 2786a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 2787a72f7ea6Sql RTW_DESC_OFFSET(hd_txmd, idx), 2788a72f7ea6Sql sizeof (struct rtw_txdesc), 2789a72f7ea6Sql DDI_DMA_SYNC_FORCPU); 2790a72f7ea6Sql 2791a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, "Head = 0x%x\n", head); 2792a72f7ea6Sql ds = bf->txdesc; 2793a72f7ea6Sql hstat = (ds->td_stat); 2794a72f7ea6Sql ds->td_len = ds->td_len & 0xfff; 2795a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2796a72f7ea6Sql "%s rtw_ring_recycling: stat=%x, pri=%x\n", 2797a72f7ea6Sql __func__, hstat, pri); 2798a72f7ea6Sql if (hstat & RTW_TXSTAT_TOK) 2799a72f7ea6Sql rsc->sc_tx_ok++; 2800a72f7ea6Sql else { 2801a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2802a72f7ea6Sql "TX err @%d, o %d, retry[%d], isr[0x%x], cnt %d\n", 2803a72f7ea6Sql idx, (hstat & RTW_TXSTAT_OWN)?1:0, 2804a72f7ea6Sql (hstat & RTW_TXSTAT_DRC_MASK), isr, cnt); 2805a72f7ea6Sql if ((hstat & RTW_TXSTAT_DRC_MASK) <= 4) { 2806a72f7ea6Sql rsc->sc_tx_ok++; 2807a72f7ea6Sql } else { 2808a72f7ea6Sql rsc->sc_tx_err++; 2809a72f7ea6Sql } 2810a72f7ea6Sql } 2811a72f7ea6Sql rsc->sc_tx_retr += 2812a72f7ea6Sql (hstat & RTW_TXSTAT_DRC_MASK); 2813a72f7ea6Sql rsc->sc_xmtretry += 2814a72f7ea6Sql (hstat & RTW_TXSTAT_DRC_MASK); 2815a72f7ea6Sql list_remove(&rsc->sc_txq[pri].tx_dirty_list, bf); 2816a72f7ea6Sql list_insert_tail(&rsc->sc_txq[pri].tx_free_list, 2817a72f7ea6Sql bf); 2818a72f7ea6Sql (rsc->sc_txq[pri].tx_nfree)++; 2819a72f7ea6Sql if (rsc->sc_need_reschedule == 1) { 2820a72f7ea6Sql mac_tx_update(rsc->sc_ic.ic_mach); 2821a72f7ea6Sql rsc->sc_need_reschedule = 0; 2822a72f7ea6Sql } 2823a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_XMIT, 2824a72f7ea6Sql "rtw_ring_recycling: nfree[%d]=%d\n", 2825a72f7ea6Sql pri, rsc->sc_txq[pri].tx_nfree); 2826a72f7ea6Sql bzero((uint8_t *)ds, sizeof (struct rtw_txdesc)); 2827a72f7ea6Sql RTW_DMA_SYNC_DESC(rsc->sc_desc_dma, 2828a72f7ea6Sql RTW_DESC_OFFSET(hd_txmd, idx), 2829a72f7ea6Sql sizeof (struct rtw_txdesc), 2830a72f7ea6Sql DDI_DMA_SYNC_FORDEV); 2831a72f7ea6Sql bf = list_head(&rsc->sc_txq[pri].tx_dirty_list); 2832a72f7ea6Sql } 2833a72f7ea6Sql mutex_exit(&rsc->sc_txq[pri].txbuf_lock); 2834a72f7ea6Sql } 2835a72f7ea6Sql 2836a72f7ea6Sql static void 2837a72f7ea6Sql rtw_intr_timeout(rtw_softc_t *rsc) 2838a72f7ea6Sql { 2839a72f7ea6Sql rtw_resume_ticks(rsc); 2840a72f7ea6Sql } 2841a72f7ea6Sql 2842a72f7ea6Sql static uint_t 2843a72f7ea6Sql rtw_intr(caddr_t arg) 2844a72f7ea6Sql { 2845020c4770Sql /* LINTED E_BAD_PTR_CAST_ALIGN */ 2846a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 2847a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 2848a72f7ea6Sql uint16_t isr = 0; 2849a72f7ea6Sql 2850a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 2851a72f7ea6Sql isr = RTW_READ16(regs, RTW_ISR); 2852a72f7ea6Sql RTW_WRITE16(regs, RTW_ISR, isr); 2853a72f7ea6Sql 2854a72f7ea6Sql if (isr == 0) { 2855a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2856a72f7ea6Sql return (DDI_INTR_UNCLAIMED); 2857a72f7ea6Sql } 2858a72f7ea6Sql 2859a72f7ea6Sql #ifdef DEBUG 2860a72f7ea6Sql #define PRINTINTR(flag) { \ 2861a72f7ea6Sql if ((isr & flag) != 0) { \ 2862a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_INTR, "|" #flag); \ 2863a72f7ea6Sql } \ 2864a72f7ea6Sql } 2865a72f7ea6Sql 2866a72f7ea6Sql if ((rtw_dbg_flags & RTW_DEBUG_INTR) != 0 && isr != 0) { 2867a72f7ea6Sql 2868a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_INTR, "rtw: reg[ISR] = %x", isr); 2869a72f7ea6Sql 2870a72f7ea6Sql PRINTINTR(RTW_INTR_TXFOVW); 2871a72f7ea6Sql PRINTINTR(RTW_INTR_TIMEOUT); 2872a72f7ea6Sql PRINTINTR(RTW_INTR_BCNINT); 2873a72f7ea6Sql PRINTINTR(RTW_INTR_ATIMINT); 2874a72f7ea6Sql PRINTINTR(RTW_INTR_TBDER); 2875a72f7ea6Sql PRINTINTR(RTW_INTR_TBDOK); 2876a72f7ea6Sql PRINTINTR(RTW_INTR_THPDER); 2877a72f7ea6Sql PRINTINTR(RTW_INTR_THPDOK); 2878a72f7ea6Sql PRINTINTR(RTW_INTR_TNPDER); 2879a72f7ea6Sql PRINTINTR(RTW_INTR_TNPDOK); 2880a72f7ea6Sql PRINTINTR(RTW_INTR_RXFOVW); 2881a72f7ea6Sql PRINTINTR(RTW_INTR_RDU); 2882a72f7ea6Sql PRINTINTR(RTW_INTR_TLPDER); 2883a72f7ea6Sql PRINTINTR(RTW_INTR_TLPDOK); 2884a72f7ea6Sql PRINTINTR(RTW_INTR_RER); 2885a72f7ea6Sql PRINTINTR(RTW_INTR_ROK); 2886a72f7ea6Sql } 2887a72f7ea6Sql #undef PRINTINTR 2888a72f7ea6Sql #endif /* DEBUG */ 2889a72f7ea6Sql 2890a72f7ea6Sql rsc->sc_intr++; 2891a72f7ea6Sql 2892a72f7ea6Sql if ((isr & RTW_INTR_RX) != 0) { 2893a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2894a72f7ea6Sql rtw_intr_rx(rsc); 2895a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 2896a72f7ea6Sql } 2897a72f7ea6Sql if ((isr & RTW_INTR_TIMEOUT) != 0) 2898a72f7ea6Sql rtw_intr_timeout(rsc); 2899a72f7ea6Sql 2900a72f7ea6Sql if ((isr & RTW_INTR_TX) != 0) 2901a72f7ea6Sql rtw_ring_recycling(rsc, isr, 1); 2902a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2903a72f7ea6Sql return (DDI_INTR_CLAIMED); 2904a72f7ea6Sql } 2905a72f7ea6Sql 2906a72f7ea6Sql static void 2907a72f7ea6Sql rtw_m_stop(void *arg) 2908a72f7ea6Sql { 2909a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 2910a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 2911a72f7ea6Sql 2912a72f7ea6Sql (void) ieee80211_new_state(&rsc->sc_ic, IEEE80211_S_INIT, -1); 2913a72f7ea6Sql /* 2914a72f7ea6Sql * Stop the transmit and receive processes. First stop DMA, 2915a72f7ea6Sql * then disable receiver and transmitter. 2916a72f7ea6Sql */ 2917a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 2918a72f7ea6Sql rtw_disable_interrupts(regs); 2919a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0); 2920a72f7ea6Sql RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL); 2921a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 2922a72f7ea6Sql delay(1); 2923a72f7ea6Sql 2924a72f7ea6Sql rsc->sc_invalid = 1; 2925a72f7ea6Sql } 2926a72f7ea6Sql 2927*94d05f6cSQin Michael Li /* 2928*94d05f6cSQin Michael Li * quiesce(9E) entry point. 2929*94d05f6cSQin Michael Li * 2930*94d05f6cSQin Michael Li * This function is called when the system is single-threaded at high 2931*94d05f6cSQin Michael Li * PIL with preemption disabled. Therefore, this function must not be 2932*94d05f6cSQin Michael Li * blocked. 2933*94d05f6cSQin Michael Li * 2934*94d05f6cSQin Michael Li * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 2935*94d05f6cSQin Michael Li * DDI_FAILURE indicates an error condition and should almost never happen. 2936*94d05f6cSQin Michael Li */ 2937*94d05f6cSQin Michael Li int 2938*94d05f6cSQin Michael Li rtw_quiesce(dev_info_t *dip) 2939*94d05f6cSQin Michael Li { 2940*94d05f6cSQin Michael Li rtw_softc_t *rsc = NULL; 2941*94d05f6cSQin Michael Li struct rtw_regs *regs; 2942*94d05f6cSQin Michael Li 2943*94d05f6cSQin Michael Li rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(dip)); 2944*94d05f6cSQin Michael Li ASSERT(rsc != NULL); 2945*94d05f6cSQin Michael Li regs = &rsc->sc_regs; 2946*94d05f6cSQin Michael Li 2947*94d05f6cSQin Michael Li rtw_dbg_flags = 0; 2948*94d05f6cSQin Michael Li rtw_disable_interrupts(regs); 2949*94d05f6cSQin Michael Li rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0); 2950*94d05f6cSQin Michael Li RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL); 2951*94d05f6cSQin Michael Li 2952*94d05f6cSQin Michael Li return (DDI_SUCCESS); 2953*94d05f6cSQin Michael Li } 2954*94d05f6cSQin Michael Li 2955*94d05f6cSQin Michael Li /* 2956*94d05f6cSQin Michael Li * callback functions for /get/set properties 2957*94d05f6cSQin Michael Li */ 2958*94d05f6cSQin Michael Li static int 2959*94d05f6cSQin Michael Li rtw_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2960*94d05f6cSQin Michael Li uint_t wldp_length, const void *wldp_buf) 2961*94d05f6cSQin Michael Li { 2962*94d05f6cSQin Michael Li rtw_softc_t *rsc = arg; 2963*94d05f6cSQin Michael Li int err; 2964*94d05f6cSQin Michael Li 2965*94d05f6cSQin Michael Li err = ieee80211_setprop(&rsc->sc_ic, pr_name, wldp_pr_num, 2966*94d05f6cSQin Michael Li wldp_length, wldp_buf); 2967*94d05f6cSQin Michael Li 2968*94d05f6cSQin Michael Li mutex_enter(&rsc->sc_genlock); 2969*94d05f6cSQin Michael Li if (err == ENETRESET) { 2970*94d05f6cSQin Michael Li if (rsc->sc_invalid == 0) { 2971*94d05f6cSQin Michael Li mutex_exit(&rsc->sc_genlock); 2972*94d05f6cSQin Michael Li rtw_m_stop(rsc); 2973*94d05f6cSQin Michael Li (void) rtw_m_start(rsc); 2974*94d05f6cSQin Michael Li (void) ieee80211_new_state(&rsc->sc_ic, 2975*94d05f6cSQin Michael Li IEEE80211_S_SCAN, -1); 2976*94d05f6cSQin Michael Li mutex_enter(&rsc->sc_genlock); 2977*94d05f6cSQin Michael Li } 2978*94d05f6cSQin Michael Li err = 0; 2979*94d05f6cSQin Michael Li } 2980*94d05f6cSQin Michael Li mutex_exit(&rsc->sc_genlock); 2981*94d05f6cSQin Michael Li return (err); 2982*94d05f6cSQin Michael Li } 2983*94d05f6cSQin Michael Li 2984*94d05f6cSQin Michael Li static int 2985*94d05f6cSQin Michael Li rtw_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2986*94d05f6cSQin Michael Li uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 2987*94d05f6cSQin Michael Li { 2988*94d05f6cSQin Michael Li rtw_softc_t *rsc = arg; 2989*94d05f6cSQin Michael Li int err; 2990*94d05f6cSQin Michael Li 2991*94d05f6cSQin Michael Li err = ieee80211_getprop(&rsc->sc_ic, pr_name, wldp_pr_num, 2992*94d05f6cSQin Michael Li pr_flags, wldp_length, wldp_buf, perm); 2993*94d05f6cSQin Michael Li 2994*94d05f6cSQin Michael Li return (err); 2995*94d05f6cSQin Michael Li } 2996*94d05f6cSQin Michael Li 2997a72f7ea6Sql 2998a72f7ea6Sql static int 2999a72f7ea6Sql rtw_m_start(void *arg) 3000a72f7ea6Sql { 3001a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 3002a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)rsc; 3003a72f7ea6Sql int ret; 3004a72f7ea6Sql #ifdef DEBUG 3005a72f7ea6Sql rtw_print_regs(&rsc->sc_regs, "rtw", "rtw_start"); 3006a72f7ea6Sql #endif 3007a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 3008a72f7ea6Sql ret = rtw_init(rsc); 3009a72f7ea6Sql if (ret) { 3010a72f7ea6Sql cmn_err(CE_WARN, "rtw: failed to do rtw_init\n"); 3011a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3012a72f7ea6Sql return (-1); 3013a72f7ea6Sql } 3014a72f7ea6Sql ic->ic_state = IEEE80211_S_INIT; 3015a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3016a72f7ea6Sql 3017a72f7ea6Sql /* 3018a72f7ea6Sql * fix KCF bug. - workaround, need to fix it in net80211 3019a72f7ea6Sql */ 3020a72f7ea6Sql (void) crypto_mech2id(SUN_CKM_RC4); 3021a72f7ea6Sql 3022a72f7ea6Sql (void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 3023a72f7ea6Sql rsc->sc_invalid = 0; 3024a72f7ea6Sql return (0); 3025a72f7ea6Sql } 3026a72f7ea6Sql 3027a72f7ea6Sql 3028a72f7ea6Sql static int 3029a72f7ea6Sql rtw_m_unicst(void *arg, const uint8_t *macaddr) 3030a72f7ea6Sql { 3031a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 3032a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)rsc; 3033a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 3034a72f7ea6Sql uint32_t t; 3035a72f7ea6Sql 3036a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 3037a72f7ea6Sql bcopy(macaddr, ic->ic_macaddr, 6); 3038a72f7ea6Sql t = ((*macaddr)<<24) | ((*(macaddr + 1))<<16) | 3039a72f7ea6Sql ((*(macaddr + 2))<<8) | (*(macaddr + 3)); 3040a72f7ea6Sql RTW_WRITE(regs, RTW_IDR0, ntohl(t)); 3041a72f7ea6Sql t = ((*(macaddr + 4))<<24) | ((*(macaddr + 5))<<16); 3042a72f7ea6Sql RTW_WRITE(regs, RTW_IDR1, ntohl(t)); 3043a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3044a72f7ea6Sql return (0); 3045a72f7ea6Sql } 3046a72f7ea6Sql 3047a72f7ea6Sql static int 3048a72f7ea6Sql rtw_m_promisc(void *arg, boolean_t on) 3049a72f7ea6Sql { 3050a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 3051a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 3052a72f7ea6Sql 3053a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 3054a72f7ea6Sql 3055a72f7ea6Sql if (on) 3056a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_PROMIC; 3057a72f7ea6Sql else 3058a72f7ea6Sql rsc->sc_rcr &= ~RTW_RCR_PROMIC; 3059a72f7ea6Sql 3060a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr); 3061a72f7ea6Sql 3062a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3063a72f7ea6Sql return (0); 3064a72f7ea6Sql } 3065a72f7ea6Sql 3066a72f7ea6Sql static int 3067a72f7ea6Sql rtw_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 3068a72f7ea6Sql { 3069a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 3070a72f7ea6Sql struct rtw_regs *regs = &rsc->sc_regs; 3071a72f7ea6Sql uint32_t t; 3072a72f7ea6Sql 3073a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 3074a72f7ea6Sql if (add) { 3075a72f7ea6Sql rsc->sc_rcr |= RTW_RCR_AM; 3076a72f7ea6Sql t = ((*macaddr)<<24) | ((*(macaddr + 1))<<16) | 3077a72f7ea6Sql ((*(macaddr + 2))<<8) | (*(macaddr + 3)); 3078a72f7ea6Sql RTW_WRITE(regs, RTW_MAR0, ntohl(t)); 3079a72f7ea6Sql t = ((*(macaddr + 4))<<24) | ((*(macaddr + 5))<<16); 3080a72f7ea6Sql RTW_WRITE(regs, RTW_MAR1, ntohl(t)); 3081a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr); 3082a72f7ea6Sql RTW_SYNC(regs, RTW_MAR0, RTW_RCR); 3083a72f7ea6Sql } else { 3084a72f7ea6Sql rsc->sc_rcr &= ~RTW_RCR_AM; 3085a72f7ea6Sql RTW_WRITE(regs, RTW_MAR0, 0); 3086a72f7ea6Sql RTW_WRITE(regs, RTW_MAR1, 0); 3087a72f7ea6Sql RTW_WRITE(regs, RTW_RCR, rsc->sc_rcr); 3088a72f7ea6Sql RTW_SYNC(regs, RTW_MAR0, RTW_RCR); 3089a72f7ea6Sql } 3090a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3091a72f7ea6Sql return (0); 3092a72f7ea6Sql } 3093a72f7ea6Sql 3094a72f7ea6Sql static void 3095a72f7ea6Sql rtw_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 3096a72f7ea6Sql { 3097a72f7ea6Sql rtw_softc_t *rsc = arg; 3098a72f7ea6Sql int32_t err; 3099a72f7ea6Sql 3100a72f7ea6Sql err = ieee80211_ioctl(&rsc->sc_ic, wq, mp); 3101a72f7ea6Sql if (err == ENETRESET) { 3102a72f7ea6Sql if (rsc->sc_invalid == 0) { 3103*94d05f6cSQin Michael Li rtw_m_stop(rsc); 3104*94d05f6cSQin Michael Li (void) rtw_m_start(rsc); 3105a72f7ea6Sql (void) ieee80211_new_state(&rsc->sc_ic, 3106a72f7ea6Sql IEEE80211_S_SCAN, -1); 3107a72f7ea6Sql } 3108a72f7ea6Sql } 3109a72f7ea6Sql } 3110a72f7ea6Sql 3111a72f7ea6Sql static int 3112a72f7ea6Sql rtw_m_stat(void *arg, uint_t stat, uint64_t *val) 3113a72f7ea6Sql { 3114a72f7ea6Sql rtw_softc_t *rsc = (rtw_softc_t *)arg; 3115a72f7ea6Sql ieee80211com_t *ic = (ieee80211com_t *)rsc; 3116a72f7ea6Sql struct ieee80211_node *in = ic->ic_bss; 3117a72f7ea6Sql struct ieee80211_rateset *rs = &in->in_rates; 3118a72f7ea6Sql 3119a72f7ea6Sql mutex_enter(&rsc->sc_genlock); 3120a72f7ea6Sql switch (stat) { 3121a72f7ea6Sql case MAC_STAT_IFSPEED: 3122a72f7ea6Sql *val = ((rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL)) 3123a72f7ea6Sql * 500000; 3124a72f7ea6Sql break; 3125a72f7ea6Sql case MAC_STAT_NOXMTBUF: 3126a72f7ea6Sql *val = rsc->sc_noxmtbuf; 3127a72f7ea6Sql break; 3128a72f7ea6Sql case MAC_STAT_NORCVBUF: 3129a72f7ea6Sql *val = rsc->sc_norcvbuf; 3130a72f7ea6Sql break; 3131a72f7ea6Sql case MAC_STAT_RBYTES: 3132a72f7ea6Sql *val = rsc->sc_bytercv64; 3133a72f7ea6Sql break; 3134a72f7ea6Sql case MAC_STAT_IPACKETS: 3135a72f7ea6Sql *val = rsc->sc_pktrcv64; 3136a72f7ea6Sql break; 3137a72f7ea6Sql case MAC_STAT_OBYTES: 3138a72f7ea6Sql *val = rsc->sc_bytexmt64; 3139a72f7ea6Sql break; 3140a72f7ea6Sql case MAC_STAT_OPACKETS: 3141a72f7ea6Sql *val = rsc->sc_pktxmt64; 3142a72f7ea6Sql break; 3143a72f7ea6Sql case WIFI_STAT_TX_RETRANS: 3144a72f7ea6Sql *val = rsc->sc_xmtretry; 3145a72f7ea6Sql break; 3146a72f7ea6Sql case WIFI_STAT_TX_FRAGS: 3147a72f7ea6Sql case WIFI_STAT_MCAST_TX: 3148a72f7ea6Sql case WIFI_STAT_RTS_SUCCESS: 3149a72f7ea6Sql case WIFI_STAT_RTS_FAILURE: 3150a72f7ea6Sql case WIFI_STAT_ACK_FAILURE: 3151a72f7ea6Sql case WIFI_STAT_RX_FRAGS: 3152a72f7ea6Sql case WIFI_STAT_MCAST_RX: 3153a72f7ea6Sql case WIFI_STAT_RX_DUPS: 3154a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3155a72f7ea6Sql return (ieee80211_stat(ic, stat, val)); 3156a72f7ea6Sql default: 3157a72f7ea6Sql *val = 0; 3158a72f7ea6Sql break; 3159a72f7ea6Sql } 3160a72f7ea6Sql mutex_exit(&rsc->sc_genlock); 3161a72f7ea6Sql 3162a72f7ea6Sql return (0); 3163a72f7ea6Sql } 3164a72f7ea6Sql 3165a72f7ea6Sql 3166a72f7ea6Sql static void 3167a72f7ea6Sql rtw_mutex_destroy(rtw_softc_t *rsc) 3168a72f7ea6Sql { 3169a72f7ea6Sql int i; 3170a72f7ea6Sql 3171a72f7ea6Sql mutex_destroy(&rsc->rxbuf_lock); 3172a72f7ea6Sql mutex_destroy(&rsc->sc_txlock); 3173a72f7ea6Sql for (i = 0; i < RTW_NTXPRI; i++) { 3174a72f7ea6Sql mutex_destroy(&rsc->sc_txq[RTW_NTXPRI - 1 - i].txbuf_lock); 3175a72f7ea6Sql } 3176a72f7ea6Sql mutex_destroy(&rsc->sc_genlock); 3177a72f7ea6Sql } 3178a72f7ea6Sql 3179a72f7ea6Sql static int 3180a72f7ea6Sql rtw_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3181a72f7ea6Sql { 3182a72f7ea6Sql rtw_softc_t *rsc; 3183a72f7ea6Sql ieee80211com_t *ic; 3184a72f7ea6Sql uint8_t csz; 3185a72f7ea6Sql uint32_t i; 3186a72f7ea6Sql uint16_t vendor_id, device_id, command; 3187a72f7ea6Sql int32_t err; 3188a72f7ea6Sql char strbuf[32]; 3189a72f7ea6Sql wifi_data_t wd = { 0 }; 3190a72f7ea6Sql mac_register_t *macp; 3191a72f7ea6Sql int instance = ddi_get_instance(devinfo); 3192a72f7ea6Sql 3193a72f7ea6Sql switch (cmd) { 3194a72f7ea6Sql case DDI_ATTACH: 3195a72f7ea6Sql break; 3196a72f7ea6Sql default: 3197a72f7ea6Sql return (DDI_FAILURE); 3198a72f7ea6Sql } 3199a72f7ea6Sql 3200a72f7ea6Sql if (ddi_soft_state_zalloc(rtw_soft_state_p, 3201a72f7ea6Sql ddi_get_instance(devinfo)) != DDI_SUCCESS) { 3202a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3203a72f7ea6Sql "Unable to alloc softstate\n"); 3204a72f7ea6Sql return (DDI_FAILURE); 3205a72f7ea6Sql } 3206a72f7ea6Sql 3207a72f7ea6Sql rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(devinfo)); 3208a72f7ea6Sql ic = &rsc->sc_ic; 3209a72f7ea6Sql rsc->sc_dev = devinfo; 3210a72f7ea6Sql 3211a72f7ea6Sql err = ddi_regs_map_setup(devinfo, 0, (caddr_t *)&rsc->sc_cfg_base, 0, 0, 3212a72f7ea6Sql &rtw_reg_accattr, &rsc->sc_cfg_handle); 3213a72f7ea6Sql if (err != DDI_SUCCESS) { 3214a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3215a72f7ea6Sql "ddi_regs_map_setup() failed"); 3216a72f7ea6Sql goto attach_fail0; 3217a72f7ea6Sql } 3218a72f7ea6Sql csz = ddi_get8(rsc->sc_cfg_handle, 3219a72f7ea6Sql (uint8_t *)(rsc->sc_cfg_base + PCI_CONF_CACHE_LINESZ)); 3220a72f7ea6Sql if (!csz) 3221a72f7ea6Sql csz = 16; 3222a72f7ea6Sql rsc->sc_cachelsz = csz << 2; 3223a72f7ea6Sql vendor_id = ddi_get16(rsc->sc_cfg_handle, 3224020c4770Sql (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_VENID)); 3225a72f7ea6Sql device_id = ddi_get16(rsc->sc_cfg_handle, 3226020c4770Sql (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_DEVID)); 3227a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): vendor 0x%x, " 3228a72f7ea6Sql "device id 0x%x, cache size %d\n", vendor_id, device_id, csz); 3229a72f7ea6Sql 3230a72f7ea6Sql /* 3231a72f7ea6Sql * Enable response to memory space accesses, 3232a72f7ea6Sql * and enabe bus master. 3233a72f7ea6Sql */ 3234a72f7ea6Sql command = PCI_COMM_MAE | PCI_COMM_ME; 3235a72f7ea6Sql ddi_put16(rsc->sc_cfg_handle, 3236020c4770Sql (uint16_t *)((uintptr_t)rsc->sc_cfg_base + PCI_CONF_COMM), command); 3237a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3238a72f7ea6Sql "set command reg to 0x%x \n", command); 3239a72f7ea6Sql 3240a72f7ea6Sql ddi_put8(rsc->sc_cfg_handle, 3241a72f7ea6Sql (uint8_t *)(rsc->sc_cfg_base + PCI_CONF_LATENCY_TIMER), 0xa8); 3242a72f7ea6Sql 3243a72f7ea6Sql ddi_regs_map_free(&rsc->sc_cfg_handle); 3244a72f7ea6Sql 3245a72f7ea6Sql err = ddi_regs_map_setup(devinfo, 2, (caddr_t *)&rsc->sc_regs.r_base, 3246a72f7ea6Sql 0, 0, &rtw_reg_accattr, &rsc->sc_regs.r_handle); 3247a72f7ea6Sql if (err != DDI_SUCCESS) { 3248a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3249a72f7ea6Sql "ddi_regs_map_setup() failed"); 3250a72f7ea6Sql goto attach_fail0; 3251a72f7ea6Sql } 3252a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: r_base=%x, r_handle=%x\n", 3253a72f7ea6Sql rsc->sc_regs.r_base, rsc->sc_regs.r_handle); 3254a72f7ea6Sql 3255a72f7ea6Sql err = rtw_dma_init(devinfo, rsc); 3256a72f7ea6Sql if (err != DDI_SUCCESS) { 3257a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3258a72f7ea6Sql "failed to init dma: %d\n", err); 3259a72f7ea6Sql goto attach_fail1; 3260a72f7ea6Sql } 3261a72f7ea6Sql 3262a72f7ea6Sql /* 3263a72f7ea6Sql * Stop the transmit and receive processes. First stop DMA, 3264a72f7ea6Sql * then disable receiver and transmitter. 3265a72f7ea6Sql */ 3266a72f7ea6Sql RTW_WRITE8(&rsc->sc_regs, RTW_TPPOLL, RTW_TPPOLL_SALL); 3267a72f7ea6Sql rtw_io_enable(rsc, RTW_CR_RE | RTW_CR_TE, 0); 3268a72f7ea6Sql 3269a72f7ea6Sql /* Reset the chip to a known state. */ 3270a72f7ea6Sql if (rtw_reset(rsc) != 0) { 3271a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3272a72f7ea6Sql "failed to reset\n"); 3273a72f7ea6Sql goto attach_fail2; 3274a72f7ea6Sql } 3275a72f7ea6Sql rsc->sc_rcr = RTW_READ(&rsc->sc_regs, RTW_RCR); 3276a72f7ea6Sql 3277a72f7ea6Sql if ((rsc->sc_rcr & RTW_RCR_9356SEL) != 0) 3278a72f7ea6Sql rsc->sc_flags |= RTW_F_9356SROM; 3279a72f7ea6Sql 3280a72f7ea6Sql if (rtw_srom_read(&rsc->sc_regs, rsc->sc_flags, &rsc->sc_srom, 3281a72f7ea6Sql "rtw") != 0) { 3282a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3283a72f7ea6Sql "failed to read srom\n"); 3284a72f7ea6Sql goto attach_fail2; 3285a72f7ea6Sql } 3286a72f7ea6Sql 3287a72f7ea6Sql if (rtw_srom_parse(&rsc->sc_srom, &rsc->sc_flags, &rsc->sc_csthr, 3288a72f7ea6Sql &rsc->sc_rfchipid, &rsc->sc_rcr, &rsc->sc_locale, 3289a72f7ea6Sql "rtw") != 0) { 3290a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw_attach():" 3291a72f7ea6Sql " malformed serial ROM\n"); 3292a72f7ea6Sql goto attach_fail3; 3293a72f7ea6Sql } 3294a72f7ea6Sql 3295a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_PHY, "rtw: %s PHY\n", 3296a72f7ea6Sql ((rsc->sc_flags & RTW_F_DIGPHY) != 0) ? "digital" : "analog"); 3297a72f7ea6Sql 3298a72f7ea6Sql 3299a72f7ea6Sql rsc->sc_rf = rtw_rf_attach(rsc, rsc->sc_rfchipid, 3300a72f7ea6Sql rsc->sc_flags & RTW_F_DIGPHY); 3301a72f7ea6Sql 3302a72f7ea6Sql if (rsc->sc_rf == NULL) { 3303a72f7ea6Sql cmn_err(CE_WARN, "rtw: rtw_attach(): could not attach RF\n"); 3304a72f7ea6Sql goto attach_fail3; 3305a72f7ea6Sql } 3306a72f7ea6Sql rsc->sc_phydelay = rtw_check_phydelay(&rsc->sc_regs, rsc->sc_rcr); 3307a72f7ea6Sql 3308a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, 3309a72f7ea6Sql "rtw: PHY delay %d\n", rsc->sc_phydelay); 3310a72f7ea6Sql 3311a72f7ea6Sql if (rsc->sc_locale == RTW_LOCALE_UNKNOWN) 3312a72f7ea6Sql rtw_identify_country(&rsc->sc_regs, &rsc->sc_locale, 3313a72f7ea6Sql "rtw"); 3314a72f7ea6Sql 3315a72f7ea6Sql rtw_init_channels(rsc->sc_locale, &rsc->sc_ic.ic_sup_channels, 3316a72f7ea6Sql "rtw"); 3317a72f7ea6Sql 3318a72f7ea6Sql rtw_set80211props(ic); 3319a72f7ea6Sql 3320a72f7ea6Sql if (rtw_identify_sta(&rsc->sc_regs, ic->ic_macaddr, 3321a72f7ea6Sql "rtw") != 0) 3322a72f7ea6Sql goto attach_fail4; 3323a72f7ea6Sql 3324a72f7ea6Sql ic->ic_xmit = rtw_send; 3325a72f7ea6Sql ieee80211_attach(ic); 3326a72f7ea6Sql 3327a72f7ea6Sql rsc->sc_newstate = ic->ic_newstate; 3328a72f7ea6Sql ic->ic_newstate = rtw_new_state; 3329a72f7ea6Sql ieee80211_media_init(ic); 3330a72f7ea6Sql ic->ic_def_txkey = 0; 3331a72f7ea6Sql 3332a72f7ea6Sql if (ddi_get_iblock_cookie(devinfo, 0, &(rsc->sc_iblock)) 3333a72f7ea6Sql != DDI_SUCCESS) { 3334a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3335a72f7ea6Sql "Can not get iblock cookie for INT\n"); 3336a72f7ea6Sql goto attach_fail5; 3337a72f7ea6Sql } 3338a72f7ea6Sql 3339a72f7ea6Sql mutex_init(&rsc->sc_genlock, NULL, MUTEX_DRIVER, rsc->sc_iblock); 3340a72f7ea6Sql for (i = 0; i < RTW_NTXPRI; i++) { 3341a72f7ea6Sql mutex_init(&rsc->sc_txq[i].txbuf_lock, NULL, MUTEX_DRIVER, 3342a72f7ea6Sql rsc->sc_iblock); 3343a72f7ea6Sql } 3344a72f7ea6Sql mutex_init(&rsc->rxbuf_lock, NULL, MUTEX_DRIVER, rsc->sc_iblock); 3345a72f7ea6Sql mutex_init(&rsc->sc_txlock, NULL, MUTEX_DRIVER, rsc->sc_iblock); 3346a72f7ea6Sql 3347a72f7ea6Sql if (ddi_add_intr(devinfo, 0, &rsc->sc_iblock, NULL, rtw_intr, 3348a72f7ea6Sql (caddr_t)(rsc)) != DDI_SUCCESS) { 3349a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3350a72f7ea6Sql "Can not add intr for rtw driver\n"); 3351a72f7ea6Sql goto attach_fail7; 3352a72f7ea6Sql } 3353a72f7ea6Sql 3354a72f7ea6Sql /* 3355a72f7ea6Sql * Provide initial settings for the WiFi plugin; whenever this 3356a72f7ea6Sql * information changes, we need to call mac_plugindata_update() 3357a72f7ea6Sql */ 3358a72f7ea6Sql wd.wd_opmode = ic->ic_opmode; 3359a72f7ea6Sql wd.wd_secalloc = WIFI_SEC_NONE; 3360a72f7ea6Sql IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 3361a72f7ea6Sql 3362a72f7ea6Sql if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 3363a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3364a72f7ea6Sql "MAC version mismatch\n"); 3365a72f7ea6Sql goto attach_fail8; 3366a72f7ea6Sql } 3367a72f7ea6Sql 3368a72f7ea6Sql macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 3369a72f7ea6Sql macp->m_driver = rsc; 3370a72f7ea6Sql macp->m_dip = devinfo; 3371a72f7ea6Sql macp->m_src_addr = ic->ic_macaddr; 3372a72f7ea6Sql macp->m_callbacks = &rtw_m_callbacks; 3373a72f7ea6Sql macp->m_min_sdu = 0; 3374a72f7ea6Sql macp->m_max_sdu = IEEE80211_MTU; 3375a72f7ea6Sql macp->m_pdata = &wd; 3376a72f7ea6Sql macp->m_pdata_size = sizeof (wd); 3377a72f7ea6Sql 3378a72f7ea6Sql err = mac_register(macp, &ic->ic_mach); 3379a72f7ea6Sql mac_free(macp); 3380a72f7ea6Sql if (err != 0) { 3381a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "rtw: rtw_attach(): " 3382a72f7ea6Sql "mac_register err %x\n", err); 3383a72f7ea6Sql goto attach_fail8; 3384a72f7ea6Sql } 3385a72f7ea6Sql 3386a72f7ea6Sql /* Create minor node of type DDI_NT_NET_WIFI */ 3387a72f7ea6Sql (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 3388a72f7ea6Sql "rtw", instance); 3389a72f7ea6Sql err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR, 3390a72f7ea6Sql instance + 1, DDI_NT_NET_WIFI, 0); 3391a72f7ea6Sql if (err != DDI_SUCCESS) { 3392a72f7ea6Sql RTW_DPRINTF(RTW_DEBUG_ATTACH, "WARN: rtw: rtw_attach(): " 3393a72f7ea6Sql "Create minor node failed - %d\n", err); 3394a72f7ea6Sql goto attach_fail9; 3395a72f7ea6Sql } 3396a72f7ea6Sql mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 3397a72f7ea6Sql rsc->sc_flags |= RTW_F_ATTACHED; 3398a72f7ea6Sql rsc->sc_need_reschedule = 0; 3399a72f7ea6Sql rsc->sc_invalid = 1; 3400a72f7ea6Sql return (DDI_SUCCESS); 3401a72f7ea6Sql attach_fail9: 3402a72f7ea6Sql (void) mac_unregister(ic->ic_mach); 3403a72f7ea6Sql attach_fail8: 3404a72f7ea6Sql ddi_remove_intr(devinfo, 0, rsc->sc_iblock); 3405a72f7ea6Sql attach_fail7: 3406a72f7ea6Sql attach_fail6: 3407a72f7ea6Sql rtw_mutex_destroy(rsc); 3408a72f7ea6Sql attach_fail5: 3409a72f7ea6Sql ieee80211_detach(ic); 3410a72f7ea6Sql attach_fail4: 3411a72f7ea6Sql rtw_rf_destroy(rsc->sc_rf); 3412a72f7ea6Sql attach_fail3: 3413a72f7ea6Sql rtw_srom_free(&rsc->sc_srom); 3414a72f7ea6Sql attach_fail2: 3415a72f7ea6Sql rtw_dma_free(rsc); 3416a72f7ea6Sql attach_fail1: 3417a72f7ea6Sql ddi_regs_map_free(&rsc->sc_regs.r_handle); 3418a72f7ea6Sql attach_fail0: 3419a72f7ea6Sql ddi_soft_state_free(rtw_soft_state_p, ddi_get_instance(devinfo)); 3420a72f7ea6Sql return (DDI_FAILURE); 3421a72f7ea6Sql } 3422a72f7ea6Sql 3423a72f7ea6Sql static int32_t 3424a72f7ea6Sql rtw_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 3425a72f7ea6Sql { 3426a72f7ea6Sql rtw_softc_t *rsc; 3427a72f7ea6Sql 3428a72f7ea6Sql rsc = ddi_get_soft_state(rtw_soft_state_p, ddi_get_instance(devinfo)); 3429a72f7ea6Sql ASSERT(rsc != NULL); 3430a72f7ea6Sql 3431a72f7ea6Sql switch (cmd) { 3432a72f7ea6Sql case DDI_DETACH: 3433a72f7ea6Sql break; 3434a72f7ea6Sql default: 3435a72f7ea6Sql return (DDI_FAILURE); 3436a72f7ea6Sql } 3437a72f7ea6Sql if (!(rsc->sc_flags & RTW_F_ATTACHED)) 3438a72f7ea6Sql return (DDI_FAILURE); 3439a72f7ea6Sql 344042516a0cSxinghua wen - Sun Microsystems - Beijing China if (mac_disable(rsc->sc_ic.ic_mach) != 0) 344142516a0cSxinghua wen - Sun Microsystems - Beijing China return (DDI_FAILURE); 344242516a0cSxinghua wen - Sun Microsystems - Beijing China 3443a72f7ea6Sql /* free intterrupt resources */ 3444a72f7ea6Sql ddi_remove_intr(devinfo, 0, rsc->sc_iblock); 3445a72f7ea6Sql 3446a72f7ea6Sql rtw_mutex_destroy(rsc); 3447a72f7ea6Sql ieee80211_detach((ieee80211com_t *)rsc); 3448a72f7ea6Sql /* 3449a72f7ea6Sql * Unregister from the MAC layer subsystem 3450a72f7ea6Sql */ 3451a72f7ea6Sql (void) mac_unregister(rsc->sc_ic.ic_mach); 3452a72f7ea6Sql 3453a72f7ea6Sql rtw_rf_destroy(rsc->sc_rf); 3454a72f7ea6Sql rtw_srom_free(&rsc->sc_srom); 3455a72f7ea6Sql rtw_dma_free(rsc); 3456a72f7ea6Sql ddi_remove_minor_node(devinfo, NULL); 3457a72f7ea6Sql ddi_regs_map_free(&rsc->sc_regs.r_handle); 3458a72f7ea6Sql 3459a72f7ea6Sql ddi_soft_state_free(rtw_soft_state_p, ddi_get_instance(devinfo)); 3460a72f7ea6Sql 3461a72f7ea6Sql return (DDI_SUCCESS); 3462a72f7ea6Sql } 3463