diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath11k')
25 files changed, 767 insertions, 223 deletions
diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index 2c94d50ae3..43d2d8ddcd 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -18,7 +18,8 @@ ath11k-y += core.o \ dbring.o \ hw.o \ pcic.o \ - fw.o + fw.o \ + p2p.o ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 7c0a235179..ca0f17ddeb 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -413,7 +413,7 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab) return ret; } -static void ath11k_ahb_power_down(struct ath11k_base *ab) +static void ath11k_ahb_power_down(struct ath11k_base *ab, bool is_suspend) { struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); @@ -442,6 +442,7 @@ static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab) free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); netif_napi_del(&irq_grp->napi); + free_netdev(irq_grp->napi_ndev); } } @@ -533,8 +534,12 @@ static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab) irq_grp->ab = ab; irq_grp->grp_id = i; - init_dummy_netdev(&irq_grp->napi_ndev); - netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + + irq_grp->napi_ndev = alloc_netdev_dummy(0); + if (!irq_grp->napi_ndev) + return -ENOMEM; + + netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi, ath11k_ahb_ext_grp_napi_poll); for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) { @@ -1256,7 +1261,7 @@ static void ath11k_ahb_remove(struct platform_device *pdev) struct ath11k_base *ab = platform_get_drvdata(pdev); if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { - ath11k_ahb_power_down(ab); + ath11k_ahb_power_down(ab, false); ath11k_debugfs_soc_destroy(ab); ath11k_qmi_deinit_service(ab); goto qmi_fail; diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 69946fc700..bcde2fcf02 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CE_H @@ -146,7 +146,7 @@ struct ath11k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* Actual start of descriptors. * Aligned to descriptor-size boundary. @@ -156,7 +156,7 @@ struct ath11k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; /* HAL ring id */ u32 hal_ring_id; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index c78bce19bd..47554c3619 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -247,7 +247,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .full_monitor_mode = false, .supports_shadow_regs = true, @@ -416,7 +419,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .full_monitor_mode = false, .supports_shadow_regs = true, @@ -501,7 +507,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .supports_shadow_regs = true, .idle_ps = true, @@ -595,7 +604,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = true, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 3, .num_peers = 512, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), @@ -750,7 +759,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .full_monitor_mode = false, .supports_shadow_regs = true, @@ -894,12 +906,6 @@ int ath11k_core_suspend(struct ath11k_base *ab) return ret; } - ret = ath11k_wow_enable(ab); - if (ret) { - ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret); - return ret; - } - ret = ath11k_dp_rx_pktlog_stop(ab, false); if (ret) { ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n", @@ -910,29 +916,85 @@ int ath11k_core_suspend(struct ath11k_base *ab) ath11k_ce_stop_shadow_timers(ab); ath11k_dp_stop_shadow_timers(ab); + /* PM framework skips suspend_late/resume_early callbacks + * if other devices report errors in their suspend callbacks. + * However ath11k_core_resume() would still be called because + * here we return success thus kernel put us on dpm_suspended_list. + * Since we won't go through a power down/up cycle, there is + * no chance to call complete(&ab->restart_completed) in + * ath11k_core_restart(), making ath11k_core_resume() timeout. + * So call it here to avoid this issue. This also works in case + * no error happens thus suspend_late/resume_early get called, + * because it will be reinitialized in ath11k_core_resume_early(). + */ + complete(&ab->restart_completed); + + return 0; +} +EXPORT_SYMBOL(ath11k_core_suspend); + +int ath11k_core_suspend_late(struct ath11k_base *ab) +{ + struct ath11k_pdev *pdev; + struct ath11k *ar; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + + /* so far single_pdev_only chips have supports_suspend as true + * and only the first pdev is valid. + */ + pdev = ath11k_core_get_single_pdev(ab); + ar = pdev->ar; + if (!ar || ar->state != ATH11K_STATE_OFF) + return 0; + ath11k_hif_irq_disable(ab); ath11k_hif_ce_irq_disable(ab); - ret = ath11k_hif_suspend(ab); - if (ret) { - ath11k_warn(ab, "failed to suspend hif: %d\n", ret); - return ret; - } + ath11k_hif_power_down(ab, true); return 0; } -EXPORT_SYMBOL(ath11k_core_suspend); +EXPORT_SYMBOL(ath11k_core_suspend_late); + +int ath11k_core_resume_early(struct ath11k_base *ab) +{ + int ret; + struct ath11k_pdev *pdev; + struct ath11k *ar; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + + /* so far single_pdev_only chips have supports_suspend as true + * and only the first pdev is valid. + */ + pdev = ath11k_core_get_single_pdev(ab); + ar = pdev->ar; + if (!ar || ar->state != ATH11K_STATE_OFF) + return 0; + + reinit_completion(&ab->restart_completed); + ret = ath11k_hif_power_up(ab); + if (ret) + ath11k_warn(ab, "failed to power up hif during resume: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(ath11k_core_resume_early); int ath11k_core_resume(struct ath11k_base *ab) { int ret; struct ath11k_pdev *pdev; struct ath11k *ar; + long time_left; if (!ab->hw_params.supports_suspend) return -EOPNOTSUPP; - /* so far signle_pdev_only chips have supports_suspend as true + /* so far single_pdev_only chips have supports_suspend as true * and only the first pdev is valid. */ pdev = ath11k_core_get_single_pdev(ab); @@ -940,29 +1002,29 @@ int ath11k_core_resume(struct ath11k_base *ab) if (!ar || ar->state != ATH11K_STATE_OFF) return 0; - ret = ath11k_hif_resume(ab); - if (ret) { - ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret); - return ret; + time_left = wait_for_completion_timeout(&ab->restart_completed, + ATH11K_RESET_TIMEOUT_HZ); + if (time_left == 0) { + ath11k_warn(ab, "timeout while waiting for restart complete"); + return -ETIMEDOUT; } - ath11k_hif_ce_irq_enable(ab); - ath11k_hif_irq_enable(ab); + if (ab->hw_params.current_cc_support && + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { + ret = ath11k_reg_set_cc(ar); + if (ret) { + ath11k_warn(ab, "failed to set country code during resume: %d\n", + ret); + return ret; + } + } ret = ath11k_dp_rx_pktlog_start(ab); - if (ret) { + if (ret) ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n", ret); - return ret; - } - ret = ath11k_wow_wakeup(ab); - if (ret) { - ath11k_warn(ab, "failed to wakeup wow during resume: %d\n", ret); - return ret; - } - - return 0; + return ret; } EXPORT_SYMBOL(ath11k_core_resume); @@ -1926,23 +1988,20 @@ static void ath11k_update_11d(struct work_struct *work) struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); struct ath11k *ar; struct ath11k_pdev *pdev; - struct wmi_set_current_country_params set_current_param = {}; int ret, i; - spin_lock_bh(&ab->base_lock); - memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); - spin_unlock_bh(&ab->base_lock); - - ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", - set_current_param.alpha2[0], - set_current_param.alpha2[1]); - for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; - memcpy(&ar->alpha2, &set_current_param.alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + spin_lock_bh(&ab->base_lock); + memcpy(&ar->alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c for pdev %d\n", + ar->alpha2[0], ar->alpha2[1], i); + + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "pdev id %d failed set current country code: %d\n", @@ -2060,6 +2119,8 @@ static void ath11k_core_restart(struct work_struct *work) if (!ab->is_reset) ath11k_core_post_reconfigure_recovery(ab); + + complete(&ab->restart_completed); } static void ath11k_core_reset(struct work_struct *work) @@ -2129,7 +2190,7 @@ static void ath11k_core_reset(struct work_struct *work) ath11k_hif_irq_disable(ab); ath11k_hif_ce_irq_disable(ab); - ath11k_hif_power_down(ab); + ath11k_hif_power_down(ab, false); ath11k_hif_power_up(ab); ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n"); @@ -2202,7 +2263,7 @@ void ath11k_core_deinit(struct ath11k_base *ab) mutex_unlock(&ab->core_lock); - ath11k_hif_power_down(ab); + ath11k_hif_power_down(ab, false); ath11k_mac_destroy(ab); ath11k_core_soc_destroy(ab); ath11k_fw_destroy(ab); @@ -2255,6 +2316,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); init_completion(&ab->wow.wakeup_completed); + init_completion(&ab->restart_completed); ab->dev = dev; ab->hif.bus = bus; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index b3fb74a226..205f40ee6b 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CORE_H @@ -174,7 +174,7 @@ struct ath11k_ext_irq_grp { u64 timestamp; bool napi_enabled; struct napi_struct napi; - struct net_device napi_ndev; + struct net_device *napi_ndev; }; enum ath11k_smbios_cc_type { @@ -1033,6 +1033,8 @@ struct ath11k_base { DECLARE_BITMAP(fw_features, ATH11K_FW_FEATURE_COUNT); } fw; + struct completion restart_completed; + #ifdef CONFIG_NL80211_TESTMODE struct { u32 data_pos; @@ -1232,8 +1234,10 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); int ath11k_core_check_dt(struct ath11k_base *ath11k); int ath11k_core_check_smbios(struct ath11k_base *ab); void ath11k_core_halt(struct ath11k *ar); +int ath11k_core_resume_early(struct ath11k_base *ab); int ath11k_core_resume(struct ath11k_base *ab); int ath11k_core_suspend(struct ath11k_base *ab); +int ath11k_core_suspend_late(struct ath11k_base *ab); void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab); bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab); diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index a48e737ef3..414a5ce279 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/vmalloc.h> @@ -980,7 +980,7 @@ int ath11k_debugfs_pdev_create(struct ath11k_base *ab) debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab, &fops_simulate_fw_crash); - debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab, + debugfs_create_file("soc_dp_stats", 0400, ab->debugfs_soc, ab, &fops_soc_dp_stats); if (ab->hw_params.sram_dump.start != 0) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index afd481f585..aabde24d87 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1877,8 +1877,7 @@ static void ath11k_dp_rx_h_csum_offload(struct ath11k *ar, struct sk_buff *msdu) CHECKSUM_NONE : CHECKSUM_UNNECESSARY; } -static int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, - enum hal_encrypt_type enctype) +int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, enum hal_encrypt_type enctype) { switch (enctype) { case HAL_ENCRYPT_TYPE_OPEN: diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.h b/drivers/net/wireless/ath/ath11k/dp_rx.h index 623da3bf9d..c322e30caa 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.h +++ b/drivers/net/wireless/ath/ath11k/dp_rx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_RX_H #define ATH11K_DP_RX_H @@ -95,4 +96,6 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab); int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer); +int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, enum hal_encrypt_type enctype); + #endif /* ATH11K_DP_RX_H */ diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 65e8f244eb..e453c13738 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -664,7 +664,7 @@ struct hal_srng_config { }; /** - * enum hal_rx_buf_return_buf_manager + * enum hal_rx_buf_return_buf_manager - manager for returned rx buffers * * @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list * @HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST: Descriptor returned to WBM idle diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index 877a4073fe..c4c6cc09c7 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HIF_H_ @@ -18,7 +18,7 @@ struct ath11k_hif_ops { int (*start)(struct ath11k_base *ab); void (*stop)(struct ath11k_base *ab); int (*power_up)(struct ath11k_base *ab); - void (*power_down)(struct ath11k_base *ab); + void (*power_down)(struct ath11k_base *ab, bool is_suspend); int (*suspend)(struct ath11k_base *ab); int (*resume)(struct ath11k_base *ab); int (*map_service_to_pipe)(struct ath11k_base *ab, u16 service_id, @@ -67,12 +67,18 @@ static inline void ath11k_hif_irq_disable(struct ath11k_base *ab) static inline int ath11k_hif_power_up(struct ath11k_base *ab) { + if (!ab->hif.ops->power_up) + return -EOPNOTSUPP; + return ab->hif.ops->power_up(ab); } -static inline void ath11k_hif_power_down(struct ath11k_base *ab) +static inline void ath11k_hif_power_down(struct ath11k_base *ab, bool is_suspend) { - ab->hif.ops->power_down(ab); + if (!ab->hif.ops->power_down) + return; + + ab->hif.ops->power_down(ab, is_suspend); } static inline int ath11k_hif_suspend(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 9f4bf41a3d..eaa53bc39a 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1231,14 +1231,7 @@ static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) enable_ps = arvif->ps; - if (!arvif->is_started) { - /* mac80211 can update vif powersave state while disconnected. - * Firmware doesn't behave nicely and consumes more power than - * necessary if PS is disabled on a non-started vdev. Hence - * force-enable PS for non-running vdevs. - */ - psmode = WMI_STA_PS_MODE_ENABLED; - } else if (enable_ps) { + if (enable_ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; @@ -1430,10 +1423,67 @@ static bool ath11k_mac_set_nontx_vif_params(struct ath11k_vif *tx_arvif, return false; } -static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, - struct sk_buff *bcn) +static int ath11k_mac_setup_bcn_p2p_ie(struct ath11k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath11k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) + return -ENOENT; + + ret = ath11k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath11k_warn(ar->ab, "failed to submit P2P GO bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return ret; +} + +static int ath11k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + size_t len; + const u8 *next, *end; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + +static int ath11k_mac_set_vif_params(struct ath11k_vif *arvif, + struct sk_buff *bcn) { + struct ath11k_base *ab = arvif->ar->ab; struct ieee80211_mgmt *mgmt; + int ret = 0; u8 *ies; ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); @@ -1451,6 +1501,32 @@ static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, arvif->wpaie_present = true; else arvif->wpaie_present = false; + + if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + return ret; + + ret = ath11k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath11k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", + ret); + return ret; + } + + /* P2P IE is inserted by firmware automatically (as + * configured above) so remove it from the base beacon + * template to avoid duplicate P2P IEs in beacon frames. + */ + ret = ath11k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + if (ret) { + ath11k_warn(ab, "failed to remove P2P vendor ie: %d\n", + ret); + return ret; + } + + return ret; } static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif) @@ -1472,10 +1548,12 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif) return -EPERM; } - if (tx_arvif == arvif) - ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb); - else + if (tx_arvif == arvif) { + if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb)) + return -EINVAL; + } else { arvif->wpaie_present = tx_arvif->wpaie_present; + } for (i = 0; i < beacons->cnt; i++) { if (tx_arvif != arvif && !nontx_vif_params_set) @@ -1534,10 +1612,12 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif) return -EPERM; } - if (tx_arvif == arvif) - ath11k_mac_set_vif_params(tx_arvif, bcn); - else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) + if (tx_arvif == arvif) { + if (ath11k_mac_set_vif_params(tx_arvif, bcn)) + return -EINVAL; + } else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) { return -EINVAL; + } ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0); kfree_skb(bcn); @@ -1579,7 +1659,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) if (vif->bss_conf.color_change_active && ieee80211_beacon_cntdwn_is_complete(vif, 0)) { arvif->bcca_zero_sent = true; - ieee80211_color_change_finish(vif); + ieee80211_color_change_finish(vif, 0); return; } @@ -3996,6 +4076,9 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, arg->vdev_id = arvif->vdev_id; arg->scan_id = ATH11K_SCAN_ID; + if (ar->ab->hw_params.single_pdev_only) + arg->scan_f_filter_prb_req = 1; + if (req->ie_len) { arg->extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL); if (!arg->extraie.ptr) { @@ -4146,6 +4229,7 @@ static int ath11k_install_key(struct ath11k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: arg.key_cipher = WMI_CIPHER_AES_CCM; /* TODO: Re-check if flag is valid */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; @@ -4155,12 +4239,10 @@ static int ath11k_install_key(struct ath11k_vif *arvif, arg.key_txmic_len = 8; arg.key_rxmic_len = 8; break; - case WLAN_CIPHER_SUITE_CCMP_256: - arg.key_cipher = WMI_CIPHER_AES_CCM; - break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: arg.key_cipher = WMI_CIPHER_AES_GCM; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; default: ath11k_warn(ar->ab, "cipher %d is not supported\n", key->cipher); @@ -5820,7 +5902,10 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, { struct ath11k_base *ab = ar->ab; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct ieee80211_tx_info *info; + enum hal_encrypt_type enctype; + unsigned int mic_len; dma_addr_t paddr; int buf_id; int ret; @@ -5844,7 +5929,12 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control)) { - skb_put(skb, IEEE80211_CCMP_MIC_LEN); + if (!(skb_cb->flags & ATH11K_SKB_CIPHER_SET)) + ath11k_warn(ab, "WMI management tx frame without ATH11K_SKB_CIPHER_SET"); + + enctype = ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); + mic_len = ath11k_dp_rx_crypto_mic_len(ar, enctype); + skb_put(skb, mic_len); } } @@ -6570,17 +6660,26 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; break; case NL80211_IFTYPE_MESH_POINT: arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: arvif->vdev_type = WMI_VDEV_TYPE_AP; + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = bit; break; + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; + default: WARN_ON(1); break; @@ -7896,8 +7995,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); int ret; - struct cur_regulatory_info *reg_info; - enum ieee80211_ap_reg_power power_type; mutex_lock(&ar->conf_mutex); @@ -7908,17 +8005,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, if (ath11k_wmi_supports_6ghz_cc_ext(ar) && ctx->def.chan->band == NL80211_BAND_6GHZ && arvif->vdev_type == WMI_VDEV_TYPE_STA) { - reg_info = &ab->reg_info_store[ar->pdev_idx]; - power_type = vif->bss_conf.power_type; - - ath11k_dbg(ab, ATH11K_DBG_MAC, "chanctx power type %d\n", power_type); - - if (power_type == IEEE80211_REG_UNSET_AP) { - ret = -EINVAL; - goto out; - } - - ath11k_reg_handle_chan_list(ab, reg_info, power_type); arvif->chanctx = *ctx; ath11k_mac_parse_tx_pwr_env(ar, vif, ctx); } @@ -8772,12 +8858,8 @@ ath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ieee80211_wake_queues(ar->hw); if (ar->ab->hw_params.current_cc_support && - ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { - struct wmi_set_current_country_params set_current_param = {}; - - memcpy(&set_current_param.alpha2, ar->alpha2, 2); - ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); - } + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) + ath11k_reg_set_cc(ar); if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); @@ -9255,9 +9337,11 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw, arg->dwell_time_passive = scan_time_msec; arg->max_scan_time = scan_time_msec; arg->scan_f_passive = 1; - arg->scan_f_filter_prb_req = 1; arg->burst_duration = duration; + if (!ar->ab->hw_params.single_pdev_only) + arg->scan_f_filter_prb_req = 1; + ret = ath11k_start_scan(ar, arg); if (ret) { ath11k_warn(ar->ab, "failed to start roc scan: %d\n", ret); @@ -9532,6 +9616,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + enum ieee80211_ap_reg_power power_type; + struct cur_regulatory_info *reg_info; struct ath11k_peer *peer; int ret = 0; @@ -9611,6 +9697,29 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", sta->addr, arvif->vdev_id, ret); } + + if (!ret && + ath11k_wmi_supports_6ghz_cc_ext(ar) && + arvif->vdev_type == WMI_VDEV_TYPE_STA && + arvif->chanctx.def.chan && + arvif->chanctx.def.chan->band == NL80211_BAND_6GHZ) { + reg_info = &ar->ab->reg_info_store[ar->pdev_idx]; + power_type = vif->bss_conf.power_type; + + if (power_type == IEEE80211_REG_UNSET_AP) { + ath11k_warn(ar->ab, "invalid power type %d\n", + power_type); + ret = -EINVAL; + } else { + ret = ath11k_reg_handle_chan_list(ar->ab, + reg_info, + power_type); + if (ret) + ath11k_warn(ar->ab, + "failed to handle chan list with power type %d\n", + power_type); + } + } } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { spin_lock_bh(&ar->ab->base_lock); @@ -9859,12 +9968,18 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits; + bool p2p; + + p2p = ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_P2P_DEVICE); combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); if (!combinations) return -ENOMEM; - n_limits = 2; + if (p2p) + n_limits = 3; + else + n_limits = 2; limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL); if (!limits) { @@ -9872,39 +9987,29 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) return -ENOMEM; } + limits[0].types |= BIT(NL80211_IFTYPE_STATION); + limits[1].types |= BIT(NL80211_IFTYPE_AP); + if (IS_ENABLED(CONFIG_MAC80211_MESH) && + ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + + combinations[0].limits = limits; + combinations[0].n_limits = n_limits; + combinations[0].beacon_int_infra_match = true; + combinations[0].beacon_int_min_gcd = 100; + if (ab->hw_params.support_dual_stations) { limits[0].max = 2; - limits[0].types |= BIT(NL80211_IFTYPE_STATION); - limits[1].max = 1; - limits[1].types |= BIT(NL80211_IFTYPE_AP); - if (IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) - limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); - combinations[0].limits = limits; - combinations[0].n_limits = 2; combinations[0].max_interfaces = ab->hw_params.num_vdevs; combinations[0].num_different_channels = 2; - combinations[0].beacon_int_infra_match = true; - combinations[0].beacon_int_min_gcd = 100; } else { limits[0].max = 1; - limits[0].types |= BIT(NL80211_IFTYPE_STATION); - limits[1].max = 16; - limits[1].types |= BIT(NL80211_IFTYPE_AP); - - if (IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) - limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); - combinations[0].limits = limits; - combinations[0].n_limits = 2; combinations[0].max_interfaces = 16; combinations[0].num_different_channels = 1; - combinations[0].beacon_int_infra_match = true; - combinations[0].beacon_int_min_gcd = 100; combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | @@ -9913,6 +10018,13 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) BIT(NL80211_CHAN_WIDTH_160); } + if (p2p) { + limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + limits[2].max = 1; + limits[2].types |= BIT(NL80211_IFTYPE_P2P_DEVICE); + } + ar->hw->wiphy->iface_combinations = combinations; ar->hw->wiphy->n_iface_combinations = 1; @@ -10029,6 +10141,7 @@ static int __ath11k_mac_register(struct ath11k *ar) if (ret) goto err; + wiphy_read_of_freq_limits(ar->hw->wiphy); ath11k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); ath11k_mac_setup_he_cap(ar, cap); @@ -10215,11 +10328,8 @@ static int __ath11k_mac_register(struct ath11k *ar) } if (ab->hw_params.current_cc_support && ab->new_alpha2[0]) { - struct wmi_set_current_country_params set_current_param = {}; - - memcpy(&set_current_param.alpha2, ab->new_alpha2, 2); memcpy(&ar->alpha2, ab->new_alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "failed set cc code for mac register: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index fb4ecf9a10..ab182690ae 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -19,6 +19,7 @@ #define MHI_TIMEOUT_DEFAULT_MS 20000 #define RDDM_DUMP_SIZE 0x420000 +#define MHI_CB_INVALID 0xff static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { { @@ -158,9 +159,8 @@ void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab) ath11k_dbg(ab, ATH11K_DBG_PCI, "mhistatus 0x%x\n", val); - /* Observed on QCA6390 that after SOC_GLOBAL_RESET, MHISTATUS - * has SYSERR bit set and thus need to set MHICTRL_RESET - * to clear SYSERR. + /* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set + * and thus need to set MHICTRL_RESET to clear SYSERR. */ ath11k_pcic_write32(ab, MHICTRL, MHICTRL_RESET_MASK); @@ -269,6 +269,7 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback cb) { struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ath11k_dbg(ab, ATH11K_DBG_BOOT, "notify status reason %s\n", ath11k_mhi_op_callback_to_str(cb)); @@ -279,12 +280,21 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, break; case MHI_CB_EE_RDDM: ath11k_warn(ab, "firmware crashed: MHI_CB_EE_RDDM\n"); + if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) { + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "do not queue again for consecutive RDDM event\n"); + break; + } + if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))) queue_work(ab->workqueue_aux, &ab->reset_work); + break; default: break; } + + ab_pci->mhi_pre_cb = cb; } static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, @@ -397,6 +407,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) goto free_controller; } + ab_pci->mhi_pre_cb = MHI_CB_INVALID; ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config); if (ret) { ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret); @@ -442,9 +453,17 @@ int ath11k_mhi_start(struct ath11k_pci *ab_pci) return 0; } -void ath11k_mhi_stop(struct ath11k_pci *ab_pci) +void ath11k_mhi_stop(struct ath11k_pci *ab_pci, bool is_suspend) { - mhi_power_down(ab_pci->mhi_ctrl, true); + /* During suspend we need to use mhi_power_down_keep_dev() + * workaround, otherwise ath11k_core_resume() will timeout + * during resume. + */ + if (is_suspend) + mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true); + else + mhi_power_down(ab_pci->mhi_ctrl, true); + mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); } diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h index f81fba2644..2d567705e7 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.h +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_MHI_H #define _ATH11K_MHI_H @@ -18,7 +18,7 @@ #define MHICTRL_RESET_MASK 0x2 int ath11k_mhi_start(struct ath11k_pci *ar_pci); -void ath11k_mhi_stop(struct ath11k_pci *ar_pci); +void ath11k_mhi_stop(struct ath11k_pci *ar_pci, bool is_suspend); int ath11k_mhi_register(struct ath11k_pci *ar_pci); void ath11k_mhi_unregister(struct ath11k_pci *ar_pci); void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab); @@ -26,5 +26,4 @@ void ath11k_mhi_clear_vector(struct ath11k_base *ab); int ath11k_mhi_suspend(struct ath11k_pci *ar_pci); int ath11k_mhi_resume(struct ath11k_pci *ar_pci); - #endif diff --git a/drivers/net/wireless/ath/ath11k/p2p.c b/drivers/net/wireless/ath/ath11k/p2p.c new file mode 100644 index 0000000000..01e14523f1 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/p2p.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" +#include "wmi.h" +#include "mac.h" +#include "p2p.h" + +static void ath11k_p2p_noa_ie_fill(u8 *data, size_t len, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ieee80211_p2p_noa_attr *noa_attr; + u8 noa_descriptors, ctwindow; + bool oppps; + __le16 *noa_attr_len; + u16 attr_len; + int i; + + ctwindow = u32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_CTWIN_TU); + oppps = u32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS); + noa_descriptors = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + + /* P2P IE */ + data[0] = WLAN_EID_VENDOR_SPECIFIC; + data[1] = len - 2; + data[2] = (WLAN_OUI_WFA >> 16) & 0xff; + data[3] = (WLAN_OUI_WFA >> 8) & 0xff; + data[4] = (WLAN_OUI_WFA >> 0) & 0xff; + data[5] = WLAN_OUI_TYPE_WFA_P2P; + + /* NOA ATTR */ + data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; + noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ + noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; + + noa_attr->index = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_INDEX); + noa_attr->oppps_ctwindow = ctwindow; + if (oppps) + noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; + + for (i = 0; i < noa_descriptors; i++) { + noa_attr->desc[i].count = noa->descriptors[i].type_count; + noa_attr->desc[i].duration = + cpu_to_le32(noa->descriptors[i].duration); + noa_attr->desc[i].interval = + cpu_to_le32(noa->descriptors[i].interval); + noa_attr->desc[i].start_time = + cpu_to_le32(noa->descriptors[i].start_time); + } + + attr_len = 2; /* index + oppps_ctwindow */ + attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); + *noa_attr_len = __cpu_to_le16(attr_len); +} + +static size_t +ath11k_p2p_noa_ie_len_compute(const struct ath11k_wmi_p2p_noa_info *noa) +{ + size_t len = 0; + u8 noa_descriptors = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + + if (!(noa_descriptors) && + !(u32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS))) + return 0; + + len += 1 + 1 + 4; /* EID + len + OUI */ + len += 1 + 2; /* noa attr + attr len */ + len += 1 + 1; /* index + oppps_ctwindow */ + len += noa_descriptors * + sizeof(struct ieee80211_p2p_noa_desc); + + return len; +} + +static void ath11k_p2p_noa_ie_assign(struct ath11k_vif *arvif, void *ie, + size_t len) +{ + struct ath11k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + kfree(arvif->u.ap.noa_data); + + arvif->u.ap.noa_data = ie; + arvif->u.ap.noa_len = len; +} + +static void __ath11k_p2p_noa_update(struct ath11k_vif *arvif, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ath11k *ar = arvif->ar; + void *ie; + size_t len; + + lockdep_assert_held(&ar->data_lock); + + ath11k_p2p_noa_ie_assign(arvif, NULL, 0); + + len = ath11k_p2p_noa_ie_len_compute(noa); + if (!len) + return; + + ie = kmalloc(len, GFP_ATOMIC); + if (!ie) + return; + + ath11k_p2p_noa_ie_fill(ie, len, noa); + ath11k_p2p_noa_ie_assign(arvif, ie, len); } + +void ath11k_p2p_noa_update(struct ath11k_vif *arvif, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ath11k *ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + __ath11k_p2p_noa_update(arvif, noa); + spin_unlock_bh(&ar->data_lock); +} + +static void ath11k_p2p_noa_update_vdev_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ath11k_p2p_noa_arg *arg = data; + + if (arvif->vdev_id != arg->vdev_id) + return; + + ath11k_p2p_noa_update(arvif, arg->noa); +} + +void ath11k_p2p_noa_update_by_vdev_id(struct ath11k *ar, u32 vdev_id, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ath11k_p2p_noa_arg arg = { + .vdev_id = vdev_id, + .noa = noa, + }; + + ieee80211_iterate_active_interfaces_atomic(ar->hw, + IEEE80211_IFACE_ITER_NORMAL, + ath11k_p2p_noa_update_vdev_iter, + &arg); +} diff --git a/drivers/net/wireless/ath/ath11k/p2p.h b/drivers/net/wireless/ath/ath11k/p2p.h new file mode 100644 index 0000000000..d907940a9b --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/p2p.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH11K_P2P_H +#define ATH11K_P2P_H + +#include "wmi.h" + +struct ath11k_wmi_p2p_noa_info; + +struct ath11k_p2p_noa_arg { + u32 vdev_id; + const struct ath11k_wmi_p2p_noa_info *noa; +}; + +void ath11k_p2p_noa_update(struct ath11k_vif *arvif, + const struct ath11k_wmi_p2p_noa_info *noa); +void ath11k_p2p_noa_update_by_vdev_id(struct ath11k *ar, u32 vdev_id, + const struct ath11k_wmi_p2p_noa_info *noa); +#endif diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index be9d2c69cc..8d63b84d12 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -638,7 +638,7 @@ static int ath11k_pci_power_up(struct ath11k_base *ab) return 0; } -static void ath11k_pci_power_down(struct ath11k_base *ab) +static void ath11k_pci_power_down(struct ath11k_base *ab, bool is_suspend) { struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); @@ -649,7 +649,7 @@ static void ath11k_pci_power_down(struct ath11k_base *ab) ath11k_pci_msi_disable(ab_pci); - ath11k_mhi_stop(ab_pci); + ath11k_mhi_stop(ab_pci, is_suspend); clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); ath11k_pci_sw_reset(ab_pci->ab, false); } @@ -970,7 +970,7 @@ static void ath11k_pci_remove(struct pci_dev *pdev) ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { - ath11k_pci_power_down(ab); + ath11k_pci_power_down(ab, false); ath11k_debugfs_soc_destroy(ab); ath11k_qmi_deinit_service(ab); goto qmi_fail; @@ -998,7 +998,7 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); - ath11k_pci_power_down(ab); + ath11k_pci_power_down(ab, false); } static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) @@ -1035,9 +1035,39 @@ static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, - ath11k_pci_pm_suspend, - ath11k_pci_pm_resume); +static __maybe_unused int ath11k_pci_pm_suspend_late(struct device *dev) +{ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath11k_core_suspend_late(ab); + if (ret) + ath11k_warn(ab, "failed to late suspend core: %d\n", ret); + + /* Similar to ath11k_pci_pm_suspend(), we return success here + * even error happens, to allow system suspend/hibernation survive. + */ + return 0; +} + +static __maybe_unused int ath11k_pci_pm_resume_early(struct device *dev) +{ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath11k_core_resume_early(ab); + if (ret) + ath11k_warn(ab, "failed to early resume core: %d\n", ret); + + return ret; +} + +static const struct dev_pm_ops __maybe_unused ath11k_pci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend, + ath11k_pci_pm_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend_late, + ath11k_pci_pm_resume_early) +}; static struct pci_driver ath11k_pci_driver = { .name = "ath11k_pci", diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index 6be73333d9..c33c786514 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -64,6 +64,7 @@ struct ath11k_pci { char amss_path[100]; struct mhi_controller *mhi_ctrl; const struct ath11k_msi_config *msi_config; + enum mhi_callback mhi_pre_cb; u32 register_window; /* protects register_window above */ diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index add4db4c50..debe7c5919 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -316,6 +316,7 @@ static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab) free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); netif_napi_del(&irq_grp->napi); + free_netdev(irq_grp->napi_ndev); } } @@ -558,8 +559,9 @@ ath11k_pcic_get_msi_irq(struct ath11k_base *ab, unsigned int vector) static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) { - int i, j, ret, num_vectors = 0; + int i, j, n, ret, num_vectors = 0; u32 user_base_data = 0, base_vector = 0; + struct ath11k_ext_irq_grp *irq_grp; unsigned long irq_flags; ret = ath11k_pcic_get_user_msi_assignment(ab, "DP", &num_vectors, @@ -573,13 +575,18 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) irq_flags |= IRQF_NOBALANCING; for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { - struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + irq_grp = &ab->ext_irq_grp[i]; u32 num_irq = 0; irq_grp->ab = ab; irq_grp->grp_id = i; - init_dummy_netdev(&irq_grp->napi_ndev); - netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + irq_grp->napi_ndev = alloc_netdev_dummy(0); + if (!irq_grp->napi_ndev) { + ret = -ENOMEM; + goto fail_allocate; + } + + netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi, ath11k_pcic_ext_grp_napi_poll); if (ab->hw_params.ring_mask->tx[i] || @@ -601,8 +608,10 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) int vector = (i % num_vectors) + base_vector; int irq = ath11k_pcic_get_msi_irq(ab, vector); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto fail_irq; + } ab->irq_num[irq_idx] = irq; @@ -615,6 +624,10 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) if (ret) { ath11k_err(ab, "failed request irq %d: %d\n", vector, ret); + for (n = 0; n <= i; n++) { + irq_grp = &ab->ext_irq_grp[n]; + free_netdev(irq_grp->napi_ndev); + } return ret; } } @@ -622,6 +635,15 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) } return 0; +fail_irq: + /* i ->napi_ndev was properly allocated. Free it also */ + i += 1; +fail_allocate: + for (n = 0; n < i; n++) { + irq_grp = &ab->ext_irq_grp[n]; + free_netdev(irq_grp->napi_ndev); + } + return ret; } int ath11k_pcic_config_irq(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 5006f81f77..d4a243b64f 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2877,7 +2877,7 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) } /* reset the firmware */ - ath11k_hif_power_down(ab); + ath11k_hif_power_down(ab, false); ath11k_hif_power_up(ab); ath11k_dbg(ab, ATH11K_DBG_QMI, "exit wait for cold boot done\n"); return 0; diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 737fcd450d..39232b8f52 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -49,7 +49,6 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wmi_init_country_params init_country_param; - struct wmi_set_current_country_params set_current_param = {}; struct ath11k *ar = hw->priv; int ret; @@ -83,9 +82,8 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) * reg info */ if (ar->ab->hw_params.current_cc_support) { - memcpy(&set_current_param.alpha2, request->alpha2, 2); - memcpy(&ar->alpha2, &set_current_param.alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + memcpy(&ar->alpha2, request->alpha2, 2); + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "failed set current country code: %d\n", ret); @@ -1017,3 +1015,11 @@ void ath11k_reg_free(struct ath11k_base *ab) kfree(ab->new_regd[i]); } } + +int ath11k_reg_set_cc(struct ath11k *ar) +{ + struct wmi_set_current_country_params set_current_param = {}; + + memcpy(&set_current_param.alpha2, ar->alpha2, 2); + return ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); +} diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 64edb79426..263ea90619 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_REG_H @@ -45,5 +45,5 @@ ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); int ath11k_reg_handle_chan_list(struct ath11k_base *ab, struct cur_regulatory_info *reg_info, enum ieee80211_ap_reg_power power_type); - +int ath11k_reg_set_cc(struct ath11k *ar); #endif diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c index 41e7499f07..18d6eab5cc 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.c +++ b/drivers/net/wireless/ath/ath11k/thermal.c @@ -101,7 +101,7 @@ static ssize_t ath11k_thermal_show_temp(struct device *dev, spin_unlock_bh(&ar->data_lock); /* display in millidegree Celsius */ - ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); + ret = sysfs_emit(buf, "%d\n", temperature * 1000); out: mutex_unlock(&ar->conf_mutex); return ret; diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h index 235ab8ea71..75246b0a82 100644 --- a/drivers/net/wireless/ath/ath11k/trace.h +++ b/drivers/net/wireless/ath/ath11k/trace.h @@ -48,8 +48,8 @@ TRACE_EVENT(ath11k_htt_pktlog, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->buf_len = buf_len; __entry->pktlog_checksum = pktlog_checksum; memcpy(__get_dynamic_array(pktlog), buf, buf_len); @@ -77,8 +77,8 @@ TRACE_EVENT(ath11k_htt_ppdu_stats, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; memcpy(__get_dynamic_array(ppdu), data, len); ), @@ -105,8 +105,8 @@ TRACE_EVENT(ath11k_htt_rxdesc, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; __entry->log_type = log_type; memcpy(__get_dynamic_array(rxdesc), data, len); @@ -130,8 +130,8 @@ DECLARE_EVENT_CLASS(ath11k_log_event, __vstring(msg, vaf->fmt, vaf->va) ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __assign_vstr(msg, vaf->fmt, vaf->va); ), TP_printk( @@ -171,8 +171,8 @@ TRACE_EVENT(ath11k_wmi_cmd, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->id = id; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -201,8 +201,8 @@ TRACE_EVENT(ath11k_wmi_event, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->id = id; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -230,8 +230,8 @@ TRACE_EVENT(ath11k_log_dbg, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->level = level; WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ATH11K_MSG_MAX, vaf->fmt, @@ -262,10 +262,10 @@ TRACE_EVENT(ath11k_log_dbg_dump, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); - __assign_str(msg, msg); - __assign_str(prefix, prefix); + __assign_str(device); + __assign_str(driver); + __assign_str(msg); + __assign_str(prefix); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), @@ -292,8 +292,8 @@ TRACE_EVENT(ath11k_wmi_diag, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; memcpy(__get_dynamic_array(data), data, len); ), @@ -318,8 +318,8 @@ TRACE_EVENT(ath11k_ps_timekeeper, __field(u32, peer_ps_timestamp) ), - TP_fast_assign(__assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + TP_fast_assign(__assign_str(device); + __assign_str(driver); memcpy(__get_dynamic_array(peer_addr), peer_addr, ETH_ALEN); __entry->peer_ps_state = peer_ps_state; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 34ab9631ff..6ff01c45f1 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -20,6 +20,7 @@ #include "hw.h" #include "peer.h" #include "testmode.h" +#include "p2p.h" struct wmi_tlv_policy { size_t min_len; @@ -154,6 +155,10 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, [WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = { .min_len = sizeof(struct wmi_twt_add_dialog_event) }, + [WMI_TAG_P2P_NOA_INFO] = { + .min_len = sizeof(struct ath11k_wmi_p2p_noa_info) }, + [WMI_TAG_P2P_NOA_EVENT] = { + .min_len = sizeof(struct wmi_p2p_noa_event) }, }; #define PRIMAP(_hw_mode_) \ @@ -981,7 +986,7 @@ int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, FIELD_PREP(WMI_TLV_LEN, 0); /* Note: This is a nested TLV containing: - * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + * [wmi_tlv][ath11k_wmi_p2p_noa_descriptor][wmi_tlv].. */ ptr += sizeof(*tlv); @@ -1704,6 +1709,45 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_p2p_go_set_beacon_ie_cmd *cmd; + size_t p2p_ie_len, aligned_len; + struct wmi_tlv *tlv; + struct sk_buff *skb; + int ret, len; + + p2p_ie_len = p2p_ie[1] + 2; + aligned_len = roundup(p2p_ie_len, 4); + + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_p2p_go_set_beacon_ie_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_P2P_GO_SET_BEACON_IE) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->ie_buf_len = p2p_ie_len; + + tlv = (struct wmi_tlv *)cmd->tlv; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, aligned_len); + memcpy(tlv->value, p2p_ie, p2p_ie_len); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_P2P_GO_SET_BEACON_IE); + if (ret) { + ath11k_warn(ar->ab, "failed to send WMI_P2P_GO_SET_BEACON_IE\n"); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn, u32 ema_params) @@ -4020,7 +4064,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk switch (ev->evt_type) { case WMI_BSS_COLOR_COLLISION_DETECTION: - ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap); + ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap, + 0); ath11k_dbg(ab, ATH11K_DBG_WMI, "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); @@ -8606,6 +8651,58 @@ exit: kfree(tb); } +static void ath11k_wmi_p2p_noa_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_p2p_noa_event *ev; + const struct ath11k_wmi_p2p_noa_info *noa; + struct ath11k *ar; + int vdev_id; + u8 noa_descriptors; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ath11k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb)); + return; + } + + ev = tb[WMI_TAG_P2P_NOA_EVENT]; + noa = tb[WMI_TAG_P2P_NOA_INFO]; + + if (!ev || !noa) + goto out; + + vdev_id = ev->vdev_id; + noa_descriptors = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + + if (noa_descriptors > WMI_P2P_MAX_NOA_DESCRIPTORS) { + ath11k_warn(ab, "invalid descriptor num %d in P2P NoA event\n", + noa_descriptors); + goto out; + } + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "wmi tlv p2p noa vdev_id %i descriptors %u\n", + vdev_id, noa_descriptors); + + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath11k_warn(ab, "invalid vdev id %d in P2P NoA event\n", + vdev_id); + goto unlock; + } + + ath11k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); + +unlock: + rcu_read_unlock(); +out: + kfree(tb); +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -8733,6 +8830,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_GTK_OFFLOAD_STATUS_EVENTID: ath11k_wmi_gtk_offload_status_event(ab, skb); break; + case WMI_P2P_NOA_EVENTID: + ath11k_wmi_p2p_noa_event(ab, skb); + break; default: ath11k_dbg(ab, ATH11K_DBG_WMI, "unsupported event id 0x%x\n", id); break; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index bb419e3abb..8982b909c8 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_WMI_H @@ -60,13 +60,9 @@ struct wmi_tlv { #define WLAN_SCAN_MAX_HINT_BSSID 10 #define MAX_RNR_BSS 5 -#define WLAN_SCAN_MAX_HINT_S_SSID 10 -#define WLAN_SCAN_MAX_HINT_BSSID 10 -#define MAX_RNR_BSS 5 - #define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 @@ -3444,34 +3440,6 @@ struct wmi_bssid_arg { const u8 *bssid; }; -struct wmi_start_scan_arg { - u32 scan_id; - u32 scan_req_id; - u32 vdev_id; - u32 scan_priority; - u32 notify_scan_events; - u32 dwell_time_active; - u32 dwell_time_passive; - u32 min_rest_time; - u32 max_rest_time; - u32 repeat_probe_time; - u32 probe_spacing_time; - u32 idle_time; - u32 max_scan_time; - u32 probe_delay; - u32 scan_ctrl_flags; - - u32 ie_len; - u32 n_channels; - u32 n_ssids; - u32 n_bssids; - - u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN]; - u32 channels[64]; - struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; - struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; -}; - #define WMI_SCAN_STOP_ONE 0x00000000 #define WMI_SCN_STOP_VAP_ALL 0x01000000 #define WMI_SCAN_STOP_ALL 0x04000000 @@ -3630,6 +3598,37 @@ struct wmi_ftm_event_msg { u8 data[]; } __packed; +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 + +struct wmi_p2p_noa_event { + u32 vdev_id; +} __packed; + +struct ath11k_wmi_p2p_noa_descriptor { + u32 type_count; /* 255: continuous schedule, 0: reserved */ + u32 duration; /* Absent period duration in micro seconds */ + u32 interval; /* Absent period interval in micro seconds */ + u32 start_time; /* 32 bit tsf time when in starts */ +} __packed; + +#define WMI_P2P_NOA_INFO_CHANGED_FLAG BIT(0) +#define WMI_P2P_NOA_INFO_INDEX GENMASK(15, 8) +#define WMI_P2P_NOA_INFO_OPP_PS BIT(16) +#define WMI_P2P_NOA_INFO_CTWIN_TU GENMASK(23, 17) +#define WMI_P2P_NOA_INFO_DESC_NUM GENMASK(31, 24) + +struct ath11k_wmi_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + * Bits 15-8 - Index (identifies the instance of NOA sub element) + * Bit 16 - Opp PS state of the AP + * Bits 23-17 - Ctwindow in TUs + * Bits 31-24 - Number of NOA descriptors + */ + u32 noa_attr; + struct ath11k_wmi_p2p_noa_descriptor descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + #define WMI_BEACON_TX_BUFFER_SIZE 512 #define WMI_EMA_TMPL_IDX_SHIFT 8 @@ -3653,6 +3652,13 @@ struct wmi_bcn_tmpl_cmd { u32 ema_params; } __packed; +struct wmi_p2p_go_set_beacon_ie_cmd { + u32 tlv_header; + u32 vdev_id; + u32 ie_buf_len; + u8 tlv[]; +} __packed; + struct wmi_key_seq_counter { u32 key_seq_counter_l; u32 key_seq_counter_h; @@ -5740,8 +5746,6 @@ struct wmi_debug_log_config_cmd_fixed_param { u32 value; } __packed; -#define WMI_MAX_MEM_REQS 32 - #define MAX_RADIOS 3 #define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ) @@ -6349,6 +6353,8 @@ int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, struct sk_buff *frame); +int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id, + const u8 *p2p_ie); int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn, u32 ema_param); |