diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-4965.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 250 |
1 files changed, 217 insertions, 33 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a9c30bcb65b8..8b9c419e094e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -122,6 +122,35 @@ static u8 is_single_stream(struct iwl4965_priv *priv) return 0; } +int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) +{ + int idx = 0; + + /* 4965 HT rate format */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + + if (idx >= IWL_RATE_MIMO_6M_PLCP) + idx = idx - IWL_RATE_MIMO_6M_PLCP; + + idx += IWL_FIRST_OFDM_RATE; + /* skip 9M not supported in ht*/ + if (idx >= IWL_RATE_9M_INDEX) + idx += 1; + if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) + return idx; + + /* 4965 legacy rate format, search for match in table */ + } else { + for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) + if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx; + } + + return -1; +} + + /* * Determine how many receiver/antenna chains to use. * More provides better reception via diversity. Fewer saves power. @@ -3523,6 +3552,160 @@ static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *ad } } } +#ifdef CONFIG_IWL4965_DEBUG + +/** + * iwl4965_dbg_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. + * + * TODO: This was originally written for 3945, need to audit for + * proper operation with 4965. + */ +static void iwl4965_dbg_report_frame(struct iwl4965_priv *priv, + struct iwl4965_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; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + if (likely(!(iwl4965_debug_level & IWL_DL_RX))) + return; + + /* 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); + rate_sym = rx_hdr->rate; + 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; + int rate_idx; + u32 bitrate; + + 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_idx = iwl4965_hwrate_to_plcp_idx(rate_sym); + if (unlikely(rate_idx == -1)) + bitrate = 0; + else + bitrate = iwl4965_rates[rate_idx].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, bitrate); + 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) + iwl4965_print_hex_dump(IWL_DL_RX, data, length); +} +#else +static inline void iwl4965_dbg_report_frame(struct iwl4965_priv *priv, + struct iwl4965_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) +{ +} +#endif + #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) @@ -3531,6 +3714,8 @@ static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *ad static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; /* Use phy data (Rx signal strength, etc.) contained within * this rx packet for legacy frames, @@ -3541,27 +3726,29 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; __le32 *rx_end; unsigned int len = 0; - struct ieee80211_hdr *header; u16 fc; - struct ieee80211_rx_status stats = { - .mactime = le64_to_cpu(rx_start->timestamp), - .freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)), - .band = - (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, - .antenna = 0, - .rate_idx = iwl4965_rate_index_from_plcp( - le32_to_cpu(rx_start->rate_n_flags)), - .flag = 0, - }; u8 network_packet; + rx_status.mactime = le64_to_cpu(rx_start->timestamp); + rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)); + rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.rate_idx = iwl4965_hwrate_to_plcp_idx( + le32_to_cpu(rx_start->rate_n_flags)); + + if (rx_status.band == IEEE80211_BAND_5GHZ) + rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; + + rx_status.antenna = 0; + rx_status.flag = 0; + if ((unlikely(rx_start->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP ("dsp size out of range [0,20]: " "%d/n", rx_start->cfg_phy_cnt); return; } + if (!include_phy) { if (priv->last_phy_res[0]) rx_start = (struct iwl4965_rx_phy_res *) @@ -3580,7 +3767,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, + rx_start->cfg_phy_cnt); len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt + + rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + sizeof(struct iwl4965_rx_phy_res) + len); } else { struct iwl4965_rx_mpdu_res_start *amsdu = @@ -3603,7 +3790,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - stats.ssi = iwl4965_calc_rssi(rx_start); + rx_status.ssi = iwl4965_calc_rssi(rx_start); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -3611,32 +3798,29 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, * Ignore these noise values while scanning (other channels) */ if (iwl4965_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { - stats.noise = priv->last_rx_noise; - stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise); + rx_status.noise = priv->last_rx_noise; + rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, + rx_status.noise); } else { - stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0); + rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); } /* Reset beacon noise level if not associated. */ if (!iwl4965_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; -#ifdef CONFIG_IWL4965_DEBUG - /* TODO: Parts of iwl4965_report_frame are broken for 4965 */ - if (iwl4965_debug_level & (IWL_DL_RX)) - /* Set "1" to report good data frames in groups of 100 */ - iwl4965_report_frame(priv, pkt, header, 1); - - if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS)) - IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", - stats.ssi, stats.noise, stats.signal, - (long unsigned int)le64_to_cpu(rx_start->timestamp)); -#endif + /* Set "1" to report good data frames in groups of 100 */ + /* FIXME: need to optimze the call: */ + iwl4965_dbg_report_frame(priv, pkt, header, 1); + + IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", + rx_status.ssi, rx_status.noise, rx_status.signal, + rx_status.mactime); network_packet = iwl4965_is_network_packet(priv, header); if (network_packet) { - priv->last_rx_rssi = stats.ssi; + priv->last_rx_rssi = rx_status.ssi; priv->last_beacon_time = priv->ucode_beacon_time; priv->last_tsf = le64_to_cpu(rx_start->timestamp); } @@ -3739,7 +3923,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, return; } } - iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats); + iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); break; case IEEE80211_FTYPE_CTL: @@ -3748,7 +3932,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, case IEEE80211_STYPE_BACK_REQ: IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); iwl4965_handle_data_packet(priv, 0, include_phy, - rxb, &stats); + rxb, &rx_status); break; default: break; @@ -3778,7 +3962,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, print_mac(mac3, header->addr3)); else iwl4965_handle_data_packet(priv, 1, include_phy, rxb, - &stats); + &rx_status); break; } default: |