Major stack changes:

* TC offload support for drivers below mac80211
  * reduced neighbor report (RNR) handling for AP mode
  * mac80211 mesh fast-xmit and fast-rx support
  * support for another mesh A-MSDU format
    (seems nobody got the spec right)
 
 Major driver changes:
 
 Kalle moved the drivers that were just plain C files
 in drivers/net/wireless/ to legacy/ and virtual/ dirs.
 
 hwsim
  * multi-BSSID support
  * some FTM support
 
 ath11k
  * MU-MIMO parameters support
  * ack signal support for management packets
 
 rtl8xxxu
  * support for RTL8710BU aka RTL8188GU chips
 
 rtw89
  * support for various newer firmware APIs
 
 ath10k
  * enabled threaded NAPI on WCN3990
 
 iwlwifi
  * lots of work for multi-link/EHT (wifi7)
  * hardware timestamping support for some devices/firwmares
  * TX beacon protection on newer hardware
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmQl9gkACgkQ10qiO8sP
 aACnTw/+KHEjBePPNSiVOziE6tlKSIruabrsSbBBWWx4btFBT0YAnqiwf4Zyp67r
 VaRWPxRNqjriKMPYDn/bpCrRgkqeN50iCV9n+/xh4TaiLokea0IuA/KDLNM+vBPf
 0VJBpNdW8tKLM0YluGWuoWUAlkjujBzjHaW0sKoII/PLh6evLGEIhqdveE8052Bc
 P3UMu3+FHXg+E1+1tpn/AK+b6bGQeBN3KG3h7uocwR4QE6xROdFPAmXDohbJ98pG
 6EmCDuuFiYPwkKu3GsxmKFNbq7NatPoFtghBPQi4Sn9wGgWWlJcK7hlNTDDW5O7c
 ZqyqY8BiUnh9A1ZcUCKLiHYx+mjxiE2P5wlfDbiZGm7k2JkrBu+AebRvtD4ie/UF
 db8T321kZJ5XKI89yQT2DXzfrvhbw2D85eFudQpIyRguoPKicICLWOyw84+esNTI
 2vqnbPVnYrLQ/X7SzKcdIh74fcSvL8Dj0EiUAzvhPDbgIvexiYDetBXVss8tXBsn
 bpCRND05tpCqqW+LyulglmYTAbhZdCYOy4DAB+g6dtxHOR8A0eLbUHocm0zlPvqd
 sc4pYpXHx4x+X3FPHpfxOqKUO87P7SvJ++d3Y3e09/ObLPSkn65ihsGJpMN/fj1e
 BkJ2yF0KUfJMNhSl5p8VELT3XZevT0EIEKMvwoIgSsWPR8cxqoI=
 =Zi6X
 -----END PGP SIGNATURE-----

Merge tag 'wireless-next-2023-03-30' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
Major stack changes:

 * TC offload support for drivers below mac80211
 * reduced neighbor report (RNR) handling for AP mode
 * mac80211 mesh fast-xmit and fast-rx support
 * support for another mesh A-MSDU format
   (seems nobody got the spec right)

Major driver changes:

Kalle moved the drivers that were just plain C files
in drivers/net/wireless/ to legacy/ and virtual/ dirs.

hwsim
 * multi-BSSID support
 * some FTM support

ath11k
 * MU-MIMO parameters support
 * ack signal support for management packets

rtl8xxxu
 * support for RTL8710BU aka RTL8188GU chips

rtw89
 * support for various newer firmware APIs

ath10k
 * enabled threaded NAPI on WCN3990

iwlwifi
 * lots of work for multi-link/EHT (wifi7)
 * hardware timestamping support for some devices/firwmares
 * TX beacon protection on newer hardware

* tag 'wireless-next-2023-03-30' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (181 commits)
  wifi: clean up erroneously introduced file
  wifi: iwlwifi: mvm: correctly use link in iwl_mvm_sta_del()
  wifi: iwlwifi: separate AP link management queues
  wifi: iwlwifi: mvm: free probe_resp_data later
  wifi: iwlwifi: bump FW API to 75 for AX devices
  wifi: iwlwifi: mvm: move max_agg_bufsize into host TLC lq_sta
  wifi: iwlwifi: mvm: send full STA during HW restart
  wifi: iwlwifi: mvm: rework active links counting
  wifi: iwlwifi: mvm: update mac config when assigning chanctx
  wifi: iwlwifi: mvm: use the correct link queue
  wifi: iwlwifi: mvm: clean up mac_id vs. link_id in MLD sta
  wifi: iwlwifi: mvm: fix station link data leak
  wifi: iwlwifi: mvm: initialize max_rc_amsdu_len per-link
  wifi: iwlwifi: mvm: use appropriate link for rate selection
  wifi: iwlwifi: mvm: use the new lockdep-checking macros
  wifi: iwlwifi: mvm: remove chanctx WARN_ON
  wifi: iwlwifi: mvm: avoid sending MAC context for idle
  wifi: iwlwifi: mvm: remove only link-specific AP keys
  wifi: iwlwifi: mvm: skip inactive links
  wifi: iwlwifi: mvm: adjust iwl_mvm_scan_respect_p2p_go_iter() for MLO
  ...
====================

Link: https://lore.kernel.org/r/20230330205612.921134-1-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2023-03-30 23:52:20 -07:00
commit ce7928f7cf
148 changed files with 14841 additions and 2355 deletions

View File

@ -12276,7 +12276,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
F: Documentation/networking/mac80211-injection.rst
F: Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst
F: drivers/net/wireless/mac80211_hwsim.[ch]
F: drivers/net/wireless/virtual/mac80211_hwsim.[ch]
F: include/net/mac80211.h
F: net/mac80211/
@ -17554,7 +17554,7 @@ F: include/ras/ras_event.h
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
F: drivers/net/wireless/ray*
F: drivers/net/wireless/legacy/ray*
RC-CORE / LIRC FRAMEWORK
M: Sean Young <sean@mess.org>
@ -21798,7 +21798,7 @@ USB WIRELESS RNDIS DRIVER (rndis_wlan)
M: Jussi Kivilinna <jussi.kivilinna@iki.fi>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/rndis_wlan.c
F: drivers/net/wireless/legacy/rndis_wlan.c
USB XHCI DRIVER
M: Mathias Nyman <mathias.nyman@intel.com>
@ -22552,7 +22552,7 @@ F: drivers/input/misc/wistron_btns.c
WL3501 WIRELESS PCMCIA CARD DRIVER
L: linux-wireless@vger.kernel.org
S: Odd fixes
F: drivers/net/wireless/wl3501*
F: drivers/net/wireless/legacy/wl3501*
WOLFSON MICROELECTRONICS DRIVERS
L: patches@opensource.cirrus.com

View File

@ -38,79 +38,8 @@ source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
source "drivers/net/wireless/quantenna/Kconfig"
config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
depends on PCMCIA
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
help
Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
(PC-card) wireless Ethernet networking card to your computer.
Please read the file
<file:Documentation/networking/device_drivers/wifi/ray_cs.rst> for
details.
source "drivers/net/wireless/legacy/Kconfig"
To compile this driver as a module, choose M here: the module will be
called ray_cs. If unsure, say N.
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
depends on CFG80211 && PCMCIA
select WIRELESS_EXT
select WEXT_SPY
help
A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
It has basic support for Linux wireless extensions and initial
micro support for ethtool.
config MAC80211_HWSIM
tristate "Simulated radio testing tool for mac80211"
depends on MAC80211
help
This driver is a developer testing tool that can be used to test
IEEE 802.11 networking stack (mac80211) functionality. This is not
needed for normal wireless LAN usage and is only for testing. See
Documentation/networking/mac80211_hwsim for more information on how
to use this tool.
To compile this driver as a module, choose M here: the module will be
called mac80211_hwsim. If unsure, say N.
config USB_NET_RNDIS_WLAN
tristate "Wireless RNDIS USB support"
depends on USB
depends on CFG80211
select USB_NET_DRIVERS
select USB_USBNET
select USB_NET_CDCETHER
select USB_NET_RNDIS_HOST
help
This is a driver for wireless RNDIS devices.
These are USB based adapters found in devices such as:
Buffalo WLI-U2-KG125S
U.S. Robotics USR5421
Belkin F5D7051
Linksys WUSB54GSv2
Linksys WUSB54GSC
Asus WL169gE
Eminent EM4045
BT Voyager 1055
Linksys WUSB54GSv1
U.S. Robotics USR5420
BUFFALO WLI-USB-G54
All of these devices are based on Broadcom 4320 chip which is the
only wireless RNDIS chip known to date.
If you choose to build a module, it'll be called rndis_wlan.
config VIRT_WIFI
tristate "Wifi wrapper for ethernet drivers"
depends on CFG80211
help
This option adds support for ethernet connections to appear as if they
are wifi connections through a special rtnetlink device.
source "drivers/net/wireless/virtual/Kconfig"
endif # WLAN

View File

@ -23,12 +23,5 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_VIRT_WIFI) += virt_wifi.o
obj-$(CONFIG_WLAN) += legacy/
obj-$(CONFIG_WLAN) += virtual/

View File

@ -96,11 +96,13 @@ struct ath_keyval {
u8 kv_type;
u8 kv_pad;
u16 kv_len;
u8 kv_val[16]; /* TK */
u8 kv_mic[8]; /* Michael MIC key */
u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
* supports both MIC keys in the same key cache entry;
* in that case, kv_mic is the RX key) */
struct_group(kv_values,
u8 kv_val[16]; /* TK */
u8 kv_mic[8]; /* Michael MIC key */
u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
* supports both MIC keys in the same key cache entry;
* in that case, kv_mic is the RX key) */
);
};
enum ath_cipher {

View File

@ -77,45 +77,6 @@ static inline u32 shadow_sr_wr_ind_addr(struct ath10k *ar,
return addr;
}
static inline u32 shadow_dst_wr_ind_addr(struct ath10k *ar,
struct ath10k_ce_pipe *ce_state)
{
u32 ce_id = ce_state->id;
u32 addr = 0;
switch (ce_id) {
case 1:
addr = 0x00032034;
break;
case 2:
addr = 0x00032038;
break;
case 5:
addr = 0x00032044;
break;
case 7:
addr = 0x0003204C;
break;
case 8:
addr = 0x00032050;
break;
case 9:
addr = 0x00032054;
break;
case 10:
addr = 0x00032058;
break;
case 11:
addr = 0x0003205C;
break;
default:
ath10k_warn(ar, "invalid CE id: %d", ce_id);
break;
}
return addr;
}
static inline unsigned int
ath10k_set_ring_byte(unsigned int offset,
struct ath10k_hw_ce_regs_addr_map *addr_map)
@ -438,19 +399,6 @@ static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar,
host_ie_addr & ~(wm_regs->wm_mask));
}
static inline void ath10k_ce_error_intr_enable(struct ath10k *ar,
u32 ce_ctrl_addr)
{
struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs;
u32 misc_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr +
ar->hw_ce_regs->misc_ie_addr);
ath10k_ce_write32(ar,
ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr,
misc_ie_addr | misc_regs->err_mask);
}
static inline void ath10k_ce_error_intr_disable(struct ath10k *ar,
u32 ce_ctrl_addr)
{

View File

@ -6030,7 +6030,6 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex);
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
ar->filter_flags = *total_flags;

View File

@ -927,6 +927,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar)
bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
dev_set_threaded(&ar->napi_dev, true);
ath10k_core_napi_enable(ar);
ath10k_snoc_irq_enable(ar);
ath10k_snoc_rx_post(ar);

View File

@ -874,11 +874,11 @@ static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
ab->pci.msi.ep_base_data = int_prop + 32;
for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!res)
return -ENODEV;
ret = platform_get_irq(pdev, i);
if (ret < 0)
return ret;
ab->pci.msi.irqs[i] = res->start;
ab->pci.msi.irqs[i] = ret;
}
set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
@ -1174,7 +1174,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
* to a new space for accessing them.
*/
ab->mem_ce = ioremap(ce_remap->base, ce_remap->size);
if (IS_ERR(ab->mem_ce)) {
if (!ab->mem_ce) {
dev_err(&pdev->dev, "ce ioremap error\n");
ret = -ENOMEM;
goto err_core_free;

View File

@ -201,6 +201,7 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab,
config->twt_ap_pdev_count = ab->num_radios;
config->twt_ap_sta_count = 1000;
config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64;
config->flag1 |= WMI_RSRC_CFG_FLAG1_ACK_RSSI;
}
static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw,

View File

@ -2699,6 +2699,117 @@ static int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif,
ath11k_smps_map[smps]);
}
static bool ath11k_mac_set_he_txbf_conf(struct ath11k_vif *arvif)
{
struct ath11k *ar = arvif->ar;
u32 param, value;
int ret;
if (!arvif->vif->bss_conf.he_support)
return true;
param = WMI_VDEV_PARAM_SET_HEMU_MODE;
value = 0;
if (arvif->vif->bss_conf.he_su_beamformer) {
value |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE);
if (arvif->vif->bss_conf.he_mu_beamformer &&
arvif->vdev_type == WMI_VDEV_TYPE_AP)
value |= FIELD_PREP(HE_MODE_MU_TX_BFER, HE_MU_BFER_ENABLE);
}
if (arvif->vif->type != NL80211_IFTYPE_MESH_POINT) {
value |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
if (arvif->vif->bss_conf.he_full_ul_mumimo)
value |= FIELD_PREP(HE_MODE_UL_MUMIMO, HE_UL_MUMIMO_ENABLE);
if (arvif->vif->bss_conf.he_su_beamformee)
value |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE);
}
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value);
if (ret) {
ath11k_warn(ar->ab, "failed to set vdev %d HE MU mode: %d\n",
arvif->vdev_id, ret);
return false;
}
param = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE;
value = FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) |
FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE,
HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE);
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param, value);
if (ret) {
ath11k_warn(ar->ab, "failed to set vdev %d sounding mode: %d\n",
arvif->vdev_id, ret);
return false;
}
return true;
}
static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta_he_cap *he_cap)
{
struct ath11k_vif *arvif = (void *)vif->drv_priv;
struct ieee80211_he_cap_elem he_cap_elem = {0};
struct ieee80211_sta_he_cap *cap_band = NULL;
struct cfg80211_chan_def def;
u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE;
u32 hemode = 0;
int ret;
if (!vif->bss_conf.he_support)
return true;
if (vif->type != NL80211_IFTYPE_STATION)
return false;
if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
return false;
if (def.chan->band == NL80211_BAND_2GHZ)
cap_band = &ar->mac.iftype[NL80211_BAND_2GHZ][vif->type].he_cap;
else
cap_band = &ar->mac.iftype[NL80211_BAND_5GHZ][vif->type].he_cap;
memcpy(&he_cap_elem, &cap_band->he_cap_elem, sizeof(he_cap_elem));
if (HECAP_PHY_SUBFME_GET(he_cap_elem.phy_cap_info)) {
if (HECAP_PHY_SUBFMR_GET(he_cap->he_cap_elem.phy_cap_info))
hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE);
if (HECAP_PHY_MUBFMR_GET(he_cap->he_cap_elem.phy_cap_info))
hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE);
}
if (vif->type != NL80211_IFTYPE_MESH_POINT) {
hemode |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
if (HECAP_PHY_ULMUMIMO_GET(he_cap_elem.phy_cap_info))
if (HECAP_PHY_ULMUMIMO_GET(he_cap->he_cap_elem.phy_cap_info))
hemode |= FIELD_PREP(HE_MODE_UL_MUMIMO,
HE_UL_MUMIMO_ENABLE);
if (FIELD_GET(HE_MODE_MU_TX_BFEE, hemode))
hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE);
if (FIELD_GET(HE_MODE_MU_TX_BFER, hemode))
hemode |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE);
}
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, hemode);
if (ret) {
ath11k_warn(ar->ab, "failed to submit vdev param txbf 0x%x: %d\n",
hemode, ret);
return false;
}
return true;
}
static void ath11k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
@ -2709,6 +2820,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_sta *ap_sta;
struct ath11k_peer *peer;
bool is_auth = false;
struct ieee80211_sta_he_cap he_cap;
int ret;
lockdep_assert_held(&ar->conf_mutex);
@ -2726,6 +2838,9 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
return;
}
/* he_cap here is updated at assoc success for sta mode only */
he_cap = ap_sta->deflink.he_cap;
ath11k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false);
rcu_read_unlock();
@ -2753,6 +2868,12 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
return;
}
if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) {
ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n",
arvif->vdev_id, bss_conf->bssid);
return;
}
WARN_ON(arvif->is_up);
arvif->aid = vif->cfg.aid;
@ -3202,6 +3323,8 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
ether_addr_copy(arvif->bssid, info->bssid);
if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (info->enable_beacon)
ath11k_mac_set_he_txbf_conf(arvif);
ath11k_control_beaconing(arvif, info);
if (arvif->is_up && vif->bss_conf.he_support &&
@ -5360,6 +5483,43 @@ static __le16 ath11k_mac_setup_he_6ghz_cap(struct ath11k_pdev_cap *pcap,
return cpu_to_le16(bcap->he_6ghz_capa);
}
static void ath11k_mac_set_hemcsmap(struct ath11k *ar,
struct ath11k_pdev_cap *cap,
struct ieee80211_sta_he_cap *he_cap,
int band)
{
u16 txmcs_map, rxmcs_map;
u32 i;
rxmcs_map = 0;
txmcs_map = 0;
for (i = 0; i < 8; i++) {
if (i < ar->num_tx_chains &&
(ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i))
txmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2);
else
txmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
if (i < ar->num_rx_chains &&
(ar->cfg_rx_chainmask >> cap->tx_chain_mask_shift) & BIT(i))
rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2);
else
rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
}
he_cap->he_mcs_nss_supp.rx_mcs_80 =
cpu_to_le16(rxmcs_map & 0xffff);
he_cap->he_mcs_nss_supp.tx_mcs_80 =
cpu_to_le16(txmcs_map & 0xffff);
he_cap->he_mcs_nss_supp.rx_mcs_160 =
cpu_to_le16(rxmcs_map & 0xffff);
he_cap->he_mcs_nss_supp.tx_mcs_160 =
cpu_to_le16(txmcs_map & 0xffff);
he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
cpu_to_le16(rxmcs_map & 0xffff);
he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
cpu_to_le16(txmcs_map & 0xffff);
}
static int ath11k_mac_copy_he_cap(struct ath11k *ar,
struct ath11k_pdev_cap *cap,
struct ieee80211_sband_iftype_data *data,
@ -5392,6 +5552,10 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
he_cap_elem->mac_cap_info[1] &=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
he_cap_elem->phy_cap_info[0] &=
~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
he_cap_elem->phy_cap_info[0] &=
~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
he_cap_elem->phy_cap_info[5] &=
~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
@ -5417,18 +5581,7 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
break;
}
he_cap->he_mcs_nss_supp.rx_mcs_80 =
cpu_to_le16(band_cap->he_mcs & 0xffff);
he_cap->he_mcs_nss_supp.tx_mcs_80 =
cpu_to_le16(band_cap->he_mcs & 0xffff);
he_cap->he_mcs_nss_supp.rx_mcs_160 =
cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
he_cap->he_mcs_nss_supp.tx_mcs_160 =
cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
ath11k_mac_set_hemcsmap(ar, cap, he_cap, band);
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
@ -6026,69 +6179,6 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif,
}
}
static u32
ath11k_mac_prepare_he_mode(struct ath11k_pdev *pdev, u32 viftype)
{
struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
struct ath11k_band_cap *cap_band = NULL;
u32 *hecap_phy_ptr = NULL;
u32 hemode = 0;
if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP)
cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
else
cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
hecap_phy_ptr = &cap_band->he_cap_phy_info[0];
hemode = FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE) |
FIELD_PREP(HE_MODE_SU_TX_BFER, HECAP_PHY_SUBFMR_GET(hecap_phy_ptr)) |
FIELD_PREP(HE_MODE_UL_MUMIMO, HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr));
/* TODO WDS and other modes */
if (viftype == NL80211_IFTYPE_AP) {
hemode |= FIELD_PREP(HE_MODE_MU_TX_BFER,
HECAP_PHY_MUBFMR_GET(hecap_phy_ptr)) |
FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
} else {
hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE);
}
return hemode;
}
static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
struct ath11k_vif *arvif)
{
u32 param_id, param_value;
struct ath11k_base *ab = ar->ab;
int ret = 0;
param_id = WMI_VDEV_PARAM_SET_HEMU_MODE;
param_value = ath11k_mac_prepare_he_mode(ar->pdev, arvif->vif->type);
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
if (ret) {
ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n",
arvif->vdev_id, ret, param_value);
return ret;
}
param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE;
param_value =
FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) |
FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE,
HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE);
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
if (ret) {
ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d\n",
arvif->vdev_id, ret);
return ret;
}
return ret;
}
static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -6757,7 +6847,6 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
struct ath11k_base *ab = ar->ab;
struct wmi_vdev_start_req_arg arg = {};
const struct cfg80211_chan_def *chandef = &ctx->def;
int he_support = arvif->vif->bss_conf.he_support;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
@ -6798,15 +6887,6 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
spin_lock_bh(&ab->base_lock);
arg.regdomain = ar->ab->dfs_region;
spin_unlock_bh(&ab->base_lock);
if (he_support) {
ret = ath11k_set_he_mu_sounding_mode(ar, arvif);
if (ret) {
ath11k_warn(ar->ab, "failed to set he mode vdev %i\n",
arg.vdev_id);
return ret;
}
}
}
arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
@ -9094,6 +9174,11 @@ static int __ath11k_mac_register(struct ath11k *ar)
goto err_free_if_combs;
}
if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI,
ar->ab->wmi_ab.svc_map))
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
ar->hw->queues = ATH11K_HW_MAX_QUEUES;
ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN;
ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;

View File

@ -382,22 +382,23 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
return -ENOBUFS;
}
mutex_lock(&ar->ab->tbl_mtx_lock);
spin_lock_bh(&ar->ab->base_lock);
peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
if (peer) {
if (peer->vdev_id == param->vdev_id) {
spin_unlock_bh(&ar->ab->base_lock);
mutex_unlock(&ar->ab->tbl_mtx_lock);
return -EINVAL;
}
/* Assume sta is transitioning to another band.
* Remove here the peer from rhash.
*/
mutex_lock(&ar->ab->tbl_mtx_lock);
ath11k_peer_rhash_delete(ar->ab, peer);
mutex_unlock(&ar->ab->tbl_mtx_lock);
}
spin_unlock_bh(&ar->ab->base_lock);
mutex_unlock(&ar->ab->tbl_mtx_lock);
ret = ath11k_wmi_send_peer_create_cmd(ar, param);
if (ret) {

View File

@ -613,13 +613,19 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
{
struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
struct cur_reg_rule *reg_rule;
u8 i = 0, j = 0;
u8 i = 0, j = 0, k = 0;
u8 num_rules;
u16 max_bw;
u32 flags;
char alpha2[3];
num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules;
/* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list.
* This can be updated after complete 6 GHz regulatory support is added.
*/
if (reg_info->is_ext_reg_event)
num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];
if (!num_rules)
goto ret;
@ -640,24 +646,24 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region);
ath11k_dbg(ab, ATH11K_DBG_REG,
"\r\nCountry %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n",
"Country %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n",
alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region),
reg_info->dfs_region, num_rules);
/* Update reg_rules[] below. Firmware is expected to
* send these rules in order(2G rules first and then 5G)
* send these rules in order(2 GHz rules first and then 5 GHz)
*/
for (; i < num_rules; i++) {
if (reg_info->num_2g_reg_rules &&
(i < reg_info->num_2g_reg_rules)) {
reg_rule = reg_info->reg_rules_2g_ptr + i;
if (reg_info->num_2ghz_reg_rules &&
(i < reg_info->num_2ghz_reg_rules)) {
reg_rule = reg_info->reg_rules_2ghz_ptr + i;
max_bw = min_t(u16, reg_rule->max_bw,
reg_info->max_bw_2g);
reg_info->max_bw_2ghz);
flags = 0;
} else if (reg_info->num_5g_reg_rules &&
(j < reg_info->num_5g_reg_rules)) {
reg_rule = reg_info->reg_rules_5g_ptr + j++;
} else if (reg_info->num_5ghz_reg_rules &&
(j < reg_info->num_5ghz_reg_rules)) {
reg_rule = reg_info->reg_rules_5ghz_ptr + j++;
max_bw = min_t(u16, reg_rule->max_bw,
reg_info->max_bw_5g);
reg_info->max_bw_5ghz);
/* FW doesn't pass NL80211_RRF_AUTO_BW flag for
* BW Auto correction, we can enable this by default
@ -666,6 +672,14 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
* per other BW rule flags we pass from here
*/
flags = NL80211_RRF_AUTO_BW;
} else if (reg_info->is_ext_reg_event &&
reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] &&
(k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) {
reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] +
k++;
max_bw = min_t(u16, reg_rule->max_bw,
reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]);
flags = NL80211_RRF_AUTO_BW;
} else {
break;
}
@ -693,12 +707,21 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
continue;
}
ath11k_dbg(ab, ATH11K_DBG_REG,
"\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
i + 1, reg_rule->start_freq, reg_rule->end_freq,
max_bw, reg_rule->ant_gain, reg_rule->reg_power,
tmp_regd->reg_rules[i].dfs_cac_ms,
flags);
if (reg_info->is_ext_reg_event) {
ath11k_dbg(ab, ATH11K_DBG_REG,
"\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n",
i + 1, reg_rule->start_freq, reg_rule->end_freq,
max_bw, reg_rule->ant_gain, reg_rule->reg_power,
tmp_regd->reg_rules[i].dfs_cac_ms, flags,
reg_rule->psd_flag, reg_rule->psd_eirp);
} else {
ath11k_dbg(ab, ATH11K_DBG_REG,
"\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
i + 1, reg_rule->start_freq, reg_rule->end_freq,
max_bw, reg_rule->ant_gain, reg_rule->reg_power,
tmp_regd->reg_rules[i].dfs_cac_ms,
flags);
}
}
tmp_regd->n_reg_rules = i;

View File

