forked from Minki/linux
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
This commit is contained in:
commit
76015021aa
@ -430,7 +430,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
|
||||
iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
|
||||
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
|
||||
|
||||
iwl_trans_d3_suspend(priv->trans);
|
||||
iwl_trans_d3_suspend(priv->trans, false);
|
||||
|
||||
goto out;
|
||||
|
||||
@ -504,7 +504,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
|
||||
/* we'll clear ctx->vif during iwlagn_prepare_restart() */
|
||||
vif = ctx->vif;
|
||||
|
||||
ret = iwl_trans_d3_resume(priv->trans, &d3_status);
|
||||
ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
|
@ -428,8 +428,9 @@ struct iwl_trans_ops {
|
||||
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
|
||||
void (*stop_device)(struct iwl_trans *trans);
|
||||
|
||||
void (*d3_suspend)(struct iwl_trans *trans);
|
||||
int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
|
||||
void (*d3_suspend)(struct iwl_trans *trans, bool test);
|
||||
int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
|
||||
bool test);
|
||||
|
||||
int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
|
||||
|
||||
@ -588,17 +589,18 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
|
||||
trans->state = IWL_TRANS_NO_FW;
|
||||
}
|
||||
|
||||
static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
|
||||
static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
|
||||
{
|
||||
might_sleep();
|
||||
trans->ops->d3_suspend(trans);
|
||||
trans->ops->d3_suspend(trans, test);
|
||||
}
|
||||
|
||||
static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
|
||||
enum iwl_d3_status *status)
|
||||
enum iwl_d3_status *status,
|
||||
bool test)
|
||||
{
|
||||
might_sleep();
|
||||
return trans->ops->d3_resume(trans, status);
|
||||
return trans->ops->d3_resume(trans, status, test);
|
||||
}
|
||||
|
||||
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
|
||||
|
@ -174,7 +174,7 @@ static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
|
||||
static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaeaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
|
@ -63,6 +63,7 @@
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/fs.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/tcp.h>
|
||||
@ -756,7 +757,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan,
|
||||
bool test)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_d3_iter_data suspend_iter_data = {
|
||||
@ -769,7 +772,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
|
||||
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
|
||||
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
|
||||
struct iwl_d3_manager_config d3_cfg_cmd = {
|
||||
struct iwl_d3_manager_config d3_cfg_cmd_data = {
|
||||
/*
|
||||
* Program the minimum sleep time to 10 seconds, as many
|
||||
* platforms have issues processing a wakeup signal while
|
||||
@ -777,17 +780,30 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
*/
|
||||
.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
|
||||
};
|
||||
struct iwl_host_cmd d3_cfg_cmd = {
|
||||
.id = D3_CONFIG_CMD,
|
||||
.flags = CMD_SYNC | CMD_WANT_SKB,
|
||||
.data[0] = &d3_cfg_cmd_data,
|
||||
.len[0] = sizeof(d3_cfg_cmd_data),
|
||||
};
|
||||
struct wowlan_key_data key_data = {
|
||||
.use_rsc_tsc = false,
|
||||
.tkip = &tkip_cmd,
|
||||
.use_tkip = false,
|
||||
};
|
||||
int ret, i;
|
||||
int len __maybe_unused;
|
||||
u16 seq;
|
||||
u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
|
||||
if (WARN_ON(!wowlan))
|
||||
if (!wowlan) {
|
||||
/*
|
||||
* mac80211 shouldn't get here, but for D3 test
|
||||
* it doesn't warrant a warning
|
||||
*/
|
||||
WARN_ON(!test);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
|
||||
if (!key_data.rsc_tsc)
|
||||
@ -1012,14 +1028,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
goto out;
|
||||
|
||||
/* must be last -- this switches firmware state */
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
|
||||
sizeof(d3_cfg_cmd), &d3_cfg_cmd);
|
||||
ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
|
||||
if (ret)
|
||||
goto out;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) &
|
||||
FH_RSCSR_FRAME_SIZE_MSK;
|
||||
if (len >= sizeof(u32) * 2) {
|
||||
mvm->d3_test_pme_ptr =
|
||||
le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
|
||||
} else if (test) {
|
||||
/* in test mode we require the pointer */
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
iwl_free_resp(&d3_cfg_cmd);
|
||||
|
||||
clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
|
||||
|
||||
iwl_trans_d3_suspend(mvm->trans);
|
||||
iwl_trans_d3_suspend(mvm->trans, test);
|
||||
out:
|
||||
mvm->aux_sta.sta_id = old_aux_sta_id;
|
||||
mvm_ap_sta->sta_id = old_ap_sta_id;
|
||||
@ -1034,6 +1062,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
return __iwl_mvm_suspend(hw, wowlan, false);
|
||||
}
|
||||
|
||||
static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
@ -1238,9 +1271,8 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
|
||||
#endif
|
||||
}
|
||||
|
||||
int iwl_mvm_resume(struct ieee80211_hw *hw)
|
||||
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_d3_iter_data resume_iter_data = {
|
||||
.mvm = mvm,
|
||||
};
|
||||
@ -1260,7 +1292,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
|
||||
|
||||
vif = resume_iter_data.vif;
|
||||
|
||||
ret = iwl_trans_d3_resume(mvm->trans, &d3_status);
|
||||
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
@ -1277,7 +1309,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
if (vif)
|
||||
if (!test && vif)
|
||||
ieee80211_resume_disconnect(vif);
|
||||
|
||||
/* return 1 to reconfigure the device */
|
||||
@ -1285,9 +1317,106 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iwl_mvm_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
return __iwl_mvm_resume(mvm, false);
|
||||
}
|
||||
|
||||
void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
device_set_wakeup_enable(mvm->trans->dev, enabled);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct iwl_mvm *mvm = inode->i_private;
|
||||
int err;
|
||||
|
||||
if (mvm->d3_test_active)
|
||||
return -EBUSY;
|
||||
|
||||
file->private_data = inode->i_private;
|
||||
|
||||
ieee80211_stop_queues(mvm->hw);
|
||||
synchronize_net();
|
||||
|
||||
/* start pseudo D3 */
|
||||
rtnl_lock();
|
||||
err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
|
||||
rtnl_unlock();
|
||||
if (err > 0)
|
||||
err = -EINVAL;
|
||||
if (err) {
|
||||
ieee80211_wake_queues(mvm->hw);
|
||||
return err;
|
||||
}
|
||||
mvm->d3_test_active = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
u32 pme_asserted;
|
||||
|
||||
while (true) {
|
||||
pme_asserted = iwl_trans_read_mem32(mvm->trans,
|
||||
mvm->d3_test_pme_ptr);
|
||||
if (pme_asserted)
|
||||
break;
|
||||
if (msleep_interruptible(100))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_connection_loss(vif);
|
||||
}
|
||||
|
||||
static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct iwl_mvm *mvm = inode->i_private;
|
||||
int remaining_time = 10;
|
||||
|
||||
mvm->d3_test_active = false;
|
||||
__iwl_mvm_resume(mvm, true);
|
||||
iwl_abort_notification_waits(&mvm->notif_wait);
|
||||
ieee80211_restart_hw(mvm->hw);
|
||||
|
||||
/* wait for restart and disconnect all interfaces */
|
||||
while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
|
||||
remaining_time > 0) {
|
||||
remaining_time--;
|
||||
msleep(1000);
|
||||
}
|
||||
|
||||
if (remaining_time == 0)
|
||||
IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n");
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_d3_test_disconn_work_iter, NULL);
|
||||
|
||||
ieee80211_wake_queues(mvm->hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations iwl_dbgfs_d3_test_ops = {
|
||||
.llseek = no_llseek,
|
||||
.open = iwl_mvm_d3_test_open,
|
||||
.read = iwl_mvm_d3_test_read,
|
||||
.release = iwl_mvm_d3_test_release,
|
||||
};
|
||||
#endif
|
||||
|
@ -938,6 +938,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
||||
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -71,7 +71,13 @@
|
||||
#define MAC_INDEX_MIN_DRIVER 0
|
||||
#define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX
|
||||
|
||||
#define AC_NUM 4 /* Number of access categories */
|
||||
enum iwl_ac {
|
||||
AC_BK,
|
||||
AC_BE,
|
||||
AC_VI,
|
||||
AC_VO,
|
||||
AC_NUM,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_mac_protection_flags - MAC context flags
|
||||
|
@ -365,7 +365,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue,
|
||||
IWL_MVM_TX_FIFO_VO);
|
||||
IWL_MVM_TX_FIFO_MCAST);
|
||||
/* fall through */
|
||||
default:
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
@ -553,6 +553,10 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
|
||||
cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);
|
||||
}
|
||||
|
||||
/* in AP mode, the MCAST FIFO takes the EDCA params from VO */
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST);
|
||||
|
||||
if (vif->bss_conf.qos)
|
||||
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
|
||||
|
||||
|
@ -609,21 +609,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
||||
mvmvif->phy_ctxt = NULL;
|
||||
iwl_mvm_mac_ctxt_remove(mvm, vif);
|
||||
out_release:
|
||||
/*
|
||||
* TODO: remove this temporary code.
|
||||
* Currently MVM FW supports power management only on single MAC.
|
||||
* Check if only one additional interface remains after releasing
|
||||
* current one. Update power mode on the remaining interface.
|
||||
*/
|
||||
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
|
||||
mvm->vif_count--;
|
||||
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
|
||||
mvm->vif_count);
|
||||
if (mvm->vif_count == 1) {
|
||||
ieee80211_iterate_active_interfaces(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_power_update_iterator, mvm);
|
||||
}
|
||||
ieee80211_iterate_active_interfaces(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_power_update_iterator, mvm);
|
||||
iwl_mvm_mac_ctxt_release(mvm, vif);
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
@ -785,6 +775,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update quotas\n");
|
||||
}
|
||||
ret = iwl_mvm_power_update_mode(mvm, vif);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
} else if (changes & BSS_CHANGED_DTIM_PERIOD) {
|
||||
/*
|
||||
* We received a beacon _after_ association so
|
||||
@ -793,19 +786,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
iwl_mvm_remove_time_event(mvm, mvmvif,
|
||||
&mvmvif->time_event_data);
|
||||
} else if (changes & BSS_CHANGED_PS) {
|
||||
/*
|
||||
* TODO: remove this temporary code.
|
||||
* Currently MVM FW supports power management only on single
|
||||
* MAC. Avoid power mode update if more than one interface
|
||||
* is active.
|
||||
*/
|
||||
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
|
||||
mvm->vif_count);
|
||||
if (mvm->vif_count == 1) {
|
||||
ret = iwl_mvm_power_update_mode(mvm, vif);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
}
|
||||
ret = iwl_mvm_power_update_mode(mvm, vif);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,7 @@ enum iwl_mvm_tx_fifo {
|
||||
IWL_MVM_TX_FIFO_BE,
|
||||
IWL_MVM_TX_FIFO_VI,
|
||||
IWL_MVM_TX_FIFO_VO,
|
||||
IWL_MVM_TX_FIFO_MCAST = 5,
|
||||
};
|
||||
|
||||
extern struct ieee80211_ops iwl_mvm_hw_ops;
|
||||
@ -459,8 +460,10 @@ struct iwl_mvm {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
bool d3_test_active;
|
||||
bool store_d3_resume_sram;
|
||||
void *d3_resume_sram;
|
||||
u32 d3_test_pme_ptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -669,6 +672,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
|
||||
struct inet6_dev *idev);
|
||||
void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, int idx);
|
||||
extern const struct file_operations iwl_dbgfs_d3_test_ops;
|
||||
|
||||
/* BT Coex */
|
||||
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
|
||||
|
@ -215,15 +215,16 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
|
||||
RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false),
|
||||
RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),
|
||||
RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false),
|
||||
RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
|
||||
|
||||
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
|
||||
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
|
||||
|
||||
RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
|
||||
RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false),
|
||||
RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true),
|
||||
|
||||
RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
|
||||
|
||||
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
|
||||
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
|
||||
|
||||
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
|
||||
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
|
||||
|
||||
|
@ -204,7 +204,8 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
|
||||
{
|
||||
int ret;
|
||||
|
||||
WARN_ON(ctxt->ref);
|
||||
WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
|
||||
ctxt->ref);
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
ctxt->channel = chandef->chan;
|
||||
|
@ -168,6 +168,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
return;
|
||||
|
||||
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
|
||||
if (!vif->bss_conf.assoc)
|
||||
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
|
||||
@ -246,6 +248,17 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* TODO: The following vif_count verification is temporary condition.
|
||||
* Avoid power mode update if more than one interface is currently
|
||||
* active. Remove this condition when FW will support power management
|
||||
* on multiple MACs.
|
||||
*/
|
||||
IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n",
|
||||
mvm->vif_count);
|
||||
if (mvm->vif_count > 1)
|
||||
return 0;
|
||||
|
||||
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
|
||||
iwl_mvm_power_log(mvm, &cmd);
|
||||
|
||||
|
@ -169,27 +169,34 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
|
||||
num_active_bindings++;
|
||||
}
|
||||
|
||||
if (!num_active_bindings)
|
||||
goto send_cmd;
|
||||
|
||||
quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
|
||||
quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
|
||||
quota = 0;
|
||||
quota_rem = 0;
|
||||
if (num_active_bindings) {
|
||||
quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
|
||||
quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
|
||||
}
|
||||
|
||||
for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
|
||||
if (data.n_interfaces[i] <= 0)
|
||||
if (data.colors[i] < 0)
|
||||
continue;
|
||||
|
||||
cmd.quotas[idx].id_and_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
|
||||
cmd.quotas[idx].quota = cpu_to_le32(quota);
|
||||
cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
|
||||
|
||||
if (data.n_interfaces[i] <= 0) {
|
||||
cmd.quotas[idx].quota = cpu_to_le32(0);
|
||||
cmd.quotas[idx].max_duration = cpu_to_le32(0);
|
||||
} else {
|
||||
cmd.quotas[idx].quota = cpu_to_le32(quota);
|
||||
cmd.quotas[idx].max_duration =
|
||||
cpu_to_le32(IWL_MVM_MAX_QUOTA);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* Give the remainder of the session to the first binding */
|
||||
le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
|
||||
|
||||
send_cmd:
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
|
||||
sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
|
@ -401,6 +401,17 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
|
||||
|
||||
load = rs_tl_get_load(lq_data, tid);
|
||||
|
||||
/*
|
||||
* Don't create TX aggregation sessions when in high
|
||||
* BT traffic, as they would just be disrupted by BT.
|
||||
*/
|
||||
if (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2) {
|
||||
IWL_DEBUG_COEX(mvm, "BT traffic (%d), no aggregation allowed\n",
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif,
|
||||
3, TRAFFIC_LOAD));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
|
||||
IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n",
|
||||
sta->addr, tid);
|
||||
@ -1519,6 +1530,29 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
|
||||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
||||
switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
|
||||
/* nothing */
|
||||
break;
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
|
||||
/* avoid antenna B unless MIMO */
|
||||
if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
|
||||
tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
|
||||
break;
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
valid_tx_ant =
|
||||
first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
|
||||
if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
|
||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(mvm, "Invalid BT load %d",
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
|
||||
break;
|
||||
}
|
||||
|
||||
start_action = tbl->action;
|
||||
while (1) {
|
||||
lq_sta->action_counter++;
|
||||
@ -1532,7 +1566,9 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
|
||||
tx_chains_num <= 2))
|
||||
break;
|
||||
|
||||
if (window->success_ratio >= IWL_RS_GOOD_RATIO)
|
||||
if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3,
|
||||
TRAFFIC_LOAD) == 0)
|
||||
break;
|
||||
|
||||
memcpy(search_tbl, tbl, sz);
|
||||
@ -1654,6 +1690,28 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
|
||||
u8 update_search_tbl_counter = 0;
|
||||
int ret;
|
||||
|
||||
switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
|
||||
/* nothing */
|
||||
break;
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
|
||||
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
|
||||
break;
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
|
||||
/* avoid antenna B unless MIMO */
|
||||
if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
|
||||
tbl->action == IWL_MIMO2_SWITCH_SISO_C)
|
||||
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(mvm, "Invalid BT load %d",
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
|
||||
break;
|
||||
}
|
||||
|
||||
start_action = tbl->action;
|
||||
while (1) {
|
||||
lq_sta->action_counter++;
|
||||
@ -1791,6 +1849,28 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
|
||||
int ret;
|
||||
u8 update_search_tbl_counter = 0;
|
||||
|
||||
switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
|
||||
/* nothing */
|
||||
break;
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
|
||||
/* avoid antenna B and MIMO */
|
||||
if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
|
||||
tbl->action = IWL_MIMO3_SWITCH_SISO_A;
|
||||
break;
|
||||
case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
|
||||
/* avoid antenna B unless MIMO */
|
||||
if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
|
||||
tbl->action == IWL_MIMO3_SWITCH_SISO_C)
|
||||
tbl->action = IWL_MIMO3_SWITCH_SISO_A;
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(mvm, "Invalid BT load %d",
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
|
||||
break;
|
||||
}
|
||||
|
||||
start_action = tbl->action;
|
||||
while (1) {
|
||||
lq_sta->action_counter++;
|
||||
@ -2302,6 +2382,32 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
|
||||
(current_tpt > (100 * tbl->expected_tpt[low]))))
|
||||
scale_action = 0;
|
||||
|
||||
if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >=
|
||||
IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
|
||||
(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
|
||||
if (lq_sta->last_bt_traffic >
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
|
||||
/*
|
||||
* don't set scale_action, don't want to scale up if
|
||||
* the rate scale doesn't otherwise think that is a
|
||||
* good idea.
|
||||
*/
|
||||
} else if (lq_sta->last_bt_traffic <=
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
|
||||
scale_action = -1;
|
||||
}
|
||||
}
|
||||
lq_sta->last_bt_traffic =
|
||||
BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD);
|
||||
|
||||
if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >=
|
||||
IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
|
||||
(is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
|
||||
/* search for a new modulation */
|
||||
rs_stay_in_table(lq_sta, true);
|
||||
goto lq_update;
|
||||
}
|
||||
|
||||
switch (scale_action) {
|
||||
case -1:
|
||||
/* Decrease starting rate, update uCode's rate table */
|
||||
@ -2782,6 +2888,13 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
|
||||
|
||||
lq_cmd->agg_time_limit =
|
||||
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||
|
||||
/*
|
||||
* overwrite if needed, pass aggregation time limit
|
||||
* to uCode in uSec - This is racy - but heh, at least it helps...
|
||||
*/
|
||||
if (mvm && BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2)
|
||||
lq_cmd->agg_time_limit = cpu_to_le16(1200);
|
||||
}
|
||||
|
||||
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||
|
@ -358,6 +358,18 @@ struct iwl_lq_sta {
|
||||
u8 last_bt_traffic;
|
||||
};
|
||||
|
||||
enum iwl_bt_coex_profile_traffic_load {
|
||||
IWL_BT_COEX_TRAFFIC_LOAD_NONE = 0,
|
||||
IWL_BT_COEX_TRAFFIC_LOAD_LOW = 1,
|
||||
IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 2,
|
||||
IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS = 3,
|
||||
/*
|
||||
* There are no more even though below is a u8, the
|
||||
* indication from the BT device only has two bits.
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
static inline u8 num_of_ant(u8 mask)
|
||||
{
|
||||
return !!((mask) & ANT_A) +
|
||||
|
@ -371,6 +371,9 @@ static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
|
||||
else
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
|
||||
* table is controlled by LINK_QUALITY commands
|
||||
*/
|
||||
|
||||
if (ieee80211_is_data(fc)) {
|
||||
if (ieee80211_is_data(fc) && sta) {
|
||||
tx_cmd->initial_rate_index = 0;
|
||||
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
|
||||
return;
|
||||
|
@ -76,6 +76,11 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)
|
||||
if (WARN_ON(mvm->d3_test_active))
|
||||
return -EIO;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Synchronous commands from this op-mode must hold
|
||||
* the mutex, this ensures we don't try to send two
|
||||
@ -125,6 +130,11 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)
|
||||
if (WARN_ON(mvm->d3_test_active))
|
||||
return -EIO;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Only synchronous commands can wait for status,
|
||||
* we use WANT_SKB so the caller can't.
|
||||
|
@ -578,9 +578,17 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
|
||||
clear_bit(STATUS_RFKILL, &trans_pcie->status);
|
||||
}
|
||||
|
||||
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
|
||||
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
|
||||
{
|
||||
iwl_disable_interrupts(trans);
|
||||
|
||||
/*
|
||||
* in testing mode, the host stays awake and the
|
||||
* hardware won't be reset (not even partially)
|
||||
*/
|
||||
if (test)
|
||||
return;
|
||||
|
||||
iwl_pcie_disable_ict(trans);
|
||||
|
||||
iwl_clear_bit(trans, CSR_GP_CNTRL,
|
||||
@ -599,11 +607,18 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
|
||||
}
|
||||
|
||||
static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
||||
enum iwl_d3_status *status)
|
||||
enum iwl_d3_status *status,
|
||||
bool test)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (test) {
|
||||
iwl_enable_interrupts(trans);
|
||||
*status = IWL_D3_STATUS_ALIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
iwl_pcie_set_pwr(trans, false);
|
||||
|
||||
val = iwl_read32(trans, CSR_RESET);
|
||||
|
@ -1527,7 +1527,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
|
||||
goto cancel;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
|
||||
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
|
||||
test_bit(STATUS_RFKILL, &trans_pcie->status)) {
|
||||
IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
|
||||
ret = -ERFKILL;
|
||||
goto cancel;
|
||||
|
Loading…
Reference in New Issue
Block a user