/* *************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * * (c) Copyright 2002, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. *************************************************************************** Module Name: cmm_radar.c Abstract: CS/DFS common functions. Revision History: Who When What -------- ---------- ---------------------------------------------- */ #include "rt_config.h" /*----- 802.11H -----*/ /* Periodic Radar detection, switch channel will occur in RTMPHandleTBTTInterrupt()*/ /* Before switch channel, driver needs doing channel switch announcement.*/ VOID RadarDetectPeriodic( IN PRTMP_ADAPTER pAd) { INT i, ChIdx = 0, bAnyUnavailableChannel = FALSE; /* 1. APStart(), CalBufTime = 0; 2. if bAnyUnavailableChannel, CalBufTime = DEFAULT_CAL_BUF_TIME; 3. if Calibrated, CalBufTime = DEFAULT_CAL_BUF_TIME_MAX; */ #if 0 /* need to check channel availability, after switch channel*/ if (pAd->Dot11_H.RDMode != RD_SILENCE_MODE) return; #endif for (i=0; iChannelListNum; i++) { if (pAd->ChannelList[i].RemainingTimeForUse != 0) { bAnyUnavailableChannel = TRUE; } if (pAd->CommonCfg.Channel == pAd->ChannelList[i].Channel) { ChIdx = i; } } if (bAnyUnavailableChannel) pAd->Dot11_H.CalBufTime = DEFAULT_CAL_BUF_TIME; if (pAd->Dot11_H.RDMode == RD_SILENCE_MODE) { /* In Silent Mode, RDCount is use to check with the CAC Time */ if (pAd->Dot11_H.RDCount++ > pAd->Dot11_H.ChMovingTime && pAd->ChannelList[ChIdx].RemainingTimeForUse == 0) { DBGPRINT(RT_DEBUG_TRACE, ("Not found radar signal, start send beacon and radar detection in service monitor\n\n")); pAd->Dot11_H.RDMode = RD_NORMAL_MODE; AsicEnableBssSync(pAd, pAd->CommonCfg.BeaconPeriod); pAd->Dot11_H.RDCount = 0; } } else if (pAd->Dot11_H.RDMode == RD_NORMAL_MODE) { if (!bAnyUnavailableChannel) { pAd->Dot11_H.RDCount++; /* In Normal Mode, RDCount is use to check with the CalBufTime */ if ((pAd->Dot11_H.RDCount >= pAd->Dot11_H.CalBufTime)) { #ifdef MT76x0 mt76x0_calibration(pAd, pAd->hw_cfg.cent_ch, FALSE, TRUE, TRUE); #endif /* MT76x0 */ pAd->Dot11_H.CalBufTime = DEFAULT_CAL_BUF_TIME_MAX; } } } } /* ======================================================================== Routine Description: Radar channel check routine Arguments: pAd Pointer to our adapter Return Value: TRUE need to do radar detect FALSE need not to do radar detect ======================================================================== */ BOOLEAN RadarChannelCheck( IN PRTMP_ADAPTER pAd, IN UCHAR Ch) { INT i; BOOLEAN result = FALSE; for (i=0; iChannelListNum; i++) { if (Ch == pAd->ChannelList[i].Channel) { result = pAd->ChannelList[i].DfsReq; break; } } return result; } /* ======================================================================== Routine Description: Determine the current radar state Arguments: pAd Pointer to our adapter Return Value: ======================================================================== */ VOID RadarStateCheck( IN PRTMP_ADAPTER pAd) { pAd->Dot11_H.CalBufTime = 0; if ((pAd->CommonCfg.Channel > 14) && (pAd->CommonCfg.bIEEE80211H == 1) && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) { pAd->Dot11_H.RDMode = RD_SILENCE_MODE; pAd->Dot11_H.RDCount = 0; pAd->Dot11_H.InServiceMonitorCount = 0; } else pAd->Dot11_H.RDMode = RD_NORMAL_MODE; #ifdef CARRIER_DETECTION_SUPPORT if ((pAd->CommonCfg.RDDurRegion == JAP) || (pAd->CommonCfg.RDDurRegion == JAP_W53) || (pAd->CommonCfg.RDDurRegion == JAP_W56)) { if ((pAd->CommonCfg.Channel > 14) || (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40)) { pAd->CommonCfg.CarrierDetect.Enable = TRUE; } } #endif /* CARRIER_DETECTION_SUPPORT */ } ULONG JapRadarType( IN PRTMP_ADAPTER pAd) { ULONG i; const UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; if (pAd->CommonCfg.RDDurRegion != JAP) { return pAd->CommonCfg.RDDurRegion; } for (i=0; i<15; i++) { if (pAd->CommonCfg.Channel == Channel[i]) { break; } } if (i < 4) return JAP_W53; else if (i < 15) return JAP_W56; else return JAP; /* W52*/ } UCHAR get_channel_by_reference( IN PRTMP_ADAPTER pAd, IN UINT8 mode) { UCHAR ch = 0; INT ch_idx; switch (mode) { case 1: { USHORT min_time = 0xFFFF; /* select channel with least RemainingTimeForUse */ for ( ch_idx = 0; ch_idx < pAd->ChannelListNum; ch_idx++) { if (pAd->ChannelList[ch_idx].RemainingTimeForUse < min_time) { min_time = pAd->ChannelList[ch_idx].RemainingTimeForUse; ch = pAd->ChannelList[ch_idx].Channel; } } break; } default: { ch = FirstChannel(pAd); break; } } DBGPRINT(RT_DEBUG_TRACE,("%s(): mode = %u, ch = %u\n", __FUNCTION__, mode, ch)); return ch; } #ifdef CONFIG_AP_SUPPORT /* ======================================================================== Routine Description: Channel switching count down process upon radar detection Arguments: pAd Pointer to our adapter ======================================================================== */ VOID ChannelSwitchingCountDownProc( IN PRTMP_ADAPTER pAd) { DBGPRINT(RT_DEBUG_TRACE, ("%s():Channel Switching...(%d/%d)\n", __FUNCTION__, pAd->Dot11_H.CSCount, pAd->Dot11_H.CSPeriod)); pAd->Dot11_H.CSCount++; if (pAd->Dot11_H.CSCount >= pAd->Dot11_H.CSPeriod) { #ifdef DFS_SUPPORT pAd->CommonCfg.RadarDetect.DFSAPRestart = 1; schedule_dfs_task(pAd); #else APStop(pAd); APStartUp(pAd); #endif /* !DFS_SUPPORT */ } } #endif /* CONFIG_AP_SUPPORT */ /* ========================================================================== Description: Set channel switch Period Return: TRUE if all parameters are OK, FALSE otherwise ========================================================================== */ INT Set_CSPeriod_Proc( IN PRTMP_ADAPTER pAd, IN RTMP_STRING *arg) { pAd->Dot11_H.CSPeriod = (USHORT) simple_strtol(arg, 0, 10); DBGPRINT(RT_DEBUG_TRACE, ("Set_CSPeriod_Proc::(CSPeriod=%d)\n", pAd->Dot11_H.CSPeriod)); return TRUE; } /* ========================================================================== Description: change channel moving time for DFS testing. Arguments: pAdapter Pointer to our adapter wrq Pointer to the ioctl argument Return Value: None Note: Usage: 1.) iwpriv ra0 set ChMovTime=[value] ========================================================================== */ INT Set_ChMovingTime_Proc( IN PRTMP_ADAPTER pAd, IN RTMP_STRING *arg) { USHORT Value; Value = (USHORT) simple_strtol(arg, 0, 10); pAd->Dot11_H.ChMovingTime = Value; DBGPRINT(RT_DEBUG_TRACE, ("%s: %d\n", __FUNCTION__, pAd->Dot11_H.ChMovingTime)); return TRUE; } /* ========================================================================== Description: Reset channel block status. Arguments: pAd Pointer to our adapter arg Not used Return Value: None Note: Usage: 1.) iwpriv ra0 set ChMovTime=[value] ========================================================================== */ INT Set_BlockChReset_Proc( IN PRTMP_ADAPTER pAd, IN RTMP_STRING *arg) { INT i; DBGPRINT(RT_DEBUG_TRACE, ("%s: Reset channel block status.\n", __FUNCTION__)); for (i=0; iChannelListNum; i++) pAd->ChannelList[i].RemainingTimeForUse = 0; return TRUE; } #if defined(DFS_SUPPORT) || defined(CARRIER_DETECTION_SUPPORT) INT Set_RadarShow_Proc( IN PRTMP_ADAPTER pAd, IN RTMP_STRING *arg) { #ifdef DFS_SUPPORT UINT8 idx; PRADAR_DETECT_STRUCT pRadarDetect = &pAd->CommonCfg.RadarDetect; PDFS_PROGRAM_PARAM pDfsProgramParam = &pRadarDetect->DfsProgramParam; PDFS_SW_DETECT_PARAM pDfsSwParam = &pRadarDetect->DfsSwParam; PCHAR RDMode[]= {"Normal State", "Switching State", "Silent State"}; printk("DFSUseTasklet = %d\n", pRadarDetect->use_tasklet); printk("McuRadarDebug = %x\n", (unsigned int)pRadarDetect->McuRadarDebug); printk("PollTime = %d\n", pRadarDetect->PollTime); printk("ChEnable = %d (0x%x)\n", pDfsProgramParam->ChEnable, pDfsProgramParam->ChEnable); printk("DeltaDelay = %d\n", pDfsProgramParam->DeltaDelay); printk("PeriodErr = %d\n", pDfsSwParam->dfs_period_err); printk("MaxPeriod = %d\n", (unsigned int)pDfsSwParam->dfs_max_period); printk("Ch0LErr = %d\n", pDfsSwParam->dfs_width_ch0_err_L); printk("Ch0HErr = %d\n", pDfsSwParam->dfs_width_ch0_err_H); printk("Ch1Shift = %d\n", pDfsSwParam->dfs_width_diff_ch1_Shift); printk("Ch2Shift = %d\n", pDfsSwParam->dfs_width_diff_ch2_Shift); printk("DfsRssiHigh = %d\n", pRadarDetect->DfsRssiHigh); printk("DfsRssiLow = %d\n", pRadarDetect->DfsRssiLow); printk("DfsSwDisable = %u\n", pRadarDetect->bDfsSwDisable); printk("CheckLoop = %d\n", pDfsSwParam->dfs_check_loop); printk("DeclareThres = %d\n", pDfsSwParam->dfs_declare_thres); for (idx=0; idx < pAd->chipCap.DfsEngineNum; idx++) printk("sw_idx[%u] = %u\n", idx, pDfsSwParam->sw_idx[idx]); for (idx=0; idx < pAd->chipCap.DfsEngineNum; idx++) printk("hw_idx[%u] = %u\n", idx, pDfsSwParam->hw_idx[idx]); printk("pAd->Dot11_H.ChMovingTime = %d\n", pAd->Dot11_H.ChMovingTime); printk("pAd->Dot11_H.RDMode = %s\n", RDMode[pAd->Dot11_H.RDMode]); printk("pAd->Dot11_H.RDCount = %d\n", pAd->Dot11_H.RDCount); printk("pAd->Dot11_H.CalBufTime = %d\n", pAd->Dot11_H.CalBufTime); #endif /* DFS_SUPPORT */ #ifdef CARRIER_DETECTION_SUPPORT printk("pAd->CommonCfg.CarrierDetect.CD_State = %d\n", pAd->CommonCfg.CarrierDetect.CD_State); printk("pAd->CommonCfg.CarrierDetect.criteria = %d\n", pAd->CommonCfg.CarrierDetect.criteria); printk("pAd->CommonCfg.CarrierDetect.Delta = %d\n", pAd->CommonCfg.CarrierDetect.delta); printk("pAd->CommonCfg.CarrierDetect.DivFlag = %d\n", pAd->CommonCfg.CarrierDetect.div_flag); printk("pAd->CommonCfg.CarrierDetect.Threshold = %d(0x%x)\n", pAd->CommonCfg.CarrierDetect.threshold, pAd->CommonCfg.CarrierDetect.threshold); #endif /* CARRIER_DETECTION_SUPPORT */ return TRUE; } /* ======================================================================== Routine Description: Control CCK_MRC Status Arguments: pAd Pointer to our adapter Return Value: ======================================================================== */ VOID CckMrcStatusCtrl(IN PRTMP_ADAPTER pAd) { #ifdef RT5592 UCHAR bbp = 0, bCckMrc = 0; #ifdef RELEASE_EXCLUDE /* This function control CCK_MRC status according to the following table: Due to the H/W issue, when CS/DFS is turned ON, the CCK_MRC should be keep OFF except in 2.4G with 40BW. This function can be removed after the H/W issue fixed. | | G band | A band | | BW |20 |40 | 20 |40 | |CS enabled | X O X X | |CS disabled | O O X X | */ #endif /* RELEASE_EXCLUDE */ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R95, &bbp); bCckMrc = (bbp >> 7); if (bCckMrc) { if (pAd->CommonCfg.Channel>14 #ifdef CARRIER_DETECTION_SUPPORT || (pAd->CommonCfg.CarrierDetect.Enable == TRUE && pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_20) #endif /* CARRIER_DETECTION_SUPPORT */ ) { /* Disable CCK_MRC*/ bbp &= ~(1 << 7); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R95, bbp); } } else { if (pAd->CommonCfg.Channel<=14) { #ifdef CARRIER_DETECTION_SUPPORT if (pAd->CommonCfg.CarrierDetect.Enable == FALSE || pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) #endif /* CARRIER_DETECTION_SUPPORT */ { /* Enable CCK_MRC */ bbp |= (1 << 7); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R95, bbp); } } } #endif /* RT5592 */ } /* ======================================================================== Routine Description: Enhance DFS/CS when using GLRT. Arguments: pAd Pointer to our adapter Return Value: ======================================================================== */ VOID RadarGLRTCompensate(IN PRTMP_ADAPTER pAd) { #ifdef RT5592 #ifdef RELEASE_EXCLUDE /* Moderate GLRT effect on CS/DFS. This is a H/W issue, CS/DFS radar will cause large false CCA at some frequency points when using GLRT. This will block DFS/CS signels. If CS/DFS is enabled, GLRT should be programmed as bellow. */ #endif /* RELEASE_EXCLUDE */ if (pAd->CommonCfg.bIEEE80211H == 1 #ifdef CARRIER_DETECTION_SUPPORT || pAd->CommonCfg.CarrierDetect.Enable == TRUE #endif /* CARRIER_DETECTION_SUPPORT */ ) { RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x91); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x24); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x95); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x2D); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x99); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x40); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x9A); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x3E); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x9B); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x42); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x9C); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x3D); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0x9D); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x40); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0xA1); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x2F); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0xA5); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x2A); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0xB5); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x40); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R195, 0xCE); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R196, 0x43); } #endif /* RT5592 */ } #endif /*defined(DFS_SUPPORT) || defined(CARRIER_DETECTION_SUPPORT) */