aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2016-12-02 04:04:49 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-14 08:00:16 -0400
commit48aa5ec292f3eba8f22a5b4d3a8eee123e7680dc (patch)
treeb9b46b4eed354e1e6999874e1a0d593666bf3590
parent04dd401a5145da42a040a622bac2eb9a96c01308 (diff)
iwlwifi: mvm/pcie: adjust A-MSDU tx_cmd length in PCIe
commit 05e5a7e58d3f8f597ebe6f78aaa13a2656b78239 upstream. Instead of setting the tx_cmd length in the mvm code, which is complicated by the fact that DQA may want to temporarily store the SKB on the side, adjust the length in the PCIe code which also knows about this since it's responsible for duplicating all those headers that are account for in this code. As the PCIe code already relies on the tx_cmd->len field, this doesn't really introduce any new dependencies. To make this possible we need to move the memcpy() of the TX command until after it was updated. This does even simplify the code though, since the PCIe code already does a lot of manipulations to build A-MSDUs correctly and changing the length becomes a simple operation to see how much was added/removed, rather than predicting it. Fixes: 24afba7690e4 ("iwlwifi: mvm: support bss dynamic alloc/dealloc of queues") Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c38
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c23
2 files changed, 22 insertions, 39 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index e129661e4d99..1d116c06cd1c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -202,7 +202,6 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
202 struct iwl_tx_cmd *tx_cmd, 202 struct iwl_tx_cmd *tx_cmd,
203 struct ieee80211_tx_info *info, u8 sta_id) 203 struct ieee80211_tx_info *info, u8 sta_id)
204{ 204{
205 struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
206 struct ieee80211_hdr *hdr = (void *)skb->data; 205 struct ieee80211_hdr *hdr = (void *)skb->data;
207 __le16 fc = hdr->frame_control; 206 __le16 fc = hdr->frame_control;
208 u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); 207 u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags);
@@ -284,9 +283,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
284 tx_flags |= TX_CMD_FLG_WRITE_TX_POWER; 283 tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
285 284
286 tx_cmd->tx_flags = cpu_to_le32(tx_flags); 285 tx_cmd->tx_flags = cpu_to_le32(tx_flags);
287 /* Total # bytes to be transmitted */ 286 /* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */
288 tx_cmd->len = cpu_to_le16((u16)skb->len + 287 tx_cmd->len = cpu_to_le16((u16)skb->len);
289 (uintptr_t)skb_info->driver_data[0]);
290 tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); 288 tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
291 tx_cmd->sta_id = sta_id; 289 tx_cmd->sta_id = sta_id;
292 290
@@ -555,9 +553,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
555 info.hw_queue != info.control.vif->cab_queue))) 553 info.hw_queue != info.control.vif->cab_queue)))
556 return -1; 554 return -1;
557 555
558 /* This holds the amsdu headers length */
559 skb_info->driver_data[0] = (void *)(uintptr_t)0;
560
561 queue = info.hw_queue; 556 queue = info.hw_queue;
562 557
563 /* 558 /*
@@ -644,7 +639,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
644 unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len; 639 unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
645 bool ipv4 = (skb->protocol == htons(ETH_P_IP)); 640 bool ipv4 = (skb->protocol == htons(ETH_P_IP));
646 u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; 641 u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
647 u16 amsdu_add, snap_ip_tcp, pad, i = 0; 642 u16 snap_ip_tcp, pad, i = 0;
648 unsigned int dbg_max_amsdu_len; 643 unsigned int dbg_max_amsdu_len;
649 netdev_features_t netdev_features = NETIF_F_CSUM_MASK | NETIF_F_SG; 644 netdev_features_t netdev_features = NETIF_F_CSUM_MASK | NETIF_F_SG;
650 u8 *qc, tid, txf; 645 u8 *qc, tid, txf;
@@ -746,21 +741,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
746 741
747 /* This skb fits in one single A-MSDU */ 742 /* This skb fits in one single A-MSDU */
748 if (num_subframes * mss >= tcp_payload_len) { 743 if (num_subframes * mss >= tcp_payload_len) {
749 struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
750
751 /*
752 * Compute the length of all the data added for the A-MSDU.
753 * This will be used to compute the length to write in the TX
754 * command. We have: SNAP + IP + TCP for n -1 subframes and
755 * ETH header for n subframes. Note that the original skb
756 * already had one set of SNAP / IP / TCP headers.
757 */
758 num_subframes = DIV_ROUND_UP(tcp_payload_len, mss);
759 amsdu_add = num_subframes * sizeof(struct ethhdr) +
760 (num_subframes - 1) * (snap_ip_tcp + pad);
761 /* This holds the amsdu headers length */
762 skb_info->driver_data[0] = (void *)(uintptr_t)amsdu_add;
763
764 __skb_queue_tail(mpdus_skb, skb); 744 __skb_queue_tail(mpdus_skb, skb);
765 return 0; 745 return 0;
766 } 746 }
@@ -799,14 +779,6 @@ segment:
799 ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes); 779 ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
800 780
801 if (tcp_payload_len > mss) { 781 if (tcp_payload_len > mss) {
802 struct ieee80211_tx_info *skb_info =
803 IEEE80211_SKB_CB(tmp);
804
805 num_subframes = DIV_ROUND_UP(tcp_payload_len, mss);
806 amsdu_add = num_subframes * sizeof(struct ethhdr) +
807 (num_subframes - 1) * (snap_ip_tcp + pad);
808 skb_info->driver_data[0] =
809 (void *)(uintptr_t)amsdu_add;
810 skb_shinfo(tmp)->gso_size = mss; 782 skb_shinfo(tmp)->gso_size = mss;
811 } else { 783 } else {
812 qc = ieee80211_get_qos_ctl((void *)tmp->data); 784 qc = ieee80211_get_qos_ctl((void *)tmp->data);
@@ -1052,7 +1024,6 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
1052 struct ieee80211_sta *sta) 1024 struct ieee80211_sta *sta)
1053{ 1025{
1054 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1026 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1055 struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
1056 struct ieee80211_tx_info info; 1027 struct ieee80211_tx_info info;
1057 struct sk_buff_head mpdus_skbs; 1028 struct sk_buff_head mpdus_skbs;
1058 unsigned int payload_len; 1029 unsigned int payload_len;
@@ -1066,9 +1037,6 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
1066 1037
1067 memcpy(&info, skb->cb, sizeof(info)); 1038 memcpy(&info, skb->cb, sizeof(info));
1068 1039
1069 /* This holds the amsdu headers length */
1070 skb_info->driver_data[0] = (void *)(uintptr_t)0;
1071
1072 if (!skb_is_gso(skb)) 1040 if (!skb_is_gso(skb))
1073 return iwl_mvm_tx_mpdu(mvm, skb, &info, sta); 1041 return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
1074 1042
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 5f840f16f40b..e1bfc9522cbe 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -2096,6 +2096,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
2096 struct iwl_cmd_meta *out_meta, 2096 struct iwl_cmd_meta *out_meta,
2097 struct iwl_device_cmd *dev_cmd, u16 tb1_len) 2097 struct iwl_device_cmd *dev_cmd, u16 tb1_len)
2098{ 2098{
2099 struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload;
2099 struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; 2100 struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
2100 struct ieee80211_hdr *hdr = (void *)skb->data; 2101 struct ieee80211_hdr *hdr = (void *)skb->data;
2101 unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; 2102 unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
@@ -2145,6 +2146,13 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
2145 */ 2146 */
2146 skb_pull(skb, hdr_len + iv_len); 2147 skb_pull(skb, hdr_len + iv_len);
2147 2148
2149 /*
2150 * Remove the length of all the headers that we don't actually
2151 * have in the MPDU by themselves, but that we duplicate into
2152 * all the different MSDUs inside the A-MSDU.
2153 */
2154 le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen);
2155
2148 tso_start(skb, &tso); 2156 tso_start(skb, &tso);
2149 2157
2150 while (total_len) { 2158 while (total_len) {
@@ -2155,7 +2163,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
2155 unsigned int hdr_tb_len; 2163 unsigned int hdr_tb_len;
2156 dma_addr_t hdr_tb_phys; 2164 dma_addr_t hdr_tb_phys;
2157 struct tcphdr *tcph; 2165 struct tcphdr *tcph;
2158 u8 *iph; 2166 u8 *iph, *subf_hdrs_start = hdr_page->pos;
2159 2167
2160 total_len -= data_left; 2168 total_len -= data_left;
2161 2169
@@ -2216,6 +2224,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
2216 hdr_tb_len, false); 2224 hdr_tb_len, false);
2217 trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, 2225 trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr,
2218 hdr_tb_len); 2226 hdr_tb_len);
2227 /* add this subframe's headers' length to the tx_cmd */
2228 le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
2219 2229
2220 /* prepare the start_hdr for the next subframe */ 2230 /* prepare the start_hdr for the next subframe */
2221 start_hdr = hdr_page->pos; 2231 start_hdr = hdr_page->pos;
@@ -2408,9 +2418,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
2408 tb1_len = len; 2418 tb1_len = len;
2409 } 2419 }
2410 2420
2411 /* The first TB points to bi-directional DMA data */ 2421 /*
2412 memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, 2422 * The first TB points to bi-directional DMA data, we'll
2413 IWL_FIRST_TB_SIZE); 2423 * memcpy the data into it later.
2424 */
2414 iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, 2425 iwl_pcie_txq_build_tfd(trans, txq, tb0_phys,
2415 IWL_FIRST_TB_SIZE, true); 2426 IWL_FIRST_TB_SIZE, true);
2416 2427
@@ -2434,6 +2445,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
2434 goto out_err; 2445 goto out_err;
2435 } 2446 }
2436 2447
2448 /* building the A-MSDU might have changed this data, so memcpy it now */
2449 memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,
2450 IWL_FIRST_TB_SIZE);
2451
2437 tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); 2452 tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr);
2438 /* Set up entry for this TFD in Tx byte-count array */ 2453 /* Set up entry for this TFD in Tx byte-count array */
2439 iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len), 2454 iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len),