Skip to content

Commit 3c6a041

Browse files
committed
Johannes Berg says: ==================== bugfixes for 6.14: * regressions from this cycle: - mac80211: fix sparse warning for monitor - nl80211: disable multi-link reconfiguration (needs fixing) * older issues: - cfg80211: reject badly combined cooked monitor, fix regulatory hint validity checks - mac80211: handle TXQ flush w/o driver per-sta flush, fix debugfs for monitor, fix element inheritance - iwlwifi: fix rfkill, dead firmware handling, rate API version, free A-MSDU handling, avoid large allocations, fix string format - brcmfmac: fix power handling on some boards * tag 'wireless-2025-03-04' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: wifi: nl80211: disable multi-link reconfiguration wifi: cfg80211: regulatory: improve invalid hints checking wifi: brcmfmac: keep power during suspend if board requires it wifi: mac80211: Fix sparse warning for monitor_sdata wifi: mac80211: fix vendor-specific inheritance wifi: mac80211: fix MLE non-inheritance parsing wifi: iwlwifi: Fix A-MSDU TSO preparation wifi: iwlwifi: Free pages allocated when failing to build A-MSDU wifi: iwlwifi: limit printed string from FW file wifi: iwlwifi: mvm: use the right version of the rate API wifi: iwlwifi: mvm: don't try to talk to a dead firmware wifi: iwlwifi: mvm: don't dump the firmware state upon RFKILL while suspend wifi: iwlwifi: mvm: clean up ROC on failure wifi: iwlwifi: fw: avoid using an uninitialized variable wifi: iwlwifi: fw: allocate chained SG tables for dump wifi: mac80211: remove debugfs dir for virtual monitor wifi: mac80211: Cleanup sta TXQs on flush wifi: nl80211: reject cooked mode if it is set along with other flags ==================== Link: https://patch.msgid.link/20250304124435.126272-3-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents b7365ea + 1f860eb commit 3c6a041

File tree

18 files changed

+274
-134
lines changed

18 files changed

+274
-134
lines changed

drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,26 +1172,31 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
11721172
struct brcmf_bus *bus_if;
11731173
struct brcmf_sdio_dev *sdiodev;
11741174
mmc_pm_flag_t sdio_flags;
1175+
bool cap_power_off;
11751176
int ret = 0;
11761177

11771178
func = container_of(dev, struct sdio_func, dev);
11781179
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
11791180
if (func->num != 1)
11801181
return 0;
11811182

1183+
cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);
11821184

11831185
bus_if = dev_get_drvdata(dev);
11841186
sdiodev = bus_if->bus_priv.sdio;
11851187

1186-
if (sdiodev->wowl_enabled) {
1188+
if (sdiodev->wowl_enabled || !cap_power_off) {
11871189
brcmf_sdiod_freezer_on(sdiodev);
11881190
brcmf_sdio_wd_timer(sdiodev->bus, 0);
11891191

11901192
sdio_flags = MMC_PM_KEEP_POWER;
1191-
if (sdiodev->settings->bus.sdio.oob_irq_supported)
1192-
enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
1193-
else
1194-
sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
1193+
1194+
if (sdiodev->wowl_enabled) {
1195+
if (sdiodev->settings->bus.sdio.oob_irq_supported)
1196+
enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
1197+
else
1198+
sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
1199+
}
11951200

11961201
if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
11971202
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
@@ -1213,18 +1218,19 @@ static int brcmf_ops_sdio_resume(struct device *dev)
12131218
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
12141219
struct sdio_func *func = container_of(dev, struct sdio_func, dev);
12151220
int ret = 0;
1221+
bool cap_power_off = !!(func->card->host->caps & MMC_CAP_POWER_OFF_CARD);
12161222

12171223
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
12181224
if (func->num != 2)
12191225
return 0;
12201226

1221-
if (!sdiodev->wowl_enabled) {
1227+
if (!sdiodev->wowl_enabled && cap_power_off) {
12221228
/* bus was powered off and device removed, probe again */
12231229
ret = brcmf_sdiod_probe(sdiodev);
12241230
if (ret)
12251231
brcmf_err("Failed to probe device on resume\n");
12261232
} else {
1227-
if (sdiodev->settings->bus.sdio.oob_irq_supported)
1233+
if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
12281234
disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
12291235

12301236
brcmf_sdiod_freezer_off(sdiodev);

drivers/net/wireless/intel/iwlwifi/fw/dbg.c

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -558,41 +558,71 @@ static void iwl_dump_prph(struct iwl_fw_runtime *fwrt,
558558
}
559559

560560
/*
561-
* alloc_sgtable - allocates scallerlist table in the given size,
562-
* fills it with pages and returns it
561+
* alloc_sgtable - allocates (chained) scatterlist in the given size,
562+
* fills it with pages and returns it
563563
* @size: the size (in bytes) of the table
564-
*/
565-
static struct scatterlist *alloc_sgtable(int size)
564+
*/
565+
static struct scatterlist *alloc_sgtable(ssize_t size)
566566
{
567-
int alloc_size, nents, i;
568-
struct page *new_page;
569-
struct scatterlist *iter;
570-
struct scatterlist *table;
567+
struct scatterlist *result = NULL, *prev;
568+
int nents, i, n_prev;
571569

572570
nents = DIV_ROUND_UP(size, PAGE_SIZE);
573-
table = kcalloc(nents, sizeof(*table), GFP_KERNEL);
574-
if (!table)
575-
return NULL;
576-
sg_init_table(table, nents);
577-
iter = table;
578-
for_each_sg(table, iter, sg_nents(table), i) {
579-
new_page = alloc_page(GFP_KERNEL);
580-
if (!new_page) {
581-
/* release all previous allocated pages in the table */
582-
iter = table;
583-
for_each_sg(table, iter, sg_nents(table), i) {
584-
new_page = sg_page(iter);
585-
if (new_page)
586-
__free_page(new_page);
587-
}
588-
kfree(table);
571+
572+
#define N_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(*result))
573+
/*
574+
* We need an additional entry for table chaining,
575+
* this ensures the loop can finish i.e. we can
576+
* fit at least two entries per page (obviously,
577+
* many more really fit.)
578+
*/
579+
BUILD_BUG_ON(N_ENTRIES_PER_PAGE < 2);
580+
581+
while (nents > 0) {
582+
struct scatterlist *new, *iter;
583+
int n_fill, n_alloc;
584+
585+
if (nents <= N_ENTRIES_PER_PAGE) {
586+
/* last needed table */
587+
n_fill = nents;
588+
n_alloc = nents;
589+
nents = 0;
590+
} else {
591+
/* fill a page with entries */
592+
n_alloc = N_ENTRIES_PER_PAGE;
593+
/* reserve one for chaining */
594+
n_fill = n_alloc - 1;
595+
nents -= n_fill;
596+
}
597+
598+
new = kcalloc(n_alloc, sizeof(*new), GFP_KERNEL);
599+
if (!new) {
600+
if (result)
601+
_devcd_free_sgtable(result);
589602
return NULL;
590603
}
591-
alloc_size = min_t(int, size, PAGE_SIZE);
592-
size -= PAGE_SIZE;
593-
sg_set_page(iter, new_page, alloc_size, 0);
604+
sg_init_table(new, n_alloc);
605+
606+
if (!result)
607+
result = new;
608+
else
609+
sg_chain(prev, n_prev, new);
610+
prev = new;
611+
n_prev = n_alloc;
612+
613+
for_each_sg(new, iter, n_fill, i) {
614+
struct page *new_page = alloc_page(GFP_KERNEL);
615+
616+
if (!new_page) {
617+
_devcd_free_sgtable(result);
618+
return NULL;
619+
}
620+
621+
sg_set_page(iter, new_page, PAGE_SIZE, 0);
622+
}
594623
}
595-
return table;
624+
625+
return result;
596626
}
597627

598628
static void iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt,

drivers/net/wireless/intel/iwlwifi/fw/dump.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,9 @@ bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id)
540540
} err_info = {};
541541
int ret;
542542

543+
if (err_id)
544+
*err_id = 0;
545+
543546
if (!base)
544547
return false;
545548

drivers/net/wireless/intel/iwlwifi/iwl-drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
11811181

11821182
if (tlv_len != sizeof(*fseq_ver))
11831183
goto invalid_tlv_len;
1184-
IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %s\n",
1184+
IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %.32s\n",
11851185
fseq_ver->version);
11861186
}
11871187
break;

drivers/net/wireless/intel/iwlwifi/mvm/d3.c

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,38 +3092,50 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
30923092
ieee80211_resume_disconnect(vif);
30933093
}
30943094

3095-
static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
3096-
struct ieee80211_vif *vif)
3095+
enum rt_status {
3096+
FW_ALIVE,
3097+
FW_NEEDS_RESET,
3098+
FW_ERROR,
3099+
};
3100+
3101+
static enum rt_status iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
3102+
struct ieee80211_vif *vif)
30973103
{
30983104
u32 err_id;
30993105

31003106
/* check for lmac1 error */
31013107
if (iwl_fwrt_read_err_table(mvm->trans,
31023108
mvm->trans->dbg.lmac_error_event_table[0],
31033109
&err_id)) {
3104-
if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) {
3105-
struct cfg80211_wowlan_wakeup wakeup = {
3106-
.rfkill_release = true,
3107-
};
3108-
ieee80211_report_wowlan_wakeup(vif, &wakeup,
3109-
GFP_KERNEL);
3110+
if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
3111+
IWL_WARN(mvm, "Rfkill was toggled during suspend\n");
3112+
if (vif) {
3113+
struct cfg80211_wowlan_wakeup wakeup = {
3114+
.rfkill_release = true,
3115+
};
3116+
3117+
ieee80211_report_wowlan_wakeup(vif, &wakeup,
3118+
GFP_KERNEL);
3119+
}
3120+
3121+
return FW_NEEDS_RESET;
31103122
}
3111-
return true;
3123+
return FW_ERROR;
31123124
}
31133125

31143126
/* check if we have lmac2 set and check for error */
31153127
if (iwl_fwrt_read_err_table(mvm->trans,
31163128
mvm->trans->dbg.lmac_error_event_table[1],
31173129
NULL))
3118-
return true;
3130+
return FW_ERROR;
31193131

31203132
/* check for umac error */
31213133
if (iwl_fwrt_read_err_table(mvm->trans,
31223134
mvm->trans->dbg.umac_error_event_table,
31233135
NULL))
3124-
return true;
3136+
return FW_ERROR;
31253137

3126-
return false;
3138+
return FW_ALIVE;
31273139
}
31283140

31293141
/*
@@ -3492,6 +3504,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
34923504
bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa,
34933505
IWL_UCODE_TLV_CAPA_D0I3_END_FIRST);
34943506
bool resume_notif_based = iwl_mvm_d3_resume_notif_based(mvm);
3507+
enum rt_status rt_status;
34953508
bool keep = false;
34963509

34973510
mutex_lock(&mvm->mutex);
@@ -3515,14 +3528,19 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
35153528

35163529
iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
35173530

3518-
if (iwl_mvm_check_rt_status(mvm, vif)) {
3519-
IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
3531+
rt_status = iwl_mvm_check_rt_status(mvm, vif);
3532+
if (rt_status != FW_ALIVE) {
35203533
set_bit(STATUS_FW_ERROR, &mvm->trans->status);
3521-
iwl_mvm_dump_nic_error_log(mvm);
3522-
iwl_dbg_tlv_time_point(&mvm->fwrt,
3523-
IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
3524-
iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
3525-
false, 0);
3534+
if (rt_status == FW_ERROR) {
3535+
IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
3536+
iwl_mvm_dump_nic_error_log(mvm);
3537+
iwl_dbg_tlv_time_point(&mvm->fwrt,
3538+
IWL_FW_INI_TIME_POINT_FW_ASSERT,
3539+
NULL);
3540+
iwl_fw_dbg_collect_desc(&mvm->fwrt,
3541+
&iwl_dump_desc_assert,
3542+
false, 0);
3543+
}
35263544
ret = 1;
35273545
goto err;
35283546
}
@@ -3679,6 +3697,7 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
36793697
.notif_expected =
36803698
IWL_D3_NOTIF_D3_END_NOTIF,
36813699
};
3700+
enum rt_status rt_status;
36823701
int ret;
36833702

36843703
lockdep_assert_held(&mvm->mutex);
@@ -3688,14 +3707,20 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
36883707
mvm->last_reset_or_resume_time_jiffies = jiffies;
36893708
iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
36903709

3691-
if (iwl_mvm_check_rt_status(mvm, NULL)) {
3692-
IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n");
3710+
rt_status = iwl_mvm_check_rt_status(mvm, NULL);
3711+
if (rt_status != FW_ALIVE) {
36933712
set_bit(STATUS_FW_ERROR, &mvm->trans->status);
3694-
iwl_mvm_dump_nic_error_log(mvm);
3695-
iwl_dbg_tlv_time_point(&mvm->fwrt,
3696-
IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
3697-
iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
3698-
false, 0);
3713+
if (rt_status == FW_ERROR) {
3714+
IWL_ERR(mvm,
3715+
"iwl_mvm_check_rt_status failed, device is gone during suspend\n");
3716+
iwl_mvm_dump_nic_error_log(mvm);
3717+
iwl_dbg_tlv_time_point(&mvm->fwrt,
3718+
IWL_FW_INI_TIME_POINT_FW_ASSERT,
3719+
NULL);
3720+
iwl_fw_dbg_collect_desc(&mvm->fwrt,
3721+
&iwl_dump_desc_assert,
3722+
false, 0);
3723+
}
36993724
mvm->trans->state = IWL_TRANS_NO_FW;
37003725
ret = -ENODEV;
37013726

drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,13 @@ static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm,
14791479
if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000)
14801480
return -EOPNOTSUPP;
14811481

1482+
/*
1483+
* If the firmware is not running, silently succeed since there is
1484+
* no data to clear.
1485+
*/
1486+
if (!iwl_mvm_firmware_running(mvm))
1487+
return count;
1488+
14821489
mutex_lock(&mvm->mutex);
14831490
iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt);
14841491
mutex_unlock(&mvm->mutex);

drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,7 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
995995
*/
996996
u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK);
997997
u32 rate_n_flags = phy_data->rate_n_flags;
998-
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK_V1;
998+
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
999999
u8 offs = 0;
10001000

10011001
rx_status->bw = RATE_INFO_BW_HE_RU;
@@ -1050,13 +1050,13 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
10501050

10511051
if (he_mu)
10521052
he_mu->flags2 |=
1053-
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK_V1,
1053+
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
10541054
rate_n_flags),
10551055
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW);
1056-
else if (he_type == RATE_MCS_HE_TYPE_TRIG_V1)
1056+
else if (he_type == RATE_MCS_HE_TYPE_TRIG)
10571057
he->data6 |=
10581058
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) |
1059-
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK_V1,
1059+
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
10601060
rate_n_flags),
10611061
IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW);
10621062
}

drivers/net/wireless/intel/iwlwifi/mvm/time-event.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
10301030
/* End TE, notify mac80211 */
10311031
mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
10321032
mvmvif->time_event_data.link_id = -1;
1033+
/* set the bit so the ROC cleanup will actually clean up */
1034+
set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status);
10331035
iwl_mvm_roc_finished(mvm);
10341036
ieee80211_remain_on_channel_expired(mvm->hw);
10351037
} else if (le32_to_cpu(notif->start)) {

drivers/net/wireless/intel/iwlwifi/pcie/internal.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
22
/*
3-
* Copyright (C) 2003-2015, 2018-2024 Intel Corporation
3+
* Copyright (C) 2003-2015, 2018-2025 Intel Corporation
44
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
55
* Copyright (C) 2016-2017 Intel Deutschland GmbH
66
*/
@@ -646,7 +646,8 @@ dma_addr_t iwl_pcie_get_sgt_tb_phys(struct sg_table *sgt, unsigned int offset,
646646
unsigned int len);
647647
struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb,
648648
struct iwl_cmd_meta *cmd_meta,
649-
u8 **hdr, unsigned int hdr_room);
649+
u8 **hdr, unsigned int hdr_room,
650+
unsigned int offset);
650651

651652
void iwl_pcie_free_tso_pages(struct iwl_trans *trans, struct sk_buff *skb,
652653
struct iwl_cmd_meta *cmd_meta);

0 commit comments

Comments
 (0)