]>
Commit | Line | Data |
---|---|---|
b74db2ac GKH |
1 | From 05e5a7e58d3f8f597ebe6f78aaa13a2656b78239 Mon Sep 17 00:00:00 2001 |
2 | From: Johannes Berg <johannes.berg@intel.com> | |
3 | Date: Fri, 2 Dec 2016 10:04:49 +0100 | |
4 | Subject: iwlwifi: mvm/pcie: adjust A-MSDU tx_cmd length in PCIe | |
5 | ||
6 | From: Johannes Berg <johannes.berg@intel.com> | |
7 | ||
8 | commit 05e5a7e58d3f8f597ebe6f78aaa13a2656b78239 upstream. | |
9 | ||
10 | Instead of setting the tx_cmd length in the mvm code, which is | |
11 | complicated by the fact that DQA may want to temporarily store | |
12 | the SKB on the side, adjust the length in the PCIe code which | |
13 | also knows about this since it's responsible for duplicating | |
14 | all those headers that are account for in this code. | |
15 | ||
16 | As the PCIe code already relies on the tx_cmd->len field, this | |
17 | doesn't really introduce any new dependencies. | |
18 | ||
19 | To make this possible we need to move the memcpy() of the TX | |
20 | command until after it was updated. | |
21 | ||
22 | This does even simplify the code though, since the PCIe code | |
23 | already does a lot of manipulations to build A-MSDUs correctly | |
24 | and changing the length becomes a simple operation to see how | |
25 | much was added/removed, rather than predicting it. | |
26 | ||
27 | Fixes: 24afba7690e4 ("iwlwifi: mvm: support bss dynamic alloc/dealloc of queues") | |
28 | Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
29 | Signed-off-by: Luca Coelho <luciano.coelho@intel.com> | |
30 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
31 | ||
32 | --- | |
33 | drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 38 ++------------------------- | |
34 | drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 23 +++++++++++++--- | |
35 | 2 files changed, 22 insertions(+), 39 deletions(-) | |
36 | ||
37 | --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c | |
38 | +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c | |
39 | @@ -202,7 +202,6 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm * | |
40 | struct iwl_tx_cmd *tx_cmd, | |
41 | struct ieee80211_tx_info *info, u8 sta_id) | |
42 | { | |
43 | - struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb); | |
44 | struct ieee80211_hdr *hdr = (void *)skb->data; | |
45 | __le16 fc = hdr->frame_control; | |
46 | u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); | |
47 | @@ -284,9 +283,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm * | |
48 | tx_flags |= TX_CMD_FLG_WRITE_TX_POWER; | |
49 | ||
50 | tx_cmd->tx_flags = cpu_to_le32(tx_flags); | |
51 | - /* Total # bytes to be transmitted */ | |
52 | - tx_cmd->len = cpu_to_le16((u16)skb->len + | |
53 | - (uintptr_t)skb_info->driver_data[0]); | |
54 | + /* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */ | |
55 | + tx_cmd->len = cpu_to_le16((u16)skb->len); | |
56 | tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); | |
57 | tx_cmd->sta_id = sta_id; | |
58 | ||
59 | @@ -555,9 +553,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mv | |
60 | info.hw_queue != info.control.vif->cab_queue))) | |
61 | return -1; | |
62 | ||
63 | - /* This holds the amsdu headers length */ | |
64 | - skb_info->driver_data[0] = (void *)(uintptr_t)0; | |
65 | - | |
66 | queue = info.hw_queue; | |
67 | ||
68 | /* | |
69 | @@ -644,7 +639,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm | |
70 | unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len; | |
71 | bool ipv4 = (skb->protocol == htons(ETH_P_IP)); | |
72 | u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; | |
73 | - u16 amsdu_add, snap_ip_tcp, pad, i = 0; | |
74 | + u16 snap_ip_tcp, pad, i = 0; | |
75 | unsigned int dbg_max_amsdu_len; | |
76 | netdev_features_t netdev_features = NETIF_F_CSUM_MASK | NETIF_F_SG; | |
77 | u8 *qc, tid, txf; | |
78 | @@ -746,21 +741,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm | |
79 | ||
80 | /* This skb fits in one single A-MSDU */ | |
81 | if (num_subframes * mss >= tcp_payload_len) { | |
82 | - struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb); | |
83 | - | |
84 | - /* | |
85 | - * Compute the length of all the data added for the A-MSDU. | |
86 | - * This will be used to compute the length to write in the TX | |
87 | - * command. We have: SNAP + IP + TCP for n -1 subframes and | |
88 | - * ETH header for n subframes. Note that the original skb | |
89 | - * already had one set of SNAP / IP / TCP headers. | |
90 | - */ | |
91 | - num_subframes = DIV_ROUND_UP(tcp_payload_len, mss); | |
92 | - amsdu_add = num_subframes * sizeof(struct ethhdr) + | |
93 | - (num_subframes - 1) * (snap_ip_tcp + pad); | |
94 | - /* This holds the amsdu headers length */ | |
95 | - skb_info->driver_data[0] = (void *)(uintptr_t)amsdu_add; | |
96 | - | |
97 | __skb_queue_tail(mpdus_skb, skb); | |
98 | return 0; | |
99 | } | |
100 | @@ -799,14 +779,6 @@ segment: | |
101 | ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes); | |
102 | ||
103 | if (tcp_payload_len > mss) { | |
104 | - struct ieee80211_tx_info *skb_info = | |
105 | - IEEE80211_SKB_CB(tmp); | |
106 | - | |
107 | - num_subframes = DIV_ROUND_UP(tcp_payload_len, mss); | |
108 | - amsdu_add = num_subframes * sizeof(struct ethhdr) + | |
109 | - (num_subframes - 1) * (snap_ip_tcp + pad); | |
110 | - skb_info->driver_data[0] = | |
111 | - (void *)(uintptr_t)amsdu_add; | |
112 | skb_shinfo(tmp)->gso_size = mss; | |
113 | } else { | |
114 | qc = ieee80211_get_qos_ctl((void *)tmp->data); | |
115 | @@ -1052,7 +1024,6 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, | |
116 | struct ieee80211_sta *sta) | |
117 | { | |
118 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | |
119 | - struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb); | |
120 | struct ieee80211_tx_info info; | |
121 | struct sk_buff_head mpdus_skbs; | |
122 | unsigned int payload_len; | |
123 | @@ -1066,9 +1037,6 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, | |
124 | ||
125 | memcpy(&info, skb->cb, sizeof(info)); | |
126 | ||
127 | - /* This holds the amsdu headers length */ | |
128 | - skb_info->driver_data[0] = (void *)(uintptr_t)0; | |
129 | - | |
130 | if (!skb_is_gso(skb)) | |
131 | return iwl_mvm_tx_mpdu(mvm, skb, &info, sta); | |
132 | ||
133 | --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c | |
134 | +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c | |
135 | @@ -2096,6 +2096,7 @@ static int iwl_fill_data_tbs_amsdu(struc | |
136 | struct iwl_cmd_meta *out_meta, | |
137 | struct iwl_device_cmd *dev_cmd, u16 tb1_len) | |
138 | { | |
139 | + struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; | |
140 | struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; | |
141 | struct ieee80211_hdr *hdr = (void *)skb->data; | |
142 | unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; | |
143 | @@ -2145,6 +2146,13 @@ static int iwl_fill_data_tbs_amsdu(struc | |
144 | */ | |
145 | skb_pull(skb, hdr_len + iv_len); | |
146 | ||
147 | + /* | |
148 | + * Remove the length of all the headers that we don't actually | |
149 | + * have in the MPDU by themselves, but that we duplicate into | |
150 | + * all the different MSDUs inside the A-MSDU. | |
151 | + */ | |
152 | + le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); | |
153 | + | |
154 | tso_start(skb, &tso); | |
155 | ||
156 | while (total_len) { | |
157 | @@ -2155,7 +2163,7 @@ static int iwl_fill_data_tbs_amsdu(struc | |
158 | unsigned int hdr_tb_len; | |
159 | dma_addr_t hdr_tb_phys; | |
160 | struct tcphdr *tcph; | |
161 | - u8 *iph; | |
162 | + u8 *iph, *subf_hdrs_start = hdr_page->pos; | |
163 | ||
164 | total_len -= data_left; | |
165 | ||
166 | @@ -2216,6 +2224,8 @@ static int iwl_fill_data_tbs_amsdu(struc | |
167 | hdr_tb_len, false); | |
168 | trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, | |
169 | hdr_tb_len); | |
170 | + /* add this subframe's headers' length to the tx_cmd */ | |
171 | + le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); | |
172 | ||
173 | /* prepare the start_hdr for the next subframe */ | |
174 | start_hdr = hdr_page->pos; | |
175 | @@ -2408,9 +2418,10 @@ int iwl_trans_pcie_tx(struct iwl_trans * | |
176 | tb1_len = len; | |
177 | } | |
178 | ||
179 | - /* The first TB points to bi-directional DMA data */ | |
180 | - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, | |
181 | - IWL_FIRST_TB_SIZE); | |
182 | + /* | |
183 | + * The first TB points to bi-directional DMA data, we'll | |
184 | + * memcpy the data into it later. | |
185 | + */ | |
186 | iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, | |
187 | IWL_FIRST_TB_SIZE, true); | |
188 | ||
189 | @@ -2434,6 +2445,10 @@ int iwl_trans_pcie_tx(struct iwl_trans * | |
190 | goto out_err; | |
191 | } | |
192 | ||
193 | + /* building the A-MSDU might have changed this data, so memcpy it now */ | |
194 | + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, | |
195 | + IWL_FIRST_TB_SIZE); | |
196 | + | |
197 | tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); | |
198 | /* Set up entry for this TFD in Tx byte-count array */ | |
199 | iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len), |