aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-08-04 04:00:42 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-04 15:09:12 -0400
commitcaab8f1a5d0da583b6ffe41afea2774c676444ca (patch)
treea732088119050a566e00d44d05976d9a4363379d /drivers/net/wireless
parentda99c4b6c25964b90c79f19beccda208df1a865a (diff)
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>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c59
5 files changed, 119 insertions, 51 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 718f9d9e4947..22bb26985c2e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2258,6 +2258,40 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
2258 IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); 2258 IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
2259} 2259}
2260 2260
2261static 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/* Set up 4965-specific Rx frame reply handlers */ 2296/* Set up 4965-specific Rx frame reply handlers */
2263static void iwl4965_rx_handler_setup(struct iwl_priv *priv) 2297static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
@@ -2289,6 +2323,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
2289 .chain_noise_reset = iwl4965_chain_noise_reset, 2323 .chain_noise_reset = iwl4965_chain_noise_reset,
2290 .gain_computation = iwl4965_gain_computation, 2324 .gain_computation = iwl4965_gain_computation,
2291 .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, 2325 .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
2326 .calc_rssi = iwl4965_calc_rssi,
2292}; 2327};
2293 2328
2294static struct iwl_lib_ops iwl4965_lib = { 2329static struct iwl_lib_ops iwl4965_lib = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 56dbc8144a34..c5b104fd149c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1459,6 +1459,44 @@ static void iwl5000_temperature(struct iwl_priv *priv)
1459 priv->temperature = le32_to_cpu(priv->statistics.general.temperature); 1459 priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
1460} 1460}
1461 1461
1462/* Calc max signal level (dBm) among 3 possible receivers */
1463static 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
1462static struct iwl_hcmd_ops iwl5000_hcmd = { 1500static struct iwl_hcmd_ops iwl5000_hcmd = {
1463 .rxon_assoc = iwl5000_send_rxon_assoc, 1501 .rxon_assoc = iwl5000_send_rxon_assoc,
1464}; 1502};
@@ -1469,6 +1507,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
1469 .gain_computation = iwl5000_gain_computation, 1507 .gain_computation = iwl5000_gain_computation,
1470 .chain_noise_reset = iwl5000_chain_noise_reset, 1508 .chain_noise_reset = iwl5000_chain_noise_reset,
1471 .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, 1509 .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
1510 .calc_rssi = iwl5000_calc_rssi,
1472}; 1511};
1473 1512
1474static struct iwl_lib_ops iwl5000_lib = { 1513static struct iwl_lib_ops iwl5000_lib = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 5e57f3ae2ea6..28b5b09996ed 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1075,10 +1075,12 @@ struct iwl4965_rx_frame {
1075} __attribute__ ((packed)); 1075} __attribute__ ((packed));
1076 1076
1077/* Fixed (non-configurable) rx data from phy */ 1077/* Fixed (non-configurable) rx data from phy */
1078#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) 1078
1079#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) 1079#define IWL49_RX_RES_PHY_CNT 14
1080#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ 1080#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4)
1081#define IWL_AGC_DB_POS (7) 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)
1082struct iwl4965_rx_non_cfg_phy { 1084struct iwl4965_rx_non_cfg_phy {
1083 __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ 1085 __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */
1084 __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ 1086 __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */
@@ -1086,12 +1088,30 @@ struct iwl4965_rx_non_cfg_phy {
1086 u8 pad[0]; 1088 u8 pad[0];
1087} __attribute__ ((packed)); 1089} __attribute__ ((packed));
1088 1090
1091
1092#define IWL50_RX_RES_PHY_CNT 8
1093#define IWL50_RX_RES_AGC_IDX 1
1094#define IWL50_RX_RES_RSSI_AB_IDX 2
1095#define IWL50_RX_RES_RSSI_C_IDX 3
1096#define IWL50_OFDM_AGC_MSK 0xfe00
1097#define IWL50_OFDM_AGC_BIT_POS 9
1098#define IWL50_OFDM_RSSI_A_MSK 0x00ff
1099#define IWL50_OFDM_RSSI_A_BIT_POS 0
1100#define IWL50_OFDM_RSSI_B_MSK 0xff0000
1101#define IWL50_OFDM_RSSI_B_BIT_POS 16
1102#define IWL50_OFDM_RSSI_C_MSK 0x00ff
1103#define IWL50_OFDM_RSSI_C_BIT_POS 0
1104
1105struct iwl5000_non_cfg_phy {
1106 __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */
1107} __attribute__ ((packed));
1108
1109
1089/* 1110/*
1090 * REPLY_RX = 0xc3 (response only, not a command) 1111 * REPLY_RX = 0xc3 (response only, not a command)
1091 * Used only for legacy (non 11n) frames. 1112 * Used only for legacy (non 11n) frames.
1092 */ 1113 */
1093#define RX_RES_PHY_CNT 14 1114struct iwl_rx_phy_res {
1094struct iwl4965_rx_phy_res {
1095 u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ 1115 u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */
1096 u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ 1116 u8 cfg_phy_cnt; /* configurable DSP phy data byte count */
1097 u8 stat_id; /* configurable DSP phy data set ID */ 1117 u8 stat_id; /* configurable DSP phy data set ID */
@@ -1100,8 +1120,7 @@ struct iwl4965_rx_phy_res {
1100 __le32 beacon_time_stamp; /* beacon at on-air rise */ 1120 __le32 beacon_time_stamp; /* beacon at on-air rise */
1101 __le16 phy_flags; /* general phy flags: band, modulation, ... */ 1121 __le16 phy_flags; /* general phy flags: band, modulation, ... */
1102 __le16 channel; /* channel number */ 1122 __le16 channel; /* channel number */
1103 __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ 1123 u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
1104 __le32 reserved2;
1105 __le32 rate_n_flags; /* RATE_MCS_* */ 1124 __le32 rate_n_flags; /* RATE_MCS_* */
1106 __le16 byte_count; /* frame's byte-count */ 1125 __le16 byte_count; /* frame's byte-count */
1107 __le16 reserved3; 1126 __le16 reserved3;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index eaefa42f37c5..64f139e97444 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -95,6 +95,8 @@ struct iwl_hcmd_utils_ops {
95 void (*chain_noise_reset)(struct iwl_priv *priv); 95 void (*chain_noise_reset)(struct iwl_priv *priv);
96 void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info, 96 void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
97 __le32 *tx_flags); 97 __le32 *tx_flags);
98 int (*calc_rssi)(struct iwl_priv *priv,
99 struct iwl_rx_phy_res *rx_resp);
98}; 100};
99 101
100struct iwl_lib_ops { 102struct iwl_lib_ops {
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index e2d9afba38a5..f3f6ea49fdd2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -791,7 +791,7 @@ static inline void iwl_dbg_report_frame(struct iwl_priv *priv,
791 791
792static void iwl_add_radiotap(struct iwl_priv *priv, 792static void iwl_add_radiotap(struct iwl_priv *priv,
793 struct sk_buff *skb, 793 struct sk_buff *skb,
794 struct iwl4965_rx_phy_res *rx_start, 794 struct iwl_rx_phy_res *rx_start,
795 struct ieee80211_rx_status *stats, 795 struct ieee80211_rx_status *stats,
796 u32 ampdu_status) 796 u32 ampdu_status)
797{ 797{
@@ -1010,8 +1010,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
1010 struct ieee80211_rx_status *stats) 1010 struct ieee80211_rx_status *stats)
1011{ 1011{
1012 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 1012 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
1013 struct iwl4965_rx_phy_res *rx_start = (include_phy) ? 1013 struct iwl_rx_phy_res *rx_start = (include_phy) ?
1014 (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; 1014 (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
1015 struct ieee80211_hdr *hdr; 1015 struct ieee80211_hdr *hdr;
1016 u16 len; 1016 u16 len;
1017 __le32 *rx_end; 1017 __le32 *rx_end;
@@ -1020,7 +1020,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
1020 u32 ampdu_status_legacy; 1020 u32 ampdu_status_legacy;
1021 1021
1022 if (!include_phy && priv->last_phy_res[0]) 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 if (!rx_start) { 1025 if (!rx_start) {
1026 IWL_ERROR("MPDU frame without a PHY data\n"); 1026 IWL_ERROR("MPDU frame without a PHY data\n");
@@ -1032,8 +1032,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
1032 1032
1033 len = le16_to_cpu(rx_start->byte_count); 1033 len = le16_to_cpu(rx_start->byte_count);
1034 1034
1035 rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + 1035 rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] +
1036 sizeof(struct iwl4965_rx_phy_res) + 1036 sizeof(struct iwl_rx_phy_res) +
1037 rx_start->cfg_phy_cnt + len); 1037 rx_start->cfg_phy_cnt + len);
1038 1038
1039 } else { 1039 } else {
@@ -1084,40 +1084,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
1084} 1084}
1085 1085
1086/* Calc max signal level (dBm) among 3 possible receivers */ 1086/* Calc max signal level (dBm) among 3 possible receivers */
1087static int iwl_calc_rssi(struct iwl_priv *priv, 1087static inline int iwl_calc_rssi(struct iwl_priv *priv,
1088 struct iwl4965_rx_phy_res *rx_resp) 1088 struct iwl_rx_phy_res *rx_resp)
1089{ 1089{
1090 /* data from PHY/DSP regarding signal strength, etc., 1090 return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
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;
1119} 1091}
1120 1092
1093
1121static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) 1094static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
1122{ 1095{
1123 unsigned long flags; 1096 unsigned long flags;
@@ -1180,9 +1153,9 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
1180 * this rx packet for legacy frames, 1153 * this rx packet for legacy frames,
1181 * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ 1154 * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
1182 int include_phy = (pkt->hdr.cmd == REPLY_RX); 1155 int include_phy = (pkt->hdr.cmd == REPLY_RX);
1183 struct iwl4965_rx_phy_res *rx_start = (include_phy) ? 1156 struct iwl_rx_phy_res *rx_start = (include_phy) ?
1184 (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : 1157 (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) :
1185 (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; 1158 (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
1186 __le32 *rx_end; 1159 __le32 *rx_end;
1187 unsigned int len = 0; 1160 unsigned int len = 0;
1188 u16 fc; 1161 u16 fc;
@@ -1210,7 +1183,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
1210 1183
1211 if (!include_phy) { 1184 if (!include_phy) {
1212 if (priv->last_phy_res[0]) 1185 if (priv->last_phy_res[0])
1213 rx_start = (struct iwl4965_rx_phy_res *) 1186 rx_start = (struct iwl_rx_phy_res *)
1214 &priv->last_phy_res[1]; 1187 &priv->last_phy_res[1];
1215 else 1188 else
1216 rx_start = NULL; 1189 rx_start = NULL;
@@ -1227,7 +1200,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
1227 1200
1228 len = le16_to_cpu(rx_start->byte_count); 1201 len = le16_to_cpu(rx_start->byte_count);
1229 rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + 1202 rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt +
1230 sizeof(struct iwl4965_rx_phy_res) + len); 1203 sizeof(struct iwl_rx_phy_res) + len);
1231 } else { 1204 } else {
1232 struct iwl4965_rx_mpdu_res_start *amsdu = 1205 struct iwl4965_rx_mpdu_res_start *amsdu =
1233 (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; 1206 (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
@@ -1316,6 +1289,6 @@ void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
1316 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 1289 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
1317 priv->last_phy_res[0] = 1; 1290 priv->last_phy_res[0] = 1;
1318 memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), 1291 memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
1319 sizeof(struct iwl4965_rx_phy_res)); 1292 sizeof(struct iwl_rx_phy_res));
1320} 1293}
1321EXPORT_SYMBOL(iwl_rx_reply_rx_phy); 1294EXPORT_SYMBOL(iwl_rx_reply_rx_phy);