This patch adds error vector magnitude collection to AR9001 and AR9002, as well as my best attempt at making sense of what the EVM numbers actually mean. There was an obvious problem with the AR_RxEVMn macros (parts of status4 were being used for rssi, and all of status4 was also being used for EVM0, so the EVM block probably actually starts at 5, since 5, 6 and 7 aren't used in the code for any other purpose). The AR6002 driver has a bit for the PCU MISC register related to EVM. A lot of the other bits line up in that register between AR9002 and AR6002, so this patch also sets that bit. I'm assuming that enables something related to EVM, but so far it seems like the default behavior for the AR9220 reports EVM just fine (so this change doesn't appear to be necessary).
The EVM readings themselves are a bit peculiar. They seem broken up by octet. Legacy rates yield 0x80808080, and HT rates yield numbers like 0x1a1e1f21. MCS0-7 produce non-zero results in EVM0, and MCS8-15 produce non-zero results in EVM0 and EVM1. At close range, the octets are typically between 0x1a and 0x24. At greater range, the octets go down to between 0x04 and 0x13. My best guess so far is that all 32-bits of each EVM reading is significant, and each octet of that is the EVM of a pilot carrier in negative dB. EVM0, then, is probably the EVM for spatial stream 0, and so on. Does that make sense to anybody? To aid in figuring this out, I track the last valid EVM reading for each bitrate in the debug rx_stats struct, and these EVM stats can be dumped by reading the recv file in debugfs. There's also a lookup table to handle conversion between EVM(dB) and EVM(%), since percentage makes more sense to me in this context. I'm just guessing on this stuff, based on experimentation. Opinions and insight are very welcome. This is an RFC, and I haven't put much thought into how this might actually be tracked and presented. In the short-term, I just want it for a better quality control metric. It does seem to shed some light on situations where RSSI is high, but minstrel_ht settles on a mid-level bitrate. In a few cases where I've seen that now with EVM reporting, often I see what I assume is a pilot carrier having an EVM 5 or 7 dB worse than the rest (perhaps due to frequency-dependent multipath interference knocking down one block of carriers). Here is the chunk of recv when the ath9k station is near the AP, and when it is about 30' away (through a few walls): Short-range: Rate Chain Pilot 1 Pilot 2 Pilot 3 Pilot 4 MCS00 0 27 ( 4%) 24 ( 6%) 24 ( 6%) 24 ( 6%) MCS01 0 24 ( 6%) 24 ( 6%) 26 ( 5%) 24 ( 6%) MCS02 0 26 ( 5%) 27 ( 4%) 26 ( 5%) 25 ( 5%) MCS03 0 33 ( 2%) 30 ( 3%) 29 ( 3%) 32 ( 2%) MCS04 0 28 ( 3%) 26 ( 5%) 28 ( 3%) 31 ( 2%) MCS05 0 32 ( 2%) 25 ( 5%) 30 ( 3%) 23 ( 7%) MCS06 0 28 ( 3%) 26 ( 5%) 31 ( 2%) 29 ( 3%) MCS07 0 28 ( 3%) 26 ( 5%) 30 ( 3%) 28 ( 3%) MCS08 0 26 ( 5%) 25 ( 5%) 27 ( 4%) 26 ( 5%) MCS08 1 25 ( 5%) 26 ( 5%) 27 ( 4%) 23 ( 7%) MCS09 0 24 ( 6%) 28 ( 3%) 29 ( 3%) 28 ( 3%) MCS09 1 24 ( 6%) 26 ( 5%) 26 ( 5%) 26 ( 5%) MCS10 0 21 ( 8%) 24 ( 6%) 26 ( 5%) 26 ( 5%) MCS10 1 22 ( 7%) 27 ( 4%) 28 ( 3%) 25 ( 5%) MCS11 0 26 ( 5%) 24 ( 6%) 26 ( 5%) 28 ( 3%) MCS11 1 23 ( 7%) 29 ( 3%) 31 ( 2%) 25 ( 5%) MCS12 0 29 ( 3%) 25 ( 5%) 32 ( 2%) 29 ( 3%) MCS12 1 27 ( 4%) 26 ( 5%) 34 ( 1%) 23 ( 7%) MCS13 0 25 ( 5%) 22 ( 7%) 28 ( 3%) 26 ( 5%) MCS13 1 23 ( 7%) 26 ( 5%) 30 ( 3%) 26 ( 5%) MCS14 0 21 ( 8%) 23 ( 7%) 21 ( 8%) 24 ( 6%) MCS14 1 20 ( 10%) 23 ( 7%) 26 ( 5%) 21 ( 8%) MCS15 0 25 ( 5%) 25 ( 5%) 28 ( 3%) 24 ( 6%) MCS15 1 22 ( 7%) 26 ( 5%) 27 ( 4%) 32 ( 2%) Mid-range: Rate Chain Pilot 1 Pilot 2 Pilot 3 Pilot 4 MCS00 0 20 ( 10%) 15 ( 17%) 26 ( 5%) 27 ( 4%) MCS01 0 20 ( 10%) 18 ( 12%) 27 ( 4%) 26 ( 5%) MCS02 0 22 ( 7%) 19 ( 11%) 25 ( 5%) 22 ( 7%) MCS03 0 19 ( 11%) 13 ( 22%) 31 ( 2%) 25 ( 5%) MCS04 0 21 ( 8%) 20 ( 10%) 29 ( 3%) 28 ( 3%) MCS05 0 17 ( 14%) 15 ( 17%) 25 ( 5%) 33 ( 2%) MCS06 0 16 ( 15%) 17 ( 14%) 32 ( 2%) 28 ( 3%) MCS07 0 19 ( 11%) 13 ( 22%) 34 ( 1%) 26 ( 5%) MCS08 0 17 ( 14%) 18 ( 12%) 11 ( 28%) 12 ( 25%) MCS08 1 9 ( 35%) 7 ( 44%) 16 ( 15%) 15 ( 17%) MCS09 0 15 ( 17%) 19 ( 11%) 9 ( 35%) 10 ( 31%) MCS09 1 12 ( 25%) 11 ( 28%) 11 ( 28%) 13 ( 22%) MCS10 0 18 ( 12%) 20 ( 10%) 9 ( 35%) 10 ( 31%) MCS10 1 9 ( 35%) 9 ( 35%) 11 ( 28%) 11 ( 28%) MCS11 0 16 ( 15%) 22 ( 7%) 5 ( 56%) 7 ( 44%) MCS11 1 14 ( 19%) 12 ( 25%) 11 ( 28%) 12 ( 25%) MCS12 0 19 ( 11%) 21 ( 8%) 11 ( 28%) 14 ( 19%) MCS12 1 14 ( 19%) 15 ( 17%) 13 ( 22%) 19 ( 11%) MCS13 0 14 ( 19%) 20 ( 10%) 6 ( 50%) 8 ( 39%) MCS13 1 14 ( 19%) 12 ( 25%) 17 ( 14%) 13 ( 22%) MCS14 0 14 ( 19%) 17 ( 14%) 11 ( 28%) 13 ( 22%) MCS14 1 14 ( 19%) 15 ( 17%) 12 ( 25%) 14 ( 19%) MCS15 0 12 ( 25%) 11 ( 28%) 9 ( 35%) 10 ( 31%) MCS15 1 14 ( 19%) 12 ( 25%) 15 ( 17%) 16 ( 15%) Keep in mind all those are just for the last received packet at that bitrate, so there's a fair amount of flux over time (maybe +/- 2 at each octet). drivers/net/wireless/ath/ath9k/debug.c | 54 +++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath9k/debug.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 1 + drivers/net/wireless/ath/ath9k/mac.c | 11 ++++++ drivers/net/wireless/ath/ath9k/mac.h | 6 ++-- drivers/net/wireless/ath/ath9k/reg.h | 1 + 6 files changed, 70 insertions(+), 4 deletions(-) --- Index: compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/mac.c =================================================================== --- compat-wireless-2011-01-07.orig/drivers/net/wireless/ath/ath9k/mac.c 2011-01-09 01:52:28.544097198 -0500 +++ compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/mac.c 2011-01-09 01:52:35.552097198 -0500 @@ -705,6 +705,17 @@ rs->rs_status |= ATH9K_RXERR_DECRYPT; } + rs->evm0 = ads.AR_RxEVM0; + rs->evm1 = ads.AR_RxEVM1; + rs->evm2 = ads.AR_RxEVM2; +#if 0 + if (0 != rs->evm0 && 0x80808080 != rs->evm0) + { + printk("ath9k: EVM0: 0x%.8x EVM1: 0x%.8x EVM2: 0x%.8x\n", + rs->evm0, rs->evm1, rs->evm2); + } +#endif + return 0; } EXPORT_SYMBOL(ath9k_hw_rxprocdesc); Index: compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/reg.h =================================================================== --- compat-wireless-2011-01-07.orig/drivers/net/wireless/ath/ath9k/reg.h 2011-01-09 01:52:28.560097198 -0500 +++ compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/reg.h 2011-01-09 01:52:35.552097198 -0500 @@ -1585,6 +1585,7 @@ #define AR_PCU_TBTT_PROTECT 0x00200000 #define AR_PCU_CLEAR_VMF 0x01000000 #define AR_PCU_CLEAR_BA_VALID 0x04000000 +#define AR_PCU_SEL_EVM 0x08000000 #define AR_PCU_ALWAYS_PERFORM_KEYSEARCH 0x10000000 #define AR_PCU_BT_ANT_PREVENT_RX 0x00100000 Index: compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/debug.c =================================================================== --- compat-wireless-2011-01-07.orig/drivers/net/wireless/ath/ath9k/debug.c 2011-01-09 01:52:28.608097198 -0500 +++ compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/debug.c 2011-01-09 01:52:35.552097198 -0500 @@ -666,6 +666,16 @@ .llseek = default_llseek, }; +#define ATH9K_EVM_LUT_MAX 44 +static u8 evm_dB_to_percent_lut[ATH9K_EVM_LUT_MAX] = { + 100, 89, 79, 70, 63, 56, 50, 44, 39, 35, 31, 28, + 25, 22, 19, 17, 15, 14, 12, 11, 10, 8, 7, 7, + 6, 5, 5, 4, 3, 3, 3, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 0, 0, +}; + +#define ATH9K_EVM_TO_PCT(x) (x >= ATH9K_EVM_LUT_MAX ? 0 : evm_dB_to_percent_lut[x]) + static ssize_t read_file_recv(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -675,8 +685,9 @@ struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 1152; + unsigned int len = 0, size = 4096; ssize_t retval = 0; + int rateidx = 0; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -738,6 +749,41 @@ "%18s : %10u\n", "RX-Bytes-All", sc->debug.stats.rxstats.rx_bytes_all); + len += snprintf(buf + len, size - len, "\nEVM:\n"); + len += snprintf(buf + len, size - len, + "\tRate Chain Pilot 1 Pilot 2 Pilot 3 Pilot 4\n"); + // \tMCSnn n nn (nnn%) nn (nnn%) nn (nnn%) nn (nnn%) + for (rateidx = 0; rateidx < 24; rateidx++) + { + if (sc->debug.stats.rxstats.evm_stats[rateidx][0] || + sc->debug.stats.rxstats.evm_stats[rateidx][1] || + sc->debug.stats.rxstats.evm_stats[rateidx][2]) + { + int chain; + for (chain = 0; chain<2; chain++) + { + u32 evm = sc->debug.stats.rxstats.evm_stats[rateidx][chain]; + if (evm) + { + u8 pilot1, pilot2, pilot3, pilot4; + pilot1 = (evm & 0xFF000000) >> 24; + pilot2 = (evm & 0x00FF0000) >> 16; + pilot3 = (evm & 0x0000FF00) >> 8; + pilot4 = (evm & 0x000000FF); + len += snprintf(buf + len, size - len, + "\tMCS%02u %u " + "%2u (%3u%%) %2u (%3u%%) " + "%2u (%3u%%) %2u (%3u%%)\n", + rateidx, chain, + pilot1, ATH9K_EVM_TO_PCT(pilot1), + pilot2, ATH9K_EVM_TO_PCT(pilot2), + pilot3, ATH9K_EVM_TO_PCT(pilot3), + pilot4, ATH9K_EVM_TO_PCT(pilot4)); + } + } + } + } + if (len > size) len = size; @@ -778,6 +824,12 @@ RX_PHY_ERR_INC(phyerr); } + if (rs->rs_rate & 0x80) { // HT rate + sc->debug.stats.rxstats.evm_stats[rs->rs_rate - 0x80][0] = rs->evm0; + sc->debug.stats.rxstats.evm_stats[rs->rs_rate - 0x80][1] = rs->evm1; + sc->debug.stats.rxstats.evm_stats[rs->rs_rate - 0x80][2] = rs->evm2; + } + #undef RX_STAT_INC #undef RX_PHY_ERR_INC } Index: compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/debug.h =================================================================== --- compat-wireless-2011-01-07.orig/drivers/net/wireless/ath/ath9k/debug.h 2011-01-09 01:52:28.572097198 -0500 +++ compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/debug.h 2011-01-09 01:52:35.552097198 -0500 @@ -149,6 +149,7 @@ u32 post_delim_crc_err; u32 decrypt_busy_err; u32 phy_err_stats[ATH9K_PHYERR_MAX]; + u32 evm_stats[24][3]; }; struct ath_stats { Index: compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/mac.h =================================================================== --- compat-wireless-2011-01-07.orig/drivers/net/wireless/ath/ath9k/mac.h 2011-01-09 01:52:28.584097198 -0500 +++ compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/mac.h 2011-01-09 01:52:35.556097198 -0500 @@ -542,9 +542,9 @@ #define AR_RxRSSICombined 0xff000000 #define AR_RxRSSICombined_S 24 -#define AR_RxEVM0 ds_rxstatus4 -#define AR_RxEVM1 ds_rxstatus5 -#define AR_RxEVM2 ds_rxstatus6 +#define AR_RxEVM0 ds_rxstatus5 +#define AR_RxEVM1 ds_rxstatus6 +#define AR_RxEVM2 ds_rxstatus7 #define AR_RxDone 0x00000001 #define AR_RxFrameOK 0x00000002 Index: compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/hw.c =================================================================== --- compat-wireless-2011-01-07.orig/drivers/net/wireless/ath/ath9k/hw.c 2011-01-07 15:03:59.000000000 -0500 +++ compat-wireless-2011-01-07/drivers/net/wireless/ath/ath9k/hw.c 2011-01-09 01:52:35.580097198 -0500 @@ -1815,6 +1815,7 @@ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; + ah->misc_mode |= AR_PCU_SEL_EVM; /* enable key search for every frame in an aggregate */ if (AR_SREV_9300_20_OR_LATER(ah)) _______________________________________________ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel