iwlwifi: implement iwl5000_calc_rssi

This patch implements rssi calculation for 5000 HW.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by Tomas Winkler and committed by John W. Linville caab8f1a da99c4b6

+119 -51
+35
drivers/net/wireless/iwlwifi/iwl-4965.c
··· 2258 2258 IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); 2259 2259 } 2260 2260 2261 + static int iwl4965_calc_rssi(struct iwl_priv *priv, 2262 + struct iwl_rx_phy_res *rx_resp) 2263 + { 2264 + /* data from PHY/DSP regarding signal strength, etc., 2265 + * contents are always there, not configurable by host. */ 2266 + struct iwl4965_rx_non_cfg_phy *ncphy = 2267 + (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy_buf; 2268 + u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL49_AGC_DB_MASK) 2269 + >> IWL49_AGC_DB_POS; 2270 + 2271 + u32 valid_antennae = 2272 + (le16_to_cpu(rx_resp->phy_flags) & IWL49_RX_PHY_FLAGS_ANTENNAE_MASK) 2273 + >> IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET; 2274 + u8 max_rssi = 0; 2275 + u32 i; 2276 + 2277 + /* Find max rssi among 3 possible receivers. 2278 + * These values are measured by the digital signal processor (DSP). 2279 + * They should stay fairly constant even as the signal strength varies, 2280 + * if the radio's automatic gain control (AGC) is working right. 2281 + * AGC value (see below) will provide the "interesting" info. */ 2282 + for (i = 0; i < 3; i++) 2283 + if (valid_antennae & (1 << i)) 2284 + max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); 2285 + 2286 + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", 2287 + ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], 2288 + max_rssi, agc); 2289 + 2290 + /* dBm = max_rssi dB - agc dB - constant. 2291 + * Higher AGC (higher radio gain) means lower signal. */ 2292 + return max_rssi - agc - IWL_RSSI_OFFSET; 2293 + } 2294 + 2261 2295 2262 2296 /* Set up 4965-specific Rx frame reply handlers */ 2263 2297 static void iwl4965_rx_handler_setup(struct iwl_priv *priv) ··· 2323 2289 .chain_noise_reset = iwl4965_chain_noise_reset, 2324 2290 .gain_computation = iwl4965_gain_computation, 2325 2291 .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, 2292 + .calc_rssi = iwl4965_calc_rssi, 2326 2293 }; 2327 2294 2328 2295 static struct iwl_lib_ops iwl4965_lib = {
+39
drivers/net/wireless/iwlwifi/iwl-5000.c
··· 1459 1459 priv->temperature = le32_to_cpu(priv->statistics.general.temperature); 1460 1460 } 1461 1461 1462 + /* Calc max signal level (dBm) among 3 possible receivers */ 1463 + static int iwl5000_calc_rssi(struct iwl_priv *priv, 1464 + struct iwl_rx_phy_res *rx_resp) 1465 + { 1466 + /* data from PHY/DSP regarding signal strength, etc., 1467 + * contents are always there, not configurable by host 1468 + */ 1469 + struct iwl5000_non_cfg_phy *ncphy = 1470 + (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf; 1471 + u32 val, rssi_a, rssi_b, rssi_c, max_rssi; 1472 + u8 agc; 1473 + 1474 + val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]); 1475 + agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS; 1476 + 1477 + /* Find max rssi among 3 possible receivers. 1478 + * These values are measured by the digital signal processor (DSP). 1479 + * They should stay fairly constant even as the signal strength varies, 1480 + * if the radio's automatic gain control (AGC) is working right. 1481 + * AGC value (see below) will provide the "interesting" info. 1482 + */ 1483 + val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]); 1484 + rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS; 1485 + rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS; 1486 + val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]); 1487 + rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS; 1488 + 1489 + max_rssi = max_t(u32, rssi_a, rssi_b); 1490 + max_rssi = max_t(u32, max_rssi, rssi_c); 1491 + 1492 + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", 1493 + rssi_a, rssi_b, rssi_c, max_rssi, agc); 1494 + 1495 + /* dBm = max_rssi dB - agc dB - constant. 1496 + * Higher AGC (higher radio gain) means lower signal. */ 1497 + return max_rssi - agc - IWL_RSSI_OFFSET; 1498 + } 1499 + 1462 1500 static struct iwl_hcmd_ops iwl5000_hcmd = { 1463 1501 .rxon_assoc = iwl5000_send_rxon_assoc, 1464 1502 }; ··· 1507 1469 .gain_computation = iwl5000_gain_computation, 1508 1470 .chain_noise_reset = iwl5000_chain_noise_reset, 1509 1471 .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, 1472 + .calc_rssi = iwl5000_calc_rssi, 1510 1473 }; 1511 1474 1512 1475 static struct iwl_lib_ops iwl5000_lib = {
+27 -8
drivers/net/wireless/iwlwifi/iwl-commands.h
··· 1075 1075 } __attribute__ ((packed)); 1076 1076 1077 1077 /* Fixed (non-configurable) rx data from phy */ 1078 - #define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) 1079 - #define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) 1080 - #define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ 1081 - #define IWL_AGC_DB_POS (7) 1078 + 1079 + #define IWL49_RX_RES_PHY_CNT 14 1080 + #define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) 1081 + #define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) 1082 + #define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ 1083 + #define IWL49_AGC_DB_POS (7) 1082 1084 struct iwl4965_rx_non_cfg_phy { 1083 1085 __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ 1084 1086 __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ ··· 1088 1086 u8 pad[0]; 1089 1087 } __attribute__ ((packed)); 1090 1088 1089 + 1090 + #define IWL50_RX_RES_PHY_CNT 8 1091 + #define IWL50_RX_RES_AGC_IDX 1 1092 + #define IWL50_RX_RES_RSSI_AB_IDX 2 1093 + #define IWL50_RX_RES_RSSI_C_IDX 3 1094 + #define IWL50_OFDM_AGC_MSK 0xfe00 1095 + #define IWL50_OFDM_AGC_BIT_POS 9 1096 + #define IWL50_OFDM_RSSI_A_MSK 0x00ff 1097 + #define IWL50_OFDM_RSSI_A_BIT_POS 0 1098 + #define IWL50_OFDM_RSSI_B_MSK 0xff0000 1099 + #define IWL50_OFDM_RSSI_B_BIT_POS 16 1100 + #define IWL50_OFDM_RSSI_C_MSK 0x00ff 1101 + #define IWL50_OFDM_RSSI_C_BIT_POS 0 1102 + 1103 + struct iwl5000_non_cfg_phy { 1104 + __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */ 1105 + } __attribute__ ((packed)); 1106 + 1107 + 1091 1108 /* 1092 1109 * REPLY_RX = 0xc3 (response only, not a command) 1093 1110 * Used only for legacy (non 11n) frames. 1094 1111 */ 1095 - #define RX_RES_PHY_CNT 14 1096 - struct iwl4965_rx_phy_res { 1112 + struct iwl_rx_phy_res { 1097 1113 u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ 1098 1114 u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ 1099 1115 u8 stat_id; /* configurable DSP phy data set ID */ ··· 1120 1100 __le32 beacon_time_stamp; /* beacon at on-air rise */ 1121 1101 __le16 phy_flags; /* general phy flags: band, modulation, ... */ 1122 1102 __le16 channel; /* channel number */ 1123 - __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ 1124 - __le32 reserved2; 1103 + u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */ 1125 1104 __le32 rate_n_flags; /* RATE_MCS_* */ 1126 1105 __le16 byte_count; /* frame's byte-count */ 1127 1106 __le16 reserved3;
+2
drivers/net/wireless/iwlwifi/iwl-core.h
··· 95 95 void (*chain_noise_reset)(struct iwl_priv *priv); 96 96 void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info, 97 97 __le32 *tx_flags); 98 + int (*calc_rssi)(struct iwl_priv *priv, 99 + struct iwl_rx_phy_res *rx_resp); 98 100 }; 99 101 100 102 struct iwl_lib_ops {
+16 -43
drivers/net/wireless/iwlwifi/iwl-rx.c
··· 791 791 792 792 static void iwl_add_radiotap(struct iwl_priv *priv, 793 793 struct sk_buff *skb, 794 - struct iwl4965_rx_phy_res *rx_start, 794 + struct iwl_rx_phy_res *rx_start, 795 795 struct ieee80211_rx_status *stats, 796 796 u32 ampdu_status) 797 797 { ··· 1010 1010 struct ieee80211_rx_status *stats) 1011 1011 { 1012 1012 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 1013 - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? 1014 - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; 1013 + struct iwl_rx_phy_res *rx_start = (include_phy) ? 1014 + (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; 1015 1015 struct ieee80211_hdr *hdr; 1016 1016 u16 len; 1017 1017 __le32 *rx_end; ··· 1020 1020 u32 ampdu_status_legacy; 1021 1021 1022 1022 if (!include_phy && priv->last_phy_res[0]) 1023 - rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; 1023 + rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; 1024 1024 1025 1025 if (!rx_start) { 1026 1026 IWL_ERROR("MPDU frame without a PHY data\n"); ··· 1032 1032 1033 1033 len = le16_to_cpu(rx_start->byte_count); 1034 1034 1035 - rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + 1036 - sizeof(struct iwl4965_rx_phy_res) + 1035 + rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + 1036 + sizeof(struct iwl_rx_phy_res) + 1037 1037 rx_start->cfg_phy_cnt + len); 1038 1038 1039 1039 } else { ··· 1084 1084 } 1085 1085 1086 1086 /* Calc max signal level (dBm) among 3 possible receivers */ 1087 - static int iwl_calc_rssi(struct iwl_priv *priv, 1088 - struct iwl4965_rx_phy_res *rx_resp) 1087 + static inline int iwl_calc_rssi(struct iwl_priv *priv, 1088 + struct iwl_rx_phy_res *rx_resp) 1089 1089 { 1090 - /* data from PHY/DSP regarding signal strength, etc., 1091 - * contents are always there, not configurable by host. */ 1092 - struct iwl4965_rx_non_cfg_phy *ncphy = 1093 - (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; 1094 - u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) 1095 - >> IWL_AGC_DB_POS; 1096 - 1097 - u32 valid_antennae = 1098 - (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) 1099 - >> RX_PHY_FLAGS_ANTENNAE_OFFSET; 1100 - u8 max_rssi = 0; 1101 - u32 i; 1102 - 1103 - /* Find max rssi among 3 possible receivers. 1104 - * These values are measured by the digital signal processor (DSP). 1105 - * They should stay fairly constant even as the signal strength varies, 1106 - * if the radio's automatic gain control (AGC) is working right. 1107 - * AGC value (see below) will provide the "interesting" info. */ 1108 - for (i = 0; i < 3; i++) 1109 - if (valid_antennae & (1 << i)) 1110 - max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); 1111 - 1112 - IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", 1113 - ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], 1114 - max_rssi, agc); 1115 - 1116 - /* dBm = max_rssi dB - agc dB - constant. 1117 - * Higher AGC (higher radio gain) means lower signal. */ 1118 - return max_rssi - agc - IWL_RSSI_OFFSET; 1090 + return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); 1119 1091 } 1092 + 1120 1093 1121 1094 static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) 1122 1095 { ··· 1153 1180 * this rx packet for legacy frames, 1154 1181 * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ 1155 1182 int include_phy = (pkt->hdr.cmd == REPLY_RX); 1156 - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? 1157 - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : 1158 - (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; 1183 + struct iwl_rx_phy_res *rx_start = (include_phy) ? 1184 + (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : 1185 + (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; 1159 1186 __le32 *rx_end; 1160 1187 unsigned int len = 0; 1161 1188 u16 fc; ··· 1183 1210 1184 1211 if (!include_phy) { 1185 1212 if (priv->last_phy_res[0]) 1186 - rx_start = (struct iwl4965_rx_phy_res *) 1213 + rx_start = (struct iwl_rx_phy_res *) 1187 1214 &priv->last_phy_res[1]; 1188 1215 else 1189 1216 rx_start = NULL; ··· 1200 1227 1201 1228 len = le16_to_cpu(rx_start->byte_count); 1202 1229 rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + 1203 - sizeof(struct iwl4965_rx_phy_res) + len); 1230 + sizeof(struct iwl_rx_phy_res) + len); 1204 1231 } else { 1205 1232 struct iwl4965_rx_mpdu_res_start *amsdu = 1206 1233 (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; ··· 1289 1316 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 1290 1317 priv->last_phy_res[0] = 1; 1291 1318 memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), 1292 - sizeof(struct iwl4965_rx_phy_res)); 1319 + sizeof(struct iwl_rx_phy_res)); 1293 1320 } 1294 1321 EXPORT_SYMBOL(iwl_rx_reply_rx_phy);