@ -105,6 +105,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
= { .min_len = sizeof(struct wmi_vdev_stopped_event) },
[WMI_TAG_REG_CHAN_LIST_CC_EVENT]
= { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) },
[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]
= { .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) },
[WMI_TAG_MGMT_RX_HDR]
= { .min_len = sizeof(struct wmi_mgmt_rx_hdr) },
[WMI_TAG_MGMT_TX_COMPL_EVENT]
@ -2068,6 +2070,12 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar,
WMI_SCAN_EVENT_FOREIGN_CHAN |
WMI_SCAN_EVENT_DEQUEUED;
arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT;
if (test_bit(WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE,
ar->ab->wmi_ab.svc_map))
arg->scan_ctrl_flags_ext |=
WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE;
arg->num_bssid = 1;
/* fill bssid_list[0] with 0xff, otherwise bssid and RA will be
@ -2149,6 +2157,8 @@ ath11k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd,
/* for adaptive scan mode using 3 bits (21 - 23 bits) */
WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags,
param->adaptive_dwell_time_mode);
cmd->scan_ctrl_flags_ext = param->scan_ctrl_flags_ext;
}
int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
@ -3966,6 +3976,10 @@ ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg,
wmi_cfg->sched_params = tg_cfg->sched_params;
wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count;
wmi_cfg->twt_ap_sta_count = tg_cfg->twt_ap_sta_count;
wmi_cfg->host_service_flags &=
~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported <<
WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
}
static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
@ -4184,6 +4198,10 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab)
ab->hw_params.hw_ops->wmi_init_config(ab, &config);
if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,
ab->wmi_ab.svc_map))
config.is_reg_cc_ext_event_supported = 1;
memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config));
init_param.res_cfg = &wmi_sc->wlan_resource_config;
@ -4907,6 +4925,26 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf
return 0;
}
static void ath11k_print_reg_rule(struct ath11k_base *ab, const char *band,
u32 num_reg_rules,
struct cur_reg_rule *reg_rule_ptr)
{
struct cur_reg_rule *reg_rule = reg_rule_ptr;
u32 count;
ath11k_dbg(ab, ATH11K_DBG_WMI, "number of reg rules in %s band: %d\n",
band, num_reg_rules);
for (count = 0; count < num_reg_rules; count++) {
ath11k_dbg(ab, ATH11K_DBG_WMI,
"reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d)\n",
count + 1, reg_rule->start_freq, reg_rule->end_freq,
reg_rule->max_bw, reg_rule->ant_gain,
reg_rule->reg_power, reg_rule->flags);
reg_rule++;
}
}
static struct cur_reg_rule
*create_reg_rules_from_wmi(u32 num_reg_rules,
struct wmi_regulatory_rule_struct *wmi_reg_rule)
@ -4951,7 +4989,7 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
const void **tb;
const struct wmi_reg_chan_list_cc_event *chan_list_event_hdr;
struct wmi_regulatory_rule_struct *wmi_reg_rule;
u32 num_2g_reg_rules, num_5g_reg_rules;
u32 num_2ghz_reg_rules, num_5ghz_reg_rules;
int ret;
ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n");
@ -4970,10 +5008,10 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
return -EPROTO;
}
reg_info->num_2g_reg_rules = chan_list_event_hdr->num_2g_reg_rules;
reg_info->num_5g_reg_rules = chan_list_event_hdr->num_5g_reg_rules;
reg_info->num_2ghz_reg_rules = chan_list_event_hdr->num_2ghz_reg_rules;
reg_info->num_5ghz_reg_rules = chan_list_event_hdr->num_5ghz_reg_rules;
if (!(reg_info->num_2g_reg_rules + reg_info->num_5g_reg_rules)) {
if (!(reg_info->num_2ghz_reg_rules + reg_info->num_5ghz_reg_rules)) {
ath11k_warn(ab, "No regulatory rules available in the event info\n");
kfree(tb);
return -EINVAL;
@ -4987,61 +5025,68 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
reg_info->phy_id = chan_list_event_hdr->phy_id;
reg_info->ctry_code = chan_list_event_hdr->country_id;
reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code;
if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_PASS)
reg_info->status_code = REG_SET_CC_STATUS_PASS;
else if (chan_list_event_hdr->status_code == WMI_REG_CURRENT_ALPHA2_NOT_FOUND)
reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND;
else if (chan_list_event_hdr->status_code == WMI_REG_INIT_ALPHA2_NOT_FOUND)
reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND;
else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_CHANGE_NOT_ALLOWED)
reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED;
else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_NO_MEMORY)
reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY;
else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL)
reg_info->status_code = REG_SET_CC_STATUS_FAIL;
reg_info->min_bw_2g = chan_list_event_hdr->min_bw_2g;
reg_info->max_bw_2g = chan_list_event_hdr->max_bw_2g;
reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g;
reg_info->max_bw_5g = chan_list_event_hdr->max_bw_5g;
num_2g_reg_rules = reg_info->num_2g_reg_rules;
num_5g_reg_rules = reg_info->num_5g_reg_rules;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"%s:cc %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
__func__, reg_info->alpha2, reg_info->dfs_region,
reg_info->min_bw_2g, reg_info->max_bw_2g,
reg_info->min_bw_5g, reg_info->max_bw_5g);
"status_code %s",
ath11k_cc_status_to_str(reg_info->status_code));
reg_info->status_code =
ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code);
reg_info->is_ext_reg_event = false;
reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz;
reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz;
reg_info->min_bw_5ghz = chan_list_event_hdr->min_bw_5ghz;
reg_info->max_bw_5ghz = chan_list_event_hdr->max_bw_5ghz;
num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules;
num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"%s: num_2g_reg_rules %d num_5g_reg_rules %d", __func__,
num_2g_reg_rules, num_5g_reg_rules);
"cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
reg_info->alpha2, reg_info->dfs_region,
reg_info->min_bw_2ghz, reg_info->max_bw_2ghz,
reg_info->min_bw_5ghz, reg_info->max_bw_5ghz);
ath11k_dbg(ab, ATH11K_DBG_WMI,
"num_2ghz_reg_rules %d num_5ghz_reg_rules %d",
num_2ghz_reg_rules, num_5ghz_reg_rules);
wmi_reg_rule =
(struct wmi_regulatory_rule_struct *)((u8 *)chan_list_event_hdr
+ sizeof(*chan_list_event_hdr)
+ sizeof(struct wmi_tlv));
if (num_2g_reg_rules) {
reg_info->reg_rules_2g_ptr = create_reg_rules_from_wmi(num_2g_reg_rules,
wmi_reg_rule);
if (!reg_info->reg_rules_2g_ptr) {
if (num_2ghz_reg_rules) {
reg_info->reg_rules_2ghz_ptr =
create_reg_rules_from_wmi(num_2ghz_reg_rules,
wmi_reg_rule);
if (!reg_info->reg_rules_2ghz_ptr) {
kfree(tb);
ath11k_warn(ab, "Unable to Allocate memory for 2g rules\n");
ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
return -ENOMEM;
}
ath11k_print_reg_rule(ab, "2 GHz",
num_2ghz_reg_rules,
reg_info->reg_rules_2ghz_ptr);
}
if (num_5g_reg_rules) {
wmi_reg_rule += num_2g_reg_rules;
reg_info->reg_rules_5g_ptr = create_reg_rules_from_wmi(num_5g_reg_rules,
wmi_reg_rule);
if (!reg_info->reg_rules_5g_ptr) {
if (num_5ghz_reg_rules) {
wmi_reg_rule += num_2ghz_reg_rules;
reg_info->reg_rules_5ghz_ptr =
create_reg_rules_from_wmi(num_5ghz_reg_rules,
wmi_reg_rule);
if (!reg_info->reg_rules_5ghz_ptr) {
kfree(tb);
ath11k_warn(ab, "Unable to Allocate memory for 5g rules\n");
ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
return -ENOMEM;
}
ath11k_print_reg_rule(ab, "5 GHz",
num_5ghz_reg_rules,
reg_info->reg_rules_5ghz_ptr);
}
ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory channel list\n");
@ -5050,6 +5095,429 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
return 0;
}
static struct cur_reg_rule
*create_ext_reg_rules_from_wmi(u32 num_reg_rules,
struct wmi_regulatory_ext_rule *wmi_reg_rule)
{
struct cur_reg_rule *reg_rule_ptr;
u32 count;
reg_rule_ptr = kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), GFP_ATOMIC);
if (!reg_rule_ptr)
return NULL;
for (count = 0; count < num_reg_rules; count++) {
reg_rule_ptr[count].start_freq =
u32_get_bits(wmi_reg_rule[count].freq_info,
REG_RULE_START_FREQ);
reg_rule_ptr[count].end_freq =
u32_get_bits(wmi_reg_rule[count].freq_info,
REG_RULE_END_FREQ);
reg_rule_ptr[count].max_bw =
u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
REG_RULE_MAX_BW);
reg_rule_ptr[count].reg_power =
u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
REG_RULE_REG_PWR);
reg_rule_ptr[count].ant_gain =
u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
REG_RULE_ANT_GAIN);
reg_rule_ptr[count].flags =
u32_get_bits(wmi_reg_rule[count].flag_info,
REG_RULE_FLAGS);
reg_rule_ptr[count].psd_flag =
u32_get_bits(wmi_reg_rule[count].psd_power_info,
REG_RULE_PSD_INFO);
reg_rule_ptr[count].psd_eirp =
u32_get_bits(wmi_reg_rule[count].psd_power_info,
REG_RULE_PSD_EIRP);
}
return reg_rule_ptr;
}
static u8
ath11k_invalid_5ghz_reg_ext_rules_from_wmi(u32 num_reg_rules,
const struct wmi_regulatory_ext_rule *rule)
{
u8 num_invalid_5ghz_rules = 0;
u32 count, start_freq;
for (count = 0; count < num_reg_rules; count++) {
start_freq = u32_get_bits(rule[count].freq_info,
REG_RULE_START_FREQ);
if (start_freq >= ATH11K_MIN_6G_FREQ)
num_invalid_5ghz_rules++;
}
return num_invalid_5ghz_rules;
}
static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab,
struct sk_buff *skb,
struct cur_regulatory_info *reg_info)
{
const void **tb;
const struct wmi_reg_chan_list_cc_ext_event *ev;
struct wmi_regulatory_ext_rule *ext_wmi_reg_rule;
u32 num_2ghz_reg_rules, num_5ghz_reg_rules;
u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
u32 num_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
u32 total_reg_rules = 0;
int ret, i, j, num_invalid_5ghz_ext_rules = 0;
ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n");
tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
if (IS_ERR(tb)) {
ret = PTR_ERR(tb);
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
return ret;
}
ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
if (!ev) {
ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n");
kfree(tb);
return -EPROTO;
}
reg_info->num_2ghz_reg_rules = ev->num_2ghz_reg_rules;
reg_info->num_5ghz_reg_rules = ev->num_5ghz_reg_rules;
reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] =
ev->num_6ghz_reg_rules_ap_lpi;
reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] =
ev->num_6ghz_reg_rules_ap_sp;
reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] =
ev->num_6ghz_reg_rules_ap_vlp;
for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] =
ev->num_6ghz_reg_rules_client_lpi[i];
reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] =
ev->num_6ghz_reg_rules_client_sp[i];
reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] =
ev->num_6ghz_reg_rules_client_vlp[i];
}
num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules;
num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules;
total_reg_rules += num_2ghz_reg_rules;
total_reg_rules += num_5ghz_reg_rules;
if ((num_2ghz_reg_rules > MAX_REG_RULES) ||
(num_5ghz_reg_rules > MAX_REG_RULES)) {
ath11k_warn(ab, "Num reg rules for 2.4 GHz/5 GHz exceeds max limit (num_2ghz_reg_rules: %d num_5ghz_reg_rules: %d max_rules: %d)\n",
num_2ghz_reg_rules, num_5ghz_reg_rules, MAX_REG_RULES);
kfree(tb);
return -EINVAL;
}
for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
num_6ghz_reg_rules_ap[i] = reg_info->num_6ghz_rules_ap[i];
if (num_6ghz_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) {
ath11k_warn(ab, "Num 6 GHz reg rules for AP mode(%d) exceeds max limit (num_6ghz_reg_rules_ap: %d, max_rules: %d)\n",
i, num_6ghz_reg_rules_ap[i], MAX_6GHZ_REG_RULES);
kfree(tb);
return -EINVAL;
}
total_reg_rules += num_6ghz_reg_rules_ap[i];
}
for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
num_6ghz_client[WMI_REG_INDOOR_AP][i] =
reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i];
total_reg_rules += num_6ghz_client[WMI_REG_INDOOR_AP][i];
num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i];
total_reg_rules += num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i];
num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i];
total_reg_rules += num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i];
if ((num_6ghz_client[WMI_REG_INDOOR_AP][i] > MAX_6GHZ_REG_RULES) ||
(num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] >
MAX_6GHZ_REG_RULES) ||
(num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] >
MAX_6GHZ_REG_RULES)) {
ath11k_warn(ab,
"Num 6 GHz client reg rules exceeds max limit, for client(type: %d)\n",
i);
kfree(tb);
return -EINVAL;
}
}
if (!total_reg_rules) {
ath11k_warn(ab, "No reg rules available\n");
kfree(tb);
return -EINVAL;
}
memcpy(reg_info->alpha2, &ev->alpha2, REG_ALPHA2_LEN);
reg_info->dfs_region = ev->dfs_region;
reg_info->phybitmap = ev->phybitmap;
reg_info->num_phy = ev->num_phy;
reg_info->phy_id = ev->phy_id;
reg_info->ctry_code = ev->country_id;
reg_info->reg_dmn_pair = ev->domain_code;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"status_code %s",
ath11k_cc_status_to_str(reg_info->status_code));
reg_info->status_code =
ath11k_wmi_cc_setting_code_to_reg(ev->status_code);
reg_info->is_ext_reg_event = true;
reg_info->min_bw_2ghz = ev->min_bw_2ghz;
reg_info->max_bw_2ghz = ev->max_bw_2ghz;
reg_info->min_bw_5ghz = ev->min_bw_5ghz;
reg_info->max_bw_5ghz = ev->max_bw_5ghz;
reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
ev->min_bw_6ghz_ap_lpi;
reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
ev->max_bw_6ghz_ap_lpi;
reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
ev->min_bw_6ghz_ap_sp;
reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
ev->max_bw_6ghz_ap_sp;
reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
ev->min_bw_6ghz_ap_vlp;
reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
ev->max_bw_6ghz_ap_vlp;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz AP BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n",
reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP],
reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP],
reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP],
reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP],
reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP],
reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP]);
for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
ev->min_bw_6ghz_client_lpi[i];
reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
ev->max_bw_6ghz_client_lpi[i];
reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
ev->min_bw_6ghz_client_sp[i];
reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
ev->max_bw_6ghz_client_sp[i];
reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
ev->min_bw_6ghz_client_vlp[i];
reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
ev->max_bw_6ghz_client_vlp[i];
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz %s BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n",
ath11k_6ghz_client_type_to_str(i),
reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i],
reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i],
reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i],
reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i],
reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i],
reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i]);
}
ath11k_dbg(ab, ATH11K_DBG_WMI,
"cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
reg_info->alpha2, reg_info->dfs_region,
reg_info->min_bw_2ghz, reg_info->max_bw_2ghz,
reg_info->min_bw_5ghz, reg_info->max_bw_5ghz);
ath11k_dbg(ab, ATH11K_DBG_WMI,
"num_2ghz_reg_rules %d num_5ghz_reg_rules %d",
num_2ghz_reg_rules, num_5ghz_reg_rules);
ath11k_dbg(ab, ATH11K_DBG_WMI,
"num_6ghz_reg_rules_ap_lpi: %d num_6ghz_reg_rules_ap_sp: %d num_6ghz_reg_rules_ap_vlp: %d",
num_6ghz_reg_rules_ap[WMI_REG_INDOOR_AP],
num_6ghz_reg_rules_ap[WMI_REG_STANDARD_POWER_AP],
num_6ghz_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP]);
j = WMI_REG_DEFAULT_CLIENT;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz Regular client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d",
num_6ghz_client[WMI_REG_INDOOR_AP][j],
num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j],
num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);
j = WMI_REG_SUBORDINATE_CLIENT;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz Subordinate client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d",
num_6ghz_client[WMI_REG_INDOOR_AP][j],
num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j],
num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);
ext_wmi_reg_rule =
(struct wmi_regulatory_ext_rule *)((u8 *)ev + sizeof(*ev) +
sizeof(struct wmi_tlv));
if (num_2ghz_reg_rules) {
reg_info->reg_rules_2ghz_ptr =
create_ext_reg_rules_from_wmi(num_2ghz_reg_rules,
ext_wmi_reg_rule);
if (!reg_info->reg_rules_2ghz_ptr) {
kfree(tb);
ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
return -ENOMEM;
}
ath11k_print_reg_rule(ab, "2 GHz",
num_2ghz_reg_rules,
reg_info->reg_rules_2ghz_ptr);
}
ext_wmi_reg_rule += num_2ghz_reg_rules;
/* Firmware might include 6 GHz reg rule in 5 GHz rule list
* for few countries along with separate 6 GHz rule.
* Having same 6 GHz reg rule in 5 GHz and 6 GHz rules list
* causes intersect check to be true, and same rules will be
* shown multiple times in iw cmd.
* Hence, avoid parsing 6 GHz rule from 5 GHz reg rule list
*/
num_invalid_5ghz_ext_rules =
ath11k_invalid_5ghz_reg_ext_rules_from_wmi(num_5ghz_reg_rules,
ext_wmi_reg_rule);
if (num_invalid_5ghz_ext_rules) {
ath11k_dbg(ab, ATH11K_DBG_WMI,
"CC: %s 5 GHz reg rules number %d from fw, %d number of invalid 5 GHz rules",
reg_info->alpha2, reg_info->num_5ghz_reg_rules,
num_invalid_5ghz_ext_rules);
num_5ghz_reg_rules = num_5ghz_reg_rules - num_invalid_5ghz_ext_rules;
reg_info->num_5ghz_reg_rules = num_5ghz_reg_rules;
}
if (num_5ghz_reg_rules) {
reg_info->reg_rules_5ghz_ptr =
create_ext_reg_rules_from_wmi(num_5ghz_reg_rules,
ext_wmi_reg_rule);
if (!reg_info->reg_rules_5ghz_ptr) {
kfree(tb);
ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
return -ENOMEM;
}
ath11k_print_reg_rule(ab, "5 GHz",
num_5ghz_reg_rules,
reg_info->reg_rules_5ghz_ptr);
}
/* We have adjusted the number of 5 GHz reg rules above. But still those
* many rules needs to be adjusted in ext_wmi_reg_rule.
*
* NOTE: num_invalid_5ghz_ext_rules will be 0 for rest other cases.
*/
ext_wmi_reg_rule += (num_5ghz_reg_rules + num_invalid_5ghz_ext_rules);
for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
reg_info->reg_rules_6ghz_ap_ptr[i] =
create_ext_reg_rules_from_wmi(num_6ghz_reg_rules_ap[i],
ext_wmi_reg_rule);
if (!reg_info->reg_rules_6ghz_ap_ptr[i]) {
kfree(tb);
ath11k_warn(ab, "Unable to Allocate memory for 6 GHz AP rules\n");
return -ENOMEM;
}
ath11k_print_reg_rule(ab, ath11k_6ghz_ap_type_to_str(i),
num_6ghz_reg_rules_ap[i],
reg_info->reg_rules_6ghz_ap_ptr[i]);
ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i];
}
for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz AP type %s", ath11k_6ghz_ap_type_to_str(j));
for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
reg_info->reg_rules_6ghz_client_ptr[j][i] =
create_ext_reg_rules_from_wmi(num_6ghz_client[j][i],
ext_wmi_reg_rule);
if (!reg_info->reg_rules_6ghz_client_ptr[j][i]) {
kfree(tb);
ath11k_warn(ab, "Unable to Allocate memory for 6 GHz client rules\n");
return -ENOMEM;
}
ath11k_print_reg_rule(ab,
ath11k_6ghz_client_type_to_str(i),
num_6ghz_client[j][i],
reg_info->reg_rules_6ghz_client_ptr[j][i]);
ext_wmi_reg_rule += num_6ghz_client[j][i];
}
}
reg_info->client_type = ev->client_type;
reg_info->rnr_tpe_usable = ev->rnr_tpe_usable;
reg_info->unspecified_ap_usable =
ev->unspecified_ap_usable;
reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] =
ev->domain_code_6ghz_ap_lpi;
reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
ev->domain_code_6ghz_ap_sp;
reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
ev->domain_code_6ghz_ap_vlp;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s, sp %s, vlp %s\n",
ath11k_6ghz_client_type_to_str(reg_info->client_type),
reg_info->rnr_tpe_usable,
reg_info->unspecified_ap_usable,
ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_lpi),
ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_sp),
ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_vlp));
for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] =
ev->domain_code_6ghz_client_lpi[i];
reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
ev->domain_code_6ghz_client_sp[i];
reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
ev->domain_code_6ghz_client_vlp[i];
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz client type %s client sub domain: lpi %s, sp %s, vlp %s\n",
ath11k_6ghz_client_type_to_str(i),
ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_lpi[i]),
ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_sp[i]),
ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_vlp[i])
);
}
reg_info->domain_code_6ghz_super_id = ev->domain_code_6ghz_super_id;
ath11k_dbg(ab, ATH11K_DBG_WMI,
"6 GHz client_type %s 6 GHz super domain %s",
ath11k_6ghz_client_type_to_str(reg_info->client_type),
ath11k_super_reg_6ghz_to_str(reg_info->domain_code_6ghz_super_id));
ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n");
kfree(tb);
return 0;
}
static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *skb,
struct wmi_peer_delete_resp_event *peer_del_resp)
{
@ -5221,8 +5689,8 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab,
return 0;
}
static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
u32 status)
static int wmi_process_mgmt_tx_comp(struct ath11k *ar,
struct wmi_mgmt_tx_compl_event *tx_compl_param)
{
struct sk_buff *msdu;
struct ieee80211_tx_info *info;
@ -5230,24 +5698,29 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
int num_mgmt;
spin_lock_bh(&ar->txmgmt_idr_lock);
msdu = idr_find(&ar->txmgmt_idr, desc_id);
msdu = idr_find(&ar->txmgmt_idr, tx_compl_param->desc_id);
if (!msdu) {
ath11k_warn(ar->ab, "received mgmt tx compl for invalid msdu_id: %d\n",
desc_id);
tx_compl_param->desc_id);
spin_unlock_bh(&ar->txmgmt_idr_lock);
return -ENOENT;
}
idr_remove(&ar->txmgmt_idr, desc_id);
idr_remove(&ar->txmgmt_idr, tx_compl_param->desc_id);
spin_unlock_bh(&ar->txmgmt_idr_lock);
skb_cb = ATH11K_SKB_CB(msdu);
dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
info = IEEE80211_SKB_CB(msdu);
if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status)
if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) &&
!tx_compl_param->status) {
info->flags |= IEEE80211_TX_STAT_ACK;
if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI,
ar->ab->wmi_ab.svc_map))
info->status.ack_signal = tx_compl_param->ack_rssi;
}
ieee80211_tx_status_irqsafe(ar->hw, msdu);
@ -5259,7 +5732,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"wmi mgmt tx comp pending %d desc id %d\n",
num_mgmt, desc_id);
num_mgmt, tx_compl_param->desc_id);
if (!num_mgmt)
wake_up(&ar->txmgmt_empty_waitq);
@ -5292,6 +5765,7 @@ static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab,
param->pdev_id = ev->pdev_id;
param->desc_id = ev->desc_id;
param->status = ev->status;
param->ack_rssi = ev->ack_rssi;
kfree(tb);
return 0;
@ -6491,12 +6965,14 @@ static bool ath11k_reg_is_world_alpha(char *alpha)
return false;
}
static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb)
static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
struct sk_buff *skb,
enum wmi_reg_chan_list_cmd_type id)
{
struct cur_regulatory_info *reg_info = NULL;
struct ieee80211_regdomain *regd = NULL;
bool intersect = false;
int ret = 0, pdev_idx;
int ret = 0, pdev_idx, i, j;
struct ath11k *ar;
reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
@ -6505,7 +6981,11 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
goto fallback;
}
ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
if (id == WMI_REG_CHAN_LIST_CC_ID)
ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
else
ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
if (ret) {
ath11k_warn(ab, "failed to extract regulatory info from received event\n");
goto fallback;
@ -6605,8 +7085,16 @@ fallback:
WARN_ON(1);
mem_free:
if (reg_info) {
kfree(reg_info->reg_rules_2g_ptr);
kfree(reg_info->reg_rules_5g_ptr);
kfree(reg_info->reg_rules_2ghz_ptr);
kfree(reg_info->reg_rules_5ghz_ptr);
if (reg_info->is_ext_reg_event) {
for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
kfree(reg_info->reg_rules_6ghz_ap_ptr[i]);
for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)
kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]);
}
kfree(reg_info);
}
return ret;
@ -7062,13 +7550,12 @@ static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *s
goto exit;
}
wmi_process_mgmt_tx_comp(ar, tx_compl_param.desc_id,
tx_compl_param.status);
wmi_process_mgmt_tx_comp(ar, &tx_compl_param);
ath11k_dbg(ab, ATH11K_DBG_MGMT,
"mgmt tx compl ev pdev_id %d, desc_id %d, status %d",
"mgmt tx compl ev pdev_id %d, desc_id %d, status %d ack_rssi %d",
tx_compl_param.pdev_id, tx_compl_param.desc_id,
tx_compl_param.status);
tx_compl_param.status, tx_compl_param.ack_rssi);
exit:
rcu_read_unlock();
@ -8039,7 +8526,10 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
ath11k_service_ready_ext2_event(ab, skb);
break;
case WMI_REG_CHAN_LIST_CC_EVENTID:
ath11k_reg_chan_list_event(ab, skb);
ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_ID);
break;
case WMI_REG_CHAN_LIST_CC_EXT_EVENTID:
ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_EXT_ID);
break;
case WMI_READY_EVENTID:
ath11k_ready_event(ab, skb);

View File

