Commit b2ca1661 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'wireless-2024-08-14' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless

Kalle Valo says:

====================
wireless fixes for v6.11

We have few fixes to drivers. The most important here is a fix for
iwlwifi which caused major slowdowns for several users.

* tag 'wireless-2024-08-14' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless:
  wifi: iwlwifi: correctly lookup DMA address in SG table
  wifi: mt76: mt7921: fix NULL pointer access in mt7921_ipv6_addr_change
  wifi: brcmfmac: cfg80211: Handle SSID based pmksa deletion
  wifi: rtlwifi: rtl8192du: Initialise value32 in _rtl92du_init_queue_reserved_page
  wifi: ath12k: use 128 bytes aligned iova in transmit path for WCN7850
====================

Link: https://patch.msgid.link/20240814171606.E14A0C116B1@smtp.kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 6c569b77 e37a9184
...@@ -162,6 +162,60 @@ static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb) ...@@ -162,6 +162,60 @@ static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb)
return 0; 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, int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -184,6 +238,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, ...@@ -184,6 +238,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
bool tcl_ring_retry; bool tcl_ring_retry;
bool msdu_ext_desc = false; bool msdu_ext_desc = false;
bool add_htt_metadata = 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)) if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN; return -ESHUTDOWN;
...@@ -279,6 +334,23 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, ...@@ -279,6 +334,23 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
goto fail_remove_tx_buf; 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); ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
if (dma_mapping_error(ab->dev, ti.paddr)) { if (dma_mapping_error(ab->dev, ti.paddr)) {
atomic_inc(&ab->soc_stats.tx_err.misc_fail); atomic_inc(&ab->soc_stats.tx_err.misc_fail);
......
...@@ -924,6 +924,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { ...@@ -924,6 +924,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.acpi_guid = NULL, .acpi_guid = NULL,
.supports_dynamic_smps_6ghz = true, .supports_dynamic_smps_6ghz = true,
.iova_mask = 0,
}, },
{ {
.name = "wcn7850 hw2.0", .name = "wcn7850 hw2.0",
...@@ -1000,6 +1002,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { ...@@ -1000,6 +1002,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.acpi_guid = &wcn7850_uuid, .acpi_guid = &wcn7850_uuid,
.supports_dynamic_smps_6ghz = false, .supports_dynamic_smps_6ghz = false,
.iova_mask = ATH12K_PCIE_MAX_PAYLOAD_SIZE - 1,
}, },
{ {
.name = "qcn9274 hw2.0", .name = "qcn9274 hw2.0",
...@@ -1072,6 +1076,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { ...@@ -1072,6 +1076,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.acpi_guid = NULL, .acpi_guid = NULL,
.supports_dynamic_smps_6ghz = true, .supports_dynamic_smps_6ghz = true,
.iova_mask = 0,
}, },
}; };
......
...@@ -96,6 +96,8 @@ ...@@ -96,6 +96,8 @@
#define ATH12K_M3_FILE "m3.bin" #define ATH12K_M3_FILE "m3.bin"
#define ATH12K_REGDB_FILE_NAME "regdb.bin" #define ATH12K_REGDB_FILE_NAME "regdb.bin"
#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128
enum ath12k_hw_rate_cck { enum ath12k_hw_rate_cck {
ATH12K_HW_RATE_CCK_LP_11M = 0, ATH12K_HW_RATE_CCK_LP_11M = 0,
ATH12K_HW_RATE_CCK_LP_5_5M, ATH12K_HW_RATE_CCK_LP_5_5M,
...@@ -215,6 +217,8 @@ struct ath12k_hw_params { ...@@ -215,6 +217,8 @@ struct ath12k_hw_params {
const guid_t *acpi_guid; const guid_t *acpi_guid;
bool supports_dynamic_smps_6ghz; bool supports_dynamic_smps_6ghz;
u32 iova_mask;
}; };
struct ath12k_hw_ops { struct ath12k_hw_ops {
......
...@@ -9193,6 +9193,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ...@@ -9193,6 +9193,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
hw->vif_data_size = sizeof(struct ath12k_vif); hw->vif_data_size = sizeof(struct ath12k_vif);
hw->sta_data_size = sizeof(struct ath12k_sta); 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_CQM_RSSI_LIST);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
......
...@@ -4320,9 +4320,16 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa, ...@@ -4320,9 +4320,16 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa,
/* Single PMK operation */ /* Single PMK operation */
pmk_op->count = cpu_to_le16(1); pmk_op->count = cpu_to_le16(1);
length += sizeof(struct brcmf_pmksa_v3); length += sizeof(struct brcmf_pmksa_v3);
if (pmksa->bssid)
memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN); memcpy(pmk_op->pmk[0].bssid, pmksa->bssid, ETH_ALEN);
if (pmksa->pmkid) {
memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN); memcpy(pmk_op->pmk[0].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN; pmk_op->pmk[0].pmkid_len = WLAN_PMKID_LEN;
}
if (pmksa->ssid && pmksa->ssid_len) {
memcpy(pmk_op->pmk[0].ssid.SSID, pmksa->ssid, pmksa->ssid_len);
pmk_op->pmk[0].ssid.SSID_len = pmksa->ssid_len;
}
pmk_op->pmk[0].time_left = cpu_to_le32(alive ? BRCMF_PMKSA_NO_EXPIRY : 0); pmk_op->pmk[0].time_left = cpu_to_le32(alive ? BRCMF_PMKSA_NO_EXPIRY : 0);
} }
......
...@@ -639,7 +639,8 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); ...@@ -639,7 +639,8 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq,
int slots_num, bool cmd_queue); int slots_num, bool cmd_queue);
dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, void *addr); dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset,
unsigned int len);
struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_cmd_meta *cmd_meta, struct iwl_cmd_meta *cmd_meta,
u8 **hdr, unsigned int hdr_room); u8 **hdr, unsigned int hdr_room);
......
...@@ -168,6 +168,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, ...@@ -168,6 +168,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
unsigned int mss = skb_shinfo(skb)->gso_size; unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int data_offset = 0;
dma_addr_t start_hdr_phys; dma_addr_t start_hdr_phys;
u16 length, amsdu_pad; u16 length, amsdu_pad;
u8 *start_hdr; u8 *start_hdr;
...@@ -260,7 +261,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, ...@@ -260,7 +261,8 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
int ret; int ret;
tb_len = min_t(unsigned int, tso.size, data_left); tb_len = min_t(unsigned int, tso.size, data_left);
tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, tso.data); tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, data_offset,
tb_len);
/* Not a real mapping error, use direct comparison */ /* Not a real mapping error, use direct comparison */
if (unlikely(tb_phys == DMA_MAPPING_ERROR)) if (unlikely(tb_phys == DMA_MAPPING_ERROR))
goto out_err; goto out_err;
...@@ -272,6 +274,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans, ...@@ -272,6 +274,7 @@ static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,
goto out_err; goto out_err;
data_left -= tb_len; data_left -= tb_len;
data_offset += tb_len;
tso_build_data(skb, &tso, tb_len); tso_build_data(skb, &tso, tb_len);
} }
} }
......
...@@ -1814,23 +1814,31 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans, ...@@ -1814,23 +1814,31 @@ static void *iwl_pcie_get_page_hdr(struct iwl_trans *trans,
/** /**
* iwl_pcie_get_sgt_tb_phys - Find TB address in mapped SG list * iwl_pcie_get_sgt_tb_phys - Find TB address in mapped SG list
* @sgt: scatter gather table * @sgt: scatter gather table
* @addr: Virtual address * @offset: Offset into the mapped memory (i.e. SKB payload data)
* @len: Length of the area
* *
* Find the entry that includes the address for the given address and return * Find the DMA address that corresponds to the SKB payload data at the
* correct physical address for the TB entry. * position given by @offset.
* *
* Returns: Address for TB entry * Returns: Address for TB entry
*/ */
dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, void *addr) dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset,
unsigned int len)
{ {
struct scatterlist *sg; struct scatterlist *sg;
unsigned int sg_offset = 0;
int i; int i;
/*
* Search the mapped DMA areas in the SG for the area that contains the
* data at offset with the given length.
*/
for_each_sgtable_dma_sg(sgt, sg, i) { for_each_sgtable_dma_sg(sgt, sg, i) {
if (addr >= sg_virt(sg) && if (offset >= sg_offset &&
(u8 *)addr < (u8 *)sg_virt(sg) + sg_dma_len(sg)) offset + len <= sg_offset + sg_dma_len(sg))
return sg_dma_address(sg) + return sg_dma_address(sg) + offset - sg_offset;
((unsigned long)addr - (unsigned long)sg_virt(sg));
sg_offset += sg_dma_len(sg);
} }
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
...@@ -1875,7 +1883,9 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, ...@@ -1875,7 +1883,9 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
sg_init_table(sgt->sgl, skb_shinfo(skb)->nr_frags + 1); sg_init_table(sgt->sgl, skb_shinfo(skb)->nr_frags + 1);
sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, 0, skb->len); /* Only map the data, not the header (it is copied to the TSO page) */
sgt->orig_nents = skb_to_sgvec(skb, sgt->sgl, skb_headlen(skb),
skb->data_len);
if (WARN_ON_ONCE(sgt->orig_nents <= 0)) if (WARN_ON_ONCE(sgt->orig_nents <= 0))
return NULL; return NULL;
...@@ -1900,6 +1910,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, ...@@ -1900,6 +1910,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
unsigned int mss = skb_shinfo(skb)->gso_size; unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int data_offset = 0;
u16 length, iv_len, amsdu_pad; u16 length, iv_len, amsdu_pad;
dma_addr_t start_hdr_phys; dma_addr_t start_hdr_phys;
u8 *start_hdr, *pos_hdr; u8 *start_hdr, *pos_hdr;
...@@ -2000,7 +2011,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, ...@@ -2000,7 +2011,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
data_left); data_left);
dma_addr_t tb_phys; dma_addr_t tb_phys;
tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, tso.data); tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, data_offset, size);
/* Not a real mapping error, use direct comparison */ /* Not a real mapping error, use direct comparison */
if (unlikely(tb_phys == DMA_MAPPING_ERROR)) if (unlikely(tb_phys == DMA_MAPPING_ERROR))
return -EINVAL; return -EINVAL;
...@@ -2011,6 +2022,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, ...@@ -2011,6 +2022,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
tb_phys, size); tb_phys, size);
data_left -= size; data_left -= size;
data_offset += size;
tso_build_data(skb, &tso, size); tso_build_data(skb, &tso, size);
} }
} }
......
...@@ -1183,7 +1183,7 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw, ...@@ -1183,7 +1183,7 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw,
struct inet6_dev *idev) struct inet6_dev *idev)
{ {
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_dev *dev = mvif->phy->dev; struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct inet6_ifaddr *ifa; struct inet6_ifaddr *ifa;
struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
struct sk_buff *skb; struct sk_buff *skb;
......
...@@ -181,11 +181,11 @@ static void _rtl92du_init_queue_reserved_page(struct ieee80211_hw *hw, ...@@ -181,11 +181,11 @@ static void _rtl92du_init_queue_reserved_page(struct ieee80211_hw *hw,
struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
u32 txqpagenum, txqpageunit; u32 txqpagenum, txqpageunit;
u32 txqremainingpage; u32 txqremainingpage;
u32 value32 = 0;
u32 numhq = 0; u32 numhq = 0;
u32 numlq = 0; u32 numlq = 0;
u32 numnq = 0; u32 numnq = 0;
u32 numpubq; u32 numpubq;
u32 value32;
if (rtlhal->macphymode != SINGLEMAC_SINGLEPHY) { if (rtlhal->macphymode != SINGLEMAC_SINGLEPHY) {
numpubq = NORMAL_PAGE_NUM_PUBQ_92D_DUAL_MAC; numpubq = NORMAL_PAGE_NUM_PUBQ_92D_DUAL_MAC;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment