diff options
author | Ron Rindjunsky <ron.rindjunsky@intel.com> | 2008-01-28 07:07:24 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-29 15:19:18 -0500 |
commit | fe01b477bbd23e69c3bdc6bce5be510ddad8297d (patch) | |
tree | 353471f96adb7580b7940c3b7cf6df4f8f0044a2 /drivers/net/wireless/iwlwifi/iwl4965-base.c | |
parent | 8114fcf185c58b23dc9fcaf4944b59b4c1407b39 (diff) |
iwlwifi: A-MPDU Tx conform flows to mac80211
This patch alters the current iwlwifi behavior to fit the flows introduced
by the mac80211, mainly queues handling and start/stop call backs flows
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl4965-base.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 121 |
1 files changed, 65 insertions, 56 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 3f5114f5fe16..16cb990e06fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -205,7 +205,7 @@ static void iwl4965_print_hex_dump(int level, void *p, u32 len) | |||
205 | * See more detailed info in iwl-4965-hw.h. | 205 | * See more detailed info in iwl-4965-hw.h. |
206 | ***************************************************/ | 206 | ***************************************************/ |
207 | 207 | ||
208 | static int iwl4965_queue_space(const struct iwl4965_queue *q) | 208 | int iwl4965_queue_space(const struct iwl4965_queue *q) |
209 | { | 209 | { |
210 | int s = q->read_ptr - q->write_ptr; | 210 | int s = q->read_ptr - q->write_ptr; |
211 | 211 | ||
@@ -2972,11 +2972,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, | |||
2972 | __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); | 2972 | __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); |
2973 | seq_number += 0x10; | 2973 | seq_number += 0x10; |
2974 | #ifdef CONFIG_IWL4965_HT | 2974 | #ifdef CONFIG_IWL4965_HT |
2975 | #ifdef CONFIG_IWL4965_HT_AGG | ||
2976 | /* aggregation is on for this <sta,tid> */ | 2975 | /* aggregation is on for this <sta,tid> */ |
2977 | if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG) | 2976 | if (ctl->flags & IEEE80211_TXCTL_AMPDU) |
2978 | txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; | 2977 | txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; |
2979 | #endif /* CONFIG_IWL4965_HT_AGG */ | 2978 | priv->stations[sta_id].tid[tid].tfds_in_queue++; |
2980 | #endif /* CONFIG_IWL4965_HT */ | 2979 | #endif /* CONFIG_IWL4965_HT */ |
2981 | } | 2980 | } |
2982 | 2981 | ||
@@ -3528,10 +3527,10 @@ int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index) | |||
3528 | nfreed++; | 3527 | nfreed++; |
3529 | } | 3528 | } |
3530 | 3529 | ||
3531 | if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && | 3530 | /* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && |
3532 | (txq_id != IWL_CMD_QUEUE_NUM) && | 3531 | (txq_id != IWL_CMD_QUEUE_NUM) && |
3533 | priv->mac80211_registered) | 3532 | priv->mac80211_registered) |
3534 | ieee80211_wake_queue(priv->hw, txq_id); | 3533 | ieee80211_wake_queue(priv->hw, txq_id); */ |
3535 | 3534 | ||
3536 | 3535 | ||
3537 | return nfreed; | 3536 | return nfreed; |
@@ -3550,7 +3549,6 @@ static int iwl4965_is_tx_success(u32 status) | |||
3550 | * | 3549 | * |
3551 | ******************************************************************************/ | 3550 | ******************************************************************************/ |
3552 | #ifdef CONFIG_IWL4965_HT | 3551 | #ifdef CONFIG_IWL4965_HT |
3553 | #ifdef CONFIG_IWL4965_HT_AGG | ||
3554 | 3552 | ||
3555 | static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv, | 3553 | static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv, |
3556 | struct ieee80211_hdr *hdr) | 3554 | struct ieee80211_hdr *hdr) |
@@ -3585,11 +3583,11 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) | |||
3585 | */ | 3583 | */ |
3586 | static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, | 3584 | static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, |
3587 | struct iwl4965_ht_agg *agg, | 3585 | struct iwl4965_ht_agg *agg, |
3588 | struct iwl4965_tx_resp *tx_resp, | 3586 | struct iwl4965_tx_resp_agg *tx_resp, |
3589 | u16 start_idx) | 3587 | u16 start_idx) |
3590 | { | 3588 | { |
3591 | u32 status; | 3589 | u16 status; |
3592 | __le32 *frame_status = &tx_resp->status; | 3590 | struct agg_tx_status *frame_status = &tx_resp->status; |
3593 | struct ieee80211_tx_status *tx_status = NULL; | 3591 | struct ieee80211_tx_status *tx_status = NULL; |
3594 | struct ieee80211_hdr *hdr = NULL; | 3592 | struct ieee80211_hdr *hdr = NULL; |
3595 | int i, sh; | 3593 | int i, sh; |
@@ -3602,26 +3600,25 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, | |||
3602 | agg->frame_count = tx_resp->frame_count; | 3600 | agg->frame_count = tx_resp->frame_count; |
3603 | agg->start_idx = start_idx; | 3601 | agg->start_idx = start_idx; |
3604 | agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); | 3602 | agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); |
3605 | agg->bitmap0 = agg->bitmap1 = 0; | 3603 | agg->bitmap = 0; |
3606 | 3604 | ||
3607 | /* # frames attempted by Tx command */ | 3605 | /* # frames attempted by Tx command */ |
3608 | if (agg->frame_count == 1) { | 3606 | if (agg->frame_count == 1) { |
3609 | /* Only one frame was attempted; no block-ack will arrive */ | 3607 | /* Only one frame was attempted; no block-ack will arrive */ |
3610 | struct iwl4965_tx_queue *txq ; | 3608 | status = le16_to_cpu(frame_status[0].status); |
3611 | status = le32_to_cpu(frame_status[0]); | 3609 | seq = le16_to_cpu(frame_status[0].sequence); |
3610 | idx = SEQ_TO_INDEX(seq); | ||
3611 | txq_id = SEQ_TO_QUEUE(seq); | ||
3612 | 3612 | ||
3613 | txq_id = agg->txq_id; | ||
3614 | txq = &priv->txq[txq_id]; | ||
3615 | /* FIXME: code repetition */ | 3613 | /* FIXME: code repetition */ |
3616 | IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n", | 3614 | IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n", |
3617 | agg->frame_count, agg->start_idx); | 3615 | agg->frame_count, agg->start_idx, idx); |
3618 | 3616 | ||
3619 | tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status); | 3617 | tx_status = &(priv->txq[txq_id].txb[idx].status); |
3620 | tx_status->retry_count = tx_resp->failure_frame; | 3618 | tx_status->retry_count = tx_resp->failure_frame; |
3621 | tx_status->queue_number = status & 0xff; | 3619 | tx_status->queue_number = status & 0xff; |
3622 | tx_status->queue_length = tx_resp->bt_kill_count; | 3620 | tx_status->queue_length = tx_resp->failure_rts; |
3623 | tx_status->queue_length |= tx_resp->failure_rts; | 3621 | tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU; |
3624 | |||
3625 | tx_status->flags = iwl4965_is_tx_success(status)? | 3622 | tx_status->flags = iwl4965_is_tx_success(status)? |
3626 | IEEE80211_TX_STATUS_ACK : 0; | 3623 | IEEE80211_TX_STATUS_ACK : 0; |
3627 | tx_status->control.tx_rate = | 3624 | tx_status->control.tx_rate = |
@@ -3642,8 +3639,8 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, | |||
3642 | /* Construct bit-map of pending frames within Tx window */ | 3639 | /* Construct bit-map of pending frames within Tx window */ |
3643 | for (i = 0; i < agg->frame_count; i++) { | 3640 | for (i = 0; i < agg->frame_count; i++) { |
3644 | u16 sc; | 3641 | u16 sc; |
3645 | status = le32_to_cpu(frame_status[i]); | 3642 | status = le16_to_cpu(frame_status[i].status); |
3646 | seq = status >> 16; | 3643 | seq = le16_to_cpu(frame_status[i].sequence); |
3647 | idx = SEQ_TO_INDEX(seq); | 3644 | idx = SEQ_TO_INDEX(seq); |
3648 | txq_id = SEQ_TO_QUEUE(seq); | 3645 | txq_id = SEQ_TO_QUEUE(seq); |
3649 | 3646 | ||
@@ -3687,13 +3684,12 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, | |||
3687 | start, (u32)(bitmap & 0xFFFFFFFF)); | 3684 | start, (u32)(bitmap & 0xFFFFFFFF)); |
3688 | } | 3685 | } |
3689 | 3686 | ||
3690 | agg->bitmap0 = bitmap & 0xFFFFFFFF; | 3687 | agg->bitmap = bitmap; |
3691 | agg->bitmap1 = bitmap >> 32; | ||
3692 | agg->start_idx = start; | 3688 | agg->start_idx = start; |
3693 | agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); | 3689 | agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); |
3694 | IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n", | 3690 | IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n", |
3695 | agg->frame_count, agg->start_idx, | 3691 | agg->frame_count, agg->start_idx, |
3696 | agg->bitmap0); | 3692 | agg->bitmap); |
3697 | 3693 | ||
3698 | if (bitmap) | 3694 | if (bitmap) |
3699 | agg->wait_for_ba = 1; | 3695 | agg->wait_for_ba = 1; |
@@ -3701,7 +3697,6 @@ static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, | |||
3701 | return 0; | 3697 | return 0; |
3702 | } | 3698 | } |
3703 | #endif | 3699 | #endif |
3704 | #endif | ||
3705 | 3700 | ||
3706 | /** | 3701 | /** |
3707 | * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response | 3702 | * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response |
@@ -3718,9 +3713,9 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, | |||
3718 | struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | 3713 | struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; |
3719 | u32 status = le32_to_cpu(tx_resp->status); | 3714 | u32 status = le32_to_cpu(tx_resp->status); |
3720 | #ifdef CONFIG_IWL4965_HT | 3715 | #ifdef CONFIG_IWL4965_HT |
3721 | #ifdef CONFIG_IWL4965_HT_AGG | 3716 | int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; |
3722 | int tid, sta_id; | 3717 | struct ieee80211_hdr *hdr; |
3723 | #endif | 3718 | __le16 *qc; |
3724 | #endif | 3719 | #endif |
3725 | 3720 | ||
3726 | if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { | 3721 | if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { |
@@ -3732,44 +3727,51 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, | |||
3732 | } | 3727 | } |
3733 | 3728 | ||
3734 | #ifdef CONFIG_IWL4965_HT | 3729 | #ifdef CONFIG_IWL4965_HT |
3735 | #ifdef CONFIG_IWL4965_HT_AGG | 3730 | hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index); |
3731 | qc = ieee80211_get_qos_ctrl(hdr); | ||
3732 | |||
3733 | if (qc) | ||
3734 | tid = le16_to_cpu(*qc) & 0xf; | ||
3735 | |||
3736 | sta_id = iwl4965_get_ra_sta_id(priv, hdr); | ||
3737 | if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { | ||
3738 | IWL_ERROR("Station not known\n"); | ||
3739 | return; | ||
3740 | } | ||
3741 | |||
3736 | if (txq->sched_retry) { | 3742 | if (txq->sched_retry) { |
3737 | const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); | 3743 | const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); |
3738 | struct ieee80211_hdr *hdr = | ||
3739 | iwl4965_tx_queue_get_hdr(priv, txq_id, index); | ||
3740 | struct iwl4965_ht_agg *agg = NULL; | 3744 | struct iwl4965_ht_agg *agg = NULL; |
3741 | __le16 *qc = ieee80211_get_qos_ctrl(hdr); | ||
3742 | 3745 | ||
3743 | if (qc == NULL) { | 3746 | if (!qc) |
3744 | IWL_ERROR("BUG_ON qc is null!!!!\n"); | ||
3745 | return; | 3747 | return; |
3746 | } | ||
3747 | |||
3748 | tid = le16_to_cpu(*qc) & 0xf; | ||
3749 | |||
3750 | sta_id = iwl4965_get_ra_sta_id(priv, hdr); | ||
3751 | if (unlikely(sta_id == IWL_INVALID_STATION)) { | ||
3752 | IWL_ERROR("Station not known for\n"); | ||
3753 | return; | ||
3754 | } | ||
3755 | 3748 | ||
3756 | agg = &priv->stations[sta_id].tid[tid].agg; | 3749 | agg = &priv->stations[sta_id].tid[tid].agg; |
3757 | 3750 | ||
3758 | iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index); | 3751 | iwl4965_tx_status_reply_tx(priv, agg, |
3752 | (struct iwl4965_tx_resp_agg *)tx_resp, index); | ||
3759 | 3753 | ||
3760 | if ((tx_resp->frame_count == 1) && | 3754 | if ((tx_resp->frame_count == 1) && |
3761 | !iwl4965_is_tx_success(status)) { | 3755 | !iwl4965_is_tx_success(status)) { |
3762 | /* TODO: send BAR */ | 3756 | /* TODO: send BAR */ |
3763 | } | 3757 | } |
3764 | 3758 | ||
3765 | if ((txq->q.read_ptr != (scd_ssn & 0xff))) { | 3759 | if (txq->q.read_ptr != (scd_ssn & 0xff)) { |
3760 | int freed; | ||
3766 | index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); | 3761 | index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); |
3767 | IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " | 3762 | IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " |
3768 | "%d index %d\n", scd_ssn , index); | 3763 | "%d index %d\n", scd_ssn , index); |
3769 | iwl4965_tx_queue_reclaim(priv, txq_id, index); | 3764 | freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); |
3765 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; | ||
3766 | |||
3767 | if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && | ||
3768 | txq_id >= 0 && priv->mac80211_registered && | ||
3769 | agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) | ||
3770 | ieee80211_wake_queue(priv->hw, txq_id); | ||
3771 | |||
3772 | iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); | ||
3770 | } | 3773 | } |
3771 | } else { | 3774 | } else { |
3772 | #endif /* CONFIG_IWL4965_HT_AGG */ | ||
3773 | #endif /* CONFIG_IWL4965_HT */ | 3775 | #endif /* CONFIG_IWL4965_HT */ |
3774 | tx_status = &(txq->txb[txq->q.read_ptr].status); | 3776 | tx_status = &(txq->txb[txq->q.read_ptr].status); |
3775 | 3777 | ||
@@ -3790,12 +3792,21 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, | |||
3790 | tx_resp->failure_frame); | 3792 | tx_resp->failure_frame); |
3791 | 3793 | ||
3792 | IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); | 3794 | IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); |
3793 | if (index != -1) | 3795 | if (index != -1) { |
3794 | iwl4965_tx_queue_reclaim(priv, txq_id, index); | 3796 | int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index); |
3797 | #ifdef CONFIG_IWL4965_HT | ||
3798 | if (tid != MAX_TID_COUNT) | ||
3799 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; | ||
3800 | if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && | ||
3801 | (txq_id >= 0) && | ||
3802 | priv->mac80211_registered) | ||
3803 | ieee80211_wake_queue(priv->hw, txq_id); | ||
3804 | if (tid != MAX_TID_COUNT) | ||
3805 | iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id); | ||
3806 | #endif | ||
3807 | } | ||
3795 | #ifdef CONFIG_IWL4965_HT | 3808 | #ifdef CONFIG_IWL4965_HT |
3796 | #ifdef CONFIG_IWL4965_HT_AGG | ||
3797 | } | 3809 | } |
3798 | #endif /* CONFIG_IWL4965_HT_AGG */ | ||
3799 | #endif /* CONFIG_IWL4965_HT */ | 3810 | #endif /* CONFIG_IWL4965_HT */ |
3800 | 3811 | ||
3801 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) | 3812 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) |
@@ -9089,10 +9100,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
9089 | /* Default value; 4 EDCA QOS priorities */ | 9100 | /* Default value; 4 EDCA QOS priorities */ |
9090 | hw->queues = 4; | 9101 | hw->queues = 4; |
9091 | #ifdef CONFIG_IWL4965_HT | 9102 | #ifdef CONFIG_IWL4965_HT |
9092 | #ifdef CONFIG_IWL4965_HT_AGG | ||
9093 | /* Enhanced value; more queues, to support 11n aggregation */ | 9103 | /* Enhanced value; more queues, to support 11n aggregation */ |
9094 | hw->queues = 16; | 9104 | hw->queues = 16; |
9095 | #endif /* CONFIG_IWL4965_HT_AGG */ | ||
9096 | #endif /* CONFIG_IWL4965_HT */ | 9105 | #endif /* CONFIG_IWL4965_HT */ |
9097 | 9106 | ||
9098 | spin_lock_init(&priv->lock); | 9107 | spin_lock_init(&priv->lock); |