@ -797,6 +797,7 @@ enum wmi_tlv_event_id {
WMI_RMC_NEW_LEADER_EVENTID = WMI_TLV_CMD(WMI_GRP_RMC),
WMI_REG_CHAN_LIST_CC_EVENTID = WMI_TLV_CMD(WMI_GRP_REGULATORY),
WMI_11D_NEW_COUNTRY_EVENTID,
WMI_REG_CHAN_LIST_CC_EXT_EVENTID,
WMI_NDI_CAP_RSP_EVENTID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE),
WMI_NDP_INITIATOR_RSP_EVENTID,
WMI_NDP_RESPONDER_RSP_EVENTID,
@ -1865,6 +1866,8 @@ enum wmi_tlv_tag {
WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD,
WMI_TAG_MAX
@ -2093,9 +2096,11 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_EXT2_MSG = 220,
WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246,
WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249,
WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263,
/* The second 128 bits */
WMI_MAX_EXT_SERVICE = 256,
WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326,
/* The third 128 bits */
@ -2310,6 +2315,9 @@ struct wmi_init_cmd {
} __packed;
#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
#define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4
struct wmi_resource_config {
u32 tlv_header;
@ -2370,6 +2378,15 @@ struct wmi_resource_config {
u32 sched_params;
u32 twt_ap_pdev_count;
u32 twt_ap_sta_count;
u32 max_nlo_ssids;
u32 num_pkt_filters;
u32 num_max_sta_vdevs;
u32 max_bssid_indicator;
u32 ul_resp_config;
u32 msdu_flow_override_config0;
u32 msdu_flow_override_config1;
u32 flags2;
u32 host_service_flags;
} __packed;
struct wmi_service_ready_event {
@ -2852,36 +2869,40 @@ struct rx_reorder_queue_remove_params {
#define REG_RULE_MAX_BW 0x0000ffff
#define REG_RULE_REG_PWR 0x00ff0000
#define REG_RULE_ANT_GAIN 0xff000000
#define REG_RULE_PSD_INFO BIT(0)
#define REG_RULE_PSD_EIRP 0xff0000
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2)
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
#define HECAP_PHYDWORD_0 0
#define HECAP_PHYDWORD_1 1
#define HECAP_PHYDWORD_2 2
#define HE_PHYCAP_BYTE_0 0
#define HE_PHYCAP_BYTE_1 1
#define HE_PHYCAP_BYTE_2 2
#define HE_PHYCAP_BYTE_3 3
#define HE_PHYCAP_BYTE_4 4
#define HECAP_PHY_SU_BFER BIT(31)
#define HECAP_PHY_SU_BFER BIT(7)
#define HECAP_PHY_SU_BFEE BIT(0)
#define HECAP_PHY_MU_BFER BIT(1)
#define HECAP_PHY_UL_MUMIMO BIT(22)
#define HECAP_PHY_UL_MUOFDMA BIT(23)
#define HECAP_PHY_UL_MUMIMO BIT(6)
#define HECAP_PHY_UL_MUOFDMA BIT(7)
#define HECAP_PHY_SUBFMR_GET(hecap_phy) \
FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HECAP_PHYDWORD_0])
FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HE_PHYCAP_BYTE_3])
#define HECAP_PHY_SUBFME_GET(hecap_phy) \
FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HECAP_PHYDWORD_1])
FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HE_PHYCAP_BYTE_4])
#define HECAP_PHY_MUBFMR_GET(hecap_phy) \
FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HECAP_PHYDWORD_1])
FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HE_PHYCAP_BYTE_4])
#define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \
FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HECAP_PHYDWORD_0])
FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HE_PHYCAP_BYTE_2])
#define HECAP_PHY_ULOFDMA_GET(hecap_phy) \
FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HECAP_PHYDWORD_0])
FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HE_PHYCAP_BYTE_2])
#define HE_MODE_SU_TX_BFEE BIT(0)
#define HE_MODE_SU_TX_BFER BIT(1)
@ -2894,8 +2915,11 @@ struct rx_reorder_queue_remove_params {
#define HE_DL_MUOFDMA_ENABLE 1
#define HE_UL_MUOFDMA_ENABLE 1
#define HE_DL_MUMIMO_ENABLE 1
#define HE_UL_MUMIMO_ENABLE 1
#define HE_MU_BFEE_ENABLE 1
#define HE_SU_BFEE_ENABLE 1
#define HE_MU_BFER_ENABLE 1
#define HE_SU_BFER_ENABLE 1
#define HE_VHT_SOUNDING_MODE_ENABLE 1
#define HE_SU_MU_SOUNDING_MODE_ENABLE 1
@ -3223,6 +3247,7 @@ struct wmi_start_scan_cmd {
#define WMI_SCAN_DWELL_MODE_MASK 0x00E00000
#define WMI_SCAN_DWELL_MODE_SHIFT 21
#define WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE 0x00000800
enum {
WMI_SCAN_DWELL_MODE_DEFAULT = 0,
@ -3270,6 +3295,7 @@ struct scan_req_params {
};
u32 scan_events;
};
u32 scan_ctrl_flags_ext;
u32 dwell_time_active;
u32 dwell_time_active_2g;
u32 dwell_time_passive;
@ -4040,6 +4066,7 @@ struct wmi_he_rate_set {
#define MAX_REG_RULES 10
#define REG_ALPHA2_LEN 2
#define MAX_6GHZ_REG_RULES 5
enum wmi_start_event_param {
WMI_VDEV_START_RESP_EVENT = 0,
@ -4070,16 +4097,6 @@ enum wmi_vdev_start_resp_status_code {
WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN = 4,
};
;
enum cc_setting_code {
REG_SET_CC_STATUS_PASS = 0,
REG_CURRENT_ALPHA2_NOT_FOUND = 1,
REG_INIT_ALPHA2_NOT_FOUND = 2,
REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
REG_SET_CC_STATUS_NO_MEMORY = 4,
REG_SET_CC_STATUS_FAIL = 5,
};
/* Regaulatory Rule Flags Passed by FW */
#define REGULATORY_CHAN_DISABLED BIT(0)
#define REGULATORY_CHAN_NO_IR BIT(1)
@ -4093,15 +4110,216 @@ enum cc_setting_code {
#define REGULATORY_CHAN_NO_20MHZ BIT(11)
#define REGULATORY_CHAN_NO_10MHZ BIT(12)
enum {
enum wmi_reg_chan_list_cmd_type {
WMI_REG_CHAN_LIST_CC_ID = 0,
WMI_REG_CHAN_LIST_CC_EXT_ID = 1,
};
enum wmi_reg_cc_setting_code {
WMI_REG_SET_CC_STATUS_PASS = 0,
WMI_REG_CURRENT_ALPHA2_NOT_FOUND = 1,
WMI_REG_INIT_ALPHA2_NOT_FOUND = 2,
WMI_REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
WMI_REG_SET_CC_STATUS_NO_MEMORY = 4,
WMI_REG_SET_CC_STATUS_FAIL = 5,
/* add new setting code above, update in
* @enum cc_setting_code as well.
* Also handle it in ath11k_wmi_cc_setting_code_to_reg()
*/
};
enum cc_setting_code {
REG_SET_CC_STATUS_PASS = 0,
REG_CURRENT_ALPHA2_NOT_FOUND = 1,
REG_INIT_ALPHA2_NOT_FOUND = 2,
REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
REG_SET_CC_STATUS_NO_MEMORY = 4,
REG_SET_CC_STATUS_FAIL = 5,
/* add new setting code above, update in
* @enum wmi_reg_cc_setting_code as well.
* Also handle it in ath11k_cc_status_to_str()
*/
};
static inline enum cc_setting_code
ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code)
{
switch (status_code) {
case WMI_REG_SET_CC_STATUS_PASS:
return REG_SET_CC_STATUS_PASS;
case WMI_REG_CURRENT_ALPHA2_NOT_FOUND:
return REG_CURRENT_ALPHA2_NOT_FOUND;
case WMI_REG_INIT_ALPHA2_NOT_FOUND:
return REG_INIT_ALPHA2_NOT_FOUND;
case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED:
return REG_SET_CC_CHANGE_NOT_ALLOWED;
case WMI_REG_SET_CC_STATUS_NO_MEMORY:
return REG_SET_CC_STATUS_NO_MEMORY;
case WMI_REG_SET_CC_STATUS_FAIL:
return REG_SET_CC_STATUS_FAIL;
}
return REG_SET_CC_STATUS_FAIL;
}
static inline const char *ath11k_cc_status_to_str(enum cc_setting_code code)
{
switch (code) {
case REG_SET_CC_STATUS_PASS:
return "REG_SET_CC_STATUS_PASS";
case REG_CURRENT_ALPHA2_NOT_FOUND:
return "REG_CURRENT_ALPHA2_NOT_FOUND";
case REG_INIT_ALPHA2_NOT_FOUND:
return "REG_INIT_ALPHA2_NOT_FOUND";
case REG_SET_CC_CHANGE_NOT_ALLOWED:
return "REG_SET_CC_CHANGE_NOT_ALLOWED";
case REG_SET_CC_STATUS_NO_MEMORY:
return "REG_SET_CC_STATUS_NO_MEMORY";
case REG_SET_CC_STATUS_FAIL:
return "REG_SET_CC_STATUS_FAIL";
}
return "Unknown CC status";
}
enum wmi_reg_6ghz_ap_type {
WMI_REG_INDOOR_AP = 0,
WMI_REG_STANDARD_POWER_AP = 1,
WMI_REG_VERY_LOW_POWER_AP = 2,
/* add AP type above, handle in ath11k_6ghz_ap_type_to_str()
*/
WMI_REG_CURRENT_MAX_AP_TYPE,
WMI_REG_MAX_AP_TYPE = 7,
};
static inline const char *
ath11k_6ghz_ap_type_to_str(enum wmi_reg_6ghz_ap_type type)
{
switch (type) {
case WMI_REG_INDOOR_AP:
return "INDOOR AP";
case WMI_REG_STANDARD_POWER_AP:
return "STANDARD POWER AP";
case WMI_REG_VERY_LOW_POWER_AP:
return "VERY LOW POWER AP";
case WMI_REG_CURRENT_MAX_AP_TYPE:
return "CURRENT_MAX_AP_TYPE";
case WMI_REG_MAX_AP_TYPE:
return "MAX_AP_TYPE";
}
return "unknown 6 GHz AP type";
}
enum wmi_reg_6ghz_client_type {
WMI_REG_DEFAULT_CLIENT = 0,
WMI_REG_SUBORDINATE_CLIENT = 1,
WMI_REG_MAX_CLIENT_TYPE = 2,
/* add client type above, handle it in
* ath11k_6ghz_client_type_to_str()
*/
};
static inline const char *
ath11k_6ghz_client_type_to_str(enum wmi_reg_6ghz_client_type type)
{
switch (type) {
case WMI_REG_DEFAULT_CLIENT:
return "DEFAULT CLIENT";
case WMI_REG_SUBORDINATE_CLIENT:
return "SUBORDINATE CLIENT";
case WMI_REG_MAX_CLIENT_TYPE:
return "MAX_CLIENT_TYPE";
}
return "unknown 6 GHz client type";
}
enum reg_subdomains_6ghz {
EMPTY_6GHZ = 0x0,
FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
FCC1_CLIENT_SP_6GHZ = 0x02,
FCC1_AP_LPI_6GHZ = 0x03,
FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
FCC1_AP_SP_6GHZ = 0x04,
ETSI1_LPI_6GHZ = 0x10,
ETSI1_VLP_6GHZ = 0x11,
ETSI2_LPI_6GHZ = 0x12,
ETSI2_VLP_6GHZ = 0x13,
APL1_LPI_6GHZ = 0x20,
APL1_VLP_6GHZ = 0x21,
/* add sub-domain above, handle it in
* ath11k_sub_reg_6ghz_to_str()
*/
};
static inline const char *
ath11k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id)
{
switch (sub_id) {
case EMPTY_6GHZ:
return "N/A";
case FCC1_CLIENT_LPI_REGULAR_6GHZ:
return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
case FCC1_CLIENT_SP_6GHZ:
return "FCC1_CLIENT_SP_6GHZ";
case FCC1_AP_LPI_6GHZ:
return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
case FCC1_AP_SP_6GHZ:
return "FCC1_AP_SP_6GHZ";
case ETSI1_LPI_6GHZ:
return "ETSI1_LPI_6GHZ";
case ETSI1_VLP_6GHZ:
return "ETSI1_VLP_6GHZ";
case ETSI2_LPI_6GHZ:
return "ETSI2_LPI_6GHZ";
case ETSI2_VLP_6GHZ:
return "ETSI2_VLP_6GHZ";
case APL1_LPI_6GHZ:
return "APL1_LPI_6GHZ";
case APL1_VLP_6GHZ:
return "APL1_VLP_6GHZ";
}
return "unknown sub reg id";
}
enum reg_super_domain_6ghz {
FCC1_6GHZ = 0x01,
ETSI1_6GHZ = 0x02,
ETSI2_6GHZ = 0x03,
APL1_6GHZ = 0x04,
FCC1_6GHZ_CL = 0x05,
/* add super domain above, handle it in
* ath11k_super_reg_6ghz_to_str()
*/
};
static inline const char *
ath11k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id)
{
switch (domain_id) {
case FCC1_6GHZ:
return "FCC1_6GHZ";
case ETSI1_6GHZ:
return "ETSI1_6GHZ";
case ETSI2_6GHZ:
return "ETSI2_6GHZ";
case APL1_6GHZ:
return "APL1_6GHZ";
case FCC1_6GHZ_CL:
return "FCC1_6GHZ_CL";
}
return "unknown domain id";
}
struct cur_reg_rule {
u16 start_freq;
u16 end_freq;
@ -4109,6 +4327,8 @@ struct cur_reg_rule {
u8 reg_power;
u8 ant_gain;
u16 flags;
bool psd_flag;
s8 psd_eirp;
};
struct cur_regulatory_info {
@ -4120,14 +4340,30 @@ struct cur_regulatory_info {
u8 alpha2[REG_ALPHA2_LEN + 1];
u32 dfs_region;
u32 phybitmap;
u32 min_bw_2g;
u32 max_bw_2g;
u32 min_bw_5g;
u32 max_bw_5g;
u32 num_2g_reg_rules;
u32 num_5g_reg_rules;
struct cur_reg_rule *reg_rules_2g_ptr;
struct cur_reg_rule *reg_rules_5g_ptr;
u32 min_bw_2ghz;
u32 max_bw_2ghz;
u32 min_bw_5ghz;
u32 max_bw_5ghz;
u32 num_2ghz_reg_rules;
u32 num_5ghz_reg_rules;
struct cur_reg_rule *reg_rules_2ghz_ptr;
struct cur_reg_rule *reg_rules_5ghz_ptr;
bool is_ext_reg_event;
enum wmi_reg_6ghz_client_type client_type;
bool rnr_tpe_usable;
bool unspecified_ap_usable;
u8 domain_code_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
u8 domain_code_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
u32 domain_code_6ghz_super_id;
u32 min_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
u32 max_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
u32 min_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
u32 max_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
u32 num_6ghz_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
u32 num_6ghz_rules_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
struct cur_reg_rule *reg_rules_6ghz_ap_ptr[WMI_REG_CURRENT_MAX_AP_TYPE];
struct cur_reg_rule *reg_rules_6ghz_client_ptr
[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
};
struct wmi_reg_chan_list_cc_event {
@ -4139,12 +4375,12 @@ struct wmi_reg_chan_list_cc_event {
u32 domain_code;
u32 dfs_region;
u32 phybitmap;
u32 min_bw_2g;
u32 max_bw_2g;
u32 min_bw_5g;
u32 max_bw_5g;
u32 num_2g_reg_rules;
u32 num_5g_reg_rules;
u32 min_bw_2ghz;
u32 max_bw_2ghz;
u32 min_bw_5ghz;
u32 max_bw_5ghz;
u32 num_2ghz_reg_rules;
u32 num_5ghz_reg_rules;
} __packed;
struct wmi_regulatory_rule_struct {
@ -4154,6 +4390,61 @@ struct wmi_regulatory_rule_struct {
u32 flag_info;
};
#define WMI_REG_CLIENT_MAX 4
struct wmi_reg_chan_list_cc_ext_event {
u32 status_code;
u32 phy_id;
u32 alpha2;
u32 num_phy;
u32 country_id;
u32 domain_code;
u32 dfs_region;
u32 phybitmap;
u32 min_bw_2ghz;
u32 max_bw_2ghz;
u32 min_bw_5ghz;
u32 max_bw_5ghz;
u32 num_2ghz_reg_rules;
u32 num_5ghz_reg_rules;
u32 client_type;
u32 rnr_tpe_usable;
u32 unspecified_ap_usable;
u32 domain_code_6ghz_ap_lpi;
u32 domain_code_6ghz_ap_sp;
u32 domain_code_6ghz_ap_vlp;
u32 domain_code_6ghz_client_lpi[WMI_REG_CLIENT_MAX];
u32 domain_code_6ghz_client_sp[WMI_REG_CLIENT_MAX];
u32 domain_code_6ghz_client_vlp[WMI_REG_CLIENT_MAX];
u32 domain_code_6ghz_super_id;
u32 min_bw_6ghz_ap_sp;
u32 max_bw_6ghz_ap_sp;
u32 min_bw_6ghz_ap_lpi;
u32 max_bw_6ghz_ap_lpi;
u32 min_bw_6ghz_ap_vlp;
u32 max_bw_6ghz_ap_vlp;
u32 min_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX];
u32 max_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX];
u32 min_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX];
u32 max_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX];
u32 min_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX];
u32 max_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX];
u32 num_6ghz_reg_rules_ap_sp;
u32 num_6ghz_reg_rules_ap_lpi;
u32 num_6ghz_reg_rules_ap_vlp;
u32 num_6ghz_reg_rules_client_sp[WMI_REG_CLIENT_MAX];
u32 num_6ghz_reg_rules_client_lpi[WMI_REG_CLIENT_MAX];
u32 num_6ghz_reg_rules_client_vlp[WMI_REG_CLIENT_MAX];
} __packed;
struct wmi_regulatory_ext_rule {
u32 tlv_header;
u32 freq_info;
u32 bw_pwr_info;
u32 flag_info;
u32 psd_power_info;
} __packed;
struct wmi_vdev_delete_resp_event {
u32 vdev_id;
} __packed;
@ -4542,6 +4833,8 @@ struct wmi_mgmt_tx_compl_event {
u32 desc_id;
u32 status;
u32 pdev_id;
u32 ppdu_id;
u32 ack_rssi;
} __packed;
struct wmi_scan_event {
@ -5347,6 +5640,7 @@ struct target_resource_config {
u32 sched_params;
u32 twt_ap_pdev_count;
u32 twt_ap_sta_count;
u8 is_reg_cc_ext_event_supported;
};
enum wmi_debug_log_param {

View File

@ -946,7 +946,7 @@ int ath12k_ce_alloc_pipes(struct ath12k_base *ab)
ret = ath12k_ce_alloc_pipe(ab, i);
if (ret) {
/* Free any parial successful allocation */
/* Free any partial successful allocation */
ath12k_ce_free_pipes(ab);
return ret;
}

View File

@ -691,7 +691,7 @@ struct ath12k_base {
/* Below regd's are protected by ab->data_lock */
/* This is the regd set for every radio
* by the firmware during initializatin
* by the firmware during initialization
*/
struct ieee80211_regdomain *default_regd[MAX_RADIOS];
/* This regd is set during dynamic country setting

View File

@ -1429,7 +1429,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab)
}
if (dp->spt_info[i].paddr & ATH12K_SPT_4K_ALIGN_CHECK) {
ath12k_warn(ab, "SPT allocated memoty is not 4K aligned");
ath12k_warn(ab, "SPT allocated memory is not 4K aligned");
ret = -EINVAL;
goto free;
}
@ -1461,15 +1461,12 @@ static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab)
dp->reoq_lut.vaddr = dma_alloc_coherent(ab->dev,
DP_REOQ_LUT_SIZE,
&dp->reoq_lut.paddr,
GFP_KERNEL);
GFP_KERNEL | __GFP_ZERO);
if (!dp->reoq_lut.vaddr) {
ath12k_warn(ab, "failed to allocate memory for reoq table");
return -ENOMEM;
}
memset(dp->reoq_lut.vaddr, 0, DP_REOQ_LUT_SIZE);
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE0(ab),
dp->reoq_lut.paddr);
return 0;

View File

@ -371,7 +371,7 @@ struct ath12k_dp {
#define HTT_TX_WBM_COMP_STATUS_OFFSET 8
/* HTT tx completion is overlayed in wbm_release_ring */
/* HTT tx completion is overlaid in wbm_release_ring */
#define HTT_TX_WBM_COMP_INFO0_STATUS GENMASK(16, 13)
#define HTT_TX_WBM_COMP_INFO1_REINJECT_REASON GENMASK(3, 0)
#define HTT_TX_WBM_COMP_INFO1_EXCEPTION_FRAME BIT(4)
@ -545,7 +545,7 @@ enum htt_srng_ring_id {
* 3'b010: 4 usec
* 3'b011: 8 usec (default)
* 3'b100: 16 usec
* Others: Reserverd
* Others: Reserved
* b'19 - response_required:
* Host needs HTT_T2H_MSG_TYPE_SRING_SETUP_DONE as response
* b'20:31 - reserved: reserved for future use
@ -1126,7 +1126,7 @@ struct htt_tx_ring_selection_cfg_cmd {
__le32 tlv_filter_mask_in1;
__le32 tlv_filter_mask_in2;
__le32 tlv_filter_mask_in3;
__le32 reserverd[3];
__le32 reserved[3];
} __packed;
#define HTT_TX_RING_TLV_FILTER_MGMT_DMA_LEN GENMASK(3, 0)

View File

@ -529,12 +529,12 @@ static void ath12k_dp_mon_parse_he_sig_su(u8 *tlv_data,
case 3:
if (he_dcm && he_stbc) {
he_gi = HE_GI_0_8;
he_ltf = HE_LTF_4_X;
he_ltf = HE_LTF_4_X;
} else {
he_gi = HE_GI_3_2;
he_ltf = HE_LTF_4_X;
}
break;
}
break;
}
ppdu_info->gi = he_gi;
value = he_gi << HE_GI_SHIFT;
@ -813,7 +813,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
spin_unlock_bh(&buf_ring->idr_lock);
if (unlikely(!msdu)) {
ath12k_warn(ab, "montior destination with invalid buf_id %d\n",
ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
buf_id);
return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
}
@ -1124,7 +1124,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
/* PN for multicast packets are not validate in HW,
* so skip 802.3 rx path
* Also, fast_rx expectes the STA to be authorized, hence
* Also, fast_rx expects the STA to be authorized, hence
* eapol packets are sent in slow path.
*/
if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol_tkip &&
@ -1268,7 +1268,8 @@ int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
struct sk_buff *skb;
struct hal_srng *srng;
dma_addr_t paddr;
u32 cookie, buf_id;
u32 cookie;
int buf_id;
srng = &ab->hal.srng_list[buf_ring->refill_buf_ring.ring_id];
spin_lock_bh(&srng->lock);
@ -1917,7 +1918,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
spin_unlock_bh(&buf_ring->idr_lock);
if (unlikely(!msdu)) {
ath12k_warn(ab, "montior destination with invalid buf_id %d\n",
ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
buf_id);
return DP_MON_TX_STATUS_PPDU_NOT_DONE;
}
@ -2110,7 +2111,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget,
spin_unlock_bh(&buf_ring->idr_lock);
if (unlikely(!skb)) {
ath12k_warn(ab, "montior destination with invalid buf_id %d\n",
ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
buf_id);
goto move_next;
}
@ -2511,7 +2512,7 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id,
spin_unlock_bh(&buf_ring->idr_lock);
if (unlikely(!skb)) {
ath12k_warn(ab, "montior destination with invalid buf_id %d\n",
ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
buf_id);
goto move_next;
}

View File

@ -2443,7 +2443,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
/* PN for multicast packets are not validate in HW,
* so skip 802.3 rx path
* Also, fast_rx expectes the STA to be authorized, hence
* Also, fast_rx expects the STA to be authorized, hence
* eapol packets are sent in slow path.
*/
if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol &&
@ -2611,7 +2611,7 @@ try_again:
if (!desc_info) {
desc_info = ath12k_dp_get_rx_desc(ab, cookie);
if (!desc_info) {
ath12k_warn(ab, "Invalid cookie in manual desc retrival");
ath12k_warn(ab, "Invalid cookie in manual desc retrieval");
continue;
}
}
@ -3297,7 +3297,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc,
if (!desc_info) {
desc_info = ath12k_dp_get_rx_desc(ab, cookie);
if (!desc_info) {
ath12k_warn(ab, "Invalid cookie in manual desc retrival");
ath12k_warn(ab, "Invalid cookie in manual desc retrieval");
return -EINVAL;
}
}
@ -3494,11 +3494,14 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu,
msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc);
peer_id = ath12k_dp_rx_h_peer_id(ab, desc);
spin_lock(&ab->base_lock);
if (!ath12k_peer_find_by_id(ab, peer_id)) {
spin_unlock(&ab->base_lock);
ath12k_dbg(ab, ATH12K_DBG_DATA, "invalid peer id received in wbm err pkt%d\n",
peer_id);
return -EINVAL;
}
spin_unlock(&ab->base_lock);
if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) {
/* First buffer will be freed by the caller, so deduct it's length */
@ -3718,7 +3721,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
if (!desc_info) {
desc_info = ath12k_dp_get_rx_desc(ab, err_info.cookie);
if (!desc_info) {
ath12k_warn(ab, "Invalid cookie in manual desc retrival");
ath12k_warn(ab, "Invalid cookie in manual desc retrieval");
continue;
}
}

View File

@ -270,7 +270,7 @@ tcl_ring_sel:
skb_ext_desc->len, DMA_TO_DEVICE);
ret = dma_mapping_error(ab->dev, ti.paddr);
if (ret) {
kfree(skb_ext_desc);
kfree_skb(skb_ext_desc);
goto fail_unmap_dma;
}

View File

@ -609,7 +609,7 @@ static int ath12k_hal_srng_create_config_qcn9274(struct ath12k_base *ab)
HAL_WBM0_RELEASE_RING_BASE_LSB(ab);
s->reg_size[1] = HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP;
/* Some LMAC rings are not accesed from the host:
/* Some LMAC rings are not accessed from the host:
* RXDMA_BUG, RXDMA_DST, RXDMA_MONITOR_BUF, RXDMA_MONITOR_STATUS,
* RXDMA_MONITOR_DST, RXDMA_MONITOR_DESC, RXDMA_DIR_BUF_SRC,
* RXDMA_RX_MONITOR_BUF, TX_MONITOR_BUF, TX_MONITOR_DST, SW2RXDMA

View File

@ -270,7 +270,7 @@ struct ath12k_base;
#define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW4_EN BIT(5)
#define HAL_WBM_SW_COOKIE_CONV_CFG_GLOBAL_EN BIT(8)
/* TCL ring feild mask and offset */
/* TCL ring field mask and offset */
#define HAL_TCL1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8)
#define HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_TCL1_RING_ID_ENTRY_SIZE GENMASK(7, 0)
@ -296,7 +296,7 @@ struct ath12k_base;
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP6 GENMASK(20, 18)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP7 GENMASK(23, 21)
/* REO ring feild mask and offset */
/* REO ring field mask and offset */
#define HAL_REO1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8)
#define HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_REO1_RING_ID_RING_ID GENMASK(15, 8)
@ -738,7 +738,7 @@ struct hal_srng {
} u;
};
/* Interrupt mitigation - Batch threshold in terms of numer of frames */
/* Interrupt mitigation - Batch threshold in terms of number of frames */
#define HAL_SRNG_INT_BATCH_THRESHOLD_TX 256
#define HAL_SRNG_INT_BATCH_THRESHOLD_RX 128
#define HAL_SRNG_INT_BATCH_THRESHOLD_OTHER 1
@ -813,7 +813,7 @@ enum hal_rx_buf_return_buf_manager {
#define HAL_REO_CMD_FLG_UNBLK_RESOURCE BIT(7)
#define HAL_REO_CMD_FLG_UNBLK_CACHE BIT(8)
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* feilds */
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* fields */
#define HAL_REO_CMD_UPD0_RX_QUEUE_NUM BIT(8)
#define HAL_REO_CMD_UPD0_VLD BIT(9)
#define HAL_REO_CMD_UPD0_ALDC BIT(10)
@ -838,7 +838,7 @@ enum hal_rx_buf_return_buf_manager {
#define HAL_REO_CMD_UPD0_PN_VALID BIT(29)
#define HAL_REO_CMD_UPD0_PN BIT(30)
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO1_* feilds */
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO1_* fields */
#define HAL_REO_CMD_UPD1_VLD BIT(16)
#define HAL_REO_CMD_UPD1_ALDC GENMASK(18, 17)
#define HAL_REO_CMD_UPD1_DIS_DUP_DETECTION BIT(19)
@ -854,7 +854,7 @@ enum hal_rx_buf_return_buf_manager {
#define HAL_REO_CMD_UPD1_PN_HANDLE_ENABLE BIT(30)
#define HAL_REO_CMD_UPD1_IGNORE_AMPDU_FLG BIT(31)
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO2_* feilds */
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO2_* fields */
#define HAL_REO_CMD_UPD2_SVLD BIT(10)
#define HAL_REO_CMD_UPD2_SSN GENMASK(22, 11)
#define HAL_REO_CMD_UPD2_SEQ_2K_ERR BIT(23)

View File

@ -706,7 +706,7 @@ struct rx_msdu_desc {
*
* msdu_continuation
* When set, this MSDU buffer was not able to hold the entire MSDU.
* The next buffer will therefor contain additional information
* The next buffer will therefore contain additional information
* related to this MSDU.
*
* msdu_length
@ -1294,7 +1294,7 @@ struct hal_tcl_data_cmd {
* link descriptor.
*
* tcl_cmd_type
* used to select the type of TCL Command decriptor
* used to select the type of TCL Command descriptor
*
* desc_type
* Indicates the type of address provided in the buf_addr_info.
@ -1408,7 +1408,7 @@ struct hal_tcl_data_cmd {
* index_loop_override
* When set, address search and packet routing is forced to use
* 'search_index' instead of following the register configuration
* seleced by Bank_id.
* selected by Bank_id.
*
* ring_id
* The buffer pointer ring ID.
@ -1990,7 +1990,7 @@ struct hal_wbm_release_ring {
* Producer: SW/TQM/RXDMA/REO/SWITCH
* Consumer: WBM/SW/FW
*
* HTT tx status is overlayed on wbm_release ring on 4-byte words 2, 3, 4 and 5
* HTT tx status is overlaid on wbm_release ring on 4-byte words 2, 3, 4 and 5
* for software based completions.
*
* buf_addr_info
@ -2552,7 +2552,7 @@ struct hal_reo_status_hdr {
* commands.
*
* execution_time (in us)
* The amount of time REO took to excecute the command. Note that
* The amount of time REO took to execute the command. Note that
* this time does not include the duration of the command waiting
* in the command ring, before the execution started.
*

View File

@ -119,6 +119,30 @@ static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"tcl2host-status-ring",
};
static int ath12k_pci_bus_wake_up(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
}
static void ath12k_pci_bus_release(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
}
static const struct ath12k_pci_ops ath12k_pci_ops_qcn9274 = {
.wakeup = NULL,
.release = NULL,
};
static const struct ath12k_pci_ops ath12k_pci_ops_wcn7850 = {
.wakeup = ath12k_pci_bus_wake_up,
.release = ath12k_pci_bus_release,
};
static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset)
{
struct ath12k_base *ab = ab_pci->ab;
@ -989,13 +1013,14 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
u32 val, window_start;
int ret = 0;
/* for offset beyond BAR + 4K - 32, may
* need to wakeup MHI to access.
*/
if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
offset >= ACCESS_ALWAYS_OFF)
mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->wakeup)
ret = ab_pci->pci_ops->wakeup(ab);
if (offset < WINDOW_START) {
val = ioread32(ab->mem + offset);
@ -1023,9 +1048,9 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset)
}
if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
offset >= ACCESS_ALWAYS_OFF)
mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->release &&
!ret)
ab_pci->pci_ops->release(ab);
return val;
}
@ -1033,13 +1058,14 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
u32 window_start;
int ret = 0;
/* for offset beyond BAR + 4K - 32, may
* need to wakeup MHI to access.
*/
if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
offset >= ACCESS_ALWAYS_OFF)
mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->wakeup)
ret = ab_pci->pci_ops->wakeup(ab);
if (offset < WINDOW_START) {
iowrite32(value, ab->mem + offset);
@ -1067,8 +1093,9 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value)
}
if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
offset >= ACCESS_ALWAYS_OFF)
mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->release &&
!ret)
ab_pci->pci_ops->release(ab);
}
int ath12k_pci_power_up(struct ath12k_base *ab)
@ -1182,6 +1209,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
case QCN9274_DEVICE_ID:
ab_pci->msi_config = &ath12k_msi_config[0];
ab->static_window_map = true;
ab_pci->pci_ops = &ath12k_pci_ops_qcn9274;
ath12k_pci_read_hw_version(ab, &soc_hw_version_major,
&soc_hw_version_minor);
switch (soc_hw_version_major) {
@ -1202,6 +1230,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
ab_pci->msi_config = &ath12k_msi_config[0];
ab->static_window_map = false;
ab->hw_rev = ATH12K_HW_WCN7850_HW20;
ab_pci->pci_ops = &ath12k_pci_ops_wcn7850;
break;
default:

View File

@ -86,6 +86,11 @@ enum ath12k_pci_flags {
ATH12K_PCI_ASPM_RESTORE,
};
struct ath12k_pci_ops {
int (*wakeup)(struct ath12k_base *ab);
void (*release)(struct ath12k_base *ab);
};
struct ath12k_pci {
struct pci_dev *pdev;
struct ath12k_base *ab;
@ -103,6 +108,7 @@ struct ath12k_pci {
/* enum ath12k_pci_flags */
unsigned long flags;
u16 link_ctl;
const struct ath12k_pci_ops *pci_ops;
};
static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab)

View File

@ -1072,7 +1072,7 @@ struct rx_msdu_end_qcn9274 {
*
* l4_offset
* Depending upon mode bit, this field either indicates the
* L4 offset nin bytes from the start of RX_HEADER (only valid
* L4 offset in bytes from the start of RX_HEADER (only valid
* if either ipv4_proto or ipv6_proto is set to 1) or indicates
* the offset in bytes to the start of TCP or UDP header from
* the start of the IP header after decapsulation (Only valid if

View File

@ -494,7 +494,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
/* tx/rx chainmask reported from fw depends on the actual hw chains used,
* For example, for 4x4 capable macphys, first 4 chains can be used for first
* mac and the remaing 4 chains can be used for the second mac or vice-versa.
* mac and the remaining 4 chains can be used for the second mac or vice-versa.
* In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0
* will be advertised for second mac or vice-versa. Compute the shift value
* for tx/rx chainmask which will be used to advertise supported ht/vht rates to
@ -1743,7 +1743,7 @@ int ath12k_wmi_vdev_install_key(struct ath12k *ar,
int ret, len, key_len_aligned;
/* WMI_TAG_ARRAY_BYTE needs to be aligned with 4, the actual key
* length is specifed in cmd->key_len.
* length is specified in cmd->key_len.
*/
key_len_aligned = roundup(arg->key_len, 4);
@ -5995,7 +5995,7 @@ static void ath12k_service_available_event(struct ath12k_base *ab, struct sk_buf
}
/* TODO: Use wmi_service_segment_offset information to get the service
* especially when more services are advertised in multiple sevice
* especially when more services are advertised in multiple service
* available events.
*/
for (i = 0, j = WMI_MAX_SERVICE;

View File

@ -4002,7 +4002,7 @@ struct ath12k_wmi_pdev_radar_event {
} __packed;
struct wmi_pdev_temperature_event {
/* temperature value in Celcius degree */
/* temperature value in Celsius degree */
a_sle32 temp;
__le32 pdev_id;
} __packed;
@ -4192,7 +4192,7 @@ enum wmi_sta_ps_param_tx_wake_threshold {
*/
enum wmi_sta_ps_param_pspoll_count {
WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0,
/* Values greater than 0 indicate the maximum numer of PS-Poll frames
/* Values greater than 0 indicate the maximum number of PS-Poll frames
* FW will send before waking up.
*/
};

View File

@ -113,15 +113,13 @@ static int ath_ahb_probe(struct platform_device *pdev)
goto err_out;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no IRQ resource found\n");
ret = -ENXIO;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq);
ret = irq;
goto err_iounmap;
}
irq = res->start;
hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
if (hw == NULL) {
dev_err(&pdev->dev, "no memory for ieee80211_hw\n");

View File

@ -529,7 +529,7 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
ee->ee_n_piers[mode]++;
freq2 = (val >> 8) & 0xff;
if (!freq2)
if (!freq2 || i >= max)
break;
pc[i++].freq = ath5k_eeprom_bin2freq(ee,

View File

@ -246,7 +246,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
return -EACCES;
}
size = sizeof(cid) + sizeof(addr) + sizeof(param);
size = sizeof(cid) + sizeof(addr) + sizeof(*param);
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;

View File

@ -960,8 +960,8 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
* Thus the possibility of ar->htc_target being NULL
* via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
*/
if (WARN_ON_ONCE(!target)) {
ath6kl_err("Target not yet initialized\n");
if (!target) {
ath6kl_dbg(ATH6KL_DBG_HTC, "Target not yet initialized\n");
status = -EINVAL;
goto free_skb;
}

View File

@ -534,6 +534,24 @@ static struct ath9k_htc_hif hif_usb = {
.send = hif_usb_send,
};
/* Need to free remain_skb allocated in ath9k_hif_usb_rx_stream
* in case ath9k_hif_usb_rx_stream wasn't called next time to
* process the buffer and subsequently free it.
*/
static void ath9k_hif_usb_free_rx_remain_skb(struct hif_device_usb *hif_dev)
{
unsigned long flags;
spin_lock_irqsave(&hif_dev->rx_lock, flags);
if (hif_dev->remain_skb) {
dev_kfree_skb_any(hif_dev->remain_skb);
hif_dev->remain_skb = NULL;
hif_dev->rx_remain_len = 0;
RX_STAT_INC(hif_dev, skb_dropped);
}
spin_unlock_irqrestore(&hif_dev->rx_lock, flags);
}
static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
struct sk_buff *skb)
{
@ -868,6 +886,7 @@ err:
static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
{
usb_kill_anchored_urbs(&hif_dev->rx_submitted);
ath9k_hif_usb_free_rx_remain_skb(hif_dev);
}
static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)

View File

@ -503,7 +503,7 @@ int ath_key_config(struct ath_common *common,
hk.kv_len = key->keylen;
if (key->keylen)
memcpy(hk.kv_val, key->key, key->keylen);
memcpy(&hk.kv_values, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
switch (vif->type) {

View File

@ -475,8 +475,8 @@ out:
#define PREPARE_HAL_BUF(send_buf, msg_body) \
do { \
memset(send_buf, 0, msg_body.header.len); \
memcpy(send_buf, &msg_body, sizeof(msg_body)); \
memcpy_and_pad(send_buf, msg_body.header.len, \
&msg_body, sizeof(msg_body), 0); \
} while (0) \
#define PREPARE_HAL_PTT_MSG_BUF(send_buf, p_msg_body) \

View File

@ -6280,6 +6280,11 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
(struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
req_len = le32_to_cpu(assoc_info->req_len);
resp_len = le32_to_cpu(assoc_info->resp_len);
if (req_len > WL_EXTRA_BUF_MAX || resp_len > WL_EXTRA_BUF_MAX) {
bphy_err(drvr, "invalid lengths in assoc info: req %u resp %u\n",
req_len, resp_len);
return -EINVAL;
}
if (req_len) {
err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
cfg->extra_buf,
@ -7881,6 +7886,7 @@ static bool brmcf_use_iso3166_ccode_fallback(struct brcmf_pub *drvr)
switch (drvr->bus_if->chip) {
case BRCM_CC_43430_CHIP_ID:
case BRCM_CC_4345_CHIP_ID:
case BRCM_CC_4356_CHIP_ID:
case BRCM_CC_43602_CHIP_ID:
return true;
default:

View File

@ -1234,9 +1234,9 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
u32 base = ipw_read32(priv, IPW_ERROR_LOG);
u32 elem_len = ipw_read_reg32(priv, base);
error = kmalloc(sizeof(*error) +
sizeof(*error->elem) * elem_len +
sizeof(*error->log) * log_len, GFP_ATOMIC);
error = kmalloc(size_add(struct_size(error, elem, elem_len),
array_size(sizeof(*error->log), log_len)),
GFP_ATOMIC);
if (!error) {
IPW_ERROR("Memory allocation for firmware error log "
"failed.\n");
@ -1247,7 +1247,6 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
error->config = priv->config;
error->elem_len = elem_len;
error->log_len = log_len;
error->elem = (struct ipw_error_elem *)error->payload;
error->log = (struct ipw_event *)(error->elem + elem_len);
ipw_capture_event_log(priv, log_len, error->log);

View File

@ -1106,9 +1106,8 @@ struct ipw_fw_error { /* XXX */
u32 config;
u32 elem_len;
u32 log_len;
struct ipw_error_elem *elem;
struct ipw_event *log;
u8 payload[];
struct ipw_error_elem elem[];
} __packed;
#ifdef CONFIG_IPW2200_PROMISCUOUS

View File

@ -10,7 +10,7 @@
#include "fw/api/txq.h"
/* Highest firmware API version supported */
#define IWL_22000_UCODE_API_MAX 74
#define IWL_22000_UCODE_API_MAX 75
/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39
@ -57,6 +57,8 @@
#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-"
#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-"
#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0-"
#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0-"
#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0-"
#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-"
#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-"
#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-"
@ -64,8 +66,11 @@
#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-"
#define IWL_BNJ_B_FM4_B_FW_PRE "iwlwifi-BzBnj-b0-fm4-b0-"
#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-"
#define IWL_BNJ_B_GF_A_FW_PRE "iwlwifi-BzBnj-b0-gf-a0-"
#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-"
#define IWL_BNJ_B_GF4_A_FW_PRE "iwlwifi-BzBnj-b0-gf4-a0-"
#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-"
#define IWL_BNJ_B_HR_B_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-"
#define IWL_BNJ_B_FM_B_FW_PRE "iwlwifi-BzBnj-b0-fm-b0-"
@ -125,6 +130,10 @@
IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \
IWL_BZ_A_FM4_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BZ_A_FM_B_MODULE_FIRMWARE(api) \
IWL_BZ_A_FM_B_FW_PRE __stringify(api) ".ucode"
#define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \
IWL_BZ_A_FM4_B_FW_PRE __stringify(api) ".ucode"
#define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \
IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode"
#define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \
@ -137,10 +146,16 @@
IWL_BNJ_B_FM4_B_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_A_GF_A_MODULE_FIRMWARE(api) \
IWL_BNJ_A_GF_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_B_GF_A_MODULE_FIRMWARE(api) \
IWL_BNJ_B_GF_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(api) \
IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(api) \
IWL_BNJ_B_GF4_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \
IWL_BNJ_A_HR_B_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_B_HR_B_MODULE_FIRMWARE(api) \
IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode"
#define IWL_BNJ_B_FM_B_MODULE_FIRMWARE(api) \
IWL_BNJ_B_FM_B_FW_PRE __stringify(api) ".ucode"
@ -281,7 +296,7 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = {
.trans.gen2 = true, \
.nvm_type = IWL_NVM_EXT, \
.dbgc_supported = true, \
.min_umac_error_event_table = 0x400000, \
.min_umac_error_event_table = 0xD0000, \
.d3_debug_data_base_addr = 0x401000, \
.d3_debug_data_length = 60 * 1024, \
.mon_smem_regs = { \
@ -961,6 +976,22 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = {
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bz_a0_fm_b0 = {
.fw_name_pre = IWL_BZ_A_FM_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0 = {
.fw_name_pre = IWL_BZ_A_FM4_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = {
.fw_name_pre = IWL_GL_A_FM_A_FW_PRE,
.uhb_supported = true,
@ -1017,6 +1048,14 @@ const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = {
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_b0_gf_a0 = {
.fw_name_pre = IWL_BNJ_B_GF_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = {
.fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE,
.uhb_supported = true,
@ -1025,6 +1064,14 @@ const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = {
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_b0_gf4_a0 = {
.fw_name_pre = IWL_BNJ_B_GF4_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = {
.fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE,
.uhb_supported = true,
@ -1033,6 +1080,14 @@ const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = {
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0 = {
.fw_name_pre = IWL_BNJ_B_HR_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = {
.fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE,
.uhb_supported = true,
@ -1067,13 +1122,18 @@ MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_B_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));

View File

@ -265,6 +265,24 @@ enum iwl_legacy_cmds {
*/
HOT_SPOT_CMD = 0x53,
/**
* @WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION: Time Sync
* measurement notification for TM/FTM. Sent on receipt of
* respective WNM action frame for TM protocol or public action
* frame for FTM protocol from peer device along with additional
* meta data specified in &struct iwl_time_msmt_notify
*/
WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION = 0x67,
/**
* @WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION: Time Sync
* measurement confirmation notification for TM/FTM. Sent on
* receipt of Ack from peer for previously Tx'ed TM/FTM
* action frame along with additional meta data specified in
* &struct iwl_time_msmt_cfm_notify
*/
WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION = 0x68,
/**
* @SCAN_OFFLOAD_COMPLETE:
* notification, &struct iwl_periodic_scan_complete

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018-2020 Intel Corporation
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -26,6 +26,17 @@ enum iwl_data_path_subcmd_ids {
*/
TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2,
/**
* @WNM_PLATFORM_PTM_REQUEST_CMD: &struct iwl_time_sync_cfg_cmd
*/
WNM_PLATFORM_PTM_REQUEST_CMD = 0x3,
/**
* @WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD:
* &struct iwl_time_sync_cfg_cmd
*/
WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD = 0x4,
/**
* @STA_HE_CTXT_CMD: &struct iwl_he_sta_context_cmd
*/
@ -146,6 +157,177 @@ enum iwl_channel_estimation_flags {
IWL_CHANNEL_ESTIMATION_COUNTER = BIT(2),
};
enum iwl_time_sync_protocol_type {
IWL_TIME_SYNC_PROTOCOL_TM = BIT(0),
IWL_TIME_SYNC_PROTOCOL_FTM = BIT(1),
}; /* WNM_TIMING_ENABLED_PROTOCOL_API_E_VER_1 */
/**
* struct iwl_time_sync_cfg_cmd - TM/FTM time sync measurement configuration
*
* @protocols: The type of frames to raise notifications for. A bitmap
* of @iwl_time_sync_protocol_type
* @peer_addr: peer address with which TM/FTM measurements are required
* @reserved: for alignment
*/
struct iwl_time_sync_cfg_cmd {
__le32 protocols;
u8 peer_addr[ETH_ALEN];
u8 reserved[2];
} __packed; /* WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD_API_S_VER_1 */
/**
* enum iwl_synced_time_operation - PTM request options
*
* @IWL_SYNCED_TIME_OPERATION_READ_ARTB: read only the ARTB time
* @IWL_SYNCED_TIME_OPERATION_READ_GP2: read only the GP2 time
* @IWL_SYNCED_TIME_OPERATION_READ_BOTH: latch the ARTB and GP2 clocks and
* provide timestamps from both clocks for the same time point
*/
enum iwl_synced_time_operation {
IWL_SYNCED_TIME_OPERATION_READ_ARTB = 1,
IWL_SYNCED_TIME_OPERATION_READ_GP2,
IWL_SYNCED_TIME_OPERATION_READ_BOTH,
};
/**
* struct iwl_synced_time_cmd - request synced GP2/ARTB timestamps
*
* @operation: one of &enum iwl_synced_time_operation
*/
struct iwl_synced_time_cmd {
__le32 operation;
} __packed; /* WNM_80211V_TIMING_CMD_API_S_VER_1 */
/**
* struct iwl_synced_time_rsp - response to iwl_synced_time_cmd
*
* @operation: one of &enum iwl_synced_time_operation
* @platform_timestamp_hi: high DWORD of the ARTB clock timestamp in nanoseconds
* @platform_timestamp_lo: low DWORD of the ARTB clock timestamp in nanoseconds
* @gp2_timestamp_hi: high DWORD of the GP2 clock timestamp in 10's of
* nanoseconds
* @gp2_timestamp_lo: low DWORD of the GP2 clock timestamp in 10's of
* nanoseconds
*/
struct iwl_synced_time_rsp {
__le32 operation;
__le32 platform_timestamp_hi;
__le32 platform_timestamp_lo;
__le32 gp2_timestamp_hi;
__le32 gp2_timestamp_lo;
} __packed; /* WNM_80211V_TIMING_RSP_API_S_VER_1 */
/* PTP_CTX_MAX_DATA_SIZE_IN_API_D_VER_1 */
#define PTP_CTX_MAX_DATA_SIZE 128
/**
* struct iwl_time_msmt_ptp_ctx - Vendor specific information element
* to allow a space for flexibility for the userspace App
*
* @element_id: element id of vendor specific ie
* @length: length of vendor specific ie
* @reserved: for alignment
* @data: vendor specific data blob
*/
struct iwl_time_msmt_ptp_ctx {
/* Differentiate between FTM and TM specific Vendor IEs */
union {
struct {
u8 element_id;
u8 length;
__le16 reserved;
u8 data[PTP_CTX_MAX_DATA_SIZE];
} ftm; /* FTM specific vendor IE */
struct {
u8 element_id;
u8 length;
u8 data[PTP_CTX_MAX_DATA_SIZE];
} tm; /* TM specific vendor IE */
};
} __packed /* PTP_CTX_VER_1 */;
/**
* struct iwl_time_msmt_notify - Time Sync measurement notification
* for TM/FTM, along with additional meta data.
*
* @peer_addr: peer address
* @reserved: for alignment
* @dialog_token: measurement flow dialog token number
* @followup_dialog_token: Measurement flow previous dialog token number
* @t1_hi: high dword of t1-time of the Tx'ed action frame departure on
* sender side in units of 10 nano seconds
* @t1_lo: low dword of t1-time of the Tx'ed action frame departure on
* sender side in units of 10 nano seconds
* @t1_max_err: maximum t1-time error in units of 10 nano seconds
* @t4_hi: high dword of t4-time of the Rx'ed action frame's Ack arrival on
* sender side in units of 10 nano seconds
* @t4_lo: low dword of t4-time of the Rx'ed action frame's Ack arrival on
* sender side in units of 10 nano seconds
* @t4_max_err: maximum t4-time error in units of 10 nano seconds
* @t2_hi: high dword of t2-time of the Rx'ed action frame arrival on
* receiver side in units of 10 nano seconds
* @t2_lo: low dword of t2-time of the Rx'ed action frame arrival on
* receiver side in units of 10 nano seconds
* @t2_max_err: maximum t2-time error in units of 10 nano seconds
* @t3_hi: high dword of t3-time of the Tx'ed action frame's Ack departure on
* receiver side in units of 10 nano seconds
* @t3_lo: low dword of t3-time of the Tx'ed action frame's Ack departure on
* receiver side in units of 10 nano seconds
* @t3_max_err: maximum t3-time error in units of 10 nano seconds
* @ptp: vendor specific information element
*/
struct iwl_time_msmt_notify {
u8 peer_addr[ETH_ALEN];
u8 reserved[2];
__le32 dialog_token;
__le32 followup_dialog_token;
__le32 t1_hi;
__le32 t1_lo;
__le32 t1_max_err;
__le32 t4_hi;
__le32 t4_lo;
__le32 t4_max_err;
__le32 t2_hi;
__le32 t2_lo;
__le32 t2_max_err;
__le32 t3_hi;
__le32 t3_lo;
__le32 t3_max_err;
struct iwl_time_msmt_ptp_ctx ptp;
} __packed; /* WNM_80211V_TIMING_MEASUREMENT_NTFY_API_S_VER_1 */
/**
* struct iwl_time_msmt_cfm_notify - Time Sync measurement confirmation
* notification for TM/FTM. Sent on receipt of 802.11 Ack from peer for the
* Tx'ed TM/FTM measurement action frame.
*
* @peer_addr: peer address
* @reserved: for alignment
* @dialog_token: measurement flow dialog token number
* @t1_hi: high dword of t1-time of the Tx'ed action frame departure on
* sender side in units of 10 nano seconds
* @t1_lo: low dword of t1-time of the Tx'ed action frame departure on
* sender side in units of 10 nano seconds
* @t1_max_err: maximum t1-time error in units of 10 nano seconds
* @t4_hi: high dword of t4-time of the Rx'ed action frame's Ack arrival on
* sender side in units of 10 nano seconds
* @t4_lo: low dword of t4-time of the Rx'ed action frame's Ack arrival on
* sender side in units of 10 nano seconds
* @t4_max_err: maximum t4-time error in units of 10 nano seconds
*/
struct iwl_time_msmt_cfm_notify {
u8 peer_addr[ETH_ALEN];
u8 reserved[2];
__le32 dialog_token;
__le32 t1_hi;
__le32 t1_lo;
__le32 t1_max_err;
__le32 t4_hi;
__le32 t4_lo;
__le32 t4_max_err;
} __packed; /* WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NTFY_API_S_VER_1 */
/**
* struct iwl_channel_estimation_cfg - channel estimation reporting config
*/

View File

@ -42,6 +42,12 @@ enum iwl_debug_cmds {
* &struct iwl_buf_alloc_cmd
*/
BUFFER_ALLOCATION = 0x8,
/**
* @GET_TAS_STATUS:
* sends command to fw to get TAS status
* the response is &struct iwl_mvm_tas_status_resp
*/
GET_TAS_STATUS = 0xA,
/**
* @FW_DUMP_COMPLETE_CMD:
* sends command to fw once dump collection completed
@ -421,4 +427,94 @@ struct iwl_dbg_dump_complete_cmd {
__le32 tp_data;
} __packed; /* FW_DUMP_COMPLETE_CMD_API_S_VER_1 */
#define TAS_LMAC_BAND_HB 0
#define TAS_LMAC_BAND_LB 1
#define TAS_LMAC_BAND_UHB 2
#define TAS_LMAC_BAND_INVALID 3
/**
* struct iwl_mvm_tas_status_per_mac - tas status per lmac
* @static_status: tas statically enabled or disabled per lmac - TRUE/FALSE
* @static_dis_reason: TAS static disable reason, uses
* &enum iwl_mvm_tas_statically_disabled_reason
* @dynamic_status: Current TAS status. uses
* &enum iwl_mvm_tas_dyna_status
* @near_disconnection: is TAS currently near disconnection per lmac? - TRUE/FALSE
* @max_reg_pwr_limit: Regulatory power limits in dBm
* @sar_limit: SAR limits per lmac in dBm
* @band: Band per lmac
* @reserved: reserved
*/
struct iwl_mvm_tas_status_per_mac {
u8 static_status;
u8 static_dis_reason;
u8 dynamic_status;
u8 near_disconnection;
__le16 max_reg_pwr_limit;
__le16 sar_limit;
u8 band;
u8 reserved[3];
} __packed; /*DEBUG_GET_TAS_STATUS_PER_MAC_S_VER_1*/
/**
* struct iwl_mvm_tas_status_resp - Response to GET_TAS_STATUS
* @tas_fw_version: TAS FW version
* @is_uhb_for_usa_enable: is UHB enabled in USA? - TRUE/FALSE
* @curr_mcc: current mcc
* @block_list: country block list
* @tas_status_mac: TAS status per lmac, uses
* &struct iwl_mvm_tas_status_per_mac
* @in_dual_radio: is TAS in dual radio? - TRUE/FALSE
* @reserved: reserved
*/
struct iwl_mvm_tas_status_resp {
u8 tas_fw_version;
u8 is_uhb_for_usa_enable;
__le16 curr_mcc;
__le16 block_list[16];
struct iwl_mvm_tas_status_per_mac tas_status_mac[2];
u8 in_dual_radio;
u8 reserved[3];
} __packed; /*DEBUG_GET_TAS_STATUS_RSP_API_S_VER_3*/
/**
* enum iwl_mvm_tas_dyna_status - TAS current running status
* @TAS_DYNA_INACTIVE: TAS status is inactive
* @TAS_DYNA_INACTIVE_MVM_MODE: TAS is disabled due because FW is in MVM mode
* or is in softap mode.
* @TAS_DYNA_INACTIVE_TRIGGER_MODE: TAS is disabled because FW is in
* multi user trigger mode
* @TAS_DYNA_INACTIVE_BLOCK_LISTED: TAS is disabled because current mcc
* is blocklisted mcc
* @TAS_DYNA_INACTIVE_UHB_NON_US: TAS is disabled because current band is UHB
* and current mcc is USA
* @TAS_DYNA_ACTIVE: TAS is currently active
* @TAS_DYNA_STATUS_MAX: TAS status max value
*/
enum iwl_mvm_tas_dyna_status {
TAS_DYNA_INACTIVE,
TAS_DYNA_INACTIVE_MVM_MODE,
TAS_DYNA_INACTIVE_TRIGGER_MODE,
TAS_DYNA_INACTIVE_BLOCK_LISTED,
TAS_DYNA_INACTIVE_UHB_NON_US,
TAS_DYNA_ACTIVE,
TAS_DYNA_STATUS_MAX,
}; /*_TAS_DYNA_STATUS_E*/
/**
* enum iwl_mvm_tas_statically_disabled_reason - TAS statically disabled reason
* @TAS_DISABLED_DUE_TO_BIOS: TAS is disabled because TAS is disabled in BIOS
* @TAS_DISABLED_DUE_TO_SAR_6DBM: TAS is disabled because SAR limit is less than 6 Dbm
* @TAS_DISABLED_REASON_INVALID: TAS disable reason is invalid
* @TAS_DISABLED_REASON_MAX: TAS disable reason max value
*/
enum iwl_mvm_tas_statically_disabled_reason {
TAS_DISABLED_DUE_TO_BIOS,
TAS_DISABLED_DUE_TO_SAR_6DBM,
TAS_DISABLED_REASON_INVALID,
TAS_DISABLED_REASON_MAX,
}; /*_TAS_STATICALLY_DISABLED_REASON_E*/
#endif /* __iwl_fw_api_debug_h__ */

View File

@ -1,12 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation
* Copyright (C) 2012-2014, 2018-2019, 2021-2022 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#ifndef __iwl_fw_api_mac_cfg_h__
#define __iwl_fw_api_mac_cfg_h__
#include "mac.h"
/**
* enum iwl_mac_conf_subcmd_ids - mac configuration command IDs
*/
@ -31,7 +33,30 @@ enum iwl_mac_conf_subcmd_ids {
* @CANCEL_CHANNEL_SWITCH_CMD: &struct iwl_cancel_channel_switch_cmd
*/
CANCEL_CHANNEL_SWITCH_CMD = 0x6,
/**
* @MAC_CONFIG_CMD: &struct iwl_mac_config_cmd
*/
MAC_CONFIG_CMD = 0x8,
/**
* @LINK_CONFIG_CMD: &struct iwl_link_config_cmd
*/
LINK_CONFIG_CMD = 0x9,
/**
* @STA_CONFIG_CMD: &struct iwl_mvm_sta_cfg_cmd
*/
STA_CONFIG_CMD = 0xA,
/**
* @AUX_STA_CMD: &struct iwl_mvm_aux_sta_cmd
*/
AUX_STA_CMD = 0xB,
/**
* @STA_REMOVE_CMD: &struct iwl_mvm_remove_sta_cmd
*/
STA_REMOVE_CMD = 0xC,
/**
* @STA_DISABLE_TX_CMD: &struct iwl_mvm_sta_disable_tx_cmd
*/
STA_DISABLE_TX_CMD = 0xD,
/**
* @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif
*/
@ -182,4 +207,401 @@ struct iwl_mac_low_latency_cmd {
__le16 reserved;
} __packed; /* MAC_LOW_LATENCY_API_S_VER_1 */
/**
* struct iwl_mac_client_data - configuration data for client MAC context
*
* @is_assoc: 1 for associated state, 0 otherwise
* @assoc_id: unique ID assigned by the AP during association
* @data_policy: see &enum iwl_mac_data_policy
* @ctwin: client traffic window in TU (period after TBTT when GO is present).
* 0 indicates that there is no CT window.
*/
struct iwl_mac_client_data {
__le32 is_assoc;
__le32 assoc_id;
__le32 data_policy;
__le32 ctwin;
} __packed; /* MAC_CONTEXT_CONFIG_CLIENT_DATA_API_S_VER_1 */
/**
* struct iwl_mac_go_ibss_data - configuration data for GO and IBSS MAC context
*
* @beacon_template: beacon template ID
*/
struct iwl_mac_go_ibss_data {
__le32 beacon_template;
} __packed; /* MAC_CONTEXT_CONFIG_GO_IBSS_DATA_API_S_VER_1 */
/**
* struct iwl_mac_p2p_dev_data - configuration data for P2P device MAC context
*
* @is_disc_extended: if set to true, P2P Device discoverability is enabled on
* other channels as well. This should be to true only in case that the
* device is discoverable and there is an active GO. Note that setting this
* field when not needed, will increase the number of interrupts and have
* effect on the platform power, as this setting opens the Rx filters on
* all macs.
*/
struct iwl_mac_p2p_dev_data {
__le32 is_disc_extended;
} __packed; /* MAC_CONTEXT_CONFIG_P2P_DEV_DATA_API_S_VER_1 */
/**
* enum iwl_mac_config_filter_flags - MAC context configuration filter flags
*
* @MAC_CFG_FILTER_PROMISC: accept all data frames
* @MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT: pass all management and
* control frames to the host
* @MAC_CFG_FILTER_ACCEPT_GRP: accept multicast frames
* @MAC_CFG_FILTER_ACCEPT_BEACON: accept beacon frames
* @MAC_CFG_FILTER_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe response
* @MAC_CFG_FILTER_ACCEPT_PROBE_REQ: accept probe requests
*/
enum iwl_mac_config_filter_flags {
MAC_CFG_FILTER_PROMISC = BIT(0),
MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT = BIT(1),
MAC_CFG_FILTER_ACCEPT_GRP = BIT(2),
MAC_CFG_FILTER_ACCEPT_BEACON = BIT(3),
MAC_CFG_FILTER_ACCEPT_BCAST_PROBE_RESP = BIT(4),
MAC_CFG_FILTER_ACCEPT_PROBE_REQ = BIT(5),
}; /* MAC_FILTER_FLAGS_MASK_E_VER_1 */
/**
* struct iwl_mac_config_cmd - command structure to configure MAC contexts in
* MLD API
* ( MAC_CONTEXT_CONFIG_CMD = 0x8 )
*
* @id_and_color: ID and color of the MAC
* @action: action to perform, one of FW_CTXT_ACTION_*
* @mac_type: one of &enum iwl_mac_types
* @local_mld_addr: mld address
* @reserved_for_local_mld_addr: reserved
* @filter_flags: combination of &enum iwl_mac_config_filter_flags
* @he_support: does this MAC support HE
* @eht_support: does this MAC support EHT. Requires he_support
* @nic_not_ack_enabled: mark that the NIC doesn't support receiving
* ACK-enabled AGG, (i.e. both BACK and non-BACK frames in single AGG).
* If the NIC is not ACK_ENABLED it may use the EOF-bit in first non-0
* len delim to determine if AGG or single.
* @client: client mac data
* @go_ibss: mac data for go or ibss
* @p2p_dev: mac data for p2p device
*/
struct iwl_mac_config_cmd {
/* COMMON_INDEX_HDR_API_S_VER_1 */
__le32 id_and_color;
__le32 action;
/* MAC_CONTEXT_TYPE_API_E */
__le32 mac_type;
u8 local_mld_addr[6];
__le16 reserved_for_local_mld_addr;
__le32 filter_flags;
__le32 he_support;
__le32 eht_support;
__le32 nic_not_ack_enabled;
/* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_1 */
union {
struct iwl_mac_client_data client;
struct iwl_mac_go_ibss_data go_ibss;
struct iwl_mac_p2p_dev_data p2p_dev;
};
} __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_1 */
/**
* enum iwl_link_ctx_modify_flags - indicate to the fw what fields are being
* modified in &iwl_link_ctx_cfg_cmd
*
* @LINK_CONTEXT_MODIFY_ACTIVE: covers iwl_link_ctx_cfg_cmd::active
* @LINK_CONTEXT_MODIFY_RATES_INFO: covers iwl_link_ctx_cfg_cmd::cck_rates,
* iwl_link_ctx_cfg_cmd::ofdm_rates,
* iwl_link_ctx_cfg_cmd::cck_short_preamble,
* iwl_link_ctx_cfg_cmd::short_slot
* @LINK_CONTEXT_MODIFY_PROTECT_FLAGS: covers
* iwl_link_ctx_cfg_cmd::protection_flags
* @LINK_CONTEXT_MODIFY_QOS_PARAMS: covers iwl_link_ctx_cfg_cmd::qos_flags,
* iwl_link_ctx_cfg_cmd::ac,
* @LINK_CONTEXT_MODIFY_BEACON_TIMING: covers iwl_link_ctx_cfg_cmd::bi,
* iwl_link_ctx_cfg_cmd::dtim_interval,
* iwl_link_ctx_cfg_cmd::dtim_time,
* iwl_link_ctx_cfg_cmd::dtim_tsf,
* iwl_link_ctx_cfg_cmd::assoc_beacon_arrive_time.
* This flag can be set only once after assoc.
* @LINK_CONTEXT_MODIFY_HE_PARAMS: covers
* iwl_link_ctx_cfg_cmd::htc_trig_based_pkt_ext
* iwl_link_ctx_cfg_cmd::rand_alloc_ecwmin,
* iwl_link_ctx_cfg_cmd::rand_alloc_ecwmax,
* iwl_link_ctx_cfg_cmd::trig_based_txf,
* iwl_link_ctx_cfg_cmd::bss_color,
* iwl_link_ctx_cfg_cmd::ndp_fdbk_buff_th_exp,
* iwl_link_ctx_cfg_cmd::ref_bssid_addr
* iwl_link_ctx_cfg_cmd::bssid_index,
* iwl_link_ctx_cfg_cmd::frame_time_rts_th.
* This flag can be set any time.
* @LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE: covers
* iwl_link_ctx_cfg_cmd::bss_color_disable
* @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask.
* This flag can be set only if the MAC that this link relates to has
* eht_support set to true.
* @LINK_CONTEXT_MODIFY_ALL: set all above flags
*/
enum iwl_link_ctx_modify_flags {
LINK_CONTEXT_MODIFY_ACTIVE = BIT(0),
LINK_CONTEXT_MODIFY_RATES_INFO = BIT(1),
LINK_CONTEXT_MODIFY_PROTECT_FLAGS = BIT(2),
LINK_CONTEXT_MODIFY_QOS_PARAMS = BIT(3),
LINK_CONTEXT_MODIFY_BEACON_TIMING = BIT(4),
LINK_CONTEXT_MODIFY_HE_PARAMS = BIT(5),
LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6),
LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7),
LINK_CONTEXT_MODIFY_ALL = 0xff,
}; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */
/**
* enum iwl_link_ctx_protection_flags - link protection flags
* @LINK_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames,
* this will require CCK RTS/CTS2self.
* RTS/CTS will protect full burst time.
* @LINK_PROT_FLG_HT_PROT: enable HT protection
* @LINK_PROT_FLG_FAT_PROT: protect 40 MHz transmissions
* @LINK_PROT_FLG_SELF_CTS_EN: allow CTS2self
*/
enum iwl_link_ctx_protection_flags {
LINK_PROT_FLG_TGG_PROTECT = BIT(0),
LINK_PROT_FLG_HT_PROT = BIT(1),
LINK_PROT_FLG_FAT_PROT = BIT(2),
LINK_PROT_FLG_SELF_CTS_EN = BIT(3),
}; /* LINK_PROTECT_FLAGS_E_VER_1 */
/**
* enum iwl_link_ctx_flags - link context flags
*
* @LINK_FLG_BSS_COLOR_DIS: BSS color disable, don't use the BSS
* color for RX filter but use MAC header
* enabled AGG, i.e. both BACK and non-BACK frames in a single AGG
* @LINK_FLG_MU_EDCA_CW: indicates that there is an element of MU EDCA
* parameter set, i.e. the backoff counters for trig-based ACs
* @LINK_FLG_RU_2MHZ_BLOCK: indicates that 26-tone RU OFDMA transmission are
* not allowed (as there are OBSS that might classify such transmissions as
* radar pulses).
* @LINK_FLG_NDP_FEEDBACK_ENABLED: mark support for NDP feedback and change
* of threshold
*/
enum iwl_link_ctx_flags {
LINK_FLG_BSS_COLOR_DIS = BIT(0),
LINK_FLG_MU_EDCA_CW = BIT(1),
LINK_FLG_RU_2MHZ_BLOCK = BIT(2),
LINK_FLG_NDP_FEEDBACK_ENABLED = BIT(3),
}; /* LINK_CONTEXT_FLAG_E_VER_1 */
/**
* struct iwl_link_config_cmd - command structure to configure the LINK context
* in MLD API
* ( LINK_CONFIG_CMD =0x9 )
*
* @action: action to perform, one of FW_CTXT_ACTION_*
* @link_id: the id of the link that this cmd configures
* @mac_id: interface ID. Relevant only if action is FW_CTXT_ACTION_ADD
* @phy_id: PHY index. Can be changed only if the link was inactive
* (and stays inactive). If the link is active (or becomes active),
* this field is ignored.
* @local_link_addr: the links MAC address. Can be changed only if the link was
* inactive (and stays inactive). If the link is active
* (or becomes active), this field is ignored.
* @reserved_for_local_link_addr: reserved
* @modify_mask: from &enum iwl_link_ctx_modify_flags, selects what to change.
* Relevant only if action is FW_CTXT_ACTION_MODIFY
* @active: indicates whether the link is active or not
* @listen_lmac: indicates whether the link should be allocated on the Listen
* Lmac or on the Main Lmac. Cannot be changed on an active Link.
* Relevant only for eSR.
* @cck_rates: basic rates available for CCK
* @ofdm_rates: basic rates available for OFDM
* @cck_short_preamble: 1 for enabling short preamble, 0 otherwise
* @short_slot: 1 for enabling short slots, 0 otherwise
* @protection_flags: combination of &enum iwl_link_ctx_protection_flags
* @qos_flags: from &enum iwl_mac_qos_flags
* @ac: one iwl_mac_qos configuration for each AC
* @htc_trig_based_pkt_ext: default PE in 4us units
* @rand_alloc_ecwmin: random CWmin = 2**ECWmin-1
* @rand_alloc_ecwmax: random CWmax = 2**ECWmax-1
* @ndp_fdbk_buff_th_exp: set exponent for the NDP feedback buffered threshold
* @trig_based_txf: MU EDCA Parameter set for the trigger based traffic queues
* @bi: beacon interval in TU, applicable only when associated
* @dtim_interval: DTIM interval in TU.
* Relevant only for GO, otherwise this is offloaded.
* @puncture_mask: puncture mask for EHT
* @frame_time_rts_th: HE duration RTS threshold, in units of 32us
* @flags: a combination from &enum iwl_link_ctx_flags
* @flags_mask: what of %flags have changed. Also &enum iwl_link_ctx_flags
* Below fields are for multi-bssid:
* @ref_bssid_addr: reference BSSID used by the AP
* @reserved_for_ref_bssid_addr: reserved
* @bssid_index: index of the associated VAP
* @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame
* @reserved: alignment
* @ibss_bssid_addr: bssid for ibss
* @reserved_for_ibss_bssid_addr: reserved
* @reserved1: reserved for future use
*/
struct iwl_link_config_cmd {
__le32 action;
__le32 link_id;
__le32 mac_id;
__le32 phy_id;
u8 local_link_addr[6];
__le16 reserved_for_local_link_addr;
__le32 modify_mask;
__le32 active;
__le32 listen_lmac;
__le32 cck_rates;
__le32 ofdm_rates;
__le32 cck_short_preamble;
__le32 short_slot;
__le32 protection_flags;
/* MAC_QOS_PARAM_API_S_VER_1 */
__le32 qos_flags;
struct iwl_ac_qos ac[AC_NUM + 1];
u8 htc_trig_based_pkt_ext;
u8 rand_alloc_ecwmin;
u8 rand_alloc_ecwmax;
u8 ndp_fdbk_buff_th_exp;
struct iwl_he_backoff_conf trig_based_txf[AC_NUM];
__le32 bi;
__le32 dtim_interval;
__le16 puncture_mask;
__le16 frame_time_rts_th;
__le32 flags;
__le32 flags_mask;
/* The below fields are for multi-bssid */
u8 ref_bssid_addr[6];
__le16 reserved_for_ref_bssid_addr;
u8 bssid_index;
u8 bss_color;
u8 reserved[2];
u8 ibss_bssid_addr[6];
__le16 reserved_for_ibss_bssid_addr;
__le32 reserved1[8];
} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 */
/* Currently FW supports link ids in the range 0-3 and can have
* at most two active links for each vif.
*/
#define IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM 2
#define IWL_MVM_FW_MAX_LINK_ID 3
/**
* enum iwl_fw_sta_type - FW station types
* @STATION_TYPE_PEER: represents a peer - AP in BSS, a TDLS sta, a client in
* P2P.
* @STATION_TYPE_BCAST_MGMT: The station used to send beacons and
* probe responses. Also used for traffic injection in sniffer mode
* @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be
* suspended / resumed at the right timing depending on the clients'
* power save state and the DTIM timing
* @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type
* for the aux sta, so this type is only for driver - internal use.
*/
enum iwl_fw_sta_type {
STATION_TYPE_PEER,
STATION_TYPE_BCAST_MGMT,
STATION_TYPE_MCAST,
STATION_TYPE_AUX,
}; /* STATION_TYPE_E_VER_1 */
/**
* struct iwl_mvm_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
* station table
* ( STA_CONFIG_CMD = 0xA )
*
* @sta_id: index of station in uCode's station table
* @link_id: the id of the link that is used to communicate with this sta
* @peer_mld_address: the peers mld address
* @reserved_for_peer_mld_address: reserved
* @peer_link_address: the address of the link that is used to communicate
* with this sta
* @reserved_for_peer_link_address: reserved
* @station_type: type of this station. See &enum iwl_fw_sta_type
* @assoc_id: for GO only
* @beamform_flags: beam forming controls
* @mfp: indicates whether the STA uses management frame protection or not.
* @mimo: indicates whether the sta uses mimo or not
* @mimo_protection: indicates whether the sta uses mimo protection or not
* @ack_enabled: indicates that the AP supports receiving ACK-
* enabled AGG, i.e. both BACK and non-BACK frames in a single AGG
* @trig_rnd_alloc: indicates that trigger based random allocation
* is enabled according to UORA element existence
* @tx_ampdu_spacing: minimum A-MPDU spacing:
* 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density
* @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K,
* 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K.
* @sp_length: the size of the SP in actual number of frames
* @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver
* enabled ACs.
* @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY
* capa
* @htc_flags: which features are supported in HTC
*/
struct iwl_mvm_sta_cfg_cmd {
__le32 sta_id;
__le32 link_id;
u8 peer_mld_address[ETH_ALEN];
__le16 reserved_for_peer_mld_address;
u8 peer_link_address[ETH_ALEN];
__le16 reserved_for_peer_link_address;
__le32 station_type;
__le32 assoc_id;
__le32 beamform_flags;
__le32 mfp;
__le32 mimo;
__le32 mimo_protection;
__le32 ack_enabled;
__le32 trig_rnd_alloc;
__le32 tx_ampdu_spacing;
__le32 tx_ampdu_max_size;
__le32 sp_length;
__le32 uapsd_acs;
struct iwl_he_pkt_ext_v2 pkt_ext;
__le32 htc_flags;
} __packed; /* STA_CMD_API_S_VER_1 */
/**
* struct iwl_mvm_aux_sta_cmd - command for AUX STA configuration
* ( AUX_STA_CMD = 0xB )
*
* @sta_id: index of aux sta to configure
* @lmac_id: ?
* @mac_addr: mac addr of the auxilary sta
* @reserved_for_mac_addr: reserved
*/
struct iwl_mvm_aux_sta_cmd {
__le32 sta_id;
__le32 lmac_id;
u8 mac_addr[ETH_ALEN];
__le16 reserved_for_mac_addr;
} __packed; /* AUX_STA_CMD_API_S_VER_1 */
/**
* struct iwl_mvm_remove_sta_cmd - a cmd structure to remove a sta added by
* STA_CONFIG_CMD or AUX_STA_CONFIG_CMD
* ( STA_REMOVE_CMD = 0xC )
*
* @sta_id: index of station to remove
*/
struct iwl_mvm_remove_sta_cmd {
__le32 sta_id;
} __packed; /* REMOVE_STA_API_S_VER_1 */
/**
* struct iwl_mvm_sta_disable_tx_cmd - disable / re-enable tx to a sta
* ( STA_DISABLE_TX_CMD = 0xD )
*
* @sta_id: index of the station to disable tx to
* @disable: indicates if to disable or re-enable tx
*/
struct iwl_mvm_sta_disable_tx_cmd {
__le32 sta_id;
__le32 disable;
} __packed; /* STA_DISABLE_TX_API_S_VER_1 */
#endif /* __iwl_fw_api_mac_cfg_h__ */

View File

@ -800,7 +800,7 @@ enum iwl_mac_beacon_flags {
* is &enum iwl_mac_beacon_flags.
* @short_ssid: Short SSID
* @reserved: reserved
* @template_id: currently equal to the mac context id of the coresponding mac.
* @link_id: the firmware id of the link that will use this beacon
* @tim_idx: the offset of the tim IE in the beacon
* @tim_size: the length of the tim IE
* @ecsa_offset: offset to the ECSA IE if present
@ -812,15 +812,17 @@ struct iwl_mac_beacon_cmd {
__le16 flags;
__le32 short_ssid;
__le32 reserved;
__le32 template_id;
__le32 link_id;
__le32 tim_idx;
__le32 tim_size;
__le32 ecsa_offset;
__le32 csa_offset;
struct ieee80211_hdr frame[];
} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_10,
BEACON_TEMPLATE_CMD_API_S_VER_11,
BEACON_TEMPLATE_CMD_API_S_VER_12 */
* BEACON_TEMPLATE_CMD_API_S_VER_11,
* BEACON_TEMPLATE_CMD_API_S_VER_12,
* BEACON_TEMPLATE_CMD_API_S_VER_13
*/
struct iwl_beacon_notif {
struct iwl_mvm_tx_resp beacon_notify_hdr;

View File

@ -2320,6 +2320,34 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt,
return entry->size;
}
static u32 iwl_dump_ini_file_name_info(struct iwl_fw_runtime *fwrt,
struct list_head *list)
{
struct iwl_fw_ini_dump_entry *entry;
struct iwl_dump_file_name_info *tlv;
u32 len = strnlen(fwrt->trans->dbg.dump_file_name_ext,
IWL_FW_INI_MAX_NAME);
if (!fwrt->trans->dbg.dump_file_name_ext_valid)
return 0;
entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + len);
if (!entry)
return 0;
entry->size = sizeof(*tlv) + len;
tlv = (void *)entry->data;
tlv->type = cpu_to_le32(IWL_INI_DUMP_NAME_TYPE);
tlv->len = cpu_to_le32(len);
memcpy(tlv->data, fwrt->trans->dbg.dump_file_name_ext, len);
/* add the dump file name extension tlv to the list */
list_add_tail(&entry->list, list);
return entry->size;
}
static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
[IWL_FW_INI_REGION_INVALID] = {},
[IWL_FW_INI_REGION_INTERNAL_BUFFER] = {
@ -2495,8 +2523,10 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt,
size += iwl_dump_ini_mem(fwrt, list, &reg_data,
&iwl_dump_ini_region_ops[IWL_FW_INI_REGION_DRAM_IMR]);
if (size)
if (size) {
size += iwl_dump_ini_file_name_info(fwrt, list);
size += iwl_dump_ini_info(fwrt, trigger, list);
}
return size;
}

View File

@ -14,6 +14,13 @@
#include "iwl-csr.h"
#include "pnvm.h"
#define FW_ASSERT_LMAC_FATAL 0x70
#define FW_ASSERT_LMAC2_FATAL 0x72
#define FW_ASSERT_UMAC_FATAL 0x71
#define UMAC_RT_NMI_LMAC2_FATAL 0x72
#define RT_NMI_INTERRUPT_OTHER_LMAC_FATAL 0x73
#define FW_ASSERT_NMI_UNKNOWN 0x84
/*
* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
@ -96,6 +103,17 @@ struct iwl_umac_error_event_table {
#define ERROR_START_OFFSET (1 * sizeof(u32))
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
static bool iwl_fwrt_if_errorid_other_cpu(u32 err_id)
{
err_id &= 0xFF;
if ((err_id >= FW_ASSERT_LMAC_FATAL &&
err_id <= RT_NMI_INTERRUPT_OTHER_LMAC_FATAL) ||
err_id == FW_ASSERT_NMI_UNKNOWN)
return true;
return false;
}
static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt)
{
struct iwl_trans *trans = fwrt->trans;
@ -113,6 +131,13 @@ static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt)
if (table.valid)
fwrt->dump.umac_err_id = table.error_id;
if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.umac_err_id) &&
!fwrt->trans->dbg.dump_file_name_ext_valid) {
fwrt->trans->dbg.dump_file_name_ext_valid = true;
snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME,
"0x%x", fwrt->dump.umac_err_id);
}
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
@ -189,6 +214,13 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu
if (table.valid)
fwrt->dump.lmac_err_id[lmac_num] = table.error_id;
if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.lmac_err_id[lmac_num]) &&
!fwrt->trans->dbg.dump_file_name_ext_valid) {
fwrt->trans->dbg.dump_file_name_ext_valid = true;
snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME,
"0x%x", fwrt->dump.lmac_err_id[lmac_num]);
}
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
@ -274,6 +306,16 @@ static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx)
iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
if (table.valid)
fwrt->dump.tcm_err_id[idx] = table.error_id;
if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.tcm_err_id[idx]) &&
!fwrt->trans->dbg.dump_file_name_ext_valid) {
fwrt->trans->dbg.dump_file_name_ext_valid = true;
snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME,
"0x%x", fwrt->dump.tcm_err_id[idx]);
}
IWL_ERR(fwrt, "TCM%d status:\n", idx + 1);
IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2);
@ -337,6 +379,16 @@ static void iwl_fwrt_dump_rcm_error_log(struct iwl_fw_runtime *fwrt, int idx)
iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
if (table.valid)
fwrt->dump.rcm_err_id[idx] = table.error_id;
if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.rcm_err_id[idx]) &&
!fwrt->trans->dbg.dump_file_name_ext_valid) {
fwrt->trans->dbg.dump_file_name_ext_valid = true;
snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME,
"0x%x", fwrt->dump.rcm_err_id[idx]);
}
IWL_ERR(fwrt, "RCM%d status:\n", idx + 1);
IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
IWL_ERR(fwrt, "0x%08X | rcm branchlink2\n", table.blink2);
@ -444,8 +496,10 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
iwl_fwrt_dump_umac_error_log(fwrt);
iwl_fwrt_dump_tcm_error_log(fwrt, 0);
iwl_fwrt_dump_rcm_error_log(fwrt, 0);
iwl_fwrt_dump_tcm_error_log(fwrt, 1);
iwl_fwrt_dump_rcm_error_log(fwrt, 1);
if (fwrt->trans->dbg.tcm_error_event_table[1])
iwl_fwrt_dump_tcm_error_log(fwrt, 1);
if (fwrt->trans->dbg.rcm_error_event_table[1])
iwl_fwrt_dump_rcm_error_log(fwrt, 1);
iwl_fwrt_dump_iml_error_log(fwrt);
iwl_fwrt_dump_fseq_regs(fwrt);

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2014, 2018-2021 Intel Corporation
* Copyright (C) 2014, 2018-2022 Intel Corporation
* Copyright (C) 2014-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -75,6 +75,18 @@ struct iwl_fw_error_dump_data {
__u8 data[];
} __packed;
/**
* struct iwl_dump_file_name_info - data for dump file name addition
* @type: region type with reserved bits
* @len: the length of file name string to be added to dump file
* @data: the string need to be added to dump file
*/
struct iwl_dump_file_name_info {
__le32 type;
__le32 len;
__u8 data[];
} __packed;
/**
* struct iwl_fw_error_dump_file - the layout of the header of the file
* @barker: must be %IWL_FW_ERROR_DUMP_BARKER
@ -231,6 +243,9 @@ struct iwl_fw_error_dump_mem {
/* Use bit 31 as dump info type to avoid colliding with region types */
#define IWL_INI_DUMP_INFO_TYPE BIT(31)
/* Use bit 31 and bit 24 as dump name type to avoid colliding with region types */
#define IWL_INI_DUMP_NAME_TYPE (BIT(31) | BIT(24))
/**
* struct iwl_fw_error_dump_data - data for one type
* @type: &enum iwl_fw_ini_region_type

View File

@ -455,6 +455,9 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100,
IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104,
IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT = (__force iwl_ucode_tlv_capa_t)105,
IWL_UCODE_TLV_CAPA_SYNCED_TIME = (__force iwl_ucode_tlv_capa_t)106,
IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM = (__force iwl_ucode_tlv_capa_t)108,
IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT = (__force iwl_ucode_tlv_capa_t)109,
#ifdef __CHECKER__
/* sparse says it cannot increment the previous enum member */

View File

@ -182,10 +182,10 @@ struct iwl_dump_exclude {
* @enhance_sensitivity_table: device can do enhanced sensitivity.
* @init_evtlog_ptr: event log offset for init ucode.
* @init_evtlog_size: event log size for init ucode.
* @init_errlog_ptr: error log offfset for init ucode.
* @init_errlog_ptr: error log offset for init ucode.
* @inst_evtlog_ptr: event log offset for runtime ucode.
* @inst_evtlog_size: event log size for runtime ucode.
* @inst_errlog_ptr: error log offfset for runtime ucode.
* @inst_errlog_ptr: error log offset for runtime ucode.
* @type: firmware type (&enum iwl_fw_type)
* @human_readable: human readable version
* we get the ALIVE from the uCode

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright(c) 2020-2021 Intel Corporation
* Copyright(c) 2020-2022 Intel Corporation
*/
#include "iwl-drv.h"
@ -318,7 +318,6 @@ parse:
kfree(data);
skip_parse:
data = NULL;
/* now try to get the reduce power table, if not loaded yet */
if (!trans->reduce_power_loaded) {
data = iwl_uefi_get_reduced_power(trans, &len);
@ -329,19 +328,16 @@ skip_parse:
* trying again over and over.
*/
trans->reduce_power_loaded = true;
goto skip_reduce_power;
} else {
ret = iwl_trans_set_reduce_power(trans, data, len);
if (ret)
IWL_DEBUG_FW(trans,
"Failed to set reduce power table %d\n",
ret);
kfree(data);
}
}
ret = iwl_trans_set_reduce_power(trans, data, len);
if (ret)
IWL_DEBUG_FW(trans,
"Failed to set reduce power table %d\n",
ret);
kfree(data);
skip_reduce_power:
iwl_init_notification_wait(notif_wait, &pnvm_wait,
ntf_cmds, ARRAY_SIZE(ntf_cmds),
iwl_pnvm_complete_fn, trans);

View File

@ -24,6 +24,8 @@ struct iwl_fw_runtime_ops {
};
#define MAX_NUM_LMAC 2
#define MAX_NUM_TCM 2
#define MAX_NUM_RCM 2
struct iwl_fwrt_shared_mem_cfg {
int num_lmacs;
int num_txfifo_entries;
@ -129,6 +131,8 @@ struct iwl_fw_runtime {
unsigned long non_collect_ts_start[IWL_FW_INI_TIME_POINT_NUM];
u32 *d3_debug_data;
u32 lmac_err_id[MAX_NUM_LMAC];
u32 tcm_err_id[MAX_NUM_TCM];
u32 rcm_err_id[MAX_NUM_RCM];
u32 umac_err_id;
struct iwl_txf_iter_data txf_iter_data;

View File

@ -650,14 +650,19 @@ extern const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0;
extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0;
extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0;
extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0;
extern const struct iwl_cfg iwl_cfg_bz_a0_fm_b0;
extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0;
extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0;
extern const struct iwl_cfg iwl_cfg_gl_b0_fm_b0;
extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_gf_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_gf4_a0;
extern const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0;
extern const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0;
#endif /* CONFIG_IWLMVM */

View File

@ -12,6 +12,9 @@
#include "iwl-trans.h"
#define CREATE_TRACE_POINTS
#ifdef CONFIG_CC_IS_GCC
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
#endif
#include "iwl-devtrace.h"
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);

View File

@ -81,7 +81,7 @@ static const u16 iwl_nvm_channels[] = {
/* 2.4 GHz */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
/* 5 GHz */
36, 40, 44 , 48, 52, 56, 60, 64,
36, 40, 44, 48, 52, 56, 60, 64,
100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
149, 153, 157, 161, 165
};

View File

@ -775,6 +775,8 @@ struct iwl_imr_data {
* @periodic_trig_list: periodic triggers list
* @domains_bitmap: bitmap of active domains other than &IWL_FW_INI_DOMAIN_ALWAYS_ON
* @ucode_preset: preset based on ucode
* @dump_file_name_ext: dump file name extension
* @dump_file_name_ext_valid: dump file name extension if valid or not
*/
struct iwl_trans_debug {
u8 n_dest_reg;
@ -813,6 +815,8 @@ struct iwl_trans_debug {
bool restart_required;
u32 last_tp_resetfw;
struct iwl_imr_data imr_data;
u8 dump_file_name_ext[IWL_FW_INI_MAX_NAME];
bool dump_file_name_ext_valid;
};
struct iwl_dma_ptr {

View File

@ -7,7 +7,9 @@ iwlmvm-y += power.o coex.o
iwlmvm-y += tt.o offloading.o tdls.o
iwlmvm-y += ftm-responder.o ftm-initiator.o
iwlmvm-y += rfi.o
iwlmvm-y += mld-key.o
iwlmvm-y += mld-key.o mld-mac.o link.o mld-sta.o mld-mac80211.o
iwlmvm-y += ptp.o
iwlmvm-y += time-sync.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
iwlmvm-$(CONFIG_PM) += d3.o

View File

@ -2,6 +2,7 @@
/*
* Copyright (C) 2012-2014, 2020 Intel Corporation
* Copyright (C) 2016 Intel Deutschland GmbH
* Copyright (C) 2022 Intel Corporation
*/
#include <net/mac80211.h>
#include "fw-api.h"
@ -75,7 +76,7 @@ static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
if (vif == data->ignore_vif)
return;
if (mvmvif->phy_ctxt != data->phyctxt)
if (mvmvif->deflink.phy_ctxt != data->phyctxt)
return;
if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
@ -132,7 +133,7 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
if (WARN_ON_ONCE(!mvmvif->deflink.phy_ctxt))
return -EINVAL;
/*
@ -142,7 +143,8 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (iwl_mvm_sf_update(mvm, vif, false))
return -EINVAL;
return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
return iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
true);
}
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
@ -150,10 +152,11 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
if (WARN_ON_ONCE(!mvmvif->deflink.phy_ctxt))
return -EINVAL;
ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
ret = iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
false);
if (!ret)
if (iwl_mvm_sf_update(mvm, vif, true))

View File

@ -194,7 +194,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
if (mvmsta->bt_reduced_txpower == enable)
return 0;
value = mvmsta->sta_id;
value = mvmsta->deflink.sta_id;
if (enable)
value |= BT_REDUCED_TX_POWER_BIT;
@ -257,33 +257,35 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm,
swap(data->primary, data->secondary);
}
/* must be called under rcu_read_lock */
static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_bt_iterator_data *data,
unsigned int link_id)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
struct ieee80211_chanctx_conf *chanctx_conf;
/* default smps_mode is AUTOMATIC - only used for client modes */
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 bt_activity_grading, min_ag_for_static_smps;
struct ieee80211_chanctx_conf *chanctx_conf;
struct iwl_mvm_vif_link_info *link_info;
struct ieee80211_bss_conf *link_conf;
int ave_rssi;
lockdep_assert_held(&mvm->mutex);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
break;
case NL80211_IFTYPE_AP:
if (!mvmvif->ap_ibss_active)
return;
break;
default:
link_info = mvmvif->link[link_id];
if (!link_info)
return;
}
chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
link_conf = rcu_dereference(vif->link_conf[link_id]);
/* This can happen due to races: if we receive the notification
* and have the mutex held, while mac80211 is stuck on our mutex
* in the middle of removing the link.
*/
if (!link_conf)
return;
chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
/* If channel context is invalid or not on 2.4GHz .. */
if ((!chanctx_conf ||
@ -291,9 +293,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (vif->type == NL80211_IFTYPE_STATION) {
/* ... relax constraints and disable rssi events */
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
smps_mode);
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
smps_mode, link_id);
iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id,
false);
/* FIXME: should this be per link? */
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
}
return;
@ -314,17 +317,18 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (!vif->cfg.assoc)
smps_mode = IEEE80211_SMPS_AUTOMATIC;
if (mvmvif->phy_ctxt &&
(mvm->last_bt_notif.rrc_status & BIT(mvmvif->phy_ctxt->id)))
if (link_info->phy_ctxt &&
(mvm->last_bt_notif.rrc_status & BIT(link_info->phy_ctxt->id)))
smps_mode = IEEE80211_SMPS_AUTOMATIC;
IWL_DEBUG_COEX(data->mvm,
"mac %d: bt_activity_grading %d smps_req %d\n",
mvmvif->id, bt_activity_grading, smps_mode);
"mac %d link %d: bt_activity_grading %d smps_req %d\n",
mvmvif->id, link_info->fw_link_id,
bt_activity_grading, smps_mode);
if (vif->type == NL80211_IFTYPE_STATION)
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
smps_mode);
smps_mode, link_id);
/* low latency is always primary */
if (iwl_mvm_vif_low_latency(mvmvif)) {
@ -353,6 +357,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
data->secondary = chanctx_conf;
}
/* FIXME: TCM load per interface? or need something per link? */
if (data->primary == chanctx_conf)
data->primary_load = mvm->tcm.result.load[mvmvif->id];
else if (data->secondary == chanctx_conf)
@ -370,6 +375,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
/* if secondary is not NULL, it might be a GO */
data->secondary = chanctx_conf;
/* FIXME: TCM load per interface? or need something per link? */
if (data->primary == chanctx_conf)
data->primary_load = mvm->tcm.result.load[mvmvif->id];
else if (data->secondary == chanctx_conf)
@ -384,7 +390,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc ||
le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id, false);
/* FIXME: should this be per link? */
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
return;
}
@ -396,10 +403,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (!ave_rssi)
ave_rssi = -100;
if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
if (iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id,
true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
if (iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id,
false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
}
@ -407,6 +416,32 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
}
/* must be called under rcu_read_lock */
static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
unsigned int link_id;
lockdep_assert_held(&mvm->mutex);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
break;
case NL80211_IFTYPE_AP:
if (!mvmvif->ap_ibss_active)
return;
break;
default:
return;
}
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id);
}
static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
{
struct iwl_bt_iterator_data data = {
@ -521,7 +556,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* Rssi update while not associated - can happen since the statistics
* are handled asynchronously
*/
if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)
if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA)
return;
/* No BT - reports should be disabled */
@ -537,10 +572,13 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
*/
if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
ret = iwl_mvm_bt_coex_reduced_txp(mvm,
mvmvif->deflink.ap_sta_id,
false);
else
ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
ret = iwl_mvm_bt_coex_reduced_txp(mvm,
mvmvif->deflink.ap_sta_id,
true);
if (ret)
IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
@ -554,7 +592,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->deflink.phy_ctxt;
enum iwl_bt_coex_lut_type lut_type;
if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))
@ -578,7 +616,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->deflink.phy_ctxt;
enum iwl_bt_coex_lut_type lut_type;
if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id))

View File

@ -470,7 +470,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++)
data.rsc->mcast_key_id_map[i] =
IWL_MCAST_KEY_MAP_INVALID;
data.rsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id);
data.rsc->sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id);
ieee80211_iter_keys(mvm->hw, vif,
iwl_mvm_wowlan_get_rsc_v5_data,
@ -493,7 +493,8 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
if (ver == 4) {
size = sizeof(*data.rsc_tsc);
data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id);
data.rsc_tsc->sta_id =
cpu_to_le32(mvmvif->deflink.ap_sta_id);
} else {
/* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */
size = sizeof(data.rsc_tsc->params);
@ -691,7 +692,7 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
pattern_cmd->n_patterns = wowlan->n_patterns;
if (ver >= 3)
pattern_cmd->sta_id = mvmvif->ap_sta_id;
pattern_cmd->sta_id = mvmvif->deflink.ap_sta_id;
for (i = 0; i < wowlan->n_patterns; i++) {
int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
@ -732,7 +733,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EINVAL;
/* add back the PHY */
if (WARN_ON(!mvmvif->phy_ctxt))
if (WARN_ON(!mvmvif->deflink.phy_ctxt))
return -EINVAL;
rcu_read_lock();
@ -746,7 +747,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
chains_dynamic = ctx->rx_chains_dynamic;
rcu_read_unlock();
ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, &chandef,
ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, &chandef,
chains_static, chains_dynamic);
if (ret)
return ret;
@ -763,12 +764,12 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* add back binding - XXX refactor? */
binding_cmd.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
mvmvif->phy_ctxt->color));
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->deflink.phy_ctxt->id,
mvmvif->deflink.phy_ctxt->color));
binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
binding_cmd.phy =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
mvmvif->phy_ctxt->color));
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->deflink.phy_ctxt->id,
mvmvif->deflink.phy_ctxt->color));
binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color));
for (i = 1; i < MAX_MACS_IN_BINDING; i++)
@ -791,7 +792,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false, 0);
if (ret)
return ret;
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id],
ap_sta);
ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
if (ret)
@ -800,8 +802,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* and some quota */
quota = iwl_mvm_quota_cmd_get_quota(mvm, &quota_cmd, 0);
quota->id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
mvmvif->phy_ctxt->color));
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->deflink.phy_ctxt->id,
mvmvif->deflink.phy_ctxt->color));
quota->quota = cpu_to_le32(IWL_MVM_MAX_QUOTA);
quota->max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
@ -1027,7 +1029,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
if (ver == 2) {
size = sizeof(tkip_data.tkip);
tkip_data.tkip.sta_id =
cpu_to_le32(mvmvif->ap_sta_id);
cpu_to_le32(mvmvif->deflink.ap_sta_id);
} else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) {
size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1);
} else {
@ -1076,7 +1078,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len);
kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm);
kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->ap_sta_id);
kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id);
if (cmd_ver == 4) {
cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4);
@ -1269,7 +1271,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA) {
if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) {
/* if we're not associated, this must be netdetect */
if (!wowlan->nd_config) {
ret = 1;
@ -1285,10 +1287,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
} else {
struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
wowlan_config_cmd.sta_id = mvmvif->ap_sta_id;
wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id;
ap_sta = rcu_dereference_protected(
mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id],
lockdep_is_held(&mvm->mutex));
if (IS_ERR_OR_NULL(ap_sta)) {
ret = -EINVAL;
@ -2575,7 +2577,8 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,
/* if FW uses status notification, status shouldn't be NULL here */
if (!d3_data->status) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : mvmvif->ap_sta_id;
u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA :
mvmvif->deflink.ap_sta_id;
d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id);
}

View File

@ -179,7 +179,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
mutex_lock(&mvm->mutex);
ap_sta_id = mvmvif->ap_sta_id;
ap_sta_id = mvmvif->deflink.ap_sta_id;
switch (ieee80211_vif_type_p2p(vif)) {
case NL80211_IFTYPE_ADHOC:
@ -211,14 +211,14 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n",
mvm->tcm.result.load[mvmvif->id]);
pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
for (i = 0; i < ARRAY_SIZE(mvmvif->deflink.queue_params); i++)
pos += scnprintf(buf+pos, bufsz-pos,
"\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
i, mvmvif->queue_params[i].txop,
mvmvif->queue_params[i].cw_min,
mvmvif->queue_params[i].cw_max,
mvmvif->queue_params[i].aifs,
mvmvif->queue_params[i].uapsd);
i, mvmvif->deflink.queue_params[i].txop,
mvmvif->deflink.queue_params[i].cw_min,
mvmvif->deflink.queue_params[i].cw_max,
mvmvif->deflink.queue_params[i].aifs,
mvmvif->deflink.queue_params[i].uapsd);
if (vif->type == NL80211_IFTYPE_STATION &&
ap_sta_id != IWL_MVM_INVALID_STA) {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -8,6 +8,7 @@
#include <linux/err.h>
#include <linux/ieee80211.h>
#include <linux/netdevice.h>
#include <linux/dmi.h>
#include "mvm.h"
#include "sta.h"
@ -15,6 +16,7 @@
#include "debugfs.h"
#include "iwl-modparams.h"
#include "fw/error-dump.h"
#include "fw/api/phy-ctxt.h"
static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
char __user *user_buf,
@ -214,9 +216,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
int pos;
if (!mvm->temperature_test)
pos = scnprintf(buf , sizeof(buf), "disabled\n");
pos = scnprintf(buf, sizeof(buf), "disabled\n");
else
pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
pos = scnprintf(buf, sizeof(buf), "%d\n", mvm->temperature);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@ -261,7 +263,7 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
mvm->temperature = temperature;
}
IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
mvm->temperature_test ? "En" : "Dis" ,
mvm->temperature_test ? "En" : "Dis",
mvm->temperature);
/* handle the temperature change */
iwl_mvm_tt_handler(mvm);
@ -291,7 +293,7 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
if (ret)
return -EIO;
pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
pos = scnprintf(buf, sizeof(buf), "%d\n", temp);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@ -374,7 +376,7 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
{
struct ieee80211_sta *sta = file->private_data;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->deflink.lq_sta.rs_fw;
struct iwl_mvm *mvm = lq_sta->pers.drv;
static const size_t bufsz = 2048;
char *buff;
@ -714,6 +716,190 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf,
return ret;
}
static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
struct iwl_mvm_tas_status_resp tas_rsp;
struct iwl_mvm_tas_status_resp *rsp = &tas_rsp;
static const size_t bufsz = 1024;
char *buff, *pos, *endpos;
const char * const tas_dis_reason[TAS_DISABLED_REASON_MAX] = {
[TAS_DISABLED_DUE_TO_BIOS] =
"Due To BIOS",
[TAS_DISABLED_DUE_TO_SAR_6DBM] =
"Due To SAR Limit Less Than 6 dBm",
[TAS_DISABLED_REASON_INVALID] =
"N/A",
};
const char * const tas_current_status[TAS_DYNA_STATUS_MAX] = {
[TAS_DYNA_INACTIVE] = "INACTIVE",
[TAS_DYNA_INACTIVE_MVM_MODE] =
"inactive due to mvm mode",
[TAS_DYNA_INACTIVE_TRIGGER_MODE] =
"inactive due to trigger mode",
[TAS_DYNA_INACTIVE_BLOCK_LISTED] =
"inactive due to block listed",
[TAS_DYNA_INACTIVE_UHB_NON_US] =
"inactive due to uhb non US",
[TAS_DYNA_ACTIVE] = "ACTIVE",
};
struct iwl_host_cmd hcmd = {
.id = WIDE_ID(DEBUG_GROUP, GET_TAS_STATUS),
.flags = CMD_WANT_SKB,
.len = { 0, },
.data = { NULL, },
};
int ret, i, tmp;
bool tas_enabled = false;
unsigned long dyn_status;
if (!iwl_mvm_firmware_running(mvm))
return -ENODEV;
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd(mvm, &hcmd);
mutex_unlock(&mvm->mutex);
if (ret < 0)
return ret;
buff = kzalloc(bufsz, GFP_KERNEL);
if (!buff)
return -ENOMEM;
pos = buff;
endpos = pos + bufsz;
rsp = (void *)hcmd.resp_pkt->data;
pos += scnprintf(pos, endpos - pos, "TAS Conclusion:\n");
for (i = 0; i < rsp->in_dual_radio + 1; i++) {
if (rsp->tas_status_mac[i].band != TAS_LMAC_BAND_INVALID &&
rsp->tas_status_mac[i].dynamic_status & BIT(TAS_DYNA_ACTIVE)) {
pos += scnprintf(pos, endpos - pos, "\tON for ");
switch (rsp->tas_status_mac[i].band) {
case TAS_LMAC_BAND_HB:
pos += scnprintf(pos, endpos - pos, "HB\n");
break;
case TAS_LMAC_BAND_LB:
pos += scnprintf(pos, endpos - pos, "LB\n");
break;
case TAS_LMAC_BAND_UHB:
pos += scnprintf(pos, endpos - pos, "UHB\n");
break;
case TAS_LMAC_BAND_INVALID:
pos += scnprintf(pos, endpos - pos,
"INVALID BAND\n");
break;
default:
pos += scnprintf(pos, endpos - pos,
"Unsupported band (%d)\n",
rsp->tas_status_mac[i].band);
goto out;
}
tas_enabled = true;
}
}
if (!tas_enabled)
pos += scnprintf(pos, endpos - pos, "\tOFF\n");
pos += scnprintf(pos, endpos - pos, "TAS Report\n");
pos += scnprintf(pos, endpos - pos, "TAS FW version: %d\n",
rsp->tas_fw_version);
pos += scnprintf(pos, endpos - pos, "Is UHB enabled for USA?: %s\n",
rsp->is_uhb_for_usa_enable ? "True" : "False");
pos += scnprintf(pos, endpos - pos, "Current MCC: 0x%x\n",
le16_to_cpu(rsp->curr_mcc));
pos += scnprintf(pos, endpos - pos, "Block list entries:");
for (i = 0; i < APCI_WTAS_BLACK_LIST_MAX; i++)
pos += scnprintf(pos, endpos - pos, " 0x%x",
le16_to_cpu(rsp->block_list[i]));
pos += scnprintf(pos, endpos - pos, "\nOEM name: %s\n",
dmi_get_system_info(DMI_SYS_VENDOR));
pos += scnprintf(pos, endpos - pos, "\tVendor In Approved List: %s\n",
iwl_mvm_is_vendor_in_approved_list() ? "YES" : "NO");
pos += scnprintf(pos, endpos - pos,
"\tDo TAS Support Dual Radio?: %s\n",
rsp->in_dual_radio ? "TRUE" : "FALSE");
for (i = 0; i < rsp->in_dual_radio + 1; i++) {
if (rsp->tas_status_mac[i].static_status == 0) {
pos += scnprintf(pos, endpos - pos,
"Static status: disabled\n");
pos += scnprintf(pos, endpos - pos,
"Static disabled reason: %s (0)\n",
tas_dis_reason[0]);
goto out;
}
pos += scnprintf(pos, endpos - pos, "TAS status for ");
switch (rsp->tas_status_mac[i].band) {
case TAS_LMAC_BAND_HB:
pos += scnprintf(pos, endpos - pos, "High band\n");
break;
case TAS_LMAC_BAND_LB:
pos += scnprintf(pos, endpos - pos, "Low band\n");
break;
case TAS_LMAC_BAND_UHB:
pos += scnprintf(pos, endpos - pos,
"Ultra high band\n");
break;
case TAS_LMAC_BAND_INVALID:
pos += scnprintf(pos, endpos - pos,
"INVALID band\n");
break;
default:
pos += scnprintf(pos, endpos - pos,
"Unsupported band (%d)\n",
rsp->tas_status_mac[i].band);
goto out;
}
pos += scnprintf(pos, endpos - pos, "Static status: %sabled\n",
rsp->tas_status_mac[i].static_status ?
"En" : "Dis");
pos += scnprintf(pos, endpos - pos,
"\tStatic Disabled Reason: ");
if (rsp->tas_status_mac[i].static_dis_reason < TAS_DISABLED_REASON_MAX)
pos += scnprintf(pos, endpos - pos, "%s (%d)\n",
tas_dis_reason[rsp->tas_status_mac[i].static_dis_reason],
rsp->tas_status_mac[i].static_dis_reason);
else
pos += scnprintf(pos, endpos - pos,
"unsupported value (%d)\n",
rsp->tas_status_mac[i].static_dis_reason);
pos += scnprintf(pos, endpos - pos, "Dynamic status:\n");
dyn_status = (rsp->tas_status_mac[i].dynamic_status);
for_each_set_bit(tmp, &dyn_status, sizeof(dyn_status)) {
if (tmp >= 0 && tmp < TAS_DYNA_STATUS_MAX)
pos += scnprintf(pos, endpos - pos,
"\t%s (%d)\n",
tas_current_status[tmp], tmp);
}
pos += scnprintf(pos, endpos - pos,
"Is near disconnection?: %s\n",
rsp->tas_status_mac[i].near_disconnection ?
"True" : "False");
tmp = le16_to_cpu(rsp->tas_status_mac[i].max_reg_pwr_limit);
pos += scnprintf(pos, endpos - pos,
"Max. regulatory pwr limit (dBm): %d.%03d\n",
tmp / 8, 125 * (tmp % 8));
tmp = le16_to_cpu(rsp->tas_status_mac[i].sar_limit);
pos += scnprintf(pos, endpos - pos,
"SAR limit (dBm): %d.%03d\n",
tmp / 8, 125 * (tmp % 8));
}
out:
ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
kfree(buff);
iwl_free_resp(&hcmd);
return ret;
}
static ssize_t iwl_dbgfs_phy_integration_ver_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@ -1202,6 +1388,7 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
struct sk_buff *beacon;
struct ieee80211_tx_info *info;
struct iwl_mac_beacon_cmd beacon_cmd = {};
unsigned int link_id;
u8 rate;
int i;
@ -1250,17 +1437,24 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
info = IEEE80211_SKB_CB(beacon);
rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
beacon_cmd.flags =
cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, rate));
beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
for_each_mvm_vif_valid_link(mvmvif, link_id) {
beacon_cmd.flags =
cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw,
rate));
beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
if (iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 12)
beacon_cmd.link_id =
cpu_to_le32(mvmvif->link[link_id]->fw_link_id);
else
beacon_cmd.link_id = cpu_to_le32((u32)mvmvif->id);
iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
&beacon_cmd.tim_size,
beacon->data, beacon->len);
iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
&beacon_cmd.tim_size,
beacon->data, beacon->len);
iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,
sizeof(beacon_cmd));
iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,
sizeof(beacon_cmd));
}
mutex_unlock(&mvm->mutex);
dev_kfree_skb(beacon);
@ -1685,6 +1879,7 @@ MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
MVM_DEBUGFS_READ_FILE_OPS(fw_ver);
MVM_DEBUGFS_READ_FILE_OPS(phy_integration_ver);
MVM_DEBUGFS_READ_FILE_OPS(tas_get_status);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
@ -1894,6 +2089,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
if (mvm->fw->phy_integration_ver)
MVM_DEBUGFS_ADD_FILE(phy_integration_ver, mvm->debugfs_dir, 0400);
MVM_DEBUGFS_ADD_FILE(tas_get_status, mvm->debugfs_dir, 0400);
#ifdef CONFIG_ACPI
MVM_DEBUGFS_ADD_FILE(sar_geo_profile, mvm->debugfs_dir, 0400);
#endif

