mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-19 02:17:08 +07:00
wireless-drivers fixes for 4.16
Quote a few fixes as I have not been able to send a pull request earlier. Most of the fixes for iwlwifi but also few others, nothing really standing out though. iwlwifi * fix a bogus warning when freeing a TFD * fix severe throughput problem with 9000 series * fix for a bug that caused queue hangs in certain situations * fix for an issue with IBSS * fix an issue with rate-scaling in AP-mode * fix Channel Switch Announcement (CSA) issues with count 0 and 1 * some firmware debugging fixes * remov a wrong error message when removing keys * fix a firmware sysassert most usually triggered in IBSS * a couple of fixes on multicast queues * a fix with CCMP 256 rtlwifi * fix loss of signal for rtl8723be brcmfmac * add possibility to obtain firmware error * fix P2P_DEVICE ethernet address generation -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJaoVCFAAoJEG4XJFUm622bRiQIAKJ9HmZQwda8Y7Ypj/y2YIJr Rqmd+PSjfD+FNT33Ue+x/LPCfM2SnFQdnL61kqOSIgOCDS+uwwe8mDVa+DtaT+Dd sU5ftjVjBXuYiqs2XW0n8dPszFftc7omCNVAeAJcBISqrqKkXUi3Bg47jK02kV6E AAGvyJwxIMr187nFaC8N55cas0At7Mbbsvh0YRNjxnoqKOmC3NpJZPskv3C/gvUs ADJkFPUwImqE9+BwoEguAGcqV8hLVVnoXf87Ro4L1SrFl11gJSiifq/FqwXHXm8E YyJNo6lGdaw5uuX2T9wW6QfBghMoncE/tmwgLKdLyjyV8H2c6iEMKMygZIN0eTI= =HvdQ -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-for-davem-2018-03-08' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers Kalle Valo: ==================== wireless-drivers fixes for 4.16 Quote a few fixes as I have not been able to send a pull request earlier. Most of the fixes for iwlwifi but also few others, nothing really standing out though. iwlwifi * fix a bogus warning when freeing a TFD * fix severe throughput problem with 9000 series * fix for a bug that caused queue hangs in certain situations * fix for an issue with IBSS * fix an issue with rate-scaling in AP-mode * fix Channel Switch Announcement (CSA) issues with count 0 and 1 * some firmware debugging fixes * remov a wrong error message when removing keys * fix a firmware sysassert most usually triggered in IBSS * a couple of fixes on multicast queues * a fix with CCMP 256 rtlwifi * fix loss of signal for rtl8723be brcmfmac * add possibility to obtain firmware error * fix P2P_DEVICE ethernet address generation ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
652dfb2b31
@ -181,6 +181,7 @@ enum brcmf_netif_stop_reason {
|
||||
* @netif_stop_lock: spinlock for update netif_stop from multiple sources.
|
||||
* @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
|
||||
* @pend_8021x_wait: used for signalling change in count.
|
||||
* @fwil_fwerr: flag indicating fwil layer should return firmware error codes.
|
||||
*/
|
||||
struct brcmf_if {
|
||||
struct brcmf_pub *drvr;
|
||||
@ -198,6 +199,7 @@ struct brcmf_if {
|
||||
wait_queue_head_t pend_8021x_wait;
|
||||
struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
|
||||
u8 ipv6addr_idx;
|
||||
bool fwil_fwerr;
|
||||
};
|
||||
|
||||
int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
|
||||
|
@ -104,6 +104,9 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
|
||||
u32 data;
|
||||
int err;
|
||||
|
||||
/* we need to know firmware error */
|
||||
ifp->fwil_fwerr = true;
|
||||
|
||||
err = brcmf_fil_iovar_int_get(ifp, name, &data);
|
||||
if (err == 0) {
|
||||
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
|
||||
@ -112,6 +115,8 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
|
||||
brcmf_dbg(TRACE, "%s feature check failed: %d\n",
|
||||
brcmf_feat_names[id], err);
|
||||
}
|
||||
|
||||
ifp->fwil_fwerr = false;
|
||||
}
|
||||
|
||||
static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
|
||||
@ -120,6 +125,9 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
|
||||
{
|
||||
int err;
|
||||
|
||||
/* we need to know firmware error */
|
||||
ifp->fwil_fwerr = true;
|
||||
|
||||
err = brcmf_fil_iovar_data_set(ifp, name, data, len);
|
||||
if (err != -BRCMF_FW_UNSUPPORTED) {
|
||||
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
|
||||
@ -128,6 +136,8 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
|
||||
brcmf_dbg(TRACE, "%s feature check failed: %d\n",
|
||||
brcmf_feat_names[id], err);
|
||||
}
|
||||
|
||||
ifp->fwil_fwerr = false;
|
||||
}
|
||||
|
||||
#define MAX_CAPS_BUFFER_SIZE 512
|
||||
|
@ -131,6 +131,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
|
||||
brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
|
||||
err = -EBADE;
|
||||
}
|
||||
if (ifp->fwil_fwerr)
|
||||
return fwerr;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -462,25 +462,23 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
|
||||
* @dev_addr: optional device address.
|
||||
*
|
||||
* P2P needs mac addresses for P2P device and interface. If no device
|
||||
* address it specified, these are derived from the primary net device, ie.
|
||||
* the permanent ethernet address of the device.
|
||||
* address it specified, these are derived from a random ethernet
|
||||
* address.
|
||||
*/
|
||||
static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
|
||||
{
|
||||
struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
|
||||
bool local_admin = false;
|
||||
bool random_addr = false;
|
||||
|
||||
if (!dev_addr || is_zero_ether_addr(dev_addr)) {
|
||||
dev_addr = pri_ifp->mac_addr;
|
||||
local_admin = true;
|
||||
}
|
||||
if (!dev_addr || is_zero_ether_addr(dev_addr))
|
||||
random_addr = true;
|
||||
|
||||
/* Generate the P2P Device Address. This consists of the device's
|
||||
* primary MAC address with the locally administered bit set.
|
||||
/* Generate the P2P Device Address obtaining a random ethernet
|
||||
* address with the locally administered bit set.
|
||||
*/
|
||||
if (random_addr)
|
||||
eth_random_addr(p2p->dev_addr);
|
||||
else
|
||||
memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
|
||||
if (local_admin)
|
||||
p2p->dev_addr[0] |= 0x02;
|
||||
|
||||
/* Generate the P2P Interface Address. If the discovery and connection
|
||||
* BSSCFGs need to simultaneously co-exist, then this address must be
|
||||
|
@ -91,7 +91,6 @@ config IWLWIFI_BCAST_FILTERING
|
||||
config IWLWIFI_PCIE_RTPM
|
||||
bool "Enable runtime power management mode for PCIe devices"
|
||||
depends on IWLMVM && PM && EXPERT
|
||||
default false
|
||||
help
|
||||
Say Y here to enable runtime power management for PCIe
|
||||
devices. If enabled, the device will go into low power mode
|
||||
|
@ -211,7 +211,7 @@ enum {
|
||||
* @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end
|
||||
* @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use.
|
||||
* @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use.
|
||||
* @T2_V2_START_IMMEDIATELY: start time event immediately
|
||||
* @TE_V2_START_IMMEDIATELY: start time event immediately
|
||||
* @TE_V2_DEP_OTHER: depends on another time event
|
||||
* @TE_V2_DEP_TSF: depends on a specific time
|
||||
* @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC
|
||||
@ -230,7 +230,7 @@ enum iwl_time_event_policy {
|
||||
TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
|
||||
TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
|
||||
TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
|
||||
T2_V2_START_IMMEDIATELY = BIT(11),
|
||||
TE_V2_START_IMMEDIATELY = BIT(11),
|
||||
|
||||
/* placement characteristics */
|
||||
TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS),
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@ -33,6 +34,7 @@
|
||||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -942,7 +944,6 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
||||
|
||||
out:
|
||||
iwl_fw_free_dump_desc(fwrt);
|
||||
fwrt->dump.trig = NULL;
|
||||
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
|
||||
IWL_DEBUG_INFO(fwrt, "WRT dump done\n");
|
||||
}
|
||||
@ -1112,6 +1113,14 @@ void iwl_fw_error_dump_wk(struct work_struct *work)
|
||||
fwrt->ops->dump_start(fwrt->ops_ctx))
|
||||
return;
|
||||
|
||||
if (fwrt->ops && fwrt->ops->fw_running &&
|
||||
!fwrt->ops->fw_running(fwrt->ops_ctx)) {
|
||||
IWL_ERR(fwrt, "Firmware not running - cannot dump error\n");
|
||||
iwl_fw_free_dump_desc(fwrt);
|
||||
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
|
||||
/* stop recording */
|
||||
iwl_fw_dbg_stop_recording(fwrt);
|
||||
@ -1145,7 +1154,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work)
|
||||
iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (fwrt->ops && fwrt->ops->dump_end)
|
||||
fwrt->ops->dump_end(fwrt->ops_ctx);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@ -33,6 +34,7 @@
|
||||
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -91,6 +93,7 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
|
||||
if (fwrt->dump.desc != &iwl_dump_desc_assert)
|
||||
kfree(fwrt->dump.desc);
|
||||
fwrt->dump.desc = NULL;
|
||||
fwrt->dump.trig = NULL;
|
||||
}
|
||||
|
||||
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt);
|
||||
|
@ -75,6 +75,20 @@ static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt)
|
||||
cancel_delayed_work_sync(&fwrt->timestamp.wk);
|
||||
}
|
||||
|
||||
static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
cancel_delayed_work_sync(&fwrt->timestamp.wk);
|
||||
}
|
||||
|
||||
static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
if (!fwrt->timestamp.delay)
|
||||
return;
|
||||
|
||||
schedule_delayed_work(&fwrt->timestamp.wk,
|
||||
round_jiffies_relative(fwrt->timestamp.delay));
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
|
||||
struct dentry *dbgfs_dir)
|
||||
@ -84,4 +98,8 @@ static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
|
||||
|
||||
static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {}
|
||||
|
||||
static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {}
|
||||
|
||||
static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
|
||||
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
@ -77,8 +77,14 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
|
||||
|
||||
void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt)
|
||||
void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
iwl_fw_cancel_timestamp(fwrt);
|
||||
iwl_fw_suspend_timestamp(fwrt);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_runtime_exit);
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend);
|
||||
|
||||
void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
iwl_fw_resume_timestamp(fwrt);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_runtime_resume);
|
||||
|
@ -6,6 +6,7 @@
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@ -26,6 +27,7 @@
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -68,6 +70,7 @@
|
||||
struct iwl_fw_runtime_ops {
|
||||
int (*dump_start)(void *ctx);
|
||||
void (*dump_end)(void *ctx);
|
||||
bool (*fw_running)(void *ctx);
|
||||
};
|
||||
|
||||
#define MAX_NUM_LMAC 2
|
||||
@ -150,6 +153,10 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
|
||||
|
||||
void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt);
|
||||
|
||||
void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt);
|
||||
|
||||
void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt);
|
||||
|
||||
static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_ucode_type cur_fw_img)
|
||||
{
|
||||
|
@ -1098,6 +1098,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
/* make sure the d0i3 exit work is not pending */
|
||||
flush_work(&mvm->d0i3_exit_work);
|
||||
|
||||
iwl_fw_runtime_suspend(&mvm->fwrt);
|
||||
|
||||
ret = iwl_trans_suspend(trans);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -2012,6 +2014,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
|
||||
|
||||
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
|
||||
|
||||
iwl_fw_runtime_resume(&mvm->fwrt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2038,6 +2042,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
|
||||
|
||||
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
|
||||
|
||||
iwl_fw_runtime_suspend(&mvm->fwrt);
|
||||
|
||||
/* start pseudo D3 */
|
||||
rtnl_lock();
|
||||
err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
|
||||
@ -2098,6 +2104,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
|
||||
__iwl_mvm_resume(mvm, true);
|
||||
rtnl_unlock();
|
||||
|
||||
iwl_fw_runtime_resume(&mvm->fwrt);
|
||||
|
||||
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
|
||||
|
||||
iwl_abort_notification_waits(&mvm->notif_wait);
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@ -35,6 +36,7 @@
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -1281,9 +1283,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!iwl_mvm_firmware_running(mvm))
|
||||
return -EIO;
|
||||
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -438,7 +438,8 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
}
|
||||
|
||||
/* Allocate the CAB queue for softAP and GO interfaces */
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
if (vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
/*
|
||||
* For TVQM this will be overwritten later with the FW assigned
|
||||
* queue value (when queue is enabled).
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@ -2106,15 +2107,40 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
if (ret)
|
||||
goto out_remove;
|
||||
|
||||
/*
|
||||
* This is not very nice, but the simplest:
|
||||
* For older FWs adding the mcast sta before the bcast station may
|
||||
* cause assert 0x2b00.
|
||||
* This is fixed in later FW so make the order of removal depend on
|
||||
* the TLV
|
||||
*/
|
||||
if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) {
|
||||
ret = iwl_mvm_add_mcast_sta(mvm, vif);
|
||||
if (ret)
|
||||
goto out_unbind;
|
||||
|
||||
/* Send the bcast station. At this stage the TBTT and DTIM time events
|
||||
* are added and applied to the scheduler */
|
||||
/*
|
||||
* Send the bcast station. At this stage the TBTT and DTIM time
|
||||
* events are added and applied to the scheduler
|
||||
*/
|
||||
ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
|
||||
if (ret) {
|
||||
iwl_mvm_rm_mcast_sta(mvm, vif);
|
||||
goto out_unbind;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Send the bcast station. At this stage the TBTT and DTIM time
|
||||
* events are added and applied to the scheduler
|
||||
*/
|
||||
iwl_mvm_send_add_bcast_sta(mvm, vif);
|
||||
if (ret)
|
||||
goto out_rm_mcast;
|
||||
goto out_unbind;
|
||||
iwl_mvm_add_mcast_sta(mvm, vif);
|
||||
if (ret) {
|
||||
iwl_mvm_send_rm_bcast_sta(mvm, vif);
|
||||
goto out_unbind;
|
||||
}
|
||||
}
|
||||
|
||||
/* must be set before quota calculations */
|
||||
mvmvif->ap_ibss_active = true;
|
||||
@ -2144,7 +2170,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
iwl_mvm_power_update_mac(mvm);
|
||||
mvmvif->ap_ibss_active = false;
|
||||
iwl_mvm_send_rm_bcast_sta(mvm, vif);
|
||||
out_rm_mcast:
|
||||
iwl_mvm_rm_mcast_sta(mvm, vif);
|
||||
out_unbind:
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
@ -2682,6 +2707,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
|
||||
|
||||
/* enable beacon filtering */
|
||||
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
|
||||
|
||||
iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
|
||||
false);
|
||||
|
||||
ret = 0;
|
||||
} else if (old_state == IEEE80211_STA_AUTHORIZED &&
|
||||
new_state == IEEE80211_STA_ASSOC) {
|
||||
|
@ -90,6 +90,7 @@
|
||||
#include "fw/runtime.h"
|
||||
#include "fw/dbg.h"
|
||||
#include "fw/acpi.h"
|
||||
#include "fw/debugfs.h"
|
||||
|
||||
#define IWL_MVM_MAX_ADDRESSES 5
|
||||
/* RSSI offset for WkP */
|
||||
@ -1783,6 +1784,7 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
|
||||
|
||||
static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
|
||||
{
|
||||
iwl_fw_cancel_timestamp(&mvm->fwrt);
|
||||
iwl_free_fw_paging(&mvm->fwrt);
|
||||
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
|
||||
iwl_fw_dump_conf_clear(&mvm->fwrt);
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@ -35,6 +36,7 @@
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -552,9 +554,15 @@ static void iwl_mvm_fwrt_dump_end(void *ctx)
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
|
||||
}
|
||||
|
||||
static bool iwl_mvm_fwrt_fw_running(void *ctx)
|
||||
{
|
||||
return iwl_mvm_firmware_running(ctx);
|
||||
}
|
||||
|
||||
static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {
|
||||
.dump_start = iwl_mvm_fwrt_dump_start,
|
||||
.dump_end = iwl_mvm_fwrt_dump_end,
|
||||
.fw_running = iwl_mvm_fwrt_fw_running,
|
||||
};
|
||||
|
||||
static struct iwl_op_mode *
|
||||
@ -802,7 +810,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
iwl_mvm_leds_exit(mvm);
|
||||
iwl_mvm_thermal_exit(mvm);
|
||||
out_free:
|
||||
iwl_fw_runtime_exit(&mvm->fwrt);
|
||||
iwl_fw_flush_dump(&mvm->fwrt);
|
||||
|
||||
if (iwlmvm_mod_params.init_dbg)
|
||||
@ -843,7 +850,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
|
||||
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
|
||||
kfree(mvm->d3_resume_sram);
|
||||
#endif
|
||||
iwl_fw_runtime_exit(&mvm->fwrt);
|
||||
iwl_trans_op_mode_leave(mvm->trans);
|
||||
|
||||
iwl_phy_db_free(mvm->phy_db);
|
||||
|
@ -2684,7 +2684,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
enum nl80211_band band,
|
||||
struct rs_rate *rate)
|
||||
struct rs_rate *rate,
|
||||
bool init)
|
||||
{
|
||||
int i, nentries;
|
||||
unsigned long active_rate;
|
||||
@ -2738,14 +2739,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
|
||||
*/
|
||||
if (sta->vht_cap.vht_supported &&
|
||||
best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
|
||||
switch (sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
/*
|
||||
* In AP mode, when a new station associates, rs is initialized
|
||||
* immediately upon association completion, before the phy
|
||||
* context is updated with the association parameters, so the
|
||||
* sta bandwidth might be wider than the phy context allows.
|
||||
* To avoid this issue, always initialize rs with 20mhz
|
||||
* bandwidth rate, and after authorization, when the phy context
|
||||
* is already up-to-date, re-init rs with the correct bw.
|
||||
*/
|
||||
u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta);
|
||||
|
||||
switch (bw) {
|
||||
case RATE_MCS_CHAN_WIDTH_40:
|
||||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
initial_rates = rs_optimal_rates_vht;
|
||||
nentries = ARRAY_SIZE(rs_optimal_rates_vht);
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_20:
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
initial_rates = rs_optimal_rates_vht_20mhz;
|
||||
nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz);
|
||||
break;
|
||||
@ -2756,7 +2768,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
|
||||
|
||||
active_rate = lq_sta->active_siso_rate;
|
||||
rate->type = LQ_VHT_SISO;
|
||||
rate->bw = rs_bw_from_sta_bw(sta);
|
||||
rate->bw = bw;
|
||||
} else if (sta->ht_cap.ht_supported &&
|
||||
best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
|
||||
initial_rates = rs_optimal_rates_ht;
|
||||
@ -2839,7 +2851,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
|
||||
tbl = &(lq_sta->lq_info[active_tbl]);
|
||||
rate = &tbl->rate;
|
||||
|
||||
rs_get_initial_rate(mvm, sta, lq_sta, band, rate);
|
||||
rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init);
|
||||
rs_init_optimal_rate(mvm, sta, lq_sta);
|
||||
|
||||
WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B,
|
||||
|
@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
|
||||
struct iwl_mvm_key_pn *ptk_pn;
|
||||
int res;
|
||||
u8 tid, keyidx;
|
||||
u8 pn[IEEE80211_CCMP_PN_LEN];
|
||||
u8 *extiv;
|
||||
@ -127,11 +128,12 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
pn[4] = extiv[1];
|
||||
pn[5] = extiv[0];
|
||||
|
||||
if (memcmp(pn, ptk_pn->q[queue].pn[tid],
|
||||
IEEE80211_CCMP_PN_LEN) <= 0)
|
||||
res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN))
|
||||
return -1;
|
||||
|
||||
if (!(stats->flag & RX_FLAG_AMSDU_MORE))
|
||||
memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);
|
||||
stats->flag |= RX_FLAG_PN_VALIDATED;
|
||||
|
||||
@ -314,28 +316,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
|
||||
}
|
||||
|
||||
/*
|
||||
* returns true if a packet outside BA session is a duplicate and
|
||||
* should be dropped
|
||||
* returns true if a packet is a duplicate and should be dropped.
|
||||
* Updates AMSDU PN tracking info
|
||||
*/
|
||||
static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
|
||||
static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_hdr *hdr,
|
||||
struct iwl_rx_mpdu_desc *desc)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta;
|
||||
struct iwl_mvm_rxq_dup_data *dup_data;
|
||||
u8 baid, tid, sub_frame_idx;
|
||||
u8 tid, sub_frame_idx;
|
||||
|
||||
if (WARN_ON(IS_ERR_OR_NULL(sta)))
|
||||
return false;
|
||||
|
||||
baid = (le32_to_cpu(desc->reorder_data) &
|
||||
IWL_RX_MPDU_REORDER_BAID_MASK) >>
|
||||
IWL_RX_MPDU_REORDER_BAID_SHIFT;
|
||||
|
||||
if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
|
||||
return false;
|
||||
|
||||
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
dup_data = &mvm_sta->dup_data[queue];
|
||||
|
||||
@ -365,6 +360,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
|
||||
dup_data->last_sub_frame[tid] >= sub_frame_idx))
|
||||
return true;
|
||||
|
||||
/* Allow same PN as the first subframe for following sub frames */
|
||||
if (dup_data->last_seq[tid] == hdr->seq_ctrl &&
|
||||
sub_frame_idx > dup_data->last_sub_frame[tid] &&
|
||||
desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU)
|
||||
rx_status->flag |= RX_FLAG_ALLOW_SAME_PN;
|
||||
|
||||
dup_data->last_seq[tid] = hdr->seq_ctrl;
|
||||
dup_data->last_sub_frame[tid] = sub_frame_idx;
|
||||
|
||||
@ -971,7 +972,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
if (ieee80211_is_data(hdr->frame_control))
|
||||
iwl_mvm_rx_csum(sta, skb, desc);
|
||||
|
||||
if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) {
|
||||
if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
@ -2039,7 +2039,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
struct iwl_trans_txq_scd_cfg cfg = {
|
||||
.fifo = IWL_MVM_TX_FIFO_MCAST,
|
||||
.sta_id = msta->sta_id,
|
||||
.tid = IWL_MAX_TID_COUNT,
|
||||
.tid = 0,
|
||||
.aggregate = false,
|
||||
.frame_limit = IWL_FRAME_LIMIT,
|
||||
};
|
||||
@ -2052,6 +2052,17 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
vif->type != NL80211_IFTYPE_ADHOC))
|
||||
return -ENOTSUPP;
|
||||
|
||||
/*
|
||||
* In IBSS, ieee80211_check_queues() sets the cab_queue to be
|
||||
* invalid, so make sure we use the queue we want.
|
||||
* Note that this is done here as we want to avoid making DQA
|
||||
* changes in mac80211 layer.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
|
||||
mvmvif->cab_queue = vif->cab_queue;
|
||||
}
|
||||
|
||||
/*
|
||||
* While in previous FWs we had to exclude cab queue from TFD queue
|
||||
* mask, now it is needed as any other queue.
|
||||
@ -2079,24 +2090,13 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
if (iwl_mvm_has_new_tx_api(mvm)) {
|
||||
int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue,
|
||||
msta->sta_id,
|
||||
IWL_MAX_TID_COUNT,
|
||||
0,
|
||||
timeout);
|
||||
mvmvif->cab_queue = queue;
|
||||
} else if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_STA_TYPE)) {
|
||||
/*
|
||||
* In IBSS, ieee80211_check_queues() sets the cab_queue to be
|
||||
* invalid, so make sure we use the queue we want.
|
||||
* Note that this is done here as we want to avoid making DQA
|
||||
* changes in mac80211 layer.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
|
||||
mvmvif->cab_queue = vif->cab_queue;
|
||||
}
|
||||
IWL_UCODE_TLV_API_STA_TYPE))
|
||||
iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0,
|
||||
&cfg, timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2115,7 +2115,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0);
|
||||
|
||||
iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue,
|
||||
IWL_MAX_TID_COUNT, 0);
|
||||
0, 0);
|
||||
|
||||
ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);
|
||||
if (ret)
|
||||
@ -3170,8 +3170,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
|
||||
int ret, size;
|
||||
u32 status;
|
||||
|
||||
/* This is a valid situation for GTK removal */
|
||||
if (sta_id == IWL_MVM_INVALID_STA)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
|
||||
STA_KEY_FLG_KEYID_MSK);
|
||||
|
@ -616,7 +616,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
|
||||
time_cmd.repeat = 1;
|
||||
time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
|
||||
TE_V2_NOTIF_HOST_EVENT_END |
|
||||
T2_V2_START_IMMEDIATELY);
|
||||
TE_V2_START_IMMEDIATELY);
|
||||
|
||||
if (!wait_for_notif) {
|
||||
iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
|
||||
@ -803,7 +803,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
time_cmd.repeat = 1;
|
||||
time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
|
||||
TE_V2_NOTIF_HOST_EVENT_END |
|
||||
T2_V2_START_IMMEDIATELY);
|
||||
TE_V2_START_IMMEDIATELY);
|
||||
|
||||
return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
|
||||
}
|
||||
@ -913,6 +913,8 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
|
||||
time_cmd.interval = cpu_to_le32(1);
|
||||
time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
|
||||
TE_V2_ABSENCE);
|
||||
if (!apply_time)
|
||||
time_cmd.policy |= cpu_to_le16(TE_V2_START_IMMEDIATELY);
|
||||
|
||||
return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
|
||||
}
|
||||
|
@ -419,11 +419,11 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
|
||||
{
|
||||
struct ieee80211_key_conf *keyconf = info->control.hw_key;
|
||||
u8 *crypto_hdr = skb_frag->data + hdrlen;
|
||||
enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM;
|
||||
u64 pn;
|
||||
|
||||
switch (keyconf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
|
||||
iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
|
||||
break;
|
||||
@ -447,13 +447,16 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
type = TX_CMD_SEC_GCMP;
|
||||
/* Fall through */
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
/* TODO: Taking the key from the table might introduce a race
|
||||
* when PTK rekeying is done, having an old packets with a PN
|
||||
* based on the old key but the message encrypted with a new
|
||||
* one.
|
||||
* Need to handle this.
|
||||
*/
|
||||
tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TX_CMD_SEC_KEY_FROM_TABLE;
|
||||
tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE;
|
||||
tx_cmd->key[0] = keyconf->hw_key_idx;
|
||||
iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
|
||||
break;
|
||||
@ -645,7 +648,11 @@ 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 (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
sta_id = mvmvif->bcast_sta.sta_id;
|
||||
else
|
||||
sta_id = mvmvif->mcast_sta.sta_id;
|
||||
|
||||
queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,
|
||||
hdr->frame_control);
|
||||
if (queue < 0)
|
||||
|
@ -147,7 +147,7 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans,
|
||||
/* Sanity check on number of chunks */
|
||||
num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd);
|
||||
|
||||
if (num_tbs >= trans_pcie->max_tbs) {
|
||||
if (num_tbs > trans_pcie->max_tbs) {
|
||||
IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
|
||||
return;
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
|
||||
/* Sanity check on number of chunks */
|
||||
num_tbs = iwl_pcie_tfd_get_num_tbs(trans, tfd);
|
||||
|
||||
if (num_tbs >= trans_pcie->max_tbs) {
|
||||
if (num_tbs > trans_pcie->max_tbs) {
|
||||
IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
|
||||
/* @todo issue fatal error, it is quite serious situation */
|
||||
return;
|
||||
|
@ -1125,7 +1125,8 @@ static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw)
|
||||
|
||||
/* Configuration Space offset 0x70f BIT7 is used to control L0S */
|
||||
tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f);
|
||||
_rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7));
|
||||
_rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7) |
|
||||
ASPM_L1_LATENCY << 3);
|
||||
|
||||
/* Configuration Space offset 0x719 Bit3 is for L1
|
||||
* BIT4 is for clock request
|
||||
|
Loading…
Reference in New Issue
Block a user