1e07d9cb8Szf162725 /* 2fb91fd8aSzf162725 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3e07d9cb8Szf162725 * Use is subject to license terms. 4e07d9cb8Szf162725 */ 5e07d9cb8Szf162725 6e07d9cb8Szf162725 /* 7e07d9cb8Szf162725 * Copyright (c) 2005, 2006 8e07d9cb8Szf162725 * Damien Bergamini <damien.bergamini@free.fr> 9e07d9cb8Szf162725 * 10e07d9cb8Szf162725 * Permission to use, copy, modify, and distribute this software for any 11e07d9cb8Szf162725 * purpose with or without fee is hereby granted, provided that the above 12e07d9cb8Szf162725 * copyright notice and this permission notice appear in all copies. 13e07d9cb8Szf162725 * 14e07d9cb8Szf162725 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15e07d9cb8Szf162725 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16e07d9cb8Szf162725 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17e07d9cb8Szf162725 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18e07d9cb8Szf162725 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19e07d9cb8Szf162725 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20e07d9cb8Szf162725 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21e07d9cb8Szf162725 */ 22e07d9cb8Szf162725 23e07d9cb8Szf162725 /* 24e07d9cb8Szf162725 * Ralink Technology RT2560 chipset driver 25e07d9cb8Szf162725 * http://www.ralinktech.com/ 26e07d9cb8Szf162725 */ 27e07d9cb8Szf162725 28e07d9cb8Szf162725 #pragma ident "%Z%%M% %I% %E% SMI" 29e07d9cb8Szf162725 30e07d9cb8Szf162725 #include <sys/types.h> 31e07d9cb8Szf162725 #include <sys/byteorder.h> 32e07d9cb8Szf162725 #include <sys/conf.h> 33e07d9cb8Szf162725 #include <sys/cmn_err.h> 34e07d9cb8Szf162725 #include <sys/stat.h> 35e07d9cb8Szf162725 #include <sys/ddi.h> 36e07d9cb8Szf162725 #include <sys/sunddi.h> 37e07d9cb8Szf162725 #include <sys/strsubr.h> 38e07d9cb8Szf162725 #include <sys/ethernet.h> 39e07d9cb8Szf162725 #include <inet/common.h> 40e07d9cb8Szf162725 #include <inet/nd.h> 41e07d9cb8Szf162725 #include <inet/mi.h> 42e07d9cb8Szf162725 #include <sys/note.h> 43e07d9cb8Szf162725 #include <sys/stream.h> 44e07d9cb8Szf162725 #include <sys/strsun.h> 45e07d9cb8Szf162725 #include <sys/modctl.h> 46e07d9cb8Szf162725 #include <sys/devops.h> 47e07d9cb8Szf162725 #include <sys/dlpi.h> 48e07d9cb8Szf162725 #include <sys/mac.h> 49e07d9cb8Szf162725 #include <sys/mac_wifi.h> 50e07d9cb8Szf162725 #include <sys/net80211.h> 51e07d9cb8Szf162725 #include <sys/net80211_proto.h> 52e07d9cb8Szf162725 #include <sys/varargs.h> 53e07d9cb8Szf162725 #include <sys/policy.h> 54e07d9cb8Szf162725 #include <sys/pci.h> 55e07d9cb8Szf162725 #include <sys/crypto/common.h> 56e07d9cb8Szf162725 #include <sys/crypto/api.h> 57e07d9cb8Szf162725 #include <inet/wifi_ioctl.h> 58e07d9cb8Szf162725 59e07d9cb8Szf162725 #include "ral_rate.h" 60e07d9cb8Szf162725 #include "rt2560_reg.h" 61e07d9cb8Szf162725 #include "rt2560_var.h" 62e07d9cb8Szf162725 63e07d9cb8Szf162725 64e07d9cb8Szf162725 static void *ral_soft_state_p = NULL; 65e07d9cb8Szf162725 66e07d9cb8Szf162725 #define RAL_TXBUF_SIZE (IEEE80211_MAX_LEN) 67e07d9cb8Szf162725 #define RAL_RXBUF_SIZE (IEEE80211_MAX_LEN) 68e07d9cb8Szf162725 69e07d9cb8Szf162725 /* quickly determine if a given rate is CCK or OFDM */ 70e07d9cb8Szf162725 #define RAL_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) 71e07d9cb8Szf162725 #define RAL_ACK_SIZE 14 /* 10 + 4(FCS) */ 72e07d9cb8Szf162725 #define RAL_CTS_SIZE 14 /* 10 + 4(FCS) */ 73e07d9cb8Szf162725 #define RAL_SIFS 10 /* us */ 74e07d9cb8Szf162725 #define RT2560_TXRX_TURNAROUND 10 /* us */ 75e07d9cb8Szf162725 76e07d9cb8Szf162725 /* 77e07d9cb8Szf162725 * Supported rates for 802.11a/b/g modes (in 500Kbps unit). 78e07d9cb8Szf162725 */ 79e07d9cb8Szf162725 static const struct ieee80211_rateset rt2560_rateset_11a = 80e07d9cb8Szf162725 { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; 81e07d9cb8Szf162725 82e07d9cb8Szf162725 static const struct ieee80211_rateset rt2560_rateset_11b = 83e07d9cb8Szf162725 { 4, { 2, 4, 11, 22 } }; 84e07d9cb8Szf162725 85e07d9cb8Szf162725 static const struct ieee80211_rateset rt2560_rateset_11g = 86e07d9cb8Szf162725 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 87e07d9cb8Szf162725 88e07d9cb8Szf162725 static const struct { 89e07d9cb8Szf162725 uint32_t reg; 90e07d9cb8Szf162725 uint32_t val; 91e07d9cb8Szf162725 } rt2560_def_mac[] = { 92e07d9cb8Szf162725 RT2560_DEF_MAC 93e07d9cb8Szf162725 }; 94e07d9cb8Szf162725 95e07d9cb8Szf162725 static const struct { 96e07d9cb8Szf162725 uint8_t reg; 97e07d9cb8Szf162725 uint8_t val; 98e07d9cb8Szf162725 } rt2560_def_bbp[] = { 99e07d9cb8Szf162725 RT2560_DEF_BBP 100e07d9cb8Szf162725 }; 101e07d9cb8Szf162725 102e07d9cb8Szf162725 static const uint32_t rt2560_rf2522_r2[] = RT2560_RF2522_R2; 103e07d9cb8Szf162725 static const uint32_t rt2560_rf2523_r2[] = RT2560_RF2523_R2; 104e07d9cb8Szf162725 static const uint32_t rt2560_rf2524_r2[] = RT2560_RF2524_R2; 105e07d9cb8Szf162725 static const uint32_t rt2560_rf2525_r2[] = RT2560_RF2525_R2; 106e07d9cb8Szf162725 static const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2; 107e07d9cb8Szf162725 static const uint32_t rt2560_rf2525e_r2[] = RT2560_RF2525E_R2; 108e07d9cb8Szf162725 static const uint32_t rt2560_rf2526_r2[] = RT2560_RF2526_R2; 109e07d9cb8Szf162725 static const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2; 110e07d9cb8Szf162725 111e07d9cb8Szf162725 static const struct { 112e07d9cb8Szf162725 uint8_t chan; 113e07d9cb8Szf162725 uint32_t r1, r2, r4; 114e07d9cb8Szf162725 } rt2560_rf5222[] = { 115e07d9cb8Szf162725 RT2560_RF5222 116e07d9cb8Szf162725 }; 117e07d9cb8Szf162725 118e07d9cb8Szf162725 /* 119e07d9cb8Szf162725 * PIO access attributes for registers 120e07d9cb8Szf162725 */ 121e07d9cb8Szf162725 static ddi_device_acc_attr_t ral_csr_accattr = { 122e07d9cb8Szf162725 DDI_DEVICE_ATTR_V0, 123e07d9cb8Szf162725 DDI_STRUCTURE_LE_ACC, 124e07d9cb8Szf162725 DDI_STRICTORDER_ACC 125e07d9cb8Szf162725 }; 126e07d9cb8Szf162725 127e07d9cb8Szf162725 /* 128e07d9cb8Szf162725 * DMA access attributes for descriptors: NOT to be byte swapped. 129e07d9cb8Szf162725 */ 130e07d9cb8Szf162725 static ddi_device_acc_attr_t ral_desc_accattr = { 131e07d9cb8Szf162725 DDI_DEVICE_ATTR_V0, 132e07d9cb8Szf162725 DDI_STRUCTURE_LE_ACC, 133e07d9cb8Szf162725 DDI_STRICTORDER_ACC 134e07d9cb8Szf162725 }; 135e07d9cb8Szf162725 136e07d9cb8Szf162725 /* 137e07d9cb8Szf162725 * Describes the chip's DMA engine 138e07d9cb8Szf162725 */ 139e07d9cb8Szf162725 static ddi_dma_attr_t ral_dma_attr = { 140e07d9cb8Szf162725 DMA_ATTR_V0, /* dma_attr version */ 141e07d9cb8Szf162725 0x0000000000000000ull, /* dma_attr_addr_lo */ 142*020c4770Sql147931 0xFFFFFFFF, /* dma_attr_addr_hi */ 143e07d9cb8Szf162725 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 144e07d9cb8Szf162725 0x0000000000000001ull, /* dma_attr_align */ 145e07d9cb8Szf162725 0x00000FFF, /* dma_attr_burstsizes */ 146e07d9cb8Szf162725 0x00000001, /* dma_attr_minxfer */ 147e07d9cb8Szf162725 0x000000000000FFFFull, /* dma_attr_maxxfer */ 148e07d9cb8Szf162725 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 149e07d9cb8Szf162725 1, /* dma_attr_sgllen */ 150e07d9cb8Szf162725 0x00000001, /* dma_attr_granular */ 151e07d9cb8Szf162725 0 /* dma_attr_flags */ 152e07d9cb8Szf162725 }; 153e07d9cb8Szf162725 154e07d9cb8Szf162725 /* 155e07d9cb8Szf162725 * device operations 156e07d9cb8Szf162725 */ 157e07d9cb8Szf162725 static int rt2560_attach(dev_info_t *, ddi_attach_cmd_t); 158e07d9cb8Szf162725 static int rt2560_detach(dev_info_t *, ddi_detach_cmd_t); 159e07d9cb8Szf162725 static int rt2560_reset(dev_info_t *, ddi_reset_cmd_t); 160e07d9cb8Szf162725 161e07d9cb8Szf162725 /* 162e07d9cb8Szf162725 * Module Loading Data & Entry Points 163e07d9cb8Szf162725 */ 164e07d9cb8Szf162725 DDI_DEFINE_STREAM_OPS(ral_dev_ops, nulldev, nulldev, rt2560_attach, 165e07d9cb8Szf162725 rt2560_detach, rt2560_reset, NULL, D_MP, NULL); 166e07d9cb8Szf162725 167e07d9cb8Szf162725 static struct modldrv ral_modldrv = { 168e07d9cb8Szf162725 &mod_driverops, /* Type of module. This one is a driver */ 169e07d9cb8Szf162725 "Ralink RT2500 driver v%I%", /* short description */ 170e07d9cb8Szf162725 &ral_dev_ops /* driver specific ops */ 171e07d9cb8Szf162725 }; 172e07d9cb8Szf162725 173e07d9cb8Szf162725 static struct modlinkage modlinkage = { 174e07d9cb8Szf162725 MODREV_1, 175e07d9cb8Szf162725 (void *)&ral_modldrv, 176e07d9cb8Szf162725 NULL 177e07d9cb8Szf162725 }; 178e07d9cb8Szf162725 179e07d9cb8Szf162725 static int rt2560_m_stat(void *, uint_t, uint64_t *); 180e07d9cb8Szf162725 static int rt2560_m_start(void *); 181e07d9cb8Szf162725 static void rt2560_m_stop(void *); 182e07d9cb8Szf162725 static int rt2560_m_promisc(void *, boolean_t); 183e07d9cb8Szf162725 static int rt2560_m_multicst(void *, boolean_t, const uint8_t *); 184e07d9cb8Szf162725 static int rt2560_m_unicst(void *, const uint8_t *); 185e07d9cb8Szf162725 static mblk_t *rt2560_m_tx(void *, mblk_t *); 186e07d9cb8Szf162725 static void rt2560_m_ioctl(void *, queue_t *, mblk_t *); 187e07d9cb8Szf162725 188e07d9cb8Szf162725 static mac_callbacks_t rt2560_m_callbacks = { 189e07d9cb8Szf162725 MC_IOCTL, 190e07d9cb8Szf162725 rt2560_m_stat, 191e07d9cb8Szf162725 rt2560_m_start, 192e07d9cb8Szf162725 rt2560_m_stop, 193e07d9cb8Szf162725 rt2560_m_promisc, 194e07d9cb8Szf162725 rt2560_m_multicst, 195e07d9cb8Szf162725 rt2560_m_unicst, 196e07d9cb8Szf162725 rt2560_m_tx, 197e07d9cb8Szf162725 NULL, /* mc_resources; */ 198e07d9cb8Szf162725 rt2560_m_ioctl, 199e07d9cb8Szf162725 NULL /* mc_getcapab */ 200e07d9cb8Szf162725 }; 201e07d9cb8Szf162725 202e07d9cb8Szf162725 uint32_t ral_dbg_flags = 0; 203e07d9cb8Szf162725 204e07d9cb8Szf162725 void 205e07d9cb8Szf162725 ral_debug(uint32_t dbg_flags, const int8_t *fmt, ...) 206e07d9cb8Szf162725 { 207e07d9cb8Szf162725 va_list args; 208e07d9cb8Szf162725 209e07d9cb8Szf162725 if (dbg_flags & ral_dbg_flags) { 210e07d9cb8Szf162725 va_start(args, fmt); 211e07d9cb8Szf162725 vcmn_err(CE_CONT, fmt, args); 212e07d9cb8Szf162725 va_end(args); 213e07d9cb8Szf162725 } 214e07d9cb8Szf162725 } 215e07d9cb8Szf162725 216e07d9cb8Szf162725 static void 217e07d9cb8Szf162725 rt2560_set_basicrates(struct rt2560_softc *sc) 218e07d9cb8Szf162725 { 219e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 220e07d9cb8Szf162725 221e07d9cb8Szf162725 /* update basic rate set */ 222e07d9cb8Szf162725 if (ic->ic_curmode == IEEE80211_MODE_11B) { 223e07d9cb8Szf162725 /* 11b basic rates: 1, 2Mbps */ 224e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3); 225e07d9cb8Szf162725 } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { 226e07d9cb8Szf162725 /* 11a basic rates: 6, 12, 24Mbps */ 227e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150); 228e07d9cb8Szf162725 } else { 229e07d9cb8Szf162725 /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */ 230e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f); 231e07d9cb8Szf162725 } 232e07d9cb8Szf162725 } 233e07d9cb8Szf162725 234e07d9cb8Szf162725 static void 235e07d9cb8Szf162725 rt2560_update_led(struct rt2560_softc *sc, int led1, int led2) 236e07d9cb8Szf162725 { 237e07d9cb8Szf162725 uint32_t tmp; 238e07d9cb8Szf162725 239e07d9cb8Szf162725 /* set ON period to 70ms and OFF period to 30ms */ 240e07d9cb8Szf162725 tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30; 241e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_LEDCSR, tmp); 242e07d9cb8Szf162725 } 243e07d9cb8Szf162725 244e07d9cb8Szf162725 static void 245e07d9cb8Szf162725 rt2560_set_bssid(struct rt2560_softc *sc, uint8_t *bssid) 246e07d9cb8Szf162725 { 247e07d9cb8Szf162725 uint32_t tmp; 248e07d9cb8Szf162725 249e07d9cb8Szf162725 tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 250e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR5, tmp); 251e07d9cb8Szf162725 252e07d9cb8Szf162725 tmp = bssid[4] | bssid[5] << 8; 253e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR6, tmp); 254e07d9cb8Szf162725 255e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "setting BSSID to " MACSTR "\n", MAC2STR(bssid)); 256e07d9cb8Szf162725 } 257e07d9cb8Szf162725 258e07d9cb8Szf162725 259e07d9cb8Szf162725 static void 260e07d9cb8Szf162725 rt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val) 261e07d9cb8Szf162725 { 262e07d9cb8Szf162725 uint32_t tmp; 263e07d9cb8Szf162725 int ntries; 264e07d9cb8Szf162725 265e07d9cb8Szf162725 for (ntries = 0; ntries < 100; ntries++) { 266e07d9cb8Szf162725 if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY)) 267e07d9cb8Szf162725 break; 268e07d9cb8Szf162725 drv_usecwait(1); 269e07d9cb8Szf162725 } 270e07d9cb8Szf162725 if (ntries == 100) { 271e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "could not write to BBP\n"); 272e07d9cb8Szf162725 return; 273e07d9cb8Szf162725 } 274e07d9cb8Szf162725 275e07d9cb8Szf162725 tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val; 276e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_BBPCSR, tmp); 277e07d9cb8Szf162725 278e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "BBP R%u <- 0x%02x\n", reg, val); 279e07d9cb8Szf162725 } 280e07d9cb8Szf162725 281e07d9cb8Szf162725 static uint8_t 282e07d9cb8Szf162725 rt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg) 283e07d9cb8Szf162725 { 284e07d9cb8Szf162725 uint32_t val; 285e07d9cb8Szf162725 int ntries; 286e07d9cb8Szf162725 287e07d9cb8Szf162725 val = RT2560_BBP_BUSY | reg << 8; 288e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_BBPCSR, val); 289e07d9cb8Szf162725 290e07d9cb8Szf162725 for (ntries = 0; ntries < 100; ntries++) { 291e07d9cb8Szf162725 val = RAL_READ(sc, RT2560_BBPCSR); 292e07d9cb8Szf162725 if (!(val & RT2560_BBP_BUSY)) 293e07d9cb8Szf162725 return (val & 0xff); 294e07d9cb8Szf162725 drv_usecwait(1); 295e07d9cb8Szf162725 } 296e07d9cb8Szf162725 297e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "could not read from BBP\n"); 298e07d9cb8Szf162725 return (0); 299e07d9cb8Szf162725 } 300e07d9cb8Szf162725 301e07d9cb8Szf162725 static void 302e07d9cb8Szf162725 rt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val) 303e07d9cb8Szf162725 { 304e07d9cb8Szf162725 uint32_t tmp; 305e07d9cb8Szf162725 int ntries; 306e07d9cb8Szf162725 307e07d9cb8Szf162725 for (ntries = 0; ntries < 100; ntries++) { 308e07d9cb8Szf162725 if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY)) 309e07d9cb8Szf162725 break; 310e07d9cb8Szf162725 drv_usecwait(1); 311e07d9cb8Szf162725 } 312e07d9cb8Szf162725 if (ntries == 100) { 313e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "could not write to RF\n"); 314e07d9cb8Szf162725 return; 315e07d9cb8Szf162725 } 316e07d9cb8Szf162725 317e07d9cb8Szf162725 tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 | 318e07d9cb8Szf162725 (reg & 0x3); 319e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RFCSR, tmp); 320e07d9cb8Szf162725 321e07d9cb8Szf162725 /* remember last written value in sc */ 322e07d9cb8Szf162725 sc->rf_regs[reg] = val; 323e07d9cb8Szf162725 324e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff); 325e07d9cb8Szf162725 } 326e07d9cb8Szf162725 327e07d9cb8Szf162725 static void 328e07d9cb8Szf162725 rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c) 329e07d9cb8Szf162725 { 330e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 331e07d9cb8Szf162725 uint8_t power, tmp; 332e07d9cb8Szf162725 uint_t i, chan; 333e07d9cb8Szf162725 334e07d9cb8Szf162725 chan = ieee80211_chan2ieee(ic, c); 335e07d9cb8Szf162725 if (chan == 0 || chan == IEEE80211_CHAN_ANY) 336e07d9cb8Szf162725 return; 337e07d9cb8Szf162725 338e07d9cb8Szf162725 if (IEEE80211_IS_CHAN_2GHZ(c)) 339e07d9cb8Szf162725 power = min(sc->txpow[chan - 1], 31); 340e07d9cb8Szf162725 else 341e07d9cb8Szf162725 power = 31; 342e07d9cb8Szf162725 343e07d9cb8Szf162725 /* adjust txpower using ifconfig settings */ 344e07d9cb8Szf162725 power -= (100 - ic->ic_txpowlimit) / 8; 345e07d9cb8Szf162725 346e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_CHAN, "setting channel to %u, txpower to %u\n", 347e07d9cb8Szf162725 chan, power); 348e07d9cb8Szf162725 349e07d9cb8Szf162725 switch (sc->rf_rev) { 350e07d9cb8Szf162725 case RT2560_RF_2522: 351e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x00814); 352e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]); 353e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 354e07d9cb8Szf162725 break; 355e07d9cb8Szf162725 356e07d9cb8Szf162725 case RT2560_RF_2523: 357e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x08804); 358e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]); 359e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044); 360e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 361e07d9cb8Szf162725 break; 362e07d9cb8Szf162725 363e07d9cb8Szf162725 case RT2560_RF_2524: 364e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x0c808); 365e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]); 366e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 367e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 368e07d9cb8Szf162725 break; 369e07d9cb8Szf162725 370e07d9cb8Szf162725 case RT2560_RF_2525: 371e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x08808); 372e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]); 373e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 374e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 375e07d9cb8Szf162725 376e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x08808); 377e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]); 378e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 379e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286); 380e07d9cb8Szf162725 break; 381e07d9cb8Szf162725 382e07d9cb8Szf162725 case RT2560_RF_2525E: 383e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x08808); 384e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]); 385e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 386e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282); 387e07d9cb8Szf162725 break; 388e07d9cb8Szf162725 389e07d9cb8Szf162725 case RT2560_RF_2526: 390e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]); 391e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 392e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, 0x08804); 393e07d9cb8Szf162725 394e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]); 395e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044); 396e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381); 397e07d9cb8Szf162725 break; 398e07d9cb8Szf162725 399e07d9cb8Szf162725 /* dual-band RF */ 400e07d9cb8Szf162725 case RT2560_RF_5222: 401e07d9cb8Szf162725 for (i = 0; rt2560_rf5222[i].chan != chan; i++) { 402e07d9cb8Szf162725 } 403e07d9cb8Szf162725 404e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1); 405e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2); 406e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040); 407e07d9cb8Szf162725 rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4); 408e07d9cb8Szf162725 break; 409e07d9cb8Szf162725 } 410e07d9cb8Szf162725 411e07d9cb8Szf162725 if (ic->ic_state != IEEE80211_S_SCAN) { 412e07d9cb8Szf162725 /* set Japan filter bit for channel 14 */ 413e07d9cb8Szf162725 tmp = rt2560_bbp_read(sc, 70); 414e07d9cb8Szf162725 415e07d9cb8Szf162725 tmp &= ~RT2560_JAPAN_FILTER; 416e07d9cb8Szf162725 if (chan == 14) 417e07d9cb8Szf162725 tmp |= RT2560_JAPAN_FILTER; 418e07d9cb8Szf162725 419e07d9cb8Szf162725 rt2560_bbp_write(sc, 70, tmp); 420e07d9cb8Szf162725 421e07d9cb8Szf162725 /* clear CRC errors */ 422e07d9cb8Szf162725 (void) RAL_READ(sc, RT2560_CNT0); 423e07d9cb8Szf162725 } 424e07d9cb8Szf162725 } 425e07d9cb8Szf162725 426e07d9cb8Szf162725 /* 427e07d9cb8Szf162725 * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF 428e07d9cb8Szf162725 * synchronization. 429e07d9cb8Szf162725 */ 430e07d9cb8Szf162725 static void 431e07d9cb8Szf162725 rt2560_enable_tsf_sync(struct rt2560_softc *sc) 432e07d9cb8Szf162725 { 433e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 434e07d9cb8Szf162725 uint16_t logcwmin, preload; 435e07d9cb8Szf162725 uint32_t tmp; 436e07d9cb8Szf162725 437e07d9cb8Szf162725 /* first, disable TSF synchronization */ 438e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR14, 0); 439e07d9cb8Szf162725 440e07d9cb8Szf162725 tmp = 16 * ic->ic_bss->in_intval; 441e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR12, tmp); 442e07d9cb8Szf162725 443e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR13, 0); 444e07d9cb8Szf162725 445e07d9cb8Szf162725 logcwmin = 5; 446e07d9cb8Szf162725 preload = (ic->ic_opmode == IEEE80211_M_STA) ? 384 : 1024; 447e07d9cb8Szf162725 tmp = logcwmin << 16 | preload; 448e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_BCNOCSR, tmp); 449e07d9cb8Szf162725 450e07d9cb8Szf162725 /* finally, enable TSF synchronization */ 451e07d9cb8Szf162725 tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN; 452e07d9cb8Szf162725 if (ic->ic_opmode == IEEE80211_M_STA) 453e07d9cb8Szf162725 tmp |= RT2560_ENABLE_TSF_SYNC(1); 454e07d9cb8Szf162725 else 455e07d9cb8Szf162725 tmp |= RT2560_ENABLE_TSF_SYNC(2) | 456e07d9cb8Szf162725 RT2560_ENABLE_BEACON_GENERATOR; 457e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR14, tmp); 458e07d9cb8Szf162725 459e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "enabling TSF synchronization\n"); 460e07d9cb8Szf162725 } 461e07d9cb8Szf162725 462e07d9cb8Szf162725 static void 463e07d9cb8Szf162725 rt2560_update_plcp(struct rt2560_softc *sc) 464e07d9cb8Szf162725 { 465e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 466e07d9cb8Szf162725 467e07d9cb8Szf162725 /* no short preamble for 1Mbps */ 468e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400); 469e07d9cb8Szf162725 470e07d9cb8Szf162725 if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { 471e07d9cb8Szf162725 /* values taken from the reference driver */ 472e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380401); 473e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402); 474e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b8403); 475e07d9cb8Szf162725 } else { 476e07d9cb8Szf162725 /* same values as above or'ed 0x8 */ 477e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP2MCSR, 0x00380409); 478e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a); 479e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_PLCP11MCSR, 0x000b840b); 480e07d9cb8Szf162725 } 481e07d9cb8Szf162725 482e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "updating PLCP for %s preamble\n", 483e07d9cb8Szf162725 (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"); 484e07d9cb8Szf162725 } 485e07d9cb8Szf162725 486e07d9cb8Szf162725 /* 487e07d9cb8Szf162725 * This function can be called by ieee80211_set_shortslottime(). Refer to 488e07d9cb8Szf162725 * IEEE Std 802.11-1999 pp. 85 to know how these values are computed. 489e07d9cb8Szf162725 */ 490e07d9cb8Szf162725 void 491e07d9cb8Szf162725 rt2560_update_slot(struct ieee80211com *ic, int onoff) 492e07d9cb8Szf162725 { 493e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)ic; 494e07d9cb8Szf162725 uint8_t slottime; 495e07d9cb8Szf162725 uint16_t tx_sifs, tx_pifs, tx_difs, eifs; 496e07d9cb8Szf162725 uint32_t tmp; 497e07d9cb8Szf162725 498e07d9cb8Szf162725 /* slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; */ 499e07d9cb8Szf162725 slottime = (onoff ? 9 : 20); 500e07d9cb8Szf162725 501e07d9cb8Szf162725 /* update the MAC slot boundaries */ 502e07d9cb8Szf162725 tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND; 503e07d9cb8Szf162725 tx_pifs = tx_sifs + slottime; 504e07d9cb8Szf162725 tx_difs = tx_sifs + 2 * slottime; 505e07d9cb8Szf162725 eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60; 506e07d9cb8Szf162725 507e07d9cb8Szf162725 tmp = RAL_READ(sc, RT2560_CSR11); 508e07d9cb8Szf162725 tmp = (tmp & ~0x1f00) | slottime << 8; 509e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR11, tmp); 510e07d9cb8Szf162725 511e07d9cb8Szf162725 tmp = tx_pifs << 16 | tx_sifs; 512e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR18, tmp); 513e07d9cb8Szf162725 514e07d9cb8Szf162725 tmp = eifs << 16 | tx_difs; 515e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR19, tmp); 516e07d9cb8Szf162725 517e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "setting slottime to %uus\n", slottime); 518e07d9cb8Szf162725 } 519e07d9cb8Szf162725 520e07d9cb8Szf162725 int 521e07d9cb8Szf162725 ral_dma_region_alloc(struct rt2560_softc *sc, struct dma_region *dr, 522e07d9cb8Szf162725 size_t size, uint_t alloc_flags, uint_t bind_flags) 523e07d9cb8Szf162725 { 524e07d9cb8Szf162725 dev_info_t *dip = sc->sc_dev; 525e07d9cb8Szf162725 int err; 526e07d9cb8Szf162725 527e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_DMA, "ral_dma_region_alloc() size=%u\n", size); 528e07d9cb8Szf162725 529e07d9cb8Szf162725 err = ddi_dma_alloc_handle(dip, &ral_dma_attr, DDI_DMA_SLEEP, NULL, 530e07d9cb8Szf162725 &dr->dr_hnd); 531e07d9cb8Szf162725 if (err != DDI_SUCCESS) 532e07d9cb8Szf162725 goto fail1; 533e07d9cb8Szf162725 534e07d9cb8Szf162725 err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ral_desc_accattr, 535e07d9cb8Szf162725 alloc_flags, DDI_DMA_SLEEP, NULL, 536e07d9cb8Szf162725 &dr->dr_base, &dr->dr_size, &dr->dr_acc); 537e07d9cb8Szf162725 if (err != DDI_SUCCESS) 538e07d9cb8Szf162725 goto fail2; 539e07d9cb8Szf162725 540e07d9cb8Szf162725 err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL, 541e07d9cb8Szf162725 dr->dr_base, dr->dr_size, 542e07d9cb8Szf162725 bind_flags, DDI_DMA_SLEEP, NULL, &dr->dr_cookie, &dr->dr_ccnt); 543e07d9cb8Szf162725 if (err != DDI_SUCCESS) 544e07d9cb8Szf162725 goto fail3; 545e07d9cb8Szf162725 546e07d9cb8Szf162725 if (dr->dr_ccnt != 1) { 547e07d9cb8Szf162725 err = DDI_FAILURE; 548e07d9cb8Szf162725 goto fail4; 549e07d9cb8Szf162725 } 550e07d9cb8Szf162725 551e07d9cb8Szf162725 dr->dr_pbase = dr->dr_cookie.dmac_address; 552e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_DMA, "get physical-base=0x%08x\n", dr->dr_pbase); 553e07d9cb8Szf162725 554e07d9cb8Szf162725 return (DDI_SUCCESS); 555e07d9cb8Szf162725 556e07d9cb8Szf162725 fail4: 557e07d9cb8Szf162725 (void) ddi_dma_unbind_handle(dr->dr_hnd); 558e07d9cb8Szf162725 fail3: 559e07d9cb8Szf162725 ddi_dma_mem_free(&dr->dr_acc); 560e07d9cb8Szf162725 fail2: 561e07d9cb8Szf162725 ddi_dma_free_handle(&dr->dr_hnd); 562e07d9cb8Szf162725 fail1: 563e07d9cb8Szf162725 return (err); 564e07d9cb8Szf162725 } 565e07d9cb8Szf162725 566e07d9cb8Szf162725 /* ARGSUSED */ 567e07d9cb8Szf162725 void 568e07d9cb8Szf162725 ral_dma_region_free(struct rt2560_softc *sc, struct dma_region *dr) 569e07d9cb8Szf162725 { 570e07d9cb8Szf162725 (void) ddi_dma_unbind_handle(dr->dr_hnd); 571e07d9cb8Szf162725 ddi_dma_mem_free(&dr->dr_acc); 572e07d9cb8Szf162725 ddi_dma_free_handle(&dr->dr_hnd); 573e07d9cb8Szf162725 } 574e07d9cb8Szf162725 575e07d9cb8Szf162725 int 576e07d9cb8Szf162725 rt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring, 577e07d9cb8Szf162725 int count) 578e07d9cb8Szf162725 { 579e07d9cb8Szf162725 int i, err; 580e07d9cb8Szf162725 int size; 581e07d9cb8Szf162725 582e07d9cb8Szf162725 ring->count = count; 583e07d9cb8Szf162725 ring->queued = 0; 584e07d9cb8Szf162725 ring->cur = ring->next = 0; 585e07d9cb8Szf162725 ring->cur_encrypt = ring->next_encrypt = 0; 586e07d9cb8Szf162725 587e07d9cb8Szf162725 ring->data = kmem_zalloc(count * (sizeof (struct rt2560_tx_data)), 588e07d9cb8Szf162725 KM_SLEEP); 589e07d9cb8Szf162725 ring->dr_txbuf = kmem_zalloc(count * (sizeof (struct dma_region)), 590e07d9cb8Szf162725 KM_SLEEP); 591e07d9cb8Szf162725 592e07d9cb8Szf162725 err = ral_dma_region_alloc(sc, &ring->dr_desc, 593e07d9cb8Szf162725 count * (sizeof (struct rt2560_tx_desc)), 594e07d9cb8Szf162725 DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT); 595e07d9cb8Szf162725 596e07d9cb8Szf162725 if (err != DDI_SUCCESS) 597e07d9cb8Szf162725 goto fail1; 598e07d9cb8Szf162725 599e07d9cb8Szf162725 size = roundup(RAL_TXBUF_SIZE, sc->sc_cachelsz); 600e07d9cb8Szf162725 for (i = 0; i < count; i++) { 601e07d9cb8Szf162725 err = ral_dma_region_alloc(sc, &ring->dr_txbuf[i], size, 602e07d9cb8Szf162725 DDI_DMA_STREAMING, DDI_DMA_WRITE | DDI_DMA_STREAMING); 603e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 604e07d9cb8Szf162725 while (i >= 0) { 605e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_txbuf[i]); 606e07d9cb8Szf162725 i--; 607e07d9cb8Szf162725 } 608e07d9cb8Szf162725 goto fail2; 609e07d9cb8Szf162725 } 610e07d9cb8Szf162725 } 611e07d9cb8Szf162725 612e07d9cb8Szf162725 ring->physaddr = LE_32(ring->dr_desc.dr_pbase); 613e07d9cb8Szf162725 ring->desc = (struct rt2560_tx_desc *)ring->dr_desc.dr_base; 614e07d9cb8Szf162725 615e07d9cb8Szf162725 for (i = 0; i < count; i++) { 616e07d9cb8Szf162725 ring->desc[i].physaddr = LE_32(ring->dr_txbuf[i].dr_pbase); 617e07d9cb8Szf162725 ring->data[i].buf = ring->dr_txbuf[i].dr_base; 618e07d9cb8Szf162725 } 619e07d9cb8Szf162725 620e07d9cb8Szf162725 return (DDI_SUCCESS); 621e07d9cb8Szf162725 fail2: 622e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_desc); 623e07d9cb8Szf162725 fail1: 624e07d9cb8Szf162725 return (err); 625e07d9cb8Szf162725 } 626e07d9cb8Szf162725 627e07d9cb8Szf162725 /* ARGSUSED */ 628e07d9cb8Szf162725 void 629e07d9cb8Szf162725 rt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 630e07d9cb8Szf162725 { 631e07d9cb8Szf162725 struct rt2560_tx_desc *desc; 632e07d9cb8Szf162725 struct rt2560_tx_data *data; 633e07d9cb8Szf162725 int i; 634e07d9cb8Szf162725 635e07d9cb8Szf162725 for (i = 0; i < ring->count; i++) { 636e07d9cb8Szf162725 desc = &ring->desc[i]; 637e07d9cb8Szf162725 data = &ring->data[i]; 638e07d9cb8Szf162725 639e07d9cb8Szf162725 if (data->ni != NULL) { 640e07d9cb8Szf162725 ieee80211_free_node(data->ni); 641e07d9cb8Szf162725 data->ni = NULL; 642e07d9cb8Szf162725 } 643e07d9cb8Szf162725 644e07d9cb8Szf162725 desc->flags = 0; 645e07d9cb8Szf162725 } 646e07d9cb8Szf162725 647e07d9cb8Szf162725 (void) ddi_dma_sync(ring->dr_desc.dr_hnd, 0, 648e07d9cb8Szf162725 ring->count * sizeof (struct rt2560_tx_desc), DDI_DMA_SYNC_FORDEV); 649e07d9cb8Szf162725 650e07d9cb8Szf162725 ring->queued = 0; 651e07d9cb8Szf162725 ring->cur = ring->next = 0; 652e07d9cb8Szf162725 ring->cur_encrypt = ring->next_encrypt = 0; 653e07d9cb8Szf162725 } 654e07d9cb8Szf162725 655e07d9cb8Szf162725 void 656e07d9cb8Szf162725 rt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring) 657e07d9cb8Szf162725 { 658e07d9cb8Szf162725 struct rt2560_tx_data *data; 659e07d9cb8Szf162725 int i; 660e07d9cb8Szf162725 661e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_desc); 662e07d9cb8Szf162725 /* tx buf */ 663e07d9cb8Szf162725 for (i = 0; i < ring->count; i++) { 664e07d9cb8Szf162725 data = &ring->data[i]; 665e07d9cb8Szf162725 if (data->ni != NULL) { 666e07d9cb8Szf162725 ieee80211_free_node(data->ni); 667e07d9cb8Szf162725 data->ni = NULL; 668e07d9cb8Szf162725 } 669e07d9cb8Szf162725 670e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_txbuf[i]); 671e07d9cb8Szf162725 } 672e07d9cb8Szf162725 673e07d9cb8Szf162725 kmem_free(ring->data, ring->count * (sizeof (struct rt2560_tx_data))); 674e07d9cb8Szf162725 kmem_free(ring->dr_txbuf, ring->count * (sizeof (struct dma_region))); 675e07d9cb8Szf162725 } 676e07d9cb8Szf162725 677e07d9cb8Szf162725 void 678e07d9cb8Szf162725 rt2560_ring_hwsetup(struct rt2560_softc *sc) 679e07d9cb8Szf162725 { 680e07d9cb8Szf162725 uint32_t tmp; 681e07d9cb8Szf162725 682e07d9cb8Szf162725 /* setup tx rings */ 683e07d9cb8Szf162725 tmp = ((uint32_t)RT2560_PRIO_RING_COUNT << 24) | 684e07d9cb8Szf162725 RT2560_ATIM_RING_COUNT << 16 | 685e07d9cb8Szf162725 RT2560_TX_RING_COUNT << 8 | 686e07d9cb8Szf162725 RT2560_TX_DESC_SIZE; 687e07d9cb8Szf162725 688e07d9cb8Szf162725 /* rings must be initialized in this exact order */ 689e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR2, tmp); 690e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr); 691e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr); 692e07d9cb8Szf162725 693e07d9cb8Szf162725 /* setup rx ring */ 694e07d9cb8Szf162725 tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE; 695e07d9cb8Szf162725 696e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RXCSR1, tmp); 697e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); 698e07d9cb8Szf162725 } 699e07d9cb8Szf162725 700e07d9cb8Szf162725 int 701e07d9cb8Szf162725 rt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring, 702e07d9cb8Szf162725 int count) 703e07d9cb8Szf162725 { 704e07d9cb8Szf162725 struct rt2560_rx_desc *desc; 705e07d9cb8Szf162725 struct rt2560_rx_data *data; 706e07d9cb8Szf162725 int i, err; 707e07d9cb8Szf162725 int size; 708e07d9cb8Szf162725 709e07d9cb8Szf162725 ring->count = count; 710e07d9cb8Szf162725 ring->cur = ring->next = 0; 711e07d9cb8Szf162725 ring->cur_decrypt = 0; 712e07d9cb8Szf162725 713e07d9cb8Szf162725 ring->data = kmem_zalloc(count * (sizeof (struct rt2560_rx_data)), 714e07d9cb8Szf162725 KM_SLEEP); 715e07d9cb8Szf162725 ring->dr_rxbuf = kmem_zalloc(count * (sizeof (struct dma_region)), 716e07d9cb8Szf162725 KM_SLEEP); 717e07d9cb8Szf162725 718e07d9cb8Szf162725 err = ral_dma_region_alloc(sc, &ring->dr_desc, 719e07d9cb8Szf162725 count * (sizeof (struct rt2560_rx_desc)), 720e07d9cb8Szf162725 DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT); 721e07d9cb8Szf162725 722e07d9cb8Szf162725 if (err != DDI_SUCCESS) 723e07d9cb8Szf162725 goto fail1; 724e07d9cb8Szf162725 725e07d9cb8Szf162725 size = roundup(RAL_RXBUF_SIZE, sc->sc_cachelsz); 726e07d9cb8Szf162725 for (i = 0; i < count; i++) { 727e07d9cb8Szf162725 err = ral_dma_region_alloc(sc, &ring->dr_rxbuf[i], size, 728e07d9cb8Szf162725 DDI_DMA_STREAMING, DDI_DMA_READ | DDI_DMA_STREAMING); 729e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 730e07d9cb8Szf162725 while (i >= 0) { 731e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_rxbuf[i]); 732e07d9cb8Szf162725 i--; 733e07d9cb8Szf162725 } 734e07d9cb8Szf162725 goto fail2; 735e07d9cb8Szf162725 } 736e07d9cb8Szf162725 } 737e07d9cb8Szf162725 738e07d9cb8Szf162725 ring->physaddr = ring->dr_desc.dr_pbase; 739e07d9cb8Szf162725 ring->desc = (struct rt2560_rx_desc *)ring->dr_desc.dr_base; 740e07d9cb8Szf162725 741e07d9cb8Szf162725 for (i = 0; i < count; i++) { 742e07d9cb8Szf162725 desc = &ring->desc[i]; 743e07d9cb8Szf162725 data = &ring->data[i]; 744e07d9cb8Szf162725 745e07d9cb8Szf162725 desc->physaddr = LE_32(ring->dr_rxbuf[i].dr_pbase); 746e07d9cb8Szf162725 desc->flags = LE_32(RT2560_RX_BUSY); 747e07d9cb8Szf162725 748e07d9cb8Szf162725 data->buf = ring->dr_rxbuf[i].dr_base; 749e07d9cb8Szf162725 } 750e07d9cb8Szf162725 751e07d9cb8Szf162725 return (DDI_SUCCESS); 752e07d9cb8Szf162725 fail2: 753e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_desc); 754e07d9cb8Szf162725 fail1: 755e07d9cb8Szf162725 return (err); 756e07d9cb8Szf162725 } 757e07d9cb8Szf162725 758e07d9cb8Szf162725 /* ARGSUSED */ 759e07d9cb8Szf162725 static void 760e07d9cb8Szf162725 rt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 761e07d9cb8Szf162725 { 762e07d9cb8Szf162725 int i; 763e07d9cb8Szf162725 764e07d9cb8Szf162725 for (i = 0; i < ring->count; i++) { 765e07d9cb8Szf162725 ring->desc[i].flags = LE_32(RT2560_RX_BUSY); 766e07d9cb8Szf162725 ring->data[i].drop = 0; 767e07d9cb8Szf162725 } 768e07d9cb8Szf162725 769e07d9cb8Szf162725 (void) ddi_dma_sync(ring->dr_desc.dr_hnd, 0, 770e07d9cb8Szf162725 ring->count * sizeof (struct rt2560_rx_desc), 771e07d9cb8Szf162725 DDI_DMA_SYNC_FORKERNEL); 772e07d9cb8Szf162725 773e07d9cb8Szf162725 ring->cur = ring->next = 0; 774e07d9cb8Szf162725 ring->cur_decrypt = 0; 775e07d9cb8Szf162725 } 776e07d9cb8Szf162725 777e07d9cb8Szf162725 static void 778e07d9cb8Szf162725 rt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring) 779e07d9cb8Szf162725 { 780e07d9cb8Szf162725 int i; 781e07d9cb8Szf162725 782e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_desc); 783e07d9cb8Szf162725 /* rx buf */ 784e07d9cb8Szf162725 for (i = 0; i < ring->count; i++) 785e07d9cb8Szf162725 ral_dma_region_free(sc, &ring->dr_rxbuf[i]); 786e07d9cb8Szf162725 787e07d9cb8Szf162725 kmem_free(ring->data, ring->count * (sizeof (struct rt2560_rx_data))); 788e07d9cb8Szf162725 kmem_free(ring->dr_rxbuf, ring->count * (sizeof (struct dma_region))); 789e07d9cb8Szf162725 } 790e07d9cb8Szf162725 791e07d9cb8Szf162725 /* ARGSUSED */ 792e07d9cb8Szf162725 static struct ieee80211_node * 793e07d9cb8Szf162725 rt2560_node_alloc(ieee80211com_t *ic) 794e07d9cb8Szf162725 { 795e07d9cb8Szf162725 struct rt2560_node *rn; 796e07d9cb8Szf162725 797e07d9cb8Szf162725 rn = kmem_zalloc(sizeof (struct rt2560_node), KM_SLEEP); 798e07d9cb8Szf162725 return ((rn != NULL) ? &rn->ni : NULL); 799e07d9cb8Szf162725 } 800e07d9cb8Szf162725 801e07d9cb8Szf162725 static void 802e07d9cb8Szf162725 rt2560_node_free(struct ieee80211_node *in) 803e07d9cb8Szf162725 { 804e07d9cb8Szf162725 ieee80211com_t *ic = in->in_ic; 805e07d9cb8Szf162725 806e07d9cb8Szf162725 ic->ic_node_cleanup(in); 807e07d9cb8Szf162725 if (in->in_wpa_ie != NULL) 808e07d9cb8Szf162725 ieee80211_free(in->in_wpa_ie); 809e07d9cb8Szf162725 kmem_free(in, sizeof (struct rt2560_node)); 810e07d9cb8Szf162725 } 811e07d9cb8Szf162725 812e07d9cb8Szf162725 /* 813e07d9cb8Szf162725 * This function is called periodically (every 200ms) during scanning to 814e07d9cb8Szf162725 * switch from one channel to another. 815e07d9cb8Szf162725 */ 816e07d9cb8Szf162725 static void 817e07d9cb8Szf162725 rt2560_next_scan(void *arg) 818e07d9cb8Szf162725 { 819e07d9cb8Szf162725 struct rt2560_softc *sc = arg; 820e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 821e07d9cb8Szf162725 822e07d9cb8Szf162725 if (ic->ic_state == IEEE80211_S_SCAN) 823e07d9cb8Szf162725 (void) ieee80211_next_scan(ic); 824e07d9cb8Szf162725 } 825e07d9cb8Szf162725 826e07d9cb8Szf162725 /* 827e07d9cb8Szf162725 * This function is called for each node present in the node station table. 828e07d9cb8Szf162725 */ 829e07d9cb8Szf162725 /* ARGSUSED */ 830e07d9cb8Szf162725 static void 831e07d9cb8Szf162725 rt2560_iter_func(void *arg, struct ieee80211_node *ni) 832e07d9cb8Szf162725 { 833e07d9cb8Szf162725 struct rt2560_node *rn = (struct rt2560_node *)ni; 834e07d9cb8Szf162725 835e07d9cb8Szf162725 ral_rssadapt_updatestats(&rn->rssadapt); 836e07d9cb8Szf162725 } 837e07d9cb8Szf162725 838e07d9cb8Szf162725 /* 839e07d9cb8Szf162725 * This function is called periodically (every 100ms) in RUN state to update 840e07d9cb8Szf162725 * the rate adaptation statistics. 841e07d9cb8Szf162725 */ 842e07d9cb8Szf162725 static void 843e07d9cb8Szf162725 rt2560_update_rssadapt(void *arg) 844e07d9cb8Szf162725 { 845e07d9cb8Szf162725 struct rt2560_softc *sc = arg; 846e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 847e07d9cb8Szf162725 848e07d9cb8Szf162725 ieee80211_iterate_nodes(&ic->ic_sta, rt2560_iter_func, arg); 849e07d9cb8Szf162725 sc->sc_rssadapt_id = timeout(rt2560_update_rssadapt, (void *)sc, 850e07d9cb8Szf162725 drv_usectohz(100 * 1000)); 851e07d9cb8Szf162725 } 852e07d9cb8Szf162725 853e07d9cb8Szf162725 static void 854e07d9cb8Szf162725 rt2560_statedog(void *arg) 855e07d9cb8Szf162725 { 856e07d9cb8Szf162725 struct rt2560_softc *sc = arg; 857e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 858e07d9cb8Szf162725 enum ieee80211_state state; 859e07d9cb8Szf162725 860e07d9cb8Szf162725 RAL_LOCK(sc); 861e07d9cb8Szf162725 862e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_MSG, "rt2560_statedog(...)\n"); 863e07d9cb8Szf162725 864e07d9cb8Szf162725 sc->sc_state_id = 0; 865e07d9cb8Szf162725 state = ic->ic_state; 866e07d9cb8Szf162725 ic->ic_state = sc->sc_ostate; 867e07d9cb8Szf162725 868e07d9cb8Szf162725 RAL_UNLOCK(sc); 869e07d9cb8Szf162725 870e07d9cb8Szf162725 ieee80211_new_state(ic, state, -1); 871e07d9cb8Szf162725 872e07d9cb8Szf162725 } 873e07d9cb8Szf162725 874e07d9cb8Szf162725 static int 875e07d9cb8Szf162725 rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 876e07d9cb8Szf162725 { 877e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)ic; 878e07d9cb8Szf162725 enum ieee80211_state ostate; 879e07d9cb8Szf162725 struct ieee80211_node *ni; 880e07d9cb8Szf162725 int err; 881e07d9cb8Szf162725 882e07d9cb8Szf162725 RAL_LOCK(sc); 883e07d9cb8Szf162725 884e07d9cb8Szf162725 ostate = ic->ic_state; 885e07d9cb8Szf162725 sc->sc_ostate = ostate; 886e07d9cb8Szf162725 887e07d9cb8Szf162725 if (sc->sc_scan_id != 0) { 888e07d9cb8Szf162725 (void) untimeout(sc->sc_scan_id); 889e07d9cb8Szf162725 sc->sc_scan_id = 0; 890e07d9cb8Szf162725 } 891e07d9cb8Szf162725 892e07d9cb8Szf162725 if (sc->sc_rssadapt_id != 0) { 893e07d9cb8Szf162725 (void) untimeout(sc->sc_rssadapt_id); 894e07d9cb8Szf162725 sc->sc_rssadapt_id = 0; 895e07d9cb8Szf162725 } 896e07d9cb8Szf162725 897e07d9cb8Szf162725 if (sc->sc_state_id != 0) { 898e07d9cb8Szf162725 (void) untimeout(sc->sc_state_id); 899e07d9cb8Szf162725 sc->sc_state_id = 0; 900e07d9cb8Szf162725 } 901e07d9cb8Szf162725 902e07d9cb8Szf162725 switch (nstate) { 903e07d9cb8Szf162725 case IEEE80211_S_INIT: 904e07d9cb8Szf162725 if (ostate == IEEE80211_S_RUN) { 905e07d9cb8Szf162725 /* abort TSF synchronization */ 906e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR14, 0); 907e07d9cb8Szf162725 /* turn association led off */ 908e07d9cb8Szf162725 rt2560_update_led(sc, 0, 0); 909e07d9cb8Szf162725 } 910e07d9cb8Szf162725 break; 911e07d9cb8Szf162725 912e07d9cb8Szf162725 case IEEE80211_S_SCAN: 913e07d9cb8Szf162725 rt2560_set_chan(sc, ic->ic_curchan); 914e07d9cb8Szf162725 sc->sc_scan_id = timeout(rt2560_next_scan, (void *)sc, 915e07d9cb8Szf162725 drv_usectohz(sc->dwelltime * 1000)); 916e07d9cb8Szf162725 break; 917e07d9cb8Szf162725 918e07d9cb8Szf162725 case IEEE80211_S_AUTH: 919e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_STATE, "-> IEEE80211_S_AUTH ...\n"); 920e07d9cb8Szf162725 rt2560_set_chan(sc, ic->ic_curchan); 921e07d9cb8Szf162725 break; 922e07d9cb8Szf162725 923e07d9cb8Szf162725 case IEEE80211_S_ASSOC: 924e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_STATE, "-> IEEE80211_S_ASSOC ...\n"); 925e07d9cb8Szf162725 rt2560_set_chan(sc, ic->ic_curchan); 926e07d9cb8Szf162725 927e07d9cb8Szf162725 drv_usecwait(10 * 1000); /* dlink */ 928e07d9cb8Szf162725 sc->sc_state_id = timeout(rt2560_statedog, (void *)sc, 929e07d9cb8Szf162725 drv_usectohz(300 * 1000)); /* ap7-3 */ 930e07d9cb8Szf162725 break; 931e07d9cb8Szf162725 932e07d9cb8Szf162725 case IEEE80211_S_RUN: 933e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_STATE, "-> IEEE80211_S_RUN ...\n"); 934e07d9cb8Szf162725 rt2560_set_chan(sc, ic->ic_curchan); 935e07d9cb8Szf162725 936e07d9cb8Szf162725 ni = ic->ic_bss; 937e07d9cb8Szf162725 938e07d9cb8Szf162725 if (ic->ic_opmode != IEEE80211_M_MONITOR) { 939e07d9cb8Szf162725 rt2560_update_plcp(sc); 940e07d9cb8Szf162725 rt2560_set_basicrates(sc); 941e07d9cb8Szf162725 rt2560_set_bssid(sc, ni->in_bssid); 942e07d9cb8Szf162725 } 943e07d9cb8Szf162725 944e07d9cb8Szf162725 /* turn assocation led on */ 945e07d9cb8Szf162725 rt2560_update_led(sc, 1, 0); 946e07d9cb8Szf162725 if (ic->ic_opmode != IEEE80211_M_MONITOR) { 947e07d9cb8Szf162725 sc->sc_rssadapt_id = timeout(rt2560_update_rssadapt, 948e07d9cb8Szf162725 (void *)sc, drv_usectohz(100 * 1000)); 949e07d9cb8Szf162725 rt2560_enable_tsf_sync(sc); 950e07d9cb8Szf162725 } 951e07d9cb8Szf162725 break; 952e07d9cb8Szf162725 } 953e07d9cb8Szf162725 954e07d9cb8Szf162725 RAL_UNLOCK(sc); 955e07d9cb8Szf162725 956e07d9cb8Szf162725 err = sc->sc_newstate(ic, nstate, arg); 957e07d9cb8Szf162725 /* 958e07d9cb8Szf162725 * Finally, start any timers. 959e07d9cb8Szf162725 */ 960e07d9cb8Szf162725 if (nstate == IEEE80211_S_RUN) 961e07d9cb8Szf162725 ieee80211_start_watchdog(ic, 1); 962e07d9cb8Szf162725 963e07d9cb8Szf162725 return (err); 964e07d9cb8Szf162725 } 965e07d9cb8Szf162725 966e07d9cb8Szf162725 /* 967e07d9cb8Szf162725 * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or 968e07d9cb8Szf162725 * 93C66). 969e07d9cb8Szf162725 */ 970e07d9cb8Szf162725 static uint16_t 971e07d9cb8Szf162725 rt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr) 972e07d9cb8Szf162725 { 973e07d9cb8Szf162725 uint32_t tmp; 974e07d9cb8Szf162725 uint16_t val; 975e07d9cb8Szf162725 int n; 976e07d9cb8Szf162725 977e07d9cb8Szf162725 /* clock C once before the first command */ 978e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, 0); 979e07d9cb8Szf162725 980e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S); 981e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 982e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S); 983e07d9cb8Szf162725 984e07d9cb8Szf162725 /* write start bit (1) */ 985e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 986e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 987e07d9cb8Szf162725 988e07d9cb8Szf162725 /* write READ opcode (10) */ 989e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D); 990e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C); 991e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S); 992e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 993e07d9cb8Szf162725 994e07d9cb8Szf162725 /* write address (A5-A0 or A7-A0) */ 995e07d9cb8Szf162725 n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7; 996e07d9cb8Szf162725 for (; n >= 0; n--) { 997e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | 998e07d9cb8Szf162725 (((addr >> n) & 1) << RT2560_SHIFT_D)); 999e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | 1000e07d9cb8Szf162725 (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C); 1001e07d9cb8Szf162725 } 1002e07d9cb8Szf162725 1003e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S); 1004e07d9cb8Szf162725 1005e07d9cb8Szf162725 /* read data Q15-Q0 */ 1006e07d9cb8Szf162725 val = 0; 1007e07d9cb8Szf162725 for (n = 15; n >= 0; n--) { 1008e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C); 1009e07d9cb8Szf162725 tmp = RAL_READ(sc, RT2560_CSR21); 1010e07d9cb8Szf162725 val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n; 1011e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S); 1012e07d9cb8Szf162725 } 1013e07d9cb8Szf162725 1014e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, 0); 1015e07d9cb8Szf162725 1016e07d9cb8Szf162725 /* clear Chip Select and clock C */ 1017e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_S); 1018e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, 0); 1019e07d9cb8Szf162725 RT2560_EEPROM_CTL(sc, RT2560_C); 1020e07d9cb8Szf162725 1021e07d9cb8Szf162725 return (val); 1022e07d9cb8Szf162725 } 1023e07d9cb8Szf162725 1024e07d9cb8Szf162725 static void 1025e07d9cb8Szf162725 rt2560_tx_intr(struct rt2560_softc *sc) 1026e07d9cb8Szf162725 { 1027e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 1028e07d9cb8Szf162725 struct rt2560_tx_desc *desc; 1029e07d9cb8Szf162725 struct rt2560_tx_data *data; 1030e07d9cb8Szf162725 struct rt2560_node *rn; 1031e07d9cb8Szf162725 1032e07d9cb8Szf162725 struct dma_region *dr; 1033e07d9cb8Szf162725 int count; 1034e07d9cb8Szf162725 1035e07d9cb8Szf162725 dr = &sc->txq.dr_desc; 1036e07d9cb8Szf162725 count = sc->txq.count; 1037e07d9cb8Szf162725 1038e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, count * RT2560_TX_DESC_SIZE, 1039e07d9cb8Szf162725 DDI_DMA_SYNC_FORKERNEL); 1040e07d9cb8Szf162725 1041e07d9cb8Szf162725 mutex_enter(&sc->txq.tx_lock); 1042e07d9cb8Szf162725 1043e07d9cb8Szf162725 for (;;) { 1044e07d9cb8Szf162725 desc = &sc->txq.desc[sc->txq.next]; 1045e07d9cb8Szf162725 data = &sc->txq.data[sc->txq.next]; 1046e07d9cb8Szf162725 1047e07d9cb8Szf162725 if ((LE_32(desc->flags) & RT2560_TX_BUSY) || 1048e07d9cb8Szf162725 (LE_32(desc->flags) & RT2560_TX_CIPHER_BUSY) || 1049e07d9cb8Szf162725 !(LE_32(desc->flags) & RT2560_TX_VALID)) 1050e07d9cb8Szf162725 break; 1051e07d9cb8Szf162725 1052e07d9cb8Szf162725 rn = (struct rt2560_node *)data->ni; 1053e07d9cb8Szf162725 1054e07d9cb8Szf162725 switch (LE_32(desc->flags) & RT2560_TX_RESULT_MASK) { 1055e07d9cb8Szf162725 case RT2560_TX_SUCCESS: 1056e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, "data frame sent success\n"); 1057e07d9cb8Szf162725 if (data->id.id_node != NULL) { 1058e07d9cb8Szf162725 ral_rssadapt_raise_rate(ic, &rn->rssadapt, 1059e07d9cb8Szf162725 &data->id); 1060e07d9cb8Szf162725 } 1061e07d9cb8Szf162725 break; 1062e07d9cb8Szf162725 1063e07d9cb8Szf162725 case RT2560_TX_SUCCESS_RETRY: 1064e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, 1065e07d9cb8Szf162725 "data frame sent after %u retries\n", 1066e07d9cb8Szf162725 (LE_32(desc->flags) >> 5) & 0x7); 1067e07d9cb8Szf162725 sc->sc_tx_retries++; 1068e07d9cb8Szf162725 break; 1069e07d9cb8Szf162725 1070e07d9cb8Szf162725 case RT2560_TX_FAIL_RETRY: 1071e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, 1072e07d9cb8Szf162725 "sending data frame failed (too much retries)\n"); 1073e07d9cb8Szf162725 if (data->id.id_node != NULL) { 1074e07d9cb8Szf162725 ral_rssadapt_lower_rate(ic, data->ni, 1075e07d9cb8Szf162725 &rn->rssadapt, &data->id); 1076e07d9cb8Szf162725 } 1077e07d9cb8Szf162725 break; 1078e07d9cb8Szf162725 1079e07d9cb8Szf162725 case RT2560_TX_FAIL_INVALID: 1080e07d9cb8Szf162725 case RT2560_TX_FAIL_OTHER: 1081e07d9cb8Szf162725 default: 1082e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, "sending data frame failed " 1083e07d9cb8Szf162725 "0x%08x\n", LE_32(desc->flags)); 1084e07d9cb8Szf162725 break; 1085e07d9cb8Szf162725 } 1086e07d9cb8Szf162725 1087e07d9cb8Szf162725 ieee80211_free_node(data->ni); 1088e07d9cb8Szf162725 data->ni = NULL; 1089e07d9cb8Szf162725 1090e07d9cb8Szf162725 /* descriptor is no longer valid */ 1091e07d9cb8Szf162725 desc->flags &= ~LE_32(RT2560_TX_VALID); 1092e07d9cb8Szf162725 1093e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, "tx done idx=%u\n", sc->txq.next); 1094e07d9cb8Szf162725 1095e07d9cb8Szf162725 sc->txq.queued--; 1096e07d9cb8Szf162725 sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT; 1097e07d9cb8Szf162725 1098e07d9cb8Szf162725 if (sc->sc_need_sched && 1099e07d9cb8Szf162725 sc->txq.queued < (RT2560_TX_RING_COUNT - 32)) { 1100e07d9cb8Szf162725 sc->sc_need_sched = 0; 1101e07d9cb8Szf162725 mac_tx_update(ic->ic_mach); 1102e07d9cb8Szf162725 } 1103e07d9cb8Szf162725 } 1104e07d9cb8Szf162725 1105e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, count * RT2560_TX_DESC_SIZE, 1106e07d9cb8Szf162725 DDI_DMA_SYNC_FORDEV); 1107e07d9cb8Szf162725 1108e07d9cb8Szf162725 sc->sc_tx_timer = 0; 1109e07d9cb8Szf162725 mutex_exit(&sc->txq.tx_lock); 1110e07d9cb8Szf162725 } 1111e07d9cb8Szf162725 1112e07d9cb8Szf162725 static void 1113e07d9cb8Szf162725 rt2560_prio_intr(struct rt2560_softc *sc) 1114e07d9cb8Szf162725 { 1115e07d9cb8Szf162725 struct rt2560_tx_desc *desc; 1116e07d9cb8Szf162725 struct rt2560_tx_data *data; 1117e07d9cb8Szf162725 1118e07d9cb8Szf162725 struct dma_region *dr; 1119e07d9cb8Szf162725 int count; 1120e07d9cb8Szf162725 1121e07d9cb8Szf162725 dr = &sc->prioq.dr_desc; 1122e07d9cb8Szf162725 count = sc->prioq.count; 1123e07d9cb8Szf162725 1124e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, count * RT2560_TX_DESC_SIZE, 1125e07d9cb8Szf162725 DDI_DMA_SYNC_FORKERNEL); 1126e07d9cb8Szf162725 1127e07d9cb8Szf162725 mutex_enter(&sc->prioq.tx_lock); 1128e07d9cb8Szf162725 1129e07d9cb8Szf162725 for (;;) { 1130e07d9cb8Szf162725 desc = &sc->prioq.desc[sc->prioq.next]; 1131e07d9cb8Szf162725 data = &sc->prioq.data[sc->prioq.next]; 1132e07d9cb8Szf162725 1133e07d9cb8Szf162725 if ((LE_32(desc->flags) & RT2560_TX_BUSY) || 1134e07d9cb8Szf162725 !(LE_32(desc->flags) & RT2560_TX_VALID)) 1135e07d9cb8Szf162725 break; 1136e07d9cb8Szf162725 1137e07d9cb8Szf162725 switch (LE_32(desc->flags) & RT2560_TX_RESULT_MASK) { 1138e07d9cb8Szf162725 case RT2560_TX_SUCCESS: 1139e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, "mgt frame sent success\n"); 1140e07d9cb8Szf162725 break; 1141e07d9cb8Szf162725 1142e07d9cb8Szf162725 case RT2560_TX_SUCCESS_RETRY: 1143e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, 1144e07d9cb8Szf162725 "mgt frame sent after %u retries\n", 1145e07d9cb8Szf162725 (LE_32(desc->flags) >> 5) & 0x7); 1146e07d9cb8Szf162725 break; 1147e07d9cb8Szf162725 1148e07d9cb8Szf162725 case RT2560_TX_FAIL_RETRY: 1149e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, 1150e07d9cb8Szf162725 "sending mgt frame failed (too much " "retries)\n"); 1151e07d9cb8Szf162725 break; 1152e07d9cb8Szf162725 1153e07d9cb8Szf162725 case RT2560_TX_FAIL_INVALID: 1154e07d9cb8Szf162725 case RT2560_TX_FAIL_OTHER: 1155e07d9cb8Szf162725 default: 1156e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, "sending mgt frame failed " 1157e07d9cb8Szf162725 "0x%08x\n", LE_32(desc->flags)); 1158e07d9cb8Szf162725 } 1159e07d9cb8Szf162725 1160e07d9cb8Szf162725 ieee80211_free_node(data->ni); 1161e07d9cb8Szf162725 data->ni = NULL; 1162e07d9cb8Szf162725 1163e07d9cb8Szf162725 /* descriptor is no longer valid */ 1164e07d9cb8Szf162725 desc->flags &= ~LE_32(RT2560_TX_VALID); 1165e07d9cb8Szf162725 1166e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_INTR, "prio done idx=%u\n", sc->prioq.next); 1167e07d9cb8Szf162725 1168e07d9cb8Szf162725 sc->prioq.queued--; 1169e07d9cb8Szf162725 sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT; 1170e07d9cb8Szf162725 } 1171e07d9cb8Szf162725 1172e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, count * RT2560_TX_DESC_SIZE, 1173e07d9cb8Szf162725 DDI_DMA_SYNC_FORDEV); 1174e07d9cb8Szf162725 1175e07d9cb8Szf162725 sc->sc_tx_timer = 0; 1176e07d9cb8Szf162725 mutex_exit(&sc->prioq.tx_lock); 1177e07d9cb8Szf162725 } 1178e07d9cb8Szf162725 1179e07d9cb8Szf162725 /* 1180e07d9cb8Szf162725 * Some frames were received. Pass them to the hardware cipher engine before 1181e07d9cb8Szf162725 * sending them to the 802.11 layer. 1182e07d9cb8Szf162725 */ 1183e07d9cb8Szf162725 void 1184e07d9cb8Szf162725 rt2560_rx_intr(struct rt2560_softc *sc) 1185e07d9cb8Szf162725 { 1186e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 1187e07d9cb8Szf162725 struct rt2560_rx_desc *desc; 1188e07d9cb8Szf162725 struct rt2560_rx_data *data; 1189e07d9cb8Szf162725 struct ieee80211_frame *wh; 1190e07d9cb8Szf162725 struct ieee80211_node *ni; 1191e07d9cb8Szf162725 struct rt2560_node *rn; 1192e07d9cb8Szf162725 1193e07d9cb8Szf162725 mblk_t *m; 1194e07d9cb8Szf162725 uint32_t len; 1195e07d9cb8Szf162725 char *rxbuf; 1196e07d9cb8Szf162725 1197e07d9cb8Szf162725 struct dma_region *dr, *dr_bf; 1198e07d9cb8Szf162725 int count; 1199e07d9cb8Szf162725 1200e07d9cb8Szf162725 dr = &sc->rxq.dr_desc; 1201e07d9cb8Szf162725 count = sc->rxq.count; 1202e07d9cb8Szf162725 1203e07d9cb8Szf162725 mutex_enter(&sc->rxq.rx_lock); 1204e07d9cb8Szf162725 1205e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, count * RT2560_RX_DESC_SIZE, 1206e07d9cb8Szf162725 DDI_DMA_SYNC_FORKERNEL); 1207e07d9cb8Szf162725 1208e07d9cb8Szf162725 for (;;) { 1209e07d9cb8Szf162725 desc = &sc->rxq.desc[sc->rxq.cur]; 1210e07d9cb8Szf162725 data = &sc->rxq.data[sc->rxq.cur]; 1211e07d9cb8Szf162725 1212e07d9cb8Szf162725 if ((LE_32(desc->flags) & RT2560_RX_BUSY) || 1213e07d9cb8Szf162725 (LE_32(desc->flags) & RT2560_RX_CIPHER_BUSY)) 1214e07d9cb8Szf162725 break; 1215e07d9cb8Szf162725 1216e07d9cb8Szf162725 data->drop = 0; 1217e07d9cb8Szf162725 1218e07d9cb8Szf162725 if ((LE_32(desc->flags) & RT2560_RX_PHY_ERROR) || 1219e07d9cb8Szf162725 (LE_32(desc->flags) & RT2560_RX_CRC_ERROR)) { 1220e07d9cb8Szf162725 /* 1221e07d9cb8Szf162725 * This should not happen since we did not request 1222e07d9cb8Szf162725 * to receive those frames when we filled RXCSR0. 1223e07d9cb8Szf162725 */ 1224e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_RX, "PHY or CRC error flags 0x%08x\n", 1225e07d9cb8Szf162725 LE_32(desc->flags)); 1226e07d9cb8Szf162725 data->drop = 1; 1227e07d9cb8Szf162725 } 1228e07d9cb8Szf162725 1229e07d9cb8Szf162725 if (((LE_32(desc->flags) >> 16) & 0xfff) > RAL_RXBUF_SIZE) { 1230e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_RX, "bad length\n"); 1231e07d9cb8Szf162725 data->drop = 1; 1232e07d9cb8Szf162725 } 1233e07d9cb8Szf162725 1234e07d9cb8Szf162725 if (data->drop) { 1235e07d9cb8Szf162725 sc->sc_rx_err++; 1236e07d9cb8Szf162725 goto skip; 1237e07d9cb8Szf162725 } 1238e07d9cb8Szf162725 1239e07d9cb8Szf162725 rxbuf = data->buf; 1240e07d9cb8Szf162725 len = (LE_32(desc->flags) >> 16) & 0xfff; 1241e07d9cb8Szf162725 1242e07d9cb8Szf162725 if ((len < sizeof (struct ieee80211_frame_min)) || 1243e07d9cb8Szf162725 (len > RAL_RXBUF_SIZE)) { 1244e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_RX, "bad frame length=%u\n", len); 1245e07d9cb8Szf162725 sc->sc_rx_err++; 1246e07d9cb8Szf162725 goto skip; 1247e07d9cb8Szf162725 } 1248e07d9cb8Szf162725 1249e07d9cb8Szf162725 if ((m = allocb(len, BPRI_MED)) == NULL) { 1250e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_RX, "rt2560_rx_intr():" 1251e07d9cb8Szf162725 " allocate mblk failed.\n"); 1252e07d9cb8Szf162725 sc->sc_rx_nobuf++; 1253e07d9cb8Szf162725 goto skip; 1254e07d9cb8Szf162725 } 1255e07d9cb8Szf162725 1256e07d9cb8Szf162725 dr_bf = &sc->rxq.dr_rxbuf[sc->rxq.cur]; 1257e07d9cb8Szf162725 (void) ddi_dma_sync(dr_bf->dr_hnd, 0, dr_bf->dr_size, 1258e07d9cb8Szf162725 DDI_DMA_SYNC_FORCPU); 1259e07d9cb8Szf162725 1260e07d9cb8Szf162725 bcopy(rxbuf, m->b_rptr, len); 1261e07d9cb8Szf162725 m->b_wptr += len; 1262e07d9cb8Szf162725 1263e07d9cb8Szf162725 wh = (struct ieee80211_frame *)m->b_rptr; 1264e07d9cb8Szf162725 ni = ieee80211_find_rxnode(ic, wh); 1265e07d9cb8Szf162725 1266e07d9cb8Szf162725 /* give rssi to the rate adatation algorithm */ 1267e07d9cb8Szf162725 rn = (struct rt2560_node *)ni; 1268e07d9cb8Szf162725 ral_rssadapt_input(ic, ni, &rn->rssadapt, desc->rssi); 1269e07d9cb8Szf162725 1270e07d9cb8Szf162725 /* send the frame to the 802.11 layer */ 1271e07d9cb8Szf162725 (void) ieee80211_input(ic, m, ni, desc->rssi, 0); 1272e07d9cb8Szf162725 1273e07d9cb8Szf162725 /* node is no longer needed */ 1274e07d9cb8Szf162725 ieee80211_free_node(ni); 1275e07d9cb8Szf162725 1276e07d9cb8Szf162725 skip: desc->flags = LE_32(RT2560_RX_BUSY); 1277e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_RX, "rx done idx=%u\n", sc->rxq.cur); 1278e07d9cb8Szf162725 1279e07d9cb8Szf162725 sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT; 1280e07d9cb8Szf162725 } 1281e07d9cb8Szf162725 mutex_exit(&sc->rxq.rx_lock); 1282e07d9cb8Szf162725 1283e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, count * RT2560_TX_DESC_SIZE, 1284e07d9cb8Szf162725 DDI_DMA_SYNC_FORDEV); 1285e07d9cb8Szf162725 } 1286e07d9cb8Szf162725 1287e07d9cb8Szf162725 uint_t 1288e07d9cb8Szf162725 ral_softint_handler(caddr_t data) 1289e07d9cb8Szf162725 { 1290e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)data; 1291e07d9cb8Szf162725 1292e07d9cb8Szf162725 /* 1293e07d9cb8Szf162725 * Check if the soft interrupt is triggered by another 1294e07d9cb8Szf162725 * driver at the same level. 1295e07d9cb8Szf162725 */ 1296e07d9cb8Szf162725 RAL_LOCK(sc); 1297e07d9cb8Szf162725 if (sc->sc_rx_pend) { 1298e07d9cb8Szf162725 sc->sc_rx_pend = 0; 1299e07d9cb8Szf162725 RAL_UNLOCK(sc); 1300e07d9cb8Szf162725 rt2560_rx_intr((struct rt2560_softc *)data); 1301e07d9cb8Szf162725 return (DDI_INTR_CLAIMED); 1302e07d9cb8Szf162725 } 1303e07d9cb8Szf162725 RAL_UNLOCK(sc); 1304e07d9cb8Szf162725 return (DDI_INTR_UNCLAIMED); 1305e07d9cb8Szf162725 } 1306e07d9cb8Szf162725 1307e07d9cb8Szf162725 /* 1308e07d9cb8Szf162725 * Return the expected ack rate for a frame transmitted at rate `rate'. 1309e07d9cb8Szf162725 * XXX: this should depend on the destination node basic rate set. 1310e07d9cb8Szf162725 */ 1311e07d9cb8Szf162725 static int 1312e07d9cb8Szf162725 rt2560_ack_rate(struct ieee80211com *ic, int rate) 1313e07d9cb8Szf162725 { 1314e07d9cb8Szf162725 switch (rate) { 1315e07d9cb8Szf162725 /* CCK rates */ 1316e07d9cb8Szf162725 case 2: 1317e07d9cb8Szf162725 return (2); 1318e07d9cb8Szf162725 case 4: 1319e07d9cb8Szf162725 case 11: 1320e07d9cb8Szf162725 case 22: 1321e07d9cb8Szf162725 return ((ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate); 1322e07d9cb8Szf162725 1323e07d9cb8Szf162725 /* OFDM rates */ 1324e07d9cb8Szf162725 case 12: 1325e07d9cb8Szf162725 case 18: 1326e07d9cb8Szf162725 return (12); 1327e07d9cb8Szf162725 case 24: 1328e07d9cb8Szf162725 case 36: 1329e07d9cb8Szf162725 return (24); 1330e07d9cb8Szf162725 case 48: 1331e07d9cb8Szf162725 case 72: 1332e07d9cb8Szf162725 case 96: 1333e07d9cb8Szf162725 case 108: 1334e07d9cb8Szf162725 return (48); 1335e07d9cb8Szf162725 } 1336e07d9cb8Szf162725 1337e07d9cb8Szf162725 /* default to 1Mbps */ 1338e07d9cb8Szf162725 return (2); 1339e07d9cb8Szf162725 } 1340e07d9cb8Szf162725 1341e07d9cb8Szf162725 /* 1342e07d9cb8Szf162725 * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'. 1343e07d9cb8Szf162725 * The function automatically determines the operating mode depending on the 1344e07d9cb8Szf162725 * given rate. `flags' indicates whether short preamble is in use or not. 1345e07d9cb8Szf162725 */ 1346e07d9cb8Szf162725 static uint16_t 1347e07d9cb8Szf162725 rt2560_txtime(int len, int rate, uint32_t flags) 1348e07d9cb8Szf162725 { 1349e07d9cb8Szf162725 uint16_t txtime; 1350e07d9cb8Szf162725 1351e07d9cb8Szf162725 if (RAL_RATE_IS_OFDM(rate)) { 1352e07d9cb8Szf162725 /* IEEE Std 802.11a-1999, pp. 37 */ 1353e07d9cb8Szf162725 txtime = (8 + 4 * len + 3 + rate - 1) / rate; 1354e07d9cb8Szf162725 txtime = 16 + 4 + 4 * txtime + 6; 1355e07d9cb8Szf162725 } else { 1356e07d9cb8Szf162725 /* IEEE Std 802.11b-1999, pp. 28 */ 1357e07d9cb8Szf162725 txtime = (16 * len + rate - 1) / rate; 1358e07d9cb8Szf162725 if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) 1359e07d9cb8Szf162725 txtime += 72 + 24; 1360e07d9cb8Szf162725 else 1361e07d9cb8Szf162725 txtime += 144 + 48; 1362e07d9cb8Szf162725 } 1363e07d9cb8Szf162725 1364e07d9cb8Szf162725 return (txtime); 1365e07d9cb8Szf162725 } 1366e07d9cb8Szf162725 1367e07d9cb8Szf162725 static uint8_t 1368e07d9cb8Szf162725 rt2560_plcp_signal(int rate) 1369e07d9cb8Szf162725 { 1370e07d9cb8Szf162725 switch (rate) { 1371e07d9cb8Szf162725 /* CCK rates (returned values are device-dependent) */ 1372e07d9cb8Szf162725 case 2: return (0x0); 1373e07d9cb8Szf162725 case 4: return (0x1); 1374e07d9cb8Szf162725 case 11: return (0x2); 1375e07d9cb8Szf162725 case 22: return (0x3); 1376e07d9cb8Szf162725 1377e07d9cb8Szf162725 /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1378e07d9cb8Szf162725 case 12: return (0xb); 1379e07d9cb8Szf162725 case 18: return (0xf); 1380e07d9cb8Szf162725 case 24: return (0xa); 1381e07d9cb8Szf162725 case 36: return (0xe); 1382e07d9cb8Szf162725 case 48: return (0x9); 1383e07d9cb8Szf162725 case 72: return (0xd); 1384e07d9cb8Szf162725 case 96: return (0x8); 1385e07d9cb8Szf162725 case 108: return (0xc); 1386e07d9cb8Szf162725 1387e07d9cb8Szf162725 /* unsupported rates (should not get there) */ 1388e07d9cb8Szf162725 default: return (0xff); 1389e07d9cb8Szf162725 } 1390e07d9cb8Szf162725 } 1391e07d9cb8Szf162725 1392e07d9cb8Szf162725 void 1393e07d9cb8Szf162725 rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, 1394e07d9cb8Szf162725 uint32_t flags, int len, int rate, int encrypt) 1395e07d9cb8Szf162725 { 1396e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 1397e07d9cb8Szf162725 uint16_t plcp_length; 1398e07d9cb8Szf162725 int remainder; 1399e07d9cb8Szf162725 1400e07d9cb8Szf162725 desc->flags = LE_32(flags); 1401e07d9cb8Szf162725 desc->flags |= LE_32(len << 16); 1402e07d9cb8Szf162725 desc->flags |= encrypt ? LE_32(RT2560_TX_CIPHER_BUSY) : 1403e07d9cb8Szf162725 LE_32(RT2560_TX_BUSY | RT2560_TX_VALID); 1404e07d9cb8Szf162725 1405e07d9cb8Szf162725 desc->wme = LE_16( 1406e07d9cb8Szf162725 RT2560_AIFSN(2) | 1407e07d9cb8Szf162725 RT2560_LOGCWMIN(3) | 1408e07d9cb8Szf162725 RT2560_LOGCWMAX(8)); 1409e07d9cb8Szf162725 1410e07d9cb8Szf162725 /* setup PLCP fields */ 1411e07d9cb8Szf162725 desc->plcp_signal = rt2560_plcp_signal(rate); 1412e07d9cb8Szf162725 desc->plcp_service = 4; 1413e07d9cb8Szf162725 1414e07d9cb8Szf162725 len += IEEE80211_CRC_LEN; 1415e07d9cb8Szf162725 if (RAL_RATE_IS_OFDM(rate)) { 1416e07d9cb8Szf162725 desc->flags |= LE_32(RT2560_TX_OFDM); 1417e07d9cb8Szf162725 1418e07d9cb8Szf162725 plcp_length = len & 0xfff; 1419e07d9cb8Szf162725 desc->plcp_length_hi = plcp_length >> 6; 1420e07d9cb8Szf162725 desc->plcp_length_lo = plcp_length & 0x3f; 1421e07d9cb8Szf162725 } else { 1422e07d9cb8Szf162725 plcp_length = (16 * len + rate - 1) / rate; 1423e07d9cb8Szf162725 if (rate == 22) { 1424e07d9cb8Szf162725 remainder = (16 * len) % 22; 1425e07d9cb8Szf162725 if (remainder != 0 && remainder < 7) 1426e07d9cb8Szf162725 desc->plcp_service |= RT2560_PLCP_LENGEXT; 1427e07d9cb8Szf162725 } 1428e07d9cb8Szf162725 desc->plcp_length_hi = plcp_length >> 8; 1429e07d9cb8Szf162725 desc->plcp_length_lo = plcp_length & 0xff; 1430e07d9cb8Szf162725 1431e07d9cb8Szf162725 if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1432e07d9cb8Szf162725 desc->plcp_signal |= 0x08; 1433e07d9cb8Szf162725 } 1434e07d9cb8Szf162725 } 1435e07d9cb8Szf162725 1436e07d9cb8Szf162725 /* ARGSUSED */ 1437e07d9cb8Szf162725 int 1438e07d9cb8Szf162725 rt2560_mgmt_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 1439e07d9cb8Szf162725 { 1440e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)ic; 1441e07d9cb8Szf162725 struct rt2560_tx_desc *desc; 1442e07d9cb8Szf162725 struct rt2560_tx_data *data; 1443e07d9cb8Szf162725 struct ieee80211_frame *wh; 1444e07d9cb8Szf162725 uint16_t dur; 1445e07d9cb8Szf162725 uint32_t flags = 0; 1446e07d9cb8Szf162725 int rate, err = DDI_SUCCESS; 1447e07d9cb8Szf162725 1448e07d9cb8Szf162725 int off, pktlen, mblen; 1449e07d9cb8Szf162725 caddr_t dest; 1450e07d9cb8Szf162725 mblk_t *m, *m0; 1451e07d9cb8Szf162725 1452e07d9cb8Szf162725 struct dma_region *dr; 1453e07d9cb8Szf162725 uint32_t idx; 1454e07d9cb8Szf162725 struct ieee80211_node *ni; 1455e07d9cb8Szf162725 struct ieee80211_key *k; 1456e07d9cb8Szf162725 1457e07d9cb8Szf162725 mutex_enter(&sc->prioq.tx_lock); 1458e07d9cb8Szf162725 1459e07d9cb8Szf162725 if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { 1460e07d9cb8Szf162725 err = ENOMEM; 1461e07d9cb8Szf162725 sc->sc_tx_nobuf++; 1462e07d9cb8Szf162725 goto fail1; 1463e07d9cb8Szf162725 } 1464e07d9cb8Szf162725 1465e07d9cb8Szf162725 m = allocb(msgdsize(mp) + 32, BPRI_MED); 1466e07d9cb8Szf162725 if (m == NULL) { 1467e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_TX, "rt2560_mgmt_send: can't alloc mblk.\n"); 1468e07d9cb8Szf162725 err = DDI_FAILURE; 1469e07d9cb8Szf162725 goto fail1; 1470e07d9cb8Szf162725 } 1471e07d9cb8Szf162725 1472e07d9cb8Szf162725 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 1473e07d9cb8Szf162725 mblen = MBLKL(m0); 1474e07d9cb8Szf162725 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); 1475e07d9cb8Szf162725 off += mblen; 1476e07d9cb8Szf162725 } 1477e07d9cb8Szf162725 m->b_wptr += off; 1478e07d9cb8Szf162725 1479e07d9cb8Szf162725 wh = (struct ieee80211_frame *)m->b_rptr; 1480e07d9cb8Szf162725 ni = ieee80211_find_txnode(ic, wh->i_addr1); 1481e07d9cb8Szf162725 1482e07d9cb8Szf162725 if (ni == NULL) { 1483e07d9cb8Szf162725 err = DDI_FAILURE; 1484e07d9cb8Szf162725 sc->sc_tx_err++; 1485e07d9cb8Szf162725 goto fail2; 1486e07d9cb8Szf162725 } 1487e07d9cb8Szf162725 1488e07d9cb8Szf162725 /* to support shared_key auth mode */ 1489e07d9cb8Szf162725 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1490e07d9cb8Szf162725 k = ieee80211_crypto_encap(ic, m); 1491e07d9cb8Szf162725 if (k == NULL) { 1492e07d9cb8Szf162725 err = DDI_FAILURE; 1493e07d9cb8Szf162725 sc->sc_tx_err++; 1494e07d9cb8Szf162725 goto fail3; 1495e07d9cb8Szf162725 } 1496e07d9cb8Szf162725 /* packet header may have moved, reset our local pointer */ 1497e07d9cb8Szf162725 wh = (struct ieee80211_frame *)m->b_rptr; 1498e07d9cb8Szf162725 } 1499e07d9cb8Szf162725 1500e07d9cb8Szf162725 desc = &sc->prioq.desc[sc->prioq.cur]; 1501e07d9cb8Szf162725 data = &sc->prioq.data[sc->prioq.cur]; 1502e07d9cb8Szf162725 1503e07d9cb8Szf162725 rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; 1504e07d9cb8Szf162725 data->ni = ieee80211_ref_node(ni); 1505e07d9cb8Szf162725 1506e07d9cb8Szf162725 pktlen = msgdsize(m); 1507e07d9cb8Szf162725 dest = data->buf; 1508e07d9cb8Szf162725 bcopy(m->b_rptr, dest, pktlen); 1509e07d9cb8Szf162725 1510e07d9cb8Szf162725 wh = (struct ieee80211_frame *)m->b_rptr; 1511e07d9cb8Szf162725 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1512e07d9cb8Szf162725 flags |= RT2560_TX_ACK; 1513e07d9cb8Szf162725 1514e07d9cb8Szf162725 dur = rt2560_txtime(RAL_ACK_SIZE, rate, ic->ic_flags) + 1515e07d9cb8Szf162725 RAL_SIFS; 1516e07d9cb8Szf162725 *(uint16_t *)wh->i_dur = LE_16(dur); 1517e07d9cb8Szf162725 1518e07d9cb8Szf162725 /* tell hardware to add timestamp for probe responses */ 1519e07d9cb8Szf162725 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1520e07d9cb8Szf162725 IEEE80211_FC0_TYPE_MGT && 1521e07d9cb8Szf162725 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1522e07d9cb8Szf162725 IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1523e07d9cb8Szf162725 flags |= RT2560_TX_TIMESTAMP; 1524e07d9cb8Szf162725 } 1525e07d9cb8Szf162725 1526e07d9cb8Szf162725 rt2560_setup_tx_desc(sc, desc, flags, pktlen, rate, 0); 1527e07d9cb8Szf162725 1528e07d9cb8Szf162725 idx = sc->prioq.cur; 1529e07d9cb8Szf162725 1530e07d9cb8Szf162725 dr = &sc->prioq.dr_txbuf[idx]; 1531e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, RAL_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 1532e07d9cb8Szf162725 1533e07d9cb8Szf162725 dr = &sc->prioq.dr_desc; 1534e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, idx * RT2560_TX_DESC_SIZE, 1535e07d9cb8Szf162725 RT2560_TX_DESC_SIZE, DDI_DMA_SYNC_FORDEV); 1536e07d9cb8Szf162725 1537e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_MGMT, "sending mgt frame len=%u idx=%u rate=%u\n", 1538e07d9cb8Szf162725 pktlen, sc->prioq.cur, rate); 1539e07d9cb8Szf162725 1540e07d9cb8Szf162725 /* kick prio */ 1541e07d9cb8Szf162725 sc->prioq.queued++; /* IF > RT2560_PRIO_RING_COUNT? FULL */ 1542e07d9cb8Szf162725 sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; 1543e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); 1544e07d9cb8Szf162725 1545e07d9cb8Szf162725 sc->sc_tx_timer = 5; 1546e07d9cb8Szf162725 1547fb91fd8aSzf162725 ic->ic_stats.is_tx_frags++; 1548fb91fd8aSzf162725 ic->ic_stats.is_tx_bytes += pktlen; 1549fb91fd8aSzf162725 1550e07d9cb8Szf162725 fail3: 1551e07d9cb8Szf162725 ieee80211_free_node(ni); 1552e07d9cb8Szf162725 fail2: 1553e07d9cb8Szf162725 freemsg(m); 1554e07d9cb8Szf162725 fail1: 1555e07d9cb8Szf162725 freemsg(mp); 1556e07d9cb8Szf162725 mutex_exit(&sc->prioq.tx_lock); 1557e07d9cb8Szf162725 1558e07d9cb8Szf162725 return (err); 1559e07d9cb8Szf162725 } 1560e07d9cb8Szf162725 1561e07d9cb8Szf162725 static int 1562e07d9cb8Szf162725 rt2560_send(ieee80211com_t *ic, mblk_t *mp) 1563e07d9cb8Szf162725 { 1564e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)ic; 1565e07d9cb8Szf162725 struct rt2560_tx_desc *desc; 1566e07d9cb8Szf162725 struct rt2560_tx_data *data; 1567e07d9cb8Szf162725 struct rt2560_node *rn; 1568e07d9cb8Szf162725 struct ieee80211_rateset *rs; 1569e07d9cb8Szf162725 struct ieee80211_frame *wh; 1570e07d9cb8Szf162725 struct ieee80211_key *k; 1571e07d9cb8Szf162725 uint16_t dur; 1572e07d9cb8Szf162725 uint32_t flags = 0; 1573e07d9cb8Szf162725 int rate, err = DDI_SUCCESS; 1574e07d9cb8Szf162725 1575e07d9cb8Szf162725 struct ieee80211_node *ni; 1576e07d9cb8Szf162725 mblk_t *m, *m0; 1577e07d9cb8Szf162725 int off, mblen, pktlen; 1578e07d9cb8Szf162725 caddr_t dest; 1579e07d9cb8Szf162725 1580e07d9cb8Szf162725 struct dma_region *dr; 1581e07d9cb8Szf162725 uint32_t idx; 1582e07d9cb8Szf162725 1583e07d9cb8Szf162725 mutex_enter(&sc->txq.tx_lock); 1584e07d9cb8Szf162725 1585e07d9cb8Szf162725 if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) { 1586e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_TX, "ral: rt2560_tx_data(): " 1587e07d9cb8Szf162725 "no TX DMA buffer available!\n"); 1588e07d9cb8Szf162725 sc->sc_need_sched = 1; 1589e07d9cb8Szf162725 sc->sc_tx_nobuf++; 1590e07d9cb8Szf162725 err = ENOMEM; 1591e07d9cb8Szf162725 goto fail1; 1592e07d9cb8Szf162725 } 1593e07d9cb8Szf162725 1594e07d9cb8Szf162725 m = allocb(msgdsize(mp) + 32, BPRI_MED); 1595e07d9cb8Szf162725 if (m == NULL) { 1596e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_TX, "rt2560_xmit(): can't alloc mblk.\n"); 1597e07d9cb8Szf162725 err = DDI_FAILURE; 1598e07d9cb8Szf162725 goto fail1; 1599e07d9cb8Szf162725 } 1600e07d9cb8Szf162725 1601e07d9cb8Szf162725 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 1602e07d9cb8Szf162725 mblen = MBLKL(m0); 1603e07d9cb8Szf162725 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); 1604e07d9cb8Szf162725 off += mblen; 1605e07d9cb8Szf162725 } 1606e07d9cb8Szf162725 m->b_wptr += off; 1607e07d9cb8Szf162725 1608e07d9cb8Szf162725 wh = (struct ieee80211_frame *)m->b_rptr; 1609e07d9cb8Szf162725 ni = ieee80211_find_txnode(ic, wh->i_addr1); 1610e07d9cb8Szf162725 1611e07d9cb8Szf162725 if (ni == NULL) { 1612e07d9cb8Szf162725 err = DDI_FAILURE; 1613e07d9cb8Szf162725 sc->sc_tx_err++; 1614e07d9cb8Szf162725 goto fail2; 1615e07d9cb8Szf162725 } 1616e07d9cb8Szf162725 1617e07d9cb8Szf162725 (void) ieee80211_encap(ic, m, ni); 1618e07d9cb8Szf162725 1619e07d9cb8Szf162725 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1620e07d9cb8Szf162725 k = ieee80211_crypto_encap(ic, m); 1621e07d9cb8Szf162725 if (k == NULL) { 1622e07d9cb8Szf162725 sc->sc_tx_err++; 1623e07d9cb8Szf162725 err = DDI_FAILURE; 1624e07d9cb8Szf162725 goto fail3; 1625e07d9cb8Szf162725 } 1626e07d9cb8Szf162725 /* packet header may have moved, reset our local pointer */ 1627e07d9cb8Szf162725 wh = (struct ieee80211_frame *)m->b_rptr; 1628e07d9cb8Szf162725 } 1629e07d9cb8Szf162725 1630e07d9cb8Szf162725 /* 1631e07d9cb8Szf162725 * RTS/CTS exchange ignore, since the max packet will less than 1632e07d9cb8Szf162725 * the rtsthreshold (2346) 1633e07d9cb8Szf162725 * Unnecessary codes deleted. 1634e07d9cb8Szf162725 */ 1635e07d9cb8Szf162725 1636e07d9cb8Szf162725 data = &sc->txq.data[sc->txq.cur]; 1637e07d9cb8Szf162725 desc = &sc->txq.desc[sc->txq.cur]; 1638e07d9cb8Szf162725 1639e07d9cb8Szf162725 data->ni = ieee80211_ref_node(ni); 1640e07d9cb8Szf162725 1641e07d9cb8Szf162725 pktlen = msgdsize(m); 1642e07d9cb8Szf162725 dest = data->buf; 1643e07d9cb8Szf162725 bcopy(m->b_rptr, dest, pktlen); 1644e07d9cb8Szf162725 1645e07d9cb8Szf162725 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { 1646e07d9cb8Szf162725 rs = &ic->ic_sup_rates[ic->ic_curmode]; 1647e07d9cb8Szf162725 rate = rs->ir_rates[ic->ic_fixed_rate]; 1648e07d9cb8Szf162725 } else { 1649e07d9cb8Szf162725 rs = &ni->in_rates; 1650e07d9cb8Szf162725 rn = (struct rt2560_node *)ni; 1651e07d9cb8Szf162725 ni->in_txrate = ral_rssadapt_choose(&rn->rssadapt, rs, wh, 1652e07d9cb8Szf162725 pktlen, NULL, 0); 1653e07d9cb8Szf162725 rate = rs->ir_rates[ni->in_txrate]; 1654e07d9cb8Szf162725 } 1655e07d9cb8Szf162725 1656e07d9cb8Szf162725 rate &= IEEE80211_RATE_VAL; 1657e07d9cb8Szf162725 if (rate <= 0) { 1658e07d9cb8Szf162725 rate = 2; /* basic rate */ 1659e07d9cb8Szf162725 } 1660e07d9cb8Szf162725 1661e07d9cb8Szf162725 /* remember link conditions for rate adaptation algorithm */ 1662e07d9cb8Szf162725 if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 1663e07d9cb8Szf162725 data->id.id_len = pktlen; 1664e07d9cb8Szf162725 data->id.id_rateidx = ni->in_txrate; 1665e07d9cb8Szf162725 data->id.id_node = ni; 1666e07d9cb8Szf162725 data->id.id_rssi = ni->in_rssi; 1667e07d9cb8Szf162725 } else 1668e07d9cb8Szf162725 data->id.id_node = NULL; 1669e07d9cb8Szf162725 1670e07d9cb8Szf162725 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1671e07d9cb8Szf162725 flags |= RT2560_TX_ACK; 1672e07d9cb8Szf162725 1673e07d9cb8Szf162725 dur = rt2560_txtime(RAL_ACK_SIZE, rt2560_ack_rate(ic, rate), 1674e07d9cb8Szf162725 ic->ic_flags) + RAL_SIFS; 1675e07d9cb8Szf162725 *(uint16_t *)wh->i_dur = LE_16(dur); 1676e07d9cb8Szf162725 } 1677e07d9cb8Szf162725 1678e07d9cb8Szf162725 /* flags |= RT2560_TX_CIPHER_NONE; */ 1679e07d9cb8Szf162725 rt2560_setup_tx_desc(sc, desc, flags, pktlen, rate, 0); 1680e07d9cb8Szf162725 1681e07d9cb8Szf162725 idx = sc->txq.cur; 1682e07d9cb8Szf162725 1683e07d9cb8Szf162725 dr = &sc->txq.dr_txbuf[idx]; 1684e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, 0, RAL_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV); 1685e07d9cb8Szf162725 1686e07d9cb8Szf162725 dr = &sc->txq.dr_desc; 1687e07d9cb8Szf162725 (void) ddi_dma_sync(dr->dr_hnd, idx * RT2560_TX_DESC_SIZE, 1688e07d9cb8Szf162725 RT2560_TX_DESC_SIZE, DDI_DMA_SYNC_FORDEV); 1689e07d9cb8Szf162725 1690e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_TX, "sending data frame len=%u idx=%u rate=%u\n", 1691e07d9cb8Szf162725 pktlen, sc->txq.cur, rate); 1692e07d9cb8Szf162725 1693e07d9cb8Szf162725 /* kick tx */ 1694e07d9cb8Szf162725 sc->txq.queued++; 1695e07d9cb8Szf162725 sc->txq.cur = (sc->txq.cur + 1) % RT2560_TX_RING_COUNT; 1696e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX); 1697e07d9cb8Szf162725 1698e07d9cb8Szf162725 sc->sc_tx_timer = 5; 1699e07d9cb8Szf162725 1700fb91fd8aSzf162725 ic->ic_stats.is_tx_frags++; 1701fb91fd8aSzf162725 ic->ic_stats.is_tx_bytes += pktlen; 1702fb91fd8aSzf162725 1703e07d9cb8Szf162725 freemsg(mp); 1704e07d9cb8Szf162725 fail3: 1705e07d9cb8Szf162725 ieee80211_free_node(ni); 1706e07d9cb8Szf162725 fail2: 1707e07d9cb8Szf162725 freemsg(m); 1708e07d9cb8Szf162725 fail1: 1709e07d9cb8Szf162725 mutex_exit(&sc->txq.tx_lock); 1710e07d9cb8Szf162725 return (err); 1711e07d9cb8Szf162725 } 1712e07d9cb8Szf162725 1713e07d9cb8Szf162725 static mblk_t * 1714e07d9cb8Szf162725 rt2560_m_tx(void *arg, mblk_t *mp) 1715e07d9cb8Szf162725 { 1716e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 1717e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 1718e07d9cb8Szf162725 mblk_t *next; 1719e07d9cb8Szf162725 1720e07d9cb8Szf162725 /* 1721e07d9cb8Szf162725 * No data frames go out unless we're associated; this 1722e07d9cb8Szf162725 * should not happen as the 802.11 layer does not enable 1723e07d9cb8Szf162725 * the xmit queue until we enter the RUN state. 1724e07d9cb8Szf162725 */ 1725e07d9cb8Szf162725 if (ic->ic_state != IEEE80211_S_RUN) { 1726e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_TX, "ral: rt2560_tx_data(): " 1727e07d9cb8Szf162725 "discard, state %u\n", ic->ic_state); 1728e07d9cb8Szf162725 freemsgchain(mp); 1729e07d9cb8Szf162725 return (NULL); 1730e07d9cb8Szf162725 } 1731e07d9cb8Szf162725 1732e07d9cb8Szf162725 while (mp != NULL) { 1733e07d9cb8Szf162725 next = mp->b_next; 1734e07d9cb8Szf162725 mp->b_next = NULL; 1735e07d9cb8Szf162725 if (rt2560_send(ic, mp) != DDI_SUCCESS) { 1736e07d9cb8Szf162725 mp->b_next = next; 1737e07d9cb8Szf162725 freemsgchain(mp); 1738e07d9cb8Szf162725 return (NULL); 1739e07d9cb8Szf162725 } 1740e07d9cb8Szf162725 mp = next; 1741e07d9cb8Szf162725 } 1742e07d9cb8Szf162725 return (mp); 1743e07d9cb8Szf162725 } 1744e07d9cb8Szf162725 1745e07d9cb8Szf162725 static void 1746e07d9cb8Szf162725 rt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr) 1747e07d9cb8Szf162725 { 1748e07d9cb8Szf162725 uint32_t tmp; 1749e07d9cb8Szf162725 1750e07d9cb8Szf162725 tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 1751e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR3, tmp); 1752e07d9cb8Szf162725 1753e07d9cb8Szf162725 tmp = addr[4] | addr[5] << 8; 1754e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR4, tmp); 1755e07d9cb8Szf162725 1756e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, 1757e07d9cb8Szf162725 "setting MAC address to " MACSTR "\n", MAC2STR(addr)); 1758e07d9cb8Szf162725 } 1759e07d9cb8Szf162725 1760e07d9cb8Szf162725 static void 1761e07d9cb8Szf162725 rt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr) 1762e07d9cb8Szf162725 { 1763e07d9cb8Szf162725 uint32_t tmp; 1764e07d9cb8Szf162725 1765e07d9cb8Szf162725 tmp = RAL_READ(sc, RT2560_CSR3); 1766e07d9cb8Szf162725 addr[0] = tmp & 0xff; 1767e07d9cb8Szf162725 addr[1] = (tmp >> 8) & 0xff; 1768e07d9cb8Szf162725 addr[2] = (tmp >> 16) & 0xff; 1769e07d9cb8Szf162725 addr[3] = (tmp >> 24); 1770e07d9cb8Szf162725 1771e07d9cb8Szf162725 tmp = RAL_READ(sc, RT2560_CSR4); 1772e07d9cb8Szf162725 addr[4] = tmp & 0xff; 1773e07d9cb8Szf162725 addr[5] = (tmp >> 8) & 0xff; 1774e07d9cb8Szf162725 } 1775e07d9cb8Szf162725 1776e07d9cb8Szf162725 static void 1777e07d9cb8Szf162725 rt2560_update_promisc(struct rt2560_softc *sc) 1778e07d9cb8Szf162725 { 1779e07d9cb8Szf162725 uint32_t tmp; 1780e07d9cb8Szf162725 1781e07d9cb8Szf162725 tmp = RAL_READ(sc, RT2560_RXCSR0); 1782e07d9cb8Szf162725 tmp &= ~RT2560_DROP_NOT_TO_ME; 1783e07d9cb8Szf162725 if (!(sc->sc_rcr & RAL_RCR_PROMISC)) 1784e07d9cb8Szf162725 tmp |= RT2560_DROP_NOT_TO_ME; 1785e07d9cb8Szf162725 1786e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RXCSR0, tmp); 1787e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "%s promiscuous mode\n", 1788e07d9cb8Szf162725 (sc->sc_rcr & RAL_RCR_PROMISC) ? "entering" : "leaving"); 1789e07d9cb8Szf162725 } 1790e07d9cb8Szf162725 1791e07d9cb8Szf162725 static const char * 1792e07d9cb8Szf162725 rt2560_get_rf(int rev) 1793e07d9cb8Szf162725 { 1794e07d9cb8Szf162725 switch (rev) { 1795e07d9cb8Szf162725 case RT2560_RF_2522: return ("RT2522"); 1796e07d9cb8Szf162725 case RT2560_RF_2523: return ("RT2523"); 1797e07d9cb8Szf162725 case RT2560_RF_2524: return ("RT2524"); 1798e07d9cb8Szf162725 case RT2560_RF_2525: return ("RT2525"); 1799e07d9cb8Szf162725 case RT2560_RF_2525E: return ("RT2525e"); 1800e07d9cb8Szf162725 case RT2560_RF_2526: return ("RT2526"); 1801e07d9cb8Szf162725 case RT2560_RF_5222: return ("RT5222"); 1802e07d9cb8Szf162725 default: return ("unknown"); 1803e07d9cb8Szf162725 } 1804e07d9cb8Szf162725 } 1805e07d9cb8Szf162725 1806e07d9cb8Szf162725 static void 1807e07d9cb8Szf162725 rt2560_read_eeprom(struct rt2560_softc *sc) 1808e07d9cb8Szf162725 { 1809e07d9cb8Szf162725 uint16_t val; 1810e07d9cb8Szf162725 int i; 1811e07d9cb8Szf162725 1812e07d9cb8Szf162725 val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0); 1813e07d9cb8Szf162725 sc->rf_rev = (val >> 11) & 0x7; 1814e07d9cb8Szf162725 sc->hw_radio = (val >> 10) & 0x1; 1815e07d9cb8Szf162725 sc->led_mode = (val >> 6) & 0x7; 1816e07d9cb8Szf162725 sc->rx_ant = (val >> 4) & 0x3; 1817e07d9cb8Szf162725 sc->tx_ant = (val >> 2) & 0x3; 1818e07d9cb8Szf162725 sc->nb_ant = val & 0x3; 1819e07d9cb8Szf162725 1820e07d9cb8Szf162725 /* read default values for BBP registers */ 1821e07d9cb8Szf162725 for (i = 0; i < 16; i++) { 1822e07d9cb8Szf162725 val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i); 1823e07d9cb8Szf162725 sc->bbp_prom[i].reg = val >> 8; 1824e07d9cb8Szf162725 sc->bbp_prom[i].val = val & 0xff; 1825e07d9cb8Szf162725 } 1826e07d9cb8Szf162725 1827e07d9cb8Szf162725 /* read Tx power for all b/g channels */ 1828e07d9cb8Szf162725 for (i = 0; i < 14 / 2; i++) { 1829e07d9cb8Szf162725 val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i); 1830e07d9cb8Szf162725 sc->txpow[i * 2] = val >> 8; 1831e07d9cb8Szf162725 sc->txpow[i * 2 + 1] = val & 0xff; 1832e07d9cb8Szf162725 } 1833e07d9cb8Szf162725 } 1834e07d9cb8Szf162725 1835e07d9cb8Szf162725 static int 1836e07d9cb8Szf162725 rt2560_bbp_init(struct rt2560_softc *sc) 1837e07d9cb8Szf162725 { 1838e07d9cb8Szf162725 #define N(a) (sizeof (a) / sizeof ((a)[0])) 1839e07d9cb8Szf162725 int i, ntries; 1840e07d9cb8Szf162725 1841e07d9cb8Szf162725 /* wait for BBP to be ready */ 1842e07d9cb8Szf162725 for (ntries = 0; ntries < 100; ntries++) { 1843e07d9cb8Szf162725 if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0) 1844e07d9cb8Szf162725 break; 1845e07d9cb8Szf162725 drv_usecwait(1); 1846e07d9cb8Szf162725 } 1847e07d9cb8Szf162725 if (ntries == 100) { 1848e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_HW, "timeout waiting for BBP\n"); 1849e07d9cb8Szf162725 return (EIO); 1850e07d9cb8Szf162725 } 1851e07d9cb8Szf162725 /* initialize BBP registers to default values */ 1852e07d9cb8Szf162725 for (i = 0; i < N(rt2560_def_bbp); i++) { 1853e07d9cb8Szf162725 rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, 1854e07d9cb8Szf162725 rt2560_def_bbp[i].val); 1855e07d9cb8Szf162725 } 1856e07d9cb8Szf162725 1857e07d9cb8Szf162725 return (0); 1858e07d9cb8Szf162725 #undef N 1859e07d9cb8Szf162725 } 1860e07d9cb8Szf162725 1861e07d9cb8Szf162725 static void 1862e07d9cb8Szf162725 rt2560_set_txantenna(struct rt2560_softc *sc, int antenna) 1863e07d9cb8Szf162725 { 1864e07d9cb8Szf162725 uint32_t tmp; 1865e07d9cb8Szf162725 uint8_t tx; 1866e07d9cb8Szf162725 1867e07d9cb8Szf162725 tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK; 1868e07d9cb8Szf162725 if (antenna == 1) 1869e07d9cb8Szf162725 tx |= RT2560_BBP_ANTA; 1870e07d9cb8Szf162725 else if (antenna == 2) 1871e07d9cb8Szf162725 tx |= RT2560_BBP_ANTB; 1872e07d9cb8Szf162725 else 1873e07d9cb8Szf162725 tx |= RT2560_BBP_DIVERSITY; 1874e07d9cb8Szf162725 1875e07d9cb8Szf162725 /* need to force I/Q flip for RF 2525e, 2526 and 5222 */ 1876e07d9cb8Szf162725 if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 || 1877e07d9cb8Szf162725 sc->rf_rev == RT2560_RF_5222) 1878e07d9cb8Szf162725 tx |= RT2560_BBP_FLIPIQ; 1879e07d9cb8Szf162725 1880e07d9cb8Szf162725 rt2560_bbp_write(sc, RT2560_BBP_TX, tx); 1881e07d9cb8Szf162725 1882e07d9cb8Szf162725 /* update values for CCK and OFDM in BBPCSR1 */ 1883e07d9cb8Szf162725 tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007; 1884e07d9cb8Szf162725 tmp |= (tx & 0x7) << 16 | (tx & 0x7); 1885e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_BBPCSR1, tmp); 1886e07d9cb8Szf162725 } 1887e07d9cb8Szf162725 1888e07d9cb8Szf162725 static void 1889e07d9cb8Szf162725 rt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) 1890e07d9cb8Szf162725 { 1891e07d9cb8Szf162725 uint8_t rx; 1892e07d9cb8Szf162725 1893e07d9cb8Szf162725 rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK; 1894e07d9cb8Szf162725 if (antenna == 1) 1895e07d9cb8Szf162725 rx |= RT2560_BBP_ANTA; 1896e07d9cb8Szf162725 else if (antenna == 2) 1897e07d9cb8Szf162725 rx |= RT2560_BBP_ANTB; 1898e07d9cb8Szf162725 else 1899e07d9cb8Szf162725 rx |= RT2560_BBP_DIVERSITY; 1900e07d9cb8Szf162725 1901e07d9cb8Szf162725 /* need to force no I/Q flip for RF 2525e and 2526 */ 1902e07d9cb8Szf162725 if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526) 1903e07d9cb8Szf162725 rx &= ~RT2560_BBP_FLIPIQ; 1904e07d9cb8Szf162725 1905e07d9cb8Szf162725 rt2560_bbp_write(sc, RT2560_BBP_RX, rx); 1906e07d9cb8Szf162725 } 1907e07d9cb8Szf162725 1908e07d9cb8Szf162725 static void 1909e07d9cb8Szf162725 rt2560_stop(struct rt2560_softc *sc) 1910e07d9cb8Szf162725 { 1911e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 1912e07d9cb8Szf162725 1913e07d9cb8Szf162725 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 1914e07d9cb8Szf162725 ieee80211_stop_watchdog(ic); /* stop the watchdog */ 1915e07d9cb8Szf162725 1916e07d9cb8Szf162725 RAL_LOCK(sc); 1917e07d9cb8Szf162725 sc->sc_tx_timer = 0; 1918e07d9cb8Szf162725 1919e07d9cb8Szf162725 /* abort Tx */ 1920e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 1921e07d9cb8Szf162725 1922e07d9cb8Szf162725 /* disable Rx */ 1923e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 1924e07d9cb8Szf162725 1925e07d9cb8Szf162725 /* reset ASIC (imply reset BBP) */ 1926e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 1927e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR1, 0); 1928e07d9cb8Szf162725 1929e07d9cb8Szf162725 /* disable interrupts */ 1930e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 1931e07d9cb8Szf162725 1932e07d9cb8Szf162725 /* reset Tx and Rx rings */ 1933e07d9cb8Szf162725 rt2560_reset_tx_ring(sc, &sc->txq); 1934e07d9cb8Szf162725 rt2560_reset_tx_ring(sc, &sc->prioq); 1935e07d9cb8Szf162725 rt2560_reset_rx_ring(sc, &sc->rxq); 1936e07d9cb8Szf162725 RAL_UNLOCK(sc); 1937e07d9cb8Szf162725 } 1938e07d9cb8Szf162725 1939e07d9cb8Szf162725 static int 1940e07d9cb8Szf162725 rt2560_init(struct rt2560_softc *sc) 1941e07d9cb8Szf162725 { 1942e07d9cb8Szf162725 #define N(a) (sizeof (a) / sizeof ((a)[0])) 1943e07d9cb8Szf162725 /* struct rt2560_softc *sc = priv; */ 1944e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 1945e07d9cb8Szf162725 uint32_t tmp; 1946e07d9cb8Szf162725 int i; 1947e07d9cb8Szf162725 1948e07d9cb8Szf162725 rt2560_stop(sc); 1949e07d9cb8Szf162725 1950e07d9cb8Szf162725 RAL_LOCK(sc); 1951e07d9cb8Szf162725 /* setup tx/rx ring */ 1952e07d9cb8Szf162725 rt2560_ring_hwsetup(sc); 1953e07d9cb8Szf162725 1954e07d9cb8Szf162725 /* initialize MAC registers to default values */ 1955e07d9cb8Szf162725 for (i = 0; i < N(rt2560_def_mac); i++) 1956e07d9cb8Szf162725 RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); 1957e07d9cb8Szf162725 1958e07d9cb8Szf162725 rt2560_set_macaddr(sc, ic->ic_macaddr); 1959e07d9cb8Szf162725 1960e07d9cb8Szf162725 /* set basic rate set (will be updated later) */ 1961e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153); 1962e07d9cb8Szf162725 1963e07d9cb8Szf162725 rt2560_set_txantenna(sc, sc->tx_ant); 1964e07d9cb8Szf162725 rt2560_set_rxantenna(sc, sc->rx_ant); 1965e07d9cb8Szf162725 rt2560_update_slot(ic, 1); 1966e07d9cb8Szf162725 rt2560_update_plcp(sc); 1967e07d9cb8Szf162725 rt2560_update_led(sc, 0, 0); 1968e07d9cb8Szf162725 1969e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 1970e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); 1971e07d9cb8Szf162725 1972e07d9cb8Szf162725 if (rt2560_bbp_init(sc) != 0) { 1973e07d9cb8Szf162725 RAL_UNLOCK(sc); 1974e07d9cb8Szf162725 rt2560_stop(sc); 1975e07d9cb8Szf162725 return (DDI_FAILURE); 1976e07d9cb8Szf162725 } 1977e07d9cb8Szf162725 1978e07d9cb8Szf162725 /* set default BSS channel */ 1979e07d9cb8Szf162725 rt2560_set_chan(sc, ic->ic_curchan); 1980e07d9cb8Szf162725 1981e07d9cb8Szf162725 /* kick Rx */ 1982e07d9cb8Szf162725 tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR; 1983e07d9cb8Szf162725 if (ic->ic_opmode != IEEE80211_M_MONITOR) { 1984e07d9cb8Szf162725 tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR; 1985e07d9cb8Szf162725 if (ic->ic_opmode != IEEE80211_M_HOSTAP) 1986e07d9cb8Szf162725 tmp |= RT2560_DROP_TODS; 1987e07d9cb8Szf162725 if (!(sc->sc_rcr & RAL_RCR_PROMISC)) 1988e07d9cb8Szf162725 tmp |= RT2560_DROP_NOT_TO_ME; 1989e07d9cb8Szf162725 1990e07d9cb8Szf162725 } 1991e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RXCSR0, tmp); 1992e07d9cb8Szf162725 1993e07d9cb8Szf162725 /* clear old FCS and Rx FIFO errors */ 1994e07d9cb8Szf162725 (void) RAL_READ(sc, RT2560_CNT0); 1995e07d9cb8Szf162725 (void) RAL_READ(sc, RT2560_CNT4); 1996e07d9cb8Szf162725 1997e07d9cb8Szf162725 /* clear any pending interrupts */ 1998e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR7, 0xffffffff); 1999e07d9cb8Szf162725 /* enable interrupts */ 2000e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2001e07d9cb8Szf162725 2002e07d9cb8Szf162725 RAL_UNLOCK(sc); 2003e07d9cb8Szf162725 #undef N 2004e07d9cb8Szf162725 return (DDI_SUCCESS); 2005e07d9cb8Szf162725 } 2006e07d9cb8Szf162725 2007e07d9cb8Szf162725 void 2008e07d9cb8Szf162725 rt2560_watchdog(void *arg) 2009e07d9cb8Szf162725 { 2010e07d9cb8Szf162725 struct rt2560_softc *sc = arg; 2011e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 2012e07d9cb8Szf162725 int ntimer = 0; 2013e07d9cb8Szf162725 2014e07d9cb8Szf162725 RAL_LOCK(sc); 2015e07d9cb8Szf162725 ic->ic_watchdog_timer = 0; 2016e07d9cb8Szf162725 2017e07d9cb8Szf162725 if (!RAL_IS_RUNNING(sc)) { 2018e07d9cb8Szf162725 RAL_UNLOCK(sc); 2019e07d9cb8Szf162725 return; 2020e07d9cb8Szf162725 } 2021e07d9cb8Szf162725 2022e07d9cb8Szf162725 if (sc->sc_tx_timer > 0) { 2023e07d9cb8Szf162725 if (--sc->sc_tx_timer == 0) { 2024e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_MSG, "tx timer timeout\n"); 2025e07d9cb8Szf162725 RAL_UNLOCK(sc); 2026e07d9cb8Szf162725 (void) rt2560_init(sc); 2027e07d9cb8Szf162725 (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2028e07d9cb8Szf162725 return; 2029e07d9cb8Szf162725 } 2030e07d9cb8Szf162725 } 2031e07d9cb8Szf162725 2032e07d9cb8Szf162725 if (ic->ic_state == IEEE80211_S_RUN) 2033e07d9cb8Szf162725 ntimer = 1; 2034e07d9cb8Szf162725 2035e07d9cb8Szf162725 RAL_UNLOCK(sc); 2036e07d9cb8Szf162725 2037e07d9cb8Szf162725 ieee80211_watchdog(ic); 2038e07d9cb8Szf162725 2039e07d9cb8Szf162725 if (ntimer) 2040e07d9cb8Szf162725 ieee80211_start_watchdog(ic, ntimer); 2041e07d9cb8Szf162725 } 2042e07d9cb8Szf162725 2043e07d9cb8Szf162725 static int 2044e07d9cb8Szf162725 rt2560_m_start(void *arg) 2045e07d9cb8Szf162725 { 2046e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2047e07d9cb8Szf162725 crypto_mech_type_t type; 2048e07d9cb8Szf162725 int err; 2049e07d9cb8Szf162725 2050e07d9cb8Szf162725 2051e07d9cb8Szf162725 type = crypto_mech2id(SUN_CKM_RC4); /* load rc4 module into kernel */ 2052e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "enter rt2560_m_start(%d)\n", type); 2053e07d9cb8Szf162725 2054e07d9cb8Szf162725 /* 2055e07d9cb8Szf162725 * initialize rt2560 hardware 2056e07d9cb8Szf162725 */ 2057e07d9cb8Szf162725 err = rt2560_init(sc); 2058e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2059e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "device configuration failed\n"); 2060e07d9cb8Szf162725 goto fail; 2061e07d9cb8Szf162725 } 2062e07d9cb8Szf162725 sc->sc_flags |= RAL_FLAG_RUNNING; /* RUNNING */ 2063e07d9cb8Szf162725 return (err); 2064e07d9cb8Szf162725 2065e07d9cb8Szf162725 fail: 2066e07d9cb8Szf162725 rt2560_stop(sc); 2067e07d9cb8Szf162725 return (err); 2068e07d9cb8Szf162725 } 2069e07d9cb8Szf162725 2070e07d9cb8Szf162725 static void 2071e07d9cb8Szf162725 rt2560_m_stop(void *arg) 2072e07d9cb8Szf162725 { 2073e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2074e07d9cb8Szf162725 2075e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "enter rt2560_m_stop()\n"); 2076e07d9cb8Szf162725 2077e07d9cb8Szf162725 (void) rt2560_stop(sc); 2078e07d9cb8Szf162725 sc->sc_flags &= ~RAL_FLAG_RUNNING; /* STOP */ 2079e07d9cb8Szf162725 } 2080e07d9cb8Szf162725 2081e07d9cb8Szf162725 static int 2082e07d9cb8Szf162725 rt2560_m_unicst(void *arg, const uint8_t *macaddr) 2083e07d9cb8Szf162725 { 2084e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2085e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 2086e07d9cb8Szf162725 2087e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "rt2560_m_unicst(): " MACSTR "\n", 2088e07d9cb8Szf162725 MAC2STR(macaddr)); 2089e07d9cb8Szf162725 2090e07d9cb8Szf162725 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 2091e07d9cb8Szf162725 (void) rt2560_set_macaddr(sc, (uint8_t *)macaddr); 2092e07d9cb8Szf162725 (void) rt2560_init(sc); 2093e07d9cb8Szf162725 2094e07d9cb8Szf162725 return (0); 2095e07d9cb8Szf162725 } 2096e07d9cb8Szf162725 2097e07d9cb8Szf162725 /*ARGSUSED*/ 2098e07d9cb8Szf162725 static int 2099e07d9cb8Szf162725 rt2560_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 2100e07d9cb8Szf162725 { 2101e07d9cb8Szf162725 return (0); 2102e07d9cb8Szf162725 } 2103e07d9cb8Szf162725 2104e07d9cb8Szf162725 static int 2105e07d9cb8Szf162725 rt2560_m_promisc(void *arg, boolean_t on) 2106e07d9cb8Szf162725 { 2107e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2108e07d9cb8Szf162725 2109e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "rt2560_m_promisc()\n"); 2110e07d9cb8Szf162725 2111e07d9cb8Szf162725 if (on) { 2112e07d9cb8Szf162725 sc->sc_rcr |= RAL_RCR_PROMISC; 2113e07d9cb8Szf162725 sc->sc_rcr |= RAL_RCR_MULTI; 2114e07d9cb8Szf162725 } else { 2115e07d9cb8Szf162725 sc->sc_rcr &= ~RAL_RCR_PROMISC; 2116e07d9cb8Szf162725 sc->sc_rcr &= ~RAL_RCR_PROMISC; 2117e07d9cb8Szf162725 } 2118e07d9cb8Szf162725 2119e07d9cb8Szf162725 rt2560_update_promisc(sc); 2120e07d9cb8Szf162725 return (0); 2121e07d9cb8Szf162725 } 2122e07d9cb8Szf162725 2123e07d9cb8Szf162725 static void 2124e07d9cb8Szf162725 rt2560_m_ioctl(void* arg, queue_t *wq, mblk_t *mp) 2125e07d9cb8Szf162725 { 2126e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2127e07d9cb8Szf162725 struct ieee80211com *ic = &sc->sc_ic; 2128e07d9cb8Szf162725 int err; 2129e07d9cb8Szf162725 2130e07d9cb8Szf162725 err = ieee80211_ioctl(ic, wq, mp); 2131e07d9cb8Szf162725 RAL_LOCK(sc); 2132e07d9cb8Szf162725 if (err == ENETRESET) { 2133e07d9cb8Szf162725 if (RAL_IS_RUNNING(sc)) { 2134e07d9cb8Szf162725 RAL_UNLOCK(sc); 2135e07d9cb8Szf162725 (void) rt2560_init(sc); 2136e07d9cb8Szf162725 (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2137e07d9cb8Szf162725 RAL_LOCK(sc); 2138e07d9cb8Szf162725 } 2139e07d9cb8Szf162725 } 2140e07d9cb8Szf162725 RAL_UNLOCK(sc); 2141e07d9cb8Szf162725 } 2142e07d9cb8Szf162725 2143e07d9cb8Szf162725 static int 2144e07d9cb8Szf162725 rt2560_m_stat(void *arg, uint_t stat, uint64_t *val) 2145e07d9cb8Szf162725 { 2146e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2147e07d9cb8Szf162725 ieee80211com_t *ic = &sc->sc_ic; 2148e07d9cb8Szf162725 ieee80211_node_t *ni = ic->ic_bss; 2149e07d9cb8Szf162725 struct ieee80211_rateset *rs = &ni->in_rates; 2150e07d9cb8Szf162725 2151e07d9cb8Szf162725 RAL_LOCK(sc); 2152e07d9cb8Szf162725 switch (stat) { 2153e07d9cb8Szf162725 case MAC_STAT_IFSPEED: 2154e07d9cb8Szf162725 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 2155e07d9cb8Szf162725 (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL) 2156*020c4770Sql147931 : ic->ic_fixed_rate) / 2 * 1000000; 2157e07d9cb8Szf162725 break; 2158e07d9cb8Szf162725 case MAC_STAT_NOXMTBUF: 2159e07d9cb8Szf162725 *val = sc->sc_tx_nobuf; 2160e07d9cb8Szf162725 break; 2161e07d9cb8Szf162725 case MAC_STAT_NORCVBUF: 2162e07d9cb8Szf162725 *val = sc->sc_rx_nobuf; 2163e07d9cb8Szf162725 break; 2164e07d9cb8Szf162725 case MAC_STAT_IERRORS: 2165e07d9cb8Szf162725 *val = sc->sc_rx_err; 2166e07d9cb8Szf162725 break; 2167e07d9cb8Szf162725 case MAC_STAT_RBYTES: 2168e07d9cb8Szf162725 *val = ic->ic_stats.is_rx_bytes; 2169e07d9cb8Szf162725 break; 2170e07d9cb8Szf162725 case MAC_STAT_IPACKETS: 2171e07d9cb8Szf162725 *val = ic->ic_stats.is_rx_frags; 2172e07d9cb8Szf162725 break; 2173e07d9cb8Szf162725 case MAC_STAT_OBYTES: 2174e07d9cb8Szf162725 *val = ic->ic_stats.is_tx_bytes; 2175e07d9cb8Szf162725 break; 2176e07d9cb8Szf162725 case MAC_STAT_OPACKETS: 2177e07d9cb8Szf162725 *val = ic->ic_stats.is_tx_frags; 2178e07d9cb8Szf162725 break; 2179e07d9cb8Szf162725 case MAC_STAT_OERRORS: 2180e07d9cb8Szf162725 case WIFI_STAT_TX_FAILED: 2181e07d9cb8Szf162725 *val = sc->sc_tx_err; 2182e07d9cb8Szf162725 break; 2183e07d9cb8Szf162725 case WIFI_STAT_TX_RETRANS: 2184e07d9cb8Szf162725 *val = sc->sc_tx_retries; 2185e07d9cb8Szf162725 break; 2186e07d9cb8Szf162725 case WIFI_STAT_FCS_ERRORS: 2187e07d9cb8Szf162725 case WIFI_STAT_WEP_ERRORS: 2188e07d9cb8Szf162725 case WIFI_STAT_TX_FRAGS: 2189e07d9cb8Szf162725 case WIFI_STAT_MCAST_TX: 2190e07d9cb8Szf162725 case WIFI_STAT_RTS_SUCCESS: 2191e07d9cb8Szf162725 case WIFI_STAT_RTS_FAILURE: 2192e07d9cb8Szf162725 case WIFI_STAT_ACK_FAILURE: 2193e07d9cb8Szf162725 case WIFI_STAT_RX_FRAGS: 2194e07d9cb8Szf162725 case WIFI_STAT_MCAST_RX: 2195e07d9cb8Szf162725 case WIFI_STAT_RX_DUPS: 2196e07d9cb8Szf162725 RAL_UNLOCK(sc); 2197e07d9cb8Szf162725 return (ieee80211_stat(ic, stat, val)); 2198e07d9cb8Szf162725 default: 2199e07d9cb8Szf162725 RAL_UNLOCK(sc); 2200e07d9cb8Szf162725 return (ENOTSUP); 2201e07d9cb8Szf162725 } 2202e07d9cb8Szf162725 RAL_UNLOCK(sc); 2203e07d9cb8Szf162725 2204e07d9cb8Szf162725 return (0); 2205e07d9cb8Szf162725 } 2206e07d9cb8Szf162725 2207e07d9cb8Szf162725 static uint_t 2208e07d9cb8Szf162725 rt2560_intr(caddr_t arg) 2209e07d9cb8Szf162725 { 2210e07d9cb8Szf162725 struct rt2560_softc *sc = (struct rt2560_softc *)arg; 2211e07d9cb8Szf162725 uint32_t r; 2212e07d9cb8Szf162725 2213e07d9cb8Szf162725 RAL_LOCK(sc); 2214e07d9cb8Szf162725 2215e07d9cb8Szf162725 r = RAL_READ(sc, RT2560_CSR7); 2216e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR7, r); 2217e07d9cb8Szf162725 2218e07d9cb8Szf162725 if (r == 0xffffffff) { 2219e07d9cb8Szf162725 RAL_UNLOCK(sc); 2220e07d9cb8Szf162725 return (DDI_INTR_UNCLAIMED); 2221e07d9cb8Szf162725 } 2222e07d9cb8Szf162725 2223e07d9cb8Szf162725 if (!(r & RT2560_INTR_ALL)) { 2224e07d9cb8Szf162725 RAL_UNLOCK(sc); 2225e07d9cb8Szf162725 return (DDI_INTR_UNCLAIMED); 2226e07d9cb8Szf162725 } 2227e07d9cb8Szf162725 2228e07d9cb8Szf162725 /* disable interrupts */ 2229e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2230e07d9cb8Szf162725 2231e07d9cb8Szf162725 if (r & RT2560_TX_DONE) { 2232e07d9cb8Szf162725 RAL_UNLOCK(sc); 2233e07d9cb8Szf162725 rt2560_tx_intr(sc); 2234e07d9cb8Szf162725 RAL_LOCK(sc); 2235e07d9cb8Szf162725 } 2236e07d9cb8Szf162725 2237e07d9cb8Szf162725 if (r & RT2560_PRIO_DONE) { 2238e07d9cb8Szf162725 RAL_UNLOCK(sc); 2239e07d9cb8Szf162725 rt2560_prio_intr(sc); 2240e07d9cb8Szf162725 RAL_LOCK(sc); 2241e07d9cb8Szf162725 } 2242e07d9cb8Szf162725 2243e07d9cb8Szf162725 if (r & RT2560_RX_DONE) { 2244e07d9cb8Szf162725 sc->sc_rx_pend = 1; 2245e07d9cb8Szf162725 ddi_trigger_softintr(sc->sc_softint_id); 2246e07d9cb8Szf162725 } 2247e07d9cb8Szf162725 2248e07d9cb8Szf162725 /* re-enable interrupts */ 2249e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK); 2250e07d9cb8Szf162725 RAL_UNLOCK(sc); 2251e07d9cb8Szf162725 2252e07d9cb8Szf162725 return (DDI_INTR_CLAIMED); 2253e07d9cb8Szf162725 } 2254e07d9cb8Szf162725 2255e07d9cb8Szf162725 static int 2256e07d9cb8Szf162725 rt2560_reset(dev_info_t *devinfo, ddi_reset_cmd_t cmd) 2257e07d9cb8Szf162725 { 2258e07d9cb8Szf162725 struct rt2560_softc *sc; 2259e07d9cb8Szf162725 2260e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "rt2560_reset(0x%p)\n", (void *)devinfo); 2261e07d9cb8Szf162725 2262e07d9cb8Szf162725 if (cmd != DDI_RESET_FORCE) 2263e07d9cb8Szf162725 return (DDI_FAILURE); 2264e07d9cb8Szf162725 2265e07d9cb8Szf162725 sc = ddi_get_soft_state(ral_soft_state_p, ddi_get_instance(devinfo)); 2266e07d9cb8Szf162725 2267e07d9cb8Szf162725 /* abort Tx */ 2268e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX); 2269e07d9cb8Szf162725 2270e07d9cb8Szf162725 /* disable Rx */ 2271e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX); 2272e07d9cb8Szf162725 2273e07d9cb8Szf162725 /* reset ASIC (imply reset BBP) */ 2274e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC); 2275e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR1, 0); 2276e07d9cb8Szf162725 2277e07d9cb8Szf162725 /* disable interrupts */ 2278e07d9cb8Szf162725 RAL_WRITE(sc, RT2560_CSR8, 0xffffffff); 2279e07d9cb8Szf162725 2280e07d9cb8Szf162725 return (DDI_SUCCESS); 2281e07d9cb8Szf162725 } 2282e07d9cb8Szf162725 2283e07d9cb8Szf162725 static int 2284e07d9cb8Szf162725 rt2560_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 2285e07d9cb8Szf162725 { 2286e07d9cb8Szf162725 struct rt2560_softc *sc; 2287e07d9cb8Szf162725 struct ieee80211com *ic; 2288e07d9cb8Szf162725 int err, i; 2289e07d9cb8Szf162725 int instance; 2290e07d9cb8Szf162725 2291e07d9cb8Szf162725 ddi_acc_handle_t ioh; 2292e07d9cb8Szf162725 caddr_t regs; 2293e07d9cb8Szf162725 uint16_t vendor_id, device_id, command; 2294e07d9cb8Szf162725 uint8_t cachelsz; 2295e07d9cb8Szf162725 char strbuf[32]; 2296e07d9cb8Szf162725 2297e07d9cb8Szf162725 wifi_data_t wd = { 0 }; 2298e07d9cb8Szf162725 mac_register_t *macp; 2299e07d9cb8Szf162725 2300e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "enter rt2560_attach()\n"); 2301e07d9cb8Szf162725 2302e07d9cb8Szf162725 if (cmd != DDI_ATTACH) 2303e07d9cb8Szf162725 return (DDI_FAILURE); 2304e07d9cb8Szf162725 2305e07d9cb8Szf162725 instance = ddi_get_instance(devinfo); 2306e07d9cb8Szf162725 2307e07d9cb8Szf162725 if (ddi_soft_state_zalloc(ral_soft_state_p, instance) != DDI_SUCCESS) { 2308e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2309e07d9cb8Szf162725 "unable to alloc soft_state_p\n"); 2310e07d9cb8Szf162725 return (DDI_FAILURE); 2311e07d9cb8Szf162725 } 2312e07d9cb8Szf162725 2313e07d9cb8Szf162725 sc = ddi_get_soft_state(ral_soft_state_p, instance); 2314e07d9cb8Szf162725 ic = (ieee80211com_t *)&sc->sc_ic; 2315e07d9cb8Szf162725 sc->sc_dev = devinfo; 2316e07d9cb8Szf162725 2317e07d9cb8Szf162725 /* pci configuration */ 2318e07d9cb8Szf162725 err = ddi_regs_map_setup(devinfo, 0, ®s, 0, 0, &ral_csr_accattr, 2319e07d9cb8Szf162725 &ioh); 2320e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2321e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2322e07d9cb8Szf162725 "ddi_regs_map_setup() failed"); 2323e07d9cb8Szf162725 goto fail1; 2324e07d9cb8Szf162725 } 2325e07d9cb8Szf162725 2326e07d9cb8Szf162725 cachelsz = ddi_get8(ioh, (uint8_t *)(regs + PCI_CONF_CACHE_LINESZ)); 2327e07d9cb8Szf162725 if (cachelsz == 0) 2328e07d9cb8Szf162725 cachelsz = 0x10; 2329e07d9cb8Szf162725 sc->sc_cachelsz = cachelsz << 2; 2330e07d9cb8Szf162725 2331e07d9cb8Szf162725 vendor_id = ddi_get16(ioh, (uint16_t *)(regs + PCI_CONF_VENID)); 2332e07d9cb8Szf162725 device_id = ddi_get16(ioh, (uint16_t *)(regs + PCI_CONF_DEVID)); 2333e07d9cb8Szf162725 2334e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): vendor 0x%x, " 2335e07d9cb8Szf162725 "device id 0x%x, cache size %d\n", vendor_id, device_id, cachelsz); 2336e07d9cb8Szf162725 2337e07d9cb8Szf162725 /* 2338e07d9cb8Szf162725 * Enable response to memory space accesses, 2339e07d9cb8Szf162725 * and enabe bus master. 2340e07d9cb8Szf162725 */ 2341e07d9cb8Szf162725 command = PCI_COMM_MAE | PCI_COMM_ME; 2342e07d9cb8Szf162725 ddi_put16(ioh, (uint16_t *)(regs + PCI_CONF_COMM), command); 2343e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2344e07d9cb8Szf162725 "set command reg to 0x%x \n", command); 2345e07d9cb8Szf162725 2346e07d9cb8Szf162725 ddi_put8(ioh, (uint8_t *)(regs + PCI_CONF_LATENCY_TIMER), 0xa8); 2347e07d9cb8Szf162725 ddi_put8(ioh, (uint8_t *)(regs + PCI_CONF_ILINE), 0x10); 2348e07d9cb8Szf162725 ddi_regs_map_free(&ioh); 2349e07d9cb8Szf162725 2350e07d9cb8Szf162725 /* pci i/o space */ 2351e07d9cb8Szf162725 err = ddi_regs_map_setup(devinfo, 1, 2352e07d9cb8Szf162725 &sc->sc_rbase, 0, 0, &ral_csr_accattr, &sc->sc_ioh); 2353e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2354e07d9cb8Szf162725 "regs map1 = %x err=%d\n", regs, err); 2355e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2356e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2357e07d9cb8Szf162725 "ddi_regs_map_setup() failed"); 2358e07d9cb8Szf162725 goto fail1; 2359e07d9cb8Szf162725 } 2360e07d9cb8Szf162725 2361e07d9cb8Szf162725 /* initialize the ral rate */ 2362e07d9cb8Szf162725 ral_rate_init(); 2363e07d9cb8Szf162725 2364e07d9cb8Szf162725 /* retrieve RT2560 rev. no */ 2365e07d9cb8Szf162725 sc->asic_rev = RAL_READ(sc, RT2560_CSR0); 2366e07d9cb8Szf162725 2367e07d9cb8Szf162725 /* retrieve MAC address */ 2368e07d9cb8Szf162725 rt2560_get_macaddr(sc, ic->ic_macaddr); 2369e07d9cb8Szf162725 2370e07d9cb8Szf162725 /* retrieve RF rev. no and various other things from EEPROM */ 2371e07d9cb8Szf162725 rt2560_read_eeprom(sc); 2372e07d9cb8Szf162725 2373e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n", 2374e07d9cb8Szf162725 sc->asic_rev, rt2560_get_rf(sc->rf_rev)); 2375e07d9cb8Szf162725 2376e07d9cb8Szf162725 /* 2377e07d9cb8Szf162725 * Allocate Tx and Rx rings. 2378e07d9cb8Szf162725 */ 2379e07d9cb8Szf162725 err = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT); 2380e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2381e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "could not allocate Tx ring\n"); 2382e07d9cb8Szf162725 goto fail2; 2383e07d9cb8Szf162725 } 2384e07d9cb8Szf162725 err = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT); 2385e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2386e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "could not allocate Prio ring\n"); 2387e07d9cb8Szf162725 goto fail3; 2388e07d9cb8Szf162725 } 2389e07d9cb8Szf162725 err = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT); 2390e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2391e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "could not allocate Rx ring\n"); 2392e07d9cb8Szf162725 goto fail4; 2393e07d9cb8Szf162725 } 2394e07d9cb8Szf162725 2395e07d9cb8Szf162725 mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL); 2396e07d9cb8Szf162725 mutex_init(&sc->txq.tx_lock, NULL, MUTEX_DRIVER, NULL); 2397e07d9cb8Szf162725 mutex_init(&sc->prioq.tx_lock, NULL, MUTEX_DRIVER, NULL); 2398e07d9cb8Szf162725 mutex_init(&sc->rxq.rx_lock, NULL, MUTEX_DRIVER, NULL); 2399e07d9cb8Szf162725 2400e07d9cb8Szf162725 2401e07d9cb8Szf162725 ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 2402e07d9cb8Szf162725 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 2403e07d9cb8Szf162725 ic->ic_state = IEEE80211_S_INIT; 2404e07d9cb8Szf162725 2405e07d9cb8Szf162725 ic->ic_maxrssi = 63; 2406e07d9cb8Szf162725 ic->ic_set_shortslot = rt2560_update_slot; 2407e07d9cb8Szf162725 ic->ic_xmit = rt2560_mgmt_send; 2408e07d9cb8Szf162725 2409e07d9cb8Szf162725 /* set device capabilities */ 2410e07d9cb8Szf162725 ic->ic_caps = 2411e07d9cb8Szf162725 IEEE80211_C_TXPMGT | /* tx power management */ 2412e07d9cb8Szf162725 IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 2413e07d9cb8Szf162725 IEEE80211_C_SHSLOT; /* short slot time supported */ 2414e07d9cb8Szf162725 24153a1a8936Szf162725 ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */ 24163a1a8936Szf162725 2417e07d9cb8Szf162725 #define IEEE80211_CHAN_A \ 2418e07d9cb8Szf162725 (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) 2419e07d9cb8Szf162725 2420e07d9cb8Szf162725 if (sc->rf_rev == RT2560_RF_5222) { 2421e07d9cb8Szf162725 /* set supported .11a rates */ 2422e07d9cb8Szf162725 ic->ic_sup_rates[IEEE80211_MODE_11A] = rt2560_rateset_11a; 2423e07d9cb8Szf162725 2424e07d9cb8Szf162725 /* set supported .11a channels */ 2425e07d9cb8Szf162725 for (i = 36; i <= 64; i += 4) { 2426e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_freq = 2427e07d9cb8Szf162725 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 2428e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 2429e07d9cb8Szf162725 } 2430e07d9cb8Szf162725 for (i = 100; i <= 140; i += 4) { 2431e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_freq = 2432e07d9cb8Szf162725 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 2433e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 2434e07d9cb8Szf162725 } 2435e07d9cb8Szf162725 for (i = 149; i <= 161; i += 4) { 2436e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_freq = 2437e07d9cb8Szf162725 ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 2438e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 2439e07d9cb8Szf162725 } 2440e07d9cb8Szf162725 } 2441e07d9cb8Szf162725 2442e07d9cb8Szf162725 /* set supported .11b and .11g rates */ 2443e07d9cb8Szf162725 ic->ic_sup_rates[IEEE80211_MODE_11B] = rt2560_rateset_11b; 2444e07d9cb8Szf162725 ic->ic_sup_rates[IEEE80211_MODE_11G] = rt2560_rateset_11g; 2445e07d9cb8Szf162725 2446e07d9cb8Szf162725 /* set supported .11b and .11g channels (1 through 14) */ 2447e07d9cb8Szf162725 for (i = 1; i <= 14; i++) { 2448e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_freq = 2449e07d9cb8Szf162725 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 2450e07d9cb8Szf162725 ic->ic_sup_channels[i].ich_flags = 2451e07d9cb8Szf162725 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 2452e07d9cb8Szf162725 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 2453e07d9cb8Szf162725 } 2454e07d9cb8Szf162725 2455e07d9cb8Szf162725 ieee80211_attach(ic); 2456e07d9cb8Szf162725 24573a1a8936Szf162725 /* register WPA door */ 24583a1a8936Szf162725 ieee80211_register_door(ic, ddi_driver_name(devinfo), 24593a1a8936Szf162725 ddi_get_instance(devinfo)); 24603a1a8936Szf162725 2461e07d9cb8Szf162725 ic->ic_node_alloc = rt2560_node_alloc; 2462e07d9cb8Szf162725 ic->ic_node_free = rt2560_node_free; 2463e07d9cb8Szf162725 2464e07d9cb8Szf162725 /* override state transition machine */ 2465e07d9cb8Szf162725 sc->sc_newstate = ic->ic_newstate; 2466e07d9cb8Szf162725 ic->ic_newstate = rt2560_newstate; 2467e07d9cb8Szf162725 ic->ic_watchdog = rt2560_watchdog; 2468e07d9cb8Szf162725 ieee80211_media_init(ic); 2469e07d9cb8Szf162725 ic->ic_def_txkey = 0; 2470e07d9cb8Szf162725 2471e07d9cb8Szf162725 sc->sc_rcr = 0; 2472e07d9cb8Szf162725 sc->sc_rx_pend = 0; 2473e07d9cb8Szf162725 sc->dwelltime = 300; 2474e07d9cb8Szf162725 sc->sc_flags &= ~RAL_FLAG_RUNNING; 2475e07d9cb8Szf162725 2476e07d9cb8Szf162725 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, 2477e07d9cb8Szf162725 &sc->sc_softint_id, NULL, 0, ral_softint_handler, (caddr_t)sc); 2478e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2479e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2480e07d9cb8Szf162725 "ddi_add_softintr() failed"); 2481e07d9cb8Szf162725 goto fail5; 2482e07d9cb8Szf162725 } 2483e07d9cb8Szf162725 2484e07d9cb8Szf162725 err = ddi_get_iblock_cookie(devinfo, 0, &sc->sc_iblock); 2485e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2486e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2487e07d9cb8Szf162725 "Can not get iblock cookie for INT\n"); 2488e07d9cb8Szf162725 goto fail6; 2489e07d9cb8Szf162725 } 2490e07d9cb8Szf162725 2491e07d9cb8Szf162725 err = ddi_add_intr(devinfo, 0, NULL, NULL, rt2560_intr, (caddr_t)sc); 2492e07d9cb8Szf162725 if (err != DDI_SUCCESS) { 2493e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, 2494e07d9cb8Szf162725 "unable to add device interrupt handler\n"); 2495e07d9cb8Szf162725 goto fail6; 2496e07d9cb8Szf162725 } 2497e07d9cb8Szf162725 2498e07d9cb8Szf162725 /* 2499e07d9cb8Szf162725 * Provide initial settings for the WiFi plugin; whenever this 2500e07d9cb8Szf162725 * information changes, we need to call mac_plugindata_update() 2501e07d9cb8Szf162725 */ 2502e07d9cb8Szf162725 wd.wd_opmode = ic->ic_opmode; 2503e07d9cb8Szf162725 wd.wd_secalloc = WIFI_SEC_NONE; 2504e07d9cb8Szf162725 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 2505e07d9cb8Szf162725 2506e07d9cb8Szf162725 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 2507e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2508e07d9cb8Szf162725 "MAC version mismatch\n"); 2509e07d9cb8Szf162725 goto fail7; 2510e07d9cb8Szf162725 } 2511e07d9cb8Szf162725 2512e07d9cb8Szf162725 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 2513e07d9cb8Szf162725 macp->m_driver = sc; 2514e07d9cb8Szf162725 macp->m_dip = devinfo; 2515e07d9cb8Szf162725 macp->m_src_addr = ic->ic_macaddr; 2516e07d9cb8Szf162725 macp->m_callbacks = &rt2560_m_callbacks; 2517e07d9cb8Szf162725 macp->m_min_sdu = 0; 2518e07d9cb8Szf162725 macp->m_max_sdu = IEEE80211_MTU; 2519e07d9cb8Szf162725 macp->m_pdata = &wd; 2520e07d9cb8Szf162725 macp->m_pdata_size = sizeof (wd); 2521e07d9cb8Szf162725 2522e07d9cb8Szf162725 err = mac_register(macp, &ic->ic_mach); 2523e07d9cb8Szf162725 mac_free(macp); 2524e07d9cb8Szf162725 if (err != 0) { 2525e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ral: rt2560_attach(): " 2526e07d9cb8Szf162725 "mac_register err %x\n", err); 2527e07d9cb8Szf162725 goto fail7; 2528e07d9cb8Szf162725 } 2529e07d9cb8Szf162725 2530e07d9cb8Szf162725 /* 2531e07d9cb8Szf162725 * Create minor node of type DDI_NT_NET_WIFI 2532e07d9cb8Szf162725 */ 2533e07d9cb8Szf162725 (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 2534e07d9cb8Szf162725 "ral", instance); 2535e07d9cb8Szf162725 err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR, 2536e07d9cb8Szf162725 instance + 1, DDI_NT_NET_WIFI, 0); 2537e07d9cb8Szf162725 2538e07d9cb8Szf162725 if (err != DDI_SUCCESS) 2539e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "ddi_create_minor_node() failed\n"); 2540e07d9cb8Szf162725 2541e07d9cb8Szf162725 /* 2542e07d9cb8Szf162725 * Notify link is down now 2543e07d9cb8Szf162725 */ 2544e07d9cb8Szf162725 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 2545e07d9cb8Szf162725 2546e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "rt2560_attach() exit successfully.\n"); 2547e07d9cb8Szf162725 return (DDI_SUCCESS); 2548e07d9cb8Szf162725 fail7: 2549e07d9cb8Szf162725 ddi_remove_intr(devinfo, 0, sc->sc_iblock); 2550e07d9cb8Szf162725 fail6: 2551e07d9cb8Szf162725 ddi_remove_softintr(sc->sc_softint_id); 2552e07d9cb8Szf162725 fail5: 2553e07d9cb8Szf162725 mutex_destroy(&sc->sc_genlock); 2554e07d9cb8Szf162725 mutex_destroy(&sc->txq.tx_lock); 2555e07d9cb8Szf162725 mutex_destroy(&sc->prioq.tx_lock); 2556e07d9cb8Szf162725 mutex_destroy(&sc->rxq.rx_lock); 2557e07d9cb8Szf162725 2558e07d9cb8Szf162725 rt2560_free_rx_ring(sc, &sc->rxq); 2559e07d9cb8Szf162725 fail4: 2560e07d9cb8Szf162725 rt2560_free_tx_ring(sc, &sc->prioq); 2561e07d9cb8Szf162725 fail3: 2562e07d9cb8Szf162725 rt2560_free_tx_ring(sc, &sc->txq); 2563e07d9cb8Szf162725 fail2: 2564e07d9cb8Szf162725 ddi_regs_map_free(&sc->sc_ioh); 2565e07d9cb8Szf162725 fail1: 2566e07d9cb8Szf162725 ddi_soft_state_free(ral_soft_state_p, ddi_get_instance(devinfo)); 2567e07d9cb8Szf162725 2568e07d9cb8Szf162725 return (DDI_FAILURE); 2569e07d9cb8Szf162725 } 2570e07d9cb8Szf162725 2571e07d9cb8Szf162725 static int 2572e07d9cb8Szf162725 rt2560_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 2573e07d9cb8Szf162725 { 2574e07d9cb8Szf162725 struct rt2560_softc *sc; 2575e07d9cb8Szf162725 2576e07d9cb8Szf162725 RAL_DEBUG(RAL_DBG_GLD, "enter rt2560_detach()\n"); 2577e07d9cb8Szf162725 sc = ddi_get_soft_state(ral_soft_state_p, ddi_get_instance(devinfo)); 2578e07d9cb8Szf162725 2579e07d9cb8Szf162725 if (cmd != DDI_DETACH) 2580e07d9cb8Szf162725 return (DDI_FAILURE); 2581e07d9cb8Szf162725 2582e07d9cb8Szf162725 rt2560_stop(sc); 2583e07d9cb8Szf162725 2584e07d9cb8Szf162725 /* 2585e07d9cb8Szf162725 * Unregister from the MAC layer subsystem 2586e07d9cb8Szf162725 */ 2587e07d9cb8Szf162725 if (mac_unregister(sc->sc_ic.ic_mach) != 0) 2588e07d9cb8Szf162725 return (DDI_FAILURE); 2589e07d9cb8Szf162725 2590e07d9cb8Szf162725 ddi_remove_intr(devinfo, 0, sc->sc_iblock); 2591e07d9cb8Szf162725 ddi_remove_softintr(sc->sc_softint_id); 2592e07d9cb8Szf162725 2593e07d9cb8Szf162725 /* 2594e07d9cb8Szf162725 * detach ieee80211 layer 2595e07d9cb8Szf162725 */ 2596e07d9cb8Szf162725 ieee80211_detach(&sc->sc_ic); 2597e07d9cb8Szf162725 2598e07d9cb8Szf162725 rt2560_free_tx_ring(sc, &sc->txq); 2599e07d9cb8Szf162725 rt2560_free_tx_ring(sc, &sc->prioq); 2600e07d9cb8Szf162725 rt2560_free_rx_ring(sc, &sc->rxq); 2601e07d9cb8Szf162725 2602e07d9cb8Szf162725 ddi_regs_map_free(&sc->sc_ioh); 2603e07d9cb8Szf162725 2604e07d9cb8Szf162725 mutex_destroy(&sc->sc_genlock); 2605e07d9cb8Szf162725 mutex_destroy(&sc->txq.tx_lock); 2606e07d9cb8Szf162725 mutex_destroy(&sc->prioq.tx_lock); 2607e07d9cb8Szf162725 mutex_destroy(&sc->rxq.rx_lock); 2608e07d9cb8Szf162725 2609e07d9cb8Szf162725 ddi_remove_minor_node(devinfo, NULL); 2610e07d9cb8Szf162725 ddi_soft_state_free(ral_soft_state_p, ddi_get_instance(devinfo)); 2611e07d9cb8Szf162725 2612e07d9cb8Szf162725 return (DDI_SUCCESS); 2613e07d9cb8Szf162725 } 2614e07d9cb8Szf162725 2615e07d9cb8Szf162725 int 2616e07d9cb8Szf162725 _info(struct modinfo *modinfop) 2617e07d9cb8Szf162725 { 2618e07d9cb8Szf162725 return (mod_info(&modlinkage, modinfop)); 2619e07d9cb8Szf162725 } 2620e07d9cb8Szf162725 2621e07d9cb8Szf162725 int 2622e07d9cb8Szf162725 _init(void) 2623e07d9cb8Szf162725 { 2624e07d9cb8Szf162725 int status; 2625e07d9cb8Szf162725 2626e07d9cb8Szf162725 status = ddi_soft_state_init(&ral_soft_state_p, 2627e07d9cb8Szf162725 sizeof (struct rt2560_softc), 1); 2628e07d9cb8Szf162725 if (status != 0) 2629e07d9cb8Szf162725 return (status); 2630e07d9cb8Szf162725 2631e07d9cb8Szf162725 mac_init_ops(&ral_dev_ops, "ral"); 2632e07d9cb8Szf162725 status = mod_install(&modlinkage); 2633e07d9cb8Szf162725 if (status != 0) { 2634e07d9cb8Szf162725 mac_fini_ops(&ral_dev_ops); 2635e07d9cb8Szf162725 ddi_soft_state_fini(&ral_soft_state_p); 2636e07d9cb8Szf162725 } 2637e07d9cb8Szf162725 return (status); 2638e07d9cb8Szf162725 } 2639e07d9cb8Szf162725 2640e07d9cb8Szf162725 int 2641e07d9cb8Szf162725 _fini(void) 2642e07d9cb8Szf162725 { 2643e07d9cb8Szf162725 int status; 2644e07d9cb8Szf162725 2645e07d9cb8Szf162725 status = mod_remove(&modlinkage); 2646e07d9cb8Szf162725 if (status == 0) { 2647e07d9cb8Szf162725 mac_fini_ops(&ral_dev_ops); 2648e07d9cb8Szf162725 ddi_soft_state_fini(&ral_soft_state_p); 2649e07d9cb8Szf162725 } 2650e07d9cb8Szf162725 return (status); 2651e07d9cb8Szf162725 } 2652