Skip to content

Commit e37a918

Browse files
author
Kalle Valo
committed
Merge tag 'ath-current-20240812' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath
ath.git patch for v6.11 We have a single patch for the next 6.11-rc which introduces a workaround to ath12k which addresses a WCN7850 hardware issue that prevents proper operation with unaligned transmit buffers.
2 parents 38c8d02 + 3805578 commit e37a918

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

drivers/net/wireless/ath/ath12k/dp_tx.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
165219
int 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);

drivers/net/wireless/ath/ath12k/hw.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
924924

925925
.acpi_guid = NULL,
926926
.supports_dynamic_smps_6ghz = true,
927+
928+
.iova_mask = 0,
927929
},
928930
{
929931
.name = "wcn7850 hw2.0",
@@ -1000,6 +1002,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
10001002

10011003
.acpi_guid = &wcn7850_uuid,
10021004
.supports_dynamic_smps_6ghz = false,
1005+
1006+
.iova_mask = ATH12K_PCIE_MAX_PAYLOAD_SIZE - 1,
10031007
},
10041008
{
10051009
.name = "qcn9274 hw2.0",
@@ -1072,6 +1076,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
10721076

10731077
.acpi_guid = NULL,
10741078
.supports_dynamic_smps_6ghz = true,
1079+
1080+
.iova_mask = 0,
10751081
},
10761082
};
10771083

drivers/net/wireless/ath/ath12k/hw.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
#define ATH12K_M3_FILE "m3.bin"
9797
#define ATH12K_REGDB_FILE_NAME "regdb.bin"
9898

99+
#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128
100+
99101
enum ath12k_hw_rate_cck {
100102
ATH12K_HW_RATE_CCK_LP_11M = 0,
101103
ATH12K_HW_RATE_CCK_LP_5_5M,
@@ -215,6 +217,8 @@ struct ath12k_hw_params {
215217

216218
const guid_t *acpi_guid;
217219
bool supports_dynamic_smps_6ghz;
220+
221+
u32 iova_mask;
218222
};
219223

220224
struct ath12k_hw_ops {

drivers/net/wireless/ath/ath12k/mac.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9193,6 +9193,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
91939193

91949194
hw->vif_data_size = sizeof(struct ath12k_vif);
91959195
hw->sta_data_size = sizeof(struct ath12k_sta);
9196+
hw->extra_tx_headroom = ab->hw_params->iova_mask;
91969197

91979198
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
91989199
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);

0 commit comments

Comments
 (0)