Annotation of sys/dev/ic/rtw.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: rtw.c,v 1.61 2007/06/07 20:20:15 damien Exp $ */
! 2: /* $NetBSD: rtw.c,v 1.29 2004/12/27 19:49:16 dyoung Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2004, 2005 David Young. All rights reserved.
! 6: *
! 7: * Programmed for NetBSD by David Young.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. The name of David Young may not be used to endorse or promote
! 18: * products derived from this software without specific prior
! 19: * written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
! 22: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
! 23: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
! 24: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David
! 25: * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 26: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
! 27: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
! 29: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! 30: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
! 32: * OF SUCH DAMAGE.
! 33: */
! 34: /*
! 35: * Device driver for the Realtek RTL8180 802.11 MAC/BBP.
! 36: */
! 37:
! 38: #include <sys/cdefs.h>
! 39: #include "bpfilter.h"
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/mbuf.h>
! 44: #include <sys/malloc.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/ioctl.h>
! 47: #include <sys/socket.h>
! 48: #include <sys/time.h>
! 49: #include <sys/types.h>
! 50:
! 51: #include <machine/endian.h>
! 52: #include <machine/bus.h>
! 53: #include <machine/intr.h> /* splnet */
! 54:
! 55: #include <uvm/uvm_extern.h>
! 56:
! 57: #include <net/if.h>
! 58: #include <net/if_media.h>
! 59:
! 60: #if NBPFILTER > 0
! 61: #include <net/bpf.h>
! 62: #endif
! 63:
! 64: #ifdef INET
! 65: #include <netinet/in.h>
! 66: #include <netinet/if_ether.h>
! 67: #endif
! 68:
! 69: #include <net80211/ieee80211_var.h>
! 70: #include <net80211/ieee80211_radiotap.h>
! 71:
! 72: #include <dev/ic/rtwreg.h>
! 73: #include <dev/ic/rtwvar.h>
! 74: #include <dev/ic/max2820reg.h>
! 75: #include <dev/ic/sa2400reg.h>
! 76: #include <dev/ic/si4136reg.h>
! 77: #include <dev/ic/rtl8225reg.h>
! 78: #include <dev/ic/smc93cx6var.h>
! 79:
! 80: int rtw_rfprog_fallback = 0;
! 81: int rtw_do_chip_reset = 0;
! 82: int rtw_dwelltime = 200; /* milliseconds per channel */
! 83: int rtw_macbangbits_timeout = 100;
! 84:
! 85: #ifdef RTW_DEBUG
! 86: int rtw_debug = 0;
! 87: int rtw_rxbufs_limit = RTW_RXQLEN;
! 88: #endif /* RTW_DEBUG */
! 89:
! 90: void rtw_start(struct ifnet *);
! 91: void rtw_txdesc_blk_init_all(struct rtw_txdesc_blk *);
! 92: void rtw_txsoft_blk_init_all(struct rtw_txsoft_blk *);
! 93: void rtw_txdesc_blk_init(struct rtw_txdesc_blk *);
! 94: void rtw_txdescs_sync(struct rtw_txdesc_blk *, u_int, u_int, int);
! 95: u_int rtw_txring_next(struct rtw_regs *, struct rtw_txdesc_blk *);
! 96: void rtw_txring_fixup(struct rtw_softc *);
! 97: void rtw_rxbufs_release(bus_dma_tag_t, struct rtw_rxsoft *);
! 98: void rtw_rxdesc_init(struct rtw_rxdesc_blk *, struct rtw_rxsoft *, int, int);
! 99: void rtw_rxring_fixup(struct rtw_softc *);
! 100: void rtw_io_enable(struct rtw_regs *, u_int8_t, int);
! 101: void rtw_intr_rx(struct rtw_softc *, u_int16_t);
! 102: void rtw_intr_beacon(struct rtw_softc *, u_int16_t);
! 103: void rtw_intr_atim(struct rtw_softc *);
! 104: void rtw_transmit_config(struct rtw_softc *);
! 105: void rtw_pktfilt_load(struct rtw_softc *);
! 106: void rtw_start(struct ifnet *);
! 107: void rtw_watchdog(struct ifnet *);
! 108: void rtw_next_scan(void *);
! 109: void rtw_recv_mgmt(struct ieee80211com *, struct mbuf *,
! 110: struct ieee80211_node *, int, int, u_int32_t);
! 111: struct ieee80211_node *rtw_node_alloc(struct ieee80211com *);
! 112: void rtw_node_free(struct ieee80211com *, struct ieee80211_node *);
! 113: void rtw_media_status(struct ifnet *, struct ifmediareq *);
! 114: void rtw_txsoft_blk_cleanup_all(struct rtw_softc *);
! 115: void rtw_txdesc_blk_setup(struct rtw_txdesc_blk *, struct rtw_txdesc *,
! 116: u_int, bus_addr_t, bus_addr_t);
! 117: void rtw_txdesc_blk_setup_all(struct rtw_softc *);
! 118: void rtw_intr_tx(struct rtw_softc *, u_int16_t);
! 119: void rtw_intr_ioerror(struct rtw_softc *, u_int16_t);
! 120: void rtw_intr_timeout(struct rtw_softc *);
! 121: void rtw_stop(struct ifnet *, int);
! 122: void rtw_maxim_pwrstate(struct rtw_regs *, enum rtw_pwrstate, int, int);
! 123: void rtw_philips_pwrstate(struct rtw_regs *, enum rtw_pwrstate, int, int);
! 124: void rtw_rtl_pwrstate(struct rtw_regs *, enum rtw_pwrstate, int, int);
! 125: void rtw_pwrstate0(struct rtw_softc *, enum rtw_pwrstate, int, int);
! 126: void rtw_join_bss(struct rtw_softc *, u_int8_t *, u_int16_t);
! 127: void rtw_set_access1(struct rtw_regs *, enum rtw_access);
! 128: int rtw_srom_parse(struct rtw_softc *);
! 129: int rtw_srom_read(struct rtw_regs *, u_int32_t, struct rtw_srom *,
! 130: const char *);
! 131: void rtw_set_rfprog(struct rtw_regs *, int, const char *);
! 132: u_int8_t rtw_chan2txpower(struct rtw_srom *, struct ieee80211com *,
! 133: struct ieee80211_channel *);
! 134: int rtw_txsoft_blk_init(struct rtw_txsoft_blk *);
! 135: int rtw_rxsoft_init_all(bus_dma_tag_t, struct rtw_rxsoft *,
! 136: int *, const char *);
! 137: void rtw_txsoft_release(bus_dma_tag_t, struct ieee80211com *,
! 138: struct rtw_txsoft *);
! 139: void rtw_txsofts_release(bus_dma_tag_t, struct ieee80211com *,
! 140: struct rtw_txsoft_blk *);
! 141: void rtw_hwring_setup(struct rtw_softc *);
! 142: int rtw_swring_setup(struct rtw_softc *);
! 143: void rtw_txdescs_reset(struct rtw_softc *);
! 144: void rtw_rfmd_pwrstate(struct rtw_regs *, enum rtw_pwrstate, int, int);
! 145: int rtw_pwrstate(struct rtw_softc *, enum rtw_pwrstate);
! 146: int rtw_tune(struct rtw_softc *);
! 147: void rtw_set_nettype(struct rtw_softc *, enum ieee80211_opmode);
! 148: int rtw_compute_duration1(int, int, uint32_t, int, struct rtw_duration *);
! 149: int rtw_compute_duration(struct ieee80211_frame *, int, uint32_t, int,
! 150: int, struct rtw_duration *, struct rtw_duration *, int *, int);
! 151: int rtw_init(struct ifnet *);
! 152: int rtw_ioctl(struct ifnet *, u_long, caddr_t);
! 153: int rtw_seg_too_short(bus_dmamap_t);
! 154: struct mbuf *rtw_dmamap_load_txbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *,
! 155: u_int, short *, const char *);
! 156: int rtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 157: int rtw_media_change(struct ifnet *);
! 158: int rtw_txsoft_blk_setup_all(struct rtw_softc *);
! 159: int rtw_rf_attach(struct rtw_softc *, int);
! 160: u_int8_t rtw_check_phydelay(struct rtw_regs *, u_int32_t);
! 161: int rtw_chip_reset1(struct rtw_regs *, const char *);
! 162: int rtw_chip_reset(struct rtw_regs *, const char *);
! 163: int rtw_recall_eeprom(struct rtw_regs *, const char *);
! 164: int rtw_reset(struct rtw_softc *);
! 165: void rtw_reset_oactive(struct rtw_softc *);
! 166: int rtw_txdesc_dmamaps_create(bus_dma_tag_t, struct rtw_txsoft *, u_int);
! 167: int rtw_rxdesc_dmamaps_create(bus_dma_tag_t, struct rtw_rxsoft *, u_int);
! 168: void rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t, struct rtw_rxsoft *, u_int);
! 169: void rtw_txdesc_dmamaps_destroy(bus_dma_tag_t, struct rtw_txsoft *, u_int);
! 170: void rtw_init_channels(enum rtw_locale, struct ieee80211_channel (*)[],
! 171: const char*);
! 172: void rtw_identify_country(struct rtw_regs *, enum rtw_locale *);
! 173: int rtw_identify_sta(struct rtw_regs *, u_int8_t (*)[], const char *);
! 174: void rtw_rxdescs_sync(struct rtw_rxdesc_blk *, int, int, int);
! 175: int rtw_rxsoft_alloc(bus_dma_tag_t, struct rtw_rxsoft *);
! 176: void rtw_collect_txpkt(struct rtw_softc *, struct rtw_txdesc_blk *,
! 177: struct rtw_txsoft *, int);
! 178: void rtw_collect_txring(struct rtw_softc *, struct rtw_txsoft_blk *,
! 179: struct rtw_txdesc_blk *, int);
! 180: void rtw_suspend_ticks(struct rtw_softc *);
! 181: void rtw_resume_ticks(struct rtw_softc *);
! 182: void rtw_enable_interrupts(struct rtw_softc *);
! 183: int rtw_dequeue(struct ifnet *, struct rtw_txsoft_blk **,
! 184: struct rtw_txdesc_blk **, struct mbuf **,
! 185: struct ieee80211_node **);
! 186: void rtw_establish_hooks(struct rtw_hooks *, const char *, void *);
! 187: void rtw_disestablish_hooks(struct rtw_hooks *, const char *, void *);
! 188: int rtw_txsoft_blk_setup(struct rtw_txsoft_blk *, u_int);
! 189: void rtw_rxdesc_init_all(struct rtw_rxdesc_blk *, struct rtw_rxsoft *,
! 190: int);
! 191: int rtw_txring_choose(struct rtw_softc *, struct rtw_txsoft_blk **,
! 192: struct rtw_txdesc_blk **, int);
! 193: u_int rtw_txring_next(struct rtw_regs *, struct rtw_txdesc_blk *);
! 194: struct mbuf *rtw_80211_dequeue(struct rtw_softc *, struct ifqueue *, int,
! 195: struct rtw_txsoft_blk **, struct rtw_txdesc_blk **,
! 196: struct ieee80211_node **, short *);
! 197: uint64_t rtw_tsf_extend(struct rtw_regs *, u_int32_t);
! 198: void rtw_ibss_merge(struct rtw_softc *, struct ieee80211_node *,
! 199: u_int32_t);
! 200: void rtw_idle(struct rtw_regs *);
! 201: void rtw_led_attach(struct rtw_led_state *, void *);
! 202: void rtw_led_init(struct rtw_regs *);
! 203: void rtw_led_slowblink(void *);
! 204: void rtw_led_fastblink(void *);
! 205: void rtw_led_set(struct rtw_led_state *, struct rtw_regs *, u_int);
! 206: void rtw_led_newstate(struct rtw_softc *, enum ieee80211_state);
! 207:
! 208: int rtw_phy_init(struct rtw_softc *);
! 209: int rtw_bbp_preinit(struct rtw_regs *, u_int, int, u_int);
! 210: int rtw_bbp_init(struct rtw_regs *, struct rtw_bbpset *, int,
! 211: int, u_int8_t, u_int);
! 212: void rtw_verify_syna(u_int, u_int32_t);
! 213: int rtw_sa2400_pwrstate(struct rtw_softc *, enum rtw_pwrstate);
! 214: int rtw_sa2400_txpower(struct rtw_softc *, u_int8_t);
! 215: int rtw_sa2400_tune(struct rtw_softc *, u_int);
! 216: int rtw_sa2400_vcocal_start(struct rtw_softc *, int);
! 217: int rtw_sa2400_vco_calibration(struct rtw_softc *);
! 218: int rtw_sa2400_filter_calibration(struct rtw_softc *);
! 219: int rtw_sa2400_dc_calibration(struct rtw_softc *);
! 220: int rtw_sa2400_calibrate(struct rtw_softc *, u_int);
! 221: int rtw_sa2400_init(struct rtw_softc *, u_int, u_int8_t,
! 222: enum rtw_pwrstate);
! 223: int rtw_max2820_pwrstate(struct rtw_softc *, enum rtw_pwrstate);
! 224: int rtw_max2820_init(struct rtw_softc *, u_int, u_int8_t,
! 225: enum rtw_pwrstate);
! 226: int rtw_max2820_txpower(struct rtw_softc *, u_int8_t);
! 227: int rtw_max2820_tune(struct rtw_softc *, u_int);
! 228: int rtw_rtl8225_pwrstate(struct rtw_softc *, enum rtw_pwrstate);
! 229: int rtw_rtl8225_init(struct rtw_softc *, u_int, u_int8_t,
! 230: enum rtw_pwrstate);
! 231: int rtw_rtl8225_txpower(struct rtw_softc *, u_int8_t);
! 232: int rtw_rtl8225_tune(struct rtw_softc *, u_int);
! 233: int rtw_rtl8255_pwrstate(struct rtw_softc *, enum rtw_pwrstate);
! 234: int rtw_rtl8255_init(struct rtw_softc *, u_int, u_int8_t,
! 235: enum rtw_pwrstate);
! 236: int rtw_rtl8255_txpower(struct rtw_softc *, u_int8_t);
! 237: int rtw_rtl8255_tune(struct rtw_softc *, u_int);
! 238: int rtw_grf5101_pwrstate(struct rtw_softc *, enum rtw_pwrstate);
! 239: int rtw_grf5101_init(struct rtw_softc *, u_int, u_int8_t,
! 240: enum rtw_pwrstate);
! 241: int rtw_grf5101_txpower(struct rtw_softc *, u_int8_t);
! 242: int rtw_grf5101_tune(struct rtw_softc *, u_int);
! 243: int rtw_rf_hostwrite(struct rtw_softc *, u_int, u_int32_t);
! 244: int rtw_rf_macwrite(struct rtw_softc *, u_int, u_int32_t);
! 245: int rtw_bbp_write(struct rtw_regs *, u_int, u_int);
! 246: u_int32_t rtw_grf5101_host_crypt(u_int, u_int32_t);
! 247: u_int32_t rtw_maxim_swizzle(u_int, uint32_t);
! 248: u_int32_t rtw_grf5101_mac_crypt(u_int, u_int32_t);
! 249: void rtw_rf_hostbangbits(struct rtw_regs *, u_int32_t, int, u_int);
! 250: void rtw_rf_rtl8225_hostbangbits(struct rtw_regs *, u_int32_t, int, u_int);
! 251: int rtw_rf_macbangbits(struct rtw_regs *, u_int32_t);
! 252:
! 253: u_int8_t rtw_read8(void *, u_int32_t);
! 254: u_int16_t rtw_read16(void *, u_int32_t);
! 255: u_int32_t rtw_read32(void *, u_int32_t);
! 256: void rtw_write8(void *, u_int32_t, u_int8_t);
! 257: void rtw_write16(void *, u_int32_t, u_int16_t);
! 258: void rtw_write32(void *, u_int32_t, u_int32_t);
! 259: void rtw_barrier(void *, u_int32_t, u_int32_t, int);
! 260:
! 261: #ifdef RTW_DEBUG
! 262: void rtw_print_txdesc(struct rtw_softc *, const char *,
! 263: struct rtw_txsoft *, struct rtw_txdesc_blk *, int);
! 264: const char *rtw_access_string(enum rtw_access);
! 265: void rtw_dump_rings(struct rtw_softc *);
! 266: void rtw_print_txdesc(struct rtw_softc *, const char *,
! 267: struct rtw_txsoft *, struct rtw_txdesc_blk *, int);
! 268: #endif
! 269:
! 270: struct cfdriver rtw_cd = {
! 271: NULL, "rtw", DV_IFNET
! 272: };
! 273:
! 274: void
! 275: rtw_continuous_tx_enable(struct rtw_softc *sc, int enable)
! 276: {
! 277: struct rtw_regs *regs = &sc->sc_regs;
! 278:
! 279: u_int32_t tcr;
! 280: tcr = RTW_READ(regs, RTW_TCR);
! 281: tcr &= ~RTW_TCR_LBK_MASK;
! 282: if (enable)
! 283: tcr |= RTW_TCR_LBK_CONT;
! 284: else
! 285: tcr |= RTW_TCR_LBK_NORMAL;
! 286: RTW_WRITE(regs, RTW_TCR, tcr);
! 287: RTW_SYNC(regs, RTW_TCR, RTW_TCR);
! 288: rtw_set_access(regs, RTW_ACCESS_ANAPARM);
! 289: rtw_txdac_enable(sc, !enable);
! 290: rtw_set_access(regs, RTW_ACCESS_ANAPARM);/* XXX Voodoo from Linux. */
! 291: rtw_set_access(regs, RTW_ACCESS_NONE);
! 292: }
! 293:
! 294: #ifdef RTW_DEBUG
! 295: const char *
! 296: rtw_access_string(enum rtw_access access)
! 297: {
! 298: switch (access) {
! 299: case RTW_ACCESS_NONE:
! 300: return "none";
! 301: case RTW_ACCESS_CONFIG:
! 302: return "config";
! 303: case RTW_ACCESS_ANAPARM:
! 304: return "anaparm";
! 305: default:
! 306: return "unknown";
! 307: }
! 308: }
! 309: #endif
! 310:
! 311: void
! 312: rtw_set_access1(struct rtw_regs *regs, enum rtw_access naccess)
! 313: {
! 314: KASSERT(naccess >= RTW_ACCESS_NONE && naccess <= RTW_ACCESS_ANAPARM);
! 315: KASSERT(regs->r_access >= RTW_ACCESS_NONE &&
! 316: regs->r_access <= RTW_ACCESS_ANAPARM);
! 317:
! 318: if (naccess == regs->r_access)
! 319: return;
! 320:
! 321: switch (naccess) {
! 322: case RTW_ACCESS_NONE:
! 323: switch (regs->r_access) {
! 324: case RTW_ACCESS_ANAPARM:
! 325: rtw_anaparm_enable(regs, 0);
! 326: /*FALLTHROUGH*/
! 327: case RTW_ACCESS_CONFIG:
! 328: rtw_config0123_enable(regs, 0);
! 329: /*FALLTHROUGH*/
! 330: case RTW_ACCESS_NONE:
! 331: break;
! 332: }
! 333: break;
! 334: case RTW_ACCESS_CONFIG:
! 335: switch (regs->r_access) {
! 336: case RTW_ACCESS_NONE:
! 337: rtw_config0123_enable(regs, 1);
! 338: /*FALLTHROUGH*/
! 339: case RTW_ACCESS_CONFIG:
! 340: break;
! 341: case RTW_ACCESS_ANAPARM:
! 342: rtw_anaparm_enable(regs, 0);
! 343: break;
! 344: }
! 345: break;
! 346: case RTW_ACCESS_ANAPARM:
! 347: switch (regs->r_access) {
! 348: case RTW_ACCESS_NONE:
! 349: rtw_config0123_enable(regs, 1);
! 350: /*FALLTHROUGH*/
! 351: case RTW_ACCESS_CONFIG:
! 352: rtw_anaparm_enable(regs, 1);
! 353: /*FALLTHROUGH*/
! 354: case RTW_ACCESS_ANAPARM:
! 355: break;
! 356: }
! 357: break;
! 358: }
! 359: }
! 360:
! 361: void
! 362: rtw_set_access(struct rtw_regs *regs, enum rtw_access access)
! 363: {
! 364: rtw_set_access1(regs, access);
! 365: RTW_DPRINTF(RTW_DEBUG_ACCESS,
! 366: ("%s: access %s -> %s\n",__func__,
! 367: rtw_access_string(regs->r_access),
! 368: rtw_access_string(access)));
! 369: regs->r_access = access;
! 370: }
! 371:
! 372: /*
! 373: * Enable registers, switch register banks.
! 374: */
! 375: void
! 376: rtw_config0123_enable(struct rtw_regs *regs, int enable)
! 377: {
! 378: u_int8_t ecr;
! 379: ecr = RTW_READ8(regs, RTW_9346CR);
! 380: ecr &= ~(RTW_9346CR_EEM_MASK | RTW_9346CR_EECS | RTW_9346CR_EESK);
! 381: if (enable)
! 382: ecr |= RTW_9346CR_EEM_CONFIG;
! 383: else {
! 384: RTW_WBW(regs, RTW_9346CR, MAX(RTW_CONFIG0, RTW_CONFIG3));
! 385: ecr |= RTW_9346CR_EEM_NORMAL;
! 386: }
! 387: RTW_WRITE8(regs, RTW_9346CR, ecr);
! 388: RTW_SYNC(regs, RTW_9346CR, RTW_9346CR);
! 389: }
! 390:
! 391: /* requires rtw_config0123_enable(, 1) */
! 392: void
! 393: rtw_anaparm_enable(struct rtw_regs *regs, int enable)
! 394: {
! 395: u_int8_t cfg3;
! 396:
! 397: cfg3 = RTW_READ8(regs, RTW_CONFIG3);
! 398: cfg3 |= RTW_CONFIG3_CLKRUNEN;
! 399: if (enable)
! 400: cfg3 |= RTW_CONFIG3_PARMEN;
! 401: else
! 402: cfg3 &= ~RTW_CONFIG3_PARMEN;
! 403: RTW_WRITE8(regs, RTW_CONFIG3, cfg3);
! 404: RTW_SYNC(regs, RTW_CONFIG3, RTW_CONFIG3);
! 405: }
! 406:
! 407: /* requires rtw_anaparm_enable(, 1) */
! 408: void
! 409: rtw_txdac_enable(struct rtw_softc *sc, int enable)
! 410: {
! 411: u_int32_t anaparm;
! 412: struct rtw_regs *regs = &sc->sc_regs;
! 413:
! 414: anaparm = RTW_READ(regs, RTW_ANAPARM_0);
! 415: if (enable)
! 416: anaparm &= ~RTW_ANAPARM_TXDACOFF;
! 417: else
! 418: anaparm |= RTW_ANAPARM_TXDACOFF;
! 419: RTW_WRITE(regs, RTW_ANAPARM_0, anaparm);
! 420: RTW_SYNC(regs, RTW_ANAPARM_0, RTW_ANAPARM_0);
! 421: }
! 422:
! 423: int
! 424: rtw_chip_reset1(struct rtw_regs *regs, const char *dvname)
! 425: {
! 426: u_int8_t cr;
! 427: int i;
! 428:
! 429: RTW_WRITE8(regs, RTW_CR, RTW_CR_RST);
! 430:
! 431: RTW_WBR(regs, RTW_CR, RTW_CR);
! 432:
! 433: for (i = 0; i < 1000; i++) {
! 434: if ((cr = RTW_READ8(regs, RTW_CR) & RTW_CR_RST) == 0) {
! 435: RTW_DPRINTF(RTW_DEBUG_RESET,
! 436: ("%s: reset in %dus\n", dvname, i));
! 437: return 0;
! 438: }
! 439: RTW_RBR(regs, RTW_CR, RTW_CR);
! 440: DELAY(10); /* 10us */
! 441: }
! 442:
! 443: printf("\n%s: reset failed\n", dvname);
! 444: return ETIMEDOUT;
! 445: }
! 446:
! 447: int
! 448: rtw_chip_reset(struct rtw_regs *regs, const char *dvname)
! 449: {
! 450: uint32_t tcr;
! 451:
! 452: /* from Linux driver */
! 453: tcr = RTW_TCR_CWMIN | RTW_TCR_MXDMA_2048 |
! 454: LSHIFT(7, RTW_TCR_SRL_MASK) | LSHIFT(7, RTW_TCR_LRL_MASK);
! 455:
! 456: RTW_WRITE(regs, RTW_TCR, tcr);
! 457:
! 458: RTW_WBW(regs, RTW_CR, RTW_TCR);
! 459:
! 460: return rtw_chip_reset1(regs, dvname);
! 461: }
! 462:
! 463: int
! 464: rtw_recall_eeprom(struct rtw_regs *regs, const char *dvname)
! 465: {
! 466: int i;
! 467: u_int8_t ecr;
! 468:
! 469: ecr = RTW_READ8(regs, RTW_9346CR);
! 470: ecr = (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_AUTOLOAD;
! 471: RTW_WRITE8(regs, RTW_9346CR, ecr);
! 472:
! 473: RTW_WBR(regs, RTW_9346CR, RTW_9346CR);
! 474:
! 475: /* wait 10ms for completion */
! 476: for (i = 0; i < 50; i++) {
! 477: ecr = RTW_READ8(regs, RTW_9346CR);
! 478: if ((ecr & RTW_9346CR_EEM_MASK) == RTW_9346CR_EEM_NORMAL) {
! 479: RTW_DPRINTF(RTW_DEBUG_RESET,
! 480: ("%s: recall EEPROM in %dus\n", dvname, i * 200));
! 481: return (0);
! 482: }
! 483: RTW_RBR(regs, RTW_9346CR, RTW_9346CR);
! 484: DELAY(200);
! 485: }
! 486:
! 487: printf("\n%s: could not recall EEPROM in %dus\n", dvname, i * 200);
! 488:
! 489: return (ETIMEDOUT);
! 490: }
! 491:
! 492: int
! 493: rtw_reset(struct rtw_softc *sc)
! 494: {
! 495: int rc;
! 496: uint8_t config1;
! 497:
! 498: if ((rc = rtw_chip_reset(&sc->sc_regs, sc->sc_dev.dv_xname)) != 0)
! 499: return rc;
! 500:
! 501: if ((rc = rtw_recall_eeprom(&sc->sc_regs, sc->sc_dev.dv_xname)) != 0)
! 502: ;
! 503:
! 504: config1 = RTW_READ8(&sc->sc_regs, RTW_CONFIG1);
! 505: RTW_WRITE8(&sc->sc_regs, RTW_CONFIG1, config1 & ~RTW_CONFIG1_PMEN);
! 506: /* TBD turn off maximum power saving? */
! 507:
! 508: return 0;
! 509: }
! 510:
! 511: int
! 512: rtw_txdesc_dmamaps_create(bus_dma_tag_t dmat, struct rtw_txsoft *descs,
! 513: u_int ndescs)
! 514: {
! 515: int i, rc = 0;
! 516: for (i = 0; i < ndescs; i++) {
! 517: rc = bus_dmamap_create(dmat, MCLBYTES, RTW_MAXPKTSEGS, MCLBYTES,
! 518: 0, 0, &descs[i].ts_dmamap);
! 519: if (rc != 0)
! 520: break;
! 521: }
! 522: return rc;
! 523: }
! 524:
! 525: int
! 526: rtw_rxdesc_dmamaps_create(bus_dma_tag_t dmat, struct rtw_rxsoft *descs,
! 527: u_int ndescs)
! 528: {
! 529: int i, rc = 0;
! 530: for (i = 0; i < ndescs; i++) {
! 531: rc = bus_dmamap_create(dmat, MCLBYTES, 1, MCLBYTES, 0, 0,
! 532: &descs[i].rs_dmamap);
! 533: if (rc != 0)
! 534: break;
! 535: }
! 536: return rc;
! 537: }
! 538:
! 539: void
! 540: rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t dmat, struct rtw_rxsoft *descs,
! 541: u_int ndescs)
! 542: {
! 543: int i;
! 544: for (i = 0; i < ndescs; i++) {
! 545: if (descs[i].rs_dmamap != NULL)
! 546: bus_dmamap_destroy(dmat, descs[i].rs_dmamap);
! 547: }
! 548: }
! 549:
! 550: void
! 551: rtw_txdesc_dmamaps_destroy(bus_dma_tag_t dmat, struct rtw_txsoft *descs,
! 552: u_int ndescs)
! 553: {
! 554: int i;
! 555: for (i = 0; i < ndescs; i++) {
! 556: if (descs[i].ts_dmamap != NULL)
! 557: bus_dmamap_destroy(dmat, descs[i].ts_dmamap);
! 558: }
! 559: }
! 560:
! 561: int
! 562: rtw_srom_parse(struct rtw_softc *sc)
! 563: {
! 564: int i;
! 565: struct rtw_srom *sr = &sc->sc_srom;
! 566: u_int32_t *flags = &sc->sc_flags;
! 567: u_int8_t *cs_threshold = &sc->sc_csthr;
! 568: int *rfchipid = &sc->sc_rfchipid;
! 569: u_int32_t *rcr = &sc->sc_rcr;
! 570: enum rtw_locale *locale = &sc->sc_locale;
! 571: u_int16_t version;
! 572: u_int8_t mac[IEEE80211_ADDR_LEN];
! 573:
! 574: *flags &= ~(RTW_F_DIGPHY|RTW_F_DFLANTB|RTW_F_ANTDIV);
! 575: *rcr &= ~(RTW_RCR_ENCS1 | RTW_RCR_ENCS2);
! 576:
! 577: version = RTW_SR_GET16(sr, RTW_SR_VERSION);
! 578: RTW_DPRINTF(RTW_DEBUG_ATTACH,
! 579: ("%s: SROM %d.%d\n", sc->sc_dev.dv_xname, version >> 8,
! 580: version & 0xff));
! 581:
! 582: if (version <= 0x0101) {
! 583: printf(" is not understood, limping along with defaults ");
! 584: *flags |= (RTW_F_DIGPHY|RTW_F_ANTDIV);
! 585: *cs_threshold = RTW_SR_ENERGYDETTHR_DEFAULT;
! 586: *rcr |= RTW_RCR_ENCS1;
! 587: *rfchipid = RTW_RFCHIPID_PHILIPS;
! 588: return 0;
! 589: }
! 590:
! 591: for (i = 0; i < IEEE80211_ADDR_LEN; i++)
! 592: mac[i] = RTW_SR_GET(sr, RTW_SR_MAC + i);
! 593:
! 594: RTW_DPRINTF(RTW_DEBUG_ATTACH,
! 595: ("%s: EEPROM MAC %s\n", sc->sc_dev.dv_xname, ether_sprintf(mac)));
! 596:
! 597: *cs_threshold = RTW_SR_GET(sr, RTW_SR_ENERGYDETTHR);
! 598:
! 599: if ((RTW_SR_GET(sr, RTW_SR_CONFIG2) & RTW8180_CONFIG2_ANT) != 0)
! 600: *flags |= RTW_F_ANTDIV;
! 601:
! 602: /* Note well: the sense of the RTW_SR_RFPARM_DIGPHY bit seems
! 603: * to be reversed.
! 604: */
! 605: if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DIGPHY) == 0)
! 606: *flags |= RTW_F_DIGPHY;
! 607: if ((RTW_SR_GET(sr, RTW_SR_RFPARM) & RTW_SR_RFPARM_DFLANTB) != 0)
! 608: *flags |= RTW_F_DFLANTB;
! 609:
! 610: *rcr |= LSHIFT(MASK_AND_RSHIFT(RTW_SR_GET(sr, RTW_SR_RFPARM),
! 611: RTW_SR_RFPARM_CS_MASK), RTW_RCR_ENCS1);
! 612:
! 613: *rfchipid = RTW_SR_GET(sr, RTW_SR_RFCHIPID);
! 614:
! 615: if (sc->sc_flags & RTW_F_RTL8185) {
! 616: *locale = RTW_LOCALE_UNKNOWN;
! 617: return (0);
! 618: }
! 619:
! 620: switch (RTW_SR_GET(sr, RTW_SR_CONFIG0) & RTW8180_CONFIG0_GL_MASK) {
! 621: case RTW8180_CONFIG0_GL_USA:
! 622: *locale = RTW_LOCALE_USA;
! 623: break;
! 624: case RTW8180_CONFIG0_GL_EUROPE:
! 625: *locale = RTW_LOCALE_EUROPE;
! 626: break;
! 627: case RTW8180_CONFIG0_GL_JAPAN:
! 628: case RTW8180_CONFIG0_GL_JAPAN2:
! 629: *locale = RTW_LOCALE_JAPAN;
! 630: break;
! 631: default:
! 632: *locale = RTW_LOCALE_UNKNOWN;
! 633: break;
! 634: }
! 635: return 0;
! 636: }
! 637:
! 638: /* Returns -1 on failure. */
! 639: int
! 640: rtw_srom_read(struct rtw_regs *regs, u_int32_t flags, struct rtw_srom *sr,
! 641: const char *dvname)
! 642: {
! 643: int rc;
! 644: struct seeprom_descriptor sd;
! 645: u_int8_t ecr;
! 646:
! 647: bzero(&sd, sizeof(sd));
! 648:
! 649: ecr = RTW_READ8(regs, RTW_9346CR);
! 650:
! 651: if ((flags & RTW_F_9356SROM) != 0) {
! 652: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: 93c56 SROM\n", dvname));
! 653: sr->sr_size = 256;
! 654: sd.sd_chip = C56_66;
! 655: } else {
! 656: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: 93c46 SROM\n", dvname));
! 657: sr->sr_size = 128;
! 658: sd.sd_chip = C46;
! 659: }
! 660:
! 661: ecr &= ~(RTW_9346CR_EEDI | RTW_9346CR_EEDO | RTW_9346CR_EESK |
! 662: RTW_9346CR_EEM_MASK | RTW_9346CR_EECS);
! 663: ecr |= RTW_9346CR_EEM_PROGRAM;
! 664:
! 665: RTW_WRITE8(regs, RTW_9346CR, ecr);
! 666:
! 667: sr->sr_content = malloc(sr->sr_size, M_DEVBUF, M_NOWAIT);
! 668:
! 669: if (sr->sr_content == NULL) {
! 670: printf("%s: unable to allocate SROM buffer\n", dvname);
! 671: return ENOMEM;
! 672: }
! 673:
! 674: bzero(sr->sr_content, sr->sr_size);
! 675:
! 676: /* RTL8180 has a single 8-bit register for controlling the
! 677: * 93cx6 SROM. There is no "ready" bit. The RTL8180
! 678: * input/output sense is the reverse of read_seeprom's.
! 679: */
! 680: sd.sd_tag = regs->r_bt;
! 681: sd.sd_bsh = regs->r_bh;
! 682: sd.sd_regsize = 1;
! 683: sd.sd_control_offset = RTW_9346CR;
! 684: sd.sd_status_offset = RTW_9346CR;
! 685: sd.sd_dataout_offset = RTW_9346CR;
! 686: sd.sd_CK = RTW_9346CR_EESK;
! 687: sd.sd_CS = RTW_9346CR_EECS;
! 688: sd.sd_DI = RTW_9346CR_EEDO;
! 689: sd.sd_DO = RTW_9346CR_EEDI;
! 690: /* make read_seeprom enter EEPROM read/write mode */
! 691: sd.sd_MS = ecr;
! 692: sd.sd_RDY = 0;
! 693:
! 694: /* TBD bus barriers */
! 695: if (!read_seeprom(&sd, sr->sr_content, 0, sr->sr_size/2)) {
! 696: printf("\n%s: could not read SROM\n", dvname);
! 697: free(sr->sr_content, M_DEVBUF);
! 698: sr->sr_content = NULL;
! 699: return -1; /* XXX */
! 700: }
! 701:
! 702: /* end EEPROM read/write mode */
! 703: RTW_WRITE8(regs, RTW_9346CR,
! 704: (ecr & ~RTW_9346CR_EEM_MASK) | RTW_9346CR_EEM_NORMAL);
! 705: RTW_WBRW(regs, RTW_9346CR, RTW_9346CR);
! 706:
! 707: if ((rc = rtw_recall_eeprom(regs, dvname)) != 0)
! 708: return rc;
! 709:
! 710: #ifdef RTW_DEBUG
! 711: {
! 712: int i;
! 713: RTW_DPRINTF(RTW_DEBUG_ATTACH,
! 714: ("\n%s: serial ROM:\n\t", dvname));
! 715: for (i = 0; i < sr->sr_size/2; i++) {
! 716: if (((i % 8) == 0) && (i != 0))
! 717: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("\n\t"));
! 718: RTW_DPRINTF(RTW_DEBUG_ATTACH,
! 719: (" %04x", sr->sr_content[i]));
! 720: }
! 721: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("\n"));
! 722: }
! 723: #endif /* RTW_DEBUG */
! 724: return 0;
! 725: }
! 726:
! 727: void
! 728: rtw_set_rfprog(struct rtw_regs *regs, int rfchipid,
! 729: const char *dvname)
! 730: {
! 731: u_int8_t cfg4;
! 732: const char *method;
! 733:
! 734: cfg4 = RTW_READ8(regs, RTW_CONFIG4) & ~RTW_CONFIG4_RFTYPE_MASK;
! 735:
! 736: switch (rfchipid) {
! 737: default:
! 738: cfg4 |= LSHIFT(rtw_rfprog_fallback, RTW_CONFIG4_RFTYPE_MASK);
! 739: method = "fallback";
! 740: break;
! 741: case RTW_RFCHIPID_INTERSIL:
! 742: cfg4 |= RTW_CONFIG4_RFTYPE_INTERSIL;
! 743: method = "Intersil";
! 744: break;
! 745: case RTW_RFCHIPID_PHILIPS:
! 746: cfg4 |= RTW_CONFIG4_RFTYPE_PHILIPS;
! 747: method = "Philips";
! 748: break;
! 749: case RTW_RFCHIPID_RFMD2948:
! 750: cfg4 |= RTW_CONFIG4_RFTYPE_RFMD;
! 751: method = "RFMD";
! 752: break;
! 753: }
! 754:
! 755: RTW_WRITE8(regs, RTW_CONFIG4, cfg4);
! 756:
! 757: RTW_WBR(regs, RTW_CONFIG4, RTW_CONFIG4);
! 758:
! 759: RTW_DPRINTF(RTW_DEBUG_INIT,
! 760: ("%s: %s RF programming method, %#02x\n", dvname, method,
! 761: RTW_READ8(regs, RTW_CONFIG4)));
! 762: }
! 763:
! 764: void
! 765: rtw_init_channels(enum rtw_locale locale,
! 766: struct ieee80211_channel (*chans)[IEEE80211_CHAN_MAX+1],
! 767: const char *dvname)
! 768: {
! 769: int i;
! 770: const char *name = NULL;
! 771: #define ADD_CHANNEL(_chans, _chan) do { \
! 772: (*_chans)[_chan].ic_flags = IEEE80211_CHAN_B; \
! 773: (*_chans)[_chan].ic_freq = \
! 774: ieee80211_ieee2mhz(_chan, (*_chans)[_chan].ic_flags);\
! 775: } while (0)
! 776:
! 777: switch (locale) {
! 778: case RTW_LOCALE_USA: /* 1-11 */
! 779: name = "USA";
! 780: for (i = 1; i <= 11; i++)
! 781: ADD_CHANNEL(chans, i);
! 782: break;
! 783: case RTW_LOCALE_JAPAN: /* 1-14 */
! 784: name = "Japan";
! 785: ADD_CHANNEL(chans, 14);
! 786: for (i = 1; i <= 14; i++)
! 787: ADD_CHANNEL(chans, i);
! 788: break;
! 789: case RTW_LOCALE_EUROPE: /* 1-13 */
! 790: name = "Europe";
! 791: for (i = 1; i <= 13; i++)
! 792: ADD_CHANNEL(chans, i);
! 793: break;
! 794: default: /* 10-11 allowed by most countries */
! 795: name = "<unknown>";
! 796: for (i = 10; i <= 11; i++)
! 797: ADD_CHANNEL(chans, i);
! 798: break;
! 799: }
! 800: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: Geographic Location %s\n",
! 801: dvname, name));
! 802: #undef ADD_CHANNEL
! 803: }
! 804:
! 805: void
! 806: rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale)
! 807: {
! 808: u_int8_t cfg0 = RTW_READ8(regs, RTW_CONFIG0);
! 809:
! 810: switch (cfg0 & RTW8180_CONFIG0_GL_MASK) {
! 811: case RTW8180_CONFIG0_GL_USA:
! 812: *locale = RTW_LOCALE_USA;
! 813: break;
! 814: case RTW8180_CONFIG0_GL_JAPAN:
! 815: case RTW8180_CONFIG0_GL_JAPAN2:
! 816: *locale = RTW_LOCALE_JAPAN;
! 817: break;
! 818: case RTW8180_CONFIG0_GL_EUROPE:
! 819: *locale = RTW_LOCALE_EUROPE;
! 820: break;
! 821: default:
! 822: *locale = RTW_LOCALE_UNKNOWN;
! 823: break;
! 824: }
! 825: }
! 826:
! 827: int
! 828: rtw_identify_sta(struct rtw_regs *regs, u_int8_t (*addr)[IEEE80211_ADDR_LEN],
! 829: const char *dvname)
! 830: {
! 831: static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
! 832: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
! 833: };
! 834: u_int32_t idr0 = RTW_READ(regs, RTW_IDR0),
! 835: idr1 = RTW_READ(regs, RTW_IDR1);
! 836:
! 837: (*addr)[0] = MASK_AND_RSHIFT(idr0, BITS(0, 7));
! 838: (*addr)[1] = MASK_AND_RSHIFT(idr0, BITS(8, 15));
! 839: (*addr)[2] = MASK_AND_RSHIFT(idr0, BITS(16, 23));
! 840: (*addr)[3] = MASK_AND_RSHIFT(idr0, BITS(24 ,31));
! 841:
! 842: (*addr)[4] = MASK_AND_RSHIFT(idr1, BITS(0, 7));
! 843: (*addr)[5] = MASK_AND_RSHIFT(idr1, BITS(8, 15));
! 844:
! 845: if (IEEE80211_ADDR_EQ(addr, empty_macaddr)) {
! 846: printf("\n%s: could not get mac address, attach failed\n",
! 847: dvname);
! 848: return ENXIO;
! 849: }
! 850:
! 851: printf("address %s\n", ether_sprintf(*addr));
! 852:
! 853: return 0;
! 854: }
! 855:
! 856: u_int8_t
! 857: rtw_chan2txpower(struct rtw_srom *sr, struct ieee80211com *ic,
! 858: struct ieee80211_channel *chan)
! 859: {
! 860: u_int idx = RTW_SR_TXPOWER1 + ieee80211_chan2ieee(ic, chan) - 1;
! 861: KASSERT2(idx >= RTW_SR_TXPOWER1 && idx <= RTW_SR_TXPOWER14,
! 862: ("%s: channel %d out of range", __func__,
! 863: idx - RTW_SR_TXPOWER1 + 1));
! 864: return RTW_SR_GET(sr, idx);
! 865: }
! 866:
! 867: void
! 868: rtw_txdesc_blk_init_all(struct rtw_txdesc_blk *tdb)
! 869: {
! 870: int pri;
! 871: /* nfree: the number of free descriptors in each ring.
! 872: * The beacon ring is a special case: I do not let the
! 873: * driver use all of the descriptors on the beacon ring.
! 874: * The reasons are two-fold:
! 875: *
! 876: * (1) A BEACON descriptor's OWN bit is (apparently) not
! 877: * updated, so the driver cannot easily know if the descriptor
! 878: * belongs to it, or if it is racing the NIC. If the NIC
! 879: * does not OWN every descriptor, then the driver can safely
! 880: * update the descriptors when RTW_TBDA points at tdb_next.
! 881: *
! 882: * (2) I hope that the NIC will process more than one BEACON
! 883: * descriptor in a single beacon interval, since that will
! 884: * enable multiple-BSS support. Since the NIC does not
! 885: * clear the OWN bit, there is no natural place for it to
! 886: * stop processing BEACON desciptors. Maybe it will *not*
! 887: * stop processing them! I do not want to chance the NIC
! 888: * looping around and around a saturated beacon ring, so
! 889: * I will leave one descriptor unOWNed at all times.
! 890: */
! 891: u_int nfree[RTW_NTXPRI] =
! 892: {RTW_NTXDESCLO, RTW_NTXDESCMD, RTW_NTXDESCHI,
! 893: RTW_NTXDESCBCN - 1};
! 894:
! 895: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 896: tdb[pri].tdb_nfree = nfree[pri];
! 897: tdb[pri].tdb_next = 0;
! 898: }
! 899: }
! 900:
! 901: int
! 902: rtw_txsoft_blk_init(struct rtw_txsoft_blk *tsb)
! 903: {
! 904: int i;
! 905: struct rtw_txsoft *ts;
! 906:
! 907: SIMPLEQ_INIT(&tsb->tsb_dirtyq);
! 908: SIMPLEQ_INIT(&tsb->tsb_freeq);
! 909: for (i = 0; i < tsb->tsb_ndesc; i++) {
! 910: ts = &tsb->tsb_desc[i];
! 911: ts->ts_mbuf = NULL;
! 912: SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q);
! 913: }
! 914: tsb->tsb_tx_timer = 0;
! 915: return 0;
! 916: }
! 917:
! 918: void
! 919: rtw_txsoft_blk_init_all(struct rtw_txsoft_blk *tsb)
! 920: {
! 921: int pri;
! 922: for (pri = 0; pri < RTW_NTXPRI; pri++)
! 923: rtw_txsoft_blk_init(&tsb[pri]);
! 924: }
! 925:
! 926: void
! 927: rtw_rxdescs_sync(struct rtw_rxdesc_blk *rdb, int desc0, int nsync, int ops)
! 928: {
! 929: KASSERT(nsync <= rdb->rdb_ndesc);
! 930: /* sync to end of ring */
! 931: if (desc0 + nsync > rdb->rdb_ndesc) {
! 932: bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap,
! 933: offsetof(struct rtw_descs, hd_rx[desc0]),
! 934: sizeof(struct rtw_rxdesc) * (rdb->rdb_ndesc - desc0), ops);
! 935: nsync -= (rdb->rdb_ndesc - desc0);
! 936: desc0 = 0;
! 937: }
! 938:
! 939: KASSERT(desc0 < rdb->rdb_ndesc);
! 940: KASSERT(nsync <= rdb->rdb_ndesc);
! 941: KASSERT(desc0 + nsync <= rdb->rdb_ndesc);
! 942:
! 943: /* sync what remains */
! 944: bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap,
! 945: offsetof(struct rtw_descs, hd_rx[desc0]),
! 946: sizeof(struct rtw_rxdesc) * nsync, ops);
! 947: }
! 948:
! 949: void
! 950: rtw_txdescs_sync(struct rtw_txdesc_blk *tdb, u_int desc0, u_int nsync, int ops)
! 951: {
! 952: /* sync to end of ring */
! 953: if (desc0 + nsync > tdb->tdb_ndesc) {
! 954: bus_dmamap_sync(tdb->tdb_dmat, tdb->tdb_dmamap,
! 955: tdb->tdb_ofs + sizeof(struct rtw_txdesc) * desc0,
! 956: sizeof(struct rtw_txdesc) * (tdb->tdb_ndesc - desc0),
! 957: ops);
! 958: nsync -= (tdb->tdb_ndesc - desc0);
! 959: desc0 = 0;
! 960: }
! 961:
! 962: /* sync what remains */
! 963: bus_dmamap_sync(tdb->tdb_dmat, tdb->tdb_dmamap,
! 964: tdb->tdb_ofs + sizeof(struct rtw_txdesc) * desc0,
! 965: sizeof(struct rtw_txdesc) * nsync, ops);
! 966: }
! 967:
! 968: void
! 969: rtw_rxbufs_release(bus_dma_tag_t dmat, struct rtw_rxsoft *desc)
! 970: {
! 971: int i;
! 972: struct rtw_rxsoft *rs;
! 973:
! 974: for (i = 0; i < RTW_RXQLEN; i++) {
! 975: rs = &desc[i];
! 976: if (rs->rs_mbuf == NULL)
! 977: continue;
! 978: bus_dmamap_sync(dmat, rs->rs_dmamap, 0,
! 979: rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 980: bus_dmamap_unload(dmat, rs->rs_dmamap);
! 981: m_freem(rs->rs_mbuf);
! 982: rs->rs_mbuf = NULL;
! 983: }
! 984: }
! 985:
! 986: int
! 987: rtw_rxsoft_alloc(bus_dma_tag_t dmat, struct rtw_rxsoft *rs)
! 988: {
! 989: int rc;
! 990: struct mbuf *m;
! 991:
! 992: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 993: if (m == NULL)
! 994: return ENOBUFS;
! 995:
! 996: MCLGET(m, M_DONTWAIT);
! 997: if ((m->m_flags & M_EXT) == 0) {
! 998: m_freem(m);
! 999: return ENOBUFS;
! 1000: }
! 1001:
! 1002: m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
! 1003:
! 1004: if (rs->rs_mbuf != NULL)
! 1005: bus_dmamap_unload(dmat, rs->rs_dmamap);
! 1006:
! 1007: rs->rs_mbuf = NULL;
! 1008:
! 1009: rc = bus_dmamap_load_mbuf(dmat, rs->rs_dmamap, m, BUS_DMA_NOWAIT);
! 1010: if (rc != 0) {
! 1011: m_freem(m);
! 1012: return -1;
! 1013: }
! 1014:
! 1015: rs->rs_mbuf = m;
! 1016:
! 1017: return 0;
! 1018: }
! 1019:
! 1020: int
! 1021: rtw_rxsoft_init_all(bus_dma_tag_t dmat, struct rtw_rxsoft *desc,
! 1022: int *ndesc, const char *dvname)
! 1023: {
! 1024: int i, rc = 0;
! 1025: struct rtw_rxsoft *rs;
! 1026:
! 1027: for (i = 0; i < RTW_RXQLEN; i++) {
! 1028: rs = &desc[i];
! 1029: /* we're in rtw_init, so there should be no mbufs allocated */
! 1030: KASSERT(rs->rs_mbuf == NULL);
! 1031: #ifdef RTW_DEBUG
! 1032: if (i == rtw_rxbufs_limit) {
! 1033: printf("%s: TEST hit %d-buffer limit\n", dvname, i);
! 1034: rc = ENOBUFS;
! 1035: break;
! 1036: }
! 1037: #endif /* RTW_DEBUG */
! 1038: if ((rc = rtw_rxsoft_alloc(dmat, rs)) != 0) {
! 1039: printf("%s: rtw_rxsoft_alloc failed, %d buffers, "
! 1040: "rc %d\n", dvname, i, rc);
! 1041: break;
! 1042: }
! 1043: }
! 1044: *ndesc = i;
! 1045: return rc;
! 1046: }
! 1047:
! 1048: void
! 1049: rtw_rxdesc_init(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *rs,
! 1050: int idx, int kick)
! 1051: {
! 1052: int is_last = (idx == rdb->rdb_ndesc - 1);
! 1053: uint32_t ctl, octl, obuf;
! 1054: struct rtw_rxdesc *rd = &rdb->rdb_desc[idx];
! 1055:
! 1056: obuf = rd->rd_buf;
! 1057: rd->rd_buf = htole32(rs->rs_dmamap->dm_segs[0].ds_addr);
! 1058:
! 1059: ctl = LSHIFT(rs->rs_mbuf->m_len, RTW_RXCTL_LENGTH_MASK) |
! 1060: RTW_RXCTL_OWN | RTW_RXCTL_FS | RTW_RXCTL_LS;
! 1061:
! 1062: if (is_last)
! 1063: ctl |= RTW_RXCTL_EOR;
! 1064:
! 1065: octl = rd->rd_ctl;
! 1066: rd->rd_ctl = htole32(ctl);
! 1067:
! 1068: RTW_DPRINTF(kick ? (RTW_DEBUG_RECV_DESC | RTW_DEBUG_IO_KICK)
! 1069: : RTW_DEBUG_RECV_DESC,
! 1070: ("%s: rd %p buf %08x -> %08x ctl %08x -> %08x\n", __func__, rd,
! 1071: letoh32(obuf), letoh32(rd->rd_buf), letoh32(octl),
! 1072: letoh32(rd->rd_ctl)));
! 1073:
! 1074: /* sync the mbuf */
! 1075: bus_dmamap_sync(rdb->rdb_dmat, rs->rs_dmamap, 0,
! 1076: rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1077:
! 1078: /* sync the descriptor */
! 1079: bus_dmamap_sync(rdb->rdb_dmat, rdb->rdb_dmamap,
! 1080: RTW_DESC_OFFSET(hd_rx, idx), sizeof(struct rtw_rxdesc),
! 1081: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1082: }
! 1083:
! 1084: void
! 1085: rtw_rxdesc_init_all(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *ctl,
! 1086: int kick)
! 1087: {
! 1088: int i;
! 1089: struct rtw_rxdesc *rd;
! 1090: struct rtw_rxsoft *rs;
! 1091:
! 1092: for (i = 0; i < rdb->rdb_ndesc; i++) {
! 1093: rd = &rdb->rdb_desc[i];
! 1094: rs = &ctl[i];
! 1095: rtw_rxdesc_init(rdb, rs, i, kick);
! 1096: }
! 1097: }
! 1098:
! 1099: void
! 1100: rtw_io_enable(struct rtw_regs *regs, u_int8_t flags, int enable)
! 1101: {
! 1102: u_int8_t cr;
! 1103:
! 1104: RTW_DPRINTF(RTW_DEBUG_IOSTATE, ("%s: %s 0x%02x\n", __func__,
! 1105: enable ? "enable" : "disable", flags));
! 1106:
! 1107: cr = RTW_READ8(regs, RTW_CR);
! 1108:
! 1109: /* XXX reference source does not enable MULRW */
! 1110: #if 0
! 1111: /* enable PCI Read/Write Multiple */
! 1112: cr |= RTW_CR_MULRW;
! 1113: #endif
! 1114:
! 1115: RTW_RBW(regs, RTW_CR, RTW_CR); /* XXX paranoia? */
! 1116: if (enable)
! 1117: cr |= flags;
! 1118: else
! 1119: cr &= ~flags;
! 1120: RTW_WRITE8(regs, RTW_CR, cr);
! 1121: RTW_SYNC(regs, RTW_CR, RTW_CR);
! 1122: }
! 1123:
! 1124: void
! 1125: rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
! 1126: {
! 1127: #define IS_BEACON(__fc0) \
! 1128: ((__fc0 & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==\
! 1129: (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON))
! 1130:
! 1131: static const int ratetbl[4] = {2, 4, 11, 22}; /* convert rates:
! 1132: * hardware -> net80211
! 1133: */
! 1134: u_int next, nproc = 0;
! 1135: int hwrate, len, rate, rssi, sq;
! 1136: u_int32_t hrssi, hstat, htsfth, htsftl;
! 1137: struct rtw_rxdesc *rd;
! 1138: struct rtw_rxsoft *rs;
! 1139: struct rtw_rxdesc_blk *rdb;
! 1140: struct mbuf *m;
! 1141:
! 1142: struct ieee80211_node *ni;
! 1143: struct ieee80211_frame *wh;
! 1144:
! 1145: rdb = &sc->sc_rxdesc_blk;
! 1146:
! 1147: KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
! 1148:
! 1149: for (next = rdb->rdb_next; ; next = (next + 1) % rdb->rdb_ndesc) {
! 1150: rtw_rxdescs_sync(rdb, next, 1,
! 1151: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 1152: rd = &rdb->rdb_desc[next];
! 1153: rs = &sc->sc_rxsoft[next];
! 1154:
! 1155: hstat = letoh32(rd->rd_stat);
! 1156: hrssi = letoh32(rd->rd_rssi);
! 1157: htsfth = letoh32(rd->rd_tsfth);
! 1158: htsftl = letoh32(rd->rd_tsftl);
! 1159:
! 1160: RTW_DPRINTF(RTW_DEBUG_RECV_DESC,
! 1161: ("%s: rxdesc[%d] hstat %08x hrssi %08x htsft %08x%08x\n",
! 1162: __func__, next, hstat, hrssi, htsfth, htsftl));
! 1163:
! 1164: ++nproc;
! 1165:
! 1166: /* still belongs to NIC */
! 1167: if ((hstat & RTW_RXSTAT_OWN) != 0) {
! 1168: if (nproc > 1)
! 1169: break;
! 1170:
! 1171: /* sometimes the NIC skips to the 0th descriptor */
! 1172: rtw_rxdescs_sync(rdb, 0, 1,
! 1173: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 1174: rd = &rdb->rdb_desc[0];
! 1175: if ((rd->rd_stat & htole32(RTW_RXSTAT_OWN)) != 0)
! 1176: break;
! 1177: RTW_DPRINTF(RTW_DEBUG_BUGS,
! 1178: ("%s: NIC skipped from rxdesc[%u] to rxdesc[0]\n",
! 1179: sc->sc_dev.dv_xname, next));
! 1180: next = rdb->rdb_ndesc - 1;
! 1181: continue;
! 1182: }
! 1183:
! 1184: #ifdef RTW_DEBUG
! 1185: #define PRINTSTAT(flag) do { \
! 1186: if ((hstat & flag) != 0) { \
! 1187: printf("%s" #flag, delim); \
! 1188: delim = ","; \
! 1189: } \
! 1190: } while (0)
! 1191: if ((rtw_debug & RTW_DEBUG_RECV_DESC) != 0) {
! 1192: const char *delim = "<";
! 1193: printf("%s: ", sc->sc_dev.dv_xname);
! 1194: if ((hstat & RTW_RXSTAT_DEBUG) != 0) {
! 1195: printf("status %08x", hstat);
! 1196: PRINTSTAT(RTW_RXSTAT_SPLCP);
! 1197: PRINTSTAT(RTW_RXSTAT_MAR);
! 1198: PRINTSTAT(RTW_RXSTAT_PAR);
! 1199: PRINTSTAT(RTW_RXSTAT_BAR);
! 1200: PRINTSTAT(RTW_RXSTAT_PWRMGT);
! 1201: PRINTSTAT(RTW_RXSTAT_CRC32);
! 1202: PRINTSTAT(RTW_RXSTAT_ICV);
! 1203: printf(">, ");
! 1204: }
! 1205: }
! 1206: #undef PRINTSTAT
! 1207: #endif /* RTW_DEBUG */
! 1208:
! 1209: if ((hstat & RTW_RXSTAT_IOERROR) != 0) {
! 1210: printf("%s: DMA error/FIFO overflow %08x, "
! 1211: "rx descriptor %d\n", sc->sc_dev.dv_xname,
! 1212: hstat & RTW_RXSTAT_IOERROR, next);
! 1213: sc->sc_if.if_ierrors++;
! 1214: goto next;
! 1215: }
! 1216:
! 1217: len = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_LENGTH_MASK);
! 1218: if (len < IEEE80211_MIN_LEN) {
! 1219: sc->sc_ic.ic_stats.is_rx_tooshort++;
! 1220: goto next;
! 1221: }
! 1222:
! 1223: /* CRC is included with the packet; trim it off. */
! 1224: len -= IEEE80211_CRC_LEN;
! 1225:
! 1226: hwrate = MASK_AND_RSHIFT(hstat, RTW_RXSTAT_RATE_MASK);
! 1227: if (hwrate >= sizeof(ratetbl) / sizeof(ratetbl[0])) {
! 1228: printf("%s: unknown rate #%d\n", sc->sc_dev.dv_xname,
! 1229: MASK_AND_RSHIFT(hstat, RTW_RXSTAT_RATE_MASK));
! 1230: sc->sc_if.if_ierrors++;
! 1231: goto next;
! 1232: }
! 1233: rate = ratetbl[hwrate];
! 1234:
! 1235: #ifdef RTW_DEBUG
! 1236: RTW_DPRINTF(RTW_DEBUG_RECV_DESC,
! 1237: ("rate %d.%d Mb/s, time %08x%08x\n", (rate * 5) / 10,
! 1238: (rate * 5) % 10, htsfth, htsftl));
! 1239: #endif /* RTW_DEBUG */
! 1240:
! 1241: if ((hstat & RTW_RXSTAT_RES) != 0 &&
! 1242: sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR)
! 1243: goto next;
! 1244:
! 1245: /* if bad flags, skip descriptor */
! 1246: if ((hstat & RTW_RXSTAT_ONESEG) != RTW_RXSTAT_ONESEG) {
! 1247: printf("%s: too many rx segments\n",
! 1248: sc->sc_dev.dv_xname);
! 1249: goto next;
! 1250: }
! 1251:
! 1252: bus_dmamap_sync(sc->sc_dmat, rs->rs_dmamap, 0,
! 1253: rs->rs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1254:
! 1255: m = rs->rs_mbuf;
! 1256:
! 1257: /* if temporarily out of memory, re-use mbuf */
! 1258: switch (rtw_rxsoft_alloc(sc->sc_dmat, rs)) {
! 1259: case 0:
! 1260: break;
! 1261: case ENOBUFS:
! 1262: printf("%s: rtw_rxsoft_alloc(, %d) failed, "
! 1263: "dropping this packet\n", sc->sc_dev.dv_xname,
! 1264: next);
! 1265: goto next;
! 1266: default:
! 1267: /* XXX shorten rx ring, instead? */
! 1268: panic("%s: could not load DMA map",
! 1269: sc->sc_dev.dv_xname);
! 1270: }
! 1271:
! 1272: if (sc->sc_rfchipid == RTW_RFCHIPID_PHILIPS)
! 1273: rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_RSSI);
! 1274: else {
! 1275: rssi = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_IMR_RSSI);
! 1276: /* TBD find out each front-end's LNA gain in the
! 1277: * front-end's units
! 1278: */
! 1279: if ((hrssi & RTW_RXRSSI_IMR_LNA) == 0)
! 1280: rssi |= 0x80;
! 1281: }
! 1282:
! 1283: sq = MASK_AND_RSHIFT(hrssi, RTW_RXRSSI_SQ);
! 1284:
! 1285: /*
! 1286: * Note well: now we cannot recycle the rs_mbuf unless
! 1287: * we restore its original length.
! 1288: */
! 1289: m->m_pkthdr.rcvif = &sc->sc_if;
! 1290: m->m_pkthdr.len = m->m_len = len;
! 1291:
! 1292: wh = mtod(m, struct ieee80211_frame *);
! 1293:
! 1294: if (!IS_BEACON(wh->i_fc[0]))
! 1295: sc->sc_led_state.ls_event |= RTW_LED_S_RX;
! 1296: /* TBD use _MAR, _BAR, _PAR flags as hints to _find_rxnode? */
! 1297: ni = ieee80211_find_rxnode(&sc->sc_ic, wh);
! 1298:
! 1299: sc->sc_tsfth = htsfth;
! 1300:
! 1301: #ifdef RTW_DEBUG
! 1302: if ((sc->sc_if.if_flags & (IFF_DEBUG|IFF_LINK2)) ==
! 1303: (IFF_DEBUG|IFF_LINK2)) {
! 1304: ieee80211_dump_pkt(mtod(m, uint8_t *), m->m_pkthdr.len,
! 1305: rate, rssi);
! 1306: }
! 1307: #endif /* RTW_DEBUG */
! 1308:
! 1309: #if NBPFILTER > 0
! 1310: if (sc->sc_radiobpf != NULL) {
! 1311: struct mbuf mb;
! 1312: struct ieee80211com *ic = &sc->sc_ic;
! 1313: struct rtw_rx_radiotap_header *rr = &sc->sc_rxtap;
! 1314:
! 1315: rr->rr_tsft =
! 1316: htole64(((uint64_t)htsfth << 32) | htsftl);
! 1317:
! 1318: if ((hstat & RTW_RXSTAT_SPLCP) != 0)
! 1319: rr->rr_flags = IEEE80211_RADIOTAP_F_SHORTPRE;
! 1320:
! 1321: rr->rr_flags = 0;
! 1322: rr->rr_rate = rate;
! 1323: rr->rr_chan_freq =
! 1324: htole16(ic->ic_bss->ni_chan->ic_freq);
! 1325: rr->rr_chan_flags =
! 1326: htole16(ic->ic_bss->ni_chan->ic_flags);
! 1327: rr->rr_antsignal = rssi;
! 1328: rr->rr_barker_lock = htole16(sq);
! 1329:
! 1330: mb.m_data = (caddr_t)rr;
! 1331: mb.m_len = sizeof(sc->sc_rxtapu);
! 1332: mb.m_next = m;
! 1333: mb.m_nextpkt = NULL;
! 1334: mb.m_type = 0;
! 1335: mb.m_flags = 0;
! 1336: bpf_mtap(sc->sc_radiobpf, &mb, BPF_DIRECTION_IN);
! 1337: }
! 1338: #endif /* NPBFILTER > 0 */
! 1339:
! 1340: ieee80211_input(&sc->sc_if, m, ni, rssi, htsftl);
! 1341: ieee80211_release_node(&sc->sc_ic, ni);
! 1342: next:
! 1343: rtw_rxdesc_init(rdb, rs, next, 0);
! 1344: }
! 1345: rdb->rdb_next = next;
! 1346:
! 1347: KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
! 1348:
! 1349: /*
! 1350: * In HostAP mode, ieee80211_input() will enqueue packets in if_snd
! 1351: * without calling if_start().
! 1352: */
! 1353: if (!IFQ_IS_EMPTY(&sc->sc_if.if_snd) &&
! 1354: !(sc->sc_if.if_flags & IFF_OACTIVE))
! 1355: (*sc->sc_if.if_start)(&sc->sc_if);
! 1356:
! 1357: return;
! 1358: #undef IS_BEACON
! 1359: }
! 1360:
! 1361: void
! 1362: rtw_txsoft_release(bus_dma_tag_t dmat, struct ieee80211com *ic,
! 1363: struct rtw_txsoft *ts)
! 1364: {
! 1365: struct mbuf *m;
! 1366: struct ieee80211_node *ni;
! 1367:
! 1368: m = ts->ts_mbuf;
! 1369: ni = ts->ts_ni;
! 1370: KASSERT(m != NULL);
! 1371: KASSERT(ni != NULL);
! 1372: ts->ts_mbuf = NULL;
! 1373: ts->ts_ni = NULL;
! 1374:
! 1375: bus_dmamap_sync(dmat, ts->ts_dmamap, 0, ts->ts_dmamap->dm_mapsize,
! 1376: BUS_DMASYNC_POSTWRITE);
! 1377: bus_dmamap_unload(dmat, ts->ts_dmamap);
! 1378: m_freem(m);
! 1379: ieee80211_release_node(ic, ni);
! 1380: }
! 1381:
! 1382: void
! 1383: rtw_txsofts_release(bus_dma_tag_t dmat, struct ieee80211com *ic,
! 1384: struct rtw_txsoft_blk *tsb)
! 1385: {
! 1386: struct rtw_txsoft *ts;
! 1387:
! 1388: while ((ts = SIMPLEQ_FIRST(&tsb->tsb_dirtyq)) != NULL) {
! 1389: rtw_txsoft_release(dmat, ic, ts);
! 1390: SIMPLEQ_REMOVE_HEAD(&tsb->tsb_dirtyq, ts_q);
! 1391: SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q);
! 1392: }
! 1393: tsb->tsb_tx_timer = 0;
! 1394: }
! 1395:
! 1396: void
! 1397: rtw_collect_txpkt(struct rtw_softc *sc, struct rtw_txdesc_blk *tdb,
! 1398: struct rtw_txsoft *ts, int ndesc)
! 1399: {
! 1400: uint32_t hstat;
! 1401: int data_retry, rts_retry;
! 1402: struct rtw_txdesc *tdn;
! 1403: const char *condstring;
! 1404:
! 1405: rtw_txsoft_release(sc->sc_dmat, &sc->sc_ic, ts);
! 1406:
! 1407: tdb->tdb_nfree += ndesc;
! 1408:
! 1409: tdn = &tdb->tdb_desc[ts->ts_last];
! 1410:
! 1411: hstat = letoh32(tdn->td_stat);
! 1412: rts_retry = MASK_AND_RSHIFT(hstat, RTW_TXSTAT_RTSRETRY_MASK);
! 1413: data_retry = MASK_AND_RSHIFT(hstat, RTW_TXSTAT_DRC_MASK);
! 1414:
! 1415: sc->sc_if.if_collisions += rts_retry + data_retry;
! 1416:
! 1417: if ((hstat & RTW_TXSTAT_TOK) != 0)
! 1418: condstring = "ok";
! 1419: else {
! 1420: sc->sc_if.if_oerrors++;
! 1421: condstring = "error";
! 1422: }
! 1423:
! 1424: DPRINTF(sc, RTW_DEBUG_XMIT_DESC,
! 1425: ("%s: ts %p txdesc[%d, %d] %s tries rts %u data %u\n",
! 1426: sc->sc_dev.dv_xname, ts, ts->ts_first, ts->ts_last,
! 1427: condstring, rts_retry, data_retry));
! 1428: }
! 1429:
! 1430: void
! 1431: rtw_reset_oactive(struct rtw_softc *sc)
! 1432: {
! 1433: short oflags;
! 1434: int pri;
! 1435: struct rtw_txsoft_blk *tsb;
! 1436: struct rtw_txdesc_blk *tdb;
! 1437: oflags = sc->sc_if.if_flags;
! 1438: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1439: tsb = &sc->sc_txsoft_blk[pri];
! 1440: tdb = &sc->sc_txdesc_blk[pri];
! 1441: if (!SIMPLEQ_EMPTY(&tsb->tsb_freeq) && tdb->tdb_nfree > 0)
! 1442: sc->sc_if.if_flags &= ~IFF_OACTIVE;
! 1443: }
! 1444: if (oflags != sc->sc_if.if_flags) {
! 1445: DPRINTF(sc, RTW_DEBUG_OACTIVE,
! 1446: ("%s: reset OACTIVE\n", __func__));
! 1447: }
! 1448: }
! 1449:
! 1450: /* Collect transmitted packets. */
! 1451: void
! 1452: rtw_collect_txring(struct rtw_softc *sc, struct rtw_txsoft_blk *tsb,
! 1453: struct rtw_txdesc_blk *tdb, int force)
! 1454: {
! 1455: int ndesc;
! 1456: struct rtw_txsoft *ts;
! 1457:
! 1458: while ((ts = SIMPLEQ_FIRST(&tsb->tsb_dirtyq)) != NULL) {
! 1459: ndesc = 1 + ts->ts_last - ts->ts_first;
! 1460: if (ts->ts_last < ts->ts_first)
! 1461: ndesc += tdb->tdb_ndesc;
! 1462:
! 1463: KASSERT(ndesc > 0);
! 1464:
! 1465: rtw_txdescs_sync(tdb, ts->ts_first, ndesc,
! 1466: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 1467:
! 1468: if (force) {
! 1469: int i;
! 1470: for (i = ts->ts_first; ; i = RTW_NEXT_IDX(tdb, i)) {
! 1471: tdb->tdb_desc[i].td_stat &=
! 1472: ~htole32(RTW_TXSTAT_OWN);
! 1473: if (i == ts->ts_last)
! 1474: break;
! 1475: }
! 1476: rtw_txdescs_sync(tdb, ts->ts_first, ndesc,
! 1477: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1478: } else if ((tdb->tdb_desc[ts->ts_last].td_stat &
! 1479: htole32(RTW_TXSTAT_OWN)) != 0)
! 1480: break;
! 1481:
! 1482: rtw_collect_txpkt(sc, tdb, ts, ndesc);
! 1483: SIMPLEQ_REMOVE_HEAD(&tsb->tsb_dirtyq, ts_q);
! 1484: SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q);
! 1485: }
! 1486: /* no more pending transmissions, cancel watchdog */
! 1487: if (ts == NULL)
! 1488: tsb->tsb_tx_timer = 0;
! 1489: rtw_reset_oactive(sc);
! 1490: }
! 1491:
! 1492: void
! 1493: rtw_intr_tx(struct rtw_softc *sc, u_int16_t isr)
! 1494: {
! 1495: int pri;
! 1496: struct rtw_txsoft_blk *tsb;
! 1497: struct rtw_txdesc_blk *tdb;
! 1498:
! 1499: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1500: tsb = &sc->sc_txsoft_blk[pri];
! 1501: tdb = &sc->sc_txdesc_blk[pri];
! 1502:
! 1503: rtw_collect_txring(sc, tsb, tdb, 0);
! 1504:
! 1505: }
! 1506:
! 1507: if ((isr & RTW_INTR_TX) != 0)
! 1508: rtw_start(&sc->sc_if);
! 1509: }
! 1510:
! 1511: void
! 1512: rtw_intr_beacon(struct rtw_softc *sc, u_int16_t isr)
! 1513: {
! 1514: u_int next;
! 1515: uint32_t tsfth, tsftl;
! 1516: struct ieee80211com *ic;
! 1517: struct rtw_txdesc_blk *tdb = &sc->sc_txdesc_blk[RTW_TXPRIBCN];
! 1518: struct rtw_txsoft_blk *tsb = &sc->sc_txsoft_blk[RTW_TXPRIBCN];
! 1519: struct mbuf *m;
! 1520:
! 1521: tsfth = RTW_READ(&sc->sc_regs, RTW_TSFTRH);
! 1522: tsftl = RTW_READ(&sc->sc_regs, RTW_TSFTRL);
! 1523:
! 1524: if ((isr & (RTW_INTR_TBDOK|RTW_INTR_TBDER)) != 0) {
! 1525: next = rtw_txring_next(&sc->sc_regs, tdb);
! 1526: RTW_DPRINTF(RTW_DEBUG_BEACON,
! 1527: ("%s: beacon ring %sprocessed, isr = %#04hx"
! 1528: ", next %u expected %u, %llu\n", __func__,
! 1529: (next == tdb->tdb_next) ? "" : "un", isr, next,
! 1530: tdb->tdb_next, (uint64_t)tsfth << 32 | tsftl));
! 1531: if ((RTW_READ8(&sc->sc_regs, RTW_TPPOLL) & RTW_TPPOLL_BQ) == 0){
! 1532: rtw_collect_txring(sc, tsb, tdb, 1);
! 1533: tdb->tdb_next = 0;
! 1534: }
! 1535: }
! 1536: /* Start beacon transmission. */
! 1537:
! 1538: if ((isr & RTW_INTR_BCNINT) != 0 &&
! 1539: sc->sc_ic.ic_state == IEEE80211_S_RUN &&
! 1540: SIMPLEQ_EMPTY(&tsb->tsb_dirtyq)) {
! 1541: RTW_DPRINTF(RTW_DEBUG_BEACON,
! 1542: ("%s: beacon prep. time, isr = %#04hx"
! 1543: ", %16llu\n", __func__, isr,
! 1544: (uint64_t)tsfth << 32 | tsftl));
! 1545: ic = &sc->sc_ic;
! 1546: if ((m = ieee80211_beacon_alloc(ic, ic->ic_bss)) != NULL) {
! 1547: RTW_DPRINTF(RTW_DEBUG_BEACON,
! 1548: ("%s: m %p len %u\n", __func__, m, m->m_len));
! 1549: }
! 1550:
! 1551: if (m == NULL) {
! 1552: printf("%s: could not allocate beacon\n",
! 1553: sc->sc_dev.dv_xname);
! 1554: return;
! 1555: }
! 1556: m->m_pkthdr.rcvif = (void *)ieee80211_ref_node(ic->ic_bss);
! 1557: IF_ENQUEUE(&sc->sc_beaconq, m);
! 1558: rtw_start(&sc->sc_if);
! 1559: }
! 1560: }
! 1561:
! 1562: void
! 1563: rtw_intr_atim(struct rtw_softc *sc)
! 1564: {
! 1565: /* TBD */
! 1566: return;
! 1567: }
! 1568:
! 1569: #ifdef RTW_DEBUG
! 1570: void
! 1571: rtw_dump_rings(struct rtw_softc *sc)
! 1572: {
! 1573: struct rtw_txdesc_blk *tdb;
! 1574: struct rtw_rxdesc *rd;
! 1575: struct rtw_rxdesc_blk *rdb;
! 1576: int desc, pri;
! 1577:
! 1578: if ((rtw_debug & RTW_DEBUG_IO_KICK) == 0)
! 1579: return;
! 1580:
! 1581: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1582: tdb = &sc->sc_txdesc_blk[pri];
! 1583: printf("%s: txpri %d ndesc %d nfree %d\n", __func__, pri,
! 1584: tdb->tdb_ndesc, tdb->tdb_nfree);
! 1585: for (desc = 0; desc < tdb->tdb_ndesc; desc++)
! 1586: rtw_print_txdesc(sc, ".", NULL, tdb, desc);
! 1587: }
! 1588:
! 1589: rdb = &sc->sc_rxdesc_blk;
! 1590:
! 1591: for (desc = 0; desc < RTW_RXQLEN; desc++) {
! 1592: rd = &rdb->rdb_desc[desc];
! 1593: printf("%s: %sctl %08x rsvd0/rssi %08x buf/tsftl %08x "
! 1594: "rsvd1/tsfth %08x\n", __func__,
! 1595: (desc >= rdb->rdb_ndesc) ? "UNUSED " : "",
! 1596: letoh32(rd->rd_ctl), letoh32(rd->rd_rssi),
! 1597: letoh32(rd->rd_buf), letoh32(rd->rd_tsfth));
! 1598: }
! 1599: }
! 1600: #endif /* RTW_DEBUG */
! 1601:
! 1602: void
! 1603: rtw_hwring_setup(struct rtw_softc *sc)
! 1604: {
! 1605: int pri;
! 1606: struct rtw_regs *regs = &sc->sc_regs;
! 1607: struct rtw_txdesc_blk *tdb;
! 1608:
! 1609: sc->sc_txdesc_blk[RTW_TXPRILO].tdb_basereg = RTW_TLPDA;
! 1610: sc->sc_txdesc_blk[RTW_TXPRILO].tdb_base = RTW_RING_BASE(sc, hd_txlo);
! 1611: sc->sc_txdesc_blk[RTW_TXPRIMD].tdb_basereg = RTW_TNPDA;
! 1612: sc->sc_txdesc_blk[RTW_TXPRIMD].tdb_base = RTW_RING_BASE(sc, hd_txmd);
! 1613: sc->sc_txdesc_blk[RTW_TXPRIHI].tdb_basereg = RTW_THPDA;
! 1614: sc->sc_txdesc_blk[RTW_TXPRIHI].tdb_base = RTW_RING_BASE(sc, hd_txhi);
! 1615: sc->sc_txdesc_blk[RTW_TXPRIBCN].tdb_basereg = RTW_TBDA;
! 1616: sc->sc_txdesc_blk[RTW_TXPRIBCN].tdb_base = RTW_RING_BASE(sc, hd_bcn);
! 1617:
! 1618: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1619: tdb = &sc->sc_txdesc_blk[pri];
! 1620: RTW_WRITE(regs, tdb->tdb_basereg, tdb->tdb_base);
! 1621: RTW_DPRINTF(RTW_DEBUG_XMIT_DESC,
! 1622: ("%s: reg[tdb->tdb_basereg] <- %lx\n", __func__,
! 1623: (u_int *)tdb->tdb_base));
! 1624: }
! 1625:
! 1626: RTW_WRITE(regs, RTW_RDSAR, RTW_RING_BASE(sc, hd_rx));
! 1627:
! 1628: RTW_DPRINTF(RTW_DEBUG_RECV_DESC,
! 1629: ("%s: reg[RDSAR] <- %lx\n", __func__,
! 1630: (u_int *)RTW_RING_BASE(sc, hd_rx)));
! 1631:
! 1632: RTW_SYNC(regs, RTW_TLPDA, RTW_RDSAR);
! 1633: }
! 1634:
! 1635: int
! 1636: rtw_swring_setup(struct rtw_softc *sc)
! 1637: {
! 1638: int rc, pri;
! 1639: struct rtw_rxdesc_blk *rdb;
! 1640: struct rtw_txdesc_blk *tdb;
! 1641:
! 1642: rtw_txdesc_blk_init_all(&sc->sc_txdesc_blk[0]);
! 1643:
! 1644: rtw_txsoft_blk_init_all(&sc->sc_txsoft_blk[0]);
! 1645:
! 1646: rdb = &sc->sc_rxdesc_blk;
! 1647: if ((rc = rtw_rxsoft_init_all(sc->sc_dmat, sc->sc_rxsoft,
! 1648: &rdb->rdb_ndesc, sc->sc_dev.dv_xname)) != 0 &&
! 1649: rdb->rdb_ndesc == 0) {
! 1650: printf("%s: could not allocate rx buffers\n",
! 1651: sc->sc_dev.dv_xname);
! 1652: return rc;
! 1653: }
! 1654:
! 1655: rdb = &sc->sc_rxdesc_blk;
! 1656: rtw_rxdescs_sync(rdb, 0, rdb->rdb_ndesc,
! 1657: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 1658: rtw_rxdesc_init_all(rdb, sc->sc_rxsoft, 1);
! 1659: rdb->rdb_next = 0;
! 1660:
! 1661: tdb = &sc->sc_txdesc_blk[0];
! 1662: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1663: rtw_txdescs_sync(&tdb[pri], 0, tdb[pri].tdb_ndesc,
! 1664: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 1665: }
! 1666: return 0;
! 1667: }
! 1668:
! 1669: void
! 1670: rtw_txdesc_blk_init(struct rtw_txdesc_blk *tdb)
! 1671: {
! 1672: int i;
! 1673:
! 1674: bzero(tdb->tdb_desc, sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc);
! 1675: for (i = 0; i < tdb->tdb_ndesc; i++)
! 1676: tdb->tdb_desc[i].td_next = htole32(RTW_NEXT_DESC(tdb, i));
! 1677: }
! 1678:
! 1679: u_int
! 1680: rtw_txring_next(struct rtw_regs *regs, struct rtw_txdesc_blk *tdb)
! 1681: {
! 1682: return (letoh32(RTW_READ(regs, tdb->tdb_basereg)) - tdb->tdb_base) /
! 1683: sizeof(struct rtw_txdesc);
! 1684: }
! 1685:
! 1686: void
! 1687: rtw_txring_fixup(struct rtw_softc *sc)
! 1688: {
! 1689: int pri;
! 1690: u_int next;
! 1691: struct rtw_txdesc_blk *tdb;
! 1692: struct rtw_regs *regs = &sc->sc_regs;
! 1693:
! 1694: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1695: tdb = &sc->sc_txdesc_blk[pri];
! 1696: next = rtw_txring_next(regs, tdb);
! 1697: if (tdb->tdb_next == next)
! 1698: continue;
! 1699: RTW_DPRINTF(RTW_DEBUG_BUGS,
! 1700: ("%s: tx-ring %d expected next %u, read %u\n", __func__,
! 1701: pri, tdb->tdb_next, next));
! 1702: tdb->tdb_next = MIN(next, tdb->tdb_ndesc - 1);
! 1703: }
! 1704: }
! 1705:
! 1706: void
! 1707: rtw_rxring_fixup(struct rtw_softc *sc)
! 1708: {
! 1709: u_int next;
! 1710: uint32_t rdsar;
! 1711: struct rtw_rxdesc_blk *rdb;
! 1712:
! 1713: rdsar = letoh32(RTW_READ(&sc->sc_regs, RTW_RDSAR));
! 1714: next = (rdsar - RTW_RING_BASE(sc, hd_rx)) / sizeof(struct rtw_rxdesc);
! 1715:
! 1716: rdb = &sc->sc_rxdesc_blk;
! 1717: if (rdb->rdb_next != next) {
! 1718: RTW_DPRINTF(RTW_DEBUG_BUGS,
! 1719: ("%s: rx-ring expected next %u, read %u\n", __func__,
! 1720: rdb->rdb_next, next));
! 1721: rdb->rdb_next = MIN(next, rdb->rdb_ndesc - 1);
! 1722: }
! 1723: }
! 1724:
! 1725: void
! 1726: rtw_txdescs_reset(struct rtw_softc *sc)
! 1727: {
! 1728: int pri;
! 1729:
! 1730: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1731: rtw_collect_txring(sc, &sc->sc_txsoft_blk[pri],
! 1732: &sc->sc_txdesc_blk[pri], 1);
! 1733: }
! 1734: }
! 1735:
! 1736: void
! 1737: rtw_intr_ioerror(struct rtw_softc *sc, u_int16_t isr)
! 1738: {
! 1739: uint8_t cr = 0;
! 1740: int xmtr = 0, rcvr = 0;
! 1741: struct rtw_regs *regs = &sc->sc_regs;
! 1742:
! 1743: if ((isr & RTW_INTR_TXFOVW) != 0) {
! 1744: RTW_DPRINTF(RTW_DEBUG_BUGS,
! 1745: ("%s: tx fifo underflow\n", sc->sc_dev.dv_xname));
! 1746: rcvr = xmtr = 1;
! 1747: cr |= RTW_CR_TE | RTW_CR_RE;
! 1748: }
! 1749:
! 1750: if ((isr & (RTW_INTR_RDU|RTW_INTR_RXFOVW)) != 0) {
! 1751: cr |= RTW_CR_RE;
! 1752: rcvr = 1;
! 1753: }
! 1754:
! 1755: RTW_DPRINTF(RTW_DEBUG_BUGS, ("%s: restarting xmit/recv, isr %hx"
! 1756: "\n", sc->sc_dev.dv_xname, isr));
! 1757:
! 1758: #ifdef RTW_DEBUG
! 1759: rtw_dump_rings(sc);
! 1760: #endif /* RTW_DEBUG */
! 1761:
! 1762: rtw_io_enable(regs, cr, 0);
! 1763:
! 1764: /* Collect rx'd packets. Refresh rx buffers. */
! 1765: if (rcvr)
! 1766: rtw_intr_rx(sc, 0);
! 1767: /* Collect tx'd packets. XXX let's hope this stops the transmit
! 1768: * timeouts.
! 1769: */
! 1770: if (xmtr)
! 1771: rtw_txdescs_reset(sc);
! 1772:
! 1773: RTW_WRITE16(regs, RTW_IMR, 0);
! 1774: RTW_SYNC(regs, RTW_IMR, RTW_IMR);
! 1775:
! 1776: if (rtw_do_chip_reset) {
! 1777: rtw_chip_reset1(regs, sc->sc_dev.dv_xname);
! 1778: }
! 1779:
! 1780: rtw_rxdesc_init_all(&sc->sc_rxdesc_blk, &sc->sc_rxsoft[0], 1);
! 1781:
! 1782: #ifdef RTW_DEBUG
! 1783: rtw_dump_rings(sc);
! 1784: #endif /* RTW_DEBUG */
! 1785:
! 1786: RTW_WRITE16(regs, RTW_IMR, sc->sc_inten);
! 1787: RTW_SYNC(regs, RTW_IMR, RTW_IMR);
! 1788: if (rcvr)
! 1789: rtw_rxring_fixup(sc);
! 1790: rtw_io_enable(regs, cr, 1);
! 1791: if (xmtr)
! 1792: rtw_txring_fixup(sc);
! 1793: }
! 1794:
! 1795: void
! 1796: rtw_suspend_ticks(struct rtw_softc *sc)
! 1797: {
! 1798: RTW_DPRINTF(RTW_DEBUG_TIMEOUT,
! 1799: ("%s: suspending ticks\n", sc->sc_dev.dv_xname));
! 1800: sc->sc_do_tick = 0;
! 1801: }
! 1802:
! 1803: void
! 1804: rtw_resume_ticks(struct rtw_softc *sc)
! 1805: {
! 1806: u_int32_t tsftrl0, tsftrl1, next_tick;
! 1807:
! 1808: tsftrl0 = RTW_READ(&sc->sc_regs, RTW_TSFTRL);
! 1809:
! 1810: tsftrl1 = RTW_READ(&sc->sc_regs, RTW_TSFTRL);
! 1811: next_tick = tsftrl1 + 1000000;
! 1812: RTW_WRITE(&sc->sc_regs, RTW_TINT, next_tick);
! 1813:
! 1814: sc->sc_do_tick = 1;
! 1815:
! 1816: RTW_DPRINTF(RTW_DEBUG_TIMEOUT,
! 1817: ("%s: resume ticks delta %#08x now %#08x next %#08x\n",
! 1818: sc->sc_dev.dv_xname, tsftrl1 - tsftrl0, tsftrl1, next_tick));
! 1819: }
! 1820:
! 1821: void
! 1822: rtw_intr_timeout(struct rtw_softc *sc)
! 1823: {
! 1824: RTW_DPRINTF(RTW_DEBUG_TIMEOUT, ("%s: timeout\n", sc->sc_dev.dv_xname));
! 1825: if (sc->sc_do_tick)
! 1826: rtw_resume_ticks(sc);
! 1827: return;
! 1828: }
! 1829:
! 1830: int
! 1831: rtw_intr(void *arg)
! 1832: {
! 1833: int i;
! 1834: struct rtw_softc *sc = arg;
! 1835: struct rtw_regs *regs = &sc->sc_regs;
! 1836: u_int16_t isr;
! 1837:
! 1838: /*
! 1839: * If the interface isn't running, the interrupt couldn't
! 1840: * possibly have come from us.
! 1841: */
! 1842: if ((sc->sc_flags & RTW_F_ENABLED) == 0 ||
! 1843: (sc->sc_if.if_flags & IFF_RUNNING) == 0 ||
! 1844: (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) {
! 1845: RTW_DPRINTF(RTW_DEBUG_INTR, ("%s: stray interrupt\n",
! 1846: sc->sc_dev.dv_xname));
! 1847: return (0);
! 1848: }
! 1849:
! 1850: for (i = 0; i < 10; i++) {
! 1851: isr = RTW_READ16(regs, RTW_ISR);
! 1852:
! 1853: RTW_WRITE16(regs, RTW_ISR, isr);
! 1854: RTW_WBR(regs, RTW_ISR, RTW_ISR);
! 1855:
! 1856: if (sc->sc_intr_ack != NULL)
! 1857: (*sc->sc_intr_ack)(regs);
! 1858:
! 1859: if (isr == 0)
! 1860: break;
! 1861:
! 1862: #ifdef RTW_DEBUG
! 1863: #define PRINTINTR(flag) do { \
! 1864: if ((isr & flag) != 0) { \
! 1865: printf("%s" #flag, delim); \
! 1866: delim = ","; \
! 1867: } \
! 1868: } while (0)
! 1869:
! 1870: if ((rtw_debug & RTW_DEBUG_INTR) != 0 && isr != 0) {
! 1871: const char *delim = "<";
! 1872:
! 1873: printf("%s: reg[ISR] = %x", sc->sc_dev.dv_xname, isr);
! 1874:
! 1875: PRINTINTR(RTW_INTR_TXFOVW);
! 1876: PRINTINTR(RTW_INTR_TIMEOUT);
! 1877: PRINTINTR(RTW_INTR_BCNINT);
! 1878: PRINTINTR(RTW_INTR_ATIMINT);
! 1879: PRINTINTR(RTW_INTR_TBDER);
! 1880: PRINTINTR(RTW_INTR_TBDOK);
! 1881: PRINTINTR(RTW_INTR_THPDER);
! 1882: PRINTINTR(RTW_INTR_THPDOK);
! 1883: PRINTINTR(RTW_INTR_TNPDER);
! 1884: PRINTINTR(RTW_INTR_TNPDOK);
! 1885: PRINTINTR(RTW_INTR_RXFOVW);
! 1886: PRINTINTR(RTW_INTR_RDU);
! 1887: PRINTINTR(RTW_INTR_TLPDER);
! 1888: PRINTINTR(RTW_INTR_TLPDOK);
! 1889: PRINTINTR(RTW_INTR_RER);
! 1890: PRINTINTR(RTW_INTR_ROK);
! 1891:
! 1892: printf(">\n");
! 1893: }
! 1894: #undef PRINTINTR
! 1895: #endif /* RTW_DEBUG */
! 1896:
! 1897: if ((isr & RTW_INTR_RX) != 0)
! 1898: rtw_intr_rx(sc, isr & RTW_INTR_RX);
! 1899: if ((isr & RTW_INTR_TX) != 0)
! 1900: rtw_intr_tx(sc, isr & RTW_INTR_TX);
! 1901: if ((isr & RTW_INTR_BEACON) != 0)
! 1902: rtw_intr_beacon(sc, isr & RTW_INTR_BEACON);
! 1903: if ((isr & RTW_INTR_ATIMINT) != 0)
! 1904: rtw_intr_atim(sc);
! 1905: if ((isr & RTW_INTR_IOERROR) != 0)
! 1906: rtw_intr_ioerror(sc, isr & RTW_INTR_IOERROR);
! 1907: if ((isr & RTW_INTR_TIMEOUT) != 0)
! 1908: rtw_intr_timeout(sc);
! 1909: }
! 1910:
! 1911: return 1;
! 1912: }
! 1913:
! 1914: /* Must be called at splnet. */
! 1915: void
! 1916: rtw_stop(struct ifnet *ifp, int disable)
! 1917: {
! 1918: int pri;
! 1919: struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc;
! 1920: struct ieee80211com *ic = &sc->sc_ic;
! 1921: struct rtw_regs *regs = &sc->sc_regs;
! 1922:
! 1923: if ((sc->sc_flags & RTW_F_ENABLED) == 0)
! 1924: return;
! 1925:
! 1926: rtw_suspend_ticks(sc);
! 1927:
! 1928: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
! 1929:
! 1930: if ((sc->sc_flags & RTW_F_INVALID) == 0) {
! 1931: /* Disable interrupts. */
! 1932: RTW_WRITE16(regs, RTW_IMR, 0);
! 1933:
! 1934: RTW_WBW(regs, RTW_TPPOLL, RTW_IMR);
! 1935:
! 1936: /* Stop the transmit and receive processes. First stop DMA,
! 1937: * then disable receiver and transmitter.
! 1938: */
! 1939: RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
! 1940:
! 1941: RTW_SYNC(regs, RTW_TPPOLL, RTW_IMR);
! 1942:
! 1943: rtw_io_enable(&sc->sc_regs, RTW_CR_RE|RTW_CR_TE, 0);
! 1944: }
! 1945:
! 1946: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 1947: rtw_txsofts_release(sc->sc_dmat, &sc->sc_ic,
! 1948: &sc->sc_txsoft_blk[pri]);
! 1949: }
! 1950:
! 1951: rtw_rxbufs_release(sc->sc_dmat, &sc->sc_rxsoft[0]);
! 1952:
! 1953: if (disable)
! 1954: rtw_disable(sc);
! 1955:
! 1956: /* Mark the interface as not running. Cancel the watchdog timer. */
! 1957: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1958: ifp->if_timer = 0;
! 1959:
! 1960: return;
! 1961: }
! 1962:
! 1963: #ifdef RTW_DEBUG
! 1964: const char *
! 1965: rtw_pwrstate_string(enum rtw_pwrstate power)
! 1966: {
! 1967: switch (power) {
! 1968: case RTW_ON:
! 1969: return "on";
! 1970: case RTW_SLEEP:
! 1971: return "sleep";
! 1972: case RTW_OFF:
! 1973: return "off";
! 1974: default:
! 1975: return "unknown";
! 1976: }
! 1977: }
! 1978: #endif
! 1979:
! 1980: /* XXX For Maxim, I am using the RFMD settings gleaned from the
! 1981: * reference driver, plus a magic Maxim "ON" value that comes from
! 1982: * the Realtek document "Windows PG for Rtl8180."
! 1983: */
! 1984: void
! 1985: rtw_maxim_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
! 1986: int before_rf, int digphy)
! 1987: {
! 1988: u_int32_t anaparm;
! 1989:
! 1990: anaparm = RTW_READ(regs, RTW_ANAPARM_0);
! 1991: anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
! 1992:
! 1993: switch (power) {
! 1994: case RTW_OFF:
! 1995: if (before_rf)
! 1996: return;
! 1997: anaparm |= RTW_ANAPARM_RFPOW_MAXIM_OFF;
! 1998: anaparm |= RTW_ANAPARM_TXDACOFF;
! 1999: break;
! 2000: case RTW_SLEEP:
! 2001: if (!before_rf)
! 2002: return;
! 2003: anaparm |= RTW_ANAPARM_RFPOW_MAXIM_SLEEP;
! 2004: anaparm |= RTW_ANAPARM_TXDACOFF;
! 2005: break;
! 2006: case RTW_ON:
! 2007: if (!before_rf)
! 2008: return;
! 2009: anaparm |= RTW_ANAPARM_RFPOW_MAXIM_ON;
! 2010: break;
! 2011: }
! 2012: RTW_DPRINTF(RTW_DEBUG_PWR,
! 2013: ("%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
! 2014: __func__, rtw_pwrstate_string(power),
! 2015: (before_rf) ? "before" : "after", anaparm));
! 2016:
! 2017: RTW_WRITE(regs, RTW_ANAPARM_0, anaparm);
! 2018: RTW_SYNC(regs, RTW_ANAPARM_0, RTW_ANAPARM_0);
! 2019: }
! 2020:
! 2021: /* XXX I am using the RFMD settings gleaned from the reference
! 2022: * driver. They agree
! 2023: */
! 2024: void
! 2025: rtw_rfmd_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
! 2026: int before_rf, int digphy)
! 2027: {
! 2028: u_int32_t anaparm;
! 2029:
! 2030: anaparm = RTW_READ(regs, RTW_ANAPARM_0);
! 2031: anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
! 2032:
! 2033: switch (power) {
! 2034: case RTW_OFF:
! 2035: if (before_rf)
! 2036: return;
! 2037: anaparm |= RTW_ANAPARM_RFPOW_RFMD_OFF;
! 2038: anaparm |= RTW_ANAPARM_TXDACOFF;
! 2039: break;
! 2040: case RTW_SLEEP:
! 2041: if (!before_rf)
! 2042: return;
! 2043: anaparm |= RTW_ANAPARM_RFPOW_RFMD_SLEEP;
! 2044: anaparm |= RTW_ANAPARM_TXDACOFF;
! 2045: break;
! 2046: case RTW_ON:
! 2047: if (!before_rf)
! 2048: return;
! 2049: anaparm |= RTW_ANAPARM_RFPOW_RFMD_ON;
! 2050: break;
! 2051: }
! 2052: RTW_DPRINTF(RTW_DEBUG_PWR,
! 2053: ("%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
! 2054: __func__, rtw_pwrstate_string(power),
! 2055: (before_rf) ? "before" : "after", anaparm));
! 2056:
! 2057: RTW_WRITE(regs, RTW_ANAPARM_0, anaparm);
! 2058: RTW_SYNC(regs, RTW_ANAPARM_0, RTW_ANAPARM_0);
! 2059: }
! 2060:
! 2061: void
! 2062: rtw_philips_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
! 2063: int before_rf, int digphy)
! 2064: {
! 2065: u_int32_t anaparm;
! 2066:
! 2067: anaparm = RTW_READ(regs, RTW_ANAPARM_0);
! 2068: anaparm &= ~(RTW_ANAPARM_RFPOW_MASK | RTW_ANAPARM_TXDACOFF);
! 2069:
! 2070: switch (power) {
! 2071: case RTW_OFF:
! 2072: if (before_rf)
! 2073: return;
! 2074: anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_OFF;
! 2075: anaparm |= RTW_ANAPARM_TXDACOFF;
! 2076: break;
! 2077: case RTW_SLEEP:
! 2078: if (!before_rf)
! 2079: return;
! 2080: anaparm |= RTW_ANAPARM_RFPOW_PHILIPS_SLEEP;
! 2081: anaparm |= RTW_ANAPARM_TXDACOFF;
! 2082: break;
! 2083: case RTW_ON:
! 2084: if (!before_rf)
! 2085: return;
! 2086: if (digphy) {
! 2087: anaparm |= RTW_ANAPARM_RFPOW_DIG_PHILIPS_ON;
! 2088: /* XXX guess */
! 2089: anaparm |= RTW_ANAPARM_TXDACOFF;
! 2090: } else
! 2091: anaparm |= RTW_ANAPARM_RFPOW_ANA_PHILIPS_ON;
! 2092: break;
! 2093: }
! 2094: RTW_DPRINTF(RTW_DEBUG_PWR,
! 2095: ("%s: power state %s, %s RF, reg[ANAPARM] <- %08x\n",
! 2096: __func__, rtw_pwrstate_string(power),
! 2097: (before_rf) ? "before" : "after", anaparm));
! 2098:
! 2099: RTW_WRITE(regs, RTW_ANAPARM_0, anaparm);
! 2100: RTW_SYNC(regs, RTW_ANAPARM_0, RTW_ANAPARM_0);
! 2101: }
! 2102:
! 2103: void
! 2104: rtw_rtl_pwrstate(struct rtw_regs *regs, enum rtw_pwrstate power,
! 2105: int before_rf, int digphy)
! 2106: {
! 2107: /* empty */
! 2108: }
! 2109:
! 2110: void
! 2111: rtw_pwrstate0(struct rtw_softc *sc, enum rtw_pwrstate power, int before_rf,
! 2112: int digphy)
! 2113: {
! 2114: struct rtw_regs *regs = &sc->sc_regs;
! 2115:
! 2116: rtw_set_access(regs, RTW_ACCESS_ANAPARM);
! 2117:
! 2118: (*sc->sc_pwrstate_cb)(regs, power, before_rf, digphy);
! 2119:
! 2120: rtw_set_access(regs, RTW_ACCESS_NONE);
! 2121:
! 2122: return;
! 2123: }
! 2124:
! 2125: int
! 2126: rtw_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power)
! 2127: {
! 2128: int rc;
! 2129:
! 2130: RTW_DPRINTF(RTW_DEBUG_PWR,
! 2131: ("%s: %s->%s\n", __func__,
! 2132: rtw_pwrstate_string(sc->sc_pwrstate), rtw_pwrstate_string(power)));
! 2133:
! 2134: if (sc->sc_pwrstate == power)
! 2135: return 0;
! 2136:
! 2137: rtw_pwrstate0(sc, power, 1, sc->sc_flags & RTW_F_DIGPHY);
! 2138: rc = (*sc->sc_rf_pwrstate)(sc, power);
! 2139: rtw_pwrstate0(sc, power, 0, sc->sc_flags & RTW_F_DIGPHY);
! 2140:
! 2141: switch (power) {
! 2142: case RTW_ON:
! 2143: /* TBD set LEDs */
! 2144: break;
! 2145: case RTW_SLEEP:
! 2146: /* TBD */
! 2147: break;
! 2148: case RTW_OFF:
! 2149: /* TBD */
! 2150: break;
! 2151: }
! 2152: if (rc == 0)
! 2153: sc->sc_pwrstate = power;
! 2154: else
! 2155: sc->sc_pwrstate = RTW_OFF;
! 2156: return rc;
! 2157: }
! 2158:
! 2159: int
! 2160: rtw_tune(struct rtw_softc *sc)
! 2161: {
! 2162: struct ieee80211com *ic = &sc->sc_ic;
! 2163: u_int chan, idx;
! 2164: u_int8_t txpower;
! 2165: int rc;
! 2166:
! 2167: KASSERT(ic->ic_bss->ni_chan != NULL);
! 2168:
! 2169: chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
! 2170: if (chan == 0 || chan == IEEE80211_CHAN_ANY)
! 2171: return 0;
! 2172:
! 2173: if (chan == sc->sc_cur_chan) {
! 2174: RTW_DPRINTF(RTW_DEBUG_TUNE,
! 2175: ("%s: already tuned chan #%d\n", __func__, chan));
! 2176: return 0;
! 2177: }
! 2178:
! 2179: rtw_suspend_ticks(sc);
! 2180:
! 2181: rtw_io_enable(&sc->sc_regs, RTW_CR_RE | RTW_CR_TE, 0);
! 2182:
! 2183: /* TBD wait for Tx to complete */
! 2184:
! 2185: KASSERT((sc->sc_flags & RTW_F_ENABLED) != 0);
! 2186:
! 2187: idx = RTW_SR_TXPOWER1 +
! 2188: ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan) - 1;
! 2189: KASSERT2(idx >= RTW_SR_TXPOWER1 && idx <= RTW_SR_TXPOWER14,
! 2190: ("%s: channel %d out of range", __func__,
! 2191: idx - RTW_SR_TXPOWER1 + 1));
! 2192: txpower = RTW_SR_GET(&sc->sc_srom, idx);
! 2193:
! 2194: if ((rc = rtw_phy_init(sc)) != 0) {
! 2195: /* XXX condition on powersaving */
! 2196: printf("%s: phy init failed\n", sc->sc_dev.dv_xname);
! 2197: }
! 2198:
! 2199: sc->sc_cur_chan = chan;
! 2200:
! 2201: rtw_io_enable(&sc->sc_regs, RTW_CR_RE | RTW_CR_TE, 1);
! 2202:
! 2203: rtw_resume_ticks(sc);
! 2204:
! 2205: return rc;
! 2206: }
! 2207:
! 2208: void
! 2209: rtw_disable(struct rtw_softc *sc)
! 2210: {
! 2211: int rc;
! 2212:
! 2213: if ((sc->sc_flags & RTW_F_ENABLED) == 0)
! 2214: return;
! 2215:
! 2216: /* turn off PHY */
! 2217: if ((sc->sc_flags & RTW_F_INVALID) == 0 &&
! 2218: (rc = rtw_pwrstate(sc, RTW_OFF)) != 0) {
! 2219: printf("%s: failed to turn off PHY (%d)\n",
! 2220: sc->sc_dev.dv_xname, rc);
! 2221: }
! 2222:
! 2223: if (sc->sc_disable != NULL)
! 2224: (*sc->sc_disable)(sc);
! 2225:
! 2226: sc->sc_flags &= ~RTW_F_ENABLED;
! 2227: }
! 2228:
! 2229: int
! 2230: rtw_enable(struct rtw_softc *sc)
! 2231: {
! 2232: if ((sc->sc_flags & RTW_F_ENABLED) == 0) {
! 2233: if (sc->sc_enable != NULL && (*sc->sc_enable)(sc) != 0) {
! 2234: printf("%s: device enable failed\n",
! 2235: sc->sc_dev.dv_xname);
! 2236: return (EIO);
! 2237: }
! 2238: sc->sc_flags |= RTW_F_ENABLED;
! 2239: }
! 2240: return (0);
! 2241: }
! 2242:
! 2243: void
! 2244: rtw_transmit_config(struct rtw_softc *sc)
! 2245: {
! 2246: struct rtw_regs *regs = &sc->sc_regs;
! 2247: u_int32_t tcr;
! 2248:
! 2249: tcr = RTW_READ(regs, RTW_TCR);
! 2250:
! 2251: tcr |= RTW_TCR_CWMIN;
! 2252: tcr &= ~RTW_TCR_MXDMA_MASK;
! 2253: tcr |= RTW_TCR_MXDMA_256;
! 2254: if ((sc->sc_flags & RTW_F_RTL8185) == 0)
! 2255: tcr |= RTW8180_TCR_SAT; /* send ACK as fast as possible */
! 2256: tcr &= ~RTW_TCR_LBK_MASK;
! 2257: tcr |= RTW_TCR_LBK_NORMAL; /* normal operating mode */
! 2258:
! 2259: /* set short/long retry limits */
! 2260: tcr &= ~(RTW_TCR_SRL_MASK|RTW_TCR_LRL_MASK);
! 2261: tcr |= LSHIFT(4, RTW_TCR_SRL_MASK) | LSHIFT(4, RTW_TCR_LRL_MASK);
! 2262:
! 2263: tcr &= ~RTW_TCR_CRC; /* NIC appends CRC32 */
! 2264:
! 2265: RTW_WRITE(regs, RTW_TCR, tcr);
! 2266: RTW_SYNC(regs, RTW_TCR, RTW_TCR);
! 2267: }
! 2268:
! 2269: void
! 2270: rtw_enable_interrupts(struct rtw_softc *sc)
! 2271: {
! 2272: struct rtw_regs *regs = &sc->sc_regs;
! 2273:
! 2274: sc->sc_inten = RTW_INTR_RX|RTW_INTR_TX|RTW_INTR_BEACON|RTW_INTR_ATIMINT;
! 2275: sc->sc_inten |= RTW_INTR_IOERROR|RTW_INTR_TIMEOUT;
! 2276:
! 2277: RTW_WRITE16(regs, RTW_IMR, sc->sc_inten);
! 2278: RTW_WBW(regs, RTW_IMR, RTW_ISR);
! 2279: RTW_WRITE16(regs, RTW_ISR, 0xffff);
! 2280: RTW_SYNC(regs, RTW_IMR, RTW_ISR);
! 2281:
! 2282: /* XXX necessary? */
! 2283: if (sc->sc_intr_ack != NULL)
! 2284: (*sc->sc_intr_ack)(regs);
! 2285: }
! 2286:
! 2287: void
! 2288: rtw_set_nettype(struct rtw_softc *sc, enum ieee80211_opmode opmode)
! 2289: {
! 2290: uint8_t msr;
! 2291:
! 2292: /* I'm guessing that MSR is protected as CONFIG[0123] are. */
! 2293: rtw_set_access(&sc->sc_regs, RTW_ACCESS_CONFIG);
! 2294:
! 2295: msr = RTW_READ8(&sc->sc_regs, RTW_MSR) & ~RTW_MSR_NETYPE_MASK;
! 2296:
! 2297: switch (opmode) {
! 2298: case IEEE80211_M_AHDEMO:
! 2299: case IEEE80211_M_IBSS:
! 2300: msr |= RTW_MSR_NETYPE_ADHOC_OK;
! 2301: break;
! 2302: case IEEE80211_M_HOSTAP:
! 2303: msr |= RTW_MSR_NETYPE_AP_OK;
! 2304: break;
! 2305: case IEEE80211_M_MONITOR:
! 2306: /* XXX */
! 2307: msr |= RTW_MSR_NETYPE_NOLINK;
! 2308: break;
! 2309: case IEEE80211_M_STA:
! 2310: msr |= RTW_MSR_NETYPE_INFRA_OK;
! 2311: break;
! 2312: }
! 2313: RTW_WRITE8(&sc->sc_regs, RTW_MSR, msr);
! 2314:
! 2315: rtw_set_access(&sc->sc_regs, RTW_ACCESS_NONE);
! 2316: }
! 2317:
! 2318: void
! 2319: rtw_pktfilt_load(struct rtw_softc *sc)
! 2320: {
! 2321: struct rtw_regs *regs = &sc->sc_regs;
! 2322: struct ieee80211com *ic = &sc->sc_ic;
! 2323: struct arpcom *ec = &ic->ic_ac;
! 2324: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 2325: int hash;
! 2326: u_int32_t hashes[2] = { 0, 0 };
! 2327: struct ether_multi *enm;
! 2328: struct ether_multistep step;
! 2329:
! 2330: /* XXX might be necessary to stop Rx/Tx engines while setting filters */
! 2331:
! 2332: sc->sc_rcr &= ~RTW_RCR_PKTFILTER_MASK;
! 2333: sc->sc_rcr &= ~(RTW_RCR_MXDMA_MASK | RTW8180_RCR_RXFTH_MASK);
! 2334:
! 2335: sc->sc_rcr |= RTW_RCR_PKTFILTER_DEFAULT;
! 2336: /* MAC auto-reset PHY (huh?) */
! 2337: sc->sc_rcr |= RTW_RCR_ENMARP;
! 2338: /* DMA whole Rx packets, only. Set Tx DMA burst size to 1024 bytes. */
! 2339: sc->sc_rcr |= RTW_RCR_MXDMA_1024 | RTW8180_RCR_RXFTH_WHOLE;
! 2340:
! 2341: switch (ic->ic_opmode) {
! 2342: case IEEE80211_M_MONITOR:
! 2343: sc->sc_rcr |= RTW_RCR_MONITOR;
! 2344: break;
! 2345: case IEEE80211_M_AHDEMO:
! 2346: case IEEE80211_M_IBSS:
! 2347: /* receive broadcasts in our BSS */
! 2348: sc->sc_rcr |= RTW_RCR_ADD3;
! 2349: break;
! 2350: default:
! 2351: break;
! 2352: }
! 2353:
! 2354: ifp->if_flags &= ~IFF_ALLMULTI;
! 2355:
! 2356: /* XXX accept all broadcast if scanning */
! 2357: if ((ifp->if_flags & IFF_BROADCAST) != 0)
! 2358: sc->sc_rcr |= RTW_RCR_AB; /* accept all broadcast */
! 2359:
! 2360: if (ifp->if_flags & IFF_PROMISC) {
! 2361: sc->sc_rcr |= RTW_RCR_AB; /* accept all broadcast */
! 2362: allmulti:
! 2363: ifp->if_flags |= IFF_ALLMULTI;
! 2364: goto setit;
! 2365: }
! 2366:
! 2367: /*
! 2368: * Program the 64-bit multicast hash filter.
! 2369: */
! 2370: ETHER_FIRST_MULTI(step, ec, enm);
! 2371: while (enm != NULL) {
! 2372: /* XXX */
! 2373: if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
! 2374: ETHER_ADDR_LEN) != 0)
! 2375: goto allmulti;
! 2376:
! 2377: hash = ether_crc32_be((enm->enm_addrlo),
! 2378: IEEE80211_ADDR_LEN) >> 26;
! 2379: hashes[hash >> 5] |= (1 << (hash & 0x1f));
! 2380: sc->sc_rcr |= RTW_RCR_AM;
! 2381: ETHER_NEXT_MULTI(step, enm);
! 2382: }
! 2383:
! 2384: /* all bits set => hash is useless */
! 2385: if (~(hashes[0] & hashes[1]) == 0)
! 2386: goto allmulti;
! 2387:
! 2388: setit:
! 2389: if (ifp->if_flags & IFF_ALLMULTI) {
! 2390: sc->sc_rcr |= RTW_RCR_AM; /* accept all multicast */
! 2391: hashes[0] = hashes[1] = 0xffffffff;
! 2392: }
! 2393:
! 2394: RTW_WRITE(regs, RTW_MAR0, hashes[0]);
! 2395: RTW_WRITE(regs, RTW_MAR1, hashes[1]);
! 2396: RTW_WRITE(regs, RTW_RCR, sc->sc_rcr);
! 2397: RTW_SYNC(regs, RTW_MAR0, RTW_RCR); /* RTW_MAR0 < RTW_MAR1 < RTW_RCR */
! 2398:
! 2399: DPRINTF(sc, RTW_DEBUG_PKTFILT,
! 2400: ("%s: RTW_MAR0 %08x RTW_MAR1 %08x RTW_RCR %08x\n",
! 2401: sc->sc_dev.dv_xname, RTW_READ(regs, RTW_MAR0),
! 2402: RTW_READ(regs, RTW_MAR1), RTW_READ(regs, RTW_RCR)));
! 2403:
! 2404: return;
! 2405: }
! 2406:
! 2407: /* Must be called at splnet. */
! 2408: int
! 2409: rtw_init(struct ifnet *ifp)
! 2410: {
! 2411: struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc;
! 2412: struct ieee80211com *ic = &sc->sc_ic;
! 2413: struct rtw_regs *regs = &sc->sc_regs;
! 2414: int rc = 0;
! 2415:
! 2416: if ((rc = rtw_enable(sc)) != 0)
! 2417: goto out;
! 2418:
! 2419: /* Cancel pending I/O and reset. */
! 2420: rtw_stop(ifp, 0);
! 2421:
! 2422: ic->ic_bss->ni_chan = ic->ic_ibss_chan;
! 2423: DPRINTF(sc, RTW_DEBUG_TUNE, ("%s: channel %d freq %d flags 0x%04x\n",
! 2424: __func__, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
! 2425: ic->ic_bss->ni_chan->ic_freq, ic->ic_bss->ni_chan->ic_flags));
! 2426:
! 2427: if ((rc = rtw_pwrstate(sc, RTW_OFF)) != 0)
! 2428: goto out;
! 2429:
! 2430: if ((rc = rtw_swring_setup(sc)) != 0)
! 2431: goto out;
! 2432:
! 2433: rtw_transmit_config(sc);
! 2434:
! 2435: rtw_set_access(regs, RTW_ACCESS_CONFIG);
! 2436:
! 2437: RTW_WRITE8(regs, RTW_MSR, 0x0); /* no link */
! 2438: RTW_WBW(regs, RTW_MSR, RTW_BRSR);
! 2439:
! 2440: /* long PLCP header, 1Mb/2Mb basic rate */
! 2441: if (sc->sc_flags & RTW_F_RTL8185)
! 2442: RTW_WRITE16(regs, RTW_BRSR, RTW8185_BRSR_MBR_2MBPS);
! 2443: else
! 2444: RTW_WRITE16(regs, RTW_BRSR, RTW8180_BRSR_MBR_2MBPS);
! 2445: RTW_SYNC(regs, RTW_BRSR, RTW_BRSR);
! 2446:
! 2447: rtw_set_access(regs, RTW_ACCESS_ANAPARM);
! 2448: rtw_set_access(regs, RTW_ACCESS_NONE);
! 2449:
! 2450: /* XXX from reference sources */
! 2451: RTW_WRITE(regs, RTW_FEMR, 0xffff);
! 2452: RTW_SYNC(regs, RTW_FEMR, RTW_FEMR);
! 2453:
! 2454: rtw_set_rfprog(regs, sc->sc_rfchipid, sc->sc_dev.dv_xname);
! 2455:
! 2456: RTW_WRITE8(regs, RTW_PHYDELAY, sc->sc_phydelay);
! 2457: /* from Linux driver */
! 2458: RTW_WRITE8(regs, RTW_CRCOUNT, RTW_CRCOUNT_MAGIC);
! 2459:
! 2460: RTW_SYNC(regs, RTW_PHYDELAY, RTW_CRCOUNT);
! 2461:
! 2462: rtw_enable_interrupts(sc);
! 2463:
! 2464: rtw_pktfilt_load(sc);
! 2465:
! 2466: rtw_hwring_setup(sc);
! 2467:
! 2468: rtw_io_enable(regs, RTW_CR_RE|RTW_CR_TE, 1);
! 2469:
! 2470: ifp->if_flags |= IFF_RUNNING;
! 2471: ic->ic_state = IEEE80211_S_INIT;
! 2472:
! 2473: RTW_WRITE16(regs, RTW_BSSID16, 0x0);
! 2474: RTW_WRITE(regs, RTW_BSSID32, 0x0);
! 2475:
! 2476: rtw_resume_ticks(sc);
! 2477:
! 2478: rtw_set_nettype(sc, IEEE80211_M_MONITOR);
! 2479:
! 2480: if (ic->ic_opmode == IEEE80211_M_MONITOR)
! 2481: return ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 2482: else
! 2483: return ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 2484:
! 2485: out:
! 2486: printf("%s: interface not running\n", sc->sc_dev.dv_xname);
! 2487: return rc;
! 2488: }
! 2489:
! 2490: void
! 2491: rtw_led_init(struct rtw_regs *regs)
! 2492: {
! 2493: u_int8_t cfg0, cfg1;
! 2494:
! 2495: rtw_set_access(regs, RTW_ACCESS_CONFIG);
! 2496:
! 2497: cfg0 = RTW_READ8(regs, RTW_CONFIG0);
! 2498: cfg0 |= RTW8180_CONFIG0_LEDGPOEN;
! 2499: RTW_WRITE8(regs, RTW_CONFIG0, cfg0);
! 2500:
! 2501: cfg1 = RTW_READ8(regs, RTW_CONFIG1);
! 2502: RTW_DPRINTF(RTW_DEBUG_LED,
! 2503: ("%s: read % from reg[CONFIG1]\n", __func__, cfg1));
! 2504:
! 2505: cfg1 &= ~RTW_CONFIG1_LEDS_MASK;
! 2506: cfg1 |= RTW_CONFIG1_LEDS_TX_RX;
! 2507: RTW_WRITE8(regs, RTW_CONFIG1, cfg1);
! 2508:
! 2509: rtw_set_access(regs, RTW_ACCESS_NONE);
! 2510: }
! 2511:
! 2512: /*
! 2513: * IEEE80211_S_INIT: LED1 off
! 2514: *
! 2515: * IEEE80211_S_AUTH,
! 2516: * IEEE80211_S_ASSOC,
! 2517: * IEEE80211_S_SCAN: LED1 blinks @ 1 Hz, blinks at 5Hz for tx/rx
! 2518: *
! 2519: * IEEE80211_S_RUN: LED1 on, blinks @ 5Hz for tx/rx
! 2520: */
! 2521: void
! 2522: rtw_led_newstate(struct rtw_softc *sc, enum ieee80211_state nstate)
! 2523: {
! 2524: struct rtw_led_state *ls;
! 2525:
! 2526: ls = &sc->sc_led_state;
! 2527:
! 2528: switch (nstate) {
! 2529: case IEEE80211_S_INIT:
! 2530: rtw_led_init(&sc->sc_regs);
! 2531: timeout_del(&ls->ls_slow_ch);
! 2532: timeout_del(&ls->ls_fast_ch);
! 2533: ls->ls_slowblink = 0;
! 2534: ls->ls_actblink = 0;
! 2535: ls->ls_default = 0;
! 2536: break;
! 2537: case IEEE80211_S_SCAN:
! 2538: timeout_add(&ls->ls_slow_ch, RTW_LED_SLOW_TICKS);
! 2539: timeout_add(&ls->ls_fast_ch, RTW_LED_FAST_TICKS);
! 2540: /*FALLTHROUGH*/
! 2541: case IEEE80211_S_AUTH:
! 2542: case IEEE80211_S_ASSOC:
! 2543: ls->ls_default = RTW_LED1;
! 2544: ls->ls_actblink = RTW_LED1;
! 2545: ls->ls_slowblink = RTW_LED1;
! 2546: break;
! 2547: case IEEE80211_S_RUN:
! 2548: ls->ls_slowblink = 0;
! 2549: break;
! 2550: }
! 2551: rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid);
! 2552: }
! 2553:
! 2554: void
! 2555: rtw_led_set(struct rtw_led_state *ls, struct rtw_regs *regs, u_int hwverid)
! 2556: {
! 2557: u_int8_t led_condition;
! 2558: bus_size_t ofs;
! 2559: u_int8_t mask, newval, val;
! 2560:
! 2561: led_condition = ls->ls_default;
! 2562:
! 2563: if (ls->ls_state & RTW_LED_S_SLOW)
! 2564: led_condition ^= ls->ls_slowblink;
! 2565: if (ls->ls_state & (RTW_LED_S_RX|RTW_LED_S_TX))
! 2566: led_condition ^= ls->ls_actblink;
! 2567:
! 2568: RTW_DPRINTF(RTW_DEBUG_LED,
! 2569: ("%s: LED condition %\n", __func__, led_condition));
! 2570:
! 2571: switch (hwverid) {
! 2572: default:
! 2573: case RTW_TCR_HWVERID_RTL8180F:
! 2574: ofs = RTW_PSR;
! 2575: newval = mask = RTW_PSR_LEDGPO0 | RTW_PSR_LEDGPO1;
! 2576: if (led_condition & RTW_LED0)
! 2577: newval &= ~RTW_PSR_LEDGPO0;
! 2578: if (led_condition & RTW_LED1)
! 2579: newval &= ~RTW_PSR_LEDGPO1;
! 2580: break;
! 2581: case RTW_TCR_HWVERID_RTL8180D:
! 2582: ofs = RTW_9346CR;
! 2583: mask = RTW_9346CR_EEM_MASK | RTW_9346CR_EEDI | RTW_9346CR_EECS;
! 2584: newval = RTW_9346CR_EEM_PROGRAM;
! 2585: if (led_condition & RTW_LED0)
! 2586: newval |= RTW_9346CR_EEDI;
! 2587: if (led_condition & RTW_LED1)
! 2588: newval |= RTW_9346CR_EECS;
! 2589: break;
! 2590: }
! 2591: val = RTW_READ8(regs, ofs);
! 2592: RTW_DPRINTF(RTW_DEBUG_LED,
! 2593: ("%s: read % from reg[%#02]\n", __func__, val,
! 2594: (u_int *)ofs));
! 2595: val &= ~mask;
! 2596: val |= newval;
! 2597: RTW_WRITE8(regs, ofs, val);
! 2598: RTW_DPRINTF(RTW_DEBUG_LED,
! 2599: ("%s: wrote % to reg[%#02]\n", __func__, val,
! 2600: (u_int *)ofs));
! 2601: RTW_SYNC(regs, ofs, ofs);
! 2602: }
! 2603:
! 2604: void
! 2605: rtw_led_fastblink(void *arg)
! 2606: {
! 2607: int ostate, s;
! 2608: struct rtw_softc *sc = (struct rtw_softc *)arg;
! 2609: struct rtw_led_state *ls = &sc->sc_led_state;
! 2610:
! 2611: s = splnet();
! 2612: ostate = ls->ls_state;
! 2613: ls->ls_state ^= ls->ls_event;
! 2614:
! 2615: if ((ls->ls_event & RTW_LED_S_TX) == 0)
! 2616: ls->ls_state &= ~RTW_LED_S_TX;
! 2617:
! 2618: if ((ls->ls_event & RTW_LED_S_RX) == 0)
! 2619: ls->ls_state &= ~RTW_LED_S_RX;
! 2620:
! 2621: ls->ls_event = 0;
! 2622:
! 2623: if (ostate != ls->ls_state)
! 2624: rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid);
! 2625: splx(s);
! 2626:
! 2627: timeout_add(&ls->ls_fast_ch, RTW_LED_FAST_TICKS);
! 2628: }
! 2629:
! 2630: void
! 2631: rtw_led_slowblink(void *arg)
! 2632: {
! 2633: int s;
! 2634: struct rtw_softc *sc = (struct rtw_softc *)arg;
! 2635: struct rtw_led_state *ls = &sc->sc_led_state;
! 2636:
! 2637: s = splnet();
! 2638: ls->ls_state ^= RTW_LED_S_SLOW;
! 2639: rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid);
! 2640: splx(s);
! 2641: timeout_add(&ls->ls_slow_ch, RTW_LED_SLOW_TICKS);
! 2642: }
! 2643:
! 2644: void
! 2645: rtw_led_attach(struct rtw_led_state *ls, void *arg)
! 2646: {
! 2647: timeout_set(&ls->ls_fast_ch, rtw_led_fastblink, arg);
! 2648: timeout_set(&ls->ls_slow_ch, rtw_led_slowblink, arg);
! 2649: }
! 2650:
! 2651: int
! 2652: rtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 2653: {
! 2654: int rc = 0, s;
! 2655: struct rtw_softc *sc = ifp->if_softc;
! 2656: struct ieee80211com *ic = &sc->sc_ic;
! 2657: struct ifreq *ifr = (struct ifreq *)data;
! 2658: struct ifaddr *ifa = (struct ifaddr *)data;
! 2659:
! 2660: s = splnet();
! 2661: switch (cmd) {
! 2662: case SIOCSIFMTU:
! 2663: if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
! 2664: rc = EINVAL;
! 2665: } else if (ifp->if_mtu != ifr->ifr_mtu) {
! 2666: ifp->if_mtu = ifr->ifr_mtu;
! 2667: }
! 2668: break;
! 2669: case SIOCSIFADDR:
! 2670: ifp->if_flags |= IFF_UP;
! 2671: #ifdef INET
! 2672: if (ifa->ifa_addr->sa_family == AF_INET) {
! 2673: arp_ifinit(&ic->ic_ac, ifa);
! 2674: }
! 2675: #endif /* INET */
! 2676: /* FALLTHROUGH */
! 2677:
! 2678: case SIOCSIFFLAGS:
! 2679: if ((ifp->if_flags & IFF_UP) != 0) {
! 2680: if ((sc->sc_flags & RTW_F_ENABLED) != 0) {
! 2681: rtw_pktfilt_load(sc);
! 2682: } else
! 2683: rc = rtw_init(ifp);
! 2684: } else if ((sc->sc_flags & RTW_F_ENABLED) != 0)
! 2685: rtw_stop(ifp, 1);
! 2686: break;
! 2687: case SIOCADDMULTI:
! 2688: case SIOCDELMULTI:
! 2689: if (cmd == SIOCADDMULTI)
! 2690: rc = ether_addmulti(ifr, &sc->sc_ic.ic_ac);
! 2691: else
! 2692: rc = ether_delmulti(ifr, &sc->sc_ic.ic_ac);
! 2693: if (rc != ENETRESET)
! 2694: break;
! 2695: if (ifp->if_flags & IFF_RUNNING)
! 2696: rtw_pktfilt_load(sc);
! 2697: rc = 0;
! 2698: break;
! 2699: default:
! 2700: if ((rc = ieee80211_ioctl(ifp, cmd, data)) == ENETRESET) {
! 2701: if ((sc->sc_flags & RTW_F_ENABLED) != 0)
! 2702: rc = rtw_init(ifp);
! 2703: else
! 2704: rc = 0;
! 2705: }
! 2706: break;
! 2707: }
! 2708: splx(s);
! 2709: return rc;
! 2710: }
! 2711:
! 2712: /* Select a transmit ring with at least one h/w and s/w descriptor free.
! 2713: * Return 0 on success, -1 on failure.
! 2714: */
! 2715: int
! 2716: rtw_txring_choose(struct rtw_softc *sc, struct rtw_txsoft_blk **tsbp,
! 2717: struct rtw_txdesc_blk **tdbp, int pri)
! 2718: {
! 2719: struct rtw_txsoft_blk *tsb;
! 2720: struct rtw_txdesc_blk *tdb;
! 2721:
! 2722: KASSERT(pri >= 0 && pri < RTW_NTXPRI);
! 2723:
! 2724: tsb = &sc->sc_txsoft_blk[pri];
! 2725: tdb = &sc->sc_txdesc_blk[pri];
! 2726:
! 2727: if (SIMPLEQ_EMPTY(&tsb->tsb_freeq) || tdb->tdb_nfree == 0) {
! 2728: if (tsb->tsb_tx_timer == 0)
! 2729: tsb->tsb_tx_timer = 5;
! 2730: *tsbp = NULL;
! 2731: *tdbp = NULL;
! 2732: return -1;
! 2733: }
! 2734: *tsbp = tsb;
! 2735: *tdbp = tdb;
! 2736: return 0;
! 2737: }
! 2738:
! 2739: struct mbuf *
! 2740: rtw_80211_dequeue(struct rtw_softc *sc, struct ifqueue *ifq, int pri,
! 2741: struct rtw_txsoft_blk **tsbp, struct rtw_txdesc_blk **tdbp,
! 2742: struct ieee80211_node **nip, short *if_flagsp)
! 2743: {
! 2744: struct mbuf *m;
! 2745:
! 2746: if (IF_IS_EMPTY(ifq))
! 2747: return NULL;
! 2748: if (rtw_txring_choose(sc, tsbp, tdbp, pri) == -1) {
! 2749: DPRINTF(sc, RTW_DEBUG_XMIT_RSRC, ("%s: no ring %d descriptor\n",
! 2750: __func__, pri));
! 2751: *if_flagsp |= IFF_OACTIVE;
! 2752: sc->sc_if.if_timer = 1;
! 2753: return NULL;
! 2754: }
! 2755: IF_DEQUEUE(ifq, m);
! 2756: *nip = (struct ieee80211_node *)m->m_pkthdr.rcvif;
! 2757: m->m_pkthdr.rcvif = NULL;
! 2758: return m;
! 2759: }
! 2760:
! 2761: /* Point *mp at the next 802.11 frame to transmit. Point *tsbp
! 2762: * at the driver's selection of transmit control block for the packet.
! 2763: */
! 2764: int
! 2765: rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp,
! 2766: struct rtw_txdesc_blk **tdbp, struct mbuf **mp,
! 2767: struct ieee80211_node **nip)
! 2768: {
! 2769: struct mbuf *m0;
! 2770: struct rtw_softc *sc;
! 2771: short *if_flagsp;
! 2772:
! 2773: sc = (struct rtw_softc *)ifp->if_softc;
! 2774:
! 2775: DPRINTF(sc, RTW_DEBUG_XMIT,
! 2776: ("%s: enter %s\n", sc->sc_dev.dv_xname, __func__));
! 2777:
! 2778: if_flagsp = &ifp->if_flags;
! 2779:
! 2780: if (sc->sc_ic.ic_state == IEEE80211_S_RUN &&
! 2781: (*mp = rtw_80211_dequeue(sc, &sc->sc_beaconq, RTW_TXPRIBCN, tsbp,
! 2782: tdbp, nip, if_flagsp)) != NULL) {
! 2783: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue beacon frame\n",
! 2784: __func__));
! 2785: return 0;
! 2786: }
! 2787:
! 2788: if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_mgtq, RTW_TXPRIMD, tsbp,
! 2789: tdbp, nip, if_flagsp)) != NULL) {
! 2790: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue mgt frame\n",
! 2791: __func__));
! 2792: return 0;
! 2793: }
! 2794:
! 2795: if (sc->sc_ic.ic_state != IEEE80211_S_RUN) {
! 2796: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: not running\n", __func__));
! 2797: return 0;
! 2798: }
! 2799:
! 2800: if ((*mp = rtw_80211_dequeue(sc, &sc->sc_ic.ic_pwrsaveq, RTW_TXPRIHI,
! 2801: tsbp, tdbp, nip, if_flagsp)) != NULL) {
! 2802: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue pwrsave frame\n",
! 2803: __func__));
! 2804: return 0;
! 2805: }
! 2806:
! 2807: if (sc->sc_ic.ic_state != IEEE80211_S_RUN) {
! 2808: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: not running\n", __func__));
! 2809: return 0;
! 2810: }
! 2811:
! 2812: *mp = NULL;
! 2813:
! 2814: IFQ_POLL(&ifp->if_snd, m0);
! 2815: if (m0 == NULL) {
! 2816: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame ready\n",
! 2817: __func__));
! 2818: return 0;
! 2819: }
! 2820:
! 2821: if (rtw_txring_choose(sc, tsbp, tdbp, RTW_TXPRIMD) == -1) {
! 2822: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no descriptor\n", __func__));
! 2823: *if_flagsp |= IFF_OACTIVE;
! 2824: sc->sc_if.if_timer = 1;
! 2825: return 0;
! 2826: }
! 2827:
! 2828: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 2829: if (m0 == NULL) {
! 2830: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame/ring ready\n",
! 2831: __func__));
! 2832: return 0;
! 2833: }
! 2834: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: dequeue data frame\n", __func__));
! 2835: ifp->if_opackets++;
! 2836: #if NBPFILTER > 0
! 2837: if (ifp->if_bpf)
! 2838: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 2839: #endif
! 2840: if ((m0 = ieee80211_encap(ifp, m0, nip)) == NULL) {
! 2841: DPRINTF(sc, RTW_DEBUG_XMIT,
! 2842: ("%s: encap error\n", __func__));
! 2843: ifp->if_oerrors++;
! 2844: return -1;
! 2845: }
! 2846:
! 2847: /* XXX should do WEP in hardware */
! 2848: if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
! 2849: if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL)
! 2850: return -1;
! 2851: }
! 2852:
! 2853: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: leave\n", __func__));
! 2854: *mp = m0;
! 2855: return 0;
! 2856: }
! 2857:
! 2858: int
! 2859: rtw_seg_too_short(bus_dmamap_t dmamap)
! 2860: {
! 2861: int i;
! 2862: for (i = 0; i < dmamap->dm_nsegs; i++) {
! 2863: if (dmamap->dm_segs[i].ds_len < 4) {
! 2864: printf("%s: segment too short\n", __func__);
! 2865: return 1;
! 2866: }
! 2867: }
! 2868: return 0;
! 2869: }
! 2870:
! 2871: /* TBD factor with atw_start */
! 2872: struct mbuf *
! 2873: rtw_dmamap_load_txbuf(bus_dma_tag_t dmat, bus_dmamap_t dmam, struct mbuf *chain,
! 2874: u_int ndescfree, short *ifflagsp, const char *dvname)
! 2875: {
! 2876: int first, rc;
! 2877: struct mbuf *m, *m0;
! 2878:
! 2879: m0 = chain;
! 2880:
! 2881: /*
! 2882: * Load the DMA map. Copy and try (once) again if the packet
! 2883: * didn't fit in the alloted number of segments.
! 2884: */
! 2885: for (first = 1;
! 2886: ((rc = bus_dmamap_load_mbuf(dmat, dmam, m0,
! 2887: BUS_DMA_WRITE|BUS_DMA_NOWAIT)) != 0 ||
! 2888: dmam->dm_nsegs > ndescfree || rtw_seg_too_short(dmam)) && first;
! 2889: first = 0) {
! 2890: if (rc == 0)
! 2891: bus_dmamap_unload(dmat, dmam);
! 2892: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 2893: if (m == NULL) {
! 2894: printf("%s: unable to allocate Tx mbuf\n",
! 2895: dvname);
! 2896: break;
! 2897: }
! 2898: if (m0->m_pkthdr.len > MHLEN) {
! 2899: MCLGET(m, M_DONTWAIT);
! 2900: if ((m->m_flags & M_EXT) == 0) {
! 2901: printf("%s: cannot allocate Tx cluster\n",
! 2902: dvname);
! 2903: m_freem(m);
! 2904: break;
! 2905: }
! 2906: }
! 2907: m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
! 2908: m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
! 2909: m_freem(m0);
! 2910: m0 = m;
! 2911: m = NULL;
! 2912: }
! 2913: if (rc != 0) {
! 2914: printf("%s: cannot load Tx buffer, rc = %d\n", dvname, rc);
! 2915: m_freem(m0);
! 2916: return NULL;
! 2917: } else if (rtw_seg_too_short(dmam)) {
! 2918: printf("%s: cannot load Tx buffer, segment too short\n",
! 2919: dvname);
! 2920: bus_dmamap_unload(dmat, dmam);
! 2921: m_freem(m0);
! 2922: return NULL;
! 2923: } else if (dmam->dm_nsegs > ndescfree) {
! 2924: printf("%s: too many tx segments\n", dvname);
! 2925: bus_dmamap_unload(dmat, dmam);
! 2926: m_freem(m0);
! 2927: return NULL;
! 2928: }
! 2929: return m0;
! 2930: }
! 2931:
! 2932:
! 2933: /*
! 2934: * Arguments in:
! 2935: *
! 2936: * paylen: payload length (no FCS, no WEP header)
! 2937: *
! 2938: * hdrlen: header length
! 2939: *
! 2940: * rate: MSDU speed, units 500kb/s
! 2941: *
! 2942: * flags: IEEE80211_F_SHPREAMBLE (use short preamble),
! 2943: * IEEE80211_F_SHSLOT (use short slot length)
! 2944: *
! 2945: * Arguments out:
! 2946: *
! 2947: * d: 802.11 Duration field for RTS,
! 2948: * 802.11 Duration field for data frame,
! 2949: * PLCP Length for data frame,
! 2950: * residual octets at end of data slot
! 2951: */
! 2952: int
! 2953: rtw_compute_duration1(int len, int use_ack, uint32_t flags, int rate,
! 2954: struct rtw_duration *d)
! 2955: {
! 2956: int pre, ctsrate;
! 2957: int ack, bitlen, data_dur, remainder;
! 2958:
! 2959: /* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK
! 2960: * DATA reserves medium for SIFS | ACK
! 2961: *
! 2962: * XXXMYC: no ACK on multicast/broadcast or control packets
! 2963: */
! 2964:
! 2965: bitlen = len * 8;
! 2966:
! 2967: pre = IEEE80211_DUR_DS_SIFS;
! 2968: if ((flags & IEEE80211_F_SHPREAMBLE) != 0)
! 2969: pre += IEEE80211_DUR_DS_SHORT_PREAMBLE +
! 2970: IEEE80211_DUR_DS_FAST_PLCPHDR;
! 2971: else
! 2972: pre += IEEE80211_DUR_DS_LONG_PREAMBLE +
! 2973: IEEE80211_DUR_DS_SLOW_PLCPHDR;
! 2974:
! 2975: d->d_residue = 0;
! 2976: data_dur = (bitlen * 2) / rate;
! 2977: remainder = (bitlen * 2) % rate;
! 2978: if (remainder != 0) {
! 2979: d->d_residue = (rate - remainder) / 16;
! 2980: data_dur++;
! 2981: }
! 2982:
! 2983: switch (rate) {
! 2984: case 2: /* 1 Mb/s */
! 2985: case 4: /* 2 Mb/s */
! 2986: /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */
! 2987: ctsrate = 2;
! 2988: break;
! 2989: case 11: /* 5.5 Mb/s */
! 2990: case 22: /* 11 Mb/s */
! 2991: case 44: /* 22 Mb/s */
! 2992: /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */
! 2993: ctsrate = 4;
! 2994: break;
! 2995: default:
! 2996: /* TBD */
! 2997: return -1;
! 2998: }
! 2999:
! 3000: d->d_plcp_len = data_dur;
! 3001:
! 3002: ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0;
! 3003:
! 3004: d->d_rts_dur =
! 3005: pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate +
! 3006: pre + data_dur +
! 3007: ack;
! 3008:
! 3009: d->d_data_dur = ack;
! 3010:
! 3011: return 0;
! 3012: }
! 3013:
! 3014: /*
! 3015: * Arguments in:
! 3016: *
! 3017: * wh: 802.11 header
! 3018: *
! 3019: * len: packet length
! 3020: *
! 3021: * rate: MSDU speed, units 500kb/s
! 3022: *
! 3023: * fraglen: fragment length, set to maximum (or higher) for no
! 3024: * fragmentation
! 3025: *
! 3026: * flags: IEEE80211_F_WEPON (hardware adds WEP),
! 3027: * IEEE80211_F_SHPREAMBLE (use short preamble),
! 3028: * IEEE80211_F_SHSLOT (use short slot length)
! 3029: *
! 3030: * Arguments out:
! 3031: *
! 3032: * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
! 3033: * of first/only fragment
! 3034: *
! 3035: * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
! 3036: * of first/only fragment
! 3037: */
! 3038: int
! 3039: rtw_compute_duration(struct ieee80211_frame *wh, int len, uint32_t flags,
! 3040: int fraglen, int rate, struct rtw_duration *d0, struct rtw_duration *dn,
! 3041: int *npktp, int debug)
! 3042: {
! 3043: int ack, rc;
! 3044: int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen;
! 3045:
! 3046: if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
! 3047: hdrlen = sizeof(struct ieee80211_frame_addr4);
! 3048: else
! 3049: hdrlen = sizeof(struct ieee80211_frame);
! 3050:
! 3051: paylen = len - hdrlen;
! 3052:
! 3053: if ((flags & IEEE80211_F_WEPON) != 0)
! 3054: overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN;
! 3055: else
! 3056: overlen = IEEE80211_CRC_LEN;
! 3057:
! 3058: npkt = paylen / fraglen;
! 3059: lastlen0 = paylen % fraglen;
! 3060:
! 3061: if (npkt == 0) /* no fragments */
! 3062: lastlen = paylen + overlen;
! 3063: else if (lastlen0 != 0) { /* a short "tail" fragment */
! 3064: lastlen = lastlen0 + overlen;
! 3065: npkt++;
! 3066: } else /* full-length "tail" fragment */
! 3067: lastlen = fraglen + overlen;
! 3068:
! 3069: if (npktp != NULL)
! 3070: *npktp = npkt;
! 3071:
! 3072: if (npkt > 1)
! 3073: firstlen = fraglen + overlen;
! 3074: else
! 3075: firstlen = paylen + overlen;
! 3076:
! 3077: if (debug) {
! 3078: printf("%s: npkt %d firstlen %d lastlen0 %d lastlen %d "
! 3079: "fraglen %d overlen %d len %d rate %d flags %08x\n",
! 3080: __func__, npkt, firstlen, lastlen0, lastlen, fraglen,
! 3081: overlen, len, rate, flags);
! 3082: }
! 3083:
! 3084: ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
! 3085: (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL;
! 3086:
! 3087: rc = rtw_compute_duration1(firstlen + hdrlen, ack, flags, rate, d0);
! 3088: if (rc == -1)
! 3089: return rc;
! 3090:
! 3091: if (npkt <= 1) {
! 3092: *dn = *d0;
! 3093: return 0;
! 3094: }
! 3095: return rtw_compute_duration1(lastlen + hdrlen, ack, flags, rate, dn);
! 3096: }
! 3097:
! 3098: #ifdef RTW_DEBUG
! 3099: void
! 3100: rtw_print_txdesc(struct rtw_softc *sc, const char *action,
! 3101: struct rtw_txsoft *ts, struct rtw_txdesc_blk *tdb, int desc)
! 3102: {
! 3103: struct rtw_txdesc *td = &tdb->tdb_desc[desc];
! 3104: DPRINTF(sc, RTW_DEBUG_XMIT_DESC, ("%s: %p %s txdesc[%d] next %#08x "
! 3105: "buf %#08x ctl0 %#08x ctl1 %#08x len %#08x\n",
! 3106: sc->sc_dev.dv_xname, ts, action, desc,
! 3107: letoh32(td->td_buf), letoh32(td->td_next),
! 3108: letoh32(td->td_ctl0), letoh32(td->td_ctl1),
! 3109: letoh32(td->td_len)));
! 3110: }
! 3111: #endif /* RTW_DEBUG */
! 3112:
! 3113: void
! 3114: rtw_start(struct ifnet *ifp)
! 3115: {
! 3116: uint8_t tppoll;
! 3117: int desc, i, lastdesc, npkt, rate;
! 3118: uint32_t proto_ctl0, ctl0, ctl1;
! 3119: bus_dmamap_t dmamap;
! 3120: struct ieee80211com *ic;
! 3121: struct ieee80211_frame *wh;
! 3122: struct ieee80211_node *ni;
! 3123: struct mbuf *m0;
! 3124: struct rtw_softc *sc;
! 3125: struct rtw_duration *d0;
! 3126: struct rtw_txsoft_blk *tsb;
! 3127: struct rtw_txdesc_blk *tdb;
! 3128: struct rtw_txsoft *ts;
! 3129: struct rtw_txdesc *td;
! 3130:
! 3131: sc = (struct rtw_softc *)ifp->if_softc;
! 3132: ic = &sc->sc_ic;
! 3133:
! 3134: DPRINTF(sc, RTW_DEBUG_XMIT,
! 3135: ("%s: enter %s\n", sc->sc_dev.dv_xname, __func__));
! 3136:
! 3137: if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
! 3138: goto out;
! 3139:
! 3140: /* XXX do real rate control */
! 3141: proto_ctl0 = RTW_TXCTL0_RTSRATE_1MBPS;
! 3142:
! 3143: if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0)
! 3144: proto_ctl0 |= RTW_TXCTL0_SPLCP;
! 3145:
! 3146: for (;;) {
! 3147: if (rtw_dequeue(ifp, &tsb, &tdb, &m0, &ni) == -1)
! 3148: continue;
! 3149: if (m0 == NULL)
! 3150: break;
! 3151: ts = SIMPLEQ_FIRST(&tsb->tsb_freeq);
! 3152:
! 3153: dmamap = ts->ts_dmamap;
! 3154:
! 3155: m0 = rtw_dmamap_load_txbuf(sc->sc_dmat, dmamap, m0,
! 3156: tdb->tdb_nfree, &ifp->if_flags, sc->sc_dev.dv_xname);
! 3157:
! 3158: if (m0 == NULL || dmamap->dm_nsegs == 0) {
! 3159: DPRINTF(sc, RTW_DEBUG_XMIT,
! 3160: ("%s: fail dmamap load\n", __func__));
! 3161: goto post_dequeue_err;
! 3162: }
! 3163:
! 3164: wh = mtod(m0, struct ieee80211_frame *);
! 3165:
! 3166: /* XXX do real rate control */
! 3167: if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
! 3168: IEEE80211_FC0_TYPE_MGT)
! 3169: rate = 2;
! 3170: else
! 3171: rate = MAX(2, ieee80211_get_rate(ic));
! 3172:
! 3173: #ifdef RTW_DEBUG
! 3174: if ((sc->sc_if.if_flags & (IFF_DEBUG|IFF_LINK2)) ==
! 3175: (IFF_DEBUG|IFF_LINK2)) {
! 3176: ieee80211_dump_pkt(mtod(m0, uint8_t *),
! 3177: (dmamap->dm_nsegs == 1) ? m0->m_pkthdr.len
! 3178: : sizeof(wh), rate, 0);
! 3179: }
! 3180: #endif /* RTW_DEBUG */
! 3181: ctl0 = proto_ctl0 |
! 3182: LSHIFT(m0->m_pkthdr.len, RTW_TXCTL0_TPKTSIZE_MASK);
! 3183:
! 3184: switch (rate) {
! 3185: default:
! 3186: case 2:
! 3187: ctl0 |= RTW_TXCTL0_RATE_1MBPS;
! 3188: break;
! 3189: case 4:
! 3190: ctl0 |= RTW_TXCTL0_RATE_2MBPS;
! 3191: break;
! 3192: case 11:
! 3193: ctl0 |= RTW_TXCTL0_RATE_5MBPS;
! 3194: break;
! 3195: case 22:
! 3196: ctl0 |= RTW_TXCTL0_RATE_11MBPS;
! 3197: break;
! 3198: }
! 3199:
! 3200: /* XXX >= ? Compare after fragmentation? */
! 3201: if (m0->m_pkthdr.len > ic->ic_rtsthreshold)
! 3202: ctl0 |= RTW_TXCTL0_RTSEN;
! 3203:
! 3204: if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
! 3205: IEEE80211_FC0_TYPE_MGT) {
! 3206: ctl0 &= ~(RTW_TXCTL0_SPLCP | RTW_TXCTL0_RTSEN);
! 3207: if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
! 3208: IEEE80211_FC0_SUBTYPE_BEACON)
! 3209: ctl0 |= RTW_TXCTL0_BEACON;
! 3210: }
! 3211:
! 3212: if (rtw_compute_duration(wh, m0->m_pkthdr.len,
! 3213: ic->ic_flags & ~IEEE80211_F_WEPON, ic->ic_fragthreshold,
! 3214: rate, &ts->ts_d0, &ts->ts_dn, &npkt,
! 3215: (sc->sc_if.if_flags & (IFF_DEBUG|IFF_LINK2)) ==
! 3216: (IFF_DEBUG|IFF_LINK2)) == -1) {
! 3217: DPRINTF(sc, RTW_DEBUG_XMIT,
! 3218: ("%s: fail compute duration\n", __func__));
! 3219: goto post_load_err;
! 3220: }
! 3221:
! 3222: d0 = &ts->ts_d0;
! 3223:
! 3224: *(uint16_t*)wh->i_dur = htole16(d0->d_data_dur);
! 3225:
! 3226: ctl1 = LSHIFT(d0->d_plcp_len, RTW_TXCTL1_LENGTH_MASK) |
! 3227: LSHIFT(d0->d_rts_dur, RTW_TXCTL1_RTSDUR_MASK);
! 3228:
! 3229: if (d0->d_residue)
! 3230: ctl1 |= RTW_TXCTL1_LENGEXT;
! 3231:
! 3232: /* TBD fragmentation */
! 3233:
! 3234: ts->ts_first = tdb->tdb_next;
! 3235:
! 3236: rtw_txdescs_sync(tdb, ts->ts_first, dmamap->dm_nsegs,
! 3237: BUS_DMASYNC_PREWRITE);
! 3238:
! 3239: KASSERT(ts->ts_first < tdb->tdb_ndesc);
! 3240:
! 3241: #if NBPFILTER > 0
! 3242: if (ic->ic_rawbpf != NULL)
! 3243: bpf_mtap((caddr_t)ic->ic_rawbpf, m0,
! 3244: BPF_DIRECTION_OUT);
! 3245:
! 3246: if (sc->sc_radiobpf != NULL) {
! 3247: struct mbuf mb;
! 3248: struct rtw_tx_radiotap_header *rt = &sc->sc_txtap;
! 3249:
! 3250: rt->rt_flags = 0;
! 3251: rt->rt_rate = rate;
! 3252: rt->rt_chan_freq =
! 3253: htole16(ic->ic_bss->ni_chan->ic_freq);
! 3254: rt->rt_chan_flags =
! 3255: htole16(ic->ic_bss->ni_chan->ic_flags);
! 3256:
! 3257: mb.m_data = (caddr_t)rt;
! 3258: mb.m_len = sizeof(sc->sc_txtapu);
! 3259: mb.m_next = m0;
! 3260: mb.m_nextpkt = NULL;
! 3261: mb.m_type = 0;
! 3262: mb.m_flags = 0;
! 3263: bpf_mtap(sc->sc_radiobpf, &mb, BPF_DIRECTION_OUT);
! 3264:
! 3265: }
! 3266: #endif /* NPBFILTER > 0 */
! 3267:
! 3268: for (i = 0, lastdesc = desc = ts->ts_first;
! 3269: i < dmamap->dm_nsegs;
! 3270: i++, desc = RTW_NEXT_IDX(tdb, desc)) {
! 3271: if (dmamap->dm_segs[i].ds_len > RTW_TXLEN_LENGTH_MASK) {
! 3272: DPRINTF(sc, RTW_DEBUG_XMIT_DESC,
! 3273: ("%s: seg too long\n", __func__));
! 3274: goto post_load_err;
! 3275: }
! 3276: td = &tdb->tdb_desc[desc];
! 3277: td->td_ctl0 = htole32(ctl0);
! 3278: if (i != 0)
! 3279: td->td_ctl0 |= htole32(RTW_TXCTL0_OWN);
! 3280: td->td_ctl1 = htole32(ctl1);
! 3281: td->td_buf = htole32(dmamap->dm_segs[i].ds_addr);
! 3282: td->td_len = htole32(dmamap->dm_segs[i].ds_len);
! 3283: lastdesc = desc;
! 3284: #ifdef RTW_DEBUG
! 3285: rtw_print_txdesc(sc, "load", ts, tdb, desc);
! 3286: #endif /* RTW_DEBUG */
! 3287: }
! 3288:
! 3289: KASSERT(desc < tdb->tdb_ndesc);
! 3290:
! 3291: ts->ts_ni = ni;
! 3292: ts->ts_mbuf = m0;
! 3293: ts->ts_last = lastdesc;
! 3294: tdb->tdb_desc[ts->ts_last].td_ctl0 |= htole32(RTW_TXCTL0_LS);
! 3295: tdb->tdb_desc[ts->ts_first].td_ctl0 |=
! 3296: htole32(RTW_TXCTL0_FS);
! 3297:
! 3298: #ifdef RTW_DEBUG
! 3299: rtw_print_txdesc(sc, "FS on", ts, tdb, ts->ts_first);
! 3300: rtw_print_txdesc(sc, "LS on", ts, tdb, ts->ts_last);
! 3301: #endif /* RTW_DEBUG */
! 3302:
! 3303: tdb->tdb_nfree -= dmamap->dm_nsegs;
! 3304: tdb->tdb_next = desc;
! 3305:
! 3306: rtw_txdescs_sync(tdb, ts->ts_first, dmamap->dm_nsegs,
! 3307: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 3308:
! 3309: tdb->tdb_desc[ts->ts_first].td_ctl0 |=
! 3310: htole32(RTW_TXCTL0_OWN);
! 3311:
! 3312: #ifdef RTW_DEBUG
! 3313: rtw_print_txdesc(sc, "OWN on", ts, tdb, ts->ts_first);
! 3314: #endif /* RTW_DEBUG */
! 3315:
! 3316: rtw_txdescs_sync(tdb, ts->ts_first, 1,
! 3317: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
! 3318:
! 3319: SIMPLEQ_REMOVE_HEAD(&tsb->tsb_freeq, ts_q);
! 3320: SIMPLEQ_INSERT_TAIL(&tsb->tsb_dirtyq, ts, ts_q);
! 3321:
! 3322: if (tsb != &sc->sc_txsoft_blk[RTW_TXPRIBCN])
! 3323: sc->sc_led_state.ls_event |= RTW_LED_S_TX;
! 3324: tsb->tsb_tx_timer = 5;
! 3325: ifp->if_timer = 1;
! 3326: tppoll = RTW_READ8(&sc->sc_regs, RTW_TPPOLL);
! 3327: tppoll &= ~RTW_TPPOLL_SALL;
! 3328: tppoll |= tsb->tsb_poll & RTW_TPPOLL_ALL;
! 3329: RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL, tppoll);
! 3330: RTW_SYNC(&sc->sc_regs, RTW_TPPOLL, RTW_TPPOLL);
! 3331: }
! 3332: out:
! 3333: DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: leave\n", __func__));
! 3334: return;
! 3335: post_load_err:
! 3336: bus_dmamap_unload(sc->sc_dmat, dmamap);
! 3337: m_freem(m0);
! 3338: post_dequeue_err:
! 3339: ieee80211_release_node(&sc->sc_ic, ni);
! 3340: return;
! 3341: }
! 3342:
! 3343: void
! 3344: rtw_idle(struct rtw_regs *regs)
! 3345: {
! 3346: int active;
! 3347:
! 3348: /* request stop DMA; wait for packets to stop transmitting. */
! 3349:
! 3350: RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL);
! 3351: RTW_WBR(regs, RTW_TPPOLL, RTW_TPPOLL);
! 3352:
! 3353: for (active = 0; active < 300 &&
! 3354: (RTW_READ8(regs, RTW_TPPOLL) & RTW_TPPOLL_ACTIVE) != 0; active++)
! 3355: DELAY(10);
! 3356: RTW_DPRINTF(RTW_DEBUG_BUGS,
! 3357: ("%s: transmit DMA idle in %dus\n", __func__, active * 10));
! 3358: }
! 3359:
! 3360: void
! 3361: rtw_watchdog(struct ifnet *ifp)
! 3362: {
! 3363: int pri, tx_timeouts = 0;
! 3364: struct rtw_softc *sc;
! 3365: struct rtw_txsoft_blk *tsb;
! 3366:
! 3367: sc = ifp->if_softc;
! 3368:
! 3369: ifp->if_timer = 0;
! 3370:
! 3371: if ((sc->sc_flags & RTW_F_ENABLED) == 0)
! 3372: return;
! 3373:
! 3374: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 3375: tsb = &sc->sc_txsoft_blk[pri];
! 3376:
! 3377: if (tsb->tsb_tx_timer == 0)
! 3378: continue;
! 3379: else if (--tsb->tsb_tx_timer == 0) {
! 3380: if (SIMPLEQ_EMPTY(&tsb->tsb_dirtyq))
! 3381: continue;
! 3382: RTW_DPRINTF(RTW_DEBUG_BUGS,
! 3383: ("%s: transmit timeout, priority %d\n",
! 3384: ifp->if_xname, pri));
! 3385: ifp->if_oerrors++;
! 3386: tx_timeouts++;
! 3387: } else
! 3388: ifp->if_timer = 1;
! 3389: }
! 3390:
! 3391: if (tx_timeouts > 0) {
! 3392: /* Stop Tx DMA, disable xmtr, flush Tx rings, enable xmtr,
! 3393: * reset s/w tx-ring pointers, and start transmission.
! 3394: *
! 3395: * TBD Stop/restart just the broken rings?
! 3396: */
! 3397: rtw_idle(&sc->sc_regs);
! 3398: rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 0);
! 3399: rtw_txdescs_reset(sc);
! 3400: rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 1);
! 3401: rtw_txring_fixup(sc);
! 3402: rtw_start(ifp);
! 3403: }
! 3404: ieee80211_watchdog(ifp);
! 3405: }
! 3406:
! 3407: void
! 3408: rtw_next_scan(void *arg)
! 3409: {
! 3410: struct rtw_softc *sc = arg;
! 3411: struct ieee80211com *ic = &sc->sc_ic;
! 3412: struct ifnet *ifp = &ic->ic_if;
! 3413: int s;
! 3414:
! 3415: /* don't call rtw_start w/o network interrupts blocked */
! 3416: s = splnet();
! 3417: if (ic->ic_state == IEEE80211_S_SCAN)
! 3418: ieee80211_next_scan(ifp);
! 3419: splx(s);
! 3420: }
! 3421:
! 3422: void
! 3423: rtw_join_bss(struct rtw_softc *sc, u_int8_t *bssid, u_int16_t intval0)
! 3424: {
! 3425: uint16_t bcnitv, bintritv, intval;
! 3426: int i;
! 3427: struct rtw_regs *regs = &sc->sc_regs;
! 3428:
! 3429: for (i = 0; i < IEEE80211_ADDR_LEN; i++)
! 3430: RTW_WRITE8(regs, RTW_BSSID + i, bssid[i]);
! 3431:
! 3432: RTW_SYNC(regs, RTW_BSSID16, RTW_BSSID32);
! 3433:
! 3434: rtw_set_access(regs, RTW_ACCESS_CONFIG);
! 3435:
! 3436: intval = MIN(intval0, PRESHIFT(RTW_BCNITV_BCNITV_MASK));
! 3437:
! 3438: bcnitv = RTW_READ16(regs, RTW_BCNITV) & ~RTW_BCNITV_BCNITV_MASK;
! 3439: bcnitv |= LSHIFT(intval, RTW_BCNITV_BCNITV_MASK);
! 3440: RTW_WRITE16(regs, RTW_BCNITV, bcnitv);
! 3441: /* interrupt host 1ms before the TBTT */
! 3442: bintritv = RTW_READ16(regs, RTW_BINTRITV) & ~RTW_BINTRITV_BINTRITV;
! 3443: bintritv |= LSHIFT(1000, RTW_BINTRITV_BINTRITV);
! 3444: RTW_WRITE16(regs, RTW_BINTRITV, bintritv);
! 3445: /* magic from Linux */
! 3446: RTW_WRITE16(regs, RTW_ATIMWND, LSHIFT(1, RTW_ATIMWND_ATIMWND));
! 3447: RTW_WRITE16(regs, RTW_ATIMTRITV, LSHIFT(2, RTW_ATIMTRITV_ATIMTRITV));
! 3448: rtw_set_access(regs, RTW_ACCESS_NONE);
! 3449:
! 3450: /* TBD WEP */
! 3451: RTW_WRITE8(regs, RTW8180_SCR, 0);
! 3452:
! 3453: rtw_io_enable(regs, RTW_CR_RE | RTW_CR_TE, 1);
! 3454: }
! 3455:
! 3456: /* Synchronize the hardware state with the software state. */
! 3457: int
! 3458: rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 3459: {
! 3460: struct ifnet *ifp = &ic->ic_if;
! 3461: struct rtw_softc *sc = ifp->if_softc;
! 3462: enum ieee80211_state ostate;
! 3463: int error;
! 3464:
! 3465: ostate = ic->ic_state;
! 3466:
! 3467: rtw_led_newstate(sc, nstate);
! 3468:
! 3469: if (nstate == IEEE80211_S_INIT) {
! 3470: timeout_del(&sc->sc_scan_to);
! 3471: sc->sc_cur_chan = IEEE80211_CHAN_ANY;
! 3472: return (*sc->sc_mtbl.mt_newstate)(ic, nstate, arg);
! 3473: }
! 3474:
! 3475: if (ostate == IEEE80211_S_INIT && nstate != IEEE80211_S_INIT)
! 3476: rtw_pwrstate(sc, RTW_ON);
! 3477:
! 3478: if ((error = rtw_tune(sc)) != 0)
! 3479: return error;
! 3480:
! 3481: switch (nstate) {
! 3482: case IEEE80211_S_INIT:
! 3483: panic("%s: unexpected state IEEE80211_S_INIT", __func__);
! 3484: break;
! 3485: case IEEE80211_S_SCAN:
! 3486: if (ostate != IEEE80211_S_SCAN) {
! 3487: bzero(ic->ic_bss->ni_bssid, IEEE80211_ADDR_LEN);
! 3488: rtw_set_nettype(sc, IEEE80211_M_MONITOR);
! 3489: }
! 3490:
! 3491: timeout_add(&sc->sc_scan_to, rtw_dwelltime * hz / 1000);
! 3492:
! 3493: break;
! 3494: case IEEE80211_S_RUN:
! 3495: switch (ic->ic_opmode) {
! 3496: case IEEE80211_M_HOSTAP:
! 3497: case IEEE80211_M_IBSS:
! 3498: rtw_set_nettype(sc, IEEE80211_M_MONITOR);
! 3499: /*FALLTHROUGH*/
! 3500: case IEEE80211_M_AHDEMO:
! 3501: case IEEE80211_M_STA:
! 3502: rtw_join_bss(sc, ic->ic_bss->ni_bssid,
! 3503: ic->ic_bss->ni_intval);
! 3504: break;
! 3505: case IEEE80211_M_MONITOR:
! 3506: break;
! 3507: }
! 3508: rtw_set_nettype(sc, ic->ic_opmode);
! 3509: break;
! 3510: case IEEE80211_S_ASSOC:
! 3511: case IEEE80211_S_AUTH:
! 3512: break;
! 3513: }
! 3514:
! 3515: if (nstate != IEEE80211_S_SCAN)
! 3516: timeout_del(&sc->sc_scan_to);
! 3517:
! 3518: return (*sc->sc_mtbl.mt_newstate)(ic, nstate, arg);
! 3519: }
! 3520:
! 3521: /* Extend a 32-bit TSF timestamp to a 64-bit timestamp. */
! 3522: uint64_t
! 3523: rtw_tsf_extend(struct rtw_regs *regs, u_int32_t rstamp)
! 3524: {
! 3525: u_int32_t tsftl, tsfth;
! 3526:
! 3527: tsfth = RTW_READ(regs, RTW_TSFTRH);
! 3528: tsftl = RTW_READ(regs, RTW_TSFTRL);
! 3529: if (tsftl < rstamp) /* Compensate for rollover. */
! 3530: tsfth--;
! 3531: return ((u_int64_t)tsfth << 32) | rstamp;
! 3532: }
! 3533:
! 3534: void
! 3535: rtw_ibss_merge(struct rtw_softc *sc, struct ieee80211_node *ni,
! 3536: u_int32_t rstamp)
! 3537: {
! 3538: u_int8_t tppoll;
! 3539: struct ieee80211com *ic = &sc->sc_ic;
! 3540:
! 3541: if (ieee80211_ibss_merge(ic, ni,
! 3542: rtw_tsf_extend(&sc->sc_regs, rstamp)) == ENETRESET) {
! 3543: /* Stop beacon queue. Kick state machine to synchronize
! 3544: * with the new IBSS.
! 3545: */
! 3546: tppoll = RTW_READ8(&sc->sc_regs, RTW_TPPOLL);
! 3547: tppoll |= RTW_TPPOLL_SBQ;
! 3548: RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL, tppoll);
! 3549: (void)ieee80211_new_state(&sc->sc_ic, IEEE80211_S_RUN, -1);
! 3550: }
! 3551: return;
! 3552: }
! 3553:
! 3554: void
! 3555: rtw_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
! 3556: struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp)
! 3557: {
! 3558: struct rtw_softc *sc = (struct rtw_softc*)ic->ic_softc;
! 3559:
! 3560: (*sc->sc_mtbl.mt_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
! 3561:
! 3562: switch (subtype) {
! 3563: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
! 3564: case IEEE80211_FC0_SUBTYPE_BEACON:
! 3565: if (ic->ic_opmode != IEEE80211_M_IBSS ||
! 3566: ic->ic_state != IEEE80211_S_RUN)
! 3567: return;
! 3568: rtw_ibss_merge(sc, ni, rstamp);
! 3569: break;
! 3570: default:
! 3571: break;
! 3572: }
! 3573: return;
! 3574: }
! 3575:
! 3576: struct ieee80211_node *
! 3577: rtw_node_alloc(struct ieee80211com *ic)
! 3578: {
! 3579: struct rtw_softc *sc = (struct rtw_softc *)ic->ic_if.if_softc;
! 3580: struct ieee80211_node *ni = (*sc->sc_mtbl.mt_node_alloc)(ic);
! 3581:
! 3582: DPRINTF(sc, RTW_DEBUG_NODE,
! 3583: ("%s: alloc node %p\n", sc->sc_dev.dv_xname, ni));
! 3584: return ni;
! 3585: }
! 3586:
! 3587: void
! 3588: rtw_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
! 3589: {
! 3590: struct rtw_softc *sc = (struct rtw_softc *)ic->ic_if.if_softc;
! 3591:
! 3592: DPRINTF(sc, RTW_DEBUG_NODE,
! 3593: ("%s: freeing node %p %s\n", sc->sc_dev.dv_xname, ni,
! 3594: ether_sprintf(ni->ni_bssid)));
! 3595: (*sc->sc_mtbl.mt_node_free)(ic, ni);
! 3596: }
! 3597:
! 3598: int
! 3599: rtw_media_change(struct ifnet *ifp)
! 3600: {
! 3601: int error;
! 3602:
! 3603: error = ieee80211_media_change(ifp);
! 3604: if (error == ENETRESET) {
! 3605: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) ==
! 3606: (IFF_RUNNING|IFF_UP))
! 3607: rtw_init(ifp); /* XXX lose error */
! 3608: error = 0;
! 3609: }
! 3610: return error;
! 3611: }
! 3612:
! 3613: void
! 3614: rtw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 3615: {
! 3616: struct rtw_softc *sc = ifp->if_softc;
! 3617:
! 3618: if ((sc->sc_flags & RTW_F_ENABLED) == 0) {
! 3619: imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
! 3620: imr->ifm_status = 0;
! 3621: return;
! 3622: }
! 3623: ieee80211_media_status(ifp, imr);
! 3624: }
! 3625:
! 3626: void
! 3627: rtw_power(int why, void *arg)
! 3628: {
! 3629: struct rtw_softc *sc = arg;
! 3630: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 3631: int s;
! 3632:
! 3633: DPRINTF(sc, RTW_DEBUG_PWR,
! 3634: ("%s: rtw_power(%d,)\n", sc->sc_dev.dv_xname, why));
! 3635:
! 3636: s = splnet();
! 3637: switch (why) {
! 3638: case PWR_STANDBY:
! 3639: /* XXX do nothing. */
! 3640: break;
! 3641: case PWR_SUSPEND:
! 3642: rtw_stop(ifp, 1);
! 3643: if (sc->sc_power != NULL)
! 3644: (*sc->sc_power)(sc, why);
! 3645: break;
! 3646: case PWR_RESUME:
! 3647: if (ifp->if_flags & IFF_UP) {
! 3648: if (sc->sc_power != NULL)
! 3649: (*sc->sc_power)(sc, why);
! 3650: rtw_init(ifp);
! 3651: }
! 3652: break;
! 3653: }
! 3654: splx(s);
! 3655: }
! 3656:
! 3657: /* rtw_shutdown: make sure the interface is stopped at reboot time. */
! 3658: void
! 3659: rtw_shutdown(void *arg)
! 3660: {
! 3661: struct rtw_softc *sc = arg;
! 3662:
! 3663: rtw_stop(&sc->sc_ic.ic_if, 1);
! 3664: }
! 3665:
! 3666: void
! 3667: rtw_establish_hooks(struct rtw_hooks *hooks, const char *dvname,
! 3668: void *arg)
! 3669: {
! 3670: /*
! 3671: * Make sure the interface is shutdown during reboot.
! 3672: */
! 3673: hooks->rh_shutdown = shutdownhook_establish(rtw_shutdown, arg);
! 3674: if (hooks->rh_shutdown == NULL)
! 3675: printf("%s: WARNING: unable to establish shutdown hook\n",
! 3676: dvname);
! 3677:
! 3678: /*
! 3679: * Add a suspend hook to make sure we come back up after a
! 3680: * resume.
! 3681: */
! 3682: hooks->rh_power = powerhook_establish(rtw_power, arg);
! 3683: if (hooks->rh_power == NULL)
! 3684: printf("%s: WARNING: unable to establish power hook\n",
! 3685: dvname);
! 3686: }
! 3687:
! 3688: void
! 3689: rtw_disestablish_hooks(struct rtw_hooks *hooks, const char *dvname,
! 3690: void *arg)
! 3691: {
! 3692: if (hooks->rh_shutdown != NULL)
! 3693: shutdownhook_disestablish(hooks->rh_shutdown);
! 3694:
! 3695: if (hooks->rh_power != NULL)
! 3696: powerhook_disestablish(hooks->rh_power);
! 3697: }
! 3698:
! 3699: int
! 3700: rtw_txsoft_blk_setup(struct rtw_txsoft_blk *tsb, u_int qlen)
! 3701: {
! 3702: SIMPLEQ_INIT(&tsb->tsb_dirtyq);
! 3703: SIMPLEQ_INIT(&tsb->tsb_freeq);
! 3704: tsb->tsb_ndesc = qlen;
! 3705: tsb->tsb_desc = malloc(qlen * sizeof(*tsb->tsb_desc), M_DEVBUF,
! 3706: M_NOWAIT);
! 3707: if (tsb->tsb_desc == NULL)
! 3708: return ENOMEM;
! 3709: return 0;
! 3710: }
! 3711:
! 3712: void
! 3713: rtw_txsoft_blk_cleanup_all(struct rtw_softc *sc)
! 3714: {
! 3715: int pri;
! 3716: struct rtw_txsoft_blk *tsb;
! 3717:
! 3718: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 3719: tsb = &sc->sc_txsoft_blk[pri];
! 3720: free(tsb->tsb_desc, M_DEVBUF);
! 3721: tsb->tsb_desc = NULL;
! 3722: }
! 3723: }
! 3724:
! 3725: int
! 3726: rtw_txsoft_blk_setup_all(struct rtw_softc *sc)
! 3727: {
! 3728: int pri, rc = 0;
! 3729: int qlen[RTW_NTXPRI] =
! 3730: {RTW_TXQLENLO, RTW_TXQLENMD, RTW_TXQLENHI, RTW_TXQLENBCN};
! 3731: struct rtw_txsoft_blk *tsbs;
! 3732:
! 3733: tsbs = sc->sc_txsoft_blk;
! 3734:
! 3735: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 3736: rc = rtw_txsoft_blk_setup(&tsbs[pri], qlen[pri]);
! 3737: if (rc != 0)
! 3738: break;
! 3739: }
! 3740: tsbs[RTW_TXPRILO].tsb_poll = RTW_TPPOLL_LPQ | RTW_TPPOLL_SLPQ;
! 3741: tsbs[RTW_TXPRIMD].tsb_poll = RTW_TPPOLL_NPQ | RTW_TPPOLL_SNPQ;
! 3742: tsbs[RTW_TXPRIHI].tsb_poll = RTW_TPPOLL_HPQ | RTW_TPPOLL_SHPQ;
! 3743: tsbs[RTW_TXPRIBCN].tsb_poll = RTW_TPPOLL_BQ | RTW_TPPOLL_SBQ;
! 3744: return rc;
! 3745: }
! 3746:
! 3747: void
! 3748: rtw_txdesc_blk_setup(struct rtw_txdesc_blk *tdb, struct rtw_txdesc *desc,
! 3749: u_int ndesc, bus_addr_t ofs, bus_addr_t physbase)
! 3750: {
! 3751: tdb->tdb_ndesc = ndesc;
! 3752: tdb->tdb_desc = desc;
! 3753: tdb->tdb_physbase = physbase;
! 3754: tdb->tdb_ofs = ofs;
! 3755:
! 3756: bzero(tdb->tdb_desc, sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc);
! 3757:
! 3758: rtw_txdesc_blk_init(tdb);
! 3759: tdb->tdb_next = 0;
! 3760: }
! 3761:
! 3762: void
! 3763: rtw_txdesc_blk_setup_all(struct rtw_softc *sc)
! 3764: {
! 3765: rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRILO],
! 3766: &sc->sc_descs->hd_txlo[0], RTW_NTXDESCLO,
! 3767: RTW_RING_OFFSET(hd_txlo), RTW_RING_BASE(sc, hd_txlo));
! 3768:
! 3769: rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRIMD],
! 3770: &sc->sc_descs->hd_txmd[0], RTW_NTXDESCMD,
! 3771: RTW_RING_OFFSET(hd_txmd), RTW_RING_BASE(sc, hd_txmd));
! 3772:
! 3773: rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRIHI],
! 3774: &sc->sc_descs->hd_txhi[0], RTW_NTXDESCHI,
! 3775: RTW_RING_OFFSET(hd_txhi), RTW_RING_BASE(sc, hd_txhi));
! 3776:
! 3777: rtw_txdesc_blk_setup(&sc->sc_txdesc_blk[RTW_TXPRIBCN],
! 3778: &sc->sc_descs->hd_bcn[0], RTW_NTXDESCBCN,
! 3779: RTW_RING_OFFSET(hd_bcn), RTW_RING_BASE(sc, hd_bcn));
! 3780: }
! 3781:
! 3782: int
! 3783: rtw_rf_attach(struct rtw_softc *sc, int rfchipid)
! 3784: {
! 3785: struct rtw_bbpset *bb = &sc->sc_bbpset;
! 3786: int notsup = 0;
! 3787: const char *rfname, *paname = NULL;
! 3788: char scratch[sizeof("unknown 0xXX")];
! 3789:
! 3790: switch (rfchipid) {
! 3791: case RTW_RFCHIPID_RTL8225:
! 3792: rfname = "RTL8225";
! 3793: sc->sc_pwrstate_cb = rtw_rtl_pwrstate;
! 3794: sc->sc_rf_init = rtw_rtl8255_init;
! 3795: sc->sc_rf_pwrstate = rtw_rtl8225_pwrstate;
! 3796: sc->sc_rf_tune = rtw_rtl8225_tune;
! 3797: sc->sc_rf_txpower = rtw_rtl8225_txpower;
! 3798: break;
! 3799: case RTW_RFCHIPID_RTL8255:
! 3800: rfname = "RTL8255";
! 3801: sc->sc_pwrstate_cb = rtw_rtl_pwrstate;
! 3802: sc->sc_rf_init = rtw_rtl8255_init;
! 3803: sc->sc_rf_pwrstate = rtw_rtl8255_pwrstate;
! 3804: sc->sc_rf_tune = rtw_rtl8255_tune;
! 3805: sc->sc_rf_txpower = rtw_rtl8255_txpower;
! 3806: break;
! 3807: case RTW_RFCHIPID_MAXIM2820:
! 3808: rfname = "MAX2820"; /* guess */
! 3809: paname = "MAX2422"; /* guess */
! 3810: /* XXX magic */
! 3811: bb->bb_antatten = RTW_BBP_ANTATTEN_MAXIM_MAGIC;
! 3812: bb->bb_chestlim = 0x00;
! 3813: bb->bb_chsqlim = 0x9f;
! 3814: bb->bb_ifagcdet = 0x64;
! 3815: bb->bb_ifagcini = 0x90;
! 3816: bb->bb_ifagclimit = 0x1a;
! 3817: bb->bb_lnadet = 0xf8;
! 3818: bb->bb_sys1 = 0x88;
! 3819: bb->bb_sys2 = 0x47;
! 3820: bb->bb_sys3 = 0x9b;
! 3821: bb->bb_trl = 0x88;
! 3822: bb->bb_txagc = 0x08;
! 3823: sc->sc_pwrstate_cb = rtw_maxim_pwrstate;
! 3824: sc->sc_rf_init = rtw_max2820_init;
! 3825: sc->sc_rf_pwrstate = rtw_max2820_pwrstate;
! 3826: sc->sc_rf_tune = rtw_max2820_tune;
! 3827: sc->sc_rf_txpower = rtw_max2820_txpower;
! 3828: break;
! 3829: case RTW_RFCHIPID_PHILIPS:
! 3830: rfname = "SA2400A";
! 3831: paname = "SA2411";
! 3832: /* XXX magic */
! 3833: bb->bb_antatten = RTW_BBP_ANTATTEN_PHILIPS_MAGIC;
! 3834: bb->bb_chestlim = 0x00;
! 3835: bb->bb_chsqlim = 0xa0;
! 3836: bb->bb_ifagcdet = 0x64;
! 3837: bb->bb_ifagcini = 0x90;
! 3838: bb->bb_ifagclimit = 0x1a;
! 3839: bb->bb_lnadet = 0xe0;
! 3840: bb->bb_sys1 = 0x98;
! 3841: bb->bb_sys2 = 0x47;
! 3842: bb->bb_sys3 = 0x90;
! 3843: bb->bb_trl = 0x88;
! 3844: bb->bb_txagc = 0x38;
! 3845: sc->sc_pwrstate_cb = rtw_philips_pwrstate;
! 3846: sc->sc_rf_init = rtw_sa2400_init;
! 3847: sc->sc_rf_pwrstate = rtw_sa2400_pwrstate;
! 3848: sc->sc_rf_tune = rtw_sa2400_tune;
! 3849: sc->sc_rf_txpower = rtw_sa2400_txpower;
! 3850: break;
! 3851: case RTW_RFCHIPID_RFMD2948:
! 3852: /* this is the same front-end as an atw(4)! */
! 3853: rfname = "RFMD RF2948B, " /* mentioned in Realtek docs */
! 3854: "LNA: RFMD RF2494, " /* mentioned in Realtek docs */
! 3855: "SYN: Silicon Labs Si4126"; /* inferred from
! 3856: * reference driver
! 3857: */
! 3858: paname = "RF2189"; /* mentioned in Realtek docs */
! 3859: /* XXX RFMD has no RF constructor */
! 3860: sc->sc_pwrstate_cb = rtw_rfmd_pwrstate;
! 3861: notsup = 1;
! 3862: break;
! 3863: case RTW_RFCHIPID_GCT: /* this combo seen in the wild */
! 3864: rfname = "GRF5101";
! 3865: paname = "WS9901";
! 3866: /* XXX magic */
! 3867: bb->bb_antatten = RTW_BBP_ANTATTEN_GCT_MAGIC;
! 3868: bb->bb_chestlim = 0x00;
! 3869: bb->bb_chsqlim = 0xa0;
! 3870: bb->bb_ifagcdet = 0x64;
! 3871: bb->bb_ifagcini = 0x90;
! 3872: bb->bb_ifagclimit = 0x1e;
! 3873: bb->bb_lnadet = 0xc0;
! 3874: bb->bb_sys1 = 0xa8;
! 3875: bb->bb_sys2 = 0x47;
! 3876: bb->bb_sys3 = 0x9b;
! 3877: bb->bb_trl = 0x88;
! 3878: bb->bb_txagc = 0x08;
! 3879: sc->sc_pwrstate_cb = rtw_maxim_pwrstate;
! 3880: sc->sc_rf_init = rtw_grf5101_init;
! 3881: sc->sc_rf_pwrstate = rtw_grf5101_pwrstate;
! 3882: sc->sc_rf_tune = rtw_grf5101_tune;
! 3883: sc->sc_rf_txpower = rtw_grf5101_txpower;
! 3884: break;
! 3885: case RTW_RFCHIPID_INTERSIL:
! 3886: rfname = "HFA3873"; /* guess */
! 3887: paname = "Intersil <unknown>";
! 3888: notsup = 1;
! 3889: break;
! 3890: default:
! 3891: snprintf(scratch, sizeof(scratch), "unknown 0x%02x", rfchipid);
! 3892: rfname = scratch;
! 3893: notsup = 1;
! 3894: }
! 3895:
! 3896: printf("radio %s, ", rfname);
! 3897: if (paname != NULL)
! 3898: printf("amp %s, ", paname);
! 3899:
! 3900: return (notsup);
! 3901: }
! 3902:
! 3903: /* Revision C and later use a different PHY delay setting than
! 3904: * revisions A and B.
! 3905: */
! 3906: u_int8_t
! 3907: rtw_check_phydelay(struct rtw_regs *regs, u_int32_t rcr0)
! 3908: {
! 3909: #define REVAB (RTW_RCR_MXDMA_UNLIMITED | RTW_RCR_AICV)
! 3910: #define REVC (REVAB | RTW8180_RCR_RXFTH_WHOLE)
! 3911:
! 3912: u_int8_t phydelay = LSHIFT(0x6, RTW_PHYDELAY_PHYDELAY);
! 3913:
! 3914: RTW_WRITE(regs, RTW_RCR, REVAB);
! 3915: RTW_WBW(regs, RTW_RCR, RTW_RCR);
! 3916: RTW_WRITE(regs, RTW_RCR, REVC);
! 3917:
! 3918: RTW_WBR(regs, RTW_RCR, RTW_RCR);
! 3919: if ((RTW_READ(regs, RTW_RCR) & REVC) == REVC)
! 3920: phydelay |= RTW_PHYDELAY_REVC_MAGIC;
! 3921:
! 3922: RTW_WRITE(regs, RTW_RCR, rcr0); /* restore RCR */
! 3923: RTW_SYNC(regs, RTW_RCR, RTW_RCR);
! 3924:
! 3925: return phydelay;
! 3926: #undef REVC
! 3927: }
! 3928:
! 3929: void
! 3930: rtw_attach(struct rtw_softc *sc)
! 3931: {
! 3932: struct ieee80211com *ic = &sc->sc_ic;
! 3933: struct rtw_txsoft_blk *tsb;
! 3934: struct rtw_mtbl *mtbl;
! 3935: struct rtw_srom *sr;
! 3936: const char *vername;
! 3937: struct ifnet *ifp;
! 3938: char scratch[sizeof("unknown 0xXXXXXXXX")];
! 3939: int pri, rc;
! 3940:
! 3941:
! 3942: /* Use default DMA memory access */
! 3943: if (sc->sc_regs.r_read8 == NULL) {
! 3944: sc->sc_regs.r_read8 = rtw_read8;
! 3945: sc->sc_regs.r_read16 = rtw_read16;
! 3946: sc->sc_regs.r_read32 = rtw_read32;
! 3947: sc->sc_regs.r_write8 = rtw_write8;
! 3948: sc->sc_regs.r_write16 = rtw_write16;
! 3949: sc->sc_regs.r_write32 = rtw_write32;
! 3950: sc->sc_regs.r_barrier = rtw_barrier;
! 3951: }
! 3952:
! 3953: sc->sc_hwverid = RTW_READ(&sc->sc_regs, RTW_TCR) & RTW_TCR_HWVERID_MASK;
! 3954: switch (sc->sc_hwverid) {
! 3955: case RTW_TCR_HWVERID_RTL8185:
! 3956: vername = "RTL8185";
! 3957: sc->sc_flags |= RTW_F_RTL8185;
! 3958: break;
! 3959: case RTW_TCR_HWVERID_RTL8180F:
! 3960: vername = "RTL8180F";
! 3961: break;
! 3962: case RTW_TCR_HWVERID_RTL8180D:
! 3963: vername = "RTL8180D";
! 3964: break;
! 3965: default:
! 3966: snprintf(scratch, sizeof(scratch), "unknown 0x%08x",
! 3967: sc->sc_hwverid);
! 3968: vername = scratch;
! 3969: break;
! 3970: }
! 3971:
! 3972: printf("%s: ver %s, ", sc->sc_dev.dv_xname, vername);
! 3973:
! 3974: rc = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct rtw_descs),
! 3975: RTW_DESC_ALIGNMENT, 0, &sc->sc_desc_segs, 1, &sc->sc_desc_nsegs,
! 3976: 0);
! 3977:
! 3978: if (rc != 0) {
! 3979: printf("\n%s: could not allocate hw descriptors, error %d\n",
! 3980: sc->sc_dev.dv_xname, rc);
! 3981: goto fail0;
! 3982: }
! 3983:
! 3984: rc = bus_dmamem_map(sc->sc_dmat, &sc->sc_desc_segs,
! 3985: sc->sc_desc_nsegs, sizeof(struct rtw_descs),
! 3986: (caddr_t*)&sc->sc_descs, BUS_DMA_COHERENT);
! 3987:
! 3988: if (rc != 0) {
! 3989: printf("\n%s: could not map hw descriptors, error %d\n",
! 3990: sc->sc_dev.dv_xname, rc);
! 3991: goto fail1;
! 3992: }
! 3993:
! 3994: rc = bus_dmamap_create(sc->sc_dmat, sizeof(struct rtw_descs), 1,
! 3995: sizeof(struct rtw_descs), 0, 0, &sc->sc_desc_dmamap);
! 3996:
! 3997: if (rc != 0) {
! 3998: printf("\n%s: could not create DMA map for hw descriptors, "
! 3999: "error %d\n", sc->sc_dev.dv_xname, rc);
! 4000: goto fail2;
! 4001: }
! 4002:
! 4003: sc->sc_rxdesc_blk.rdb_dmat = sc->sc_dmat;
! 4004: sc->sc_rxdesc_blk.rdb_dmamap = sc->sc_desc_dmamap;
! 4005:
! 4006: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 4007: sc->sc_txdesc_blk[pri].tdb_dmat = sc->sc_dmat;
! 4008: sc->sc_txdesc_blk[pri].tdb_dmamap = sc->sc_desc_dmamap;
! 4009: }
! 4010:
! 4011: rc = bus_dmamap_load(sc->sc_dmat, sc->sc_desc_dmamap, sc->sc_descs,
! 4012: sizeof(struct rtw_descs), NULL, 0);
! 4013:
! 4014: if (rc != 0) {
! 4015: printf("\n%s: could not load DMA map for hw descriptors, "
! 4016: "error %d\n", sc->sc_dev.dv_xname, rc);
! 4017: goto fail3;
! 4018: }
! 4019:
! 4020: if (rtw_txsoft_blk_setup_all(sc) != 0)
! 4021: goto fail4;
! 4022:
! 4023: rtw_txdesc_blk_setup_all(sc);
! 4024:
! 4025: sc->sc_rxdesc_blk.rdb_desc = &sc->sc_descs->hd_rx[0];
! 4026:
! 4027: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 4028: tsb = &sc->sc_txsoft_blk[pri];
! 4029:
! 4030: if ((rc = rtw_txdesc_dmamaps_create(sc->sc_dmat,
! 4031: &tsb->tsb_desc[0], tsb->tsb_ndesc)) != 0) {
! 4032: printf("\n%s: could not load DMA map for "
! 4033: "hw tx descriptors, error %d\n",
! 4034: sc->sc_dev.dv_xname, rc);
! 4035: goto fail5;
! 4036: }
! 4037: }
! 4038:
! 4039: if ((rc = rtw_rxdesc_dmamaps_create(sc->sc_dmat, &sc->sc_rxsoft[0],
! 4040: RTW_RXQLEN)) != 0) {
! 4041: printf("\n%s: could not load DMA map for hw rx descriptors, "
! 4042: "error %d\n", sc->sc_dev.dv_xname, rc);
! 4043: goto fail6;
! 4044: }
! 4045:
! 4046: /* Reset the chip to a known state. */
! 4047: if (rtw_reset(sc) != 0)
! 4048: goto fail7;
! 4049:
! 4050: sc->sc_rcr = RTW_READ(&sc->sc_regs, RTW_RCR);
! 4051:
! 4052: if ((sc->sc_rcr & RTW_RCR_9356SEL) != 0)
! 4053: sc->sc_flags |= RTW_F_9356SROM;
! 4054:
! 4055: if (rtw_srom_read(&sc->sc_regs, sc->sc_flags, &sc->sc_srom,
! 4056: sc->sc_dev.dv_xname) != 0)
! 4057: goto fail7;
! 4058:
! 4059: if (rtw_srom_parse(sc) != 0) {
! 4060: printf("\n%s: attach failed, malformed serial ROM\n",
! 4061: sc->sc_dev.dv_xname);
! 4062: goto fail8;
! 4063: }
! 4064:
! 4065: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: %s PHY\n", sc->sc_dev.dv_xname,
! 4066: ((sc->sc_flags & RTW_F_DIGPHY) != 0) ? "digital" : "analog"));
! 4067:
! 4068: RTW_DPRINTF(RTW_DEBUG_ATTACH, ("%s: CS threshold %u\n",
! 4069: sc->sc_dev.dv_xname, sc->sc_csthr));
! 4070:
! 4071: if ((rtw_rf_attach(sc, sc->sc_rfchipid)) != 0) {
! 4072: printf("\n%s: attach failed, could not attach RF\n",
! 4073: sc->sc_dev.dv_xname);
! 4074: goto fail8;
! 4075: }
! 4076:
! 4077: sc->sc_phydelay = rtw_check_phydelay(&sc->sc_regs, sc->sc_rcr);
! 4078:
! 4079: RTW_DPRINTF(RTW_DEBUG_ATTACH,
! 4080: ("%s: PHY delay %d\n", sc->sc_dev.dv_xname, sc->sc_phydelay));
! 4081:
! 4082: if (sc->sc_locale == RTW_LOCALE_UNKNOWN)
! 4083: rtw_identify_country(&sc->sc_regs, &sc->sc_locale);
! 4084:
! 4085: rtw_init_channels(sc->sc_locale, &sc->sc_ic.ic_channels,
! 4086: sc->sc_dev.dv_xname);
! 4087:
! 4088: if (rtw_identify_sta(&sc->sc_regs, &sc->sc_ic.ic_myaddr,
! 4089: sc->sc_dev.dv_xname) != 0)
! 4090: goto fail8;
! 4091:
! 4092: ifp = &sc->sc_if;
! 4093: (void)memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 4094: ifp->if_softc = sc;
! 4095: ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST |
! 4096: IFF_NOTRAILERS;
! 4097: ifp->if_ioctl = rtw_ioctl;
! 4098: ifp->if_start = rtw_start;
! 4099: ifp->if_watchdog = rtw_watchdog;
! 4100:
! 4101: IFQ_SET_READY(&sc->sc_if.if_snd);
! 4102:
! 4103: ic->ic_phytype = IEEE80211_T_DS;
! 4104: ic->ic_opmode = IEEE80211_M_STA;
! 4105: ic->ic_caps = IEEE80211_C_PMGT | IEEE80211_C_IBSS |
! 4106: IEEE80211_C_HOSTAP | IEEE80211_C_MONITOR | IEEE80211_C_WEP;
! 4107:
! 4108: ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
! 4109:
! 4110: rtw_led_attach(&sc->sc_led_state, (void *)sc);
! 4111:
! 4112: /*
! 4113: * Call MI attach routines.
! 4114: */
! 4115: if_attach(&sc->sc_if);
! 4116: ieee80211_ifattach(&sc->sc_if);
! 4117:
! 4118: mtbl = &sc->sc_mtbl;
! 4119: mtbl->mt_newstate = ic->ic_newstate;
! 4120: ic->ic_newstate = rtw_newstate;
! 4121:
! 4122: mtbl->mt_recv_mgmt = ic->ic_recv_mgmt;
! 4123: ic->ic_recv_mgmt = rtw_recv_mgmt;
! 4124:
! 4125: mtbl->mt_node_free = ic->ic_node_free;
! 4126: ic->ic_node_free = rtw_node_free;
! 4127:
! 4128: mtbl->mt_node_alloc = ic->ic_node_alloc;
! 4129: ic->ic_node_alloc = rtw_node_alloc;
! 4130:
! 4131: /* possibly we should fill in our own sc_send_prresp, since
! 4132: * the RTL8180 is probably sending probe responses in ad hoc
! 4133: * mode.
! 4134: */
! 4135:
! 4136: /* complete initialization */
! 4137: ieee80211_media_init(&sc->sc_if, rtw_media_change, rtw_media_status);
! 4138: timeout_set(&sc->sc_scan_to, rtw_next_scan, sc);
! 4139:
! 4140: #if NBPFILTER > 0
! 4141: bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu));
! 4142: sc->sc_rxtap.rr_ihdr.it_len = sizeof(sc->sc_rxtapu);
! 4143: sc->sc_rxtap.rr_ihdr.it_present = RTW_RX_RADIOTAP_PRESENT;
! 4144:
! 4145: bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu));
! 4146: sc->sc_txtap.rt_ihdr.it_len = sizeof(sc->sc_txtapu);
! 4147: sc->sc_txtap.rt_ihdr.it_present = RTW_TX_RADIOTAP_PRESENT;
! 4148:
! 4149: bpfattach(&sc->sc_radiobpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO,
! 4150: sizeof(struct ieee80211_frame) + 64);
! 4151: #endif
! 4152:
! 4153: rtw_establish_hooks(&sc->sc_hooks, sc->sc_dev.dv_xname, (void*)sc);
! 4154:
! 4155: return;
! 4156:
! 4157: fail8:
! 4158: sr = &sc->sc_srom;
! 4159: sr->sr_size = 0;
! 4160: if (sr->sr_content != NULL) {
! 4161: free(sr->sr_content, M_DEVBUF);
! 4162: sr->sr_content = NULL;
! 4163: }
! 4164:
! 4165: fail7:
! 4166: rtw_rxdesc_dmamaps_destroy(sc->sc_dmat, &sc->sc_rxsoft[0],
! 4167: RTW_RXQLEN);
! 4168:
! 4169: fail6:
! 4170: for (pri = 0; pri < RTW_NTXPRI; pri++) {
! 4171: rtw_txdesc_dmamaps_destroy(sc->sc_dmat,
! 4172: sc->sc_txsoft_blk[pri].tsb_desc,
! 4173: sc->sc_txsoft_blk[pri].tsb_ndesc);
! 4174: }
! 4175:
! 4176: fail5:
! 4177: rtw_txsoft_blk_cleanup_all(sc);
! 4178:
! 4179: fail4:
! 4180: bus_dmamap_unload(sc->sc_dmat, sc->sc_desc_dmamap);
! 4181: fail3:
! 4182: bus_dmamap_destroy(sc->sc_dmat, sc->sc_desc_dmamap);
! 4183: fail2:
! 4184: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_descs,
! 4185: sizeof(struct rtw_descs));
! 4186: fail1:
! 4187: bus_dmamem_free(sc->sc_dmat, &sc->sc_desc_segs,
! 4188: sc->sc_desc_nsegs);
! 4189: fail0:
! 4190: return;
! 4191: }
! 4192:
! 4193: int
! 4194: rtw_detach(struct rtw_softc *sc)
! 4195: {
! 4196: sc->sc_flags |= RTW_F_INVALID;
! 4197:
! 4198: rtw_stop(&sc->sc_if, 1);
! 4199:
! 4200: rtw_disestablish_hooks(&sc->sc_hooks, sc->sc_dev.dv_xname,
! 4201: (void*)sc);
! 4202: timeout_del(&sc->sc_scan_to);
! 4203: ieee80211_ifdetach(&sc->sc_if);
! 4204: if_detach(&sc->sc_if);
! 4205:
! 4206: return 0;
! 4207: }
! 4208:
! 4209: /*
! 4210: * PHY specific functions
! 4211: */
! 4212:
! 4213: int
! 4214: rtw_bbp_preinit(struct rtw_regs *regs, u_int antatten0, int dflantb,
! 4215: u_int freq)
! 4216: {
! 4217: u_int antatten = antatten0;
! 4218: if (dflantb)
! 4219: antatten |= RTW_BBP_ANTATTEN_DFLANTB;
! 4220: if (freq == 2484) /* channel 14 */
! 4221: antatten |= RTW_BBP_ANTATTEN_CHAN14;
! 4222: return rtw_bbp_write(regs, RTW_BBP_ANTATTEN, antatten);
! 4223: }
! 4224:
! 4225: int
! 4226: rtw_bbp_init(struct rtw_regs *regs, struct rtw_bbpset *bb, int antdiv,
! 4227: int dflantb, u_int8_t cs_threshold, u_int freq)
! 4228: {
! 4229: int rc;
! 4230: u_int32_t sys2, sys3;
! 4231:
! 4232: sys2 = bb->bb_sys2;
! 4233: if (antdiv)
! 4234: sys2 |= RTW_BBP_SYS2_ANTDIV;
! 4235: sys3 = bb->bb_sys3 |
! 4236: LSHIFT(cs_threshold, RTW_BBP_SYS3_CSTHRESH_MASK);
! 4237:
! 4238: #define RTW_BBP_WRITE_OR_RETURN(reg, val) \
! 4239: if ((rc = rtw_bbp_write(regs, reg, val)) != 0) \
! 4240: return rc;
! 4241:
! 4242: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_SYS1, bb->bb_sys1);
! 4243: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_TXAGC, bb->bb_txagc);
! 4244: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_LNADET, bb->bb_lnadet);
! 4245: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_IFAGCINI, bb->bb_ifagcini);
! 4246: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_IFAGCLIMIT, bb->bb_ifagclimit);
! 4247: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_IFAGCDET, bb->bb_ifagcdet);
! 4248:
! 4249: if ((rc = rtw_bbp_preinit(regs, bb->bb_antatten, dflantb, freq)) != 0)
! 4250: return rc;
! 4251:
! 4252: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_TRL, bb->bb_trl);
! 4253: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_SYS2, sys2);
! 4254: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_SYS3, sys3);
! 4255: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_CHESTLIM, bb->bb_chestlim);
! 4256: RTW_BBP_WRITE_OR_RETURN(RTW_BBP_CHSQLIM, bb->bb_chsqlim);
! 4257: return 0;
! 4258: }
! 4259:
! 4260: int
! 4261: rtw_sa2400_txpower(struct rtw_softc *sc, u_int8_t opaque_txpower)
! 4262: {
! 4263: return rtw_rf_macwrite(sc, SA2400_TX, opaque_txpower);
! 4264: }
! 4265:
! 4266: /* make sure we're using the same settings as the reference driver */
! 4267: void
! 4268: rtw_verify_syna(u_int freq, u_int32_t val)
! 4269: {
! 4270: u_int32_t expected_val = ~val;
! 4271:
! 4272: switch (freq) {
! 4273: case 2412:
! 4274: expected_val = 0x0000096c; /* ch 1 */
! 4275: break;
! 4276: case 2417:
! 4277: expected_val = 0x00080970; /* ch 2 */
! 4278: break;
! 4279: case 2422:
! 4280: expected_val = 0x00100974; /* ch 3 */
! 4281: break;
! 4282: case 2427:
! 4283: expected_val = 0x00180978; /* ch 4 */
! 4284: break;
! 4285: case 2432:
! 4286: expected_val = 0x00000980; /* ch 5 */
! 4287: break;
! 4288: case 2437:
! 4289: expected_val = 0x00080984; /* ch 6 */
! 4290: break;
! 4291: case 2442:
! 4292: expected_val = 0x00100988; /* ch 7 */
! 4293: break;
! 4294: case 2447:
! 4295: expected_val = 0x0018098c; /* ch 8 */
! 4296: break;
! 4297: case 2452:
! 4298: expected_val = 0x00000994; /* ch 9 */
! 4299: break;
! 4300: case 2457:
! 4301: expected_val = 0x00080998; /* ch 10 */
! 4302: break;
! 4303: case 2462:
! 4304: expected_val = 0x0010099c; /* ch 11 */
! 4305: break;
! 4306: case 2467:
! 4307: expected_val = 0x001809a0; /* ch 12 */
! 4308: break;
! 4309: case 2472:
! 4310: expected_val = 0x000009a8; /* ch 13 */
! 4311: break;
! 4312: case 2484:
! 4313: expected_val = 0x000009b4; /* ch 14 */
! 4314: break;
! 4315: }
! 4316: KASSERT(val == expected_val);
! 4317: }
! 4318:
! 4319: /* freq is in MHz */
! 4320: int
! 4321: rtw_sa2400_tune(struct rtw_softc *sc, u_int freq)
! 4322: {
! 4323: int rc;
! 4324: u_int32_t syna, synb, sync;
! 4325:
! 4326: /* XO = 44MHz, R = 11, hence N is in units of XO / R = 4MHz.
! 4327: *
! 4328: * The channel spacing (5MHz) is not divisible by 4MHz, so
! 4329: * we set the fractional part of N to compensate.
! 4330: */
! 4331: int n = freq / 4, nf = (freq % 4) * 2;
! 4332:
! 4333: syna = LSHIFT(nf, SA2400_SYNA_NF_MASK) | LSHIFT(n, SA2400_SYNA_N_MASK);
! 4334: rtw_verify_syna(freq, syna);
! 4335:
! 4336: /* Divide the 44MHz crystal down to 4MHz. Set the fractional
! 4337: * compensation charge pump value to agree with the fractional
! 4338: * modulus.
! 4339: */
! 4340: synb = LSHIFT(11, SA2400_SYNB_R_MASK) | SA2400_SYNB_L_NORMAL |
! 4341: SA2400_SYNB_ON | SA2400_SYNB_ONE |
! 4342: LSHIFT(80, SA2400_SYNB_FC_MASK); /* agrees w/ SA2400_SYNA_FM = 0 */
! 4343:
! 4344: sync = SA2400_SYNC_CP_NORMAL;
! 4345:
! 4346: if ((rc = rtw_rf_macwrite(sc, SA2400_SYNA, syna)) != 0)
! 4347: return rc;
! 4348: if ((rc = rtw_rf_macwrite(sc, SA2400_SYNB, synb)) != 0)
! 4349: return rc;
! 4350: if ((rc = rtw_rf_macwrite(sc, SA2400_SYNC, sync)) != 0)
! 4351: return rc;
! 4352: return rtw_rf_macwrite(sc, SA2400_SYND, 0x0);
! 4353: }
! 4354:
! 4355: int
! 4356: rtw_sa2400_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power)
! 4357: {
! 4358: u_int32_t opmode;
! 4359: opmode = SA2400_OPMODE_DEFAULTS;
! 4360: switch (power) {
! 4361: case RTW_ON:
! 4362: opmode |= SA2400_OPMODE_MODE_TXRX;
! 4363: break;
! 4364: case RTW_SLEEP:
! 4365: opmode |= SA2400_OPMODE_MODE_WAIT;
! 4366: break;
! 4367: case RTW_OFF:
! 4368: opmode |= SA2400_OPMODE_MODE_SLEEP;
! 4369: break;
! 4370: }
! 4371:
! 4372: if (sc->sc_flags & RTW_F_DIGPHY)
! 4373: opmode |= SA2400_OPMODE_DIGIN;
! 4374:
! 4375: return rtw_rf_macwrite(sc, SA2400_OPMODE, opmode);
! 4376: }
! 4377:
! 4378: int
! 4379: rtw_sa2400_vcocal_start(struct rtw_softc *sc, int start)
! 4380: {
! 4381: u_int32_t opmode;
! 4382:
! 4383: opmode = SA2400_OPMODE_DEFAULTS;
! 4384: if (start)
! 4385: opmode |= SA2400_OPMODE_MODE_VCOCALIB;
! 4386: else
! 4387: opmode |= SA2400_OPMODE_MODE_SLEEP;
! 4388:
! 4389: if (sc->sc_flags & RTW_F_DIGPHY)
! 4390: opmode |= SA2400_OPMODE_DIGIN;
! 4391:
! 4392: return rtw_rf_macwrite(sc, SA2400_OPMODE, opmode);
! 4393: }
! 4394:
! 4395: int
! 4396: rtw_sa2400_vco_calibration(struct rtw_softc *sc)
! 4397: {
! 4398: int rc;
! 4399: /* calibrate VCO */
! 4400: if ((rc = rtw_sa2400_vcocal_start(sc, 1)) != 0)
! 4401: return rc;
! 4402: DELAY(2200); /* 2.2 milliseconds */
! 4403: /* XXX superfluous: SA2400 automatically entered SLEEP mode. */
! 4404: return rtw_sa2400_vcocal_start(sc, 0);
! 4405: }
! 4406:
! 4407: int
! 4408: rtw_sa2400_filter_calibration(struct rtw_softc *sc)
! 4409: {
! 4410: u_int32_t opmode;
! 4411:
! 4412: opmode = SA2400_OPMODE_DEFAULTS | SA2400_OPMODE_MODE_FCALIB;
! 4413: if (sc->sc_flags & RTW_F_DIGPHY)
! 4414: opmode |= SA2400_OPMODE_DIGIN;
! 4415:
! 4416: return rtw_rf_macwrite(sc, SA2400_OPMODE, opmode);
! 4417: }
! 4418:
! 4419: int
! 4420: rtw_sa2400_dc_calibration(struct rtw_softc *sc)
! 4421: {
! 4422: int rc;
! 4423: u_int32_t dccal;
! 4424:
! 4425: rtw_continuous_tx_enable(sc, 1);
! 4426:
! 4427: dccal = SA2400_OPMODE_DEFAULTS | SA2400_OPMODE_MODE_TXRX;
! 4428:
! 4429: rc = rtw_rf_macwrite(sc, SA2400_OPMODE, dccal);
! 4430:
! 4431: if (rc != 0)
! 4432: return rc;
! 4433:
! 4434: DELAY(5); /* DCALIB after being in Tx mode for 5
! 4435: * microseconds
! 4436: */
! 4437:
! 4438: dccal &= ~SA2400_OPMODE_MODE_MASK;
! 4439: dccal |= SA2400_OPMODE_MODE_DCALIB;
! 4440:
! 4441: rc = rtw_rf_macwrite(sc, SA2400_OPMODE, dccal);
! 4442: if (rc != 0)
! 4443: return rc;
! 4444:
! 4445: DELAY(20); /* calibration takes at most 20 microseconds */
! 4446:
! 4447: rtw_continuous_tx_enable(sc, 0);
! 4448:
! 4449: return 0;
! 4450: }
! 4451:
! 4452: int
! 4453: rtw_sa2400_calibrate(struct rtw_softc *sc, u_int freq)
! 4454: {
! 4455: int i, rc;
! 4456:
! 4457: /* XXX reference driver calibrates VCO twice. Is it a bug? */
! 4458: for (i = 0; i < 2; i++) {
! 4459: if ((rc = rtw_sa2400_vco_calibration(sc)) != 0)
! 4460: return rc;
! 4461: }
! 4462: /* VCO calibration erases synthesizer registers, so re-tune */
! 4463: if ((rc = rtw_sa2400_tune(sc, freq)) != 0)
! 4464: return rc;
! 4465: if ((rc = rtw_sa2400_filter_calibration(sc)) != 0)
! 4466: return rc;
! 4467: /* analog PHY needs DC calibration */
! 4468: if (!(sc->sc_flags & RTW_F_DIGPHY))
! 4469: return rtw_sa2400_dc_calibration(sc);
! 4470: return 0;
! 4471: }
! 4472:
! 4473: int
! 4474: rtw_sa2400_init(struct rtw_softc *sc, u_int freq, u_int8_t opaque_txpower,
! 4475: enum rtw_pwrstate power)
! 4476: {
! 4477: int rc;
! 4478: u_int32_t agc, manrx;
! 4479:
! 4480: if ((rc = rtw_sa2400_txpower(sc, opaque_txpower)) != 0)
! 4481: return rc;
! 4482:
! 4483: /* skip configuration if it's time to sleep or to power-down. */
! 4484: if (power == RTW_SLEEP || power == RTW_OFF)
! 4485: return rtw_sa2400_pwrstate(sc, power);
! 4486:
! 4487: /* go to sleep for configuration */
! 4488: if ((rc = rtw_sa2400_pwrstate(sc, RTW_SLEEP)) != 0)
! 4489: return rc;
! 4490:
! 4491: if ((rc = rtw_sa2400_tune(sc, freq)) != 0)
! 4492: return rc;
! 4493:
! 4494: agc = LSHIFT(25, SA2400_AGC_MAXGAIN_MASK);
! 4495: agc |= LSHIFT(7, SA2400_AGC_BBPDELAY_MASK);
! 4496: agc |= LSHIFT(15, SA2400_AGC_LNADELAY_MASK);
! 4497: agc |= LSHIFT(27, SA2400_AGC_RXONDELAY_MASK);
! 4498:
! 4499: if ((rc = rtw_rf_macwrite(sc, SA2400_AGC, agc)) != 0)
! 4500: return rc;
! 4501:
! 4502: /* XXX we are not supposed to be in RXMGC mode when we do this? */
! 4503: manrx = SA2400_MANRX_AHSN;
! 4504: manrx |= SA2400_MANRX_TEN;
! 4505: manrx |= LSHIFT(1023, SA2400_MANRX_RXGAIN_MASK);
! 4506:
! 4507: if ((rc = rtw_rf_macwrite(sc, SA2400_MANRX, manrx)) != 0)
! 4508: return rc;
! 4509:
! 4510: if ((rc = rtw_sa2400_calibrate(sc, freq)) != 0)
! 4511: return rc;
! 4512:
! 4513: /* enter Tx/Rx mode */
! 4514: return rtw_sa2400_pwrstate(sc, power);
! 4515: }
! 4516:
! 4517: /* freq is in MHz */
! 4518: int
! 4519: rtw_max2820_tune(struct rtw_softc *sc, u_int freq)
! 4520: {
! 4521: if (freq < 2400 || freq > 2499)
! 4522: return -1;
! 4523:
! 4524: return rtw_rf_hostwrite(sc, MAX2820_CHANNEL,
! 4525: LSHIFT(freq - 2400, MAX2820_CHANNEL_CF_MASK));
! 4526: }
! 4527:
! 4528: int
! 4529: rtw_max2820_init(struct rtw_softc *sc, u_int freq, u_int8_t opaque_txpower,
! 4530: enum rtw_pwrstate power)
! 4531: {
! 4532: int rc;
! 4533:
! 4534: if ((rc = rtw_rf_hostwrite(sc, MAX2820_TEST,
! 4535: MAX2820_TEST_DEFAULT)) != 0)
! 4536: return rc;
! 4537:
! 4538: if ((rc = rtw_rf_hostwrite(sc, MAX2820_ENABLE,
! 4539: MAX2820_ENABLE_DEFAULT)) != 0)
! 4540: return rc;
! 4541:
! 4542: /* skip configuration if it's time to sleep or to power-down. */
! 4543: if ((rc = rtw_max2820_pwrstate(sc, power)) != 0)
! 4544: return rc;
! 4545: else if (power == RTW_OFF || power == RTW_SLEEP)
! 4546: return 0;
! 4547:
! 4548: if ((rc = rtw_rf_hostwrite(sc, MAX2820_SYNTH,
! 4549: MAX2820_SYNTH_R_44MHZ)) != 0)
! 4550: return rc;
! 4551:
! 4552: if ((rc = rtw_max2820_tune(sc, freq)) != 0)
! 4553: return rc;
! 4554:
! 4555: /* XXX The MAX2820 datasheet indicates that 1C and 2C should not
! 4556: * be changed from 7, however, the reference driver sets them
! 4557: * to 4 and 1, respectively.
! 4558: */
! 4559: if ((rc = rtw_rf_hostwrite(sc, MAX2820_RECEIVE,
! 4560: MAX2820_RECEIVE_DL_DEFAULT |
! 4561: LSHIFT(4, MAX2820A_RECEIVE_1C_MASK) |
! 4562: LSHIFT(1, MAX2820A_RECEIVE_2C_MASK))) != 0)
! 4563: return rc;
! 4564:
! 4565: return rtw_rf_hostwrite(sc, MAX2820_TRANSMIT,
! 4566: MAX2820_TRANSMIT_PA_DEFAULT);
! 4567: }
! 4568:
! 4569: int
! 4570: rtw_max2820_txpower(struct rtw_softc *sc, u_int8_t opaque_txpower)
! 4571: {
! 4572: /* TBD */
! 4573: return 0;
! 4574: }
! 4575:
! 4576: int
! 4577: rtw_max2820_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power)
! 4578: {
! 4579: uint32_t enable;
! 4580:
! 4581: switch (power) {
! 4582: case RTW_OFF:
! 4583: case RTW_SLEEP:
! 4584: default:
! 4585: enable = 0x0;
! 4586: break;
! 4587: case RTW_ON:
! 4588: enable = MAX2820_ENABLE_DEFAULT;
! 4589: break;
! 4590: }
! 4591: return rtw_rf_hostwrite(sc, MAX2820_ENABLE, enable);
! 4592: }
! 4593:
! 4594: int
! 4595: rtw_grf5101_init(struct rtw_softc *sc, u_int freq, u_int8_t opaque_txpower,
! 4596: enum rtw_pwrstate power)
! 4597: {
! 4598: int rc;
! 4599:
! 4600: /*
! 4601: * These values have been derived from the rtl8180-sa2400 Linux driver.
! 4602: * It is unknown what they all do, GCT refuse to release any documentation
! 4603: * so these are more than likely sub optimal settings
! 4604: */
! 4605:
! 4606: rtw_rf_macwrite(sc, 0x01, 0x1a23);
! 4607: rtw_rf_macwrite(sc, 0x02, 0x4971);
! 4608: rtw_rf_macwrite(sc, 0x03, 0x41de);
! 4609: rtw_rf_macwrite(sc, 0x04, 0x2d80);
! 4610:
! 4611: rtw_rf_macwrite(sc, 0x05, 0x61ff);
! 4612:
! 4613: rtw_rf_macwrite(sc, 0x06, 0x0);
! 4614:
! 4615: rtw_rf_macwrite(sc, 0x08, 0x7533);
! 4616: rtw_rf_macwrite(sc, 0x09, 0xc401);
! 4617: rtw_rf_macwrite(sc, 0x0a, 0x0);
! 4618: rtw_rf_macwrite(sc, 0x0c, 0x1c7);
! 4619: rtw_rf_macwrite(sc, 0x0d, 0x29d3);
! 4620: rtw_rf_macwrite(sc, 0x0e, 0x2e8);
! 4621: rtw_rf_macwrite(sc, 0x10, 0x192);
! 4622: rtw_rf_macwrite(sc, 0x11, 0x248);
! 4623: rtw_rf_macwrite(sc, 0x12, 0x0);
! 4624: rtw_rf_macwrite(sc, 0x13, 0x20c4);
! 4625: rtw_rf_macwrite(sc, 0x14, 0xf4fc);
! 4626: rtw_rf_macwrite(sc, 0x15, 0x0);
! 4627: rtw_rf_macwrite(sc, 0x16, 0x1500);
! 4628:
! 4629: if ((rc = rtw_grf5101_txpower(sc, opaque_txpower)) != 0)
! 4630: return rc;
! 4631:
! 4632: if ((rc = rtw_grf5101_tune(sc, freq)) != 0)
! 4633: return rc;
! 4634:
! 4635: return (0);
! 4636: }
! 4637:
! 4638: int
! 4639: rtw_grf5101_tune(struct rtw_softc *sc, u_int freq)
! 4640: {
! 4641: struct ieee80211com *ic = &sc->sc_ic;
! 4642: u_int channel = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
! 4643:
! 4644: /* set channel */
! 4645: rtw_rf_macwrite(sc, 0x07, 0);
! 4646: rtw_rf_macwrite(sc, 0x0b, channel - 1);
! 4647: rtw_rf_macwrite(sc, 0x07, 0x1000);
! 4648:
! 4649: return (0);
! 4650: }
! 4651:
! 4652: int
! 4653: rtw_grf5101_txpower(struct rtw_softc *sc, u_int8_t opaque_txpower)
! 4654: {
! 4655: rtw_rf_macwrite(sc, 0x15, 0);
! 4656: rtw_rf_macwrite(sc, 0x06, opaque_txpower);
! 4657: rtw_rf_macwrite(sc, 0x15, 0x10);
! 4658: rtw_rf_macwrite(sc, 0x15, 0x00);
! 4659:
! 4660: return (0);
! 4661: }
! 4662:
! 4663: int
! 4664: rtw_grf5101_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power)
! 4665: {
! 4666: switch (power) {
! 4667: case RTW_OFF:
! 4668: case RTW_SLEEP:
! 4669: rtw_rf_macwrite(sc, 0x07, 0x0000);
! 4670: rtw_rf_macwrite(sc, 0x1f, 0x0045);
! 4671: rtw_rf_macwrite(sc, 0x1f, 0x0005);
! 4672: rtw_rf_macwrite(sc, 0x00, 0x08e4);
! 4673: default:
! 4674: break;
! 4675: case RTW_ON:
! 4676: rtw_rf_macwrite(sc, 0x1f, 0x0001);
! 4677: DELAY(10);
! 4678: rtw_rf_macwrite(sc, 0x1f, 0x0001);
! 4679: DELAY(10);
! 4680: rtw_rf_macwrite(sc, 0x1f, 0x0041);
! 4681: DELAY(10);
! 4682: rtw_rf_macwrite(sc, 0x1f, 0x0061);
! 4683: DELAY(10);
! 4684: rtw_rf_macwrite(sc, 0x00, 0x0ae4);
! 4685: DELAY(10);
! 4686: rtw_rf_macwrite(sc, 0x07, 0x1000);
! 4687: DELAY(100);
! 4688: break;
! 4689: }
! 4690:
! 4691: return 0;
! 4692: }
! 4693:
! 4694: int
! 4695: rtw_rtl8225_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power)
! 4696: {
! 4697: return (0);
! 4698: }
! 4699:
! 4700: int
! 4701: rtw_rtl8225_init(struct rtw_softc *sc, u_int freq, u_int8_t opaque_txpower,
! 4702: enum rtw_pwrstate power)
! 4703: {
! 4704: return (0);
! 4705: }
! 4706:
! 4707: int
! 4708: rtw_rtl8225_txpower(struct rtw_softc *sc, u_int8_t opaque_txpower)
! 4709: {
! 4710: return (0);
! 4711: }
! 4712:
! 4713: int
! 4714: rtw_rtl8225_tune(struct rtw_softc *sc, u_int freq)
! 4715: {
! 4716: return (0);
! 4717: }
! 4718:
! 4719: int
! 4720: rtw_rtl8255_pwrstate(struct rtw_softc *sc, enum rtw_pwrstate power)
! 4721: {
! 4722: return (0);
! 4723: }
! 4724:
! 4725: int
! 4726: rtw_rtl8255_init(struct rtw_softc *sc, u_int freq, u_int8_t opaque_txpower,
! 4727: enum rtw_pwrstate power)
! 4728: {
! 4729: return (0);
! 4730: }
! 4731:
! 4732: int
! 4733: rtw_rtl8255_txpower(struct rtw_softc *sc, u_int8_t opaque_txpower)
! 4734: {
! 4735: return (0);
! 4736: }
! 4737:
! 4738: int
! 4739: rtw_rtl8255_tune(struct rtw_softc *sc, u_int freq)
! 4740: {
! 4741: return (0);
! 4742: }
! 4743:
! 4744: int
! 4745: rtw_phy_init(struct rtw_softc *sc)
! 4746: {
! 4747: int rc;
! 4748: struct ieee80211com *ic = &sc->sc_ic;
! 4749: struct rtw_regs *regs = &sc->sc_regs;
! 4750: int antdiv = sc->sc_flags & RTW_F_ANTDIV;
! 4751: int dflantb = sc->sc_flags & RTW_F_DFLANTB;
! 4752: u_int freq = ic->ic_bss->ni_chan->ic_freq; /* freq is in MHz */
! 4753: u_int8_t opaque_txpower = rtw_chan2txpower(&sc->sc_srom, ic,
! 4754: ic->ic_bss->ni_chan);
! 4755: u_int8_t cs_threshold = sc->sc_csthr;
! 4756: enum rtw_pwrstate power = RTW_ON;
! 4757:
! 4758: RTW_DPRINTF(RTW_DEBUG_PHY,
! 4759: ("%s: txpower %u csthresh %u freq %u antdiv %u dflantb %u "
! 4760: "pwrstate %s\n", __func__, opaque_txpower, cs_threshold, freq,
! 4761: antdiv, dflantb, rtw_pwrstate_string(power)));
! 4762:
! 4763: /* XXX is this really necessary? */
! 4764: if ((rc = (*sc->sc_rf_txpower)(sc, opaque_txpower)) != 0)
! 4765: return rc;
! 4766: if ((rc = rtw_bbp_preinit(regs, sc->sc_bbpset.bb_antatten, dflantb,
! 4767: freq)) != 0)
! 4768: return rc;
! 4769: if ((rc = (*sc->sc_rf_tune)(sc, freq)) != 0)
! 4770: return rc;
! 4771: /* initialize RF */
! 4772: if ((rc = (*sc->sc_rf_init)(sc, freq, opaque_txpower, power)) != 0)
! 4773: return rc;
! 4774: #if 0 /* what is this redundant tx power setting here for? */
! 4775: if ((rc = (*sc->sc_rf_txpower)(sc, opaque_txpower)) != 0)
! 4776: return rc;
! 4777: #endif
! 4778: return rtw_bbp_init(regs, &sc->sc_bbpset, antdiv, dflantb,
! 4779: cs_threshold, freq);
! 4780: }
! 4781:
! 4782: /*
! 4783: * Generic PHY I/O functions
! 4784: */
! 4785:
! 4786: int
! 4787: rtw_bbp_write(struct rtw_regs *regs, u_int addr, u_int val)
! 4788: {
! 4789: #define BBP_WRITE_ITERS 50
! 4790: #define BBP_WRITE_DELAY 1
! 4791: int i;
! 4792: u_int32_t wrbbp, rdbbp;
! 4793:
! 4794: RTW_DPRINTF(RTW_DEBUG_PHYIO,
! 4795: ("%s: bbp[%u] <- %u\n", __func__, addr, val));
! 4796:
! 4797: KASSERT((addr & ~PRESHIFT(RTW_BB_ADDR_MASK)) == 0);
! 4798: KASSERT((val & ~PRESHIFT(RTW_BB_WR_MASK)) == 0);
! 4799:
! 4800: wrbbp = LSHIFT(addr, RTW_BB_ADDR_MASK) | RTW_BB_WREN |
! 4801: LSHIFT(val, RTW_BB_WR_MASK) | RTW_BB_RD_MASK,
! 4802:
! 4803: rdbbp = LSHIFT(addr, RTW_BB_ADDR_MASK) |
! 4804: RTW_BB_WR_MASK | RTW_BB_RD_MASK;
! 4805:
! 4806: RTW_DPRINTF(RTW_DEBUG_PHYIO,
! 4807: ("%s: rdbbp = %#08x, wrbbp = %#08x\n", __func__, rdbbp, wrbbp));
! 4808:
! 4809: for (i = BBP_WRITE_ITERS; --i >= 0; ) {
! 4810: RTW_RBW(regs, RTW_BB, RTW_BB);
! 4811: RTW_WRITE(regs, RTW_BB, wrbbp);
! 4812: RTW_SYNC(regs, RTW_BB, RTW_BB);
! 4813: RTW_WRITE(regs, RTW_BB, rdbbp);
! 4814: RTW_SYNC(regs, RTW_BB, RTW_BB);
! 4815: delay(BBP_WRITE_DELAY); /* 1 microsecond */
! 4816: if (MASK_AND_RSHIFT(RTW_READ(regs, RTW_BB),
! 4817: RTW_BB_RD_MASK) == val) {
! 4818: RTW_DPRINTF(RTW_DEBUG_PHYIO,
! 4819: ("%s: finished in %dus\n", __func__,
! 4820: BBP_WRITE_DELAY * (BBP_WRITE_ITERS - i)));
! 4821: return 0;
! 4822: }
! 4823: delay(BBP_WRITE_DELAY); /* again */
! 4824: }
! 4825: printf("%s: timeout\n", __func__);
! 4826: return -1;
! 4827: }
! 4828:
! 4829: /* Help rtw_rf_hostwrite bang bits to RF over 3-wire interface. */
! 4830: void
! 4831: rtw_rf_hostbangbits(struct rtw_regs *regs, u_int32_t bits, int lo_to_hi,
! 4832: u_int nbits)
! 4833: {
! 4834: int i;
! 4835: u_int32_t mask, reg;
! 4836:
! 4837: KASSERT(nbits <= 32);
! 4838:
! 4839: RTW_DPRINTF(RTW_DEBUG_PHYIO,
! 4840: ("%s: %u bits, %#08x, %s\n", __func__, nbits, bits,
! 4841: (lo_to_hi) ? "lo to hi" : "hi to lo"));
! 4842:
! 4843: reg = RTW8180_PHYCFG_HST;
! 4844: RTW_WRITE(regs, RTW8180_PHYCFG, reg);
! 4845: RTW_SYNC(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4846:
! 4847: if (lo_to_hi)
! 4848: mask = 0x1;
! 4849: else
! 4850: mask = 1 << (nbits - 1);
! 4851:
! 4852: for (i = 0; i < nbits; i++) {
! 4853: RTW_DPRINTF(RTW_DEBUG_PHYBITIO,
! 4854: ("%s: bits %#08x mask %#08x -> bit %#08x\n",
! 4855: __func__, bits, mask, bits & mask));
! 4856:
! 4857: if ((bits & mask) != 0)
! 4858: reg |= RTW8180_PHYCFG_HST_DATA;
! 4859: else
! 4860: reg &= ~RTW8180_PHYCFG_HST_DATA;
! 4861:
! 4862: reg |= RTW8180_PHYCFG_HST_CLK;
! 4863: RTW_WRITE(regs, RTW8180_PHYCFG, reg);
! 4864: RTW_SYNC(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4865:
! 4866: DELAY(2); /* arbitrary delay */
! 4867:
! 4868: reg &= ~RTW8180_PHYCFG_HST_CLK;
! 4869: RTW_WRITE(regs, RTW8180_PHYCFG, reg);
! 4870: RTW_SYNC(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4871:
! 4872: if (lo_to_hi)
! 4873: mask <<= 1;
! 4874: else
! 4875: mask >>= 1;
! 4876: }
! 4877:
! 4878: reg |= RTW8180_PHYCFG_HST_EN;
! 4879: KASSERT((reg & RTW8180_PHYCFG_HST_CLK) == 0);
! 4880: RTW_WRITE(regs, RTW8180_PHYCFG, reg);
! 4881: RTW_SYNC(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4882: }
! 4883:
! 4884: #if 0
! 4885: void
! 4886: rtw_rf_rtl8225_hostbangbits(struct rtw_regs *regs, u_int32_t bits, int lo_to_hi,
! 4887: u_int nbits)
! 4888: {
! 4889: int i;
! 4890: u_int8_t page;
! 4891: u_int16_t reg0, reg1, reg2;
! 4892: u_int32_t mask;
! 4893:
! 4894: /* enable page 0 */
! 4895: page = RTW_READ8(regs, RTW_PSR);
! 4896: RTW_WRITE8(regs, RTW_PSR, page & ~RTW_PSR_PSEN);
! 4897:
! 4898: /* enable RF access */
! 4899: reg0 = RTW_READ16(regs, RTW8185_RFPINSOUTPUT) &
! 4900: RTW8185_RFPINSOUTPUT_MASK;
! 4901: reg1 = RTW_READ16(regs, RTW8185_RFPINSENABLE);
! 4902: RTW_WRITE16(regs, RTW8185_RFPINSENABLE,
! 4903: RTW8185_RFPINSENABLE_ENABLE | reg0);
! 4904: reg2 = RTW_READ16(regs, RTW8185_RFPINSSELECT);
! 4905: RTW_WRITE16(regs, RTW8185_RFPINSSELECT,
! 4906: RTW8185_RFPINSSELECT_ENABLE | reg1 /* XXX | SW_GPIO_CTL */);
! 4907: DELAY(10);
! 4908:
! 4909: RTW_WRITE16(regs, RTW8185_RFPINSOUTPUT, reg0);
! 4910: DELAY(10);
! 4911:
! 4912: if (lo_to_hi)
! 4913: mask = 0x1;
! 4914: else
! 4915: mask = 1 << (nbits - 1);
! 4916:
! 4917: for (i = 0; i < nbits; i++) {
! 4918: RTW_DPRINTF(RTW_DEBUG_PHYBITIO,
! 4919: ("%s: bits %#08x mask %#08x -> bit %#08x\n",
! 4920: __func__, bits, mask, bits & mask));
! 4921:
! 4922: if ((bits & mask) != 0)
! 4923: reg |= RTW8180_PHYCFG_HST_DATA;
! 4924: else
! 4925: reg &= ~RTW8180_PHYCFG_HST_DATA;
! 4926:
! 4927: reg |= RTW8180_PHYCFG_HST_CLK;
! 4928: RTW_WRITE(regs, RTW8180_PHYCFG, reg);
! 4929: RTW_SYNC(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4930:
! 4931: DELAY(2); /* arbitrary delay */
! 4932:
! 4933: reg &= ~RTW8180_PHYCFG_HST_CLK;
! 4934: RTW_WRITE(regs, RTW8180_PHYCFG, reg);
! 4935: RTW_SYNC(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4936:
! 4937: if (lo_to_hi)
! 4938: mask <<= 1;
! 4939: else
! 4940: mask >>= 1;
! 4941: }
! 4942:
! 4943: /* reset the page */
! 4944: RTW_WRITE8(regs, RTW_PSR, page);
! 4945: }
! 4946: #endif
! 4947:
! 4948: /* Help rtw_rf_macwrite: tell MAC to bang bits to RF over the 3-wire
! 4949: * interface.
! 4950: */
! 4951: int
! 4952: rtw_rf_macbangbits(struct rtw_regs *regs, u_int32_t reg)
! 4953: {
! 4954: int i;
! 4955:
! 4956: RTW_DPRINTF(RTW_DEBUG_PHY, ("%s: %#08x\n", __func__, reg));
! 4957:
! 4958: RTW_WRITE(regs, RTW8180_PHYCFG, RTW8180_PHYCFG_MAC_POLL | reg);
! 4959:
! 4960: RTW_WBR(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4961:
! 4962: for (i = rtw_macbangbits_timeout; --i >= 0; delay(1)) {
! 4963: if ((RTW_READ(regs, RTW8180_PHYCFG) &
! 4964: RTW8180_PHYCFG_MAC_POLL) == 0) {
! 4965: RTW_DPRINTF(RTW_DEBUG_PHY,
! 4966: ("%s: finished in %dus\n", __func__,
! 4967: rtw_macbangbits_timeout - i));
! 4968: return 0;
! 4969: }
! 4970: RTW_RBR(regs, RTW8180_PHYCFG, RTW8180_PHYCFG);
! 4971: }
! 4972:
! 4973: printf("%s: RTW8180_PHYCFG_MAC_POLL still set.\n", __func__);
! 4974: return -1;
! 4975: }
! 4976:
! 4977: u_int32_t
! 4978: rtw_grf5101_host_crypt(u_int addr, u_int32_t val)
! 4979: {
! 4980: /* TBD */
! 4981: return 0;
! 4982: }
! 4983:
! 4984: u_int32_t
! 4985: rtw_grf5101_mac_crypt(u_int addr, u_int32_t val)
! 4986: {
! 4987: u_int32_t data_and_addr;
! 4988: #define EXTRACT_NIBBLE(d, which) (((d) >> (4 * (which))) & 0xf)
! 4989: static u_int8_t caesar[16] = {
! 4990: 0x0, 0x8, 0x4, 0xc,
! 4991: 0x2, 0xa, 0x6, 0xe,
! 4992: 0x1, 0x9, 0x5, 0xd,
! 4993: 0x3, 0xb, 0x7, 0xf
! 4994: };
! 4995: data_and_addr =
! 4996: caesar[EXTRACT_NIBBLE(val, 2)] |
! 4997: (caesar[EXTRACT_NIBBLE(val, 1)] << 4) |
! 4998: (caesar[EXTRACT_NIBBLE(val, 0)] << 8) |
! 4999: (caesar[(addr >> 1) & 0xf] << 12) |
! 5000: ((addr & 0x1) << 16) |
! 5001: (caesar[EXTRACT_NIBBLE(val, 3)] << 24);
! 5002: return LSHIFT(data_and_addr, RTW8180_PHYCFG_MAC_PHILIPS_ADDR_MASK |
! 5003: RTW8180_PHYCFG_MAC_PHILIPS_DATA_MASK);
! 5004: #undef EXTRACT_NIBBLE
! 5005: }
! 5006:
! 5007: /* Bang bits over the 3-wire interface. */
! 5008: int
! 5009: rtw_rf_hostwrite(struct rtw_softc *sc, u_int addr, u_int32_t val)
! 5010: {
! 5011: u_int nbits;
! 5012: int lo_to_hi;
! 5013: u_int32_t bits;
! 5014: void(*rf_bangbits)(struct rtw_regs *, u_int32_t, int, u_int) =
! 5015: rtw_rf_hostbangbits;
! 5016:
! 5017: RTW_DPRINTF(RTW_DEBUG_PHYIO, ("%s: [%u] <- %#08x\n", __func__,
! 5018: addr, val));
! 5019:
! 5020: switch (sc->sc_rfchipid) {
! 5021: case RTW_RFCHIPID_MAXIM2820:
! 5022: nbits = 16;
! 5023: lo_to_hi = 0;
! 5024: bits = LSHIFT(val, MAX2820_TWI_DATA_MASK) |
! 5025: LSHIFT(addr, MAX2820_TWI_ADDR_MASK);
! 5026: break;
! 5027: case RTW_RFCHIPID_PHILIPS:
! 5028: KASSERT((addr & ~PRESHIFT(SA2400_TWI_ADDR_MASK)) == 0);
! 5029: KASSERT((val & ~PRESHIFT(SA2400_TWI_DATA_MASK)) == 0);
! 5030: bits = LSHIFT(val, SA2400_TWI_DATA_MASK) |
! 5031: LSHIFT(addr, SA2400_TWI_ADDR_MASK) | SA2400_TWI_WREN;
! 5032: nbits = 32;
! 5033: lo_to_hi = 1;
! 5034: break;
! 5035: case RTW_RFCHIPID_GCT:
! 5036: KASSERT((addr & ~PRESHIFT(SI4126_TWI_ADDR_MASK)) == 0);
! 5037: KASSERT((val & ~PRESHIFT(SI4126_TWI_DATA_MASK)) == 0);
! 5038: bits = rtw_grf5101_host_crypt(addr, val);
! 5039: nbits = 21;
! 5040: lo_to_hi = 1;
! 5041: break;
! 5042: case RTW_RFCHIPID_RFMD2948:
! 5043: KASSERT((addr & ~PRESHIFT(SI4126_TWI_ADDR_MASK)) == 0);
! 5044: KASSERT((val & ~PRESHIFT(SI4126_TWI_DATA_MASK)) == 0);
! 5045: bits = LSHIFT(val, SI4126_TWI_DATA_MASK) |
! 5046: LSHIFT(addr, SI4126_TWI_ADDR_MASK);
! 5047: nbits = 22;
! 5048: lo_to_hi = 0;
! 5049: break;
! 5050: case RTW_RFCHIPID_RTL8225:
! 5051: case RTW_RFCHIPID_RTL8255:
! 5052: nbits = 16;
! 5053: lo_to_hi = 0;
! 5054: bits = LSHIFT(val, RTL8225_TWI_DATA_MASK) |
! 5055: LSHIFT(addr, RTL8225_TWI_ADDR_MASK);
! 5056:
! 5057: /* the RTL8225 uses a slightly modified RF interface */
! 5058: rf_bangbits = rtw_rf_hostbangbits;
! 5059: break;
! 5060: case RTW_RFCHIPID_INTERSIL:
! 5061: default:
! 5062: printf("%s: unknown rfchipid %d\n", __func__, sc->sc_rfchipid);
! 5063: return -1;
! 5064: }
! 5065:
! 5066: (*rf_bangbits)(&sc->sc_regs, bits, lo_to_hi, nbits);
! 5067:
! 5068: return 0;
! 5069: }
! 5070:
! 5071: u_int32_t
! 5072: rtw_maxim_swizzle(u_int addr, u_int32_t val)
! 5073: {
! 5074: u_int32_t hidata, lodata;
! 5075:
! 5076: KASSERT((val & ~(RTW_MAXIM_LODATA_MASK|RTW_MAXIM_HIDATA_MASK)) == 0);
! 5077: lodata = MASK_AND_RSHIFT(val, RTW_MAXIM_LODATA_MASK);
! 5078: hidata = MASK_AND_RSHIFT(val, RTW_MAXIM_HIDATA_MASK);
! 5079: return LSHIFT(lodata, RTW8180_PHYCFG_MAC_MAXIM_LODATA_MASK) |
! 5080: LSHIFT(hidata, RTW8180_PHYCFG_MAC_MAXIM_HIDATA_MASK) |
! 5081: LSHIFT(addr, RTW8180_PHYCFG_MAC_MAXIM_ADDR_MASK);
! 5082: }
! 5083:
! 5084: /* Tell the MAC what to bang over the 3-wire interface. */
! 5085: int
! 5086: rtw_rf_macwrite(struct rtw_softc *sc, u_int addr, u_int32_t val)
! 5087: {
! 5088: u_int32_t reg;
! 5089:
! 5090: RTW_DPRINTF(RTW_DEBUG_PHYIO, ("%s: %s[%u] <- %#08x\n", __func__,
! 5091: addr, val));
! 5092:
! 5093: switch (sc->sc_rfchipid) {
! 5094: case RTW_RFCHIPID_GCT:
! 5095: reg = rtw_grf5101_mac_crypt(addr, val);
! 5096: break;
! 5097: case RTW_RFCHIPID_MAXIM2820:
! 5098: reg = rtw_maxim_swizzle(addr, val);
! 5099: break;
! 5100: default: /* XXX */
! 5101: case RTW_RFCHIPID_PHILIPS:
! 5102: KASSERT((addr &
! 5103: ~PRESHIFT(RTW8180_PHYCFG_MAC_PHILIPS_ADDR_MASK)) == 0);
! 5104: KASSERT((val &
! 5105: ~PRESHIFT(RTW8180_PHYCFG_MAC_PHILIPS_DATA_MASK)) == 0);
! 5106:
! 5107: reg = LSHIFT(addr, RTW8180_PHYCFG_MAC_PHILIPS_ADDR_MASK) |
! 5108: LSHIFT(val, RTW8180_PHYCFG_MAC_PHILIPS_DATA_MASK);
! 5109: }
! 5110:
! 5111: switch (sc->sc_rfchipid) {
! 5112: case RTW_RFCHIPID_GCT:
! 5113: case RTW_RFCHIPID_MAXIM2820:
! 5114: case RTW_RFCHIPID_RFMD2948:
! 5115: reg |= RTW8180_PHYCFG_MAC_RFTYPE_RFMD;
! 5116: break;
! 5117: case RTW_RFCHIPID_INTERSIL:
! 5118: reg |= RTW8180_PHYCFG_MAC_RFTYPE_INTERSIL;
! 5119: break;
! 5120: case RTW_RFCHIPID_PHILIPS:
! 5121: reg |= RTW8180_PHYCFG_MAC_RFTYPE_PHILIPS;
! 5122: break;
! 5123: default:
! 5124: printf("%s: unknown rfchipid %d\n", __func__, sc->sc_rfchipid);
! 5125: return -1;
! 5126: }
! 5127:
! 5128: return rtw_rf_macbangbits(&sc->sc_regs, reg);
! 5129: }
! 5130:
! 5131:
! 5132: u_int8_t
! 5133: rtw_read8(void *arg, u_int32_t off)
! 5134: {
! 5135: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5136: return (bus_space_read_1(regs->r_bt, regs->r_bh, off));
! 5137: }
! 5138:
! 5139: u_int16_t
! 5140: rtw_read16(void *arg, u_int32_t off)
! 5141: {
! 5142: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5143: return (bus_space_read_2(regs->r_bt, regs->r_bh, off));
! 5144: }
! 5145:
! 5146: u_int32_t
! 5147: rtw_read32(void *arg, u_int32_t off)
! 5148: {
! 5149: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5150: return (bus_space_read_4(regs->r_bt, regs->r_bh, off));
! 5151: }
! 5152:
! 5153: void
! 5154: rtw_write8(void *arg, u_int32_t off, u_int8_t val)
! 5155: {
! 5156: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5157: bus_space_write_1(regs->r_bt, regs->r_bh, off, val);
! 5158: }
! 5159:
! 5160: void
! 5161: rtw_write16(void *arg, u_int32_t off, u_int16_t val)
! 5162: {
! 5163: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5164: bus_space_write_2(regs->r_bt, regs->r_bh, off, val);
! 5165: }
! 5166:
! 5167: void
! 5168: rtw_write32(void *arg, u_int32_t off, u_int32_t val)
! 5169: {
! 5170: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5171: bus_space_write_4(regs->r_bt, regs->r_bh, off, val);
! 5172: }
! 5173:
! 5174: void
! 5175: rtw_barrier(void *arg, u_int32_t reg0, u_int32_t reg1, int flags)
! 5176: {
! 5177: struct rtw_regs *regs = (struct rtw_regs *)arg;
! 5178: bus_space_barrier(regs->r_bt, regs->r_bh, MIN(reg0, reg1),
! 5179: MAX(reg0, reg1) - MIN(reg0, reg1) + 4, flags);
! 5180: }
CVSweb