Skip to content

Commit

Permalink
wifi: ath12k: use 128 bytes aligned iova in transmit path for WCN7850
Browse files Browse the repository at this point in the history
In transmit path, it is likely that the iova is not aligned to PCIe TLP
max payload size, which is 128 for WCN7850. Normally in such cases hardware
is expected to split the packet into several parts in a manner such that
they, other than the first one, have aligned iova. However due to hardware
limitations, WCN7850 does not behave like that properly with some specific
unaligned iova in transmit path. This easily results in target hang in a
KPI transmit test: packet send/receive failure, WMI command send timeout
etc. Also fatal error seen in PCIe level:

	...
	Capabilities: ...
		...
		DevSta: ... FatalErr+ ...
		...
	...

Work around this by manually moving/reallocating payload buffer such that
we can map it to a 128 bytes aligned iova. The moving requires sufficient
head room or tail room in skb: for the former we can do ourselves a favor
by asking some extra bytes when registering with mac80211, while for the
latter we can do nothing.

Moving/reallocating buffer consumes additional CPU cycles, but the good news
is that an aligned iova increases PCIe efficiency. In my tests on some X86
platforms the KPI results are almost consistent.

Since this is seen only with WCN7850, add a new hardware parameter to
differentiate from others.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Cc: <stable@vger.kernel.org>
Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://patch.msgid.link/20240715023814.20242-1-quic_bqiang@quicinc.com
  • Loading branch information
Baochen Qiang authored and Kalle Valo committed Aug 5, 2024
1 parent de9c2c6 commit 3805578
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 0 deletions.
72 changes: 72 additions & 0 deletions drivers/net/wireless/ath/ath12k/dp_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,60 @@ static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb)
return 0;
}

static void ath12k_dp_tx_move_payload(struct sk_buff *skb,
unsigned long delta,
bool head)
{
unsigned long len = skb->len;

if (head) {
skb_push(skb, delta);
memmove(skb->data, skb->data + delta, len);
skb_trim(skb, len);
} else {
skb_put(skb, delta);
memmove(skb->data + delta, skb->data, len);
skb_pull(skb, delta);
}
}

static int ath12k_dp_tx_align_payload(struct ath12k_base *ab,
struct sk_buff **pskb)
{
u32 iova_mask = ab->hw_params->iova_mask;
unsigned long offset, delta1, delta2;
struct sk_buff *skb2, *skb = *pskb;
unsigned int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
int ret = 0;

offset = (unsigned long)skb->data & iova_mask;
delta1 = offset;
delta2 = iova_mask - offset + 1;

if (headroom >= delta1) {
ath12k_dp_tx_move_payload(skb, delta1, true);
} else if (tailroom >= delta2) {
ath12k_dp_tx_move_payload(skb, delta2, false);
} else {
skb2 = skb_realloc_headroom(skb, iova_mask);
if (!skb2) {
ret = -ENOMEM;
goto out;
}

dev_kfree_skb_any(skb);

offset = (unsigned long)skb2->data & iova_mask;
if (offset)
ath12k_dp_tx_move_payload(skb2, offset, true);
*pskb = skb2;
}

out:
return ret;
}

int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
struct sk_buff *skb)
{
Expand All @@ -184,6 +238,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
bool tcl_ring_retry;
bool msdu_ext_desc = false;
bool add_htt_metadata = false;
u32 iova_mask = ab->hw_params->iova_mask;

if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN;
Expand Down Expand Up @@ -279,6 +334,23 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
goto fail_remove_tx_buf;
}

if (iova_mask &&
(unsigned long)skb->data & iova_mask) {
ret = ath12k_dp_tx_align_payload(ab, &skb);
if (ret) {
ath12k_warn(ab, "failed to align TX buffer %d\n", ret);
/* don't bail out, give original buffer
* a chance even unaligned.
*/
goto map;
}

/* hdr is pointing to a wrong place after alignment,
* so refresh it for later use.
*/
hdr = (void *)skb->data;
}
map:
ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
if (dma_mapping_error(ab->dev, ti.paddr)) {
atomic_inc(&ab->soc_stats.tx_err.misc_fail);
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/ath/ath12k/hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {

.acpi_guid = NULL,
.supports_dynamic_smps_6ghz = true,

.iova_mask = 0,
},
{
.name = "wcn7850 hw2.0",
Expand Down Expand Up @@ -1000,6 +1002,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {

.acpi_guid = &wcn7850_uuid,
.supports_dynamic_smps_6ghz = false,

.iova_mask = ATH12K_PCIE_MAX_PAYLOAD_SIZE - 1,
},
{
.name = "qcn9274 hw2.0",
Expand Down Expand Up @@ -1072,6 +1076,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {

.acpi_guid = NULL,
.supports_dynamic_smps_6ghz = true,

.iova_mask = 0,
},
};

Expand Down
4 changes: 4 additions & 0 deletions drivers/net/wireless/ath/ath12k/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
#define ATH12K_M3_FILE "m3.bin"
#define ATH12K_REGDB_FILE_NAME "regdb.bin"

#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128

enum ath12k_hw_rate_cck {
ATH12K_HW_RATE_CCK_LP_11M = 0,
ATH12K_HW_RATE_CCK_LP_5_5M,
Expand Down Expand Up @@ -215,6 +217,8 @@ struct ath12k_hw_params {

const guid_t *acpi_guid;
bool supports_dynamic_smps_6ghz;

u32 iova_mask;
};

struct ath12k_hw_ops {
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath12k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -9193,6 +9193,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)

hw->vif_data_size = sizeof(struct ath12k_vif);
hw->sta_data_size = sizeof(struct ath12k_sta);
hw->extra_tx_headroom = ab->hw_params->iova_mask;

wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
Expand Down

0 comments on commit 3805578

Please sign in to comment.