aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-4965.c
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-05-29 04:35:10 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-03 15:00:24 -0400
commitf20217d9d57584b6c7fcfef8c4183f10ee45fddd (patch)
tree352bc4f0b1de22a1cbed0fb98457fef0172f16f3 /drivers/net/wireless/iwlwifi/iwl-4965.c
parente532fa0e3ce3feda1f1eb14aa31caae503cd9bda (diff)
iwlwifi: move 4965 tx response into iwl-4965.c
This patch moves 4965 tx repsone into iwl-4965.c. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-4965.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 3bb6ac588aaf..98f3df0210d7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3477,6 +3477,251 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
3477 3477
3478 return (u16)sizeof(struct iwl4965_addsta_cmd); 3478 return (u16)sizeof(struct iwl4965_addsta_cmd);
3479} 3479}
3480
3481#ifdef CONFIG_IWL4965_HT
3482static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
3483{
3484 __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
3485 tx_resp->frame_count);
3486 return le32_to_cpu(*scd_ssn) & MAX_SN;
3487
3488}
3489
3490/**
3491 * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
3492 */
3493static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
3494 struct iwl_ht_agg *agg,
3495 struct iwl4965_tx_resp_agg *tx_resp,
3496 u16 start_idx)
3497{
3498 u16 status;
3499 struct agg_tx_status *frame_status = &tx_resp->status;
3500 struct ieee80211_tx_info *info = NULL;
3501 struct ieee80211_hdr *hdr = NULL;
3502 int i, sh;
3503 int txq_id, idx;
3504 u16 seq;
3505
3506 if (agg->wait_for_ba)
3507 IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
3508
3509 agg->frame_count = tx_resp->frame_count;
3510 agg->start_idx = start_idx;
3511 agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
3512 agg->bitmap = 0;
3513
3514 /* # frames attempted by Tx command */
3515 if (agg->frame_count == 1) {
3516 /* Only one frame was attempted; no block-ack will arrive */
3517 status = le16_to_cpu(frame_status[0].status);
3518 seq = le16_to_cpu(frame_status[0].sequence);
3519 idx = SEQ_TO_INDEX(seq);
3520 txq_id = SEQ_TO_QUEUE(seq);
3521
3522 /* FIXME: code repetition */
3523 IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
3524 agg->frame_count, agg->start_idx, idx);
3525
3526 info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
3527 info->status.retry_count = tx_resp->failure_frame;
3528 info->flags &= ~IEEE80211_TX_CTL_AMPDU;
3529 info->flags |= iwl_is_tx_success(status)?
3530 IEEE80211_TX_STAT_ACK : 0;
3531 iwl4965_hwrate_to_tx_control(priv,
3532 le32_to_cpu(tx_resp->rate_n_flags),
3533 info);
3534 /* FIXME: code repetition end */
3535
3536 IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
3537 status & 0xff, tx_resp->failure_frame);
3538 IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
3539 iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
3540
3541 agg->wait_for_ba = 0;
3542 } else {
3543 /* Two or more frames were attempted; expect block-ack */
3544 u64 bitmap = 0;
3545 int start = agg->start_idx;
3546
3547 /* Construct bit-map of pending frames within Tx window */
3548 for (i = 0; i < agg->frame_count; i++) {
3549 u16 sc;
3550 status = le16_to_cpu(frame_status[i].status);
3551 seq = le16_to_cpu(frame_status[i].sequence);
3552 idx = SEQ_TO_INDEX(seq);
3553 txq_id = SEQ_TO_QUEUE(seq);
3554
3555 if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
3556 AGG_TX_STATE_ABORT_MSK))
3557 continue;
3558
3559 IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
3560 agg->frame_count, txq_id, idx);
3561
3562 hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
3563
3564 sc = le16_to_cpu(hdr->seq_ctrl);
3565 if (idx != (SEQ_TO_SN(sc) & 0xff)) {
3566 IWL_ERROR("BUG_ON idx doesn't match seq control"
3567 " idx=%d, seq_idx=%d, seq=%d\n",
3568 idx, SEQ_TO_SN(sc),
3569 hdr->seq_ctrl);
3570 return -1;
3571 }
3572
3573 IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
3574 i, idx, SEQ_TO_SN(sc));
3575
3576 sh = idx - start;
3577 if (sh > 64) {
3578 sh = (start - idx) + 0xff;
3579 bitmap = bitmap << sh;
3580 sh = 0;
3581 start = idx;
3582 } else if (sh < -64)
3583 sh = 0xff - (start - idx);
3584 else if (sh < 0) {
3585 sh = start - idx;
3586 start = idx;
3587 bitmap = bitmap << sh;
3588 sh = 0;
3589 }
3590 bitmap |= (1 << sh);
3591 IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
3592 start, (u32)(bitmap & 0xFFFFFFFF));
3593 }
3594
3595 agg->bitmap = bitmap;
3596 agg->start_idx = start;
3597 agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
3598 IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
3599 agg->frame_count, agg->start_idx,
3600 (unsigned long long)agg->bitmap);
3601
3602 if (bitmap)
3603 agg->wait_for_ba = 1;
3604 }
3605 return 0;
3606}
3607#endif
3608
3609/**
3610 * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
3611 */
3612static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
3613 struct iwl_rx_mem_buffer *rxb)
3614{
3615 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
3616 u16 sequence = le16_to_cpu(pkt->hdr.sequence);
3617 int txq_id = SEQ_TO_QUEUE(sequence);
3618 int index = SEQ_TO_INDEX(sequence);
3619 struct iwl_tx_queue *txq = &priv->txq[txq_id];
3620 struct ieee80211_tx_info *info;
3621 struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
3622 u32 status = le32_to_cpu(tx_resp->status);
3623#ifdef CONFIG_IWL4965_HT
3624 int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
3625 u16 fc;
3626 struct ieee80211_hdr *hdr;
3627 u8 *qc = NULL;
3628#endif
3629
3630 if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
3631 IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
3632 "is out of range [0-%d] %d %d\n", txq_id,
3633 index, txq->q.n_bd, txq->q.write_ptr,
3634 txq->q.read_ptr);
3635 return;
3636 }
3637
3638 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
3639 memset(&info->status, 0, sizeof(info->status));
3640
3641#ifdef CONFIG_IWL4965_HT
3642 hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
3643 fc = le16_to_cpu(hdr->frame_control);
3644 if (ieee80211_is_qos_data(fc)) {
3645 qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
3646 tid = qc[0] & 0xf;
3647 }
3648
3649 sta_id = iwl_get_ra_sta_id(priv, hdr);
3650 if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
3651 IWL_ERROR("Station not known\n");
3652 return;
3653 }
3654
3655 if (txq->sched_retry) {
3656 const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
3657 struct iwl_ht_agg *agg = NULL;
3658
3659 if (!qc)
3660 return;
3661
3662 agg = &priv->stations[sta_id].tid[tid].agg;
3663
3664 iwl4965_tx_status_reply_tx(priv, agg,
3665 (struct iwl4965_tx_resp_agg *)tx_resp, index);
3666
3667 if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
3668 /* TODO: send BAR */
3669 }
3670
3671 if (txq->q.read_ptr != (scd_ssn & 0xff)) {
3672 int freed, ampdu_q;
3673 index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
3674 IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
3675 "%d index %d\n", scd_ssn , index);
3676 freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
3677 priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
3678
3679 if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
3680 txq_id >= 0 && priv->mac80211_registered &&
3681 agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
3682 /* calculate mac80211 ampdu sw queue to wake */
3683 ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID +
3684 priv->hw->queues;
3685 if (agg->state == IWL_AGG_OFF)
3686 ieee80211_wake_queue(priv->hw, txq_id);
3687 else
3688 ieee80211_wake_queue(priv->hw, ampdu_q);
3689 }
3690 iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
3691 }
3692 } else {
3693#endif /* CONFIG_IWL4965_HT */
3694
3695 info->status.retry_count = tx_resp->failure_frame;
3696 info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
3697 iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
3698 info);
3699
3700 IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
3701 "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
3702 status, le32_to_cpu(tx_resp->rate_n_flags),
3703 tx_resp->failure_frame);
3704
3705 IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
3706#ifdef CONFIG_IWL4965_HT
3707 if (index != -1) {
3708 int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
3709 if (tid != MAX_TID_COUNT)
3710 priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
3711 if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
3712 (txq_id >= 0) && priv->mac80211_registered)
3713 ieee80211_wake_queue(priv->hw, txq_id);
3714 if (tid != MAX_TID_COUNT)
3715 iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
3716 }
3717 }
3718#endif /* CONFIG_IWL4965_HT */
3719
3720 if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
3721 IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
3722}
3723
3724
3480/* Set up 4965-specific Rx frame reply handlers */ 3725/* Set up 4965-specific Rx frame reply handlers */
3481static void iwl4965_rx_handler_setup(struct iwl_priv *priv) 3726static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
3482{ 3727{
@@ -3487,6 +3732,8 @@ static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
3487 priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; 3732 priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
3488 priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; 3733 priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
3489 3734
3735 priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
3736
3490#ifdef CONFIG_IWL4965_HT 3737#ifdef CONFIG_IWL4965_HT
3491 priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; 3738 priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
3492#endif /* CONFIG_IWL4965_HT */ 3739#endif /* CONFIG_IWL4965_HT */