@@ -162,6 +162,60 @@ static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb)
162162 return 0 ;
163163}
164164
165+ static void ath12k_dp_tx_move_payload (struct sk_buff * skb ,
166+ unsigned long delta ,
167+ bool head )
168+ {
169+ unsigned long len = skb -> len ;
170+
171+ if (head ) {
172+ skb_push (skb , delta );
173+ memmove (skb -> data , skb -> data + delta , len );
174+ skb_trim (skb , len );
175+ } else {
176+ skb_put (skb , delta );
177+ memmove (skb -> data + delta , skb -> data , len );
178+ skb_pull (skb , delta );
179+ }
180+ }
181+
182+ static int ath12k_dp_tx_align_payload (struct ath12k_base * ab ,
183+ struct sk_buff * * pskb )
184+ {
185+ u32 iova_mask = ab -> hw_params -> iova_mask ;
186+ unsigned long offset , delta1 , delta2 ;
187+ struct sk_buff * skb2 , * skb = * pskb ;
188+ unsigned int headroom = skb_headroom (skb );
189+ int tailroom = skb_tailroom (skb );
190+ int ret = 0 ;
191+
192+ offset = (unsigned long )skb -> data & iova_mask ;
193+ delta1 = offset ;
194+ delta2 = iova_mask - offset + 1 ;
195+
196+ if (headroom >= delta1 ) {
197+ ath12k_dp_tx_move_payload (skb , delta1 , true);
198+ } else if (tailroom >= delta2 ) {
199+ ath12k_dp_tx_move_payload (skb , delta2 , false);
200+ } else {
201+ skb2 = skb_realloc_headroom (skb , iova_mask );
202+ if (!skb2 ) {
203+ ret = - ENOMEM ;
204+ goto out ;
205+ }
206+
207+ dev_kfree_skb_any (skb );
208+
209+ offset = (unsigned long )skb2 -> data & iova_mask ;
210+ if (offset )
211+ ath12k_dp_tx_move_payload (skb2 , offset , true);
212+ * pskb = skb2 ;
213+ }
214+
215+ out :
216+ return ret ;
217+ }
218+
165219int ath12k_dp_tx (struct ath12k * ar , struct ath12k_vif * arvif ,
166220 struct sk_buff * skb )
167221{
@@ -184,6 +238,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
184238 bool tcl_ring_retry ;
185239 bool msdu_ext_desc = false;
186240 bool add_htt_metadata = false;
241+ u32 iova_mask = ab -> hw_params -> iova_mask ;
187242
188243 if (test_bit (ATH12K_FLAG_CRASH_FLUSH , & ar -> ab -> dev_flags ))
189244 return - ESHUTDOWN ;
@@ -279,6 +334,23 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
279334 goto fail_remove_tx_buf ;
280335 }
281336
337+ if (iova_mask &&
338+ (unsigned long )skb -> data & iova_mask ) {
339+ ret = ath12k_dp_tx_align_payload (ab , & skb );
340+ if (ret ) {
341+ ath12k_warn (ab , "failed to align TX buffer %d\n" , ret );
342+ /* don't bail out, give original buffer
343+ * a chance even unaligned.
344+ */
345+ goto map ;
346+ }
347+
348+ /* hdr is pointing to a wrong place after alignment,
349+ * so refresh it for later use.
350+ */
351+ hdr = (void * )skb -> data ;
352+ }
353+ map :
282354 ti .paddr = dma_map_single (ab -> dev , skb -> data , skb -> len , DMA_TO_DEVICE );
283355 if (dma_mapping_error (ab -> dev , ti .paddr )) {
284356 atomic_inc (& ab -> soc_stats .tx_err .misc_fail );
0 commit comments