380939960@qq.com 2015-9-29
【引子】
l 在调试WIFI client设备时发现基于MT7620的WIFI网关的WIFI非常不稳定; 串口上经常会出现“MgmtRingFullCount”, 导致WIFI client连不上WIFI网关,或者download firmware很慢。
“Qidx(0), notenough space in MgmtRing, MgmtRingFullCount=118!”
l WIFI标准中除了DFS(欧洲为了避免WIFI干扰5G频段的雷达)外,目前了解的情况是并没有明确规定WIFI AP如果通过自动调频来避免噪杂的环境干扰。
l 目前处于2.4G的有很多无线应用,zigbee,蓝牙,WIFI,无绳电话等等;在这些应用中,蓝牙标准通过自动动态调频来规避可能的信道拥塞。目前WIFI网关出现的问题也可能和无线电干扰有关,因此如果能够自动切换channel,可能会让网关的WIFI更灵活。家用路由器如果WIFI异常了,大不了人工重启一下,但是可能某些WIFI网关需要能够做到无人工干预的自适应。
在Ralink的WIFI driver源码中,提供了一种QBSS_LoadAlarm的机制,它可以根据系统负载自动切换WIFIchannel,这里我们尝试对该机制进行分析。
QBSS_LoadAlarm简介
l 从RT5350使用的WIFI driver上看,本身提供一种QBSS_LoadAlarm的机制; 该机制需要修改代码,使能几个条件编译宏打开该功能;
l 然后通过iwpriv命令合理设置"qloadalarmtimethres"和"qloadalarmnumthres"两个参数;
iwpriv ra0 set qloadalarmtimethres=50
在原厂的SDK中, 这两个参数还未写入到nvram中;因此这两个参数重启后无法保存,用户必须每次在加载Ralink WIFI driver后,通过“iwpriv”命令进行设置。
l “qloadalarmtimethres”该参数设置的是driver中的QloadAlarmBusyTimeThreshold;它是百分比,就是channel繁忙的时间占用TBTT的百分比;因此” iwpriv ra0 setqloadalarmtimethres=value”中value的取值范围应该是0~100; driver中将TBTT设置为beaconPeriod, 也就是发送Beacon帧的周期;
l "qloadalarmnumthres":channel连续繁忙>=“qloadalarmtimethres”的次数超过"qloadalarmnumthres",driver就会发送一个告警,然后开始自动寻找并切换到一个相对不那么繁忙的channel。
l The continued number of busy time >= threshold islarger than number threshold so issuing an alarm.
从底层获取channel方法状况
从Datasheet中,可知通过“CH_BUSY_STA”和“CH_BUSY_STA_SEC”这两个寄存器获得“primary channel”和“secondarychannel”的繁忙情况。
至于“primary channel”和“secondarychannel”,是因为当个WIFI channel的宽度是20M,如果要实现40M宽度的话,就需要使用到两个channel;具体可以参见WIFI协议。
“CH_BUSY_STA”和“CH_BUSY_STA_SEC”这两个寄存器在datasheet中的定义如下所示:
对应的源码如下所示:
/* Count EIFS, NAV, RX busy, TX busy as channel busy and enable Channel statistic timer (bit 0) */ /* Note: if bit 0 == 0, the function will be disabled */ RTMP_IO_WRITE32(pAd, CH_TIME_CFG, 0x0000001F);
#define TBTT_SYNC_CFG 0x1118 /* txrx_csr10 */ #define TSF_TIMER_DW0 0x111C /* Local TSF timer lsb 32 bits. Read-only */ #define TSF_TIMER_DW1 0x1120 /* msb 32 bits. Read-only. */ #define TBTT_TIMER 0x1124 /* TImer remains till next TBTT. Read-only. TXRX_CSR14 */ #define INT_TIMER_CFG 0x1128 /* */ #define INT_TIMER_EN 0x112c /* GP-timer and pre-tbtt Int enable */ #define CH_IDLE_STA 0x1130 /* channel idle time */ #define CH_BUSY_STA 0x1134 /* channle busy time */ #define CH_BUSY_STA_SEC 0x1138 /* channel busy time for secondary channel */
/* in 20MHz, no need to check busy time of secondary channel */ RTMP_IO_READ32(pAd, CH_BUSY_STA_SEC, &BusyTime); pAd->QloadLatestChannelBusyTimeSec |