1121991Sjhb/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2121991Sjhb 3121991Sjhb/*- 4121991Sjhb * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5121991Sjhb * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6121991Sjhb * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 7121991Sjhb * 8121991Sjhb * Permission to use, copy, modify, and distribute this software for any 9121991Sjhb * purpose with or without fee is hereby granted, provided that the above 10121991Sjhb * copyright notice and this permission notice appear in all copies. 11121991Sjhb * 12121991Sjhb * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13121991Sjhb * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14121991Sjhb * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15121991Sjhb * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16121991Sjhb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17121991Sjhb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18121991Sjhb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19121991Sjhb */ 20121991Sjhb 21121991Sjhb#include <sys/cdefs.h> 22121991Sjhb__FBSDID("$FreeBSD$"); 23121991Sjhb 24121991Sjhb#include "opt_wlan.h" 25121991Sjhb 26121991Sjhb#include <sys/param.h> 27121991Sjhb#include <sys/lock.h> 28121991Sjhb#include <sys/mutex.h> 29121991Sjhb#include <sys/mbuf.h> 30121991Sjhb#include <sys/kernel.h> 31121991Sjhb#include <sys/socket.h> 32121991Sjhb#include <sys/systm.h> 33121991Sjhb#include <sys/malloc.h> 34121991Sjhb#include <sys/queue.h> 35121991Sjhb#include <sys/taskqueue.h> 36121991Sjhb#include <sys/bus.h> 37121991Sjhb#include <sys/endian.h> 38121991Sjhb#include <sys/linker.h> 39121991Sjhb 40121991Sjhb#include <net/if.h> 41121991Sjhb#include <net/ethernet.h> 42121991Sjhb#include <net/if_media.h> 43121991Sjhb 44121991Sjhb#include <net80211/ieee80211_var.h> 45121991Sjhb#include <net80211/ieee80211_radiotap.h> 46121991Sjhb 47121991Sjhb#include <dev/rtwn/if_rtwnreg.h> 48121991Sjhb#include <dev/rtwn/if_rtwnvar.h> 49121991Sjhb#include <dev/rtwn/if_rtwn_ridx.h> 50121991Sjhb 51121991Sjhb#include <dev/rtwn/rtl8192c/r92c.h> 52121991Sjhb#include <dev/rtwn/rtl8192c/r92c_rx_desc.h> 53121991Sjhb 54121991Sjhbint 55121991Sjhbr92c_classify_intr(struct rtwn_softc *sc, void *buf, int len) 56121991Sjhb{ 57121991Sjhb /* NB: reports are fetched from C2H_MSG register. */ 58121991Sjhb return (RTWN_RX_DATA); 59121991Sjhb} 60121991Sjhb 61121991Sjhbint8_t 62121991Sjhbr92c_get_rssi_cck(struct rtwn_softc *sc, void *physt) 63121991Sjhb{ 64121991Sjhb static const int8_t cckoff[] = { 16, -12, -26, -46 }; 65121991Sjhb struct r92c_rx_cck *cck = (struct r92c_rx_cck *)physt; 66121991Sjhb uint8_t rpt; 67128873Sjhb int8_t rssi; 68128873Sjhb 69128873Sjhb if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) { 70128873Sjhb rpt = (cck->agc_rpt >> 5) & 0x03; 71128873Sjhb rssi = (cck->agc_rpt & 0x1f) << 1; 72128873Sjhb } else { 73128873Sjhb rpt = (cck->agc_rpt >> 6) & 0x03; 74128873Sjhb rssi = cck->agc_rpt & 0x3e; 75121991Sjhb } 76121991Sjhb rssi = cckoff[rpt] - rssi; 77121991Sjhb 78128873Sjhb return (rssi); 79121991Sjhb} 80121991Sjhb 81121991Sjhbint8_t 82121991Sjhbr92c_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) 83121991Sjhb{ 84121991Sjhb struct r92c_rx_phystat *phy = (struct r92c_rx_phystat *)physt; 85121991Sjhb int rssi; 86121991Sjhb 87150264Simp /* Get average RSSI. */ 88121991Sjhb rssi = ((phy->pwdb_all >> 1) & 0x7f) - 110; 89121991Sjhb 90121991Sjhb return (rssi); 91121991Sjhb} 92121991Sjhb 93121991Sjhbuint8_t 94121991Sjhbr92c_rx_radiotap_flags(const void *buf) 95121991Sjhb{ 96121991Sjhb const struct r92c_rx_stat *stat = buf; 97121991Sjhb uint8_t flags, rate; 98121991Sjhb 99164265Sjhb if (!(stat->rxdw3 & htole32(R92C_RXDW3_SPLCP))) 100164265Sjhb return (0); 101164265Sjhb 102164265Sjhb rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); 103121991Sjhb if (RTWN_RATE_IS_CCK(rate)) 104121991Sjhb flags = IEEE80211_RADIOTAP_F_SHORTPRE; 105121991Sjhb else 106121991Sjhb flags = IEEE80211_RADIOTAP_F_SHORTGI; 107154079Sjhb return (flags); 108121991Sjhb} 109154079Sjhb 110154079Sjhbvoid 111121991Sjhbr92c_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, 112121991Sjhb const void *desc, const void *physt_ptr) 113121991Sjhb{ 114121991Sjhb const struct r92c_rx_stat *stat = desc; 115121991Sjhb uint32_t rxdw1, rxdw3; 116121991Sjhb uint8_t rate; 117121991Sjhb 118121991Sjhb rxdw1 = le32toh(stat->rxdw1); 119121991Sjhb rxdw3 = le32toh(stat->rxdw3); 120121991Sjhb rate = MS(rxdw3, R92C_RXDW3_RATE); 121121991Sjhb 122121991Sjhb if (rxdw1 & R92C_RXDW1_AMPDU) 123121991Sjhb rxs->c_pktflags |= IEEE80211_RX_F_AMPDU; 124121991Sjhb else if (rxdw1 & R92C_RXDW1_AMPDU_MORE) 125121991Sjhb rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; 126121991Sjhb if ((rxdw3 & R92C_RXDW3_SPLCP) && rate >= RTWN_RIDX_HT_MCS(0)) 127121991Sjhb rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; 128121991Sjhb 129121991Sjhb if (rxdw3 & R92C_RXDW3_HT40) 130121991Sjhb rxs->c_width = IEEE80211_RX_FW_40MHZ; 131121991Sjhb else 132121991Sjhb rxs->c_width = IEEE80211_RX_FW_20MHZ; 133121991Sjhb 134121991Sjhb if (RTWN_RATE_IS_CCK(rate)) 135121991Sjhb rxs->c_phytype = IEEE80211_RX_FP_11B; 136121991Sjhb else if (rate < RTWN_RIDX_HT_MCS(0)) 137121991Sjhb rxs->c_phytype = IEEE80211_RX_FP_11G; 138121991Sjhb else 139121991Sjhb rxs->c_phytype = IEEE80211_RX_FP_11NG; 140121991Sjhb 141121991Sjhb /* Map HW rate index to 802.11 rate. */ 142121991Sjhb if (rate < RTWN_RIDX_HT_MCS(0)) { 143121991Sjhb rxs->c_rate = ridx2rate[rate]; 144121991Sjhb if (RTWN_RATE_IS_CCK(rate)) 145121991Sjhb rxs->c_pktflags |= IEEE80211_RX_F_CCK; 146121991Sjhb else 147121991Sjhb rxs->c_pktflags |= IEEE80211_RX_F_OFDM; 148121991Sjhb } else { /* MCS0~15. */ 149121991Sjhb rxs->c_rate = 150121991Sjhb IEEE80211_RATE_MCS | (rate - RTWN_RIDX_HT_MCS_SHIFT); 151121991Sjhb rxs->c_pktflags |= IEEE80211_RX_F_HT; 152121991Sjhb } 153121991Sjhb} 154121991Sjhb