diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 86 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 6 |
5 files changed, 87 insertions, 99 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 69d0f997298..a31cdef8484 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -395,6 +395,77 @@ drop_unlock_priv: | |||
395 | return -1; | 395 | return -1; |
396 | } | 396 | } |
397 | 397 | ||
398 | int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | ||
399 | struct ieee80211_sta *sta, u16 tid) | ||
400 | { | ||
401 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
402 | struct iwl_tid_data *tid_data; | ||
403 | unsigned long flags; | ||
404 | int sta_id; | ||
405 | |||
406 | sta_id = iwl_sta_id(sta); | ||
407 | |||
408 | if (sta_id == IWL_INVALID_STATION) { | ||
409 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | ||
410 | return -ENXIO; | ||
411 | } | ||
412 | |||
413 | spin_lock_irqsave(&priv->shrd->sta_lock, flags); | ||
414 | |||
415 | tid_data = &priv->shrd->tid_data[sta_id][tid]; | ||
416 | |||
417 | switch (priv->shrd->tid_data[sta_id][tid].agg.state) { | ||
418 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | ||
419 | /* | ||
420 | * This can happen if the peer stops aggregation | ||
421 | * again before we've had a chance to drain the | ||
422 | * queue we selected previously, i.e. before the | ||
423 | * session was really started completely. | ||
424 | */ | ||
425 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); | ||
426 | goto turn_off; | ||
427 | case IWL_AGG_ON: | ||
428 | break; | ||
429 | default: | ||
430 | IWL_WARN(priv, "Stopping AGG while state not ON " | ||
431 | "or starting for %d on %d (%d)\n", sta_id, tid, | ||
432 | priv->shrd->tid_data[sta_id][tid].agg.state); | ||
433 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); | ||
438 | |||
439 | /* There are still packets for this RA / TID in the HW */ | ||
440 | if (tid_data->agg.ssn != tid_data->next_reclaimed) { | ||
441 | IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " | ||
442 | "next_recl = %d", | ||
443 | tid_data->agg.ssn, | ||
444 | tid_data->next_reclaimed); | ||
445 | priv->shrd->tid_data[sta_id][tid].agg.state = | ||
446 | IWL_EMPTYING_HW_QUEUE_DELBA; | ||
447 | spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d", | ||
452 | tid_data->agg.ssn); | ||
453 | turn_off: | ||
454 | priv->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; | ||
455 | |||
456 | /* do not restore/save irqs */ | ||
457 | spin_unlock(&priv->shrd->sta_lock); | ||
458 | spin_lock(&priv->shrd->lock); | ||
459 | |||
460 | iwl_trans_tx_agg_disable(trans(priv), sta_id, tid); | ||
461 | |||
462 | spin_unlock_irqrestore(&priv->shrd->lock, flags); | ||
463 | |||
464 | iwl_stop_tx_ba_trans_ready(priv, vif_priv->ctx->ctxid, sta_id, tid); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
398 | int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | 469 | int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, |
399 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 470 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
400 | { | 471 | { |
@@ -428,23 +499,6 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
428 | return ret; | 499 | return ret; |
429 | } | 500 | } |
430 | 501 | ||
431 | int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | ||
432 | struct ieee80211_sta *sta, u16 tid) | ||
433 | { | ||
434 | int sta_id; | ||
435 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
436 | |||
437 | sta_id = iwl_sta_id(sta); | ||
438 | |||
439 | if (sta_id == IWL_INVALID_STATION) { | ||
440 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | ||
441 | return -ENXIO; | ||
442 | } | ||
443 | |||
444 | return iwl_trans_tx_agg_disable(trans(priv), vif_priv->ctx->ctxid, | ||
445 | sta_id, tid); | ||
446 | } | ||
447 | |||
448 | static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, | 502 | static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, |
449 | struct iwl_rxon_context *ctx, | 503 | struct iwl_rxon_context *ctx, |
450 | const u8 *addr1) | 504 | const u8 *addr1) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 5a384b309b0..342ee2df213 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h | |||
@@ -280,10 +280,8 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, | |||
280 | void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, | 280 | void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, |
281 | struct iwl_tx_queue *txq, | 281 | struct iwl_tx_queue *txq, |
282 | u16 byte_cnt); | 282 | u16 byte_cnt); |
283 | void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id); | ||
284 | int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, | 283 | int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, |
285 | enum iwl_rxon_context_id ctx, int sta_id, | 284 | int sta_id, int tid); |
286 | int tid); | ||
287 | void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index); | 285 | void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index); |
288 | void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, | 286 | void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, |
289 | struct iwl_tx_queue *txq, | 287 | struct iwl_tx_queue *txq, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index 58ee0ac5706..4ee5f50643f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | |||
@@ -578,35 +578,11 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, | |||
578 | return 0; | 578 | return 0; |
579 | } | 579 | } |
580 | 580 | ||
581 | void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id) | 581 | int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) |
582 | { | 582 | { |
583 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 583 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
584 | iwlagn_tx_queue_stop_scheduler(trans, txq_id); | 584 | /* TODO: the transport layer shouldn't access the tid_data */ |
585 | 585 | int txq_id = trans->shrd->tid_data[sta_id][tid].agg.txq_id; | |
586 | iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id)); | ||
587 | |||
588 | trans_pcie->txq[txq_id].q.read_ptr = 0; | ||
589 | trans_pcie->txq[txq_id].q.write_ptr = 0; | ||
590 | /* supposes that ssn_idx is valid (!= 0xFFF) */ | ||
591 | iwl_trans_set_wr_ptrs(trans, txq_id, 0); | ||
592 | |||
593 | iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); | ||
594 | iwl_txq_ctx_deactivate(trans_pcie, txq_id); | ||
595 | iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); | ||
596 | } | ||
597 | |||
598 | int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, | ||
599 | enum iwl_rxon_context_id ctx, int sta_id, | ||
600 | int tid) | ||
601 | { | ||
602 | struct iwl_tid_data *tid_data; | ||
603 | unsigned long flags; | ||
604 | int txq_id; | ||
605 | |||
606 | spin_lock_irqsave(&trans->shrd->sta_lock, flags); | ||
607 | |||
608 | tid_data = &trans->shrd->tid_data[sta_id][tid]; | ||
609 | txq_id = tid_data->agg.txq_id; | ||
610 | 586 | ||
611 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || | 587 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || |
612 | (IWLAGN_FIRST_AMPDU_QUEUE + | 588 | (IWLAGN_FIRST_AMPDU_QUEUE + |
@@ -616,59 +592,21 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, | |||
616 | txq_id, IWLAGN_FIRST_AMPDU_QUEUE, | 592 | txq_id, IWLAGN_FIRST_AMPDU_QUEUE, |
617 | IWLAGN_FIRST_AMPDU_QUEUE + | 593 | IWLAGN_FIRST_AMPDU_QUEUE + |
618 | hw_params(trans).num_ampdu_queues - 1); | 594 | hw_params(trans).num_ampdu_queues - 1); |
619 | spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); | ||
620 | return -EINVAL; | 595 | return -EINVAL; |
621 | } | 596 | } |
622 | 597 | ||
623 | switch (trans->shrd->tid_data[sta_id][tid].agg.state) { | 598 | iwlagn_tx_queue_stop_scheduler(trans, txq_id); |
624 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | ||
625 | /* | ||
626 | * This can happen if the peer stops aggregation | ||
627 | * again before we've had a chance to drain the | ||
628 | * queue we selected previously, i.e. before the | ||
629 | * session was really started completely. | ||
630 | */ | ||
631 | IWL_DEBUG_HT(trans, "AGG stop before setup done\n"); | ||
632 | goto turn_off; | ||
633 | case IWL_AGG_ON: | ||
634 | break; | ||
635 | default: | ||
636 | IWL_WARN(trans, "Stopping AGG while state not ON " | ||
637 | "or starting for %d on %d (%d)\n", sta_id, tid, | ||
638 | trans->shrd->tid_data[sta_id][tid].agg.state); | ||
639 | spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); | ||
644 | |||
645 | /* There are still packets for this RA / TID in the HW */ | ||
646 | if (tid_data->agg.ssn != tid_data->next_reclaimed) { | ||
647 | IWL_DEBUG_TX_QUEUES(trans, "Can't proceed: ssn %d, " | ||
648 | "next_recl = %d", | ||
649 | tid_data->agg.ssn, | ||
650 | tid_data->next_reclaimed); | ||
651 | trans->shrd->tid_data[sta_id][tid].agg.state = | ||
652 | IWL_EMPTYING_HW_QUEUE_DELBA; | ||
653 | spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); | ||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | IWL_DEBUG_TX_QUEUES(trans, "Can proceed: ssn = next_recl = %d", | ||
658 | tid_data->agg.ssn); | ||
659 | turn_off: | ||
660 | trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; | ||
661 | |||
662 | /* do not restore/save irqs */ | ||
663 | spin_unlock(&trans->shrd->sta_lock); | ||
664 | spin_lock(&trans->shrd->lock); | ||
665 | |||
666 | iwl_trans_pcie_txq_agg_disable(trans, txq_id); | ||
667 | 599 | ||
668 | spin_unlock_irqrestore(&trans->shrd->lock, flags); | 600 | iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id)); |
669 | 601 | ||
670 | iwl_stop_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); | 602 | trans_pcie->txq[txq_id].q.read_ptr = 0; |
603 | trans_pcie->txq[txq_id].q.write_ptr = 0; | ||
604 | /* supposes that ssn_idx is valid (!= 0xFFF) */ | ||
605 | iwl_trans_set_wr_ptrs(trans, txq_id, 0); | ||
671 | 606 | ||
607 | iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); | ||
608 | iwl_txq_ctx_deactivate(trans_pcie, txq_id); | ||
609 | iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); | ||
672 | return 0; | 610 | return 0; |
673 | } | 611 | } |
674 | 612 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index ef057ff219e..15bee2b97c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | |||
@@ -1290,7 +1290,7 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans, | |||
1290 | IWL_DEBUG_TX_QUEUES(trans, | 1290 | IWL_DEBUG_TX_QUEUES(trans, |
1291 | "Can continue DELBA flow ssn = next_recl =" | 1291 | "Can continue DELBA flow ssn = next_recl =" |
1292 | " %d", tid_data->next_reclaimed); | 1292 | " %d", tid_data->next_reclaimed); |
1293 | iwl_trans_pcie_txq_agg_disable(trans, txq_id); | 1293 | iwl_trans_pcie_tx_agg_disable(trans, sta_id, tid); |
1294 | tid_data->agg.state = IWL_AGG_OFF; | 1294 | tid_data->agg.state = IWL_AGG_OFF; |
1295 | iwl_stop_tx_ba_trans_ready(priv(trans), | 1295 | iwl_stop_tx_ba_trans_ready(priv(trans), |
1296 | NUM_IWL_RXON_CTX, | 1296 | NUM_IWL_RXON_CTX, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index f94a6ee5f82..32c1deb3f7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -184,8 +184,7 @@ struct iwl_trans_ops { | |||
184 | struct sk_buff_head *skbs); | 184 | struct sk_buff_head *skbs); |
185 | 185 | ||
186 | int (*tx_agg_disable)(struct iwl_trans *trans, | 186 | int (*tx_agg_disable)(struct iwl_trans *trans, |
187 | enum iwl_rxon_context_id ctx, int sta_id, | 187 | int sta_id, int tid); |
188 | int tid); | ||
189 | int (*tx_agg_alloc)(struct iwl_trans *trans, | 188 | int (*tx_agg_alloc)(struct iwl_trans *trans, |
190 | enum iwl_rxon_context_id ctx, int sta_id, int tid, | 189 | enum iwl_rxon_context_id ctx, int sta_id, int tid, |
191 | u16 *ssn); | 190 | u16 *ssn); |
@@ -318,10 +317,9 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, | |||
318 | } | 317 | } |
319 | 318 | ||
320 | static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, | 319 | static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, |
321 | enum iwl_rxon_context_id ctx, | ||
322 | int sta_id, int tid) | 320 | int sta_id, int tid) |
323 | { | 321 | { |
324 | return trans->ops->tx_agg_disable(trans, ctx, sta_id, tid); | 322 | return trans->ops->tx_agg_disable(trans, sta_id, tid); |
325 | } | 323 | } |
326 | 324 | ||
327 | static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, | 325 | static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, |