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) | |||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags) | ||
126 | { | ||
127 | int idx = 0; | ||
128 | |||
129 | /* 4965 HT rate format */ | ||
130 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
131 | idx = (rate_n_flags & 0xff); | ||
132 | |||
133 | if (idx >= IWL_RATE_MIMO_6M_PLCP) | ||
134 | idx = idx - IWL_RATE_MIMO_6M_PLCP; | ||
135 | |||
136 | idx += IWL_FIRST_OFDM_RATE; | ||
137 | /* skip 9M not supported in ht*/ | ||
138 | if (idx >= IWL_RATE_9M_INDEX) | ||
139 | idx += 1; | ||
140 | if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) | ||
141 | return idx; | ||
142 | |||
143 | /* 4965 legacy rate format, search for match in table */ | ||
144 | } else { | ||
145 | for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++) | ||
146 | if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF)) | ||
147 | return idx; | ||
148 | } | ||
149 | |||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | |||
125 | /* | 154 | /* |
126 | * Determine how many receiver/antenna chains to use. | 155 | * Determine how many receiver/antenna chains to use. |
127 | * More provides better reception via diversity. Fewer saves power. | 156 | * 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 | |||
3523 | } | 3552 | } |
3524 | } | 3553 | } |
3525 | } | 3554 | } |
3555 | #ifdef CONFIG_IWL4965_DEBUG | ||
3556 | |||
3557 | /** | ||
3558 | * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions | ||
3559 | * | ||
3560 | * You may hack this function to show different aspects of received frames, | ||
3561 | * including selective frame dumps. | ||
3562 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
3563 | * | ||
3564 | * TODO: This was originally written for 3945, need to audit for | ||
3565 | * proper operation with 4965. | ||
3566 | */ | ||
3567 | static void iwl4965_dbg_report_frame(struct iwl4965_priv *priv, | ||
3568 | struct iwl4965_rx_packet *pkt, | ||
3569 | struct ieee80211_hdr *header, int group100) | ||
3570 | { | ||
3571 | u32 to_us; | ||
3572 | u32 print_summary = 0; | ||
3573 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
3574 | u32 hundred = 0; | ||
3575 | u32 dataframe = 0; | ||
3576 | u16 fc; | ||
3577 | u16 seq_ctl; | ||
3578 | u16 channel; | ||
3579 | u16 phy_flags; | ||
3580 | int rate_sym; | ||
3581 | u16 length; | ||
3582 | u16 status; | ||
3583 | u16 bcn_tmr; | ||
3584 | u32 tsf_low; | ||
3585 | u64 tsf; | ||
3586 | u8 rssi; | ||
3587 | u8 agc; | ||
3588 | u16 sig_avg; | ||
3589 | u16 noise_diff; | ||
3590 | struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
3591 | struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
3592 | struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
3593 | u8 *data = IWL_RX_DATA(pkt); | ||
3594 | |||
3595 | if (likely(!(iwl4965_debug_level & IWL_DL_RX))) | ||
3596 | return; | ||
3597 | |||
3598 | /* MAC header */ | ||
3599 | fc = le16_to_cpu(header->frame_control); | ||
3600 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
3601 | |||
3602 | /* metadata */ | ||
3603 | channel = le16_to_cpu(rx_hdr->channel); | ||
3604 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
3605 | rate_sym = rx_hdr->rate; | ||
3606 | length = le16_to_cpu(rx_hdr->len); | ||
3607 | |||
3608 | /* end-of-frame status and timestamp */ | ||
3609 | status = le32_to_cpu(rx_end->status); | ||
3610 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
3611 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
3612 | tsf = le64_to_cpu(rx_end->timestamp); | ||
3613 | |||
3614 | /* signal statistics */ | ||
3615 | rssi = rx_stats->rssi; | ||
3616 | agc = rx_stats->agc; | ||
3617 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
3618 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
3619 | |||
3620 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
3621 | |||
3622 | /* if data frame is to us and all is good, | ||
3623 | * (optionally) print summary for only 1 out of every 100 */ | ||
3624 | if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == | ||
3625 | (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
3626 | dataframe = 1; | ||
3627 | if (!group100) | ||
3628 | print_summary = 1; /* print each frame */ | ||
3629 | else if (priv->framecnt_to_us < 100) { | ||
3630 | priv->framecnt_to_us++; | ||
3631 | print_summary = 0; | ||
3632 | } else { | ||
3633 | priv->framecnt_to_us = 0; | ||
3634 | print_summary = 1; | ||
3635 | hundred = 1; | ||
3636 | } | ||
3637 | } else { | ||
3638 | /* print summary for all other frames */ | ||
3639 | print_summary = 1; | ||
3640 | } | ||
3641 | |||
3642 | if (print_summary) { | ||
3643 | char *title; | ||
3644 | int rate_idx; | ||
3645 | u32 bitrate; | ||
3646 | |||
3647 | if (hundred) | ||
3648 | title = "100Frames"; | ||
3649 | else if (fc & IEEE80211_FCTL_RETRY) | ||
3650 | title = "Retry"; | ||
3651 | else if (ieee80211_is_assoc_response(fc)) | ||
3652 | title = "AscRsp"; | ||
3653 | else if (ieee80211_is_reassoc_response(fc)) | ||
3654 | title = "RasRsp"; | ||
3655 | else if (ieee80211_is_probe_response(fc)) { | ||
3656 | title = "PrbRsp"; | ||
3657 | print_dump = 1; /* dump frame contents */ | ||
3658 | } else if (ieee80211_is_beacon(fc)) { | ||
3659 | title = "Beacon"; | ||
3660 | print_dump = 1; /* dump frame contents */ | ||
3661 | } else if (ieee80211_is_atim(fc)) | ||
3662 | title = "ATIM"; | ||
3663 | else if (ieee80211_is_auth(fc)) | ||
3664 | title = "Auth"; | ||
3665 | else if (ieee80211_is_deauth(fc)) | ||
3666 | title = "DeAuth"; | ||
3667 | else if (ieee80211_is_disassoc(fc)) | ||
3668 | title = "DisAssoc"; | ||
3669 | else | ||
3670 | title = "Frame"; | ||
3671 | |||
3672 | rate_idx = iwl4965_hwrate_to_plcp_idx(rate_sym); | ||
3673 | if (unlikely(rate_idx == -1)) | ||
3674 | bitrate = 0; | ||
3675 | else | ||
3676 | bitrate = iwl4965_rates[rate_idx].ieee / 2; | ||
3677 | |||
3678 | /* print frame summary. | ||
3679 | * MAC addresses show just the last byte (for brevity), | ||
3680 | * but you can hack it to show more, if you'd like to. */ | ||
3681 | if (dataframe) | ||
3682 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
3683 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
3684 | title, fc, header->addr1[5], | ||
3685 | length, rssi, channel, bitrate); | ||
3686 | else { | ||
3687 | /* src/dst addresses assume managed mode */ | ||
3688 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
3689 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
3690 | "phy=0x%02x, chnl=%d\n", | ||
3691 | title, fc, header->addr1[5], | ||
3692 | header->addr3[5], rssi, | ||
3693 | tsf_low - priv->scan_start_tsf, | ||
3694 | phy_flags, channel); | ||
3695 | } | ||
3696 | } | ||
3697 | if (print_dump) | ||
3698 | iwl4965_print_hex_dump(IWL_DL_RX, data, length); | ||
3699 | } | ||
3700 | #else | ||
3701 | static inline void iwl4965_dbg_report_frame(struct iwl4965_priv *priv, | ||
3702 | struct iwl4965_rx_packet *pkt, | ||
3703 | struct ieee80211_hdr *header, | ||
3704 | int group100) | ||
3705 | { | ||
3706 | } | ||
3707 | #endif | ||
3708 | |||
3526 | 3709 | ||
3527 | #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) | 3710 | #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) |
3528 | 3711 | ||
@@ -3531,6 +3714,8 @@ static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *ad | |||
3531 | static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | 3714 | static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, |
3532 | struct iwl4965_rx_mem_buffer *rxb) | 3715 | struct iwl4965_rx_mem_buffer *rxb) |
3533 | { | 3716 | { |
3717 | struct ieee80211_hdr *header; | ||
3718 | struct ieee80211_rx_status rx_status; | ||
3534 | struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; | 3719 | struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; |
3535 | /* Use phy data (Rx signal strength, etc.) contained within | 3720 | /* Use phy data (Rx signal strength, etc.) contained within |
3536 | * this rx packet for legacy frames, | 3721 | * this rx packet for legacy frames, |
@@ -3541,27 +3726,29 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3541 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | 3726 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; |
3542 | __le32 *rx_end; | 3727 | __le32 *rx_end; |
3543 | unsigned int len = 0; | 3728 | unsigned int len = 0; |
3544 | struct ieee80211_hdr *header; | ||
3545 | u16 fc; | 3729 | u16 fc; |
3546 | struct ieee80211_rx_status stats = { | ||
3547 | .mactime = le64_to_cpu(rx_start->timestamp), | ||
3548 | .freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)), | ||
3549 | .band = | ||
3550 | (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
3551 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, | ||
3552 | .antenna = 0, | ||
3553 | .rate_idx = iwl4965_rate_index_from_plcp( | ||
3554 | le32_to_cpu(rx_start->rate_n_flags)), | ||
3555 | .flag = 0, | ||
3556 | }; | ||
3557 | u8 network_packet; | 3730 | u8 network_packet; |
3558 | 3731 | ||
3732 | rx_status.mactime = le64_to_cpu(rx_start->timestamp); | ||
3733 | rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)); | ||
3734 | rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
3735 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
3736 | rx_status.rate_idx = iwl4965_hwrate_to_plcp_idx( | ||
3737 | le32_to_cpu(rx_start->rate_n_flags)); | ||
3738 | |||
3739 | if (rx_status.band == IEEE80211_BAND_5GHZ) | ||
3740 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | ||
3741 | |||
3742 | rx_status.antenna = 0; | ||
3743 | rx_status.flag = 0; | ||
3744 | |||
3559 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | 3745 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { |
3560 | IWL_DEBUG_DROP | 3746 | IWL_DEBUG_DROP |
3561 | ("dsp size out of range [0,20]: " | 3747 | ("dsp size out of range [0,20]: " |
3562 | "%d/n", rx_start->cfg_phy_cnt); | 3748 | "%d/n", rx_start->cfg_phy_cnt); |
3563 | return; | 3749 | return; |
3564 | } | 3750 | } |
3751 | |||
3565 | if (!include_phy) { | 3752 | if (!include_phy) { |
3566 | if (priv->last_phy_res[0]) | 3753 | if (priv->last_phy_res[0]) |
3567 | rx_start = (struct iwl4965_rx_phy_res *) | 3754 | rx_start = (struct iwl4965_rx_phy_res *) |
@@ -3580,7 +3767,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3580 | + rx_start->cfg_phy_cnt); | 3767 | + rx_start->cfg_phy_cnt); |
3581 | 3768 | ||
3582 | len = le16_to_cpu(rx_start->byte_count); | 3769 | len = le16_to_cpu(rx_start->byte_count); |
3583 | rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt + | 3770 | rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + |
3584 | sizeof(struct iwl4965_rx_phy_res) + len); | 3771 | sizeof(struct iwl4965_rx_phy_res) + len); |
3585 | } else { | 3772 | } else { |
3586 | struct iwl4965_rx_mpdu_res_start *amsdu = | 3773 | struct iwl4965_rx_mpdu_res_start *amsdu = |
@@ -3603,7 +3790,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3603 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); | 3790 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); |
3604 | 3791 | ||
3605 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | 3792 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ |
3606 | stats.ssi = iwl4965_calc_rssi(rx_start); | 3793 | rx_status.ssi = iwl4965_calc_rssi(rx_start); |
3607 | 3794 | ||
3608 | /* Meaningful noise values are available only from beacon statistics, | 3795 | /* Meaningful noise values are available only from beacon statistics, |
3609 | * which are gathered only when associated, and indicate noise | 3796 | * which are gathered only when associated, and indicate noise |
@@ -3611,32 +3798,29 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3611 | * Ignore these noise values while scanning (other channels) */ | 3798 | * Ignore these noise values while scanning (other channels) */ |
3612 | if (iwl4965_is_associated(priv) && | 3799 | if (iwl4965_is_associated(priv) && |
3613 | !test_bit(STATUS_SCANNING, &priv->status)) { | 3800 | !test_bit(STATUS_SCANNING, &priv->status)) { |
3614 | stats.noise = priv->last_rx_noise; | 3801 | rx_status.noise = priv->last_rx_noise; |
3615 | stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise); | 3802 | rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, |
3803 | rx_status.noise); | ||
3616 | } else { | 3804 | } else { |
3617 | stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | 3805 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; |
3618 | stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0); | 3806 | rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0); |
3619 | } | 3807 | } |
3620 | 3808 | ||
3621 | /* Reset beacon noise level if not associated. */ | 3809 | /* Reset beacon noise level if not associated. */ |
3622 | if (!iwl4965_is_associated(priv)) | 3810 | if (!iwl4965_is_associated(priv)) |
3623 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | 3811 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; |
3624 | 3812 | ||
3625 | #ifdef CONFIG_IWL4965_DEBUG | 3813 | /* Set "1" to report good data frames in groups of 100 */ |
3626 | /* TODO: Parts of iwl4965_report_frame are broken for 4965 */ | 3814 | /* FIXME: need to optimze the call: */ |
3627 | if (iwl4965_debug_level & (IWL_DL_RX)) | 3815 | iwl4965_dbg_report_frame(priv, pkt, header, 1); |
3628 | /* Set "1" to report good data frames in groups of 100 */ | 3816 | |
3629 | iwl4965_report_frame(priv, pkt, header, 1); | 3817 | IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", |
3630 | 3818 | rx_status.ssi, rx_status.noise, rx_status.signal, | |
3631 | if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS)) | 3819 | rx_status.mactime); |
3632 | IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", | ||
3633 | stats.ssi, stats.noise, stats.signal, | ||
3634 | (long unsigned int)le64_to_cpu(rx_start->timestamp)); | ||
3635 | #endif | ||
3636 | 3820 | ||
3637 | network_packet = iwl4965_is_network_packet(priv, header); | 3821 | network_packet = iwl4965_is_network_packet(priv, header); |
3638 | if (network_packet) { | 3822 | if (network_packet) { |
3639 | priv->last_rx_rssi = stats.ssi; | 3823 | priv->last_rx_rssi = rx_status.ssi; |
3640 | priv->last_beacon_time = priv->ucode_beacon_time; | 3824 | priv->last_beacon_time = priv->ucode_beacon_time; |
3641 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); | 3825 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); |
3642 | } | 3826 | } |
@@ -3739,7 +3923,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3739 | return; | 3923 | return; |
3740 | } | 3924 | } |
3741 | } | 3925 | } |
3742 | iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats); | 3926 | iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); |
3743 | break; | 3927 | break; |
3744 | 3928 | ||
3745 | case IEEE80211_FTYPE_CTL: | 3929 | case IEEE80211_FTYPE_CTL: |
@@ -3748,7 +3932,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3748 | case IEEE80211_STYPE_BACK_REQ: | 3932 | case IEEE80211_STYPE_BACK_REQ: |
3749 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); | 3933 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); |
3750 | iwl4965_handle_data_packet(priv, 0, include_phy, | 3934 | iwl4965_handle_data_packet(priv, 0, include_phy, |
3751 | rxb, &stats); | 3935 | rxb, &rx_status); |
3752 | break; | 3936 | break; |
3753 | default: | 3937 | default: |
3754 | break; | 3938 | break; |
@@ -3778,7 +3962,7 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, | |||
3778 | print_mac(mac3, header->addr3)); | 3962 | print_mac(mac3, header->addr3)); |
3779 | else | 3963 | else |
3780 | iwl4965_handle_data_packet(priv, 1, include_phy, rxb, | 3964 | iwl4965_handle_data_packet(priv, 1, include_phy, rxb, |
3781 | &stats); | 3965 | &rx_status); |
3782 | break; | 3966 | break; |
3783 | } | 3967 | } |
3784 | default: | 3968 | default: |