diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-3945.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 231 |
1 files changed, 196 insertions, 35 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 82d282730b7..63e832cdba7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -183,6 +183,16 @@ void iwl3945_disable_events(struct iwl3945_priv *priv) } +static int iwl3945_hwrate_to_plcp_idx(u8 plcp) +{ + int idx; + + for (idx = 0; idx < IWL_RATE_COUNT; idx++) + if (iwl3945_rates[idx].plcp == plcp) + return idx; + return -1; +} + /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -238,6 +248,156 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b priv->last_statistics_time = jiffies; } +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ +#ifdef CONFIG_IWL3945_DEBUG + +/** + * iwl3945_report_frame - dump frame to syslog during debug sessions + * + * You may hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + */ +static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + u32 rate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); + if (rate == -1) + rate = 0; + else + rate = iwl3945_rates[rate].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, rate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl3945_print_hex_dump(IWL_DL_RX, data, length); +} +#else +static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ +} +#endif + + static void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb, struct iwl3945_rx_frame_hdr *rx_hdr, @@ -376,24 +536,28 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) { + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); - struct ieee80211_hdr *header; + int snr; u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); - struct ieee80211_rx_status stats = { - .mactime = le64_to_cpu(rx_end->timestamp), - .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)), - .band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, - .antenna = 0, - .rate_idx = iwl3945_rate_index_from_plcp(rx_hdr->rate), - .flag = 0, - }; u8 network_packet; - int snr; + + rx_status.antenna = 0; + rx_status.flag = 0; + rx_status.mactime = le64_to_cpu(rx_end->timestamp); + rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)); + rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + + rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); + + if (rx_status.band == IEEE80211_BAND_5GHZ) + rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; if ((unlikely(rx_stats->phy_count > 20))) { IWL_DEBUG_DROP @@ -409,12 +573,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_handle_data_packet(priv, 1, rxb, &stats); + iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); return; } /* Convert 3945's rssi indicator to dBm */ - stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; /* Set default noise value to -127 */ if (priv->last_rx_noise == 0) @@ -430,50 +594,47 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, * signal-to-noise ratio (SNR) is (sig_avg / noise_diff). * Convert linear SNR to dB SNR, then subtract that from rssi dBm * to obtain noise level in dBm. - * Calculate stats.signal (quality indicator in %) based on SNR. */ + * Calculate rx_status.signal (quality indicator in %) based on SNR. */ if (rx_stats_noise_diff) { snr = rx_stats_sig_avg / rx_stats_noise_diff; - stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr); - stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise); + rx_status.noise = rx_status.ssi - + iwl3945_calc_db_from_ratio(snr); + rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, + rx_status.noise); /* If noise info not available, calculate signal quality indicator (%) * using just the dBm signal level. */ } else { - stats.noise = priv->last_rx_noise; - stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0); + rx_status.noise = priv->last_rx_noise; + rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0); } IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", - stats.ssi, stats.noise, stats.signal, + rx_status.ssi, rx_status.noise, rx_status.signal, rx_stats_sig_avg, rx_stats_noise_diff); - /* can be covered by iwl3945_report_frame() in most cases */ -/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ - header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); network_packet = iwl3945_is_network_packet(priv, header); -#ifdef CONFIG_IWL3945_DEBUG - if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit()) - IWL_DEBUG_STATS - ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", - network_packet ? '*' : ' ', - le16_to_cpu(rx_hdr->channel), - stats.ssi, stats.ssi, - stats.ssi, stats.rate_idx); + IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", + network_packet ? '*' : ' ', + le16_to_cpu(rx_hdr->channel), + rx_status.ssi, rx_status.ssi, + rx_status.ssi, rx_status.rate_idx); +#ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_RX)) /* Set "1" to report good data frames in groups of 100 */ - iwl3945_report_frame(priv, pkt, header, 1); + iwl3945_dbg_report_frame(priv, pkt, header, 1); #endif if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); priv->last_tsf = le64_to_cpu(rx_end->timestamp); - priv->last_rx_rssi = stats.ssi; - priv->last_rx_noise = stats.noise; + priv->last_rx_rssi = rx_status.ssi; + priv->last_rx_noise = rx_status.noise; } switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { @@ -560,7 +721,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, } } - iwl3945_handle_data_packet(priv, 0, rxb, &stats); + iwl3945_handle_data_packet(priv, 0, rxb, &rx_status); break; case IEEE80211_FTYPE_CTL: @@ -577,7 +738,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, print_mac(mac2, header->addr2), print_mac(mac3, header->addr3)); else - iwl3945_handle_data_packet(priv, 1, rxb, &stats); + iwl3945_handle_data_packet(priv, 1, rxb, &rx_status); break; } } |