iwlwifi: mvm: detect U-APSD breaking aggregation
Try to detect that the AP is not using aggregation even when there's enough traffic to make it worthwhile; if this is the case and U-APSD is enabled then assume the AP is broken (like so many) and doesn't enable aggregation when U-APSD is used. In this case, disconnect from the AP and blacklist U-APSD for a potential new connection to it. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>hifive-unleashed-5.1
parent
bde1492d4a
commit
b0ffe455bc
|
@ -69,6 +69,8 @@
|
|||
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20
|
||||
|
||||
#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
|
||||
#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
|
||||
#define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
|
||||
|
@ -115,6 +117,8 @@
|
|||
#define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */
|
||||
#define IWL_MVM_TCM_LOAD_HIGH_THRESH 50 /* percentage */
|
||||
#define IWL_MVM_TCM_LOWLAT_ENABLE_THRESH 100 /* packets/10 seconds */
|
||||
#define IWL_MVM_UAPSD_NONAGG_PERIOD 5000 /* msecs */
|
||||
#define IWL_MVM_UAPSD_NOAGG_LIST_LEN IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM
|
||||
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
|
||||
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
|
||||
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1
|
||||
|
|
|
@ -1728,6 +1728,27 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
|
|||
return ret ?: count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
u8 buf[IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM * ETH_ALEN * 3 + 1];
|
||||
unsigned int pos = 0;
|
||||
size_t bufsz = sizeof(buf);
|
||||
int i;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
for (i = 0; i < IWL_MVM_UAPSD_NOAGG_LIST_LEN; i++)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
|
||||
mvm->uapsd_noagg_bssids[i].addr);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
|
||||
|
||||
/* Device wide debugfs entries */
|
||||
|
@ -1762,6 +1783,8 @@ MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
|
|||
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
|
||||
|
||||
MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
|
||||
|
@ -1972,6 +1995,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||
mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
|
||||
goto err;
|
||||
|
||||
MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
|
||||
bcast_dir = debugfs_create_dir("bcast_filtering",
|
||||
|
|
|
@ -952,6 +952,16 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
|||
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
if (iwl_mvm_vif_from_mac80211(vif)->ap_sta_id ==
|
||||
iwl_mvm_sta_from_mac80211(sta)->sta_id) {
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
u16 macid = iwl_mvm_vif_from_mac80211(vif)->id;
|
||||
struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[macid];
|
||||
|
||||
mdata->opened_rx_ba_sessions = true;
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
cancel_delayed_work(&mvmvif->uapsd_nonagg_detected_wk);
|
||||
}
|
||||
if (!iwl_enable_rx_ampdu(mvm->cfg)) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
|
@ -1435,6 +1445,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|||
mvm->p2p_device_vif = vif;
|
||||
}
|
||||
|
||||
iwl_mvm_tcm_add_vif(mvm, vif);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_MONITOR)
|
||||
mvm->monitor_on = true;
|
||||
|
||||
|
@ -1486,6 +1498,10 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
|
||||
iwl_mvm_prepare_mac_removal(mvm, vif);
|
||||
|
||||
if (!(vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC))
|
||||
iwl_mvm_tcm_rm_vif(mvm, vif);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (mvm->bf_allowed_vif == mvmvif) {
|
||||
|
@ -2535,6 +2551,16 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
|
|||
static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
const u8 *bssid)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
|
||||
struct iwl_mvm_tcm_mac *mdata;
|
||||
|
||||
mdata = &mvm->tcm.data[iwl_mvm_vif_from_mac80211(vif)->id];
|
||||
ewma_rate_init(&mdata->uapsd_nonagg_detect.rate);
|
||||
mdata->opened_rx_ba_sessions = false;
|
||||
}
|
||||
|
||||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
|
||||
return;
|
||||
|
||||
|
@ -2549,6 +2575,13 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < IWL_MVM_UAPSD_NOAGG_LIST_LEN; i++) {
|
||||
if (ether_addr_equal(mvm->uapsd_noagg_bssids[i].addr, bssid)) {
|
||||
vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
|
||||
}
|
||||
|
||||
|
|
|
@ -446,6 +446,8 @@ struct iwl_mvm_vif {
|
|||
/* 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;
|
||||
|
@ -621,6 +623,7 @@ struct iwl_mvm_tcm_mac {
|
|||
struct ewma_rate rate;
|
||||
bool detected;
|
||||
} uapsd_nonagg_detect;
|
||||
bool opened_rx_ba_sessions;
|
||||
};
|
||||
|
||||
struct iwl_mvm_tcm {
|
||||
|
@ -1028,6 +1031,10 @@ struct iwl_mvm {
|
|||
unsigned long bt_coex_last_tcm_ts;
|
||||
struct iwl_mvm_tcm tcm;
|
||||
|
||||
u8 uapsd_noagg_bssid_write_idx;
|
||||
struct mac_address uapsd_noagg_bssids[IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM]
|
||||
__aligned(2);
|
||||
|
||||
struct iwl_time_quota_cmd last_quota_cmd;
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
|
@ -1963,6 +1970,8 @@ void iwl_mvm_tcm_work(struct work_struct *work);
|
|||
void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel);
|
||||
void iwl_mvm_resume_tcm(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void iwl_mvm_tcm_rm_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
u8 iwl_mvm_tcm_load_percentage(u32 airtime, u32 elapsed);
|
||||
|
||||
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
|
||||
|
|
|
@ -264,6 +264,12 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
|
|||
struct iwl_mvm_tcm_mac *mdata;
|
||||
int mac;
|
||||
int ac = IEEE80211_AC_BE; /* treat non-QoS as BE */
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
/* expected throughput in 100Kbps, single stream, 20 MHz */
|
||||
static const u8 thresh_tpt[] = {
|
||||
9, 18, 30, 42, 60, 78, 90, 96, 120, 135,
|
||||
};
|
||||
u16 thr;
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)];
|
||||
|
@ -285,6 +291,35 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
|
|||
if (!(rate_n_flags & (RATE_MCS_HT_MSK | RATE_MCS_VHT_MSK)))
|
||||
return;
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
if (rate_n_flags & RATE_MCS_HT_MSK) {
|
||||
thr = thresh_tpt[rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK];
|
||||
thr *= 1 + ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >>
|
||||
RATE_HT_MCS_NSS_POS);
|
||||
} else {
|
||||
if (WARN_ON((rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK) >=
|
||||
ARRAY_SIZE(thresh_tpt)))
|
||||
return;
|
||||
thr = thresh_tpt[rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK];
|
||||
thr *= 1 + ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
|
||||
RATE_VHT_MCS_NSS_POS);
|
||||
}
|
||||
|
||||
thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) >>
|
||||
RATE_MCS_CHAN_WIDTH_POS);
|
||||
|
||||
mdata->uapsd_nonagg_detect.rx_bytes += len;
|
||||
ewma_rate_add(&mdata->uapsd_nonagg_detect.rate, thr);
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
|
||||
|
@ -693,6 +728,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
|
|||
int expected_size;
|
||||
int i;
|
||||
u8 *energy;
|
||||
__le32 *bytes;
|
||||
__le32 *air_time;
|
||||
__le32 flags;
|
||||
|
||||
|
@ -768,11 +804,13 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
|
|||
struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data;
|
||||
|
||||
energy = (void *)&v11->load_stats.avg_energy;
|
||||
bytes = (void *)&v11->load_stats.byte_count;
|
||||
air_time = (void *)&v11->load_stats.air_time;
|
||||
} else {
|
||||
struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data;
|
||||
|
||||
energy = (void *)&stats->load_stats.avg_energy;
|
||||
bytes = (void *)&stats->load_stats.byte_count;
|
||||
air_time = (void *)&stats->load_stats.air_time;
|
||||
}
|
||||
|
||||
|
@ -802,6 +840,15 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
|
|||
for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) {
|
||||
struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[i];
|
||||
u32 airtime = le32_to_cpu(air_time[i]);
|
||||
u32 rx_bytes = le32_to_cpu(bytes[i]);
|
||||
|
||||
mdata->uapsd_nonagg_detect.rx_bytes += rx_bytes;
|
||||
if (airtime) {
|
||||
/* re-init every time to store rate from FW */
|
||||
ewma_rate_init(&mdata->uapsd_nonagg_detect.rate);
|
||||
ewma_rate_add(&mdata->uapsd_nonagg_detect.rate,
|
||||
rx_bytes * 8 / airtime);
|
||||
}
|
||||
|
||||
mdata->rx.airtime += airtime;
|
||||
}
|
||||
|
|
|
@ -1503,12 +1503,109 @@ static void iwl_mvm_tcm_results(struct iwl_mvm *mvm)
|
|||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static void iwl_mvm_tcm_uapsd_nonagg_detected_wk(struct work_struct *wk)
|
||||
{
|
||||
struct iwl_mvm *mvm;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
mvmvif = container_of(wk, struct iwl_mvm_vif,
|
||||
uapsd_nonagg_detected_wk.work);
|
||||
vif = container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);
|
||||
mvm = mvmvif->mvm;
|
||||
|
||||
if (mvm->tcm.data[mvmvif->id].opened_rx_ba_sessions)
|
||||
return;
|
||||
|
||||
/* remember that this AP is broken */
|
||||
memcpy(mvm->uapsd_noagg_bssids[mvm->uapsd_noagg_bssid_write_idx].addr,
|
||||
vif->bss_conf.bssid, ETH_ALEN);
|
||||
mvm->uapsd_noagg_bssid_write_idx++;
|
||||
if (mvm->uapsd_noagg_bssid_write_idx >= IWL_MVM_UAPSD_NOAGG_LIST_LEN)
|
||||
mvm->uapsd_noagg_bssid_write_idx = 0;
|
||||
|
||||
iwl_mvm_connection_loss(mvm, vif,
|
||||
"AP isn't using AMPDU with uAPSD enabled");
|
||||
}
|
||||
|
||||
static void iwl_mvm_uapsd_agg_disconnect_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm *mvm = mvmvif->mvm;
|
||||
int *mac_id = data;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
if (mvmvif->id != *mac_id)
|
||||
return;
|
||||
|
||||
if (!vif->bss_conf.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)
|
||||
return;
|
||||
|
||||
if (mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected)
|
||||
return;
|
||||
|
||||
mvm->tcm.data[*mac_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);
|
||||
}
|
||||
|
||||
static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm,
|
||||
unsigned int elapsed,
|
||||
int mac)
|
||||
{
|
||||
u64 bytes = mvm->tcm.data[mac].uapsd_nonagg_detect.rx_bytes;
|
||||
u64 tpt;
|
||||
unsigned long rate;
|
||||
|
||||
rate = ewma_rate_read(&mvm->tcm.data[mac].uapsd_nonagg_detect.rate);
|
||||
|
||||
if (!rate || mvm->tcm.data[mac].opened_rx_ba_sessions ||
|
||||
mvm->tcm.data[mac].uapsd_nonagg_detect.detected)
|
||||
return;
|
||||
|
||||
if (iwl_mvm_has_new_rx_api(mvm)) {
|
||||
tpt = 8 * bytes; /* kbps */
|
||||
do_div(tpt, elapsed);
|
||||
rate *= 1000; /* kbps */
|
||||
if (tpt < 22 * rate / 100)
|
||||
return;
|
||||
} else {
|
||||
/*
|
||||
* the rate here is actually the threshold, in 100Kbps units,
|
||||
* so do the needed conversion from bytes to 100Kbps:
|
||||
* 100kb = bits / (100 * 1000),
|
||||
* 100kbps = 100kb / (msecs / 1000) ==
|
||||
* (bits / (100 * 1000)) / (msecs / 1000) ==
|
||||
* bits / (100 * msecs)
|
||||
*/
|
||||
tpt = (8 * bytes);
|
||||
do_div(tpt, elapsed * 100);
|
||||
if (tpt < rate)
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_uapsd_agg_disconnect_iter, &mac);
|
||||
}
|
||||
|
||||
static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
|
||||
unsigned long ts,
|
||||
bool handle_uapsd)
|
||||
{
|
||||
unsigned int elapsed = jiffies_to_msecs(ts - mvm->tcm.ts);
|
||||
unsigned int uapsd_elapsed =
|
||||
jiffies_to_msecs(ts - mvm->tcm.uapsd_nonagg_ts);
|
||||
u32 total_airtime = 0;
|
||||
int ac, mac;
|
||||
bool low_latency = false;
|
||||
|
@ -1551,6 +1648,12 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,
|
|||
}
|
||||
low_latency |= mvm->tcm.result.low_latency[mac];
|
||||
|
||||
if (!mvm->tcm.result.low_latency[mac] && handle_uapsd)
|
||||
iwl_mvm_check_uapsd_agg_expected_tpt(mvm, uapsd_elapsed,
|
||||
mac);
|
||||
/* clear old data */
|
||||
if (handle_uapsd)
|
||||
mdata->uapsd_nonagg_detect.rx_bytes = 0;
|
||||
memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime));
|
||||
memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime));
|
||||
}
|
||||
|
@ -1592,7 +1695,8 @@ void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)
|
|||
{
|
||||
unsigned long ts = jiffies;
|
||||
bool handle_uapsd =
|
||||
false;
|
||||
time_after(ts, mvm->tcm.uapsd_nonagg_ts +
|
||||
msecs_to_jiffies(IWL_MVM_UAPSD_NONAGG_PERIOD));
|
||||
|
||||
spin_lock(&mvm->tcm.lock);
|
||||
if (mvm->tcm.paused || !time_after(ts, mvm->tcm.ts + MVM_TCM_PERIOD)) {
|
||||
|
@ -1601,6 +1705,12 @@ void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)
|
|||
}
|
||||
spin_unlock(&mvm->tcm.lock);
|
||||
|
||||
if (handle_uapsd && iwl_mvm_has_new_rx_api(mvm)) {
|
||||
mutex_lock(&mvm->mutex);
|
||||
if (iwl_mvm_request_statistics(mvm, true))
|
||||
handle_uapsd = false;
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
spin_lock(&mvm->tcm.lock);
|
||||
/* re-check if somebody else won the recheck race */
|
||||
|
@ -1659,6 +1769,21 @@ void iwl_mvm_resume_tcm(struct iwl_mvm *mvm)
|
|||
spin_unlock_bh(&mvm->tcm.lock);
|
||||
}
|
||||
|
||||
void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
INIT_DELAYED_WORK(&mvmvif->uapsd_nonagg_detected_wk,
|
||||
iwl_mvm_tcm_uapsd_nonagg_detected_wk);
|
||||
}
|
||||
|
||||
void iwl_mvm_tcm_rm_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
cancel_delayed_work_sync(&mvmvif->uapsd_nonagg_detected_wk);
|
||||
}
|
||||
|
||||
|
||||
void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue