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