diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 81 |
1 files changed, 42 insertions, 39 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a51a7cfa5a1..5950184d986 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -71,18 +71,6 @@ static const u8 tid_to_ac[] = { | |||
71 | 2, 3, 3, 2, 1, 1, 0, 0 | 71 | 2, 3, 3, 2, 1, 1, 0, 0 |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static const u8 ac_to_fifo[] = { | ||
75 | IWL_TX_FIFO_VO, | ||
76 | IWL_TX_FIFO_VI, | ||
77 | IWL_TX_FIFO_BE, | ||
78 | IWL_TX_FIFO_BK, | ||
79 | }; | ||
80 | |||
81 | static inline int get_fifo_from_ac(u8 ac) | ||
82 | { | ||
83 | return ac_to_fifo[ac]; | ||
84 | } | ||
85 | |||
86 | static inline int get_ac_from_tid(u16 tid) | 74 | static inline int get_ac_from_tid(u16 tid) |
87 | { | 75 | { |
88 | if (likely(tid < ARRAY_SIZE(tid_to_ac))) | 76 | if (likely(tid < ARRAY_SIZE(tid_to_ac))) |
@@ -92,10 +80,10 @@ static inline int get_ac_from_tid(u16 tid) | |||
92 | return -EINVAL; | 80 | return -EINVAL; |
93 | } | 81 | } |
94 | 82 | ||
95 | static inline int get_fifo_from_tid(u16 tid) | 83 | static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid) |
96 | { | 84 | { |
97 | if (likely(tid < ARRAY_SIZE(tid_to_ac))) | 85 | if (likely(tid < ARRAY_SIZE(tid_to_ac))) |
98 | return get_fifo_from_ac(tid_to_ac[tid]); | 86 | return ctx->ac_to_fifo[tid_to_ac[tid]]; |
99 | 87 | ||
100 | /* no support for TIDs 8-15 yet */ | 88 | /* no support for TIDs 8-15 yet */ |
101 | return -EINVAL; | 89 | return -EINVAL; |
@@ -118,7 +106,7 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, | |||
118 | 106 | ||
119 | WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); | 107 | WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); |
120 | 108 | ||
121 | if (txq_id != IWL_CMD_QUEUE_NUM) { | 109 | if (txq_id != priv->cmd_queue) { |
122 | sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; | 110 | sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; |
123 | sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; | 111 | sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; |
124 | 112 | ||
@@ -155,7 +143,7 @@ void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, | |||
155 | 143 | ||
156 | WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); | 144 | WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); |
157 | 145 | ||
158 | if (txq_id != IWL_CMD_QUEUE_NUM) | 146 | if (txq_id != priv->cmd_queue) |
159 | sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; | 147 | sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; |
160 | 148 | ||
161 | bc_ent = cpu_to_le16(1 | (sta_id << 12)); | 149 | bc_ent = cpu_to_le16(1 | (sta_id << 12)); |
@@ -333,11 +321,6 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask) | |||
333 | iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask); | 321 | iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask); |
334 | } | 322 | } |
335 | 323 | ||
336 | static inline int get_queue_from_ac(u16 ac) | ||
337 | { | ||
338 | return ac; | ||
339 | } | ||
340 | |||
341 | /* | 324 | /* |
342 | * handle build REPLY_TX command notification. | 325 | * handle build REPLY_TX command notification. |
343 | */ | 326 | */ |
@@ -531,6 +514,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
531 | struct iwl_device_cmd *out_cmd; | 514 | struct iwl_device_cmd *out_cmd; |
532 | struct iwl_cmd_meta *out_meta; | 515 | struct iwl_cmd_meta *out_meta; |
533 | struct iwl_tx_cmd *tx_cmd; | 516 | struct iwl_tx_cmd *tx_cmd; |
517 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
534 | int swq_id, txq_id; | 518 | int swq_id, txq_id; |
535 | dma_addr_t phys_addr; | 519 | dma_addr_t phys_addr; |
536 | dma_addr_t txcmd_phys; | 520 | dma_addr_t txcmd_phys; |
@@ -545,6 +529,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
545 | u8 *qc = NULL; | 529 | u8 *qc = NULL; |
546 | unsigned long flags; | 530 | unsigned long flags; |
547 | 531 | ||
532 | if (info->control.vif) | ||
533 | ctx = iwl_rxon_ctx_from_vif(info->control.vif); | ||
534 | |||
548 | spin_lock_irqsave(&priv->lock, flags); | 535 | spin_lock_irqsave(&priv->lock, flags); |
549 | if (iwl_is_rfkill(priv)) { | 536 | if (iwl_is_rfkill(priv)) { |
550 | IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); | 537 | IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); |
@@ -565,7 +552,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
565 | hdr_len = ieee80211_hdrlen(fc); | 552 | hdr_len = ieee80211_hdrlen(fc); |
566 | 553 | ||
567 | /* Find index into station table for destination station */ | 554 | /* Find index into station table for destination station */ |
568 | sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta); | 555 | sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); |
569 | if (sta_id == IWL_INVALID_STATION) { | 556 | if (sta_id == IWL_INVALID_STATION) { |
570 | IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", | 557 | IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", |
571 | hdr->addr1); | 558 | hdr->addr1); |
@@ -577,8 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
577 | if (sta) | 564 | if (sta) |
578 | sta_priv = (void *)sta->drv_priv; | 565 | sta_priv = (void *)sta->drv_priv; |
579 | 566 | ||
580 | if (sta_priv && sta_id != priv->hw_params.bcast_sta_id && | 567 | if (sta_priv && sta_priv->asleep) { |
581 | sta_priv->asleep) { | ||
582 | WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)); | 568 | WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)); |
583 | /* | 569 | /* |
584 | * This sends an asynchronous command to the device, | 570 | * This sends an asynchronous command to the device, |
@@ -592,7 +578,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
592 | iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); | 578 | iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); |
593 | } | 579 | } |
594 | 580 | ||
595 | txq_id = get_queue_from_ac(skb_get_queue_mapping(skb)); | 581 | /* |
582 | * Send this frame after DTIM -- there's a special queue | ||
583 | * reserved for this for contexts that support AP mode. | ||
584 | */ | ||
585 | if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { | ||
586 | txq_id = ctx->mcast_queue; | ||
587 | /* | ||
588 | * The microcode will clear the more data | ||
589 | * bit in the last frame it transmits. | ||
590 | */ | ||
591 | hdr->frame_control |= | ||
592 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
593 | } else | ||
594 | txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)]; | ||
596 | 595 | ||
597 | /* irqs already disabled/saved above when locking priv->lock */ | 596 | /* irqs already disabled/saved above when locking priv->lock */ |
598 | spin_lock(&priv->sta_lock); | 597 | spin_lock(&priv->sta_lock); |
@@ -637,6 +636,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
637 | /* Set up driver data for this TFD */ | 636 | /* Set up driver data for this TFD */ |
638 | memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); | 637 | memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); |
639 | txq->txb[q->write_ptr].skb = skb; | 638 | txq->txb[q->write_ptr].skb = skb; |
639 | txq->txb[q->write_ptr].ctx = ctx; | ||
640 | 640 | ||
641 | /* Set up first empty entry in queue's array of Tx/cmd buffers */ | 641 | /* Set up first empty entry in queue's array of Tx/cmd buffers */ |
642 | out_cmd = txq->cmd[q->write_ptr]; | 642 | out_cmd = txq->cmd[q->write_ptr]; |
@@ -825,7 +825,7 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv) | |||
825 | /* Tx queues */ | 825 | /* Tx queues */ |
826 | if (priv->txq) { | 826 | if (priv->txq) { |
827 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) | 827 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) |
828 | if (txq_id == IWL_CMD_QUEUE_NUM) | 828 | if (txq_id == priv->cmd_queue) |
829 | iwl_cmd_queue_free(priv); | 829 | iwl_cmd_queue_free(priv); |
830 | else | 830 | else |
831 | iwl_tx_queue_free(priv, txq_id); | 831 | iwl_tx_queue_free(priv, txq_id); |
@@ -882,9 +882,9 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv) | |||
882 | 882 | ||
883 | spin_unlock_irqrestore(&priv->lock, flags); | 883 | spin_unlock_irqrestore(&priv->lock, flags); |
884 | 884 | ||
885 | /* Alloc and init all Tx queues, including the command queue (#4) */ | 885 | /* Alloc and init all Tx queues, including the command queue (#4/#9) */ |
886 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { | 886 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { |
887 | slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? | 887 | slots_num = (txq_id == priv->cmd_queue) ? |
888 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; | 888 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; |
889 | ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, | 889 | ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, |
890 | txq_id); | 890 | txq_id); |
@@ -922,7 +922,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv) | |||
922 | 922 | ||
923 | /* Alloc and init all Tx queues, including the command queue (#4) */ | 923 | /* Alloc and init all Tx queues, including the command queue (#4) */ |
924 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { | 924 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { |
925 | slots_num = txq_id == IWL_CMD_QUEUE_NUM ? | 925 | slots_num = txq_id == priv->cmd_queue ? |
926 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; | 926 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; |
927 | iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id); | 927 | iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id); |
928 | } | 928 | } |
@@ -980,7 +980,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
980 | unsigned long flags; | 980 | unsigned long flags; |
981 | struct iwl_tid_data *tid_data; | 981 | struct iwl_tid_data *tid_data; |
982 | 982 | ||
983 | tx_fifo = get_fifo_from_tid(tid); | 983 | tx_fifo = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid); |
984 | if (unlikely(tx_fifo < 0)) | 984 | if (unlikely(tx_fifo < 0)) |
985 | return tx_fifo; | 985 | return tx_fifo; |
986 | 986 | ||
@@ -1041,7 +1041,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1041 | int write_ptr, read_ptr; | 1041 | int write_ptr, read_ptr; |
1042 | unsigned long flags; | 1042 | unsigned long flags; |
1043 | 1043 | ||
1044 | tx_fifo_id = get_fifo_from_tid(tid); | 1044 | tx_fifo_id = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid); |
1045 | if (unlikely(tx_fifo_id < 0)) | 1045 | if (unlikely(tx_fifo_id < 0)) |
1046 | return tx_fifo_id; | 1046 | return tx_fifo_id; |
1047 | 1047 | ||
@@ -1116,6 +1116,9 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1116 | struct iwl_queue *q = &priv->txq[txq_id].q; | 1116 | struct iwl_queue *q = &priv->txq[txq_id].q; |
1117 | u8 *addr = priv->stations[sta_id].sta.sta.addr; | 1117 | u8 *addr = priv->stations[sta_id].sta.sta.addr; |
1118 | struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; | 1118 | struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; |
1119 | struct iwl_rxon_context *ctx; | ||
1120 | |||
1121 | ctx = &priv->contexts[priv->stations[sta_id].ctxid]; | ||
1119 | 1122 | ||
1120 | lockdep_assert_held(&priv->sta_lock); | 1123 | lockdep_assert_held(&priv->sta_lock); |
1121 | 1124 | ||
@@ -1126,12 +1129,12 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1126 | if ((txq_id == tid_data->agg.txq_id) && | 1129 | if ((txq_id == tid_data->agg.txq_id) && |
1127 | (q->read_ptr == q->write_ptr)) { | 1130 | (q->read_ptr == q->write_ptr)) { |
1128 | u16 ssn = SEQ_TO_SN(tid_data->seq_number); | 1131 | u16 ssn = SEQ_TO_SN(tid_data->seq_number); |
1129 | int tx_fifo = get_fifo_from_tid(tid); | 1132 | int tx_fifo = get_fifo_from_tid(ctx, tid); |
1130 | IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); | 1133 | IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); |
1131 | priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, | 1134 | priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, |
1132 | ssn, tx_fifo); | 1135 | ssn, tx_fifo); |
1133 | tid_data->agg.state = IWL_AGG_OFF; | 1136 | tid_data->agg.state = IWL_AGG_OFF; |
1134 | ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid); | 1137 | ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); |
1135 | } | 1138 | } |
1136 | break; | 1139 | break; |
1137 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | 1140 | case IWL_EMPTYING_HW_QUEUE_ADDBA: |
@@ -1139,7 +1142,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1139 | if (tid_data->tfds_in_queue == 0) { | 1142 | if (tid_data->tfds_in_queue == 0) { |
1140 | IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); | 1143 | IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); |
1141 | tid_data->agg.state = IWL_AGG_ON; | 1144 | tid_data->agg.state = IWL_AGG_ON; |
1142 | ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid); | 1145 | ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid); |
1143 | } | 1146 | } |
1144 | break; | 1147 | break; |
1145 | } | 1148 | } |
@@ -1147,14 +1150,14 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1147 | return 0; | 1150 | return 0; |
1148 | } | 1151 | } |
1149 | 1152 | ||
1150 | static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb) | 1153 | static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info) |
1151 | { | 1154 | { |
1152 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 1155 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data; |
1153 | struct ieee80211_sta *sta; | 1156 | struct ieee80211_sta *sta; |
1154 | struct iwl_station_priv *sta_priv; | 1157 | struct iwl_station_priv *sta_priv; |
1155 | 1158 | ||
1156 | rcu_read_lock(); | 1159 | rcu_read_lock(); |
1157 | sta = ieee80211_find_sta(priv->vif, hdr->addr1); | 1160 | sta = ieee80211_find_sta(tx_info->ctx->vif, hdr->addr1); |
1158 | if (sta) { | 1161 | if (sta) { |
1159 | sta_priv = (void *)sta->drv_priv; | 1162 | sta_priv = (void *)sta->drv_priv; |
1160 | /* avoid atomic ops if this isn't a client */ | 1163 | /* avoid atomic ops if this isn't a client */ |
@@ -1164,7 +1167,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb) | |||
1164 | } | 1167 | } |
1165 | rcu_read_unlock(); | 1168 | rcu_read_unlock(); |
1166 | 1169 | ||
1167 | ieee80211_tx_status_irqsafe(priv->hw, skb); | 1170 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb); |
1168 | } | 1171 | } |
1169 | 1172 | ||
1170 | int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | 1173 | int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) |
@@ -1187,7 +1190,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | |||
1187 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 1190 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { |
1188 | 1191 | ||
1189 | tx_info = &txq->txb[txq->q.read_ptr]; | 1192 | tx_info = &txq->txb[txq->q.read_ptr]; |
1190 | iwlagn_tx_status(priv, tx_info->skb); | 1193 | iwlagn_tx_status(priv, tx_info); |
1191 | 1194 | ||
1192 | hdr = (struct ieee80211_hdr *)tx_info->skb->data; | 1195 | hdr = (struct ieee80211_hdr *)tx_info->skb->data; |
1193 | if (hdr && ieee80211_is_data_qos(hdr->frame_control)) | 1196 | if (hdr && ieee80211_is_data_qos(hdr->frame_control)) |