View File

@ -73,7 +73,7 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta;
rcu_read_lock();
sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id]);
sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]);
if (!IS_ERR_OR_NULL(sta) && sta->mfp)
expected_tk_len = 0;
rcu_read_unlock();
@ -510,13 +510,13 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
rcu_read_lock();
sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id]);
sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]);
if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based))
FTM_PUT_FLAG(PMF);
rcu_read_unlock();
target->sta_id = mvmvif->ap_sta_id;
target->sta_id = mvmvif->deflink.ap_sta_id;
} else {
target->sta_id = IWL_MVM_INVALID_STA;
}

View File

@ -119,7 +119,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
IWL_TOF_RESPONDER_CMD_VALID_BSSID |
IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
.sta_id = mvmvif->bcast_sta.sta_id,
.sta_id = mvmvif->deflink.bcast_sta.sta_id,
};
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 6);
int err;

View File

@ -21,6 +21,7 @@
#include "iwl-phy-db.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
#include "time-sync.h"
#define MVM_UCODE_ALIVE_TIMEOUT (HZ)
#define MVM_UCODE_CALIB_TIMEOUT (2 * HZ)
@ -122,8 +123,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
UCODE_ALIVE_NTFY, 0);
u32 i;
struct iwl_trans *trans = mvm->trans;
enum iwl_device_family device_family = trans->trans_cfg->device_family;
if (version == 6) {
@ -233,8 +232,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
if (umac_error_table) {
if (umac_error_table >=
mvm->trans->cfg->min_umac_error_event_table ||
device_family >= IWL_DEVICE_FAMILY_BZ) {
mvm->trans->cfg->min_umac_error_event_table) {
iwl_fw_umac_set_alive_err_table(mvm->trans,
umac_error_table);
} else {
@ -1040,7 +1038,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
ret = iwl_read_ppag_table(&mvm->fwrt, &cmd, &cmd_size);
/* Not supporting PPAG table is a valid scenario */
if(ret < 0)
if (ret < 0)
return 0;
IWL_DEBUG_RADIO(mvm, "Sending PER_PLATFORM_ANT_GAIN_CMD\n");
@ -1094,6 +1092,11 @@ static const struct dmi_system_id dmi_tas_approved_list[] = {
{}
};
bool iwl_mvm_is_vendor_in_approved_list(void)
{
return dmi_check_system(dmi_tas_approved_list);
}
static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc)
{
int i;
@ -1373,6 +1376,11 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{
}
bool iwl_mvm_is_vendor_in_approved_list(void)
{
return false;
}
static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
{
return DSM_VALUE_RFI_DISABLE;
@ -1562,8 +1570,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
}
/* init the fw <-> mac80211 STA mapping */
for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++)
for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);
}
memset(&mvm->fw_link_ids_map, 0, sizeof(mvm->fw_link_ids_map));
mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;
@ -1669,8 +1681,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB);
iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr,
IWL_TIME_SYNC_PROTOCOL_TM |
IWL_TIME_SYNC_PROTOCOL_FTM);
}
if (!mvm->ptp_data.ptp_clock)
iwl_mvm_ptp_init(mvm);
if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid))
IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n");
@ -1740,8 +1759,10 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
goto error;
/* init the fw <-> mac80211 STA mapping */
for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++)
for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);
}
if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) {
/*

View File

@ -0,0 +1,294 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2022 - 2023 Intel Corporation
*/
#include "mvm.h"
#include "time-event.h"
static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvm_vif)
{
u32 link_id;
lockdep_assert_held(&mvm->mutex);
link_id = ffz(mvm->fw_link_ids_map);
/* this case can happen if there're deactivated but not removed links */
if (link_id > IWL_MVM_FW_MAX_LINK_ID)
return IWL_MVM_FW_LINK_ID_INVALID;
mvm->fw_link_ids_map |= BIT(link_id);
return link_id;
}
static void iwl_mvm_release_fw_link_id(struct iwl_mvm *mvm, u32 link_id)
{
lockdep_assert_held(&mvm->mutex);
if (!WARN_ON(link_id > IWL_MVM_FW_MAX_LINK_ID))
mvm->fw_link_ids_map &= ~BIT(link_id);
}
static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm,
struct iwl_link_config_cmd *cmd,
enum iwl_ctxt_action action)
{
int ret;
cmd->action = cpu_to_le32(action);
ret = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD), 0,
sizeof(*cmd), cmd);
if (ret)
IWL_ERR(mvm, "Failed to send LINK_CONFIG_CMD (action:%d): %d\n",
action, ret);
return ret;
}
int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
unsigned int link_id = link_conf->link_id;
struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
struct iwl_link_config_cmd cmd = {};
struct iwl_mvm_phy_ctxt *phyctxt;
if (WARN_ON_ONCE(!link_info))
return -EINVAL;
if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) {
link_info->fw_link_id = iwl_mvm_get_free_fw_link_id(mvm,
mvmvif);
if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
return -EINVAL;
}
/* Update SF - Disable if needed. if this fails, SF might still be on
* while many macs are bound, which is forbidden - so fail the binding.
*/
if (iwl_mvm_sf_update(mvm, vif, false))
return -EINVAL;
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
cmd.mac_id = cpu_to_le32(mvmvif->id);
/* P2P-Device already has a valid PHY context during add */
phyctxt = link_info->phy_ctxt;
if (phyctxt)
cmd.phy_id = cpu_to_le32(phyctxt->id);
else
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
}
int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
u32 changes, bool active)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
unsigned int link_id = link_conf->link_id;
struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
struct iwl_mvm_phy_ctxt *phyctxt;
struct iwl_link_config_cmd cmd = {};
u32 ht_flag, flags = 0, flags_mask = 0;
int ret;
if (WARN_ON_ONCE(!link_info ||
link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
return -EINVAL;
if (changes & LINK_CONTEXT_MODIFY_ACTIVE) {
/* When activating a link, phy context should be valid;
* when deactivating a link, it also should be valid since
* the link was active before. So, do nothing in this case.
* Since a link is added first with FW_CTXT_INVALID, then we
* can get here in case it's removed before it was activated.
*/
if (!link_info->phy_ctxt)
return 0;
/* check there aren't too many active links */
if (!link_info->active && active) {
int i, count = 0;
/* link with phy_ctxt is active in FW */
for_each_mvm_vif_valid_link(mvmvif, i)
if (mvmvif->link[i]->phy_ctxt)
count++;
/* FIXME: IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM should be
* defined per HW
*/
if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM)
return -EINVAL;
}
/* Catch early if driver tries to activate or deactivate a link
* twice.
*/
WARN_ON_ONCE(active == link_info->active);
/* When deactivating a link session protection should
* be stopped
*/
if (!active && vif->type == NL80211_IFTYPE_STATION)
iwl_mvm_stop_session_protection(mvm, vif);
}
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
/* The phy_id, link address and listen_lmac can be modified only until
* the link becomes active, otherwise they will be ignored.
*/
phyctxt = link_info->phy_ctxt;
if (phyctxt)
cmd.phy_id = cpu_to_le32(phyctxt->id);
else
cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
cmd.mac_id = cpu_to_le32(mvmvif->id);
memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
cmd.active = cpu_to_le32(active);
if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
/* TODO: set a value to cmd.listen_lmac when system requiremens
* will define it
*/
iwl_mvm_set_fw_basic_rates(mvm, vif, link_conf,
&cmd.cck_rates, &cmd.ofdm_rates);
cmd.cck_short_preamble = cpu_to_le32(link_conf->use_short_preamble);
cmd.short_slot = cpu_to_le32(link_conf->use_short_slot);
/* The fw does not distinguish between ht and fat */
ht_flag = LINK_PROT_FLG_HT_PROT | LINK_PROT_FLG_FAT_PROT;
iwl_mvm_set_fw_protection_flags(mvm, vif, link_conf,
&cmd.protection_flags,
ht_flag, LINK_PROT_FLG_TGG_PROTECT);
iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, &cmd.ac[0],
&cmd.qos_flags);
cmd.bi = cpu_to_le32(link_conf->beacon_int);
cmd.dtim_interval = cpu_to_le32(link_conf->beacon_int *
link_conf->dtim_period);
if (!link_conf->he_support || iwlwifi_mod_params.disable_11ax ||
(vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS;
goto send_cmd;
}
cmd.htc_trig_based_pkt_ext = link_conf->htc_trig_based_pkt_ext;
if (link_conf->uora_exists) {
cmd.rand_alloc_ecwmin =
link_conf->uora_ocw_range & 0x7;
cmd.rand_alloc_ecwmax =
(link_conf->uora_ocw_range >> 3) & 0x7;
}
/* TODO how to set ndp_fdbk_buff_th_exp? */
if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif,
&cmd.trig_based_txf[0])) {
flags |= LINK_FLG_MU_EDCA_CW;
flags_mask |= LINK_FLG_MU_EDCA_CW;
}
if (link_conf->eht_puncturing && !iwlwifi_mod_params.disable_11be)
cmd.puncture_mask = cpu_to_le16(link_conf->eht_puncturing);
else
/* This flag can be set only if the MAC has eht support */
changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
cmd.bss_color = link_conf->he_bss_color.color;
if (!link_conf->he_bss_color.enabled) {
flags |= LINK_FLG_BSS_COLOR_DIS;
flags_mask |= LINK_FLG_BSS_COLOR_DIS;
}
cmd.frame_time_rts_th = cpu_to_le16(link_conf->frame_time_rts_th);
/* Block 26-tone RU OFDMA transmissions */
if (link_info->he_ru_2mhz_block) {
flags |= LINK_FLG_RU_2MHZ_BLOCK;
flags_mask |= LINK_FLG_RU_2MHZ_BLOCK;
}
if (link_conf->nontransmitted) {
ether_addr_copy(cmd.ref_bssid_addr,
link_conf->transmitter_bssid);
cmd.bssid_index = link_conf->bssid_index;
}
send_cmd:
cmd.modify_mask = cpu_to_le32(changes);
cmd.flags = cpu_to_le32(flags);
cmd.flags_mask = cpu_to_le32(flags_mask);
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY);
if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE))
link_info->active = active;
return ret;
}
int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
unsigned int link_id = link_conf->link_id;
struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
struct iwl_link_config_cmd cmd = {};
int ret;
if (WARN_ON(!link_info ||
link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
return -EINVAL;
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
iwl_mvm_release_fw_link_id(mvm, link_info->fw_link_id);
link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE);
if (!ret)
if (iwl_mvm_sf_update(mvm, vif, true))
IWL_ERR(mvm, "Failed to update SF state\n");
return ret;
}
/* link should be deactivated before removal, so in most cases we need to
* perform these two operations together
*/
int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
int ret;
ret = iwl_mvm_link_changed(mvm, vif, link_conf,
LINK_CONTEXT_MODIFY_ACTIVE, false);
if (ret)
return ret;
ret = iwl_mvm_remove_link(mvm, vif, link_conf);
if (ret)
return ret;
return ret;
}

View File

@ -293,15 +293,15 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* For TVQM this will be overwritten later with the FW assigned
* queue value (when queue is enabled).
*/
mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
mvmvif->deflink.cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
}
mvmvif->bcast_sta.sta_id = IWL_MVM_INVALID_STA;
mvmvif->mcast_sta.sta_id = IWL_MVM_INVALID_STA;
mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;
mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA;
mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA;
mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++)
mvmvif->smps_requests[i] = IEEE80211_SMPS_AUTOMATIC;
mvmvif->deflink.smps_requests[i] = IEEE80211_SMPS_AUTOMATIC;
return 0;
@ -396,15 +396,46 @@ static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,
*ofdm_rates = ofdm;
}
static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd)
void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
__le32 *cck_rates, __le32 *ofdm_rates)
{
struct ieee80211_chanctx_conf *chanctx;
u8 cck_ack_rates = 0, ofdm_ack_rates = 0;
rcu_read_lock();
chanctx = rcu_dereference(link_conf->chanctx_conf);
iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band
: NL80211_BAND_2GHZ,
&cck_ack_rates, &ofdm_ack_rates);
rcu_read_unlock();
*cck_rates = cpu_to_le32((u32)cck_ack_rates);
*ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates);
}
void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
__le32 *protection_flags, u32 ht_flag,
u32 tgg_flag)
{
/* for both sta and ap, ht_operation_mode hold the protection_mode */
u8 protection_mode = vif->bss_conf.ht_operation_mode &
u8 protection_mode = link_conf->ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION;
/* The fw does not distinguish between ht and fat */
u32 ht_flag = MAC_PROT_FLG_HT_PROT | MAC_PROT_FLG_FAT_PROT;
bool ht_enabled = !!(link_conf->ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION);
if (link_conf->use_cts_prot)
*protection_flags |= cpu_to_le32(tgg_flag);
IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n",
link_conf->use_cts_prot,
link_conf->ht_operation_mode);
if (!ht_enabled)
return;
IWL_DEBUG_RATE(mvm, "protection mode set to %d\n", protection_mode);
/*
@ -416,12 +447,12 @@ static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm,
break;
case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
cmd->protection_flags |= cpu_to_le32(ht_flag);
*protection_flags |= cpu_to_le32(ht_flag);
break;
case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
/* Protect when channel wider than 20MHz */
if (vif->bss_conf.chandef.width > NL80211_CHAN_WIDTH_20)
cmd->protection_flags |= cpu_to_le32(ht_flag);
if (link_conf->chandef.width > NL80211_CHAN_WIDTH_20)
*protection_flags |= cpu_to_le32(ht_flag);
break;
default:
IWL_ERR(mvm, "Illegal protection mode %d\n",
@ -430,6 +461,63 @@ static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm,
}
}
void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct iwl_ac_qos *ac, __le32 *qos_flags)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int i;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i);
u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
ac[ucode_ac].cw_min =
cpu_to_le16(mvmvif->deflink.queue_params[i].cw_min);
ac[ucode_ac].cw_max =
cpu_to_le16(mvmvif->deflink.queue_params[i].cw_max);
ac[ucode_ac].edca_txop =
cpu_to_le16(mvmvif->deflink.queue_params[i].txop * 32);
ac[ucode_ac].aifsn = mvmvif->deflink.queue_params[i].aifs;
ac[ucode_ac].fifos_mask = BIT(txf);
}
if (link_conf->qos)
*qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
if (link_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
*qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
}
int iwl_mvm_get_mac_type(struct ieee80211_vif *vif)
{
u32 mac_type = FW_MAC_TYPE_BSS_STA;
switch (vif->type) {
case NL80211_IFTYPE_STATION:
if (vif->p2p)
mac_type = FW_MAC_TYPE_P2P_STA;
else
mac_type = FW_MAC_TYPE_BSS_STA;
break;
case NL80211_IFTYPE_AP:
mac_type = FW_MAC_TYPE_GO;
break;
case NL80211_IFTYPE_MONITOR:
mac_type = FW_MAC_TYPE_LISTENER;
break;
case NL80211_IFTYPE_P2P_DEVICE:
mac_type = FW_MAC_TYPE_P2P_DEVICE;
break;
case NL80211_IFTYPE_ADHOC:
mac_type = FW_MAC_TYPE_IBSS;
break;
default:
WARN_ON_ONCE(1);
}
return mac_type;
}
static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd,
@ -437,39 +525,13 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
u32 action)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_chanctx_conf *chanctx;
bool ht_enabled = !!(vif->bss_conf.ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION);
u8 cck_ack_rates, ofdm_ack_rates;
const u8 *bssid = bssid_override ?: vif->bss_conf.bssid;
int i;
u32 ht_flag;
cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color));
cmd->action = cpu_to_le32(action);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
if (vif->p2p)
cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_STA);
else
cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_BSS_STA);
break;
case NL80211_IFTYPE_AP:
cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_GO);
break;
case NL80211_IFTYPE_MONITOR:
cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_LISTENER);
break;
case NL80211_IFTYPE_P2P_DEVICE:
cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_DEVICE);
break;
case NL80211_IFTYPE_ADHOC:
cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_IBSS);
break;
default:
WARN_ON_ONCE(1);
}
cmd->mac_type = cpu_to_le32(iwl_mvm_get_mac_type(vif));
cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
@ -480,15 +542,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
else
eth_broadcast_addr(cmd->bssid_addr);
rcu_read_lock();
chanctx = rcu_dereference(vif->bss_conf.chanctx_conf);
iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band
: NL80211_BAND_2GHZ,
&cck_ack_rates, &ofdm_ack_rates);
rcu_read_unlock();
cmd->cck_rates = cpu_to_le32((u32)cck_ack_rates);
cmd->ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates);
iwl_mvm_set_fw_basic_rates(mvm, vif, &vif->bss_conf, &cmd->cck_rates,
&cmd->ofdm_rates);
cmd->cck_short_preamble =
cpu_to_le32(vif->bss_conf.use_short_preamble ?
@ -499,33 +554,14 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->filter_flags = 0;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i);
u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, &cmd->ac[0],
&cmd->qos_flags);
cmd->ac[ucode_ac].cw_min =
cpu_to_le16(mvmvif->queue_params[i].cw_min);
cmd->ac[ucode_ac].cw_max =
cpu_to_le16(mvmvif->queue_params[i].cw_max);
cmd->ac[ucode_ac].edca_txop =
cpu_to_le16(mvmvif->queue_params[i].txop * 32);
cmd->ac[ucode_ac].aifsn = mvmvif->queue_params[i].aifs;
cmd->ac[ucode_ac].fifos_mask = BIT(txf);
}
if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
if (vif->bss_conf.use_cts_prot)
cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
IWL_DEBUG_RATE(mvm, "use_cts_prot %d, ht_operation_mode %d\n",
vif->bss_conf.use_cts_prot,
vif->bss_conf.ht_operation_mode);
if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
if (ht_enabled)
iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd);
/* The fw does not distinguish between ht and fat */
ht_flag = MAC_PROT_FLG_HT_PROT | MAC_PROT_FLG_FAT_PROT;
iwl_mvm_set_fw_protection_flags(mvm, vif, &vif->bss_conf,
&cmd->protection_flags,
ht_flag, MAC_PROT_FLG_TGG_PROTECT);
}
static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
@ -534,11 +570,76 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
int ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, 0,
sizeof(*cmd), cmd);
if (ret)
IWL_ERR(mvm, "Failed to send MAC context (action:%d): %d\n",
IWL_ERR(mvm, "Failed to send MAC_CONTEXT_CMD (action:%d): %d\n",
le32_to_cpu(cmd->action), ret);
return ret;
}
void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
__le64 *dtim_tsf, __le32 *dtim_time,
__le32 *assoc_beacon_arrive_time)
{
u32 dtim_offs;
/*
* The DTIM count counts down, so when it is N that means N
* more beacon intervals happen until the DTIM TBTT. Therefore
* add this to the current time. If that ends up being in the
* future, the firmware will handle it.
*
* Also note that the system_timestamp (which we get here as
* "sync_device_ts") and TSF timestamp aren't at exactly the
* same offset in the frame -- the TSF is at the first symbol
* of the TSF, the system timestamp is at signal acquisition
* time. This means there's an offset between them of at most
* a few hundred microseconds (24 * 8 bits + PLCP time gives
* 384us in the longest case), this is currently not relevant
* as the firmware wakes up around 2ms before the TBTT.
*/
dtim_offs = link_conf->sync_dtim_count *
link_conf->beacon_int;
/* convert TU to usecs */
dtim_offs *= 1024;
*dtim_tsf =
cpu_to_le64(link_conf->sync_tsf + dtim_offs);
*dtim_time =
cpu_to_le32(link_conf->sync_device_ts + dtim_offs);
*assoc_beacon_arrive_time =
cpu_to_le32(link_conf->sync_device_ts);
IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n",
le64_to_cpu(*dtim_tsf),
le32_to_cpu(*dtim_time),
dtim_offs);
}
__le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct ieee80211_p2p_noa_attr *noa =
&vif->bss_conf.p2p_noa_attr;
return cpu_to_le32(noa->oppps_ctwindow &
IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
}
__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
__le32 twt_policy = cpu_to_le32(0);
if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT)
twt_policy |= cpu_to_le32(TWT_SUPPORTED);
if (vif->bss_conf.twt_protected)
twt_policy |= cpu_to_le32(PROTECTED_TWT_SUPPORTED);
if (vif->bss_conf.twt_broadcast)
twt_policy |= cpu_to_le32(BROADCAST_TWT_SUPPORTED);
return twt_policy;
}
static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action, bool force_assoc_off,
@ -559,11 +660,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
if (vif->p2p) {
struct ieee80211_p2p_noa_attr *noa =
&vif->bss_conf.p2p_noa_attr;
cmd.p2p_sta.ctwin =
iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);
cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow &
IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
ctxt_sta = &cmd.p2p_sta.sta;
} else {
ctxt_sta = &cmd.sta;
@ -573,39 +672,11 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
if (vif->cfg.assoc && vif->bss_conf.dtim_period &&
!force_assoc_off) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 dtim_offs;
/*
* The DTIM count counts down, so when it is N that means N
* more beacon intervals happen until the DTIM TBTT. Therefore
* add this to the current time. If that ends up being in the
* future, the firmware will handle it.
*
* Also note that the system_timestamp (which we get here as
* "sync_device_ts") and TSF timestamp aren't at exactly the
* same offset in the frame -- the TSF is at the first symbol
* of the TSF, the system timestamp is at signal acquisition
* time. This means there's an offset between them of at most
* a few hundred microseconds (24 * 8 bits + PLCP time gives
* 384us in the longest case), this is currently not relevant
* as the firmware wakes up around 2ms before the TBTT.
*/
dtim_offs = vif->bss_conf.sync_dtim_count *
vif->bss_conf.beacon_int;
/* convert TU to usecs */
dtim_offs *= 1024;
ctxt_sta->dtim_tsf =
cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs);
ctxt_sta->dtim_time =
cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs);
ctxt_sta->assoc_beacon_arrive_time =
cpu_to_le32(vif->bss_conf.sync_device_ts);
IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n",
le64_to_cpu(ctxt_sta->dtim_tsf),
le32_to_cpu(ctxt_sta->dtim_time),
dtim_offs);
iwl_mvm_set_fw_dtim_tbtt(mvm, vif, &vif->bss_conf,
&ctxt_sta->dtim_tsf,
&ctxt_sta->dtim_time,
&ctxt_sta->assoc_beacon_arrive_time);
ctxt_sta->is_assoc = cpu_to_le32(1);
@ -635,14 +706,8 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) {
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT)
ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED);
if (vif->bss_conf.twt_protected)
ctxt_sta->data_policy |=
cpu_to_le32(PROTECTED_TWT_SUPPORTED);
if (vif->bss_conf.twt_broadcast)
ctxt_sta->data_policy |=
cpu_to_le32(BROADCAST_TWT_SUPPORTED);
ctxt_sta->data_policy |=
iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif);
}
@ -724,20 +789,11 @@ static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif)
data->go_active = true;
}
static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action)
__le32 iwl_mac_ctxt_p2p_dev_has_extended_disc(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mac_ctx_cmd cmd = {};
struct iwl_mvm_go_iterator_data data = {};
WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/* Override the filter flags to accept only probe requests */
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
/*
* This flag should be set to true when the P2P Device is
* discoverable and there is at least another active P2P GO. Settings
@ -750,7 +806,25 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
iwl_mvm_go_iterator, &data);
cmd.p2p_dev.is_disc_extended = cpu_to_le32(data.go_active ? 1 : 0);
return cpu_to_le32(data.go_active ? 1 : 0);
}
static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action)
{
struct iwl_mac_ctx_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.p2p_dev.is_disc_extended =
iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif);
/* Override the filter flags to accept only probe requests */
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@ -878,7 +952,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
/* Set up TX command fields */
tx->len = cpu_to_le16((u16)beacon->len);
tx->sta_id = mvmvif->bcast_sta.sta_id;
tx->sta_id = mvmvif->deflink.bcast_sta.sta_id;
tx->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
tx_flags |=
@ -973,7 +1047,8 @@ static int iwl_mvm_mac_ctxt_send_beacon_v7(struct iwl_mvm *mvm,
static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct sk_buff *beacon)
struct sk_buff *beacon,
struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(beacon);
@ -986,7 +1061,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
/* Enable FILS on PSC channels only */
rcu_read_lock();
ctx = rcu_dereference(vif->bss_conf.chanctx_conf);
ctx = rcu_dereference(link_conf->chanctx_conf);
channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq);
WARN_ON(channel == 0);
if (cfg80211_channel_is_psc(ctx->def.chan) &&
@ -1003,7 +1078,11 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
beacon_cmd.flags = cpu_to_le16(flags);
beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
if (iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 12)
beacon_cmd.link_id =
cpu_to_le32(mvmvif->link[link_conf->link_id]->fw_link_id);
else
beacon_cmd.link_id = cpu_to_le32((u32)mvmvif->id);
if (vif->type == NL80211_IFTYPE_AP)
iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
@ -1025,7 +1104,8 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct sk_buff *beacon)
struct sk_buff *beacon,
struct ieee80211_bss_conf *link_conf)
{
if (WARN_ON(!beacon))
return -EINVAL;
@ -1039,14 +1119,16 @@ int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
if (fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE))
return iwl_mvm_mac_ctxt_send_beacon_v9(mvm, vif, beacon);
return iwl_mvm_mac_ctxt_send_beacon_v9(mvm, vif, beacon,
link_conf);
return iwl_mvm_mac_ctxt_send_beacon_v7(mvm, vif, beacon);
}
/* The beacon template for the AP/GO/IBSS has changed and needs update */
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct sk_buff *beacon;
int ret;
@ -1054,7 +1136,8 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC);
beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0);
beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL,
link_conf->link_id);
if (!beacon)
return -ENOMEM;
@ -1065,7 +1148,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
}
#endif
ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon);
ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon, link_conf);
dev_kfree_skb(beacon);
return ret;
}
@ -1094,6 +1177,30 @@ static void iwl_mvm_mac_ap_iterator(void *_data, u8 *mac,
data->beacon_int = vif->bss_conf.beacon_int;
}
/*
* Fill the filter flags for mac context of type AP or P2P GO.
*/
void iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif,
__le32 *filter_flags,
int accept_probe_req_flag,
int accept_beacon_flag)
{
/*
* in AP mode, pass probe requests and beacons from other APs
* (needed for ht protection); when there're no any associated
* station don't ask FW to pass beacons to prevent unnecessary
* wake-ups.
*/
*filter_flags |= cpu_to_le32(accept_probe_req_flag);
if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) {
*filter_flags |= cpu_to_le32(accept_beacon_flag);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
}
/*
* Fill the specific data for mac context of type AP of P2P GO
*/
@ -1113,19 +1220,10 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
/* in AP mode, the MCAST FIFO takes the EDCA params from VO */
cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST);
/*
* in AP mode, pass probe requests and beacons from other APs
* (needed for ht protection); when there're no any associated
* station don't ask FW to pass beacons to prevent unnecessary
* wake-ups.
*/
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) {
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
&cmd->filter_flags,
MAC_FILTER_IN_PROBE_REQUEST,
MAC_FILTER_IN_BEACON);
ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
@ -1133,7 +1231,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_STA_TYPE))
ctxt_ap->mcast_qid = cpu_to_le32(mvmvif->cab_queue);
ctxt_ap->mcast_qid = cpu_to_le32(mvmvif->deflink.cab_queue);
/*
* Only set the beacon time when the MAC is being added, when we
@ -1287,12 +1385,9 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->color));
cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, 0,
sizeof(cmd), &cmd);
if (ret) {
IWL_ERR(mvm, "Failed to remove MAC context: %d\n", ret);
ret = iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
if (ret)
return ret;
}
mvmvif->uploaded = false;
@ -1320,7 +1415,8 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) {
int c = ieee80211_beacon_update_cntdwn(csa_vif);
iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif);
iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif,
&csa_vif->bss_conf);
if (csa_vif->p2p &&
!iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2 &&
tx_success) {
@ -1428,6 +1524,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
struct ieee80211_vif *vif;
u32 id = le32_to_cpu(mb->mac_id);
union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };
u32 mac_type;
IWL_DEBUG_INFO(mvm,
"missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
@ -1443,6 +1540,14 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
if (!vif)
goto out;
mac_type = iwl_mvm_get_mac_type(vif);
IWL_DEBUG_INFO(mvm, "missed beacon mac_type=%u,\n", mac_type);
mvm->trans->dbg.dump_file_name_ext_valid = true;
snprintf(mvm->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME,
"MacId_%d_MacType_%d", id, mac_type);
rx_missed_bcon = le32_to_cpu(mb->consec_missed_beacons);
rx_missed_bcon_since_rx =
le32_to_cpu(mb->consec_missed_beacons_since_last_rx);
@ -1576,9 +1681,9 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
sizeof(struct ieee80211_p2p_noa_desc) + 2)
new_data->noa_len -= sizeof(struct ieee80211_p2p_noa_desc);
old_data = rcu_dereference_protected(mvmvif->probe_resp_data,
lockdep_is_held(&mvmvif->mvm->mutex));
rcu_assign_pointer(mvmvif->probe_resp_data, new_data);
old_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,
lockdep_is_held(&mvmvif->mvm->mutex));
rcu_assign_pointer(mvmvif->deflink.probe_resp_data, new_data);
if (old_data)
kfree_rcu(old_data, rcu_head);

File diff suppressed because it is too large Load Diff

View File

@ -17,17 +17,17 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_AP &&
!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return BIT(mvmvif->mcast_sta.sta_id);
return BIT(mvmvif->deflink.mcast_sta.sta_id);
if (sta) {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
return BIT(mvmsta->sta_id);
return BIT(mvmsta->deflink.sta_id);
}
if (vif->type == NL80211_IFTYPE_STATION &&
mvmvif->ap_sta_id != IWL_MVM_INVALID_STA)
return BIT(mvmvif->ap_sta_id);
mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA)
return BIT(mvmvif->deflink.ap_sta_id);
/* invalid */
return 0;
@ -70,8 +70,8 @@ static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
rcu_read_lock();
if (!sta && vif->type == NL80211_IFTYPE_STATION &&
mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) {
u8 sta_id = mvmvif->ap_sta_id;
mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) {
u8 sta_id = mvmvif->deflink.ap_sta_id;
sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
lockdep_is_held(&mvm->mutex));
@ -195,6 +195,7 @@ static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
void *data)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
unsigned int link_id = (uintptr_t)data;
if (key->hw_key_idx == STA_KEY_IDX_INVALID)
return;
@ -202,19 +203,23 @@ static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
if (sta)
return;
if (key->link_id >= 0 && key->link_id != link_id)
return;
_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
key->hw_key_idx = STA_KEY_IDX_INVALID;
}
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
struct ieee80211_vif *vif,
struct iwl_mvm_vif_link_info *link,
unsigned int link_id)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION ||
mvmvif->ap_sta_id == IWL_MVM_INVALID_STA))
if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
link->ap_sta_id == IWL_MVM_INVALID_STA))
return;
if (!sec_key_ver)
@ -222,5 +227,5 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
ieee80211_iter_keys_rcu(mvm->hw, vif,
iwl_mvm_sec_key_remove_ap_iter,
NULL);
(void *)(uintptr_t)link_id);
}

View File

@ -0,0 +1,306 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2022 Intel Corporation
*/
#include "mvm.h"
static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_config_cmd *cmd,
u32 action)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_bss_conf *link_conf;
unsigned int link_id;
cmd->id_and_color = cpu_to_le32(mvmvif->id);
cmd->action = cpu_to_le32(action);
cmd->mac_type = cpu_to_le32(iwl_mvm_get_mac_type(vif));
memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN);
cmd->he_support = 0;
cmd->eht_support = 0;
/* should be set by specific context type handler */
cmd->filter_flags = 0;
cmd->nic_not_ack_enabled =
cpu_to_le32(!iwl_mvm_is_nic_ack_enabled(mvm, vif));
if (iwlwifi_mod_params.disable_11ax)
return;
/* If we have MLO enabled, then the firmware needs to enable
* address translation for the station(s) we add. That depends
* on having EHT enabled in firmware, which in turn depends on
* mac80211 in the code below.
* However, mac80211 doesn't enable HE/EHT until it has parsed
* the association response successfully, so just skip all that
* and enable both when we have MLO.
*/
if (vif->valid_links) {
cmd->he_support = cpu_to_le32(1);
cmd->eht_support = cpu_to_le32(1);
return;
}
rcu_read_lock();
for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) {
link_conf = rcu_dereference(vif->link_conf[link_id]);
if (!link_conf)
continue;
if (link_conf->he_support)
cmd->he_support = cpu_to_le32(1);
/* it's not reasonable to have EHT without HE and FW API doesn't
* support it. Ignore EHT in this case.
*/
if (!link_conf->he_support && link_conf->eht_support)
continue;
if (link_conf->eht_support) {
cmd->eht_support = cpu_to_le32(1);
break;
}
}
rcu_read_unlock();
}
static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
struct iwl_mac_config_cmd *cmd)
{
int ret = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD),
0, sizeof(*cmd), cmd);
if (ret)
IWL_ERR(mvm, "Failed to send MAC_CONFIG_CMD (action:%d): %d\n",
le32_to_cpu(cmd->action), ret);
return ret;
}
static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action, bool force_assoc_off)
{
struct iwl_mac_config_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_STATION);
/* Fill the common data for all mac context types */
iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
/*
* We always want to hear MCAST frames, if we're not authorized yet,
* we'll drop them.
*/
cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP);
if (vif->p2p)
cmd.client.ctwin =
iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);
if (vif->cfg.assoc && !force_assoc_off) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
cmd.client.is_assoc = cpu_to_le32(1);
if (!mvmvif->authorized &&
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO))
cmd.client.data_policy |=
cpu_to_le32(COEX_HIGH_PRIORITY_ENABLE);
} else {
cmd.client.is_assoc = cpu_to_le32(0);
/* Allow beacons to pass through as long as we are not
* associated, or we do not have dtim period information.
*/
cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
}
cmd.client.assoc_id = cpu_to_le32(vif->cfg.aid);
if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)
cmd.client.data_policy |=
iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif);
return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
}
static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action)
{
struct iwl_mac_config_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC |
MAC_FILTER_IN_CONTROL_AND_MGMT |
MAC_CFG_FILTER_ACCEPT_BEACON |
MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
MAC_CFG_FILTER_ACCEPT_GRP);
return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
}
static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mac_config_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON |
MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
MAC_CFG_FILTER_ACCEPT_GRP);
/* TODO: Assumes that the beacon id == mac context id */
cmd.go_ibss.beacon_template = cpu_to_le32(mvmvif->id);
return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
}
static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action)
{
struct iwl_mac_config_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
cmd.p2p_dev.is_disc_extended =
iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif);
/* Override the filter flags to accept only probe requests */
cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
}
static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mac_config_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_AP);
/* Fill the common data for all mac context types */
iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
&cmd.filter_flags,
MAC_CFG_FILTER_ACCEPT_PROBE_REQ,
MAC_CFG_FILTER_ACCEPT_BEACON);
/* TODO: Assume that the beacon id == mac context id */
cmd.go_ibss.beacon_template = cpu_to_le32(mvmvif->id);
return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
}
static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action, bool force_assoc_off)
{
switch (vif->type) {
case NL80211_IFTYPE_STATION:
return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,
force_assoc_off);
case NL80211_IFTYPE_AP:
return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action);
case NL80211_IFTYPE_MONITOR:
return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action);
case NL80211_IFTYPE_P2P_DEVICE:
return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action);
case NL80211_IFTYPE_ADHOC:
return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action);
default:
break;
}
return -EOPNOTSUPP;
}
int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
return -EOPNOTSUPP;
if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
vif->addr, ieee80211_vif_type_p2p(vif)))
return -EIO;
ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
true);
if (ret)
return ret;
/* will only do anything at resume from D3 time */
iwl_mvm_set_last_nonqos_seq(mvm, vif);
mvmvif->uploaded = true;
return 0;
}
int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool force_assoc_off)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
return -EOPNOTSUPP;
if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
vif->addr, ieee80211_vif_type_p2p(vif)))
return -EIO;
return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
force_assoc_off);
}
int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mac_config_cmd cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
.id_and_color = cpu_to_le32(mvmvif->id),
};
int ret;
if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
return -EOPNOTSUPP;
if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
vif->addr, ieee80211_vif_type_p2p(vif)))
return -EIO;
ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
if (ret)
return ret;
mvmvif->uploaded = false;
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@
#include <linux/thermal.h>
#endif
#include <linux/ptp_clock_kernel.h>
#include <linux/ktime.h>
#include "iwl-op-mode.h"
@ -71,7 +73,11 @@
/* offchannel queue towards mac80211 */
#define IWL_MVM_OFFCHANNEL_QUEUE 0
/* invalid value for FW link id */
#define IWL_MVM_FW_LINK_ID_INVALID 0xff
extern const struct ieee80211_ops iwl_mvm_hw_ops;
extern const struct ieee80211_ops iwl_mvm_mld_hw_ops;
/**
* struct iwl_mvm_mod_params - module parameters for iwlmvm
@ -277,12 +283,61 @@ struct iwl_probe_resp_data {
int noa_len;
};
/**
* struct iwl_mvm_vif_link_info - per link data in Virtual Interface
* @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
* @fw_link_id: the id of the link according to the FW API
* @bssid: BSSID for this (client) interface
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
* @beacon_stats: beacon statistics, containing the # of received beacons,
* # of received beacons accumulated over FW restart, and the current
* average signal of beacons retrieved from the firmware
* @smps_requests: the SMPS requests of different parts of the driver,
* combined on update to yield the overall request to mac80211.
* @probe_resp_data: data from FW notification to store NOA and CSA related
* data to be inserted into probe response.
* @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked
* @queue_params: QoS params for this MAC
* @mgmt_queue: queue number for unbufferable management frames
*/
struct iwl_mvm_vif_link_info {
u8 bssid[ETH_ALEN];
u8 ap_sta_id;
u8 fw_link_id;
struct iwl_mvm_int_sta bcast_sta;
struct iwl_mvm_int_sta mcast_sta;
struct {
u32 num_beacons, accu_num_beacons;
u8 avg_signal;
} beacon_stats;
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
struct iwl_probe_resp_data __rcu *probe_resp_data;
bool he_ru_2mhz_block;
bool active;
u16 cab_queue;
/* Assigned while mac80211 has the link in a channel context,
* or, for P2P Device, while it exists.
*/
struct iwl_mvm_phy_ctxt *phy_ctxt;
/* QoS data from mac80211, need to store this here
* as mac80211 has a separate callback but we need
* to have the data for the MAC context
*/
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
u16 mgmt_queue;
};
/**
* struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
* @id: between 0 and 3
* @color: to solve races upon MAC addition and removal
* @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
* @bssid: BSSID for this (client) interface
* @associated: indicates that we're currently associated, used only for
* managing the firmware state in iwl_mvm_bss_info_changed_station()
* @ap_assoc_sta_count: count of stations associated to us - valid only
@ -290,7 +345,7 @@ struct iwl_probe_resp_data {
* @uploaded: indicates the MAC context has been added to the device
* @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
* should get quota etc.
* @pm_enabled - Indicate if MAC power management is allowed
* @pm_enabled - indicate if MAC power management is allowed
* @monitor_active: indicates that monitor context is configured, and that the
* interface should get quota etc.
* @low_latency: bit flags for low latency
@ -299,68 +354,31 @@ struct iwl_probe_resp_data {
* as a result from low_latency bit flags and takes force into account.
* @authorized: indicates the AP station was set to authorized
* @ps_disabled: indicates that this interface requires PS to be disabled
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
* @beacon_skb: the skb used to hold the AP/GO beacon template
* @smps_requests: the SMPS requests of different parts of the driver,
* combined on update to yield the overall request to mac80211.
* @beacon_stats: beacon statistics, containing the # of received beacons,
* # of received beacons accumulated over FW restart, and the current
* average signal of beacons retrieved from the firmware
* @csa_countdown: indicates that CSA countdown may be started
* @csa_failed: CSA failed to schedule time event, report an error later
* @csa_bcn_pending: indicates that we are waiting for a beacon on a new channel
* @features: hw features active for this vif
* @probe_resp_data: data from FW notification to store NOA and CSA related
* data to be inserted into probe response.
*/
struct iwl_mvm_vif {
struct iwl_mvm *mvm;
u16 id;
u16 color;
u8 ap_sta_id;
u8 bssid[ETH_ALEN];
bool associated;
u8 ap_assoc_sta_count;
u16 cab_queue;
bool uploaded;
bool ap_ibss_active;
bool pm_enabled;
bool monitor_active;
u8 low_latency: 6;
u8 low_latency_actual: 1;
u8 authorized:1;
bool ps_disabled;
struct iwl_mvm_vif_bf_data bf_data;
struct {
u32 num_beacons, accu_num_beacons;
u8 avg_signal;
} beacon_stats;
u32 ap_beacon_time;
enum iwl_tsf_id tsf_id;
/*
* QoS data from mac80211, need to store this here
* as mac80211 has a separate callback but we need
* to have the data for the MAC context
*/
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
struct iwl_mvm_time_event_data time_event_data;
struct iwl_mvm_time_event_data hs_time_event_data;
struct iwl_mvm_int_sta bcast_sta;
struct iwl_mvm_int_sta mcast_sta;
/*
* Assigned while mac80211 has the interface in a channel context,
* or, for P2P Device, while it exists.
*/
struct iwl_mvm_phy_ctxt *phy_ctxt;
struct iwl_mvm_vif_bf_data bf_data;
#ifdef CONFIG_PM
/* WoWLAN GTK rekey data */
@ -396,40 +414,43 @@ struct iwl_mvm_vif {
int dbgfs_quota_min;
#endif
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
/* FW identified misbehaving AP */
u8 uapsd_misbehaving_bssid[ETH_ALEN];
struct delayed_work uapsd_nonagg_detected_wk;
/* Indicates that CSA countdown may be started */
bool csa_countdown;
bool csa_failed;
bool csa_bcn_pending;
u16 csa_target_freq;
u16 csa_count;
u16 csa_misbehave;
struct delayed_work csa_work;
/* Indicates that we are waiting for a beacon on a new channel */
bool csa_bcn_pending;
enum iwl_tsf_id tsf_id;
struct iwl_mvm_time_event_data time_event_data;
struct iwl_mvm_time_event_data hs_time_event_data;
/* TCP Checksum Offload */
netdev_features_t features;
struct iwl_probe_resp_data __rcu *probe_resp_data;
/* we can only have 2 GTK + 2 IGTK active at a time */
struct ieee80211_key_conf *ap_early_keys[4];
/* 26-tone RU OFDMA transmissions should be blocked */
bool he_ru_2mhz_block;
struct {
struct ieee80211_key_conf __rcu *keys[2];
} bcn_prot;
struct iwl_mvm_vif_link_info deflink;
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
};
#define for_each_mvm_vif_valid_link(mvm_vif, link_id) \
for (link_id = 0; \
link_id < ARRAY_SIZE((mvm_vif)->link); \
link_id++) \
if ((mvm_vif)->link[link_id])
static inline struct iwl_mvm_vif *
iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
{
@ -772,6 +793,37 @@ struct iwl_mvm_dqa_txq_info {
enum iwl_mvm_queue_status status;
};
struct ptp_data {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
struct delayed_work dwork;
/* The last GP2 reading from the hw */
u32 last_gp2;
/* number of wraparounds since scale_update_adj_time_ns */
u32 wrap_counter;
/* GP2 time when the scale was last updated */
u32 scale_update_gp2;
/* Adjusted time when the scale was last updated in nanoseconds */
u64 scale_update_adj_time_ns;
/* clock frequency offset, scaled to 65536000000 */
u64 scaled_freq;
/* Delta between hardware clock and ptp clock in nanoseconds */
s64 delta;
};
struct iwl_time_sync_data {
struct sk_buff_head frame_list;
u8 peer_addr[ETH_ALEN];
bool active;
};
struct iwl_mvm {
/* for logger access */
struct device *dev;
@ -857,6 +909,8 @@ struct iwl_mvm {
/* data related to data path */
struct iwl_rx_phy_info last_phy_info;
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT_MAX];
struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_MVM_STATION_COUNT_MAX];
unsigned long fw_link_ids_map;
u8 rx_ba_sessions;
/* configured by mac80211 */
@ -1083,6 +1137,8 @@ struct iwl_mvm {
struct list_head resp_pasn_list;
struct ptp_data ptp_data;
struct {
u8 range_resp;
} cmd_ver;
@ -1114,8 +1170,11 @@ struct iwl_mvm {
unsigned long last_reset_or_resume_time_jiffies;
bool sta_remove_requires_queue_remove;
bool mld_api_is_used;
bool pldr_sync;
struct iwl_time_sync_data time_sync;
};
/* Extract MVM priv from op_mode and _hw */
@ -1315,7 +1374,7 @@ static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm)
{
return fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CSUM_SUPPORT) &&
!IWL_MVM_HW_CSUM_DISABLE;
!IWL_MVM_HW_CSUM_DISABLE;
}
static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
@ -1340,6 +1399,28 @@ static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT);
}
static inline bool iwl_mvm_has_mld_api(const struct iwl_fw *fw)
{
return (iwl_fw_lookup_cmd_ver(fw, LINK_CONFIG_CMD,
IWL_FW_CMD_VER_UNKNOWN) !=
IWL_FW_CMD_VER_UNKNOWN) &&
(iwl_fw_lookup_cmd_ver(fw, MAC_CONFIG_CMD,
IWL_FW_CMD_VER_UNKNOWN) !=
IWL_FW_CMD_VER_UNKNOWN) &&
(iwl_fw_lookup_cmd_ver(fw, STA_CONFIG_CMD,
IWL_FW_CMD_VER_UNKNOWN) !=
IWL_FW_CMD_VER_UNKNOWN) &&
(iwl_fw_lookup_cmd_ver(fw, AUX_STA_CMD,
IWL_FW_CMD_VER_UNKNOWN) !=
IWL_FW_CMD_VER_UNKNOWN) &&
(iwl_fw_lookup_cmd_ver(fw, STA_REMOVE_CMD,
IWL_FW_CMD_VER_UNKNOWN) !=
IWL_FW_CMD_VER_UNKNOWN) &&
(iwl_fw_lookup_cmd_ver(fw, STA_DISABLE_TX_CMD,
IWL_FW_CMD_VER_UNKNOWN) !=
IWL_FW_CMD_VER_UNKNOWN);
}
static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm)
{
/* TODO - replace with TLV once defined */
@ -1481,6 +1562,7 @@ void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags,
struct ieee80211_tx_rate *r);
u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx);
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
{
@ -1528,6 +1610,17 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk);
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal);
int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, u16 tids);
/* Utils to extract sta related data */
__le32 iwl_mvm_get_sta_htc_flags(struct ieee80211_sta *sta,
struct ieee80211_link_sta *link_sta);
u8 iwl_mvm_get_sta_uapsd_acs(struct ieee80211_sta *sta);
u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta,
struct ieee80211_bss_conf *link_conf,
u32 *_agg_size);
int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm,
struct ieee80211_link_sta *link_sta,
struct iwl_he_pkt_ext_v2 *pkt_ext);
void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info,
@ -1627,6 +1720,7 @@ void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
/* MVM PHY */
struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm);
int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic);
@ -1642,16 +1736,55 @@ u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef);
u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef);
/* MAC (virtual interface) programming */
void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
void iwl_mvm_set_fw_basic_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
__le32 *cck_rates, __le32 *ofdm_rates);
void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
__le32 *protection_flags, u32 ht_flag,
u32 tgg_flag);
void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct iwl_ac_qos *ac, __le32 *qos_flags);
bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif,
struct iwl_he_backoff_conf *trig_based_txf);
void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
__le64 *dtim_tsf, __le32 *dtim_time,
__le32 *assoc_beacon_arrive_time);
__le32 iwl_mac_ctxt_p2p_dev_has_extended_disc(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
void iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif,
__le32 *filter_flags,
int accept_probe_req_flag,
int accept_beacon_flag);
int iwl_mvm_get_mac_type(struct ieee80211_vif *vif);
__le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool force_assoc_off);
int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool force_assoc_off, const u8 *bssid_override);
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct sk_buff *beacon);
struct sk_buff *beacon,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
struct sk_buff *beacon,
void *data, int len);
@ -1688,6 +1821,93 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
/* Links */
int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
u32 changes, bool active);
int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
/* AP and IBSS */
bool iwl_mvm_start_ap_ibss_common(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int *ret);
void iwl_mvm_stop_ap_ibss_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
/* BSS Info */
/**
* struct iwl_mvm_bss_info_changed_ops - callbacks for the bss_info_changed()
*
* Since the only difference between both MLD and
* non-MLD versions of bss_info_changed() is these function calls,
* each version will send its specific function calls to
* %iwl_mvm_bss_info_changed_common().
*
* @bss_info_changed_sta: pointer to the function that handles changes
* in bss_info in sta mode
* @bss_info_changed_ap_ibss: pointer to the function that handles changes
* in bss_info in ap and ibss modes
*/
struct iwl_mvm_bss_info_changed_ops {
void (*bss_info_changed_sta)(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u64 changes);
void (*bss_info_changed_ap_ibss)(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u64 changes);
};
void
iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
struct iwl_mvm_bss_info_changed_ops *callbacks,
u64 changes);
void
iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
u64 changes);
void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u64 changes);
/* ROC */
/**
* struct iwl_mvm_roc_ops - callbacks for the remain_on_channel()
*
* Since the only difference between both MLD and
* non-MLD versions of remain_on_channel() is these function calls,
* each version will send its specific function calls to
* %iwl_mvm_roc_common().
*
* @add_aux_sta_for_hs20: pointer to the function that adds an aux sta
* for Hot Spot 2.0
* @switch_phy_ctxt: pointer to the function that switches a vif from one
* phy_ctx to another
*/
struct iwl_mvm_roc_ops {
int (*add_aux_sta_for_hs20)(struct iwl_mvm *mvm, u32 lmac_id);
int (*switch_phy_ctxt)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_phy_ctxt *new_phy_ctxt);
};
int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, int duration,
enum ieee80211_roc_type type,
struct iwl_mvm_roc_ops *ops);
int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
/*Session Protection */
void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u32 duration_override);
/* Quota management */
static inline size_t iwl_mvm_quota_cmd_size(struct iwl_mvm *mvm)
{
@ -1867,10 +2087,17 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
/* SMPS */
void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request);
enum ieee80211_smps_mode smps_request,
unsigned int link_id);
void
iwl_mvm_update_smps_on_active_links(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request);
bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *ctxt);
void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif);
void iwl_mvm_update_link_smps(struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
/* Low latency */
int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@ -2080,6 +2307,9 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
const struct ieee80211_sta *sta,
u16 tid);
void iwl_mvm_ptp_init(struct iwl_mvm *mvm);
void iwl_mvm_ptp_remove(struct iwl_mvm *mvm);
u64 iwl_mvm_ptp_get_adj_time(struct iwl_mvm *mvm, u64 base_time);
int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b);
int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm);
int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm);
@ -2101,7 +2331,9 @@ int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf);
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
struct ieee80211_vif *vif,
struct iwl_mvm_vif_link_info *link,
unsigned int link_id);
int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm,
struct iwl_rfi_lut_entry *rfi_table);
@ -2124,6 +2356,45 @@ static inline u8 iwl_mvm_phy_band_from_nl80211(enum nl80211_band band)
}
}
/* Channel Switch */
void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk);
int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
/* Channel Context */
/**
* struct iwl_mvm_switch_vif_chanctx_ops - callbacks for switch_vif_chanctx()
*
* Since the only difference between both MLD and
* non-MLD versions of switch_vif_chanctx() is these function calls,
* each version will send its specific function calls to
* %iwl_mvm_switch_vif_chanctx_common().
*
* @__assign_vif_chanctx: pointer to the function that assigns a chanctx to
* a given vif
* @__unassign_vif_chanctx: pointer to the function that unassigns a chanctx to
* a given vif
*/
struct iwl_mvm_switch_vif_chanctx_ops {
int (*__assign_vif_chanctx)(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx,
bool switching_chanctx);
void (*__unassign_vif_chanctx)(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx,
bool switching_chanctx);
};
int
iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode,
struct iwl_mvm_switch_vif_chanctx_ops *ops);
/* Channel info utils */
static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm)
{
@ -2244,5 +2515,128 @@ static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool forbidden);
bool iwl_mvm_is_vendor_in_approved_list(void);
/* Callbacks for ieee80211_ops */
void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control, struct sk_buff *skb);
void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw,
struct ieee80211_txq *txq);
int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params);
int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
int iwl_mvm_mac_start(struct ieee80211_hw *hw);
void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type);
void iwl_mvm_mac_stop(struct ieee80211_hw *hw);
static inline int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
{
return 0;
}
u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags, u64 multicast);
int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req);
void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta);
void
iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tids,
int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data);
void
iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tids,
int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data);
int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u32 changed);
void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_prep_tx_info *info);
void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_prep_tx_info *info);
void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_scan_ies *ies);
int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_key_conf *keyconf,
struct ieee80211_sta *sta,
u32 iv32, u16 *phase1key);
int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx, u32 changed);
int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw);
int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set);
void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw);
int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw);
void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw);
void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct ieee80211_event *event);
void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw);
int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
void *data, int len);
int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo);
int
iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_ftm_responder_stats *stats);
int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_pmsr_request *request);
void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_pmsr_request *request);
bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1,
struct iwl_mvm_vif *vif2);
bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif);
int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
s16 tx_power);
int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_set_hw_timestamp *hwts);
int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
#endif /* __IWL_MVM_H__ */

View File

@ -29,6 +29,7 @@
#include "fw-api.h"
#include "fw/acpi.h"
#include "fw/uefi.h"
#include "time-sync.h"
#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
MODULE_DESCRIPTION(DRV_DESCRIPTION);
@ -208,24 +209,37 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm,
ieee80211_disconnect(vif, true);
}
void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif)
void iwl_mvm_update_link_smps(struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
enum ieee80211_smps_mode mode = IEEE80211_SMPS_AUTOMATIC;
if (!link_conf)
return;
if (mvm->fw_static_smps_request &&
vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_160 &&
vif->bss_conf.he_support)
link_conf->chandef.width == NL80211_CHAN_WIDTH_160 &&
link_conf->he_support)
mode = IEEE80211_SMPS_STATIC;
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, mode);
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, mode,
link_conf->link_id);
}
static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
iwl_mvm_apply_fw_smps_request(vif);
struct ieee80211_bss_conf *link_conf;
unsigned int link_id;
rcu_read_lock();
for_each_vif_active_link(vif, link_conf, link_id)
iwl_mvm_update_link_smps(vif, link_conf);
rcu_read_unlock();
}
static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm,
@ -404,6 +418,15 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER_GRP(SYSTEM_GROUP, RFI_DEACTIVATE_NOTIF,
iwl_rfi_deactivate_notif_handler, RX_HANDLER_ASYNC_UNLOCKED,
struct iwl_rfi_deactivate_notif),
RX_HANDLER_GRP(LEGACY_GROUP,
WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION,
iwl_mvm_time_sync_msmt_event, RX_HANDLER_SYNC,
struct iwl_time_msmt_notify),
RX_HANDLER_GRP(LEGACY_GROUP,
WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION,
iwl_mvm_time_sync_msmt_confirm_event, RX_HANDLER_SYNC,
struct iwl_time_msmt_cfm_notify),
};
#undef RX_HANDLER
#undef RX_HANDLER_GRP
@ -449,6 +472,8 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD),
HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP),
HCMD_NAME(BT_COEX_CI),
HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION),
HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION),
HCMD_NAME(PHY_CONFIGURATION_CMD),
HCMD_NAME(CALIB_RES_NOTIF_PHY_DB),
HCMD_NAME(PHY_DB_CMD),
@ -521,6 +546,12 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD),
HCMD_NAME(SESSION_PROTECTION_CMD),
HCMD_NAME(MAC_CONFIG_CMD),
HCMD_NAME(LINK_CONFIG_CMD),
HCMD_NAME(STA_CONFIG_CMD),
HCMD_NAME(AUX_STA_CMD),
HCMD_NAME(STA_REMOVE_CMD),
HCMD_NAME(STA_DISABLE_TX_CMD),
HCMD_NAME(SESSION_PROTECTION_NOTIF),
HCMD_NAME(CHANNEL_SWITCH_START_NOTIF),
};
@ -1098,6 +1129,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
********************************/
hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) +
sizeof(struct iwl_mvm),
iwl_mvm_has_mld_api(fw) ? &iwl_mvm_mld_hw_ops :
&iwl_mvm_hw_ops);
if (!hw)
return NULL;
@ -1278,6 +1310,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->sta_remove_requires_queue_remove =
trans_cfg.queue_alloc_cmd_ver > 0;
mvm->mld_api_is_used = iwl_mvm_has_mld_api(mvm->fw);
/* Configure transport layer */
iwl_trans_configure(mvm->trans, &trans_cfg);
@ -1333,6 +1367,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
else
memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
iwl_mvm_init_time_sync(&mvm->time_sync);
mvm->debugfs_dir = dbgfs_dir;
mvm->mei_registered = !iwl_mei_register(mvm, &mei_ops);
@ -1430,6 +1466,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
kfree(mvm->error_recovery_buf);
mvm->error_recovery_buf = NULL;
iwl_mvm_ptp_remove(mvm);
iwl_trans_op_mode_leave(mvm->trans);
iwl_phy_db_free(mvm->phy_db);

View File

@ -382,12 +382,12 @@ static void iwl_mvm_binding_iterator(void *_data, u8 *mac,
unsigned long *data = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (!mvmvif->phy_ctxt)
if (!mvmvif->deflink.phy_ctxt)
return;
if (vif->type == NL80211_IFTYPE_STATION ||
vif->type == NL80211_IFTYPE_AP)
__set_bit(mvmvif->phy_ctxt->id, data);
__set_bit(mvmvif->deflink.phy_ctxt->id, data);
}
int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm)

View File

@ -150,7 +150,7 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
#endif
for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
if (!mvmvif->queue_params[ac].uapsd)
if (!mvmvif->deflink.queue_params[ac].uapsd)
continue;
if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))
@ -160,7 +160,7 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
cmd->uapsd_ac_flags |= BIT(ac);
/* QNDP TID - the highest TID with no admission control */
if (!tid_found && !mvmvif->queue_params[ac].acm) {
if (!tid_found && !mvmvif->deflink.queue_params[ac].acm) {
tid_found = true;
switch (ac) {
case IEEE80211_AC_VO:
@ -279,18 +279,25 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
{
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
struct ieee80211_bss_conf *link_conf;
bool radar_detect = false;
unsigned int link_id;
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
WARN_ON(!chanctx_conf);
if (chanctx_conf) {
chan = chanctx_conf->def.chan;
radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
}
rcu_read_unlock();
for_each_vif_active_link(vif, link_conf, link_id) {
chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
/* this happens on link switching, just ignore inactive ones */
if (!chanctx_conf)
continue;
radar_detect = !!(chanctx_conf->def.chan->flags &
IEEE80211_CHAN_RADAR);
if (radar_detect)
goto out;
}
out:
rcu_read_unlock();
return radar_detect;
}
@ -509,8 +516,9 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
/* The ap_sta_id is not expected to change during current association
* so no explicit protection is needed
*/
if (mvmvif->ap_sta_id == *ap_sta_id)
memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
if (mvmvif->deflink.ap_sta_id == *ap_sta_id)
memcpy(mvmvif->uapsd_misbehaving_bssid,
vif->bss_conf.bssid,
ETH_ALEN);
}
@ -552,7 +560,7 @@ static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
bool *disable_ps = _data;
if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < NUM_PHY_CTX)
if (iwl_mvm_vif_is_active(mvmvif))
*disable_ps |= mvmvif->ps_disabled;
}
@ -561,11 +569,13 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_power_vifs *power_iterator = _data;
bool active = mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < NUM_PHY_CTX;
bool active;
if (!mvmvif->uploaded)
return;
active = iwl_mvm_vif_is_active(mvmvif);
switch (ieee80211_vif_type_p2p(vif)) {
case NL80211_IFTYPE_P2P_DEVICE:
break;
@ -649,11 +659,12 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
}
if (vifs->bss_active && vifs->p2p_active)
client_same_channel = (bss_mvmvif->phy_ctxt->id ==
p2p_mvmvif->phy_ctxt->id);
client_same_channel =
iwl_mvm_have_links_same_channel(bss_mvmvif, p2p_mvmvif);
if (vifs->bss_active && vifs->ap_active)
ap_same_channel = (bss_mvmvif->phy_ctxt->id ==
ap_mvmvif->phy_ctxt->id);
ap_same_channel =
iwl_mvm_have_links_same_channel(bss_mvmvif, ap_mvmvif);
/* clients are not stand alone: enable PM if DCM */
if (!(client_same_channel || ap_same_channel)) {

View File

@ -0,0 +1,326 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2021 - 2023 Intel Corporation
*/
#include "mvm.h"
#include "iwl-debug.h"
#include <linux/timekeeping.h>
#include <linux/math64.h>
#define IWL_PTP_GP2_WRAP 0x100000000ULL
#define IWL_PTP_WRAP_TIME (3600 * HZ)
/* The scaled_ppm parameter is ppm (parts per million) with a 16-bit fractional
* part, which means that a value of 1 in one of those fields actually means
* 2^-16 ppm, and 2^16=65536 is 1 ppm.
*/
#define SCALE_FACTOR 65536000000ULL
#define IWL_PTP_WRAP_THRESHOLD_USEC (5000)
#define IWL_PTP_GET_CROSS_TS_NUM 5
static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2)
{
/* If the difference is above the threshold, assume it's a wraparound.
* Otherwise assume it's an old read and ignore it.
*/
if (gp2 < mvm->ptp_data.last_gp2 &&
mvm->ptp_data.last_gp2 - gp2 < IWL_PTP_WRAP_THRESHOLD_USEC) {
IWL_DEBUG_INFO(mvm,
"PTP: ignore old read (gp2=%u, last_gp2=%u)\n",
gp2, mvm->ptp_data.last_gp2);
return;
}
if (gp2 < mvm->ptp_data.last_gp2) {
mvm->ptp_data.wrap_counter++;
IWL_DEBUG_INFO(mvm,
"PTP: wraparound detected (new counter=%u)\n",
mvm->ptp_data.wrap_counter);
}
mvm->ptp_data.last_gp2 = gp2;
schedule_delayed_work(&mvm->ptp_data.dwork, IWL_PTP_WRAP_TIME);
}
u64 iwl_mvm_ptp_get_adj_time(struct iwl_mvm *mvm, u64 base_time_ns)
{
struct ptp_data *data = &mvm->ptp_data;
u64 last_gp2_ns = mvm->ptp_data.scale_update_gp2 * NSEC_PER_USEC;
u64 res;
u64 diff;
iwl_mvm_ptp_update_new_read(mvm,
div64_u64(base_time_ns, NSEC_PER_USEC));
IWL_DEBUG_INFO(mvm, "base_time_ns=%llu, wrap_counter=%u\n",
(unsigned long long)base_time_ns, data->wrap_counter);
base_time_ns = base_time_ns +
(data->wrap_counter * IWL_PTP_GP2_WRAP * NSEC_PER_USEC);
/* It is possible that a GP2 timestamp was received from fw before the
* last scale update. Since we don't know how to scale - ignore it.
*/
if (base_time_ns < last_gp2_ns) {
IWL_DEBUG_INFO(mvm, "Time before scale update - ignore\n");
return 0;
}
diff = base_time_ns - last_gp2_ns;
IWL_DEBUG_INFO(mvm, "diff ns=%llu\n", (unsigned long long)diff);
diff = mul_u64_u64_div_u64(diff, data->scaled_freq,
SCALE_FACTOR);
IWL_DEBUG_INFO(mvm, "scaled diff ns=%llu\n", (unsigned long long)diff);
res = data->scale_update_adj_time_ns + data->delta + diff;
IWL_DEBUG_INFO(mvm, "base=%llu delta=%lld adj=%llu\n",
(unsigned long long)base_time_ns, (long long)data->delta,
(unsigned long long)res);
return res;
}
static int
iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time)
{
struct iwl_synced_time_cmd synced_time_cmd = {
.operation = cpu_to_le32(IWL_SYNCED_TIME_OPERATION_READ_BOTH)
};
struct iwl_host_cmd cmd = {
.id = WIDE_ID(DATA_PATH_GROUP, WNM_PLATFORM_PTM_REQUEST_CMD),
.flags = CMD_WANT_SKB,
.data[0] = &synced_time_cmd,
.len[0] = sizeof(synced_time_cmd),
};
struct iwl_synced_time_rsp *resp;
struct iwl_rx_packet *pkt;
int ret;
u64 gp2_10ns;
ret = iwl_mvm_send_cmd(mvm, &cmd);
if (ret)
return ret;
pkt = cmd.resp_pkt;
if (iwl_rx_packet_payload_len(pkt) != sizeof(*resp)) {
IWL_ERR(mvm, "PTP: Invalid command response\n");
iwl_free_resp(&cmd);
return -EIO;
}
resp = (void *)pkt->data;
gp2_10ns = (u64)le32_to_cpu(resp->gp2_timestamp_hi) << 32 |
le32_to_cpu(resp->gp2_timestamp_lo);
*gp2 = div_u64(gp2_10ns, 100);
*sys_time = (u64)le32_to_cpu(resp->platform_timestamp_hi) << 32 |
le32_to_cpu(resp->platform_timestamp_lo);
return ret;
}
static void iwl_mvm_phc_get_crosstimestamp_loop(struct iwl_mvm *mvm,
ktime_t *sys_time, u32 *gp2)
{
u64 diff = 0, new_diff;
u64 tmp_sys_time;
u32 tmp_gp2;
int i;
for (i = 0; i < IWL_PTP_GET_CROSS_TS_NUM; i++) {
iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &tmp_gp2, NULL,
&tmp_sys_time);
new_diff = tmp_sys_time - ((u64)tmp_gp2 * NSEC_PER_USEC);
if (!diff || new_diff < diff) {
*sys_time = tmp_sys_time;
*gp2 = tmp_gp2;
diff = new_diff;
IWL_DEBUG_INFO(mvm, "PTP: new times: gp2=%u sys=%lld\n",
*gp2, *sys_time);
}
}
}
static int
iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp,
struct system_device_crosststamp *xtstamp)
{
struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
ptp_data.ptp_clock_info);
int ret = 0;
/* Raw value read from GP2 register in usec */
u32 gp2;
/* GP2 value in ns*/
s64 gp2_ns;
/* System (wall) time */
ktime_t sys_time;
memset(xtstamp, 0, sizeof(struct system_device_crosststamp));
if (!mvm->ptp_data.ptp_clock) {
IWL_ERR(mvm, "No PHC clock registered\n");
return -ENODEV;
}
mutex_lock(&mvm->mutex);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SYNCED_TIME)) {
ret = iwl_mvm_get_crosstimestamp_fw(mvm, &gp2, &sys_time);
if (ret)
goto out;
} else {
iwl_mvm_phc_get_crosstimestamp_loop(mvm, &sys_time, &gp2);
}
gp2_ns = iwl_mvm_ptp_get_adj_time(mvm, (u64)gp2 * NSEC_PER_USEC);
IWL_INFO(mvm, "Got Sync Time: GP2:%u, last_GP2: %u, GP2_ns: %lld, sys_time: %lld\n",
gp2, mvm->ptp_data.last_gp2, gp2_ns, (s64)sys_time);
/* System monotonic raw time is not used */
xtstamp->device = (ktime_t)gp2_ns;
xtstamp->sys_realtime = sys_time;
out:
mutex_unlock(&mvm->mutex);
return ret;
}
static void iwl_mvm_ptp_work(struct work_struct *wk)
{
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm,
ptp_data.dwork.work);
u32 gp2;
mutex_lock(&mvm->mutex);
gp2 = iwl_mvm_get_systime(mvm);
iwl_mvm_ptp_update_new_read(mvm, gp2);
mutex_unlock(&mvm->mutex);
}
static int iwl_mvm_ptp_gettime(struct ptp_clock_info *ptp,
struct timespec64 *ts)
{
struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
ptp_data.ptp_clock_info);
u64 gp2;
u64 ns;
mutex_lock(&mvm->mutex);
gp2 = iwl_mvm_get_systime(mvm);
ns = iwl_mvm_ptp_get_adj_time(mvm, gp2 * NSEC_PER_USEC);
mutex_unlock(&mvm->mutex);
*ts = ns_to_timespec64(ns);
return 0;
}
static int iwl_mvm_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
ptp_data.ptp_clock_info);
struct ptp_data *data = container_of(ptp, struct ptp_data,
ptp_clock_info);
mutex_lock(&mvm->mutex);
data->delta += delta;
IWL_DEBUG_INFO(mvm, "delta=%lld, new delta=%lld\n", (long long)delta,
(long long)data->delta);
mutex_unlock(&mvm->mutex);
return 0;
}
static int iwl_mvm_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
ptp_data.ptp_clock_info);
struct ptp_data *data = &mvm->ptp_data;
u32 gp2;
mutex_lock(&mvm->mutex);
/* Must call _iwl_mvm_ptp_get_adj_time() before updating
* data->scale_update_gp2 or data->scaled_freq since
* scale_update_adj_time_ns should reflect the previous scaled_freq.
*/
gp2 = iwl_mvm_get_systime(mvm);
data->scale_update_adj_time_ns =
iwl_mvm_ptp_get_adj_time(mvm, gp2 * NSEC_PER_USEC);
data->scale_update_gp2 = gp2;
data->wrap_counter = 0;
data->delta = 0;
data->scaled_freq = SCALE_FACTOR + scaled_ppm;
IWL_DEBUG_INFO(mvm, "adjfine: scaled_ppm=%ld new=%llu\n",
scaled_ppm, (unsigned long long)data->scaled_freq);
mutex_unlock(&mvm->mutex);
return 0;
}
/* iwl_mvm_ptp_init - initialize PTP for devices which support it.
* @mvm: internal mvm structure, see &struct iwl_mvm.
*
* Performs the required steps for enabling PTP support.
*/
void iwl_mvm_ptp_init(struct iwl_mvm *mvm)
{
/* Warn if the interface already has a ptp_clock defined */
if (WARN_ON(mvm->ptp_data.ptp_clock))
return;
mvm->ptp_data.ptp_clock_info.owner = THIS_MODULE;
mvm->ptp_data.ptp_clock_info.max_adj = 0x7fffffff;
mvm->ptp_data.ptp_clock_info.getcrosststamp =
iwl_mvm_phc_get_crosstimestamp;
mvm->ptp_data.ptp_clock_info.adjfine = iwl_mvm_ptp_adjfine;
mvm->ptp_data.ptp_clock_info.adjtime = iwl_mvm_ptp_adjtime;
mvm->ptp_data.ptp_clock_info.gettime64 = iwl_mvm_ptp_gettime;
mvm->ptp_data.scaled_freq = SCALE_FACTOR;
/* Give a short 'friendly name' to identify the PHC clock */
snprintf(mvm->ptp_data.ptp_clock_info.name,
sizeof(mvm->ptp_data.ptp_clock_info.name),
"%s", "iwlwifi-PTP");
INIT_DELAYED_WORK(&mvm->ptp_data.dwork, iwl_mvm_ptp_work);
mvm->ptp_data.ptp_clock =
ptp_clock_register(&mvm->ptp_data.ptp_clock_info, mvm->dev);
if (IS_ERR(mvm->ptp_data.ptp_clock)) {
IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n",
PTR_ERR(mvm->ptp_data.ptp_clock));
mvm->ptp_data.ptp_clock = NULL;
} else if (mvm->ptp_data.ptp_clock) {
IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n",
mvm->ptp_data.ptp_clock_info.name,
ptp_clock_index(mvm->ptp_data.ptp_clock));
}
}
/* iwl_mvm_ptp_remove - disable PTP device.
* @mvm: internal mvm structure, see &struct iwl_mvm.
*
* Disable PTP support.
*/
void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
{
if (mvm->ptp_data.ptp_clock) {
IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n",
mvm->ptp_data.ptp_clock_info.name,
ptp_clock_index(mvm->ptp_data.ptp_clock));
ptp_clock_unregister(mvm->ptp_data.ptp_clock);
mvm->ptp_data.ptp_clock = NULL;
memset(&mvm->ptp_data.ptp_clock_info, 0,
sizeof(mvm->ptp_data.ptp_clock_info));
mvm->ptp_data.last_gp2 = 0;
cancel_delayed_work_sync(&mvm->ptp_data.dwork);
}
}

View File

@ -33,11 +33,11 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
if (vif == data->disabled_vif)
return;
if (!mvmvif->phy_ctxt)
if (!mvmvif->deflink.phy_ctxt)
return;
/* currently, PHY ID == binding ID */
id = mvmvif->phy_ctxt->id;
id = mvmvif->deflink.phy_ctxt->id;
/* need at least one binding per PHY */
BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);
@ -67,9 +67,10 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
}
if (data->colors[id] < 0)
data->colors[id] = mvmvif->phy_ctxt->color;
data->colors[id] = mvmvif->deflink.phy_ctxt->color;
else
WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);
WARN_ON_ONCE(data->colors[id] !=
mvmvif->deflink.phy_ctxt->color);
data->n_interfaces[id]++;
@ -99,7 +100,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
if (!mvmvif->ap_ibss_active)
return;
phy_id = mvmvif->phy_ctxt->id;
phy_id = mvmvif->deflink.phy_ctxt->id;
beacon_int = mvm->noa_vif->bss_conf.beacon_int;
for (i = 0; i < MAX_BINDINGS; i++) {

View File

@ -9,9 +9,9 @@
#include "iwl-op-mode.h"
#include "mvm.h"
static u8 rs_fw_bw_from_sta_bw(const struct ieee80211_sta *sta)
static u8 rs_fw_bw_from_sta_bw(const struct ieee80211_link_sta *link_sta)
{
switch (sta->deflink.bandwidth) {
switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_320:
return IWL_TLC_MNG_CH_WIDTH_320MHZ;
case IEEE80211_STA_RX_BW_160:
@ -38,11 +38,11 @@ static u8 rs_fw_set_active_chains(u8 chains)
return fw_chains;
}
static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
static u8 rs_fw_sgi_cw_support(struct ieee80211_link_sta *link_sta)
{
struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
u8 supp = 0;
if (he_cap->has_he)
@ -61,12 +61,12 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
}
static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband)
{
struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
bool vht_ena = vht_cap->vht_supported;
u16 flags = 0;
@ -132,20 +132,20 @@ int rs_fw_vht_highest_rx_mcs_index(const struct ieee80211_sta_vht_cap *vht_cap,
}
static void
rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
rs_fw_vht_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
const struct ieee80211_sta_vht_cap *vht_cap,
struct iwl_tlc_config_cmd_v4 *cmd)
{
u16 supp;
int i, highest_mcs;
u8 max_nss = sta->deflink.rx_nss;
u8 max_nss = link_sta->rx_nss;
struct ieee80211_vht_cap ieee_vht_cap = {
.vht_cap_info = cpu_to_le32(vht_cap->cap),
.supp_mcs = vht_cap->vht_mcs,
};
/* the station support only a single receive chain */
if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC)
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
max_nss = 1;
for (i = 0; i < max_nss && i < IWL_TLC_NSS_MAX; i++) {
@ -156,7 +156,7 @@ rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
continue;
supp = BIT(highest_mcs + 1) - 1;
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp);
@ -165,7 +165,7 @@ rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
* configuration is supported - only for MCS 0 since we already
* decoded the MCS bits anyway ourselves.
*/
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160 &&
if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160 &&
ieee80211_get_vht_max_nss(&ieee_vht_cap,
IEEE80211_VHT_CHANWIDTH_160MHZ,
0, true, nss) >= nss)
@ -192,11 +192,11 @@ static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs)
}
static void
rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
rs_fw_he_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband,
struct iwl_tlc_config_cmd_v4 *cmd)
{
const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
u16 tx_mcs_80 =
@ -204,10 +204,10 @@ rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
u16 tx_mcs_160 =
le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160);
int i;
u8 nss = sta->deflink.rx_nss;
u8 nss = link_sta->rx_nss;
/* the station support only a single receive chain */
if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC)
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
nss = 1;
for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
@ -282,13 +282,14 @@ rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw,
}
}
static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
struct ieee80211_supported_band *sband,
struct iwl_tlc_config_cmd_v4 *cmd)
static void
rs_fw_eht_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband,
struct iwl_tlc_config_cmd_v4 *cmd)
{
/* peer RX mcs capa */
const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs =
&sta->deflink.eht_cap.eht_mcs_nss_supp;
&link_sta->eht_cap.eht_mcs_nss_supp;
/* our TX mcs capa */
const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs =
&sband->iftype_data->eht_cap.eht_mcs_nss_supp;
@ -298,7 +299,7 @@ static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_tx_20;
/* peer is 20Mhz only */
if (!(sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
if (!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
mcs_rx_20 = eht_rx_mcs->only_20mhz;
} else {
@ -354,25 +355,25 @@ static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
}
/* the station support only a single receive chain */
if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC ||
sta->deflink.rx_nss < 2)
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC ||
link_sta->rx_nss < 2)
memset(cmd->ht_rates[IWL_TLC_NSS_2], 0,
sizeof(cmd->ht_rates[IWL_TLC_NSS_2]));
}
static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
static void rs_fw_set_supp_rates(struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband,
struct iwl_tlc_config_cmd_v4 *cmd)
{
int i;
u16 supp = 0;
unsigned long tmp; /* must be unsigned long for for_each_set_bit */
const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
/* non HT rates */
tmp = sta->deflink.supp_rates[sband->band];
tmp = link_sta->supp_rates[sband->band];
for_each_set_bit(i, &tmp, BITS_PER_LONG)
supp |= BIT(sband->bitrates[i].hw_value);
@ -380,22 +381,22 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
/* HT/VHT rates */
if (sta->deflink.eht_cap.has_eht) {
if (link_sta->eht_cap.has_eht) {
cmd->mode = IWL_TLC_MNG_MODE_EHT;
rs_fw_eht_set_enabled_rates(sta, sband, cmd);
rs_fw_eht_set_enabled_rates(link_sta, sband, cmd);
} else if (he_cap->has_he) {
cmd->mode = IWL_TLC_MNG_MODE_HE;
rs_fw_he_set_enabled_rates(sta, sband, cmd);
rs_fw_he_set_enabled_rates(link_sta, sband, cmd);
} else if (vht_cap->vht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_VHT;
rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
rs_fw_vht_set_enabled_rates(link_sta, vht_cap, cmd);
} else if (ht_cap->ht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_HT;
cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] =
cpu_to_le16(ht_cap->mcs.rx_mask[0]);
/* the station support only a single receive chain */
if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC)
if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
0;
else
@ -410,15 +411,18 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_tlc_update_notif *notif;
struct ieee80211_sta *sta;
struct ieee80211_link_sta *link_sta;
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_link_sta *mvm_link_sta;
struct iwl_lq_sta_rs_fw *lq_sta;
u32 flags;
rcu_read_lock();
notif = (void *)pkt->data;
link_sta = rcu_dereference(mvm->fw_id_to_link_sta[notif->sta_id]);
sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
if (IS_ERR_OR_NULL(sta)) {
if (IS_ERR_OR_NULL(sta) || !link_sta) {
/* can happen in remove station flow where mvm removed internally
* the station before removing from FW
*/
@ -438,7 +442,14 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
flags = le32_to_cpu(notif->flags);
lq_sta = &mvmsta->lq_sta.rs_fw;
mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]);
if (!mvm_link_sta) {
IWL_DEBUG_RATE(mvm,
"Invalid mvmsta RCU pointer for link (%d) of sta id (%d) in TLC notification\n",
link_sta->link_id, notif->sta_id);
goto out;
}
lq_sta = &mvm_link_sta->lq_sta.rs_fw;
if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
char pretty_rate[100];
@ -465,9 +476,9 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
u16 size = le32_to_cpu(notif->amsdu_size);
int i;
if (sta->deflink.agg.max_amsdu_len < size) {
if (link_sta->agg.max_amsdu_len < size) {
/*
* In debug sta->deflink.agg.max_amsdu_len < size
* In debug link_sta->agg.max_amsdu_len < size
* so also check with orig_amsdu_len which holds the
* original data before debugfs changed the value
*/
@ -477,18 +488,18 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled);
mvmsta->max_amsdu_len = size;
sta->deflink.agg.max_rc_amsdu_len = mvmsta->max_amsdu_len;
link_sta->agg.max_rc_amsdu_len = mvmsta->max_amsdu_len;
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
if (mvmsta->amsdu_enabled & BIT(i))
sta->deflink.agg.max_tid_amsdu_len[i] =
link_sta->agg.max_tid_amsdu_len[i] =
iwl_mvm_max_amsdu_size(mvm, sta, i);
else
/*
* Not so elegant, but this will effectively
* prevent AMSDU on this TID
*/
sta->deflink.agg.max_tid_amsdu_len[i] = 1;
link_sta->agg.max_tid_amsdu_len[i] = 1;
}
IWL_DEBUG_RATE(mvm,
@ -500,14 +511,18 @@ out:
rcu_read_unlock();
}
u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
if (mvmsta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
switch (le16_get_bits(sta->deflink.he_6ghz_capa.capa,
if (WARN_ON_ONCE(!link_conf->chandef.chan))
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) {
switch (le16_get_bits(link_sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
@ -543,33 +558,50 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
}
void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update)
{
struct ieee80211_hw *hw = mvm->hw;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta);
u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta, link_conf, link_sta);
struct iwl_mvm_link_sta *mvm_link_sta;
struct iwl_lq_sta_rs_fw *lq_sta;
struct iwl_tlc_config_cmd_v4 cfg_cmd = {
.sta_id = mvmsta->sta_id,
.max_ch_width = update ?
rs_fw_bw_from_sta_bw(sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ,
.flags = cpu_to_le16(rs_fw_get_config_flags(mvm, sta, sband)),
rs_fw_bw_from_sta_bw(link_sta) :
IWL_TLC_MNG_CH_WIDTH_20MHZ,
.flags = cpu_to_le16(rs_fw_get_config_flags(mvm, link_sta,
sband)),
.chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
.sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),
.sgi_ch_width_supp = rs_fw_sgi_cw_support(link_sta),
.max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
cpu_to_le16(max_amsdu_len) : 0,
};
int ret;
unsigned int link_id = link_conf->link_id;
int cmd_ver;
int ret;
rcu_read_lock();
mvm_link_sta = rcu_dereference(mvmsta->link[link_id]);
if (WARN_ON_ONCE(!mvm_link_sta)) {
rcu_read_unlock();
return;
}
cfg_cmd.sta_id = mvm_link_sta->sta_id;
lq_sta = &mvm_link_sta->lq_sta.rs_fw;
memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
rcu_read_unlock();
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm);
#endif
rs_fw_set_supp_rates(sta, sband, &cfg_cmd);
rs_fw_set_supp_rates(link_sta, sband, &cfg_cmd);
/*
* since TLC offload works with one mode we can assume
@ -641,18 +673,30 @@ int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta)
{
struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
unsigned int link_id;
IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
lq_sta->pers.drv = mvm;
lq_sta->pers.sta_id = mvmsta->sta_id;
lq_sta->pers.chains = 0;
memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
lq_sta->pers.last_rssi = S8_MIN;
lq_sta->last_rate_n_flags = 0;
for (link_id = 0; link_id < ARRAY_SIZE(mvmsta->link); link_id++) {
struct iwl_lq_sta_rs_fw *lq_sta;
struct iwl_mvm_link_sta *link =
rcu_dereference_protected(mvmsta->link[link_id],
lockdep_is_held(&mvm->mutex));
if (!link)
continue;
lq_sta = &link->lq_sta.rs_fw;
lq_sta->pers.drv = mvm;
lq_sta->pers.sta_id = link->sta_id;
lq_sta->pers.chains = 0;
memset(lq_sta->pers.chain_signal, 0,
sizeof(lq_sta->pers.chain_signal));
lq_sta->pers.last_rssi = S8_MIN;
lq_sta->last_rate_n_flags = 0;
#ifdef CONFIG_MAC80211_DEBUGFS
lq_sta->pers.dbg_fixed_rate = 0;
lq_sta->pers.dbg_fixed_rate = 0;
#endif
}
}

View File

@ -512,10 +512,10 @@ static char *rs_pretty_rate(const struct rs_rate *rate)
(rate->index <= IWL_RATE_MCS_9_INDEX))
rate_str = ht_vht_rates[rate->index];
else
rate_str = "BAD_RATE";
rate_str = NULL;
sprintf(buf, "(%s|%s|%s)", rs_pretty_lq_type(rate->type),
iwl_rs_pretty_ant(rate->ant), rate_str);
iwl_rs_pretty_ant(rate->ant), rate_str ?: "BAD_RATE");
return buf;
}
@ -754,7 +754,7 @@ static int rs_collect_tlc_data(struct iwl_mvm *mvm,
return -EINVAL;
if (tbl->column != RS_COLUMN_INVALID) {
struct lq_sta_pers *pers = &mvmsta->lq_sta.rs_drv.pers;
struct lq_sta_pers *pers = &mvmsta->deflink.lq_sta.rs_drv.pers;
pers->tx_stats[tbl->column][scale_index].total += attempts;
pers->tx_stats[tbl->column][scale_index].success += successes;
@ -1487,9 +1487,11 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum rs_action scale_action)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_bss_conf *bss_conf = &mvmsta->vif->bss_conf;
int i;
sta->deflink.agg.max_amsdu_len = rs_fw_get_max_amsdu_len(sta);
sta->deflink.agg.max_amsdu_len =
rs_fw_get_max_amsdu_len(sta, bss_conf, &sta->deflink);
/*
* In case TLC offload is not active amsdu_enabled is either 0xFFFF
@ -1502,7 +1504,7 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
else
mvmsta->amsdu_enabled = 0xFFFF;
if (mvmsta->vif->bss_conf.he_support &&
if (bss_conf->he_support &&
!iwlwifi_mod_params.disable_11ax)
mvmsta->max_amsdu_len = sta->deflink.agg.max_amsdu_len;
else
@ -2599,7 +2601,7 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta,
struct ieee80211_rx_status *rx_status)
{
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
struct iwl_lq_sta *lq_sta = &mvmsta->deflink.lq_sta.rs_drv;
int i;
lq_sta->pers.chains = rx_status->chains;
@ -2682,7 +2684,6 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
/* if vif isn't initialized mvm doesn't know about
* this station, so don't do anything with the it
*/
sta = NULL;
mvm_sta = NULL;
}
@ -2712,7 +2713,7 @@ static void *rs_drv_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate;
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
struct iwl_lq_sta *lq_sta = &mvmsta->deflink.lq_sta.rs_drv;
IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
@ -2918,18 +2919,18 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
struct iwl_lq_sta *lq_sta = &mvmsta->deflink.lq_sta.rs_drv;
struct ieee80211_supported_band *sband;
unsigned long supp; /* must be unsigned long for for_each_set_bit */
lockdep_assert_held(&mvmsta->lq_sta.rs_drv.pers.lock);
lockdep_assert_held(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
/* clear all non-persistent lq data */
memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
sband = hw->wiphy->bands[band];
lq_sta->lq.sta_id = mvmsta->sta_id;
lq_sta->lq.sta_id = mvmsta->deflink.sta_id;
mvmsta->amsdu_enabled = 0;
mvmsta->max_amsdu_len = sta->cur->max_amsdu_len;
@ -2941,7 +2942,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
IWL_DEBUG_RATE(mvm,
"LQ: *** rate scale station global init for station %d ***\n",
mvmsta->sta_id);
mvmsta->deflink.sta_id);
/* TODO: what is a good starting rate for STA? About middle? Maybe not
* the lowest or the highest rate.. Could consider using RSSI from
* previous packets? Need to have IEEE 802.1X auth succeed immediately
@ -3003,17 +3004,20 @@ static void rs_drv_rate_update(void *mvm_r,
void *priv_sta, u32 changed)
{
struct iwl_op_mode *op_mode = mvm_r;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
u8 tid;
if (!iwl_mvm_sta_from_mac80211(sta)->vif)
if (!mvmsta->vif)
return;
/* Stop any ongoing aggregations as rs starts off assuming no agg */
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
ieee80211_stop_tx_ba_session(sta, tid);
iwl_mvm_rs_rate_init(mvm, sta, sband->band, true);
iwl_mvm_rs_rate_init(mvm, sta,
&mvmsta->vif->bss_conf, &sta->deflink,
sband->band, true);
}
static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
@ -3033,7 +3037,7 @@ static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info);
u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta.rs_drv;
struct iwl_lq_sta *lq_sta = &mvmsta->deflink.lq_sta.rs_drv;
if (!lq_sta->pers.drv) {
IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
@ -3257,11 +3261,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* If it's locked we are in middle of init flow
* just wait for next tx status to update the lq_sta data
*/
if (!spin_trylock(&mvmsta->lq_sta.rs_drv.pers.lock))
if (!spin_trylock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock))
return;
__iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp);
spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock);
spin_unlock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
}
#ifdef CONFIG_MAC80211_DEBUGFS
@ -3437,7 +3441,7 @@ static void rs_bfer_active_iter(void *_data,
{
struct rs_bfer_active_iter_data *data = _data;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.rs_drv.lq;
struct iwl_lq_cmd *lq_cmd = &mvmsta->deflink.lq_sta.rs_drv.lq;
u32 ss_params = le32_to_cpu(lq_cmd->ss_params);
if (sta == data->exclude_sta)
@ -3468,7 +3472,8 @@ static int rs_bfer_priority(struct iwl_mvm_sta *sta)
prio = 1;
break;
default:
WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id);
WARN_ONCE(true, "viftype %d sta_id %d", viftype,
sta->deflink.sta_id);
prio = -1;
}
@ -3545,12 +3550,12 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
}
IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n",
bfer_mvmsta->sta_id);
bfer_mvmsta->deflink.sta_id);
/* Disallow BFER on another STA if active and we're a higher priority */
if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) {
struct iwl_lq_cmd *bfersta_lq_cmd =
&bfer_mvmsta->lq_sta.rs_drv.lq;
&bfer_mvmsta->deflink.lq_sta.rs_drv.lq;
u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params);
bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED;
@ -3560,7 +3565,7 @@ static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
ss_params |= LQ_SS_BFER_ALLOWED;
IWL_DEBUG_RATE(mvm,
"Lower priority BFER sta found (%d). Switch BFER\n",
bfer_mvmsta->sta_id);
bfer_mvmsta->deflink.sta_id);
}
out:
lq_cmd->ss_params = cpu_to_le32(ss_params);
@ -3602,7 +3607,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant;
lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
lq_cmd->agg_frame_cnt_limit = lq_sta->pers.max_agg_bufsize;
/*
* In case of low latency, tell the firmware to leave a frame in the
@ -3745,7 +3750,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_mvm_sta *mvmsta =
container_of(lq_sta, struct iwl_mvm_sta, lq_sta.rs_drv);
container_of(lq_sta, struct iwl_mvm_sta, deflink.lq_sta.rs_drv);
struct iwl_mvm *mvm;
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
struct rs_rate *rate = &tbl->rate;
@ -4046,7 +4051,8 @@ static void rs_drv_add_sta_debugfs(void *mvm, void *priv_sta,
struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_mvm_sta *mvmsta;
mvmsta = container_of(lq_sta, struct iwl_mvm_sta, lq_sta.rs_drv);
mvmsta = container_of(lq_sta, struct iwl_mvm_sta,
deflink.lq_sta.rs_drv);
if (!mvmsta->vif)
return;
@ -4096,16 +4102,18 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
};
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update)
{
if (iwl_mvm_has_tlc_offload(mvm)) {
rs_fw_rate_init(mvm, sta, band, update);
rs_fw_rate_init(mvm, sta, link_conf, link_sta, band, update);
} else {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
spin_lock(&mvmsta->lq_sta.rs_drv.pers.lock);
spin_lock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
rs_drv_rate_init(mvm, sta, band);
spin_unlock(&mvmsta->lq_sta.rs_drv.pers.lock);
spin_unlock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
}
}
@ -4122,7 +4130,7 @@ void iwl_mvm_rate_control_unregister(void)
static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool enable)
{
struct iwl_lq_cmd *lq = &mvmsta->lq_sta.rs_drv.lq;
struct iwl_lq_cmd *lq = &mvmsta->deflink.lq_sta.rs_drv.lq;
lockdep_assert_held(&mvm->mutex);

View File

@ -1,10 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
* Copyright(c) 2018 - 2019 Intel Corporation
* Copyright (C) 2003 - 2014, 2018 - 2022 Intel Corporation
*****************************************************************************/
#ifndef __rs_h__
@ -204,6 +203,7 @@ struct rs_rate {
/**
* struct iwl_lq_sta_rs_fw - rate and related statistics for RS in FW
* @last_rate_n_flags: last rate reported by FW
* @max_agg_bufsize: the maximal size of the AGG buffer for this station
* @sta_id: the id of the station
#ifdef CONFIG_MAC80211_DEBUGFS
* @dbg_fixed_rate: for debug, use fixed rate if not 0
@ -353,6 +353,7 @@ struct iwl_lq_sta {
/* last tx rate_n_flags */
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
u8 is_agg;
@ -371,6 +372,7 @@ struct iwl_lq_sta {
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
s8 last_rssi;
u16 max_agg_bufsize;
struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
struct iwl_mvm *drv;
spinlock_t lock; /* for races in reinit/update table */
@ -393,7 +395,9 @@ struct iwl_lq_sta {
/* Initialize station's rate scaling information after adding station */
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum nl80211_band band, bool init);
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update);
/* Notify RS about Tx status */
void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
@ -430,11 +434,15 @@ void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm);
void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta);
void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update);
int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool enable);
void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta);
u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta);
#endif /* __rs__ */

View File

@ -237,11 +237,11 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
if (mdata->opened_rx_ba_sessions ||
mdata->uapsd_nonagg_detect.detected ||
(!mvmvif->queue_params[IEEE80211_AC_VO].uapsd &&
!mvmvif->queue_params[IEEE80211_AC_VI].uapsd &&
!mvmvif->queue_params[IEEE80211_AC_BE].uapsd &&
!mvmvif->queue_params[IEEE80211_AC_BK].uapsd) ||
mvmsta->sta_id != mvmvif->ap_sta_id)
(!mvmvif->deflink.queue_params[IEEE80211_AC_VO].uapsd &&
!mvmvif->deflink.queue_params[IEEE80211_AC_VI].uapsd &&
!mvmvif->deflink.queue_params[IEEE80211_AC_BE].uapsd &&
!mvmvif->deflink.queue_params[IEEE80211_AC_BK].uapsd) ||
mvmsta->deflink.sta_id != mvmvif->deflink.ap_sta_id)
return;
if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
@ -628,9 +628,9 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
* data copied into the "data" struct, but rather the data from
* the notification directly.
*/
mvmvif->beacon_stats.num_beacons =
mvmvif->deflink.beacon_stats.num_beacons =
le32_to_cpu(data->beacon_counter[vif_id]);
mvmvif->beacon_stats.avg_signal =
mvmvif->deflink.beacon_stats.avg_signal =
-data->beacon_average_energy[vif_id];
if (mvmvif->id != id)
@ -643,8 +643,8 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
* request to clear statistics
*/
if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
mvmvif->beacon_stats.accu_num_beacons +=
mvmvif->beacon_stats.num_beacons;
mvmvif->deflink.beacon_stats.accu_num_beacons +=
mvmvif->deflink.beacon_stats.num_beacons;
iwl_mvm_update_vif_sig(vif, sig);
}
@ -666,17 +666,17 @@ static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac,
mac_stats = &data->per_mac_stats[vif_id];
mvmvif->beacon_stats.num_beacons =
mvmvif->deflink.beacon_stats.num_beacons =
le32_to_cpu(mac_stats->beacon_counter);
mvmvif->beacon_stats.avg_signal =
mvmvif->deflink.beacon_stats.avg_signal =
-le32_to_cpu(mac_stats->beacon_average_energy);
/* make sure that beacon statistics don't go backwards with TCM
* request to clear statistics
*/
if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)
mvmvif->beacon_stats.accu_num_beacons +=
mvmvif->beacon_stats.num_beacons;
mvmvif->deflink.beacon_stats.accu_num_beacons +=
mvmvif->deflink.beacon_stats.num_beacons;
sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy);
iwl_mvm_update_vif_sig(vif, sig);
@ -712,14 +712,14 @@ static void iwl_mvm_stats_energy_iter(void *_data,
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
u8 *energy = _data;
u32 sta_id = mvmsta->sta_id;
u32 sta_id = mvmsta->deflink.sta_id;
if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT_MAX, "sta_id %d >= %d",
sta_id, IWL_MVM_STATION_COUNT_MAX))
return;
if (energy[sta_id])
mvmsta->avg_energy = energy[sta_id];
mvmsta->deflink.avg_energy = energy[sta_id];
}

