Path: blob/main/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2010-2011 Atheros Communications, Inc.4*5* Permission to use, copy, modify, and/or distribute this software for any6* purpose with or without fee is hereby granted, provided that the above7* copyright notice and this permission notice appear in all copies.8*9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16*/17#include "opt_ah.h"1819#include "ah.h"20#include "ah_internal.h"21#include "ah_devid.h"22#include "ah_desc.h" /* NB: for HAL_PHYERR* */2324#include "ar5416/ar5416.h"25#include "ar5416/ar5416reg.h"26#include "ar5416/ar5416phy.h"2728#include "ah_eeprom_v14.h" /* for owl_get_ntxchains() */2930/*31* These are default parameters for the AR5416 and32* later 802.11n NICs. They simply enable some33* radar pulse event generation.34*35* These are very likely not valid for the AR5212 era36* NICs.37*38* Since these define signal sizing and threshold39* parameters, they may need changing based on the40* specific antenna and receive amplifier41* configuration.42*/43#define AR5416_DFS_FIRPWR -3344#define AR5416_DFS_RRSSI 2045#define AR5416_DFS_HEIGHT 1046#define AR5416_DFS_PRSSI 1547#define AR5416_DFS_INBAND 1548#define AR5416_DFS_RELPWR 849#define AR5416_DFS_RELSTEP 1250#define AR5416_DFS_MAXLEN 2555152HAL_BOOL53ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)54{5556/*57* These are general examples of the parameter values58* to use when configuring radar pulse detection for59* the AR5416, AR91xx, AR92xx NICs. They are only60* for testing and do require tuning depending upon the61* hardware and deployment specifics.62*/63pe->pe_firpwr = AR5416_DFS_FIRPWR;64pe->pe_rrssi = AR5416_DFS_RRSSI;65pe->pe_height = AR5416_DFS_HEIGHT;66pe->pe_prssi = AR5416_DFS_PRSSI;67pe->pe_inband = AR5416_DFS_INBAND;68pe->pe_relpwr = AR5416_DFS_RELPWR;69pe->pe_relstep = AR5416_DFS_RELSTEP;70pe->pe_maxlen = AR5416_DFS_MAXLEN;7172return (AH_TRUE);73}7475/*76* Get the radar parameter values and return them in the pe77* structure78*/79void80ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)81{82uint32_t val, temp;8384val = OS_REG_READ(ah, AR_PHY_RADAR_0);8586temp = MS(val,AR_PHY_RADAR_0_FIRPWR);87temp |= 0xFFFFFF80;88pe->pe_firpwr = temp;89pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);90pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);91pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);92pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);9394/* RADAR_1 values */95val = OS_REG_READ(ah, AR_PHY_RADAR_1);96pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);97pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);98pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);99100pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &101AR_PHY_RADAR_EXT_ENA);102103pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &104AR_PHY_RADAR_1_USE_FIR128);105pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &106AR_PHY_RADAR_1_BLOCK_CHECK);107pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &108AR_PHY_RADAR_1_MAX_RRSSI);109pe->pe_enabled = !!110(OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);111pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &112AR_PHY_RADAR_1_RELPWR_ENA);113pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &114AR_PHY_RADAR_1_RELSTEP_CHECK);115}116117/*118* Enable radar detection and set the radar parameters per the119* values in pe120*/121void122ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)123{124uint32_t val;125126val = OS_REG_READ(ah, AR_PHY_RADAR_0);127128if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {129val &= ~AR_PHY_RADAR_0_FIRPWR;130val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);131}132if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {133val &= ~AR_PHY_RADAR_0_RRSSI;134val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);135}136if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {137val &= ~AR_PHY_RADAR_0_HEIGHT;138val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);139}140if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {141val &= ~AR_PHY_RADAR_0_PRSSI;142val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);143}144if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {145val &= ~AR_PHY_RADAR_0_INBAND;146val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);147}148149/*Enable FFT data*/150val |= AR_PHY_RADAR_0_FFT_ENA;151OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);152153/* Implicitly enable */154if (pe->pe_enabled == 1)155OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);156else if (pe->pe_enabled == 0)157OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);158159if (pe->pe_usefir128 == 1)160OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);161else if (pe->pe_usefir128 == 0)162OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);163164if (pe->pe_enmaxrssi == 1)165OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);166else if (pe->pe_enmaxrssi == 0)167OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);168169if (pe->pe_blockradar == 1)170OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);171else if (pe->pe_blockradar == 0)172OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);173174if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {175val = OS_REG_READ(ah, AR_PHY_RADAR_1);176val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;177val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);178OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);179}180if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {181val = OS_REG_READ(ah, AR_PHY_RADAR_1);182val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;183val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);184OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);185}186187if (pe->pe_en_relstep_check == 1)188OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,189AR_PHY_RADAR_1_RELSTEP_CHECK);190else if (pe->pe_en_relstep_check == 0)191OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,192AR_PHY_RADAR_1_RELSTEP_CHECK);193194if (pe->pe_enrelpwr == 1)195OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,196AR_PHY_RADAR_1_RELPWR_ENA);197else if (pe->pe_enrelpwr == 0)198OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,199AR_PHY_RADAR_1_RELPWR_ENA);200201if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {202val = OS_REG_READ(ah, AR_PHY_RADAR_1);203val &= ~AR_PHY_RADAR_1_MAXLEN;204val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);205OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);206}207208/*209* Enable HT/40 if the upper layer asks;210* it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS211* is available.212*/213if (pe->pe_extchannel == 1)214OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);215else if (pe->pe_extchannel == 0)216OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);217}218219/*220* Extract the radar event information from the given phy error.221*222* Returns AH_TRUE if the phy error was actually a phy error,223* AH_FALSE if the phy error wasn't a phy error.224*/225226/* Flags for pulse_bw_info */227#define PRI_CH_RADAR_FOUND 0x01228#define EXT_CH_RADAR_FOUND 0x02229#define EXT_CH_RADAR_EARLY_FOUND 0x04230231HAL_BOOL232ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,233uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)234{235HAL_BOOL doDfsExtCh;236HAL_BOOL doDfsEnhanced;237HAL_BOOL doDfsCombinedRssi;238239uint8_t rssi = 0, ext_rssi = 0;240uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;241uint32_t dur = 0;242int pri_found = 1, ext_found = 0;243int early_ext = 0;244int is_dc = 0;245uint16_t datalen; /* length from the RX status field */246247/* Check whether the given phy error is a radar event */248if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&249(rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {250return AH_FALSE;251}252253/* Grab copies of the capabilities; just to make the code clearer */254doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;255doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;256doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;257258datalen = rxs->rs_datalen;259260/* If hardware supports it, use combined RSSI, else use chain 0 RSSI */261if (doDfsCombinedRssi)262rssi = (uint8_t) rxs->rs_rssi;263else264rssi = (uint8_t) rxs->rs_rssi_ctl[0];265266/* Set this; but only use it if doDfsExtCh is set */267ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];268269/* Cap it at 0 if the RSSI is a negative number */270if (rssi & 0x80)271rssi = 0;272273if (ext_rssi & 0x80)274ext_rssi = 0;275276/*277* Fetch the relevant data from the frame278*/279if (doDfsExtCh) {280if (datalen < 3)281return AH_FALSE;282283/* Last three bytes of the frame are of interest */284pulse_length_pri = *(buf + datalen - 3);285pulse_length_ext = *(buf + datalen - 2);286pulse_bw_info = *(buf + datalen - 1);287HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"288" pulse_length_ext=%d, pulse_bw_info=%x\n",289__func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,290pulse_bw_info);291} else {292/* The pulse width is byte 0 of the data */293if (datalen >= 1)294dur = ((uint8_t) buf[0]) & 0xff;295else296dur = 0;297298if (dur == 0 && rssi == 0) {299HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);300return AH_FALSE;301}302303HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);304305/* Single-channel only */306pri_found = 1;307ext_found = 0;308}309310/*311* If doing extended channel data, pulse_bw_info must312* have one of the flags set.313*/314if (doDfsExtCh && pulse_bw_info == 0x0)315return AH_FALSE;316317/*318* If the extended channel data is available, calculate319* which to pay attention to.320*/321if (doDfsExtCh) {322/* If pulse is on DC, take the larger duration of the two */323if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&324(pulse_bw_info & PRI_CH_RADAR_FOUND)) {325is_dc = 1;326if (pulse_length_ext > pulse_length_pri) {327dur = pulse_length_ext;328pri_found = 0;329ext_found = 1;330} else {331dur = pulse_length_pri;332pri_found = 1;333ext_found = 0;334}335} else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {336dur = pulse_length_ext;337pri_found = 0;338ext_found = 1;339early_ext = 1;340} else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {341dur = pulse_length_pri;342pri_found = 1;343ext_found = 0;344} else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {345dur = pulse_length_ext;346pri_found = 0;347ext_found = 1;348}349350}351352/*353* For enhanced DFS (Merlin and later), pulse_bw_info has354* implications for selecting the correct RSSI value.355*/356if (doDfsEnhanced) {357switch (pulse_bw_info & 0x03) {358case 0:359/* No radar? */360rssi = 0;361break;362case PRI_CH_RADAR_FOUND:363/* Radar in primary channel */364/* Cannot use ctrl channel RSSI if ext channel is stronger */365if (ext_rssi >= (rssi + 3)) {366rssi = 0;367}368break;369case EXT_CH_RADAR_FOUND:370/* Radar in extended channel */371/* Cannot use ext channel RSSI if ctrl channel is stronger */372if (rssi >= (ext_rssi + 12)) {373rssi = 0;374} else {375rssi = ext_rssi;376}377break;378case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):379/* When both are present, use stronger one */380if (rssi < ext_rssi)381rssi = ext_rssi;382break;383}384}385386/*387* If not doing enhanced DFS, choose the ext channel if388* it is stronger than the main channel389*/390if (doDfsExtCh && !doDfsEnhanced) {391if ((ext_rssi > rssi) && (ext_rssi < 128))392rssi = ext_rssi;393}394395/*396* XXX what happens if the above code decides the RSSI397* XXX wasn't valid, an sets it to 0?398*/399400/*401* Fill out dfs_event structure.402*/403event->re_full_ts = fulltsf;404event->re_ts = rxs->rs_tstamp;405event->re_rssi = rssi;406event->re_dur = dur;407408event->re_flags = 0;409if (pri_found)410event->re_flags |= HAL_DFS_EVENT_PRICH;411if (ext_found)412event->re_flags |= HAL_DFS_EVENT_EXTCH;413if (early_ext)414event->re_flags |= HAL_DFS_EVENT_EXTEARLY;415if (is_dc)416event->re_flags |= HAL_DFS_EVENT_ISDC;417418return AH_TRUE;419}420421/*422* Return whether fast-clock is currently enabled for this423* channel.424*/425HAL_BOOL426ar5416IsFastClockEnabled(struct ath_hal *ah)427{428struct ath_hal_private *ahp = AH_PRIVATE(ah);429430return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);431}432433434