View File

@ -9,6 +9,7 @@
#include "iwl-trans.h"
#include "mvm.h"
#include "fw-api.h"
#include "time-sync.h"
static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
int queue, struct ieee80211_sta *sta)
@ -252,12 +253,22 @@ static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
struct napi_struct *napi,
struct sk_buff *skb, int queue,
struct ieee80211_sta *sta)
struct ieee80211_sta *sta,
struct ieee80211_link_sta *link_sta)
{
if (iwl_mvm_check_pn(mvm, skb, queue, sta))
if (unlikely(iwl_mvm_check_pn(mvm, skb, queue, sta))) {
kfree_skb(skb);
else
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
return;
}
if (sta && sta->valid_links && link_sta) {
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
rx_status->link_valid = 1;
rx_status->link_id = link_sta->link_id;
}
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
}
static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
@ -630,7 +641,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
while ((skb = __skb_dequeue(skb_list))) {
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
reorder_buf->queue,
sta);
sta, NULL /* FIXME */);
reorder_buf->num_stored--;
}
}
@ -978,9 +989,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
return false;
}
if (WARN(tid != baid_data->tid || mvm_sta->sta_id != baid_data->sta_id,
if (WARN(tid != baid_data->tid ||
mvm_sta->deflink.sta_id != baid_data->sta_id,
"baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n",
baid, baid_data->sta_id, baid_data->tid, mvm_sta->sta_id,
baid, baid_data->sta_id, baid_data->tid, mvm_sta->deflink.sta_id,
tid))
return false;
@ -2296,6 +2308,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
u32 len;
u32 pkt_len = iwl_rx_packet_payload_len(pkt);
struct ieee80211_sta *sta = NULL;
struct ieee80211_link_sta *link_sta = NULL;
struct sk_buff *skb;
u8 crypt_len = 0;
size_t desc_size;
@ -2452,6 +2465,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
if (IS_ERR(sta))
sta = NULL;
link_sta = rcu_dereference(mvm->fw_id_to_link_sta[id]);
}
} else if (!is_multicast_ether_addr(hdr->addr2)) {
/*
@ -2585,9 +2599,11 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
goto out;
}
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue,
sta);
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc) &&
likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2)))
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta,
link_sta);
out:
rcu_read_unlock();
}

View File

@ -193,8 +193,9 @@ static void iwl_mvm_scan_iterator(void *_data, u8 *mac,
struct iwl_mvm_scan_iter_data *data = _data;
struct iwl_mvm_vif *curr_mvmvif;
if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
mvmvif->phy_ctxt->id < NUM_PHY_CTX)
if (vif->type != NL80211_IFTYPE_P2P_DEVICE &&
mvmvif->deflink.phy_ctxt &&
mvmvif->deflink.phy_ctxt->id < NUM_PHY_CTX)
data->global_cnt += 1;
if (!data->current_vif || vif == data->current_vif)
@ -203,8 +204,8 @@ static void iwl_mvm_scan_iterator(void *_data, u8 *mac,
curr_mvmvif = iwl_mvm_vif_from_mac80211(data->current_vif);
if (vif->type == NL80211_IFTYPE_AP && vif->p2p &&
mvmvif->phy_ctxt && curr_mvmvif->phy_ctxt &&
mvmvif->phy_ctxt->id != curr_mvmvif->phy_ctxt->id)
mvmvif->deflink.phy_ctxt && curr_mvmvif->deflink.phy_ctxt &&
mvmvif->deflink.phy_ctxt->id != curr_mvmvif->deflink.phy_ctxt->id)
data->is_dcm_with_p2p_go = true;
}
@ -2676,11 +2677,23 @@ static void iwl_mvm_scan_respect_p2p_go_iter(void *_data, u8 *mac,
if (vif == data->current_vif)
return;
if (vif->type == NL80211_IFTYPE_AP && vif->p2p &&
mvmvif->phy_ctxt->id < NUM_PHY_CTX &&
(data->band == NUM_NL80211_BANDS ||
mvmvif->phy_ctxt->channel->band == data->band))
data->p2p_go = true;
if (vif->type == NL80211_IFTYPE_AP && vif->p2p) {
u32 link_id;
for (link_id = 0;
link_id < ARRAY_SIZE(mvmvif->link);
link_id++) {
struct iwl_mvm_vif_link_info *link =
mvmvif->link[link_id];
if (link && link->phy_ctxt->id < NUM_PHY_CTX &&
(data->band == NUM_NL80211_BANDS ||
link->phy_ctxt->channel->band == data->band)) {
data->p2p_go = true;
break;
}
}
}
}
static bool _iwl_mvm_get_respect_p2p_go(struct iwl_mvm *mvm,
@ -2980,7 +2993,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
.scan_start_tsf = mvm->scan_start,
};
memcpy(info.tsf_bssid, mvm->scan_vif->bssid, ETH_ALEN);
memcpy(info.tsf_bssid, mvm->scan_vif->deflink.bssid, ETH_ALEN);
ieee80211_scan_completed(mvm->hw, &info);
mvm->scan_vif = NULL;
cancel_delayed_work(&mvm->scan_timeout_dwork);

View File

@ -23,14 +23,14 @@ static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
struct iwl_mvm_active_iface_iterator_data *data = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
if (vif == data->ignore_vif || !mvmvif->deflink.phy_ctxt ||
vif->type == NL80211_IFTYPE_P2P_DEVICE)
return;
data->num_active_macs++;
if (vif->type == NL80211_IFTYPE_STATION) {
data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
data->sta_vif_ap_sta_id = mvmvif->deflink.ap_sta_id;
if (vif->cfg.assoc)
data->sta_vif_state = SF_FULL_ON;
else
@ -98,6 +98,10 @@ static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
struct ieee80211_sta *sta)
{
int i, j, watermark;
u8 max_rx_nss = 0;
bool is_legacy = true;
struct ieee80211_link_sta *link_sta;
unsigned int link_id;
sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
@ -106,10 +110,25 @@ static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
* capabilities of the AP station, and choose the watermark accordingly.
*/
if (sta) {
if (sta->deflink.ht_cap.ht_supported ||
sta->deflink.vht_cap.vht_supported ||
sta->deflink.he_cap.has_he) {
switch (sta->deflink.rx_nss) {
/* find the maximal NSS number among all links (if relevant) */
rcu_read_lock();
for (link_id = 0; link_id < ARRAY_SIZE(sta->link); link_id++) {
link_sta = rcu_dereference(sta->link[link_id]);
if (!link_sta)
continue;
if (link_sta->ht_cap.ht_supported ||
link_sta->vht_cap.vht_supported ||
link_sta->eht_cap.has_eht ||
link_sta->he_cap.has_he) {
is_legacy = false;
max_rx_nss = max(max_rx_nss, link_sta->rx_nss);
}
}
rcu_read_unlock();
if (!is_legacy) {
switch (max_rx_nss) {
case 1:
watermark = SF_W_MARK_SISO;
break;
@ -151,7 +170,6 @@ static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm,
memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def,
sizeof(sf_full_timeout_def));
}
}
static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
@ -264,7 +282,7 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
} else if (changed_vif->cfg.assoc &&
changed_vif->bss_conf.dtim_period) {
mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
sta_id = mvmvif->ap_sta_id;
sta_id = mvmvif->deflink.ap_sta_id;
new_state = SF_FULL_ON;
} else {
new_state = SF_INIT_OFF;
@ -275,5 +293,9 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
/* If there are multiple active macs - change to SF_UNINIT */
new_state = SF_UNINIT;
}
/* For MLO it's ok to use deflink->sta_id as it's needed only to get
* a pointer to mac80211 sta
*/
return iwl_mvm_sf_config(mvm, sta_id, new_state);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2016 Intel Deutschland GmbH
*/
@ -330,14 +330,31 @@ struct iwl_mvm_rxq_dup_data {
u8 last_sub_frame[IWL_MAX_TID_COUNT + 1];
} ____cacheline_aligned_in_smp;
/**
* struct iwl_mvm_link_sta - link specific parameters of a station
* @rcu_head: used for freeing the data
* @sta_id: the index of the station in the fw
* @lq_sta: holds rate scaling data, either for the case when RS is done in
* the driver - %rs_drv or in the FW - %rs_fw.
* @avg_energy: energy as reported by FW statistics notification
*/
struct iwl_mvm_link_sta {
struct rcu_head rcu_head;
u32 sta_id;
union {
struct iwl_lq_sta_rs_fw rs_fw;
struct iwl_lq_sta rs_drv;
} lq_sta;
u8 avg_energy;
};
/**
* struct iwl_mvm_sta - representation of a station in the driver
* @sta_id: the index of the station in the fw (will be replaced by id_n_color)
* @tfd_queue_msk: the tfd queues used by the station
* @mac_id_n_color: the MAC context this station is linked to
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid.
* @max_agg_bufsize: the maximal size of the AGG buffer for this station
* @sta_type: station type
* @sta_state: station state according to enum %ieee80211_sta_state
* @bt_reduced_txpower: is reduced tx power enabled for this station
@ -347,8 +364,6 @@ struct iwl_mvm_rxq_dup_data {
* and from Tx response flow, it needs a spinlock.
* @tid_data: per tid data + mgmt. Look at %iwl_mvm_tid_data.
* @tid_to_baid: a simple map of TID to baid
* @lq_sta: holds rate scaling data, either for the case when RS is done in
* the driver - %rs_drv or in the FW - %rs_fw.
* @reserved_queue: the queue reserved for this STA for DQA purposes
* Every STA has is given one reserved queue to allow it to operate. If no
* such queue can be guaranteed, the STA addition will fail.
@ -374,6 +389,12 @@ struct iwl_mvm_rxq_dup_data {
* used during connection establishment (e.g. for the 4 way handshake
* exchange).
* @pairwise_cipher: used to feed iwlmei upon authorization
* @deflink: the default link station, for non-MLO STA, all link specific data
* is accessed via deflink (or link[0]). For MLO, it will hold data of the
* first added link STA.
* @link: per link sta entries. For non-MLO only link[0] holds data. For MLO,
* link[0] points to deflink and link[link_id] is allocated when new link
* sta is added.
*
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
* in the structure for use by driver. This structure is placed in that
@ -381,22 +402,16 @@ struct iwl_mvm_rxq_dup_data {
*
*/
struct iwl_mvm_sta {
u32 sta_id;
u32 tfd_queue_msk;
u32 mac_id_n_color;
u16 tid_disable_agg;
u16 max_agg_bufsize;
enum iwl_sta_type sta_type;
u8 sta_type;
enum ieee80211_sta_state sta_state;
bool bt_reduced_txpower;
bool next_status_eosp;
spinlock_t lock;
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT + 1];
u8 tid_to_baid[IWL_MAX_TID_COUNT];
union {
struct iwl_lq_sta_rs_fw rs_fw;
struct iwl_lq_sta rs_drv;
} lq_sta;
struct ieee80211_vif *vif;
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
struct iwl_mvm_rxq_dup_data *dup_data;
@ -414,9 +429,11 @@ struct iwl_mvm_sta {
bool sleeping;
u8 agg_tids;
u8 sleep_tx_count;
u8 avg_energy;
u8 tx_ant;
u32 pairwise_cipher;
struct iwl_mvm_link_sta deflink;
struct iwl_mvm_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
};
u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data);
@ -436,7 +453,7 @@ iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta)
*/
struct iwl_mvm_int_sta {
u32 sta_id;
enum iwl_sta_type type;
u8 type;
u32 tfd_queue_msk;
};
@ -452,6 +469,9 @@ struct iwl_mvm_int_sta {
*/
int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
bool update, unsigned int flags);
int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype);
int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, int sta_id, u8 sta_type);
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@ -463,8 +483,13 @@ static inline int iwl_mvm_update_sta(struct iwl_mvm *mvm,
return iwl_mvm_sta_send_to_fw(mvm, sta, true, 0);
}
void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta);
bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_link_sta *link_sta, int *ret);
int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@ -510,6 +535,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id);
int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm);
int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_add_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@ -519,7 +546,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *sta,
u32 qmask, enum nl80211_iftype iftype,
enum iwl_sta_type type);
u8 type);
void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta);
int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@ -543,6 +570,7 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif,
bool disable);
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@ -551,4 +579,78 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 mac_id);
/* Queues */
int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
u8 sta_id, u8 tid, unsigned int timeout);
/* Sta state */
/**
* struct iwl_mvm_sta_state_ops - callbacks for the sta_state() ops
*
* Since the only difference between both MLD and
* non-MLD versions of sta_state() is these function calls,
* each version will send its specific function calls to
* %iwl_mvm_mac_sta_state_common().
*
* @add_sta: pointer to the function that adds a new sta
* @update_sta: pointer to the function that updates a sta
* @rm_sta: pointer to the functions that removes a sta
* @mac_ctxt_changed: pointer to the function that handles a change in mac ctxt
*/
struct iwl_mvm_sta_state_ops {
int (*add_sta)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int (*update_sta)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int (*rm_sta)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int (*mac_ctxt_changed)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool force_assoc_off);
};
int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state,
struct iwl_mvm_sta_state_ops *callbacks);
/* New MLD STA related APIs */
/* STA */
int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mld_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mld_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id);
int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_mld_rm_aux_sta(struct iwl_mvm *mvm);
int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id);
int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u16 old_links, u16 new_links);
/* Queues */
void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif,
bool disable);
void iwl_mvm_mld_sta_modify_disable_tx(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta,
bool disable);
void iwl_mvm_mld_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
bool disable);
#endif /* __sta_h__ */

View File

@ -369,7 +369,7 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
goto out;
}
mvmsta = iwl_mvm_sta_from_mac80211(sta);
cmd.peer_sta_id = cpu_to_le32(mvmsta->sta_id);
cmd.peer_sta_id = cpu_to_le32(mvmsta->deflink.sta_id);
if (!chandef) {
if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT &&
@ -414,7 +414,7 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
}
iwl_mvm_set_tx_cmd(mvm, skb, &tail->frame.tx_cmd, info,
mvmsta->sta_id);
mvmsta->deflink.sta_id);
iwl_mvm_set_tx_cmd_rate(mvm, &tail->frame.tx_cmd, info, sta,
hdr->frame_control);
@ -431,7 +431,7 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
/* channel switch has started, update state */
if (type != TDLS_MOVE_CH) {
mvm->tdls_cs.cur_sta_id = mvmsta->sta_id;
mvm->tdls_cs.cur_sta_id = mvmsta->deflink.sta_id;
iwl_mvm_tdls_update_cs_state(mvm,
type == TDLS_SEND_CHAN_SW_REQ ?
IWL_MVM_TDLS_SW_REQ_SENT :
@ -541,7 +541,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw,
}
mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvm->tdls_cs.peer.sta_id = mvmsta->sta_id;
mvm->tdls_cs.peer.sta_id = mvmsta->deflink.sta_id;
mvm->tdls_cs.peer.chandef = *chandef;
mvm->tdls_cs.peer.initiator = sta->tdls_initiator;
mvm->tdls_cs.peer.op_class = oper_class;

View File

@ -79,7 +79,8 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
if (!WARN_ON(!mvm->p2p_device_vif)) {
mvmvif = iwl_mvm_vif_from_mac80211(mvm->p2p_device_vif);
iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true);
iwl_mvm_flush_sta(mvm, &mvmvif->deflink.bcast_sta,
true);
}
}
@ -94,6 +95,11 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
/* do the same in case of hot spot 2.0 */
iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true);
if (mvm->mld_api_is_used) {
iwl_mvm_mld_rm_aux_sta(mvm);
goto out_unlock;
}
/* In newer version of this command an aux station is added only
* in cases of dedicated tx queue and need to be removed in end
* of use */
@ -101,6 +107,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
iwl_mvm_rm_aux_sta(mvm);
}
out_unlock:
mutex_unlock(&mvm->mutex);
}
@ -170,7 +177,8 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta;
rcu_read_lock();
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id);
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm,
mvmvif->deflink.ap_sta_id);
if (!WARN_ON(!mvmsta))
iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
rcu_read_unlock();

View File

@ -0,0 +1,173 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2022 Intel Corporation
*/
#include "mvm.h"
#include "time-sync.h"
#include <linux/ieee80211.h>
void iwl_mvm_init_time_sync(struct iwl_time_sync_data *data)
{
skb_queue_head_init(&data->frame_list);
}
static bool iwl_mvm_is_skb_match(struct sk_buff *skb, u8 *addr, u8 dialog_token)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
u8 skb_dialog_token;
if (ieee80211_is_timing_measurement(skb))
skb_dialog_token = mgmt->u.action.u.wnm_timing_msr.dialog_token;
else
skb_dialog_token = mgmt->u.action.u.ftm.dialog_token;
if ((ether_addr_equal(mgmt->sa, addr) ||
ether_addr_equal(mgmt->da, addr)) &&
skb_dialog_token == dialog_token)
return true;
return false;
}
static struct sk_buff *iwl_mvm_time_sync_find_skb(struct iwl_mvm *mvm, u8 *addr,
u8 dialog_token)
{
struct sk_buff *skb;
/* The queue is expected to have only one SKB. If there are other SKBs
* in the queue, they did not get a time sync notification and are
* probably obsolete by now, so drop them.
*/
while ((skb = skb_dequeue(&mvm->time_sync.frame_list))) {
if (iwl_mvm_is_skb_match(skb, addr, dialog_token))
break;
kfree_skb(skb);
skb = NULL;
}
return skb;
}
static u64 iwl_mvm_get_64_bit(__le32 high, __le32 low)
{
return ((u64)le32_to_cpu(high) << 32) | le32_to_cpu(low);
}
void iwl_mvm_time_sync_msmt_event(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_time_msmt_notify *notif = (void *)pkt->data;
struct ieee80211_rx_status *rx_status;
struct skb_shared_hwtstamps *shwt;
u64 ts_10ns;
struct sk_buff *skb =
iwl_mvm_time_sync_find_skb(mvm, notif->peer_addr,
le32_to_cpu(notif->dialog_token));
u64 adj_time;
if (!skb) {
IWL_DEBUG_INFO(mvm, "Time sync event but no pending skb\n");
return;
}
ts_10ns = iwl_mvm_get_64_bit(notif->t2_hi, notif->t2_lo);
adj_time = iwl_mvm_ptp_get_adj_time(mvm, ts_10ns * 10);
shwt = skb_hwtstamps(skb);
shwt->hwtstamp = ktime_set(0, adj_time);
ts_10ns = iwl_mvm_get_64_bit(notif->t3_hi, notif->t3_lo);
adj_time = iwl_mvm_ptp_get_adj_time(mvm, ts_10ns * 10);
rx_status = IEEE80211_SKB_RXCB(skb);
rx_status->ack_tx_hwtstamp = ktime_set(0, adj_time);
IWL_DEBUG_INFO(mvm,
"Time sync: RX event - report frame t2=%llu t3=%llu\n",
ktime_to_ns(shwt->hwtstamp),
ktime_to_ns(rx_status->ack_tx_hwtstamp));
ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);
}
void iwl_mvm_time_sync_msmt_confirm_event(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_time_msmt_cfm_notify *notif = (void *)pkt->data;
struct ieee80211_tx_status status = {};
struct skb_shared_hwtstamps *shwt;
u64 ts_10ns, adj_time;
status.skb =
iwl_mvm_time_sync_find_skb(mvm, notif->peer_addr,
le32_to_cpu(notif->dialog_token));
if (!status.skb) {
IWL_DEBUG_INFO(mvm, "Time sync confirm but no pending skb\n");
return;
}
ts_10ns = iwl_mvm_get_64_bit(notif->t1_hi, notif->t1_lo);
adj_time = iwl_mvm_ptp_get_adj_time(mvm, ts_10ns * 10);
shwt = skb_hwtstamps(status.skb);
shwt->hwtstamp = ktime_set(0, adj_time);
ts_10ns = iwl_mvm_get_64_bit(notif->t4_hi, notif->t4_lo);
adj_time = iwl_mvm_ptp_get_adj_time(mvm, ts_10ns * 10);
status.info = IEEE80211_SKB_CB(status.skb);
status.ack_hwtstamp = ktime_set(0, adj_time);
IWL_DEBUG_INFO(mvm,
"Time sync: TX event - report frame t1=%llu t4=%llu\n",
ktime_to_ns(shwt->hwtstamp),
ktime_to_ns(status.ack_hwtstamp));
ieee80211_tx_status_ext(mvm->hw, &status);
}
int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, const u8 *addr, u32 protocols)
{
struct iwl_time_sync_cfg_cmd cmd = {};
int err;
lockdep_assert_held(&mvm->mutex);
if (!fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM))
return -EINVAL;
/* The fw only supports one peer. We do allow reconfiguration of the
* same peer for cases of fw reset etc.
*/
if (mvm->time_sync.active &&
!ether_addr_equal(addr, mvm->time_sync.peer_addr)) {
IWL_DEBUG_INFO(mvm, "Time sync: reject config for peer: %pM\n",
addr);
return -ENOBUFS;
}
if (protocols & ~(IWL_TIME_SYNC_PROTOCOL_TM |
IWL_TIME_SYNC_PROTOCOL_FTM))
return -EINVAL;
cmd.protocols = cpu_to_le32(protocols);
ether_addr_copy(cmd.peer_addr, addr);
err = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(DATA_PATH_GROUP,
WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD),
0, sizeof(cmd), &cmd);
if (err) {
IWL_ERR(mvm, "Failed to send time sync cfg cmd: %d\n", err);
} else {
mvm->time_sync.active = protocols != 0;
ether_addr_copy(mvm->time_sync.peer_addr, addr);
IWL_DEBUG_INFO(mvm, "Time sync: set peer addr=%pM\n", addr);
}
if (!mvm->time_sync.active)
skb_queue_purge(&mvm->time_sync.frame_list);
return err;
}

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2022 Intel Corporation
*/
#ifndef __TIME_SYNC_H__
#define __TIME_SYNC_H__
#include "mvm.h"
#include <linux/ieee80211.h>
void iwl_mvm_init_time_sync(struct iwl_time_sync_data *data);
void iwl_mvm_time_sync_msmt_event(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_time_sync_msmt_confirm_event(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, const u8 *addr,
u32 protocols);
static inline
bool iwl_mvm_time_sync_frame(struct iwl_mvm *mvm, struct sk_buff *skb, u8 *addr)
{
if (ether_addr_equal(mvm->time_sync.peer_addr, addr) &&
(ieee80211_is_timing_measurement(skb) || ieee80211_is_ftm(skb))) {
skb_queue_tail(&mvm->time_sync.frame_list, skb);
return true;
}
return false;
}
#endif

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2019-2021 Intel Corporation
* Copyright (C) 2012-2014, 2019-2022 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2016 Intel Deutschland GmbH
*/
@ -334,7 +334,7 @@ static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
if (vif->type != NL80211_IFTYPE_STATION)
return;
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode, 0);
}
static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)

View File

@ -14,6 +14,7 @@
#include "iwl-eeprom-parse.h"
#include "mvm.h"
#include "sta.h"
#include "time-sync.h"
static void
iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
@ -603,11 +604,10 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb,
}
static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
struct iwl_mvm_vif_link_info *link,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr)
{
struct iwl_mvm_vif *mvmvif =
iwl_mvm_vif_from_mac80211(info->control.vif);
__le16 fc = hdr->frame_control;
switch (info->control.vif->type) {
@ -626,15 +626,15 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
if (ieee80211_is_mgmt(fc) &&
(!ieee80211_is_bufferable_mmpdu(fc) ||
ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))
return mvm->probe_queue;
return link->mgmt_queue;
if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) &&
is_multicast_ether_addr(hdr->addr1))
return mvmvif->cab_queue;
return link->cab_queue;
WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC,
"fc=0x%02x", le16_to_cpu(fc));
return mvm->probe_queue;
return link->mgmt_queue;
case NL80211_IFTYPE_P2P_DEVICE:
if (ieee80211_is_mgmt(fc))
return mvm->p2p_dev_queue;
@ -667,7 +667,7 @@ static void iwl_mvm_probe_resp_set_noa(struct iwl_mvm *mvm,
rcu_read_lock();
resp_data = rcu_dereference(mvmvif->probe_resp_data);
resp_data = rcu_dereference(mvmvif->deflink.probe_resp_data);
if (!resp_data)
goto out;
@ -738,12 +738,26 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
info.control.vif->type == NL80211_IFTYPE_AP ||
info.control.vif->type == NL80211_IFTYPE_ADHOC) {
if (!ieee80211_is_data(hdr->frame_control))
sta_id = mvmvif->bcast_sta.sta_id;
else
sta_id = mvmvif->mcast_sta.sta_id;
u32 link_id = u32_get_bits(info.control.flags,
IEEE80211_TX_CTRL_MLO_LINK);
struct iwl_mvm_vif_link_info *link;
queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr);
if (link_id == IEEE80211_LINK_UNSPECIFIED) {
if (info.control.vif->active_links)
link_id = ffs(info.control.vif->active_links) - 1;
else
link_id = 0;
}
link = mvmvif->link[link_id];
if (!ieee80211_is_data(hdr->frame_control))
sta_id = link->bcast_sta.sta_id;
else
sta_id = link->mcast_sta.sta_id;
queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info,
hdr);
} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
queue = mvm->snif_queue;
sta_id = mvm->snif_sta.sta_id;
@ -1083,7 +1097,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
if (WARN_ON_ONCE(!mvmsta))
return -1;
if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA))
if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
return -1;
if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->deflink.he_cap.has_he)
@ -1093,7 +1107,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
iwl_mvm_probe_resp_set_noa(mvm, skb);
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen,
sta, mvmsta->sta_id);
sta, mvmsta->deflink.sta_id);
if (!dev_cmd)
goto drop;
@ -1169,7 +1183,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
}
IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x len %d\n",
mvmsta->sta_id, tid, txq_id,
mvmsta->deflink.sta_id, tid, txq_id,
IEEE80211_SEQ_TO_SN(seq_number), skb->len);
/* From now on, we cannot access info->control */
@ -1204,7 +1218,8 @@ drop_unlock_sta:
iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
spin_unlock(&mvmsta->lock);
drop:
IWL_DEBUG_TX(mvm, "TX to [%d|%d] dropped\n", mvmsta->sta_id, tid);
IWL_DEBUG_TX(mvm, "TX to [%d|%d] dropped\n", mvmsta->deflink.sta_id,
tid);
return -1;
}
@ -1221,7 +1236,7 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
if (WARN_ON_ONCE(!mvmsta))
return -1;
if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA))
if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
return -1;
memcpy(&info, skb->cb, sizeof(info));
@ -1643,7 +1658,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
info->status.status_driver_data[0] =
RS_DRV_DATA_PACK(lq_color, tx_resp->reduced_tpc);
ieee80211_tx_status(mvm->hw, skb);
if (likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr1)))
ieee80211_tx_status(mvm->hw, skb);
}
/* This is an aggregation queue or might become one, so we use
@ -1973,9 +1989,11 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
* possible (i.e. first MPDU in the aggregation wasn't acked)
* Still it's important to update RS about sent vs. acked.
*/
if (!is_flush && skb_queue_empty(&reclaimed_skbs)) {
if (!is_flush && skb_queue_empty(&reclaimed_skbs) &&
!iwl_mvm_has_tlc_offload(mvm)) {
struct ieee80211_chanctx_conf *chanctx_conf = NULL;
/* no TLC offload, so non-MLD mode */
if (mvmsta->vif)
chanctx_conf =
rcu_dereference(mvmsta->vif->bss_conf.chanctx_conf);
@ -1986,11 +2004,8 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
tx_info->band = chanctx_conf->def.chan->band;
iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, tx_info);
if (!iwl_mvm_has_tlc_offload(mvm)) {
IWL_DEBUG_TX_REPLY(mvm,
"No reclaim. Update rs directly\n");
iwl_mvm_rs_tx_status(mvm, sta, tid, tx_info, false);
}
IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n");
iwl_mvm_rs_tx_status(mvm, sta, tid, tx_info, false);
}
out:
@ -2228,17 +2243,22 @@ free_rsp:
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal)
{
struct iwl_mvm_int_sta *int_sta = sta;
struct iwl_mvm_sta *mvm_sta = sta;
u32 sta_id, tfd_queue_msk;
BUILD_BUG_ON(offsetof(struct iwl_mvm_int_sta, sta_id) !=
offsetof(struct iwl_mvm_sta, sta_id));
if (internal) {
struct iwl_mvm_int_sta *int_sta = sta;
sta_id = int_sta->sta_id;
tfd_queue_msk = int_sta->tfd_queue_msk;
} else {
struct iwl_mvm_sta *mvm_sta = sta;
sta_id = mvm_sta->deflink.sta_id;
tfd_queue_msk = mvm_sta->tfd_queue_msk;
}
if (iwl_mvm_has_new_tx_api(mvm))
return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, 0xffff);
return iwl_mvm_flush_sta_tids(mvm, sta_id, 0xffff);
if (internal)
return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk);
return iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk);
return iwl_mvm_flush_tx_path(mvm, tfd_queue_msk);
}

View File

@ -272,13 +272,15 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq)
* @vif: Pointer to the ieee80211_vif structure
* @req_type: The part of the driver who call for a change.
* @smps_request: The request to change the SMPS mode.
* @link_id: for MLO link_id, otherwise 0 (deflink)
*
* Get a requst to change the SMPS mode,
* and change it according to all other requests in the driver.
*/
void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request)
enum ieee80211_smps_mode smps_request,
unsigned int link_id)
{
struct iwl_mvm_vif *mvmvif;
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
@ -294,17 +296,38 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return;
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmvif->smps_requests[req_type] = smps_request;
if (WARN_ON_ONCE(!mvmvif->link[link_id]))
return;
mvmvif->link[link_id]->smps_requests[req_type] = smps_request;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC) {
if (mvmvif->link[link_id]->smps_requests[i] ==
IEEE80211_SMPS_STATIC) {
smps_mode = IEEE80211_SMPS_STATIC;
break;
}
if (mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC)
if (mvmvif->link[link_id]->smps_requests[i] ==
IEEE80211_SMPS_DYNAMIC)
smps_mode = IEEE80211_SMPS_DYNAMIC;
}
ieee80211_request_smps(vif, 0, smps_mode);
ieee80211_request_smps(vif, link_id, smps_mode);
}
void iwl_mvm_update_smps_on_active_links(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request)
{
struct ieee80211_bss_conf *link_conf;
unsigned int link_id;
rcu_read_lock();
for_each_vif_active_link(vif, link_conf, link_id)
iwl_mvm_update_smps(mvm, vif, req_type, smps_request,
link_id);
rcu_read_unlock();
}
static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait,
@ -392,12 +415,12 @@ static void iwl_mvm_diversity_iter(void *_data, u8 *mac,
struct iwl_mvm_diversity_iter_data *data = _data;
int i;
if (mvmvif->phy_ctxt != data->ctxt)
if (mvmvif->deflink.phy_ctxt != data->ctxt)
return;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC ||
mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) {
if (mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_STATIC ||
mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_DYNAMIC) {
data->result = false;
break;
}
@ -495,10 +518,10 @@ static void iwl_mvm_ll_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)
if (iwl_mvm_vif_low_latency(mvmvif)) {
result->result = true;
if (!mvmvif->phy_ctxt)
if (!mvmvif->deflink.phy_ctxt)
return;
band = mvmvif->phy_ctxt->channel->band;
band = mvmvif->deflink.phy_ctxt->channel->band;
result->result_per_band[band] = true;
}
}
@ -819,10 +842,10 @@ static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm,
if (!vif->cfg.assoc)
return;
if (!mvmvif->queue_params[IEEE80211_AC_VO].uapsd &&
!mvmvif->queue_params[IEEE80211_AC_VI].uapsd &&
!mvmvif->queue_params[IEEE80211_AC_BE].uapsd &&
!mvmvif->queue_params[IEEE80211_AC_BK].uapsd)
if (!mvmvif->deflink.queue_params[IEEE80211_AC_VO].uapsd &&
!mvmvif->deflink.queue_params[IEEE80211_AC_VI].uapsd &&
!mvmvif->deflink.queue_params[IEEE80211_AC_BE].uapsd &&
!mvmvif->deflink.queue_params[IEEE80211_AC_BK].uapsd)
return;
if (mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected)
@ -831,7 +854,8 @@ static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm,
mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected = true;
IWL_INFO(mvm,
"detected AP should do aggregation but isn't, likely due to U-APSD\n");
schedule_delayed_work(&mvmvif->uapsd_nonagg_detected_wk, 15 * HZ);
schedule_delayed_work(&mvmvif->uapsd_nonagg_detected_wk,
15 * HZ);
}
static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm,
@ -883,10 +907,10 @@ static void iwl_mvm_tcm_iterator(void *_data, u8 *mac,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 *band = _data;
if (!mvmvif->phy_ctxt)
if (!mvmvif->deflink.phy_ctxt)
return;
band[mvmvif->id] = mvmvif->phy_ctxt->channel->band;
band[mvmvif->id] = mvmvif->deflink.phy_ctxt->channel->band;
}
static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
@ -1137,3 +1161,36 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type,
iwl_mvm_power_update_device(mvm);
}
}
/* Find if at least two links from different vifs use same channel
* FIXME: consider having a refcount array in struct iwl_mvm_vif for
* used phy_ctxt ids.
*/
bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1,
struct iwl_mvm_vif *vif2)
{
unsigned int i, j;
for_each_mvm_vif_valid_link(vif1, i) {
for_each_mvm_vif_valid_link(vif2, j) {
if (vif1->link[i]->phy_ctxt == vif2->link[j]->phy_ctxt)
return true;
}
}
return false;
}
bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif)
{
unsigned int i;
/* FIXME: can it fail when phy_ctxt is assigned? */
for_each_mvm_vif_valid_link(mvmvif, i) {
if (mvmvif->link[i]->phy_ctxt &&
mvmvif->link[i]->phy_ctxt->id < NUM_PHY_CTX)
return true;
}
return false;
}

View File

@ -1159,6 +1159,16 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET,
iwl_cfg_bz_a0_fm4_a0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY,
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bz_a0_fm_b0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY,
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bz_a0_fm4_b0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP,
IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
@ -1204,15 +1214,30 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_a0_gf_a0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP,
IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_b0_gf_a0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP,
IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_a0_gf4_a0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP,
IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_b0_gf4_a0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP,
IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET,
iwl_cfg_bnj_a0_hr_b0, iwl_bz_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP,
IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET,
iwl_cfg_bnj_b0_hr_b0, iwl_bz_name),
/* SoF with JF2 */
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,

View File

@ -0,0 +1,55 @@
config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
depends on PCMCIA
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
help
Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
(PC-card) wireless Ethernet networking card to your computer.
Please read the file
<file:Documentation/networking/device_drivers/wifi/ray_cs.rst> for
details.
To compile this driver as a module, choose M here: the module will be
called ray_cs. If unsure, say N.
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
depends on CFG80211 && PCMCIA
select WIRELESS_EXT
select WEXT_SPY
help
A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
It has basic support for Linux wireless extensions and initial
micro support for ethtool.
config USB_NET_RNDIS_WLAN
tristate "Wireless RNDIS USB support"
depends on USB
depends on CFG80211
select USB_NET_DRIVERS
select USB_USBNET
select USB_NET_CDCETHER
select USB_NET_RNDIS_HOST
help
This is a driver for wireless RNDIS devices.
These are USB based adapters found in devices such as:
Buffalo WLI-U2-KG125S
U.S. Robotics USR5421
Belkin F5D7051
Linksys WUSB54GSv2
Linksys WUSB54GSC
Asus WL169gE
Eminent EM4045
BT Voyager 1055
Linksys WUSB54GSv1
U.S. Robotics USR5420
BUFFALO WLI-USB-G54
All of these devices are based on Broadcom 4320 chip which is the
only wireless RNDIS chip known to date.
If you choose to build a module, it'll be called rndis_wlan.

View File

@ -0,0 +1,6 @@
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o

Some files were not shown because too many files have changed in this diff Show More