diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
68 files changed, 7211 insertions, 2083 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 824f5e287783..ab019b45551b 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
| @@ -59,6 +59,7 @@ config IWLDVM | |||
| 59 | 59 | ||
| 60 | config IWLMVM | 60 | config IWLMVM |
| 61 | tristate "Intel Wireless WiFi MVM Firmware support" | 61 | tristate "Intel Wireless WiFi MVM Firmware support" |
| 62 | select WANT_DEV_COREDUMP | ||
| 62 | help | 63 | help |
| 63 | This is the driver that supports the MVM firmware which is | 64 | This is the driver that supports the MVM firmware which is |
| 64 | currently only available for 7260 and 3160 devices. | 65 | currently only available for 7260 and 3160 devices. |
| @@ -85,6 +86,16 @@ config IWLWIFI_BCAST_FILTERING | |||
| 85 | If unsure, don't enable this option, as some programs might | 86 | If unsure, don't enable this option, as some programs might |
| 86 | expect incoming broadcasts for their normal operations. | 87 | expect incoming broadcasts for their normal operations. |
| 87 | 88 | ||
| 89 | config IWLWIFI_UAPSD | ||
| 90 | bool "enable U-APSD by default" | ||
| 91 | depends on IWLMVM | ||
| 92 | help | ||
| 93 | Say Y here to enable U-APSD by default. This may cause | ||
| 94 | interoperability problems with some APs, manifesting in lower than | ||
| 95 | expected throughput due to those APs not enabling aggregation | ||
| 96 | |||
| 97 | If unsure, say N. | ||
| 98 | |||
| 88 | menu "Debugging Options" | 99 | menu "Debugging Options" |
| 89 | 100 | ||
| 90 | config IWLWIFI_DEBUG | 101 | config IWLWIFI_DEBUG |
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 751ae1d10b7f..7a34e4d158d1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
| @@ -966,21 +966,21 @@ struct iwl_rem_sta_cmd { | |||
| 966 | 966 | ||
| 967 | 967 | ||
| 968 | /* WiFi queues mask */ | 968 | /* WiFi queues mask */ |
| 969 | #define IWL_SCD_BK_MSK cpu_to_le32(BIT(0)) | 969 | #define IWL_SCD_BK_MSK BIT(0) |
| 970 | #define IWL_SCD_BE_MSK cpu_to_le32(BIT(1)) | 970 | #define IWL_SCD_BE_MSK BIT(1) |
| 971 | #define IWL_SCD_VI_MSK cpu_to_le32(BIT(2)) | 971 | #define IWL_SCD_VI_MSK BIT(2) |
| 972 | #define IWL_SCD_VO_MSK cpu_to_le32(BIT(3)) | 972 | #define IWL_SCD_VO_MSK BIT(3) |
| 973 | #define IWL_SCD_MGMT_MSK cpu_to_le32(BIT(3)) | 973 | #define IWL_SCD_MGMT_MSK BIT(3) |
| 974 | 974 | ||
| 975 | /* PAN queues mask */ | 975 | /* PAN queues mask */ |
| 976 | #define IWL_PAN_SCD_BK_MSK cpu_to_le32(BIT(4)) | 976 | #define IWL_PAN_SCD_BK_MSK BIT(4) |
| 977 | #define IWL_PAN_SCD_BE_MSK cpu_to_le32(BIT(5)) | 977 | #define IWL_PAN_SCD_BE_MSK BIT(5) |
| 978 | #define IWL_PAN_SCD_VI_MSK cpu_to_le32(BIT(6)) | 978 | #define IWL_PAN_SCD_VI_MSK BIT(6) |
| 979 | #define IWL_PAN_SCD_VO_MSK cpu_to_le32(BIT(7)) | 979 | #define IWL_PAN_SCD_VO_MSK BIT(7) |
| 980 | #define IWL_PAN_SCD_MGMT_MSK cpu_to_le32(BIT(7)) | 980 | #define IWL_PAN_SCD_MGMT_MSK BIT(7) |
| 981 | #define IWL_PAN_SCD_MULTICAST_MSK cpu_to_le32(BIT(8)) | 981 | #define IWL_PAN_SCD_MULTICAST_MSK BIT(8) |
| 982 | 982 | ||
| 983 | #define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00) | 983 | #define IWL_AGG_TX_QUEUE_MSK 0xffc00 |
| 984 | 984 | ||
| 985 | #define IWL_DROP_ALL BIT(1) | 985 | #define IWL_DROP_ALL BIT(1) |
| 986 | 986 | ||
| @@ -1005,12 +1005,17 @@ struct iwl_rem_sta_cmd { | |||
| 1005 | * 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable. | 1005 | * 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable. |
| 1006 | * 2: Dump all FIFO | 1006 | * 2: Dump all FIFO |
| 1007 | */ | 1007 | */ |
| 1008 | struct iwl_txfifo_flush_cmd { | 1008 | struct iwl_txfifo_flush_cmd_v3 { |
| 1009 | __le32 queue_control; | 1009 | __le32 queue_control; |
| 1010 | __le16 flush_control; | 1010 | __le16 flush_control; |
| 1011 | __le16 reserved; | 1011 | __le16 reserved; |
| 1012 | } __packed; | 1012 | } __packed; |
| 1013 | 1013 | ||
| 1014 | struct iwl_txfifo_flush_cmd_v2 { | ||
| 1015 | __le16 queue_control; | ||
| 1016 | __le16 flush_control; | ||
| 1017 | } __packed; | ||
| 1018 | |||
| 1014 | /* | 1019 | /* |
| 1015 | * REPLY_WEP_KEY = 0x20 | 1020 | * REPLY_WEP_KEY = 0x20 |
| 1016 | */ | 1021 | */ |
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 2191621d69c1..1d2223df5cb0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c | |||
| @@ -137,37 +137,38 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, | |||
| 137 | */ | 137 | */ |
| 138 | int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk) | 138 | int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk) |
| 139 | { | 139 | { |
| 140 | struct iwl_txfifo_flush_cmd flush_cmd; | 140 | struct iwl_txfifo_flush_cmd_v3 flush_cmd_v3 = { |
| 141 | struct iwl_host_cmd cmd = { | 141 | .flush_control = cpu_to_le16(IWL_DROP_ALL), |
| 142 | .id = REPLY_TXFIFO_FLUSH, | 142 | }; |
| 143 | .len = { sizeof(struct iwl_txfifo_flush_cmd), }, | 143 | struct iwl_txfifo_flush_cmd_v2 flush_cmd_v2 = { |
| 144 | .data = { &flush_cmd, }, | 144 | .flush_control = cpu_to_le16(IWL_DROP_ALL), |
| 145 | }; | 145 | }; |
| 146 | 146 | ||
| 147 | memset(&flush_cmd, 0, sizeof(flush_cmd)); | 147 | u32 queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | |
| 148 | IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | IWL_SCD_MGMT_MSK; | ||
| 148 | 149 | ||
| 149 | flush_cmd.queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | | ||
| 150 | IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | | ||
| 151 | IWL_SCD_MGMT_MSK; | ||
| 152 | if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) | 150 | if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) |
| 153 | flush_cmd.queue_control |= IWL_PAN_SCD_VO_MSK | | 151 | queue_control |= IWL_PAN_SCD_VO_MSK | IWL_PAN_SCD_VI_MSK | |
| 154 | IWL_PAN_SCD_VI_MSK | | 152 | IWL_PAN_SCD_BE_MSK | IWL_PAN_SCD_BK_MSK | |
| 155 | IWL_PAN_SCD_BE_MSK | | 153 | IWL_PAN_SCD_MGMT_MSK | |
| 156 | IWL_PAN_SCD_BK_MSK | | 154 | IWL_PAN_SCD_MULTICAST_MSK; |
| 157 | IWL_PAN_SCD_MGMT_MSK | | ||
| 158 | IWL_PAN_SCD_MULTICAST_MSK; | ||
| 159 | 155 | ||
| 160 | if (priv->nvm_data->sku_cap_11n_enable) | 156 | if (priv->nvm_data->sku_cap_11n_enable) |
| 161 | flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK; | 157 | queue_control |= IWL_AGG_TX_QUEUE_MSK; |
| 162 | 158 | ||
| 163 | if (scd_q_msk) | 159 | if (scd_q_msk) |
| 164 | flush_cmd.queue_control = cpu_to_le32(scd_q_msk); | 160 | queue_control = scd_q_msk; |
| 165 | 161 | ||
| 166 | IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", | 162 | IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", queue_control); |
| 167 | flush_cmd.queue_control); | 163 | flush_cmd_v3.queue_control = cpu_to_le32(queue_control); |
| 168 | flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL); | 164 | flush_cmd_v2.queue_control = cpu_to_le16((u16)queue_control); |
| 169 | 165 | ||
| 170 | return iwl_dvm_send_cmd(priv, &cmd); | 166 | if (IWL_UCODE_API(priv->fw->ucode_ver) > 2) |
| 167 | return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0, | ||
| 168 | sizeof(flush_cmd_v3), | ||
| 169 | &flush_cmd_v3); | ||
| 170 | return iwl_dvm_send_cmd_pdu(priv, REPLY_TXFIFO_FLUSH, 0, | ||
| 171 | sizeof(flush_cmd_v2), &flush_cmd_v2); | ||
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) | 174 | void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) |
| @@ -418,8 +419,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena) | |||
| 418 | 419 | ||
| 419 | static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg) | 420 | static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg) |
| 420 | { | 421 | { |
| 421 | return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >> | 422 | return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >> |
| 422 | BT_UART_MSG_FRAME3SCOESCO_POS; | 423 | BT_UART_MSG_FRAME3SCOESCO_POS; |
| 423 | } | 424 | } |
| 424 | 425 | ||
| 425 | static void iwlagn_bt_traffic_change_work(struct work_struct *work) | 426 | static void iwlagn_bt_traffic_change_work(struct work_struct *work) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index afb98f4fdaf3..47e64e8b9517 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
| @@ -125,8 +125,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, | |||
| 125 | */ | 125 | */ |
| 126 | 126 | ||
| 127 | if (priv->nvm_data->sku_cap_11n_enable) | 127 | if (priv->nvm_data->sku_cap_11n_enable) |
| 128 | hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | 128 | hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS | |
| 129 | IEEE80211_HW_SUPPORTS_STATIC_SMPS; | 129 | NL80211_FEATURE_STATIC_SMPS; |
| 130 | 130 | ||
| 131 | /* | 131 | /* |
| 132 | * Enable 11w if advertised by firmware and software crypto | 132 | * Enable 11w if advertised by firmware and software crypto |
| @@ -941,6 +941,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw, | |||
| 941 | } | 941 | } |
| 942 | 942 | ||
| 943 | static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | 943 | static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, |
| 944 | struct ieee80211_vif *vif, | ||
| 944 | struct ieee80211_channel_switch *ch_switch) | 945 | struct ieee80211_channel_switch *ch_switch) |
| 945 | { | 946 | { |
| 946 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 947 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
| @@ -1095,6 +1096,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
| 1095 | u32 queues, bool drop) | 1096 | u32 queues, bool drop) |
| 1096 | { | 1097 | { |
| 1097 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 1098 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
| 1099 | u32 scd_queues; | ||
| 1098 | 1100 | ||
| 1099 | mutex_lock(&priv->mutex); | 1101 | mutex_lock(&priv->mutex); |
| 1100 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 1102 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
| @@ -1108,18 +1110,19 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
| 1108 | goto done; | 1110 | goto done; |
| 1109 | } | 1111 | } |
| 1110 | 1112 | ||
| 1111 | /* | 1113 | scd_queues = BIT(priv->cfg->base_params->num_of_queues) - 1; |
| 1112 | * mac80211 will not push any more frames for transmit | 1114 | scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) | |
| 1113 | * until the flush is completed | 1115 | BIT(IWL_DEFAULT_CMD_QUEUE_NUM)); |
| 1114 | */ | 1116 | |
| 1115 | if (drop) { | 1117 | if (vif) |
| 1116 | IWL_DEBUG_MAC80211(priv, "send flush command\n"); | 1118 | scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]); |
| 1117 | if (iwlagn_txfifo_flush(priv, 0)) { | 1119 | |
| 1118 | IWL_ERR(priv, "flush request fail\n"); | 1120 | IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues); |
| 1119 | goto done; | 1121 | if (iwlagn_txfifo_flush(priv, scd_queues)) { |
| 1120 | } | 1122 | IWL_ERR(priv, "flush request fail\n"); |
| 1123 | goto done; | ||
| 1121 | } | 1124 | } |
| 1122 | IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); | 1125 | IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n"); |
| 1123 | iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); | 1126 | iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); |
| 1124 | done: | 1127 | done: |
| 1125 | mutex_unlock(&priv->mutex); | 1128 | mutex_unlock(&priv->mutex); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 3255a1723d17..d1ce3ce13591 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
| @@ -580,7 +580,7 @@ turn_off: | |||
| 580 | * time, or we hadn't time to drain the AC queues. | 580 | * time, or we hadn't time to drain the AC queues. |
| 581 | */ | 581 | */ |
| 582 | if (agg_state == IWL_AGG_ON) | 582 | if (agg_state == IWL_AGG_ON) |
| 583 | iwl_trans_txq_disable(priv->trans, txq_id); | 583 | iwl_trans_txq_disable(priv->trans, txq_id, true); |
| 584 | else | 584 | else |
| 585 | IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", | 585 | IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", |
| 586 | agg_state); | 586 | agg_state); |
| @@ -686,7 +686,7 @@ int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
| 686 | * time, or we hadn't time to drain the AC queues. | 686 | * time, or we hadn't time to drain the AC queues. |
| 687 | */ | 687 | */ |
| 688 | if (agg_state == IWL_AGG_ON) | 688 | if (agg_state == IWL_AGG_ON) |
| 689 | iwl_trans_txq_disable(priv->trans, txq_id); | 689 | iwl_trans_txq_disable(priv->trans, txq_id, true); |
| 690 | else | 690 | else |
| 691 | IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", | 691 | IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", |
| 692 | agg_state); | 692 | agg_state); |
| @@ -781,7 +781,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid) | |||
| 781 | "Can continue DELBA flow ssn = next_recl = %d\n", | 781 | "Can continue DELBA flow ssn = next_recl = %d\n", |
| 782 | tid_data->next_reclaimed); | 782 | tid_data->next_reclaimed); |
| 783 | iwl_trans_txq_disable(priv->trans, | 783 | iwl_trans_txq_disable(priv->trans, |
| 784 | tid_data->agg.txq_id); | 784 | tid_data->agg.txq_id, true); |
| 785 | iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id); | 785 | iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id); |
| 786 | tid_data->agg.state = IWL_AGG_OFF; | 786 | tid_data->agg.state = IWL_AGG_OFF; |
| 787 | ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); | 787 | ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index d53adc245497..e5be2d21868f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -71,12 +73,12 @@ | |||
| 71 | #define IWL3160_UCODE_API_MAX 10 | 73 | #define IWL3160_UCODE_API_MAX 10 |
| 72 | 74 | ||
| 73 | /* Oldest version we won't warn about */ | 75 | /* Oldest version we won't warn about */ |
| 74 | #define IWL7260_UCODE_API_OK 9 | 76 | #define IWL7260_UCODE_API_OK 10 |
| 75 | #define IWL3160_UCODE_API_OK 9 | 77 | #define IWL3160_UCODE_API_OK 10 |
| 76 | 78 | ||
| 77 | /* Lowest firmware API version supported */ | 79 | /* Lowest firmware API version supported */ |
| 78 | #define IWL7260_UCODE_API_MIN 8 | 80 | #define IWL7260_UCODE_API_MIN 9 |
| 79 | #define IWL3160_UCODE_API_MIN 8 | 81 | #define IWL3160_UCODE_API_MIN 9 |
| 80 | 82 | ||
| 81 | /* NVM versions */ | 83 | /* NVM versions */ |
| 82 | #define IWL7260_NVM_VERSION 0x0a1d | 84 | #define IWL7260_NVM_VERSION 0x0a1d |
| @@ -87,6 +89,8 @@ | |||
| 87 | #define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ | 89 | #define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ |
| 88 | #define IWL7265_NVM_VERSION 0x0a1d | 90 | #define IWL7265_NVM_VERSION 0x0a1d |
| 89 | #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ | 91 | #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ |
| 92 | #define IWL7265D_NVM_VERSION 0x0c11 | ||
| 93 | #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ | ||
| 90 | 94 | ||
| 91 | #define IWL7260_FW_PRE "iwlwifi-7260-" | 95 | #define IWL7260_FW_PRE "iwlwifi-7260-" |
| 92 | #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" | 96 | #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" |
| @@ -100,6 +104,9 @@ | |||
| 100 | #define IWL7265_FW_PRE "iwlwifi-7265-" | 104 | #define IWL7265_FW_PRE "iwlwifi-7265-" |
| 101 | #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" | 105 | #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" |
| 102 | 106 | ||
| 107 | #define IWL7265D_FW_PRE "iwlwifi-7265D-" | ||
| 108 | #define IWL7265D_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" | ||
| 109 | |||
| 103 | #define NVM_HW_SECTION_NUM_FAMILY_7000 0 | 110 | #define NVM_HW_SECTION_NUM_FAMILY_7000 0 |
| 104 | 111 | ||
| 105 | static const struct iwl_base_params iwl7000_base_params = { | 112 | static const struct iwl_base_params iwl7000_base_params = { |
| @@ -129,8 +136,9 @@ static const struct iwl_ht_params iwl7000_ht_params = { | |||
| 129 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | 136 | .max_data_size = IWL60_RTC_DATA_SIZE, \ |
| 130 | .base_params = &iwl7000_base_params, \ | 137 | .base_params = &iwl7000_base_params, \ |
| 131 | .led_mode = IWL_LED_RF_STATE, \ | 138 | .led_mode = IWL_LED_RF_STATE, \ |
| 132 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000 | 139 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ |
| 133 | 140 | .non_shared_ant = ANT_A, \ | |
| 141 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
| 134 | 142 | ||
| 135 | const struct iwl_cfg iwl7260_2ac_cfg = { | 143 | const struct iwl_cfg iwl7260_2ac_cfg = { |
| 136 | .name = "Intel(R) Dual Band Wireless AC 7260", | 144 | .name = "Intel(R) Dual Band Wireless AC 7260", |
| @@ -218,6 +226,12 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { | |||
| 218 | {0}, | 226 | {0}, |
| 219 | }; | 227 | }; |
| 220 | 228 | ||
| 229 | static const struct iwl_ht_params iwl7265_ht_params = { | ||
| 230 | .stbc = true, | ||
| 231 | .ldpc = true, | ||
| 232 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), | ||
| 233 | }; | ||
| 234 | |||
| 221 | const struct iwl_cfg iwl3165_2ac_cfg = { | 235 | const struct iwl_cfg iwl3165_2ac_cfg = { |
| 222 | .name = "Intel(R) Dual Band Wireless AC 3165", | 236 | .name = "Intel(R) Dual Band Wireless AC 3165", |
| 223 | .fw_name_pre = IWL3165_FW_PRE, | 237 | .fw_name_pre = IWL3165_FW_PRE, |
| @@ -232,7 +246,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { | |||
| 232 | .name = "Intel(R) Dual Band Wireless AC 7265", | 246 | .name = "Intel(R) Dual Band Wireless AC 7265", |
| 233 | .fw_name_pre = IWL7265_FW_PRE, | 247 | .fw_name_pre = IWL7265_FW_PRE, |
| 234 | IWL_DEVICE_7000, | 248 | IWL_DEVICE_7000, |
| 235 | .ht_params = &iwl7000_ht_params, | 249 | .ht_params = &iwl7265_ht_params, |
| 236 | .nvm_ver = IWL7265_NVM_VERSION, | 250 | .nvm_ver = IWL7265_NVM_VERSION, |
| 237 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | 251 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, |
| 238 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | 252 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, |
| @@ -242,7 +256,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { | |||
| 242 | .name = "Intel(R) Dual Band Wireless N 7265", | 256 | .name = "Intel(R) Dual Band Wireless N 7265", |
| 243 | .fw_name_pre = IWL7265_FW_PRE, | 257 | .fw_name_pre = IWL7265_FW_PRE, |
| 244 | IWL_DEVICE_7000, | 258 | IWL_DEVICE_7000, |
| 245 | .ht_params = &iwl7000_ht_params, | 259 | .ht_params = &iwl7265_ht_params, |
| 246 | .nvm_ver = IWL7265_NVM_VERSION, | 260 | .nvm_ver = IWL7265_NVM_VERSION, |
| 247 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | 261 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, |
| 248 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | 262 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, |
| @@ -252,13 +266,44 @@ const struct iwl_cfg iwl7265_n_cfg = { | |||
| 252 | .name = "Intel(R) Wireless N 7265", | 266 | .name = "Intel(R) Wireless N 7265", |
| 253 | .fw_name_pre = IWL7265_FW_PRE, | 267 | .fw_name_pre = IWL7265_FW_PRE, |
| 254 | IWL_DEVICE_7000, | 268 | IWL_DEVICE_7000, |
| 255 | .ht_params = &iwl7000_ht_params, | 269 | .ht_params = &iwl7265_ht_params, |
| 256 | .nvm_ver = IWL7265_NVM_VERSION, | 270 | .nvm_ver = IWL7265_NVM_VERSION, |
| 257 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | 271 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, |
| 258 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | 272 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, |
| 259 | }; | 273 | }; |
| 260 | 274 | ||
| 275 | const struct iwl_cfg iwl7265d_2ac_cfg = { | ||
| 276 | .name = "Intel(R) Dual Band Wireless AC 7265", | ||
| 277 | .fw_name_pre = IWL7265D_FW_PRE, | ||
| 278 | IWL_DEVICE_7000, | ||
| 279 | .ht_params = &iwl7265_ht_params, | ||
| 280 | .nvm_ver = IWL7265D_NVM_VERSION, | ||
| 281 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | ||
| 282 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
| 283 | }; | ||
| 284 | |||
| 285 | const struct iwl_cfg iwl7265d_2n_cfg = { | ||
| 286 | .name = "Intel(R) Dual Band Wireless N 7265", | ||
| 287 | .fw_name_pre = IWL7265D_FW_PRE, | ||
| 288 | IWL_DEVICE_7000, | ||
| 289 | .ht_params = &iwl7265_ht_params, | ||
| 290 | .nvm_ver = IWL7265D_NVM_VERSION, | ||
| 291 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | ||
| 292 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
| 293 | }; | ||
| 294 | |||
| 295 | const struct iwl_cfg iwl7265d_n_cfg = { | ||
| 296 | .name = "Intel(R) Wireless N 7265", | ||
| 297 | .fw_name_pre = IWL7265D_FW_PRE, | ||
| 298 | IWL_DEVICE_7000, | ||
| 299 | .ht_params = &iwl7265_ht_params, | ||
| 300 | .nvm_ver = IWL7265D_NVM_VERSION, | ||
| 301 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | ||
| 302 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
| 303 | }; | ||
| 304 | |||
| 261 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | 305 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); |
| 262 | MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); | 306 | MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); |
| 263 | MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); | 307 | MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); |
| 264 | MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | 308 | MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); |
| 309 | MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index e93c6972290b..bf0a95cb7153 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -70,17 +72,18 @@ | |||
| 70 | #define IWL8000_UCODE_API_MAX 10 | 72 | #define IWL8000_UCODE_API_MAX 10 |
| 71 | 73 | ||
| 72 | /* Oldest version we won't warn about */ | 74 | /* Oldest version we won't warn about */ |
| 73 | #define IWL8000_UCODE_API_OK 8 | 75 | #define IWL8000_UCODE_API_OK 10 |
| 74 | 76 | ||
| 75 | /* Lowest firmware API version supported */ | 77 | /* Lowest firmware API version supported */ |
| 76 | #define IWL8000_UCODE_API_MIN 8 | 78 | #define IWL8000_UCODE_API_MIN 9 |
| 77 | 79 | ||
| 78 | /* NVM versions */ | 80 | /* NVM versions */ |
| 79 | #define IWL8000_NVM_VERSION 0x0a1d | 81 | #define IWL8000_NVM_VERSION 0x0a1d |
| 80 | #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ | 82 | #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ |
| 81 | 83 | ||
| 82 | #define IWL8000_FW_PRE "iwlwifi-8000-" | 84 | #define IWL8000_FW_PRE "iwlwifi-8000" |
| 83 | #define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode" | 85 | #define IWL8000_MODULE_FIRMWARE(api) \ |
| 86 | IWL8000_FW_PRE "-" __stringify(api) ".ucode" | ||
| 84 | 87 | ||
| 85 | #define NVM_HW_SECTION_NUM_FAMILY_8000 10 | 88 | #define NVM_HW_SECTION_NUM_FAMILY_8000 10 |
| 86 | #define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" | 89 | #define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" |
| @@ -88,6 +91,10 @@ | |||
| 88 | /* Max SDIO RX aggregation size of the ADDBA request/response */ | 91 | /* Max SDIO RX aggregation size of the ADDBA request/response */ |
| 89 | #define MAX_RX_AGG_SIZE_8260_SDIO 28 | 92 | #define MAX_RX_AGG_SIZE_8260_SDIO 28 |
| 90 | 93 | ||
| 94 | /* Max A-MPDU exponent for HT and VHT */ | ||
| 95 | #define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K | ||
| 96 | #define MAX_VHT_AMPDU_EXPONENT_8260_SDIO IEEE80211_VHT_MAX_AMPDU_32K | ||
| 97 | |||
| 91 | static const struct iwl_base_params iwl8000_base_params = { | 98 | static const struct iwl_base_params iwl8000_base_params = { |
| 92 | .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, | 99 | .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, |
| 93 | .num_of_queues = IWLAGN_NUM_QUEUES, | 100 | .num_of_queues = IWLAGN_NUM_QUEUES, |
| @@ -101,6 +108,8 @@ static const struct iwl_base_params iwl8000_base_params = { | |||
| 101 | }; | 108 | }; |
| 102 | 109 | ||
| 103 | static const struct iwl_ht_params iwl8000_ht_params = { | 110 | static const struct iwl_ht_params iwl8000_ht_params = { |
| 111 | .stbc = true, | ||
| 112 | .ldpc = true, | ||
| 104 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), | 113 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), |
| 105 | }; | 114 | }; |
| 106 | 115 | ||
| @@ -113,7 +122,18 @@ static const struct iwl_ht_params iwl8000_ht_params = { | |||
| 113 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | 122 | .max_data_size = IWL60_RTC_DATA_SIZE, \ |
| 114 | .base_params = &iwl8000_base_params, \ | 123 | .base_params = &iwl8000_base_params, \ |
| 115 | .led_mode = IWL_LED_RF_STATE, \ | 124 | .led_mode = IWL_LED_RF_STATE, \ |
| 116 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 | 125 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ |
| 126 | .d0i3 = true, \ | ||
| 127 | .non_shared_ant = ANT_A | ||
| 128 | |||
| 129 | const struct iwl_cfg iwl8260_2n_cfg = { | ||
| 130 | .name = "Intel(R) Dual Band Wireless N 8260", | ||
| 131 | .fw_name_pre = IWL8000_FW_PRE, | ||
| 132 | IWL_DEVICE_8000, | ||
| 133 | .ht_params = &iwl8000_ht_params, | ||
| 134 | .nvm_ver = IWL8000_NVM_VERSION, | ||
| 135 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | ||
| 136 | }; | ||
| 117 | 137 | ||
| 118 | const struct iwl_cfg iwl8260_2ac_cfg = { | 138 | const struct iwl_cfg iwl8260_2ac_cfg = { |
| 119 | .name = "Intel(R) Dual Band Wireless AC 8260", | 139 | .name = "Intel(R) Dual Band Wireless AC 8260", |
| @@ -122,6 +142,7 @@ const struct iwl_cfg iwl8260_2ac_cfg = { | |||
| 122 | .ht_params = &iwl8000_ht_params, | 142 | .ht_params = &iwl8000_ht_params, |
| 123 | .nvm_ver = IWL8000_NVM_VERSION, | 143 | .nvm_ver = IWL8000_NVM_VERSION, |
| 124 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | 144 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, |
| 145 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, | ||
| 125 | }; | 146 | }; |
| 126 | 147 | ||
| 127 | const struct iwl_cfg iwl8260_2ac_sdio_cfg = { | 148 | const struct iwl_cfg iwl8260_2ac_sdio_cfg = { |
| @@ -133,6 +154,24 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { | |||
| 133 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | 154 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, |
| 134 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, | 155 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, |
| 135 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, | 156 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, |
| 157 | .disable_dummy_notification = true, | ||
| 158 | .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, | ||
| 159 | .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, | ||
| 160 | }; | ||
| 161 | |||
| 162 | const struct iwl_cfg iwl4165_2ac_sdio_cfg = { | ||
| 163 | .name = "Intel(R) Dual Band Wireless-AC 4165", | ||
| 164 | .fw_name_pre = IWL8000_FW_PRE, | ||
| 165 | IWL_DEVICE_8000, | ||
| 166 | .ht_params = &iwl8000_ht_params, | ||
| 167 | .nvm_ver = IWL8000_NVM_VERSION, | ||
| 168 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | ||
| 169 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, | ||
| 170 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, | ||
| 171 | .bt_shared_single_ant = true, | ||
| 172 | .disable_dummy_notification = true, | ||
| 173 | .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, | ||
| 174 | .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, | ||
| 136 | }; | 175 | }; |
| 137 | 176 | ||
| 138 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); | 177 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3d7cc37420ae..3a4b9c7fc083 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
| @@ -87,6 +87,16 @@ enum iwl_device_family { | |||
| 87 | IWL_DEVICE_FAMILY_8000, | 87 | IWL_DEVICE_FAMILY_8000, |
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| 90 | static inline bool iwl_has_secure_boot(u32 hw_rev, | ||
| 91 | enum iwl_device_family family) | ||
| 92 | { | ||
| 93 | /* return 1 only for family 8000 B0 */ | ||
| 94 | if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC)) | ||
| 95 | return 1; | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 90 | /* | 100 | /* |
| 91 | * LED mode | 101 | * LED mode |
| 92 | * IWL_LED_DEFAULT: use device default | 102 | * IWL_LED_DEFAULT: use device default |
| @@ -171,6 +181,7 @@ struct iwl_base_params { | |||
| 171 | 181 | ||
| 172 | /* | 182 | /* |
| 173 | * @stbc: support Tx STBC and 1*SS Rx STBC | 183 | * @stbc: support Tx STBC and 1*SS Rx STBC |
| 184 | * @ldpc: support Tx/Rx with LDPC | ||
| 174 | * @use_rts_for_aggregation: use rts/cts protection for HT traffic | 185 | * @use_rts_for_aggregation: use rts/cts protection for HT traffic |
| 175 | * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 | 186 | * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 |
| 176 | */ | 187 | */ |
| @@ -178,6 +189,7 @@ struct iwl_ht_params { | |||
| 178 | enum ieee80211_smps_mode smps_mode; | 189 | enum ieee80211_smps_mode smps_mode; |
| 179 | const bool ht_greenfield_support; /* if used set to true */ | 190 | const bool ht_greenfield_support; /* if used set to true */ |
| 180 | const bool stbc; | 191 | const bool stbc; |
| 192 | const bool ldpc; | ||
| 181 | bool use_rts_for_aggregation; | 193 | bool use_rts_for_aggregation; |
| 182 | u8 ht40_bands; | 194 | u8 ht40_bands; |
| 183 | }; | 195 | }; |
| @@ -228,6 +240,7 @@ struct iwl_pwr_tx_backoff { | |||
| 228 | * @max_data_size: The maximal length of the fw data section | 240 | * @max_data_size: The maximal length of the fw data section |
| 229 | * @valid_tx_ant: valid transmit antenna | 241 | * @valid_tx_ant: valid transmit antenna |
| 230 | * @valid_rx_ant: valid receive antenna | 242 | * @valid_rx_ant: valid receive antenna |
| 243 | * @non_shared_ant: the antenna that is for WiFi only | ||
| 231 | * @nvm_ver: NVM version | 244 | * @nvm_ver: NVM version |
| 232 | * @nvm_calib_ver: NVM calibration version | 245 | * @nvm_calib_ver: NVM calibration version |
| 233 | * @lib: pointer to the lib ops | 246 | * @lib: pointer to the lib ops |
| @@ -243,6 +256,11 @@ struct iwl_pwr_tx_backoff { | |||
| 243 | * @nvm_hw_section_num: the ID of the HW NVM section | 256 | * @nvm_hw_section_num: the ID of the HW NVM section |
| 244 | * @pwr_tx_backoffs: translation table between power limits and backoffs | 257 | * @pwr_tx_backoffs: translation table between power limits and backoffs |
| 245 | * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response | 258 | * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response |
| 259 | * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response | ||
| 260 | * @max_ht_ampdu_factor: the exponent of the max length of A-MPDU that the | ||
| 261 | * station can receive in HT | ||
| 262 | * @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the | ||
| 263 | * station can receive in VHT | ||
| 246 | * | 264 | * |
| 247 | * We enable the driver to be backward compatible wrt. hardware features. | 265 | * We enable the driver to be backward compatible wrt. hardware features. |
| 248 | * API differences in uCode shouldn't be handled here but through TLVs | 266 | * API differences in uCode shouldn't be handled here but through TLVs |
| @@ -260,6 +278,7 @@ struct iwl_cfg { | |||
| 260 | const u32 max_inst_size; | 278 | const u32 max_inst_size; |
| 261 | u8 valid_tx_ant; | 279 | u8 valid_tx_ant; |
| 262 | u8 valid_rx_ant; | 280 | u8 valid_rx_ant; |
| 281 | u8 non_shared_ant; | ||
| 263 | bool bt_shared_single_ant; | 282 | bool bt_shared_single_ant; |
| 264 | u16 nvm_ver; | 283 | u16 nvm_ver; |
| 265 | u16 nvm_calib_ver; | 284 | u16 nvm_calib_ver; |
| @@ -280,6 +299,10 @@ struct iwl_cfg { | |||
| 280 | bool no_power_up_nic_in_init; | 299 | bool no_power_up_nic_in_init; |
| 281 | const char *default_nvm_file; | 300 | const char *default_nvm_file; |
| 282 | unsigned int max_rx_agg_size; | 301 | unsigned int max_rx_agg_size; |
| 302 | bool disable_dummy_notification; | ||
| 303 | unsigned int max_tx_agg_size; | ||
| 304 | unsigned int max_ht_ampdu_exponent; | ||
| 305 | unsigned int max_vht_ampdu_exponent; | ||
| 283 | }; | 306 | }; |
| 284 | 307 | ||
| 285 | /* | 308 | /* |
| @@ -341,8 +364,14 @@ extern const struct iwl_cfg iwl3165_2ac_cfg; | |||
| 341 | extern const struct iwl_cfg iwl7265_2ac_cfg; | 364 | extern const struct iwl_cfg iwl7265_2ac_cfg; |
| 342 | extern const struct iwl_cfg iwl7265_2n_cfg; | 365 | extern const struct iwl_cfg iwl7265_2n_cfg; |
| 343 | extern const struct iwl_cfg iwl7265_n_cfg; | 366 | extern const struct iwl_cfg iwl7265_n_cfg; |
| 367 | extern const struct iwl_cfg iwl7265d_2ac_cfg; | ||
| 368 | extern const struct iwl_cfg iwl7265d_2n_cfg; | ||
| 369 | extern const struct iwl_cfg iwl7265d_n_cfg; | ||
| 370 | extern const struct iwl_cfg iwl8260_2n_cfg; | ||
| 344 | extern const struct iwl_cfg iwl8260_2ac_cfg; | 371 | extern const struct iwl_cfg iwl8260_2ac_cfg; |
| 345 | extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; | 372 | extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; |
| 373 | extern const struct iwl_cfg iwl4265_2ac_sdio_cfg; | ||
| 374 | extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; | ||
| 346 | #endif /* CONFIG_IWLMVM */ | 375 | #endif /* CONFIG_IWLMVM */ |
| 347 | 376 | ||
| 348 | #endif /* __IWL_CONFIG_H__ */ | 377 | #endif /* __IWL_CONFIG_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index fe129c94ae3e..aff63c3f5bf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -127,6 +129,8 @@ | |||
| 127 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | 129 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) |
| 128 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | 130 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) |
| 129 | 131 | ||
| 132 | #define CSR_MBOX_SET_REG (CSR_BASE + 0x88) | ||
| 133 | |||
| 130 | #define CSR_LED_REG (CSR_BASE+0x094) | 134 | #define CSR_LED_REG (CSR_BASE+0x094) |
| 131 | #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) | 135 | #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) |
| 132 | #define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ | 136 | #define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ |
| @@ -182,6 +186,8 @@ | |||
| 182 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ | 186 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ |
| 183 | #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ | 187 | #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ |
| 184 | 188 | ||
| 189 | #define CSR_MBOX_SET_REG_OS_ALIVE BIT(5) | ||
| 190 | |||
| 185 | #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ | 191 | #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ |
| 186 | #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ | 192 | #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ |
| 187 | 193 | ||
| @@ -293,23 +299,34 @@ | |||
| 293 | #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) | 299 | #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) |
| 294 | #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) | 300 | #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) |
| 295 | 301 | ||
| 296 | #define CSR_HW_REV_TYPE_MSK (0x000FFF0) | 302 | |
| 297 | #define CSR_HW_REV_TYPE_5300 (0x0000020) | 303 | /** |
| 298 | #define CSR_HW_REV_TYPE_5350 (0x0000030) | 304 | * hw_rev values |
| 299 | #define CSR_HW_REV_TYPE_5100 (0x0000050) | 305 | */ |
| 300 | #define CSR_HW_REV_TYPE_5150 (0x0000040) | 306 | enum { |
| 301 | #define CSR_HW_REV_TYPE_1000 (0x0000060) | 307 | SILICON_A_STEP = 0, |
| 302 | #define CSR_HW_REV_TYPE_6x00 (0x0000070) | 308 | SILICON_B_STEP, |
| 303 | #define CSR_HW_REV_TYPE_6x50 (0x0000080) | 309 | }; |
| 304 | #define CSR_HW_REV_TYPE_6150 (0x0000084) | 310 | |
| 305 | #define CSR_HW_REV_TYPE_6x05 (0x00000B0) | 311 | |
| 306 | #define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05 | 312 | #define CSR_HW_REV_TYPE_MSK (0x000FFF0) |
| 307 | #define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05 | 313 | #define CSR_HW_REV_TYPE_5300 (0x0000020) |
| 308 | #define CSR_HW_REV_TYPE_2x30 (0x00000C0) | 314 | #define CSR_HW_REV_TYPE_5350 (0x0000030) |
| 309 | #define CSR_HW_REV_TYPE_2x00 (0x0000100) | 315 | #define CSR_HW_REV_TYPE_5100 (0x0000050) |
| 310 | #define CSR_HW_REV_TYPE_105 (0x0000110) | 316 | #define CSR_HW_REV_TYPE_5150 (0x0000040) |
| 311 | #define CSR_HW_REV_TYPE_135 (0x0000120) | 317 | #define CSR_HW_REV_TYPE_1000 (0x0000060) |
| 312 | #define CSR_HW_REV_TYPE_NONE (0x00001F0) | 318 | #define CSR_HW_REV_TYPE_6x00 (0x0000070) |
| 319 | #define CSR_HW_REV_TYPE_6x50 (0x0000080) | ||
| 320 | #define CSR_HW_REV_TYPE_6150 (0x0000084) | ||
| 321 | #define CSR_HW_REV_TYPE_6x05 (0x00000B0) | ||
| 322 | #define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05 | ||
| 323 | #define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05 | ||
| 324 | #define CSR_HW_REV_TYPE_2x30 (0x00000C0) | ||
| 325 | #define CSR_HW_REV_TYPE_2x00 (0x0000100) | ||
| 326 | #define CSR_HW_REV_TYPE_105 (0x0000110) | ||
| 327 | #define CSR_HW_REV_TYPE_135 (0x0000120) | ||
| 328 | #define CSR_HW_REV_TYPE_7265D (0x0000210) | ||
| 329 | #define CSR_HW_REV_TYPE_NONE (0x00001F0) | ||
| 313 | 330 | ||
| 314 | /* EEPROM REG */ | 331 | /* EEPROM REG */ |
| 315 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) | 332 | #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 295083510e72..684254553558 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
| @@ -143,8 +143,9 @@ do { \ | |||
| 143 | #define IWL_DL_INFO 0x00000001 | 143 | #define IWL_DL_INFO 0x00000001 |
| 144 | #define IWL_DL_MAC80211 0x00000002 | 144 | #define IWL_DL_MAC80211 0x00000002 |
| 145 | #define IWL_DL_HCMD 0x00000004 | 145 | #define IWL_DL_HCMD 0x00000004 |
| 146 | #define IWL_DL_STATE 0x00000008 | 146 | #define IWL_DL_TDLS 0x00000008 |
| 147 | /* 0x000000F0 - 0x00000010 */ | 147 | /* 0x000000F0 - 0x00000010 */ |
| 148 | #define IWL_DL_QUOTA 0x00000010 | ||
| 148 | #define IWL_DL_TE 0x00000020 | 149 | #define IWL_DL_TE 0x00000020 |
| 149 | #define IWL_DL_EEPROM 0x00000040 | 150 | #define IWL_DL_EEPROM 0x00000040 |
| 150 | #define IWL_DL_RADIO 0x00000080 | 151 | #define IWL_DL_RADIO 0x00000080 |
| @@ -179,6 +180,7 @@ do { \ | |||
| 179 | #define IWL_DL_TX_QUEUES 0x80000000 | 180 | #define IWL_DL_TX_QUEUES 0x80000000 |
| 180 | 181 | ||
| 181 | #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) | 182 | #define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a) |
| 183 | #define IWL_DEBUG_TDLS(p, f, a...) IWL_DEBUG(p, IWL_DL_TDLS, f, ## a) | ||
| 182 | #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) | 184 | #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a) |
| 183 | #define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a) | 185 | #define IWL_DEBUG_EXTERNAL(p, f, a...) IWL_DEBUG(p, IWL_DL_EXTERNAL, f, ## a) |
| 184 | #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) | 186 | #define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a) |
| @@ -189,6 +191,7 @@ do { \ | |||
| 189 | #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) | 191 | #define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a) |
| 190 | #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) | 192 | #define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a) |
| 191 | #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) | 193 | #define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a) |
| 194 | #define IWL_DEBUG_QUOTA(p, f, a...) IWL_DEBUG(p, IWL_DL_QUOTA, f, ## a) | ||
| 192 | #define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a) | 195 | #define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a) |
| 193 | #define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a) | 196 | #define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a) |
| 194 | #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) | 197 | #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 23e7351e02de..90987d6f348e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c | |||
| @@ -36,15 +36,8 @@ | |||
| 36 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8); | 36 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8); |
| 37 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); | 37 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); |
| 38 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); | 38 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); |
| 39 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); | ||
| 40 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx); | ||
| 41 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); | 39 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); |
| 42 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); | 40 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); |
| 43 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); | 41 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); |
| 44 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); | 42 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event); |
| 45 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info); | ||
| 46 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn); | ||
| 47 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit); | ||
| 48 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err); | ||
| 49 | EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg); | ||
| 50 | #endif | 43 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 77e3178040b2..850b85a47806 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -67,6 +69,7 @@ | |||
| 67 | #include <linux/vmalloc.h> | 69 | #include <linux/vmalloc.h> |
| 68 | 70 | ||
| 69 | #include "iwl-drv.h" | 71 | #include "iwl-drv.h" |
| 72 | #include "iwl-csr.h" | ||
| 70 | #include "iwl-debug.h" | 73 | #include "iwl-debug.h" |
| 71 | #include "iwl-trans.h" | 74 | #include "iwl-trans.h" |
| 72 | #include "iwl-op-mode.h" | 75 | #include "iwl-op-mode.h" |
| @@ -75,9 +78,6 @@ | |||
| 75 | #include "iwl-config.h" | 78 | #include "iwl-config.h" |
| 76 | #include "iwl-modparams.h" | 79 | #include "iwl-modparams.h" |
| 77 | 80 | ||
| 78 | /* private includes */ | ||
| 79 | #include "iwl-fw-file.h" | ||
| 80 | |||
| 81 | /****************************************************************************** | 81 | /****************************************************************************** |
| 82 | * | 82 | * |
| 83 | * module boiler plate | 83 | * module boiler plate |
| @@ -184,6 +184,11 @@ static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img) | |||
| 184 | static void iwl_dealloc_ucode(struct iwl_drv *drv) | 184 | static void iwl_dealloc_ucode(struct iwl_drv *drv) |
| 185 | { | 185 | { |
| 186 | int i; | 186 | int i; |
| 187 | |||
| 188 | kfree(drv->fw.dbg_dest_tlv); | ||
| 189 | for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) | ||
| 190 | kfree(drv->fw.dbg_conf_tlv[i]); | ||
| 191 | |||
| 187 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) | 192 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
| 188 | iwl_free_fw_img(drv, drv->fw.img + i); | 193 | iwl_free_fw_img(drv, drv->fw.img + i); |
| 189 | } | 194 | } |
| @@ -242,6 +247,33 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
| 242 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", | 247 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", |
| 243 | name_pre, tag); | 248 | name_pre, tag); |
| 244 | 249 | ||
| 250 | /* | ||
| 251 | * Starting 8000B - FW name format has changed. This overwrites the | ||
| 252 | * previous name and uses the new format. | ||
| 253 | * | ||
| 254 | * TODO: | ||
| 255 | * Once there is only one supported step for 8000 family - delete this! | ||
| 256 | */ | ||
| 257 | if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { | ||
| 258 | char rev_step[2] = { | ||
| 259 | 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev), 0 | ||
| 260 | }; | ||
| 261 | |||
| 262 | /* A-step doesn't have an indication */ | ||
| 263 | if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP) | ||
| 264 | rev_step[0] = 0; | ||
| 265 | |||
| 266 | /* | ||
| 267 | * If hw_rev wasn't set yet - default as B-step. If it IS A-step | ||
| 268 | * we'll reload that FW later instead. | ||
| 269 | */ | ||
| 270 | if (drv->trans->hw_rev == 0) | ||
| 271 | rev_step[0] = 'B'; | ||
| 272 | |||
| 273 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), | ||
| 274 | "%s%s-%s.ucode", name_pre, rev_step, tag); | ||
| 275 | } | ||
| 276 | |||
| 245 | IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", | 277 | IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", |
| 246 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) | 278 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) |
| 247 | ? "EXPERIMENTAL " : "", | 279 | ? "EXPERIMENTAL " : "", |
| @@ -281,6 +313,11 @@ struct iwl_firmware_pieces { | |||
| 281 | 313 | ||
| 282 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 314 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
| 283 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 315 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
| 316 | |||
| 317 | /* FW debug data parsed for driver usage */ | ||
| 318 | struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
| 319 | struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
| 320 | size_t dbg_conf_tlv_len[FW_DBG_MAX]; | ||
| 284 | }; | 321 | }; |
| 285 | 322 | ||
| 286 | /* | 323 | /* |
| @@ -554,6 +591,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
| 554 | char buildstr[25]; | 591 | char buildstr[25]; |
| 555 | u32 build; | 592 | u32 build; |
| 556 | int num_of_cpus; | 593 | int num_of_cpus; |
| 594 | bool usniffer_images = false; | ||
| 595 | bool usniffer_req = false; | ||
| 557 | 596 | ||
| 558 | if (len < sizeof(*ucode)) { | 597 | if (len < sizeof(*ucode)) { |
| 559 | IWL_ERR(drv, "uCode has invalid length: %zd\n", len); | 598 | IWL_ERR(drv, "uCode has invalid length: %zd\n", len); |
| @@ -787,19 +826,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
| 787 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, | 826 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, |
| 788 | tlv_len); | 827 | tlv_len); |
| 789 | drv->fw.mvm_fw = true; | 828 | drv->fw.mvm_fw = true; |
| 790 | drv->fw.img[IWL_UCODE_REGULAR].is_secure = true; | ||
| 791 | break; | 829 | break; |
| 792 | case IWL_UCODE_TLV_SECURE_SEC_INIT: | 830 | case IWL_UCODE_TLV_SECURE_SEC_INIT: |
| 793 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, | 831 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, |
| 794 | tlv_len); | 832 | tlv_len); |
| 795 | drv->fw.mvm_fw = true; | 833 | drv->fw.mvm_fw = true; |
| 796 | drv->fw.img[IWL_UCODE_INIT].is_secure = true; | ||
| 797 | break; | 834 | break; |
| 798 | case IWL_UCODE_TLV_SECURE_SEC_WOWLAN: | 835 | case IWL_UCODE_TLV_SECURE_SEC_WOWLAN: |
| 799 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, | 836 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, |
| 800 | tlv_len); | 837 | tlv_len); |
| 801 | drv->fw.mvm_fw = true; | 838 | drv->fw.mvm_fw = true; |
| 802 | drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true; | ||
| 803 | break; | 839 | break; |
| 804 | case IWL_UCODE_TLV_NUM_OF_CPU: | 840 | case IWL_UCODE_TLV_NUM_OF_CPU: |
| 805 | if (tlv_len != sizeof(u32)) | 841 | if (tlv_len != sizeof(u32)) |
| @@ -829,12 +865,79 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
| 829 | capa->n_scan_channels = | 865 | capa->n_scan_channels = |
| 830 | le32_to_cpup((__le32 *)tlv_data); | 866 | le32_to_cpup((__le32 *)tlv_data); |
| 831 | break; | 867 | break; |
| 868 | case IWL_UCODE_TLV_FW_DBG_DEST: { | ||
| 869 | struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data; | ||
| 870 | |||
| 871 | if (pieces->dbg_dest_tlv) { | ||
| 872 | IWL_ERR(drv, | ||
| 873 | "dbg destination ignored, already exists\n"); | ||
| 874 | break; | ||
| 875 | } | ||
| 876 | |||
| 877 | pieces->dbg_dest_tlv = dest; | ||
| 878 | IWL_INFO(drv, "Found debug destination: %s\n", | ||
| 879 | get_fw_dbg_mode_string(dest->monitor_mode)); | ||
| 880 | |||
| 881 | drv->fw.dbg_dest_reg_num = | ||
| 882 | tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv, | ||
| 883 | reg_ops); | ||
| 884 | drv->fw.dbg_dest_reg_num /= | ||
| 885 | sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]); | ||
| 886 | |||
| 887 | break; | ||
| 888 | } | ||
| 889 | case IWL_UCODE_TLV_FW_DBG_CONF: { | ||
| 890 | struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data; | ||
| 891 | |||
| 892 | if (!pieces->dbg_dest_tlv) { | ||
| 893 | IWL_ERR(drv, | ||
| 894 | "Ignore dbg config %d - no destination configured\n", | ||
| 895 | conf->id); | ||
| 896 | break; | ||
| 897 | } | ||
| 898 | |||
| 899 | if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) { | ||
| 900 | IWL_ERR(drv, | ||
| 901 | "Skip unknown configuration: %d\n", | ||
| 902 | conf->id); | ||
| 903 | break; | ||
| 904 | } | ||
| 905 | |||
| 906 | if (pieces->dbg_conf_tlv[conf->id]) { | ||
| 907 | IWL_ERR(drv, | ||
| 908 | "Ignore duplicate dbg config %d\n", | ||
| 909 | conf->id); | ||
| 910 | break; | ||
| 911 | } | ||
| 912 | |||
| 913 | if (conf->usniffer) | ||
| 914 | usniffer_req = true; | ||
| 915 | |||
| 916 | IWL_INFO(drv, "Found debug configuration: %d\n", | ||
| 917 | conf->id); | ||
| 918 | |||
| 919 | pieces->dbg_conf_tlv[conf->id] = conf; | ||
| 920 | pieces->dbg_conf_tlv_len[conf->id] = tlv_len; | ||
| 921 | break; | ||
| 922 | } | ||
| 923 | case IWL_UCODE_TLV_SEC_RT_USNIFFER: | ||
| 924 | usniffer_images = true; | ||
| 925 | iwl_store_ucode_sec(pieces, tlv_data, | ||
| 926 | IWL_UCODE_REGULAR_USNIFFER, | ||
| 927 | tlv_len); | ||
| 928 | break; | ||
| 832 | default: | 929 | default: |
| 833 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); | 930 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
| 834 | break; | 931 | break; |
| 835 | } | 932 | } |
| 836 | } | 933 | } |
| 837 | 934 | ||
| 935 | if (usniffer_req && !usniffer_images) { | ||
| 936 | IWL_ERR(drv, | ||
| 937 | "user selected to work with usniffer but usniffer image isn't available in ucode package\n"); | ||
| 938 | return -EINVAL; | ||
| 939 | } | ||
| 940 | |||
| 838 | if (len) { | 941 | if (len) { |
| 839 | IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len); | 942 | IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len); |
| 840 | iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len); | 943 | iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len); |
| @@ -972,13 +1075,14 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 972 | struct iwl_ucode_header *ucode; | 1075 | struct iwl_ucode_header *ucode; |
| 973 | struct iwlwifi_opmode_table *op; | 1076 | struct iwlwifi_opmode_table *op; |
| 974 | int err; | 1077 | int err; |
| 975 | struct iwl_firmware_pieces pieces; | 1078 | struct iwl_firmware_pieces *pieces; |
| 976 | const unsigned int api_max = drv->cfg->ucode_api_max; | 1079 | const unsigned int api_max = drv->cfg->ucode_api_max; |
| 977 | unsigned int api_ok = drv->cfg->ucode_api_ok; | 1080 | unsigned int api_ok = drv->cfg->ucode_api_ok; |
| 978 | const unsigned int api_min = drv->cfg->ucode_api_min; | 1081 | const unsigned int api_min = drv->cfg->ucode_api_min; |
| 979 | u32 api_ver; | 1082 | u32 api_ver; |
| 980 | int i; | 1083 | int i; |
| 981 | bool load_module = false; | 1084 | bool load_module = false; |
| 1085 | u32 hw_rev = drv->trans->hw_rev; | ||
| 982 | 1086 | ||
| 983 | fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; | 1087 | fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; |
| 984 | fw->ucode_capa.standard_phy_calibration_size = | 1088 | fw->ucode_capa.standard_phy_calibration_size = |
| @@ -988,7 +1092,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 988 | if (!api_ok) | 1092 | if (!api_ok) |
| 989 | api_ok = api_max; | 1093 | api_ok = api_max; |
| 990 | 1094 | ||
| 991 | memset(&pieces, 0, sizeof(pieces)); | 1095 | pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); |
| 1096 | if (!pieces) | ||
| 1097 | return; | ||
| 992 | 1098 | ||
| 993 | if (!ucode_raw) { | 1099 | if (!ucode_raw) { |
| 994 | if (drv->fw_index <= api_ok) | 1100 | if (drv->fw_index <= api_ok) |
| @@ -1011,10 +1117,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1011 | ucode = (struct iwl_ucode_header *)ucode_raw->data; | 1117 | ucode = (struct iwl_ucode_header *)ucode_raw->data; |
| 1012 | 1118 | ||
| 1013 | if (ucode->ver) | 1119 | if (ucode->ver) |
| 1014 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); | 1120 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, pieces); |
| 1015 | else | 1121 | else |
| 1016 | err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, | 1122 | err = iwl_parse_tlv_firmware(drv, ucode_raw, pieces, |
| 1017 | &fw->ucode_capa); | 1123 | &fw->ucode_capa); |
| 1018 | 1124 | ||
| 1019 | if (err) | 1125 | if (err) |
| 1020 | goto try_again; | 1126 | goto try_again; |
| @@ -1054,7 +1160,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1054 | * In mvm uCode there is no difference between data and instructions | 1160 | * In mvm uCode there is no difference between data and instructions |
| 1055 | * sections. | 1161 | * sections. |
| 1056 | */ | 1162 | */ |
| 1057 | if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) | 1163 | if (!fw->mvm_fw && validate_sec_sizes(drv, pieces, drv->cfg)) |
| 1058 | goto try_again; | 1164 | goto try_again; |
| 1059 | 1165 | ||
| 1060 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1166 | /* Allocate ucode buffers for card's bus-master loading ... */ |
| @@ -1063,8 +1169,32 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1063 | * 1) unmodified from disk | 1169 | * 1) unmodified from disk |
| 1064 | * 2) backup cache for save/restore during power-downs */ | 1170 | * 2) backup cache for save/restore during power-downs */ |
| 1065 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) | 1171 | for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) |
| 1066 | if (iwl_alloc_ucode(drv, &pieces, i)) | 1172 | if (iwl_alloc_ucode(drv, pieces, i)) |
| 1173 | goto out_free_fw; | ||
| 1174 | |||
| 1175 | if (pieces->dbg_dest_tlv) { | ||
| 1176 | drv->fw.dbg_dest_tlv = | ||
| 1177 | kmemdup(pieces->dbg_dest_tlv, | ||
| 1178 | sizeof(*pieces->dbg_dest_tlv) + | ||
| 1179 | sizeof(pieces->dbg_dest_tlv->reg_ops[0]) * | ||
| 1180 | drv->fw.dbg_dest_reg_num, GFP_KERNEL); | ||
| 1181 | |||
| 1182 | if (!drv->fw.dbg_dest_tlv) | ||
| 1067 | goto out_free_fw; | 1183 | goto out_free_fw; |
| 1184 | } | ||
| 1185 | |||
| 1186 | for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) { | ||
| 1187 | if (pieces->dbg_conf_tlv[i]) { | ||
| 1188 | drv->fw.dbg_conf_tlv_len[i] = | ||
| 1189 | pieces->dbg_conf_tlv_len[i]; | ||
| 1190 | drv->fw.dbg_conf_tlv[i] = | ||
| 1191 | kmemdup(pieces->dbg_conf_tlv[i], | ||
| 1192 | drv->fw.dbg_conf_tlv_len[i], | ||
| 1193 | GFP_KERNEL); | ||
| 1194 | if (!drv->fw.dbg_conf_tlv[i]) | ||
| 1195 | goto out_free_fw; | ||
| 1196 | } | ||
| 1197 | } | ||
| 1068 | 1198 | ||
| 1069 | /* Now that we can no longer fail, copy information */ | 1199 | /* Now that we can no longer fail, copy information */ |
| 1070 | 1200 | ||
| @@ -1073,20 +1203,20 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1073 | * for each event, which is of mode 1 (including timestamp) for all | 1203 | * for each event, which is of mode 1 (including timestamp) for all |
| 1074 | * new microcodes that include this information. | 1204 | * new microcodes that include this information. |
| 1075 | */ | 1205 | */ |
| 1076 | fw->init_evtlog_ptr = pieces.init_evtlog_ptr; | 1206 | fw->init_evtlog_ptr = pieces->init_evtlog_ptr; |
| 1077 | if (pieces.init_evtlog_size) | 1207 | if (pieces->init_evtlog_size) |
| 1078 | fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; | 1208 | fw->init_evtlog_size = (pieces->init_evtlog_size - 16)/12; |
| 1079 | else | 1209 | else |
| 1080 | fw->init_evtlog_size = | 1210 | fw->init_evtlog_size = |
| 1081 | drv->cfg->base_params->max_event_log_size; | 1211 | drv->cfg->base_params->max_event_log_size; |
| 1082 | fw->init_errlog_ptr = pieces.init_errlog_ptr; | 1212 | fw->init_errlog_ptr = pieces->init_errlog_ptr; |
| 1083 | fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | 1213 | fw->inst_evtlog_ptr = pieces->inst_evtlog_ptr; |
| 1084 | if (pieces.inst_evtlog_size) | 1214 | if (pieces->inst_evtlog_size) |
| 1085 | fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; | 1215 | fw->inst_evtlog_size = (pieces->inst_evtlog_size - 16)/12; |
| 1086 | else | 1216 | else |
| 1087 | fw->inst_evtlog_size = | 1217 | fw->inst_evtlog_size = |
| 1088 | drv->cfg->base_params->max_event_log_size; | 1218 | drv->cfg->base_params->max_event_log_size; |
| 1089 | fw->inst_errlog_ptr = pieces.inst_errlog_ptr; | 1219 | fw->inst_errlog_ptr = pieces->inst_errlog_ptr; |
| 1090 | 1220 | ||
| 1091 | /* | 1221 | /* |
| 1092 | * figure out the offset of chain noise reset and gain commands | 1222 | * figure out the offset of chain noise reset and gain commands |
| @@ -1145,6 +1275,50 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1145 | op->name, err); | 1275 | op->name, err); |
| 1146 | #endif | 1276 | #endif |
| 1147 | } | 1277 | } |
| 1278 | |||
| 1279 | /* | ||
| 1280 | * We may have loaded the wrong FW file in 8000 HW family if it is an | ||
| 1281 | * A-step card, and if drv->trans->hw_rev wasn't properly read when | ||
| 1282 | * the FW file had been loaded. (This might happen in SDIO.) In such a | ||
| 1283 | * case - unload and reload the correct file. | ||
| 1284 | * | ||
| 1285 | * TODO: | ||
| 1286 | * Once there is only one supported step for 8000 family - delete this! | ||
| 1287 | */ | ||
| 1288 | if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && | ||
| 1289 | CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP && | ||
| 1290 | drv->trans->hw_rev != hw_rev) { | ||
| 1291 | char firmware_name[32]; | ||
| 1292 | |||
| 1293 | /* Free previous FW resources */ | ||
| 1294 | if (drv->op_mode) | ||
| 1295 | _iwl_op_mode_stop(drv); | ||
| 1296 | iwl_dealloc_ucode(drv); | ||
| 1297 | |||
| 1298 | /* Build name of correct-step FW */ | ||
| 1299 | snprintf(firmware_name, sizeof(firmware_name), | ||
| 1300 | strrchr(drv->firmware_name, '-')); | ||
| 1301 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), | ||
| 1302 | "%s%s", drv->cfg->fw_name_pre, firmware_name); | ||
| 1303 | |||
| 1304 | /* Clear data before loading correct FW */ | ||
| 1305 | list_del(&drv->list); | ||
| 1306 | |||
| 1307 | /* Request correct FW file this time */ | ||
| 1308 | IWL_DEBUG_INFO(drv, "attempting to load A-step FW %s\n", | ||
| 1309 | drv->firmware_name); | ||
| 1310 | err = request_firmware(&ucode_raw, drv->firmware_name, | ||
| 1311 | drv->trans->dev); | ||
| 1312 | if (err) { | ||
| 1313 | IWL_ERR(drv, "Failed swapping FW!\n"); | ||
| 1314 | goto out_unbind; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | /* Redo callback function - this time with right FW */ | ||
| 1318 | iwl_req_fw_callback(ucode_raw, context); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | kfree(pieces); | ||
| 1148 | return; | 1322 | return; |
| 1149 | 1323 | ||
| 1150 | try_again: | 1324 | try_again: |
| @@ -1152,6 +1326,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1152 | release_firmware(ucode_raw); | 1326 | release_firmware(ucode_raw); |
| 1153 | if (iwl_request_firmware(drv, false)) | 1327 | if (iwl_request_firmware(drv, false)) |
| 1154 | goto out_unbind; | 1328 | goto out_unbind; |
| 1329 | kfree(pieces); | ||
| 1155 | return; | 1330 | return; |
| 1156 | 1331 | ||
| 1157 | out_free_fw: | 1332 | out_free_fw: |
| @@ -1159,6 +1334,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
| 1159 | iwl_dealloc_ucode(drv); | 1334 | iwl_dealloc_ucode(drv); |
| 1160 | release_firmware(ucode_raw); | 1335 | release_firmware(ucode_raw); |
| 1161 | out_unbind: | 1336 | out_unbind: |
| 1337 | kfree(pieces); | ||
| 1162 | complete(&drv->request_firmware_complete); | 1338 | complete(&drv->request_firmware_complete); |
| 1163 | device_release_driver(drv->trans->dev); | 1339 | device_release_driver(drv->trans->dev); |
| 1164 | } | 1340 | } |
| @@ -1254,7 +1430,9 @@ struct iwl_mod_params iwlwifi_mod_params = { | |||
| 1254 | .bt_coex_active = true, | 1430 | .bt_coex_active = true, |
| 1255 | .power_level = IWL_POWER_INDEX_1, | 1431 | .power_level = IWL_POWER_INDEX_1, |
| 1256 | .wd_disable = true, | 1432 | .wd_disable = true, |
| 1257 | .uapsd_disable = false, | 1433 | #ifndef CONFIG_IWLWIFI_UAPSD |
| 1434 | .uapsd_disable = true, | ||
| 1435 | #endif /* CONFIG_IWLWIFI_UAPSD */ | ||
| 1258 | /* the rest are 0 by default */ | 1436 | /* the rest are 0 by default */ |
| 1259 | }; | 1437 | }; |
| 1260 | IWL_EXPORT_SYMBOL(iwlwifi_mod_params); | 1438 | IWL_EXPORT_SYMBOL(iwlwifi_mod_params); |
| @@ -1359,7 +1537,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)") | |||
| 1359 | module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, | 1537 | module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, |
| 1360 | int, S_IRUGO); | 1538 | int, S_IRUGO); |
| 1361 | MODULE_PARM_DESC(antenna_coupling, | 1539 | MODULE_PARM_DESC(antenna_coupling, |
| 1362 | "specify antenna coupling in dB (defualt: 0 dB)"); | 1540 | "specify antenna coupling in dB (default: 0 dB)"); |
| 1363 | 1541 | ||
| 1364 | module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); | 1542 | module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); |
| 1365 | MODULE_PARM_DESC(wd_disable, | 1543 | MODULE_PARM_DESC(wd_disable, |
| @@ -1370,7 +1548,11 @@ MODULE_PARM_DESC(nvm_file, "NVM file name"); | |||
| 1370 | 1548 | ||
| 1371 | module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, | 1549 | module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, |
| 1372 | bool, S_IRUGO); | 1550 | bool, S_IRUGO); |
| 1551 | #ifdef CONFIG_IWLWIFI_UAPSD | ||
| 1373 | MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)"); | 1552 | MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)"); |
| 1553 | #else | ||
| 1554 | MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)"); | ||
| 1555 | #endif | ||
| 1374 | 1556 | ||
| 1375 | /* | 1557 | /* |
| 1376 | * set bt_coex_active to true, uCode will do kill/defer | 1558 | * set bt_coex_active to true, uCode will do kill/defer |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 3c72cb710b0c..be4f8972241a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 07ff7e0028ee..41ff85de7334 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | |||
| @@ -758,10 +758,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, | |||
| 758 | ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; | 758 | ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; |
| 759 | } | 759 | } |
| 760 | 760 | ||
| 761 | if (cfg->ht_params->ldpc) | ||
| 762 | ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; | ||
| 763 | |||
| 761 | if (iwlwifi_mod_params.amsdu_size_8K) | 764 | if (iwlwifi_mod_params.amsdu_size_8K) |
| 762 | ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; | 765 | ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; |
| 763 | 766 | ||
| 764 | ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | 767 | ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent; |
| 765 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; | 768 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; |
| 766 | 769 | ||
| 767 | ht_info->mcs.rx_mask[0] = 0xFF; | 770 | ht_info->mcs.rx_mask[0] = 0xFF; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 9564ae173d06..1f7f15eb86da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h | |||
| @@ -310,6 +310,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) | |||
| 310 | #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) | 310 | #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) |
| 311 | 311 | ||
| 312 | #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 | 312 | #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 |
| 313 | #define FH_MEM_TB_MAX_LENGTH (0x00020000) | ||
| 313 | 314 | ||
| 314 | /* TFDB Area - TFDs buffer table */ | 315 | /* TFDB Area - TFDs buffer table */ |
| 315 | #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) | 316 | #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index de5994a776c7..20a8a64c9fe3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -79,6 +81,7 @@ | |||
| 79 | * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor | 81 | * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor |
| 80 | * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several | 82 | * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several |
| 81 | * sections like this in a single file. | 83 | * sections like this in a single file. |
| 84 | * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers | ||
| 82 | */ | 85 | */ |
| 83 | enum iwl_fw_error_dump_type { | 86 | enum iwl_fw_error_dump_type { |
| 84 | IWL_FW_ERROR_DUMP_SRAM = 0, | 87 | IWL_FW_ERROR_DUMP_SRAM = 0, |
| @@ -88,6 +91,8 @@ enum iwl_fw_error_dump_type { | |||
| 88 | IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, | 91 | IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, |
| 89 | IWL_FW_ERROR_DUMP_FW_MONITOR = 5, | 92 | IWL_FW_ERROR_DUMP_FW_MONITOR = 5, |
| 90 | IWL_FW_ERROR_DUMP_PRPH = 6, | 93 | IWL_FW_ERROR_DUMP_PRPH = 6, |
| 94 | IWL_FW_ERROR_DUMP_TXF = 7, | ||
| 95 | IWL_FW_ERROR_DUMP_FH_REGS = 8, | ||
| 91 | 96 | ||
| 92 | IWL_FW_ERROR_DUMP_MAX, | 97 | IWL_FW_ERROR_DUMP_MAX, |
| 93 | }; | 98 | }; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 929a8063354c..f2a047f6bb3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -129,6 +131,9 @@ enum iwl_ucode_tlv_type { | |||
| 129 | IWL_UCODE_TLV_API_CHANGES_SET = 29, | 131 | IWL_UCODE_TLV_API_CHANGES_SET = 29, |
| 130 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, | 132 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, |
| 131 | IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, | 133 | IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, |
| 134 | IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, | ||
| 135 | IWL_UCODE_TLV_FW_DBG_DEST = 38, | ||
| 136 | IWL_UCODE_TLV_FW_DBG_CONF = 39, | ||
| 132 | }; | 137 | }; |
| 133 | 138 | ||
| 134 | struct iwl_ucode_tlv { | 139 | struct iwl_ucode_tlv { |
| @@ -177,4 +182,309 @@ struct iwl_ucode_capa { | |||
| 177 | __le32 api_capa; | 182 | __le32 api_capa; |
| 178 | } __packed; | 183 | } __packed; |
| 179 | 184 | ||
| 185 | /** | ||
| 186 | * enum iwl_ucode_tlv_flag - ucode API flags | ||
| 187 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously | ||
| 188 | * was a separate TLV but moved here to save space. | ||
| 189 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, | ||
| 190 | * treats good CRC threshold as a boolean | ||
| 191 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | ||
| 192 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. | ||
| 193 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | ||
| 194 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD | ||
| 195 | * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan | ||
| 196 | * offload profile config command. | ||
| 197 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | ||
| 198 | * (rather than two) IPv6 addresses | ||
| 199 | * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element | ||
| 200 | * from the probe request template. | ||
| 201 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) | ||
| 202 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) | ||
| 203 | * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC | ||
| 204 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and | ||
| 205 | * P2P client interfaces simultaneously if they are in different bindings. | ||
| 206 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and | ||
| 207 | * P2P client interfaces simultaneously if they are in same bindings. | ||
| 208 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD | ||
| 209 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save | ||
| 210 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. | ||
| 211 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients | ||
| 212 | * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. | ||
| 213 | */ | ||
| 214 | enum iwl_ucode_tlv_flag { | ||
| 215 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | ||
| 216 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), | ||
| 217 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | ||
| 218 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), | ||
| 219 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | ||
| 220 | IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), | ||
| 221 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | ||
| 222 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), | ||
| 223 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), | ||
| 224 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), | ||
| 225 | IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), | ||
| 226 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), | ||
| 227 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), | ||
| 228 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), | ||
| 229 | IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), | ||
| 230 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), | ||
| 231 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), | ||
| 232 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), | ||
| 233 | }; | ||
| 234 | |||
| 235 | /** | ||
| 236 | * enum iwl_ucode_tlv_api - ucode api | ||
| 237 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | ||
| 238 | * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification | ||
| 239 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex | ||
| 240 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. | ||
| 241 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. | ||
| 242 | * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. | ||
| 243 | * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. | ||
| 244 | * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time | ||
| 245 | * longer than the passive one, which is essential for fragmented scan. | ||
| 246 | */ | ||
| 247 | enum iwl_ucode_tlv_api { | ||
| 248 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | ||
| 249 | IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), | ||
| 250 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | ||
| 251 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), | ||
| 252 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), | ||
| 253 | IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), | ||
| 254 | IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), | ||
| 255 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), | ||
| 256 | }; | ||
| 257 | |||
| 258 | /** | ||
| 259 | * enum iwl_ucode_tlv_capa - ucode capabilities | ||
| 260 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | ||
| 261 | * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory | ||
| 262 | * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. | ||
| 263 | * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality | ||
| 264 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current | ||
| 265 | * tx power value into TPC Report action frame and Link Measurement Report | ||
| 266 | * action frame | ||
| 267 | * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current | ||
| 268 | * channel in DS parameter set element in probe requests. | ||
| 269 | * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in | ||
| 270 | * probe requests. | ||
| 271 | * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests | ||
| 272 | * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), | ||
| 273 | * which also implies support for the scheduler configuration command | ||
| 274 | * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching | ||
| 275 | * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command | ||
| 276 | */ | ||
| 277 | enum iwl_ucode_tlv_capa { | ||
| 278 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | ||
| 279 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1), | ||
| 280 | IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), | ||
| 281 | IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6), | ||
| 282 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), | ||
| 283 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), | ||
| 284 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), | ||
| 285 | IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), | ||
| 286 | IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), | ||
| 287 | IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13), | ||
| 288 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), | ||
| 289 | }; | ||
| 290 | |||
| 291 | /* The default calibrate table size if not specified by firmware file */ | ||
| 292 | #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 | ||
| 293 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 | ||
| 294 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 | ||
| 295 | |||
| 296 | /* The default max probe length if not specified by the firmware file */ | ||
| 297 | #define IWL_DEFAULT_MAX_PROBE_LENGTH 200 | ||
| 298 | |||
| 299 | /* | ||
| 300 | * For 16.0 uCode and above, there is no differentiation between sections, | ||
| 301 | * just an offset to the HW address. | ||
| 302 | */ | ||
| 303 | #define IWL_UCODE_SECTION_MAX 12 | ||
| 304 | #define IWL_API_ARRAY_SIZE 1 | ||
| 305 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 | ||
| 306 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC | ||
| 307 | |||
| 308 | /* uCode version contains 4 values: Major/Minor/API/Serial */ | ||
| 309 | #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) | ||
| 310 | #define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) | ||
| 311 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) | ||
| 312 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) | ||
| 313 | |||
| 314 | /* | ||
| 315 | * Calibration control struct. | ||
| 316 | * Sent as part of the phy configuration command. | ||
| 317 | * @flow_trigger: bitmap for which calibrations to perform according to | ||
| 318 | * flow triggers. | ||
| 319 | * @event_trigger: bitmap for which calibrations to perform according to | ||
| 320 | * event triggers. | ||
| 321 | */ | ||
| 322 | struct iwl_tlv_calib_ctrl { | ||
| 323 | __le32 flow_trigger; | ||
| 324 | __le32 event_trigger; | ||
| 325 | } __packed; | ||
| 326 | |||
| 327 | enum iwl_fw_phy_cfg { | ||
| 328 | FW_PHY_CFG_RADIO_TYPE_POS = 0, | ||
| 329 | FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, | ||
| 330 | FW_PHY_CFG_RADIO_STEP_POS = 2, | ||
| 331 | FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, | ||
| 332 | FW_PHY_CFG_RADIO_DASH_POS = 4, | ||
| 333 | FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, | ||
| 334 | FW_PHY_CFG_TX_CHAIN_POS = 16, | ||
| 335 | FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, | ||
| 336 | FW_PHY_CFG_RX_CHAIN_POS = 20, | ||
| 337 | FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, | ||
| 338 | }; | ||
| 339 | |||
| 340 | #define IWL_UCODE_MAX_CS 1 | ||
| 341 | |||
| 342 | /** | ||
| 343 | * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. | ||
| 344 | * @cipher: a cipher suite selector | ||
| 345 | * @flags: cipher scheme flags (currently reserved for a future use) | ||
| 346 | * @hdr_len: a size of MPDU security header | ||
| 347 | * @pn_len: a size of PN | ||
| 348 | * @pn_off: an offset of pn from the beginning of the security header | ||
| 349 | * @key_idx_off: an offset of key index byte in the security header | ||
| 350 | * @key_idx_mask: a bit mask of key_idx bits | ||
| 351 | * @key_idx_shift: bit shift needed to get key_idx | ||
| 352 | * @mic_len: mic length in bytes | ||
| 353 | * @hw_cipher: a HW cipher index used in host commands | ||
| 354 | */ | ||
| 355 | struct iwl_fw_cipher_scheme { | ||
| 356 | __le32 cipher; | ||
| 357 | u8 flags; | ||
| 358 | u8 hdr_len; | ||
| 359 | u8 pn_len; | ||
| 360 | u8 pn_off; | ||
| 361 | u8 key_idx_off; | ||
| 362 | u8 key_idx_mask; | ||
| 363 | u8 key_idx_shift; | ||
| 364 | u8 mic_len; | ||
| 365 | u8 hw_cipher; | ||
| 366 | } __packed; | ||
| 367 | |||
| 368 | enum iwl_fw_dbg_reg_operator { | ||
| 369 | CSR_ASSIGN, | ||
| 370 | CSR_SETBIT, | ||
| 371 | CSR_CLEARBIT, | ||
| 372 | |||
| 373 | PRPH_ASSIGN, | ||
| 374 | PRPH_SETBIT, | ||
| 375 | PRPH_CLEARBIT, | ||
| 376 | }; | ||
| 377 | |||
| 378 | /** | ||
| 379 | * struct iwl_fw_dbg_reg_op - an operation on a register | ||
| 380 | * | ||
| 381 | * @op: %enum iwl_fw_dbg_reg_operator | ||
| 382 | * @addr: offset of the register | ||
| 383 | * @val: value | ||
| 384 | */ | ||
| 385 | struct iwl_fw_dbg_reg_op { | ||
| 386 | u8 op; | ||
| 387 | u8 reserved[3]; | ||
| 388 | __le32 addr; | ||
| 389 | __le32 val; | ||
| 390 | } __packed; | ||
| 391 | |||
| 392 | /** | ||
| 393 | * enum iwl_fw_dbg_monitor_mode - available monitor recording modes | ||
| 394 | * | ||
| 395 | * @SMEM_MODE: monitor stores the data in SMEM | ||
| 396 | * @EXTERNAL_MODE: monitor stores the data in allocated DRAM | ||
| 397 | * @MARBH_MODE: monitor stores the data in MARBH buffer | ||
| 398 | */ | ||
| 399 | enum iwl_fw_dbg_monitor_mode { | ||
| 400 | SMEM_MODE = 0, | ||
| 401 | EXTERNAL_MODE = 1, | ||
| 402 | MARBH_MODE = 2, | ||
| 403 | }; | ||
| 404 | |||
| 405 | /** | ||
| 406 | * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data | ||
| 407 | * | ||
| 408 | * @version: version of the TLV - currently 0 | ||
| 409 | * @monitor_mode: %enum iwl_fw_dbg_monitor_mode | ||
| 410 | * @base_reg: addr of the base addr register (PRPH) | ||
| 411 | * @end_reg: addr of the end addr register (PRPH) | ||
| 412 | * @write_ptr_reg: the addr of the reg of the write pointer | ||
| 413 | * @wrap_count: the addr of the reg of the wrap_count | ||
| 414 | * @base_shift: shift right of the base addr reg | ||
| 415 | * @end_shift: shift right of the end addr reg | ||
| 416 | * @reg_ops: array of registers operations | ||
| 417 | * | ||
| 418 | * This parses IWL_UCODE_TLV_FW_DBG_DEST | ||
| 419 | */ | ||
| 420 | struct iwl_fw_dbg_dest_tlv { | ||
| 421 | u8 version; | ||
| 422 | u8 monitor_mode; | ||
| 423 | u8 reserved[2]; | ||
| 424 | __le32 base_reg; | ||
| 425 | __le32 end_reg; | ||
| 426 | __le32 write_ptr_reg; | ||
| 427 | __le32 wrap_count; | ||
| 428 | u8 base_shift; | ||
| 429 | u8 end_shift; | ||
| 430 | struct iwl_fw_dbg_reg_op reg_ops[0]; | ||
| 431 | } __packed; | ||
| 432 | |||
| 433 | struct iwl_fw_dbg_conf_hcmd { | ||
| 434 | u8 id; | ||
| 435 | u8 reserved; | ||
| 436 | __le16 len; | ||
| 437 | u8 data[0]; | ||
| 438 | } __packed; | ||
| 439 | |||
| 440 | /** | ||
| 441 | * struct iwl_fw_dbg_trigger - a TLV that describes a debug configuration | ||
| 442 | * | ||
| 443 | * @enabled: is this trigger enabled | ||
| 444 | * @reserved: | ||
| 445 | * @len: length, in bytes, of the %trigger field | ||
| 446 | * @trigger: pointer to a trigger struct | ||
| 447 | */ | ||
| 448 | struct iwl_fw_dbg_trigger { | ||
| 449 | u8 enabled; | ||
| 450 | u8 reserved; | ||
| 451 | u8 len; | ||
| 452 | u8 trigger[0]; | ||
| 453 | } __packed; | ||
| 454 | |||
| 455 | /** | ||
| 456 | * enum iwl_fw_dbg_conf - configurations available | ||
| 457 | * | ||
| 458 | * @FW_DBG_CUSTOM: take this configuration from alive | ||
| 459 | * Note that the trigger is NO-OP for this configuration | ||
| 460 | */ | ||
| 461 | enum iwl_fw_dbg_conf { | ||
| 462 | FW_DBG_CUSTOM = 0, | ||
| 463 | |||
| 464 | /* must be last */ | ||
| 465 | FW_DBG_MAX, | ||
| 466 | FW_DBG_INVALID = 0xff, | ||
| 467 | }; | ||
| 468 | |||
| 469 | /** | ||
| 470 | * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration | ||
| 471 | * | ||
| 472 | * @id: %enum iwl_fw_dbg_conf | ||
| 473 | * @usniffer: should the uSniffer image be used | ||
| 474 | * @num_of_hcmds: how many HCMDs to send are present here | ||
| 475 | * @hcmd: a variable length host command to be sent to apply the configuration. | ||
| 476 | * If there is more than one HCMD to send, they will appear one after the | ||
| 477 | * other and be sent in the order that they appear in. | ||
| 478 | * This parses IWL_UCODE_TLV_FW_DBG_CONF | ||
| 479 | */ | ||
| 480 | struct iwl_fw_dbg_conf_tlv { | ||
| 481 | u8 id; | ||
| 482 | u8 usniffer; | ||
| 483 | u8 reserved; | ||
| 484 | u8 num_of_hcmds; | ||
| 485 | struct iwl_fw_dbg_conf_hcmd hcmd; | ||
| 486 | |||
| 487 | /* struct iwl_fw_dbg_trigger sits after all variable length hcmds */ | ||
| 488 | } __packed; | ||
| 489 | |||
| 180 | #endif /* __iwl_fw_file_h__ */ | 490 | #endif /* __iwl_fw_file_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 1bb5193c5b1b..e6dc3b870949 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -68,90 +70,6 @@ | |||
| 68 | #include "iwl-fw-file.h" | 70 | #include "iwl-fw-file.h" |
| 69 | 71 | ||
| 70 | /** | 72 | /** |
| 71 | * enum iwl_ucode_tlv_flag - ucode API flags | ||
| 72 | * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously | ||
| 73 | * was a separate TLV but moved here to save space. | ||
| 74 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, | ||
| 75 | * treats good CRC threshold as a boolean | ||
| 76 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | ||
| 77 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. | ||
| 78 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | ||
| 79 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD | ||
| 80 | * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan | ||
| 81 | * offload profile config command. | ||
| 82 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | ||
| 83 | * (rather than two) IPv6 addresses | ||
| 84 | * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element | ||
| 85 | * from the probe request template. | ||
| 86 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) | ||
| 87 | * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) | ||
| 88 | * @IWL_UCODE_TLV_FLAGS_P2P_PM: P2P client supports PM as a stand alone MAC | ||
| 89 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and | ||
| 90 | * P2P client interfaces simultaneously if they are in different bindings. | ||
| 91 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_SCM: support power save on BSS station and | ||
| 92 | * P2P client interfaces simultaneously if they are in same bindings. | ||
| 93 | * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD | ||
| 94 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save | ||
| 95 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. | ||
| 96 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients | ||
| 97 | * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. | ||
| 98 | */ | ||
| 99 | enum iwl_ucode_tlv_flag { | ||
| 100 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | ||
| 101 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), | ||
| 102 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | ||
| 103 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), | ||
| 104 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | ||
| 105 | IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), | ||
| 106 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | ||
| 107 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), | ||
| 108 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), | ||
| 109 | IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), | ||
| 110 | IWL_UCODE_TLV_FLAGS_P2P_PM = BIT(21), | ||
| 111 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), | ||
| 112 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM = BIT(23), | ||
| 113 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), | ||
| 114 | IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), | ||
| 115 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), | ||
| 116 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), | ||
| 117 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), | ||
| 118 | }; | ||
| 119 | |||
| 120 | /** | ||
| 121 | * enum iwl_ucode_tlv_api - ucode api | ||
| 122 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | ||
| 123 | * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification | ||
| 124 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex | ||
| 125 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. | ||
| 126 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. | ||
| 127 | * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. | ||
| 128 | */ | ||
| 129 | enum iwl_ucode_tlv_api { | ||
| 130 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | ||
| 131 | IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), | ||
| 132 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | ||
| 133 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), | ||
| 134 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), | ||
| 135 | IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), | ||
| 136 | }; | ||
| 137 | |||
| 138 | /** | ||
| 139 | * enum iwl_ucode_tlv_capa - ucode capabilities | ||
| 140 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | ||
| 141 | */ | ||
| 142 | enum iwl_ucode_tlv_capa { | ||
| 143 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | ||
| 144 | }; | ||
| 145 | |||
| 146 | /* The default calibrate table size if not specified by firmware file */ | ||
| 147 | #define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 | ||
| 148 | #define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 | ||
| 149 | #define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 | ||
| 150 | |||
| 151 | /* The default max probe length if not specified by the firmware file */ | ||
| 152 | #define IWL_DEFAULT_MAX_PROBE_LENGTH 200 | ||
| 153 | |||
| 154 | /** | ||
| 155 | * enum iwl_ucode_type | 73 | * enum iwl_ucode_type |
| 156 | * | 74 | * |
| 157 | * The type of ucode. | 75 | * The type of ucode. |
| @@ -159,11 +77,13 @@ enum iwl_ucode_tlv_capa { | |||
| 159 | * @IWL_UCODE_REGULAR: Normal runtime ucode | 77 | * @IWL_UCODE_REGULAR: Normal runtime ucode |
| 160 | * @IWL_UCODE_INIT: Initial ucode | 78 | * @IWL_UCODE_INIT: Initial ucode |
| 161 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode | 79 | * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode |
| 80 | * @IWL_UCODE_REGULAR_USNIFFER: Normal runtime ucode when using usniffer image | ||
| 162 | */ | 81 | */ |
| 163 | enum iwl_ucode_type { | 82 | enum iwl_ucode_type { |
| 164 | IWL_UCODE_REGULAR, | 83 | IWL_UCODE_REGULAR, |
| 165 | IWL_UCODE_INIT, | 84 | IWL_UCODE_INIT, |
| 166 | IWL_UCODE_WOWLAN, | 85 | IWL_UCODE_WOWLAN, |
| 86 | IWL_UCODE_REGULAR_USNIFFER, | ||
| 167 | IWL_UCODE_TYPE_MAX, | 87 | IWL_UCODE_TYPE_MAX, |
| 168 | }; | 88 | }; |
| 169 | 89 | ||
| @@ -178,14 +98,6 @@ enum iwl_ucode_sec { | |||
| 178 | IWL_UCODE_SECTION_DATA, | 98 | IWL_UCODE_SECTION_DATA, |
| 179 | IWL_UCODE_SECTION_INST, | 99 | IWL_UCODE_SECTION_INST, |
| 180 | }; | 100 | }; |
| 181 | /* | ||
| 182 | * For 16.0 uCode and above, there is no differentiation between sections, | ||
| 183 | * just an offset to the HW address. | ||
| 184 | */ | ||
| 185 | #define IWL_UCODE_SECTION_MAX 12 | ||
| 186 | #define IWL_API_ARRAY_SIZE 1 | ||
| 187 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 | ||
| 188 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC | ||
| 189 | 101 | ||
| 190 | struct iwl_ucode_capabilities { | 102 | struct iwl_ucode_capabilities { |
| 191 | u32 max_probe_length; | 103 | u32 max_probe_length; |
| @@ -205,7 +117,6 @@ struct fw_desc { | |||
| 205 | 117 | ||
| 206 | struct fw_img { | 118 | struct fw_img { |
| 207 | struct fw_desc sec[IWL_UCODE_SECTION_MAX]; | 119 | struct fw_desc sec[IWL_UCODE_SECTION_MAX]; |
| 208 | bool is_secure; | ||
| 209 | bool is_dual_cpus; | 120 | bool is_dual_cpus; |
| 210 | }; | 121 | }; |
| 211 | 122 | ||
| @@ -214,66 +125,6 @@ struct iwl_sf_region { | |||
| 214 | u32 size; | 125 | u32 size; |
| 215 | }; | 126 | }; |
| 216 | 127 | ||
| 217 | /* uCode version contains 4 values: Major/Minor/API/Serial */ | ||
| 218 | #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) | ||
| 219 | #define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) | ||
| 220 | #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) | ||
| 221 | #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Calibration control struct. | ||
| 225 | * Sent as part of the phy configuration command. | ||
| 226 | * @flow_trigger: bitmap for which calibrations to perform according to | ||
| 227 | * flow triggers. | ||
| 228 | * @event_trigger: bitmap for which calibrations to perform according to | ||
| 229 | * event triggers. | ||
| 230 | */ | ||
| 231 | struct iwl_tlv_calib_ctrl { | ||
| 232 | __le32 flow_trigger; | ||
| 233 | __le32 event_trigger; | ||
| 234 | } __packed; | ||
| 235 | |||
| 236 | enum iwl_fw_phy_cfg { | ||
| 237 | FW_PHY_CFG_RADIO_TYPE_POS = 0, | ||
| 238 | FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, | ||
| 239 | FW_PHY_CFG_RADIO_STEP_POS = 2, | ||
| 240 | FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, | ||
| 241 | FW_PHY_CFG_RADIO_DASH_POS = 4, | ||
| 242 | FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, | ||
| 243 | FW_PHY_CFG_TX_CHAIN_POS = 16, | ||
| 244 | FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, | ||
| 245 | FW_PHY_CFG_RX_CHAIN_POS = 20, | ||
| 246 | FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, | ||
| 247 | }; | ||
| 248 | |||
| 249 | #define IWL_UCODE_MAX_CS 1 | ||
| 250 | |||
| 251 | /** | ||
| 252 | * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. | ||
| 253 | * @cipher: a cipher suite selector | ||
| 254 | * @flags: cipher scheme flags (currently reserved for a future use) | ||
| 255 | * @hdr_len: a size of MPDU security header | ||
| 256 | * @pn_len: a size of PN | ||
| 257 | * @pn_off: an offset of pn from the beginning of the security header | ||
| 258 | * @key_idx_off: an offset of key index byte in the security header | ||
| 259 | * @key_idx_mask: a bit mask of key_idx bits | ||
| 260 | * @key_idx_shift: bit shift needed to get key_idx | ||
| 261 | * @mic_len: mic length in bytes | ||
| 262 | * @hw_cipher: a HW cipher index used in host commands | ||
| 263 | */ | ||
| 264 | struct iwl_fw_cipher_scheme { | ||
| 265 | __le32 cipher; | ||
| 266 | u8 flags; | ||
| 267 | u8 hdr_len; | ||
| 268 | u8 pn_len; | ||
| 269 | u8 pn_off; | ||
| 270 | u8 key_idx_off; | ||
| 271 | u8 key_idx_mask; | ||
| 272 | u8 key_idx_shift; | ||
| 273 | u8 mic_len; | ||
| 274 | u8 hw_cipher; | ||
| 275 | } __packed; | ||
| 276 | |||
| 277 | /** | 128 | /** |
| 278 | * struct iwl_fw_cscheme_list - a cipher scheme list | 129 | * struct iwl_fw_cscheme_list - a cipher scheme list |
| 279 | * @size: a number of entries | 130 | * @size: a number of entries |
| @@ -300,6 +151,11 @@ struct iwl_fw_cscheme_list { | |||
| 300 | * @inst_errlog_ptr: error log offfset for runtime ucode. | 151 | * @inst_errlog_ptr: error log offfset for runtime ucode. |
| 301 | * @mvm_fw: indicates this is MVM firmware | 152 | * @mvm_fw: indicates this is MVM firmware |
| 302 | * @cipher_scheme: optional external cipher scheme. | 153 | * @cipher_scheme: optional external cipher scheme. |
| 154 | * @human_readable: human readable version | ||
| 155 | * @dbg_dest_tlv: points to the destination TLV for debug | ||
| 156 | * @dbg_conf_tlv: array of pointers to configuration TLVs for debug | ||
| 157 | * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries | ||
| 158 | * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv | ||
| 303 | */ | 159 | */ |
| 304 | struct iwl_fw { | 160 | struct iwl_fw { |
| 305 | u32 ucode_ver; | 161 | u32 ucode_ver; |
| @@ -324,6 +180,68 @@ struct iwl_fw { | |||
| 324 | 180 | ||
| 325 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; | 181 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; |
| 326 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; | 182 | u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; |
| 183 | |||
| 184 | struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
| 185 | struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
| 186 | size_t dbg_conf_tlv_len[FW_DBG_MAX]; | ||
| 187 | |||
| 188 | u8 dbg_dest_reg_num; | ||
| 327 | }; | 189 | }; |
| 328 | 190 | ||
| 191 | static inline const char *get_fw_dbg_mode_string(int mode) | ||
| 192 | { | ||
| 193 | switch (mode) { | ||
| 194 | case SMEM_MODE: | ||
| 195 | return "SMEM"; | ||
| 196 | case EXTERNAL_MODE: | ||
| 197 | return "EXTERNAL_DRAM"; | ||
| 198 | case MARBH_MODE: | ||
| 199 | return "MARBH"; | ||
| 200 | default: | ||
| 201 | return "UNKNOWN"; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | static inline const struct iwl_fw_dbg_trigger * | ||
| 206 | iwl_fw_dbg_conf_get_trigger(const struct iwl_fw *fw, u8 id) | ||
| 207 | { | ||
| 208 | const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; | ||
| 209 | u8 *ptr; | ||
| 210 | int i; | ||
| 211 | |||
| 212 | if (!conf_tlv) | ||
| 213 | return NULL; | ||
| 214 | |||
| 215 | ptr = (void *)&conf_tlv->hcmd; | ||
| 216 | for (i = 0; i < conf_tlv->num_of_hcmds; i++) { | ||
| 217 | ptr += sizeof(conf_tlv->hcmd); | ||
| 218 | ptr += le16_to_cpu(conf_tlv->hcmd.len); | ||
| 219 | } | ||
| 220 | |||
| 221 | return (const struct iwl_fw_dbg_trigger *)ptr; | ||
| 222 | } | ||
| 223 | |||
| 224 | static inline bool | ||
| 225 | iwl_fw_dbg_conf_enabled(const struct iwl_fw *fw, u8 id) | ||
| 226 | { | ||
| 227 | const struct iwl_fw_dbg_trigger *trigger = | ||
| 228 | iwl_fw_dbg_conf_get_trigger(fw, id); | ||
| 229 | |||
| 230 | if (!trigger) | ||
| 231 | return false; | ||
| 232 | |||
| 233 | return trigger->enabled; | ||
| 234 | } | ||
| 235 | |||
| 236 | static inline bool | ||
| 237 | iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id) | ||
| 238 | { | ||
| 239 | const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; | ||
| 240 | |||
| 241 | if (!conf_tlv) | ||
| 242 | return false; | ||
| 243 | |||
| 244 | return conf_tlv->usniffer; | ||
| 245 | } | ||
| 246 | |||
| 329 | #endif /* __iwl_fw_h__ */ | 247 | #endif /* __iwl_fw_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 5eef4ae7333b..7a2cbf6f90db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c | |||
| @@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans) | |||
| 193 | * DEVICE_SET_NMI_8000B_REG - is used. | 193 | * DEVICE_SET_NMI_8000B_REG - is used. |
| 194 | */ | 194 | */ |
| 195 | if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || | 195 | if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || |
| 196 | ((trans->hw_rev & 0xc) == 0x0)) | 196 | (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) |
| 197 | iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); | 197 | iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); |
| 198 | else | 198 | else |
| 199 | iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, | 199 | iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 354255f08754..06e02fcd6f7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -323,6 +325,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
| 323 | { | 325 | { |
| 324 | int num_rx_ants = num_of_ant(rx_chains); | 326 | int num_rx_ants = num_of_ant(rx_chains); |
| 325 | int num_tx_ants = num_of_ant(tx_chains); | 327 | int num_tx_ants = num_of_ant(tx_chains); |
| 328 | unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?: | ||
| 329 | IEEE80211_VHT_MAX_AMPDU_1024K); | ||
| 326 | 330 | ||
| 327 | vht_cap->vht_supported = true; | 331 | vht_cap->vht_supported = true; |
| 328 | 332 | ||
| @@ -330,7 +334,11 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
| 330 | IEEE80211_VHT_CAP_RXSTBC_1 | | 334 | IEEE80211_VHT_CAP_RXSTBC_1 | |
| 331 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | 335 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
| 332 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | | 336 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | |
| 333 | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | 337 | max_ampdu_exponent << |
| 338 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
| 339 | |||
| 340 | if (cfg->ht_params->ldpc) | ||
| 341 | vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; | ||
| 334 | 342 | ||
| 335 | if (num_tx_ants > 1) | 343 | if (num_tx_ants > 1) |
| 336 | vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; | 344 | vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 99785c892f96..17de6d46222a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -136,7 +138,8 @@ struct iwl_cfg; | |||
| 136 | * @nic_config: configure NIC, called before firmware is started. | 138 | * @nic_config: configure NIC, called before firmware is started. |
| 137 | * May sleep | 139 | * May sleep |
| 138 | * @wimax_active: invoked when WiMax becomes active. May sleep | 140 | * @wimax_active: invoked when WiMax becomes active. May sleep |
| 139 | * @enter_d0i3: configure the fw to enter d0i3. May sleep. | 141 | * @enter_d0i3: configure the fw to enter d0i3. return 1 to indicate d0i3 |
| 142 | * entrance is aborted (e.g. due to held reference). May sleep. | ||
| 140 | * @exit_d0i3: configure the fw to exit d0i3. May sleep. | 143 | * @exit_d0i3: configure the fw to exit d0i3. May sleep. |
| 141 | */ | 144 | */ |
| 142 | struct iwl_op_mode_ops { | 145 | struct iwl_op_mode_ops { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 47033a35a402..2df51eab1348 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -281,6 +283,7 @@ | |||
| 281 | #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) | 283 | #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) |
| 282 | #define SCD_AGGR_SEL (SCD_BASE + 0x248) | 284 | #define SCD_AGGR_SEL (SCD_BASE + 0x248) |
| 283 | #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) | 285 | #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) |
| 286 | #define SCD_EN_CTRL (SCD_BASE + 0x254) | ||
| 284 | 287 | ||
| 285 | static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) | 288 | static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) |
| 286 | { | 289 | { |
| @@ -319,6 +322,7 @@ enum secure_boot_config_reg { | |||
| 319 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, | 322 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, |
| 320 | }; | 323 | }; |
| 321 | 324 | ||
| 325 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0 (0xA01E30) | ||
| 322 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) | 326 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) |
| 323 | #define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) | 327 | #define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) |
| 324 | enum secure_boot_status_reg { | 328 | enum secure_boot_status_reg { |
| @@ -330,6 +334,7 @@ enum secure_boot_status_reg { | |||
| 330 | LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, | 334 | LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, |
| 331 | }; | 335 | }; |
| 332 | 336 | ||
| 337 | #define FH_UCODE_LOAD_STATUS (0x1AF0) | ||
| 333 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) | 338 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) |
| 334 | enum secure_load_status_reg { | 339 | enum secure_load_status_reg { |
| 335 | LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, | 340 | LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, |
| @@ -349,7 +354,7 @@ enum secure_load_status_reg { | |||
| 349 | #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) | 354 | #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) |
| 350 | #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) | 355 | #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) |
| 351 | 356 | ||
| 352 | #define LMPM_SECURE_TIME_OUT (100) | 357 | #define LMPM_SECURE_TIME_OUT (100) /* 10 micro */ |
| 353 | 358 | ||
| 354 | /* Rx FIFO */ | 359 | /* Rx FIFO */ |
| 355 | #define RXF_SIZE_ADDR (0xa00c88) | 360 | #define RXF_SIZE_ADDR (0xa00c88) |
| @@ -365,4 +370,10 @@ enum secure_load_status_reg { | |||
| 365 | #define MON_BUFF_WRPTR (0xa03c44) | 370 | #define MON_BUFF_WRPTR (0xa03c44) |
| 366 | #define MON_BUFF_CYCLE_CNT (0xa03c48) | 371 | #define MON_BUFF_CYCLE_CNT (0xa03c48) |
| 367 | 372 | ||
| 373 | /* FW chicken bits */ | ||
| 374 | #define LMPM_CHICK 0xA01FF8 | ||
| 375 | enum { | ||
| 376 | LMPM_CHICK_EXTENDED_ADDR_SPACE = BIT(0), | ||
| 377 | }; | ||
| 378 | |||
| 368 | #endif /* __iwl_prph_h__ */ | 379 | #endif /* __iwl_prph_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h new file mode 100644 index 000000000000..6c622b21bba7 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-scd.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * | ||
| 3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
| 4 | * redistributing this file, you may do so under either license. | ||
| 5 | * | ||
| 6 | * GPL LICENSE SUMMARY | ||
| 7 | * | ||
| 8 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of version 2 of the GNU General Public License as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
| 22 | * USA | ||
| 23 | * | ||
| 24 | * The full GNU General Public License is included in this distribution | ||
| 25 | * in the file called COPYING. | ||
| 26 | * | ||
| 27 | * Contact Information: | ||
| 28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
| 29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
| 30 | * | ||
| 31 | * BSD LICENSE | ||
| 32 | * | ||
| 33 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | ||
| 35 | * | ||
| 36 | * Redistribution and use in source and binary forms, with or without | ||
| 37 | * modification, are permitted provided that the following conditions | ||
| 38 | * are met: | ||
| 39 | * | ||
| 40 | * * Redistributions of source code must retain the above copyright | ||
| 41 | * notice, this list of conditions and the following disclaimer. | ||
| 42 | * * Redistributions in binary form must reproduce the above copyright | ||
| 43 | * notice, this list of conditions and the following disclaimer in | ||
| 44 | * the documentation and/or other materials provided with the | ||
| 45 | * distribution. | ||
| 46 | * * Neither the name Intel Corporation nor the names of its | ||
| 47 | * contributors may be used to endorse or promote products derived | ||
| 48 | * from this software without specific prior written permission. | ||
| 49 | * | ||
| 50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 61 | * | ||
| 62 | *****************************************************************************/ | ||
| 63 | |||
| 64 | #ifndef __iwl_scd_h__ | ||
| 65 | #define __iwl_scd_h__ | ||
| 66 | |||
| 67 | #include "iwl-trans.h" | ||
| 68 | #include "iwl-io.h" | ||
| 69 | #include "iwl-prph.h" | ||
| 70 | |||
| 71 | |||
| 72 | static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, | ||
| 73 | u16 txq_id) | ||
| 74 | { | ||
| 75 | iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), | ||
| 76 | (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| | ||
| 77 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, | ||
| 81 | u16 txq_id) | ||
| 82 | { | ||
| 83 | iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); | ||
| 84 | } | ||
| 85 | |||
| 86 | static inline void iwl_scd_txq_enable_agg(struct iwl_trans *trans, | ||
| 87 | u16 txq_id) | ||
| 88 | { | ||
| 89 | iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); | ||
| 90 | } | ||
| 91 | |||
| 92 | static inline void iwl_scd_txq_disable_agg(struct iwl_trans *trans, | ||
| 93 | u16 txq_id) | ||
| 94 | { | ||
| 95 | iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); | ||
| 96 | } | ||
| 97 | |||
| 98 | static inline void iwl_scd_disable_agg(struct iwl_trans *trans) | ||
| 99 | { | ||
| 100 | iwl_set_bits_prph(trans, SCD_AGGR_SEL, 0); | ||
| 101 | } | ||
| 102 | |||
| 103 | static inline void iwl_scd_activate_fifos(struct iwl_trans *trans) | ||
| 104 | { | ||
| 105 | iwl_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7)); | ||
| 106 | } | ||
| 107 | |||
| 108 | static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans) | ||
| 109 | { | ||
| 110 | iwl_write_prph(trans, SCD_TXFACT, 0); | ||
| 111 | } | ||
| 112 | |||
| 113 | static inline void iwl_scd_enable_set_active(struct iwl_trans *trans, | ||
| 114 | u32 value) | ||
| 115 | { | ||
| 116 | iwl_write_prph(trans, SCD_EN_CTRL, value); | ||
| 117 | } | ||
| 118 | #endif | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 656371a668da..028408a6ecba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -375,6 +377,7 @@ enum iwl_trans_status { | |||
| 375 | * if unset 4k will be the RX buffer size | 377 | * if unset 4k will be the RX buffer size |
| 376 | * @bc_table_dword: set to true if the BC table expects the byte count to be | 378 | * @bc_table_dword: set to true if the BC table expects the byte count to be |
| 377 | * in DWORD (as opposed to bytes) | 379 | * in DWORD (as opposed to bytes) |
| 380 | * @scd_set_active: should the transport configure the SCD for HCMD queue | ||
| 378 | * @queue_watchdog_timeout: time (in ms) after which queues | 381 | * @queue_watchdog_timeout: time (in ms) after which queues |
| 379 | * are considered stuck and will trigger device restart | 382 | * are considered stuck and will trigger device restart |
| 380 | * @command_names: array of command names, must be 256 entries | 383 | * @command_names: array of command names, must be 256 entries |
| @@ -390,6 +393,7 @@ struct iwl_trans_config { | |||
| 390 | 393 | ||
| 391 | bool rx_buf_size_8k; | 394 | bool rx_buf_size_8k; |
| 392 | bool bc_table_dword; | 395 | bool bc_table_dword; |
| 396 | bool scd_set_active; | ||
| 393 | unsigned int queue_watchdog_timeout; | 397 | unsigned int queue_watchdog_timeout; |
| 394 | const char *const *command_names; | 398 | const char *const *command_names; |
| 395 | }; | 399 | }; |
| @@ -401,6 +405,14 @@ struct iwl_trans_dump_data { | |||
| 401 | 405 | ||
| 402 | struct iwl_trans; | 406 | struct iwl_trans; |
| 403 | 407 | ||
| 408 | struct iwl_trans_txq_scd_cfg { | ||
| 409 | u8 fifo; | ||
| 410 | s8 sta_id; | ||
| 411 | u8 tid; | ||
| 412 | bool aggregate; | ||
| 413 | int frame_limit; | ||
| 414 | }; | ||
| 415 | |||
| 404 | /** | 416 | /** |
| 405 | * struct iwl_trans_ops - transport specific operations | 417 | * struct iwl_trans_ops - transport specific operations |
| 406 | * | 418 | * |
| @@ -437,7 +449,9 @@ struct iwl_trans; | |||
| 437 | * Must be atomic | 449 | * Must be atomic |
| 438 | * @txq_enable: setup a queue. To setup an AC queue, use the | 450 | * @txq_enable: setup a queue. To setup an AC queue, use the |
| 439 | * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before | 451 | * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before |
| 440 | * this one. The op_mode must not configure the HCMD queue. May sleep. | 452 | * this one. The op_mode must not configure the HCMD queue. The scheduler |
| 453 | * configuration may be %NULL, in which case the hardware will not be | ||
| 454 | * configured. May sleep. | ||
| 441 | * @txq_disable: de-configure a Tx queue to send AMPDUs | 455 | * @txq_disable: de-configure a Tx queue to send AMPDUs |
| 442 | * Must be atomic | 456 | * Must be atomic |
| 443 | * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. | 457 | * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. |
| @@ -492,9 +506,10 @@ struct iwl_trans_ops { | |||
| 492 | void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, | 506 | void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, |
| 493 | struct sk_buff_head *skbs); | 507 | struct sk_buff_head *skbs); |
| 494 | 508 | ||
| 495 | void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo, | 509 | void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, |
| 496 | int sta_id, int tid, int frame_limit, u16 ssn); | 510 | const struct iwl_trans_txq_scd_cfg *cfg); |
| 497 | void (*txq_disable)(struct iwl_trans *trans, int queue); | 511 | void (*txq_disable)(struct iwl_trans *trans, int queue, |
| 512 | bool configure_scd); | ||
| 498 | 513 | ||
| 499 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); | 514 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); |
| 500 | int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); | 515 | int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); |
| @@ -519,10 +534,10 @@ struct iwl_trans_ops { | |||
| 519 | u32 value); | 534 | u32 value); |
| 520 | void (*ref)(struct iwl_trans *trans); | 535 | void (*ref)(struct iwl_trans *trans); |
| 521 | void (*unref)(struct iwl_trans *trans); | 536 | void (*unref)(struct iwl_trans *trans); |
| 537 | void (*suspend)(struct iwl_trans *trans); | ||
| 538 | void (*resume)(struct iwl_trans *trans); | ||
| 522 | 539 | ||
| 523 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
| 524 | struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); | 540 | struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); |
| 525 | #endif | ||
| 526 | }; | 541 | }; |
| 527 | 542 | ||
| 528 | /** | 543 | /** |
| @@ -548,6 +563,7 @@ enum iwl_trans_state { | |||
| 548 | * Set during transport allocation. | 563 | * Set during transport allocation. |
| 549 | * @hw_id_str: a string with info about HW ID. Set during transport allocation. | 564 | * @hw_id_str: a string with info about HW ID. Set during transport allocation. |
| 550 | * @pm_support: set to true in start_hw if link pm is supported | 565 | * @pm_support: set to true in start_hw if link pm is supported |
| 566 | * @ltr_enabled: set to true if the LTR is enabled | ||
| 551 | * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. | 567 | * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. |
| 552 | * The user should use iwl_trans_{alloc,free}_tx_cmd. | 568 | * The user should use iwl_trans_{alloc,free}_tx_cmd. |
| 553 | * @dev_cmd_headroom: room needed for the transport's private use before the | 569 | * @dev_cmd_headroom: room needed for the transport's private use before the |
| @@ -558,6 +574,9 @@ enum iwl_trans_state { | |||
| 558 | * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the | 574 | * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the |
| 559 | * start of the 802.11 header in the @rx_mpdu_cmd | 575 | * start of the 802.11 header in the @rx_mpdu_cmd |
| 560 | * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) | 576 | * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) |
| 577 | * @dbg_dest_tlv: points to the destination TLV for debug | ||
| 578 | * @dbg_conf_tlv: array of pointers to configuration TLVs for debug | ||
| 579 | * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv | ||
| 561 | */ | 580 | */ |
| 562 | struct iwl_trans { | 581 | struct iwl_trans { |
| 563 | const struct iwl_trans_ops *ops; | 582 | const struct iwl_trans_ops *ops; |
| @@ -574,6 +593,7 @@ struct iwl_trans { | |||
| 574 | u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; | 593 | u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; |
| 575 | 594 | ||
| 576 | bool pm_support; | 595 | bool pm_support; |
| 596 | bool ltr_enabled; | ||
| 577 | 597 | ||
| 578 | /* The following fields are internal only */ | 598 | /* The following fields are internal only */ |
| 579 | struct kmem_cache *dev_cmd_pool; | 599 | struct kmem_cache *dev_cmd_pool; |
| @@ -588,6 +608,10 @@ struct iwl_trans { | |||
| 588 | 608 | ||
| 589 | u64 dflt_pwr_limit; | 609 | u64 dflt_pwr_limit; |
| 590 | 610 | ||
| 611 | const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; | ||
| 612 | const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; | ||
| 613 | u8 dbg_dest_reg_num; | ||
| 614 | |||
| 591 | /* pointer to trans specific struct */ | 615 | /* pointer to trans specific struct */ |
| 592 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 616 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
| 593 | char trans_specific[0] __aligned(sizeof(void *)); | 617 | char trans_specific[0] __aligned(sizeof(void *)); |
| @@ -687,7 +711,18 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) | |||
| 687 | trans->ops->unref(trans); | 711 | trans->ops->unref(trans); |
| 688 | } | 712 | } |
| 689 | 713 | ||
| 690 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 714 | static inline void iwl_trans_suspend(struct iwl_trans *trans) |
| 715 | { | ||
| 716 | if (trans->ops->suspend) | ||
| 717 | trans->ops->suspend(trans); | ||
| 718 | } | ||
| 719 | |||
| 720 | static inline void iwl_trans_resume(struct iwl_trans *trans) | ||
| 721 | { | ||
| 722 | if (trans->ops->resume) | ||
| 723 | trans->ops->resume(trans); | ||
| 724 | } | ||
| 725 | |||
| 691 | static inline struct iwl_trans_dump_data * | 726 | static inline struct iwl_trans_dump_data * |
| 692 | iwl_trans_dump_data(struct iwl_trans *trans) | 727 | iwl_trans_dump_data(struct iwl_trans *trans) |
| 693 | { | 728 | { |
| @@ -695,7 +730,6 @@ iwl_trans_dump_data(struct iwl_trans *trans) | |||
| 695 | return NULL; | 730 | return NULL; |
| 696 | return trans->ops->dump_data(trans); | 731 | return trans->ops->dump_data(trans); |
| 697 | } | 732 | } |
| 698 | #endif | ||
| 699 | 733 | ||
| 700 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 734 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
| 701 | struct iwl_host_cmd *cmd) | 735 | struct iwl_host_cmd *cmd) |
| @@ -766,29 +800,51 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, | |||
| 766 | trans->ops->reclaim(trans, queue, ssn, skbs); | 800 | trans->ops->reclaim(trans, queue, ssn, skbs); |
| 767 | } | 801 | } |
| 768 | 802 | ||
| 769 | static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue) | 803 | static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, |
| 804 | bool configure_scd) | ||
| 770 | { | 805 | { |
| 771 | trans->ops->txq_disable(trans, queue); | 806 | trans->ops->txq_disable(trans, queue, configure_scd); |
| 772 | } | 807 | } |
| 773 | 808 | ||
| 774 | static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, | 809 | static inline void |
| 775 | int fifo, int sta_id, int tid, | 810 | iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, |
| 776 | int frame_limit, u16 ssn) | 811 | const struct iwl_trans_txq_scd_cfg *cfg) |
| 777 | { | 812 | { |
| 778 | might_sleep(); | 813 | might_sleep(); |
| 779 | 814 | ||
| 780 | if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) | 815 | if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) |
| 781 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); | 816 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); |
| 782 | 817 | ||
| 783 | trans->ops->txq_enable(trans, queue, fifo, sta_id, tid, | 818 | trans->ops->txq_enable(trans, queue, ssn, cfg); |
| 784 | frame_limit, ssn); | 819 | } |
| 820 | |||
| 821 | static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, | ||
| 822 | int fifo, int sta_id, int tid, | ||
| 823 | int frame_limit, u16 ssn) | ||
| 824 | { | ||
| 825 | struct iwl_trans_txq_scd_cfg cfg = { | ||
| 826 | .fifo = fifo, | ||
| 827 | .sta_id = sta_id, | ||
| 828 | .tid = tid, | ||
| 829 | .frame_limit = frame_limit, | ||
| 830 | .aggregate = sta_id >= 0, | ||
| 831 | }; | ||
| 832 | |||
| 833 | iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg); | ||
| 785 | } | 834 | } |
| 786 | 835 | ||
| 787 | static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, | 836 | static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, |
| 788 | int fifo) | 837 | int fifo) |
| 789 | { | 838 | { |
| 790 | iwl_trans_txq_enable(trans, queue, fifo, -1, | 839 | struct iwl_trans_txq_scd_cfg cfg = { |
| 791 | IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); | 840 | .fifo = fifo, |
| 841 | .sta_id = -1, | ||
| 842 | .tid = IWL_MAX_TID_COUNT, | ||
| 843 | .frame_limit = IWL_FRAME_LIMIT, | ||
| 844 | .aggregate = false, | ||
| 845 | }; | ||
| 846 | |||
| 847 | iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); | ||
| 792 | } | 848 | } |
| 793 | 849 | ||
| 794 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, | 850 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index a28235913c2c..2d7c3ea3c4f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
| @@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o | |||
| 3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o | 3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o |
| 4 | iwlmvm-y += scan.o time-event.o rs.o | 4 | iwlmvm-y += scan.o time-event.o rs.o |
| 5 | iwlmvm-y += power.o coex.o coex_legacy.o | 5 | iwlmvm-y += power.o coex.o coex_legacy.o |
| 6 | iwlmvm-y += tt.o offloading.o | 6 | iwlmvm-y += tt.o offloading.o tdls.o |
| 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o | 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o |
| 8 | iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o | 8 | iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o |
| 9 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | 9 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o |
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index ce71625f497f..a3bfda45d9e6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -70,8 +72,6 @@ | |||
| 70 | #include "mvm.h" | 72 | #include "mvm.h" |
| 71 | #include "iwl-debug.h" | 73 | #include "iwl-debug.h" |
| 72 | 74 | ||
| 73 | #define BT_ANTENNA_COUPLING_THRESHOLD (30) | ||
| 74 | |||
| 75 | const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { | 75 | const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { |
| 76 | [BT_KILL_MSK_DEFAULT] = 0xfffffc00, | 76 | [BT_KILL_MSK_DEFAULT] = 0xfffffc00, |
| 77 | [BT_KILL_MSK_NEVER] = 0xffffffff, | 77 | [BT_KILL_MSK_NEVER] = 0xffffffff, |
| @@ -300,11 +300,6 @@ static const __le64 iwl_ci_mask[][3] = { | |||
| 300 | }, | 300 | }, |
| 301 | }; | 301 | }; |
| 302 | 302 | ||
| 303 | static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { | ||
| 304 | cpu_to_le32(0x28412201), | ||
| 305 | cpu_to_le32(0x11118451), | ||
| 306 | }; | ||
| 307 | |||
| 308 | struct corunning_block_luts { | 303 | struct corunning_block_luts { |
| 309 | u8 range; | 304 | u8 range; |
| 310 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; | 305 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; |
| @@ -603,7 +598,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
| 603 | 598 | ||
| 604 | bt_cmd->max_kill = cpu_to_le32(5); | 599 | bt_cmd->max_kill = cpu_to_le32(5); |
| 605 | bt_cmd->bt4_antenna_isolation_thr = | 600 | bt_cmd->bt4_antenna_isolation_thr = |
| 606 | cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD); | 601 | cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS); |
| 607 | bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); | 602 | bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); |
| 608 | bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); | 603 | bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); |
| 609 | bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); | 604 | bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); |
| @@ -636,8 +631,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
| 636 | 631 | ||
| 637 | memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, | 632 | memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, |
| 638 | sizeof(iwl_bt_prio_boost)); | 633 | sizeof(iwl_bt_prio_boost)); |
| 639 | memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut, | 634 | bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); |
| 640 | sizeof(iwl_bt_mprio_lut)); | 635 | bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); |
| 641 | 636 | ||
| 642 | send_cmd: | 637 | send_cmd: |
| 643 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 638 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
| @@ -1142,8 +1137,28 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | |||
| 1142 | return lut_type != BT_COEX_LOOSE_LUT; | 1137 | return lut_type != BT_COEX_LOOSE_LUT; |
| 1143 | } | 1138 | } |
| 1144 | 1139 | ||
| 1140 | bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) | ||
| 1141 | { | ||
| 1142 | /* there is no other antenna, shared antenna is always available */ | ||
| 1143 | if (mvm->cfg->bt_shared_single_ant) | ||
| 1144 | return true; | ||
| 1145 | |||
| 1146 | if (ant & mvm->cfg->non_shared_ant) | ||
| 1147 | return true; | ||
| 1148 | |||
| 1149 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) | ||
| 1150 | return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); | ||
| 1151 | |||
| 1152 | return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | ||
| 1153 | BT_HIGH_TRAFFIC; | ||
| 1154 | } | ||
| 1155 | |||
| 1145 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) | 1156 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) |
| 1146 | { | 1157 | { |
| 1158 | /* there is no other antenna, shared antenna is always available */ | ||
| 1159 | if (mvm->cfg->bt_shared_single_ant) | ||
| 1160 | return true; | ||
| 1161 | |||
| 1147 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) | 1162 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) |
| 1148 | return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); | 1163 | return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); |
| 1149 | 1164 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index a3be33359927..b3210cfbecc8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -100,8 +102,6 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { | |||
| 100 | 102 | ||
| 101 | #undef EVENT_PRIO_ANT | 103 | #undef EVENT_PRIO_ANT |
| 102 | 104 | ||
| 103 | #define BT_ANTENNA_COUPLING_THRESHOLD (30) | ||
| 104 | |||
| 105 | static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) | 105 | static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) |
| 106 | { | 106 | { |
| 107 | if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) | 107 | if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) |
| @@ -288,11 +288,6 @@ static const __le64 iwl_ci_mask[][3] = { | |||
| 288 | }, | 288 | }, |
| 289 | }; | 289 | }; |
| 290 | 290 | ||
| 291 | static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { | ||
| 292 | cpu_to_le32(0x28412201), | ||
| 293 | cpu_to_le32(0x11118451), | ||
| 294 | }; | ||
| 295 | |||
| 296 | struct corunning_block_luts { | 291 | struct corunning_block_luts { |
| 297 | u8 range; | 292 | u8 range; |
| 298 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; | 293 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; |
| @@ -591,7 +586,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
| 591 | } | 586 | } |
| 592 | 587 | ||
| 593 | bt_cmd->max_kill = 5; | 588 | bt_cmd->max_kill = 5; |
| 594 | bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; | 589 | bt_cmd->bt4_antenna_isolation_thr = |
| 590 | IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS; | ||
| 595 | bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; | 591 | bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; |
| 596 | bt_cmd->bt4_tx_tx_delta_freq_thr = 15; | 592 | bt_cmd->bt4_tx_tx_delta_freq_thr = 15; |
| 597 | bt_cmd->bt4_tx_rx_max_freq0 = 15; | 593 | bt_cmd->bt4_tx_rx_max_freq0 = 15; |
| @@ -616,7 +612,9 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
| 616 | BT_VALID_ANT_ISOLATION_THRS | | 612 | BT_VALID_ANT_ISOLATION_THRS | |
| 617 | BT_VALID_TXTX_DELTA_FREQ_THRS | | 613 | BT_VALID_TXTX_DELTA_FREQ_THRS | |
| 618 | BT_VALID_TXRX_MAX_FREQ_0 | | 614 | BT_VALID_TXRX_MAX_FREQ_0 | |
| 619 | BT_VALID_SYNC_TO_SCO); | 615 | BT_VALID_SYNC_TO_SCO | |
| 616 | BT_VALID_TTC | | ||
| 617 | BT_VALID_RRC); | ||
| 620 | 618 | ||
| 621 | if (IWL_MVM_BT_COEX_SYNC2SCO) | 619 | if (IWL_MVM_BT_COEX_SYNC2SCO) |
| 622 | bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); | 620 | bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); |
| @@ -632,6 +630,12 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
| 632 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); | 630 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); |
| 633 | } | 631 | } |
| 634 | 632 | ||
| 633 | if (IWL_MVM_BT_COEX_TTC) | ||
| 634 | bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC); | ||
| 635 | |||
| 636 | if (IWL_MVM_BT_COEX_RRC) | ||
| 637 | bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC); | ||
| 638 | |||
| 635 | if (mvm->cfg->bt_shared_single_ant) | 639 | if (mvm->cfg->bt_shared_single_ant) |
| 636 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, | 640 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, |
| 637 | sizeof(iwl_single_shared_ant)); | 641 | sizeof(iwl_single_shared_ant)); |
| @@ -647,8 +651,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
| 647 | 651 | ||
| 648 | memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, | 652 | memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, |
| 649 | sizeof(iwl_bt_prio_boost)); | 653 | sizeof(iwl_bt_prio_boost)); |
| 650 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, | 654 | bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); |
| 651 | sizeof(iwl_bt_mprio_lut)); | 655 | bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); |
| 652 | 656 | ||
| 653 | send_cmd: | 657 | send_cmd: |
| 654 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); | 658 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); |
| @@ -828,6 +832,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
| 828 | if (!vif->bss_conf.assoc) | 832 | if (!vif->bss_conf.assoc) |
| 829 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 833 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
| 830 | 834 | ||
| 835 | if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id)) | ||
| 836 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
| 837 | |||
| 831 | IWL_DEBUG_COEX(data->mvm, | 838 | IWL_DEBUG_COEX(data->mvm, |
| 832 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", | 839 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", |
| 833 | mvmvif->id, data->notif->bt_status, bt_activity_grading, | 840 | mvmvif->id, data->notif->bt_status, bt_activity_grading, |
| @@ -1160,6 +1167,12 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, | |||
| 1160 | return lut_type != BT_COEX_LOOSE_LUT; | 1167 | return lut_type != BT_COEX_LOOSE_LUT; |
| 1161 | } | 1168 | } |
| 1162 | 1169 | ||
| 1170 | bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant) | ||
| 1171 | { | ||
| 1172 | u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); | ||
| 1173 | return ag < BT_HIGH_TRAFFIC; | ||
| 1174 | } | ||
| 1175 | |||
| 1163 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) | 1176 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) |
| 1164 | { | 1177 | { |
| 1165 | u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); | 1178 | u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index ca79f7160573..3bd93476ec1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -63,12 +65,18 @@ | |||
| 63 | #ifndef __MVM_CONSTANTS_H | 65 | #ifndef __MVM_CONSTANTS_H |
| 64 | #define __MVM_CONSTANTS_H | 66 | #define __MVM_CONSTANTS_H |
| 65 | 67 | ||
| 68 | #include <linux/ieee80211.h> | ||
| 69 | |||
| 66 | #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) | 70 | #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) |
| 67 | #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) | 71 | #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) |
| 68 | #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) | 72 | #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) |
| 69 | #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) | 73 | #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) |
| 70 | #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) | 74 | #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) |
| 71 | #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) | 75 | #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) |
| 76 | #define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ | ||
| 77 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ | ||
| 78 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ | ||
| 79 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
| 72 | #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 | 80 | #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 |
| 73 | #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 | 81 | #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 |
| 74 | #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 | 82 | #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 |
| @@ -82,7 +90,17 @@ | |||
| 82 | #define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH 62 | 90 | #define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH 62 |
| 83 | #define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH 65 | 91 | #define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH 65 |
| 84 | #define IWL_MVM_BT_COEX_SYNC2SCO 1 | 92 | #define IWL_MVM_BT_COEX_SYNC2SCO 1 |
| 85 | #define IWL_MVM_BT_COEX_CORUNNING 1 | 93 | #define IWL_MVM_BT_COEX_CORUNNING 0 |
| 86 | #define IWL_MVM_BT_COEX_MPLUT 1 | 94 | #define IWL_MVM_BT_COEX_MPLUT 1 |
| 95 | #define IWL_MVM_BT_COEX_RRC 1 | ||
| 96 | #define IWL_MVM_BT_COEX_TTC 1 | ||
| 97 | #define IWL_MVM_BT_COEX_MPLUT_REG0 0x28412201 | ||
| 98 | #define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451 | ||
| 99 | #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 | ||
| 100 | #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 | ||
| 101 | #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 | ||
| 102 | #define IWL_MVM_QUOTA_THRESHOLD 8 | ||
| 103 | #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 | ||
| 104 | #define IWL_MVM_RS_DISABLE_MIMO 0 | ||
| 87 | 105 | ||
| 88 | #endif /* __MVM_CONSTANTS_H */ | 106 | #endif /* __MVM_CONSTANTS_H */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 645b3cfc29a5..744de262373e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -599,33 +601,6 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, | |||
| 599 | return ret; | 601 | return ret; |
| 600 | } | 602 | } |
| 601 | 603 | ||
| 602 | struct iwl_d3_iter_data { | ||
| 603 | struct iwl_mvm *mvm; | ||
| 604 | struct ieee80211_vif *vif; | ||
| 605 | bool error; | ||
| 606 | }; | ||
| 607 | |||
| 608 | static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac, | ||
| 609 | struct ieee80211_vif *vif) | ||
| 610 | { | ||
| 611 | struct iwl_d3_iter_data *data = _data; | ||
| 612 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 613 | |||
| 614 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
| 615 | return; | ||
| 616 | |||
| 617 | if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
| 618 | return; | ||
| 619 | |||
| 620 | if (data->vif) { | ||
| 621 | IWL_ERR(data->mvm, "More than one managed interface active!\n"); | ||
| 622 | data->error = true; | ||
| 623 | return; | ||
| 624 | } | ||
| 625 | |||
| 626 | data->vif = vif; | ||
| 627 | } | ||
| 628 | |||
| 629 | static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 604 | static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 630 | struct ieee80211_sta *ap_sta) | 605 | struct ieee80211_sta *ap_sta) |
| 631 | { | 606 | { |
| @@ -700,7 +675,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 700 | return ret; | 675 | return ret; |
| 701 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); | 676 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); |
| 702 | 677 | ||
| 703 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); | 678 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); |
| 704 | if (ret) | 679 | if (ret) |
| 705 | return ret; | 680 | return ret; |
| 706 | 681 | ||
| @@ -781,130 +756,81 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 781 | IWL_ERR(mvm, "failed to set non-QoS seqno\n"); | 756 | IWL_ERR(mvm, "failed to set non-QoS seqno\n"); |
| 782 | } | 757 | } |
| 783 | 758 | ||
| 784 | static int | 759 | static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) |
| 785 | iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, | ||
| 786 | const struct iwl_wowlan_config_cmd_v3 *cmd) | ||
| 787 | { | 760 | { |
| 788 | /* start only with the v2 part of the command */ | 761 | iwl_mvm_cancel_scan(mvm); |
| 789 | u16 cmd_len = sizeof(cmd->common); | ||
| 790 | |||
| 791 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID) | ||
| 792 | cmd_len = sizeof(*cmd); | ||
| 793 | |||
| 794 | return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, | ||
| 795 | cmd_len, cmd); | ||
| 796 | } | ||
| 797 | |||
| 798 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | ||
| 799 | struct cfg80211_wowlan *wowlan, | ||
| 800 | bool test) | ||
| 801 | { | ||
| 802 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 803 | struct iwl_d3_iter_data suspend_iter_data = { | ||
| 804 | .mvm = mvm, | ||
| 805 | }; | ||
| 806 | struct ieee80211_vif *vif; | ||
| 807 | struct iwl_mvm_vif *mvmvif; | ||
| 808 | struct ieee80211_sta *ap_sta; | ||
| 809 | struct iwl_mvm_sta *mvm_ap_sta; | ||
| 810 | struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; | ||
| 811 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; | ||
| 812 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; | ||
| 813 | struct iwl_d3_manager_config d3_cfg_cmd_data = { | ||
| 814 | /* | ||
| 815 | * Program the minimum sleep time to 10 seconds, as many | ||
| 816 | * platforms have issues processing a wakeup signal while | ||
| 817 | * still being in the process of suspending. | ||
| 818 | */ | ||
| 819 | .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), | ||
| 820 | }; | ||
| 821 | struct iwl_host_cmd d3_cfg_cmd = { | ||
| 822 | .id = D3_CONFIG_CMD, | ||
| 823 | .flags = CMD_WANT_SKB, | ||
| 824 | .data[0] = &d3_cfg_cmd_data, | ||
| 825 | .len[0] = sizeof(d3_cfg_cmd_data), | ||
| 826 | }; | ||
| 827 | struct wowlan_key_data key_data = { | ||
| 828 | .use_rsc_tsc = false, | ||
| 829 | .tkip = &tkip_cmd, | ||
| 830 | .use_tkip = false, | ||
| 831 | }; | ||
| 832 | int ret; | ||
| 833 | int len __maybe_unused; | ||
| 834 | |||
| 835 | if (!wowlan) { | ||
| 836 | /* | ||
| 837 | * mac80211 shouldn't get here, but for D3 test | ||
| 838 | * it doesn't warrant a warning | ||
| 839 | */ | ||
| 840 | WARN_ON(!test); | ||
| 841 | return -EINVAL; | ||
| 842 | } | ||
| 843 | |||
| 844 | key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); | ||
| 845 | if (!key_data.rsc_tsc) | ||
| 846 | return -ENOMEM; | ||
| 847 | 762 | ||
| 848 | mutex_lock(&mvm->mutex); | 763 | iwl_trans_stop_device(mvm->trans); |
| 849 | 764 | ||
| 850 | /* see if there's only a single BSS vif and it's associated */ | 765 | /* |
| 851 | ieee80211_iterate_active_interfaces_atomic( | 766 | * Set the HW restart bit -- this is mostly true as we're |
| 852 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 767 | * going to load new firmware and reprogram that, though |
| 853 | iwl_mvm_d3_iface_iterator, &suspend_iter_data); | 768 | * the reprogramming is going to be manual to avoid adding |
| 769 | * all the MACs that aren't support. | ||
| 770 | * We don't have to clear up everything though because the | ||
| 771 | * reprogramming is manual. When we resume, we'll actually | ||
| 772 | * go through a proper restart sequence again to switch | ||
| 773 | * back to the runtime firmware image. | ||
| 774 | */ | ||
| 775 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
| 854 | 776 | ||
| 855 | if (suspend_iter_data.error || !suspend_iter_data.vif) { | 777 | /* We reprogram keys and shouldn't allocate new key indices */ |
| 856 | ret = 1; | 778 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
| 857 | goto out_noreset; | ||
| 858 | } | ||
| 859 | 779 | ||
| 860 | vif = suspend_iter_data.vif; | 780 | mvm->ptk_ivlen = 0; |
| 861 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | 781 | mvm->ptk_icvlen = 0; |
| 782 | mvm->ptk_ivlen = 0; | ||
| 783 | mvm->ptk_icvlen = 0; | ||
| 862 | 784 | ||
| 863 | ap_sta = rcu_dereference_protected( | 785 | return iwl_mvm_load_d3_fw(mvm); |
| 864 | mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], | 786 | } |
| 865 | lockdep_is_held(&mvm->mutex)); | ||
| 866 | if (IS_ERR_OR_NULL(ap_sta)) { | ||
| 867 | ret = -EINVAL; | ||
| 868 | goto out_noreset; | ||
| 869 | } | ||
| 870 | 787 | ||
| 871 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | 788 | static int |
| 789 | iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, | ||
| 790 | struct cfg80211_wowlan *wowlan, | ||
| 791 | struct iwl_wowlan_config_cmd *wowlan_config_cmd, | ||
| 792 | struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, | ||
| 793 | struct ieee80211_sta *ap_sta) | ||
| 794 | { | ||
| 795 | int ret; | ||
| 796 | struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | ||
| 872 | 797 | ||
| 873 | /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */ | 798 | /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ |
| 874 | 799 | ||
| 875 | wowlan_config_cmd.common.is_11n_connection = | 800 | wowlan_config_cmd->is_11n_connection = |
| 876 | ap_sta->ht_cap.ht_supported; | 801 | ap_sta->ht_cap.ht_supported; |
| 877 | 802 | ||
| 878 | /* Query the last used seqno and set it */ | 803 | /* Query the last used seqno and set it */ |
| 879 | ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); | 804 | ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); |
| 880 | if (ret < 0) | 805 | if (ret < 0) |
| 881 | goto out_noreset; | 806 | return ret; |
| 882 | wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret); | 807 | |
| 808 | wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); | ||
| 883 | 809 | ||
| 884 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common); | 810 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); |
| 885 | 811 | ||
| 886 | if (wowlan->disconnect) | 812 | if (wowlan->disconnect) |
| 887 | wowlan_config_cmd.common.wakeup_filter |= | 813 | wowlan_config_cmd->wakeup_filter |= |
| 888 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | | 814 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | |
| 889 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); | 815 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); |
| 890 | if (wowlan->magic_pkt) | 816 | if (wowlan->magic_pkt) |
| 891 | wowlan_config_cmd.common.wakeup_filter |= | 817 | wowlan_config_cmd->wakeup_filter |= |
| 892 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); | 818 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); |
| 893 | if (wowlan->gtk_rekey_failure) | 819 | if (wowlan->gtk_rekey_failure) |
| 894 | wowlan_config_cmd.common.wakeup_filter |= | 820 | wowlan_config_cmd->wakeup_filter |= |
| 895 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); | 821 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); |
| 896 | if (wowlan->eap_identity_req) | 822 | if (wowlan->eap_identity_req) |
| 897 | wowlan_config_cmd.common.wakeup_filter |= | 823 | wowlan_config_cmd->wakeup_filter |= |
| 898 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); | 824 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); |
| 899 | if (wowlan->four_way_handshake) | 825 | if (wowlan->four_way_handshake) |
| 900 | wowlan_config_cmd.common.wakeup_filter |= | 826 | wowlan_config_cmd->wakeup_filter |= |
| 901 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); | 827 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); |
| 902 | if (wowlan->n_patterns) | 828 | if (wowlan->n_patterns) |
| 903 | wowlan_config_cmd.common.wakeup_filter |= | 829 | wowlan_config_cmd->wakeup_filter |= |
| 904 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); | 830 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); |
| 905 | 831 | ||
| 906 | if (wowlan->rfkill_release) | 832 | if (wowlan->rfkill_release) |
| 907 | wowlan_config_cmd.common.wakeup_filter |= | 833 | wowlan_config_cmd->wakeup_filter |= |
| 908 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | 834 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); |
| 909 | 835 | ||
| 910 | if (wowlan->tcp) { | 836 | if (wowlan->tcp) { |
| @@ -912,44 +838,43 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
| 912 | * Set the "link change" (really "link lost") flag as well | 838 | * Set the "link change" (really "link lost") flag as well |
| 913 | * since that implies losing the TCP connection. | 839 | * since that implies losing the TCP connection. |
| 914 | */ | 840 | */ |
| 915 | wowlan_config_cmd.common.wakeup_filter |= | 841 | wowlan_config_cmd->wakeup_filter |= |
| 916 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | | 842 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | |
| 917 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | | 843 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | |
| 918 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | | 844 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | |
| 919 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); | 845 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); |
| 920 | } | 846 | } |
| 921 | 847 | ||
| 922 | iwl_mvm_cancel_scan(mvm); | 848 | return 0; |
| 923 | 849 | } | |
| 924 | iwl_trans_stop_device(mvm->trans); | ||
| 925 | |||
| 926 | /* | ||
| 927 | * Set the HW restart bit -- this is mostly true as we're | ||
| 928 | * going to load new firmware and reprogram that, though | ||
| 929 | * the reprogramming is going to be manual to avoid adding | ||
| 930 | * all the MACs that aren't support. | ||
| 931 | * We don't have to clear up everything though because the | ||
| 932 | * reprogramming is manual. When we resume, we'll actually | ||
| 933 | * go through a proper restart sequence again to switch | ||
| 934 | * back to the runtime firmware image. | ||
| 935 | */ | ||
| 936 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
| 937 | |||
| 938 | /* We reprogram keys and shouldn't allocate new key indices */ | ||
| 939 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | ||
| 940 | 850 | ||
| 941 | mvm->ptk_ivlen = 0; | 851 | static int |
| 942 | mvm->ptk_icvlen = 0; | 852 | iwl_mvm_wowlan_config(struct iwl_mvm *mvm, |
| 943 | mvm->ptk_ivlen = 0; | 853 | struct cfg80211_wowlan *wowlan, |
| 944 | mvm->ptk_icvlen = 0; | 854 | struct iwl_wowlan_config_cmd *wowlan_config_cmd, |
| 855 | struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, | ||
| 856 | struct ieee80211_sta *ap_sta) | ||
| 857 | { | ||
| 858 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; | ||
| 859 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; | ||
| 860 | struct wowlan_key_data key_data = { | ||
| 861 | .use_rsc_tsc = false, | ||
| 862 | .tkip = &tkip_cmd, | ||
| 863 | .use_tkip = false, | ||
| 864 | }; | ||
| 865 | int ret; | ||
| 945 | 866 | ||
| 946 | ret = iwl_mvm_load_d3_fw(mvm); | 867 | ret = iwl_mvm_switch_to_d3(mvm); |
| 947 | if (ret) | 868 | if (ret) |
| 948 | goto out; | 869 | return ret; |
| 949 | 870 | ||
| 950 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); | 871 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); |
| 951 | if (ret) | 872 | if (ret) |
| 952 | goto out; | 873 | return ret; |
| 874 | |||
| 875 | key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); | ||
| 876 | if (!key_data.rsc_tsc) | ||
| 877 | return -ENOMEM; | ||
| 953 | 878 | ||
| 954 | if (!iwlwifi_mod_params.sw_crypto) { | 879 | if (!iwlwifi_mod_params.sw_crypto) { |
| 955 | /* | 880 | /* |
| @@ -1008,7 +933,9 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
| 1008 | } | 933 | } |
| 1009 | } | 934 | } |
| 1010 | 935 | ||
| 1011 | ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd); | 936 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, |
| 937 | sizeof(*wowlan_config_cmd), | ||
| 938 | wowlan_config_cmd); | ||
| 1012 | if (ret) | 939 | if (ret) |
| 1013 | goto out; | 940 | goto out; |
| 1014 | 941 | ||
| @@ -1021,8 +948,153 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
| 1021 | goto out; | 948 | goto out; |
| 1022 | 949 | ||
| 1023 | ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp); | 950 | ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp); |
| 951 | |||
| 952 | out: | ||
| 953 | kfree(key_data.rsc_tsc); | ||
| 954 | return ret; | ||
| 955 | } | ||
| 956 | |||
| 957 | static int | ||
| 958 | iwl_mvm_netdetect_config(struct iwl_mvm *mvm, | ||
| 959 | struct cfg80211_wowlan *wowlan, | ||
| 960 | struct cfg80211_sched_scan_request *nd_config, | ||
| 961 | struct ieee80211_vif *vif) | ||
| 962 | { | ||
| 963 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | ||
| 964 | int ret; | ||
| 965 | |||
| 966 | ret = iwl_mvm_switch_to_d3(mvm); | ||
| 1024 | if (ret) | 967 | if (ret) |
| 1025 | goto out; | 968 | return ret; |
| 969 | |||
| 970 | /* rfkill release can be either for wowlan or netdetect */ | ||
| 971 | if (wowlan->rfkill_release) | ||
| 972 | wowlan_config_cmd.wakeup_filter |= | ||
| 973 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | ||
| 974 | |||
| 975 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, | ||
| 976 | sizeof(wowlan_config_cmd), | ||
| 977 | &wowlan_config_cmd); | ||
| 978 | if (ret) | ||
| 979 | return ret; | ||
| 980 | |||
| 981 | ret = iwl_mvm_scan_offload_start(mvm, vif, nd_config, &mvm->nd_ies); | ||
| 982 | if (ret) | ||
| 983 | return ret; | ||
| 984 | |||
| 985 | if (WARN_ON(mvm->nd_match_sets || mvm->nd_channels)) | ||
| 986 | return -EBUSY; | ||
| 987 | |||
| 988 | /* save the sched scan matchsets... */ | ||
| 989 | if (nd_config->n_match_sets) { | ||
| 990 | mvm->nd_match_sets = kmemdup(nd_config->match_sets, | ||
| 991 | sizeof(*nd_config->match_sets) * | ||
| 992 | nd_config->n_match_sets, | ||
| 993 | GFP_KERNEL); | ||
| 994 | if (mvm->nd_match_sets) | ||
| 995 | mvm->n_nd_match_sets = nd_config->n_match_sets; | ||
| 996 | } | ||
| 997 | |||
| 998 | /* ...and the sched scan channels for later reporting */ | ||
| 999 | mvm->nd_channels = kmemdup(nd_config->channels, | ||
| 1000 | sizeof(*nd_config->channels) * | ||
| 1001 | nd_config->n_channels, | ||
| 1002 | GFP_KERNEL); | ||
| 1003 | if (mvm->nd_channels) | ||
| 1004 | mvm->n_nd_channels = nd_config->n_channels; | ||
| 1005 | |||
| 1006 | return 0; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static void iwl_mvm_free_nd(struct iwl_mvm *mvm) | ||
| 1010 | { | ||
| 1011 | kfree(mvm->nd_match_sets); | ||
| 1012 | mvm->nd_match_sets = NULL; | ||
| 1013 | mvm->n_nd_match_sets = 0; | ||
| 1014 | kfree(mvm->nd_channels); | ||
| 1015 | mvm->nd_channels = NULL; | ||
| 1016 | mvm->n_nd_channels = 0; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | ||
| 1020 | struct cfg80211_wowlan *wowlan, | ||
| 1021 | bool test) | ||
| 1022 | { | ||
| 1023 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 1024 | struct ieee80211_vif *vif = NULL; | ||
| 1025 | struct iwl_mvm_vif *mvmvif = NULL; | ||
| 1026 | struct ieee80211_sta *ap_sta = NULL; | ||
| 1027 | struct iwl_d3_manager_config d3_cfg_cmd_data = { | ||
| 1028 | /* | ||
| 1029 | * Program the minimum sleep time to 10 seconds, as many | ||
| 1030 | * platforms have issues processing a wakeup signal while | ||
| 1031 | * still being in the process of suspending. | ||
| 1032 | */ | ||
| 1033 | .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), | ||
| 1034 | }; | ||
| 1035 | struct iwl_host_cmd d3_cfg_cmd = { | ||
| 1036 | .id = D3_CONFIG_CMD, | ||
| 1037 | .flags = CMD_WANT_SKB, | ||
| 1038 | .data[0] = &d3_cfg_cmd_data, | ||
| 1039 | .len[0] = sizeof(d3_cfg_cmd_data), | ||
| 1040 | }; | ||
| 1041 | int ret; | ||
| 1042 | int len __maybe_unused; | ||
| 1043 | |||
| 1044 | if (!wowlan) { | ||
| 1045 | /* | ||
| 1046 | * mac80211 shouldn't get here, but for D3 test | ||
| 1047 | * it doesn't warrant a warning | ||
| 1048 | */ | ||
| 1049 | WARN_ON(!test); | ||
| 1050 | return -EINVAL; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | mutex_lock(&mvm->mutex); | ||
| 1054 | |||
| 1055 | vif = iwl_mvm_get_bss_vif(mvm); | ||
| 1056 | if (IS_ERR_OR_NULL(vif)) { | ||
| 1057 | ret = 1; | ||
| 1058 | goto out_noreset; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 1062 | |||
| 1063 | if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) { | ||
| 1064 | /* if we're not associated, this must be netdetect */ | ||
| 1065 | if (!wowlan->nd_config && !mvm->nd_config) { | ||
| 1066 | ret = 1; | ||
| 1067 | goto out_noreset; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | ret = iwl_mvm_netdetect_config( | ||
| 1071 | mvm, wowlan, wowlan->nd_config ?: mvm->nd_config, vif); | ||
| 1072 | if (ret) | ||
| 1073 | goto out; | ||
| 1074 | |||
| 1075 | mvm->net_detect = true; | ||
| 1076 | } else { | ||
| 1077 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | ||
| 1078 | |||
| 1079 | ap_sta = rcu_dereference_protected( | ||
| 1080 | mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], | ||
| 1081 | lockdep_is_held(&mvm->mutex)); | ||
| 1082 | if (IS_ERR_OR_NULL(ap_sta)) { | ||
| 1083 | ret = -EINVAL; | ||
| 1084 | goto out_noreset; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd, | ||
| 1088 | vif, mvmvif, ap_sta); | ||
| 1089 | if (ret) | ||
| 1090 | goto out_noreset; | ||
| 1091 | ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, | ||
| 1092 | vif, mvmvif, ap_sta); | ||
| 1093 | if (ret) | ||
| 1094 | goto out; | ||
| 1095 | |||
| 1096 | mvm->net_detect = false; | ||
| 1097 | } | ||
| 1026 | 1098 | ||
| 1027 | ret = iwl_mvm_power_update_device(mvm); | 1099 | ret = iwl_mvm_power_update_device(mvm); |
| 1028 | if (ret) | 1100 | if (ret) |
| @@ -1055,11 +1127,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
| 1055 | 1127 | ||
| 1056 | iwl_trans_d3_suspend(mvm->trans, test); | 1128 | iwl_trans_d3_suspend(mvm->trans, test); |
| 1057 | out: | 1129 | out: |
| 1058 | if (ret < 0) | 1130 | if (ret < 0) { |
| 1059 | ieee80211_restart_hw(mvm->hw); | 1131 | ieee80211_restart_hw(mvm->hw); |
| 1132 | iwl_mvm_free_nd(mvm); | ||
| 1133 | } | ||
| 1060 | out_noreset: | 1134 | out_noreset: |
| 1061 | kfree(key_data.rsc_tsc); | ||
| 1062 | |||
| 1063 | mutex_unlock(&mvm->mutex); | 1135 | mutex_unlock(&mvm->mutex); |
| 1064 | 1136 | ||
| 1065 | return ret; | 1137 | return ret; |
| @@ -1069,6 +1141,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 1069 | { | 1141 | { |
| 1070 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1142 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 1071 | 1143 | ||
| 1144 | iwl_trans_suspend(mvm->trans); | ||
| 1072 | if (iwl_mvm_is_d0i3_supported(mvm)) { | 1145 | if (iwl_mvm_is_d0i3_supported(mvm)) { |
| 1073 | mutex_lock(&mvm->d0i3_suspend_mutex); | 1146 | mutex_lock(&mvm->d0i3_suspend_mutex); |
| 1074 | __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | 1147 | __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); |
| @@ -1447,9 +1520,8 @@ out: | |||
| 1447 | return true; | 1520 | return true; |
| 1448 | } | 1521 | } |
| 1449 | 1522 | ||
| 1450 | /* releases the MVM mutex */ | 1523 | static struct iwl_wowlan_status * |
| 1451 | static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | 1524 | iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 1452 | struct ieee80211_vif *vif) | ||
| 1453 | { | 1525 | { |
| 1454 | u32 base = mvm->error_event_table; | 1526 | u32 base = mvm->error_event_table; |
| 1455 | struct error_table_start { | 1527 | struct error_table_start { |
| @@ -1461,19 +1533,15 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 1461 | .id = WOWLAN_GET_STATUSES, | 1533 | .id = WOWLAN_GET_STATUSES, |
| 1462 | .flags = CMD_WANT_SKB, | 1534 | .flags = CMD_WANT_SKB, |
| 1463 | }; | 1535 | }; |
| 1464 | struct iwl_wowlan_status_data status; | 1536 | struct iwl_wowlan_status *status, *fw_status; |
| 1465 | struct iwl_wowlan_status *fw_status; | 1537 | int ret, len, status_size; |
| 1466 | int ret, len, status_size, i; | ||
| 1467 | bool keep; | ||
| 1468 | struct ieee80211_sta *ap_sta; | ||
| 1469 | struct iwl_mvm_sta *mvm_ap_sta; | ||
| 1470 | 1538 | ||
| 1471 | iwl_trans_read_mem_bytes(mvm->trans, base, | 1539 | iwl_trans_read_mem_bytes(mvm->trans, base, |
| 1472 | &err_info, sizeof(err_info)); | 1540 | &err_info, sizeof(err_info)); |
| 1473 | 1541 | ||
| 1474 | if (err_info.valid) { | 1542 | if (err_info.valid) { |
| 1475 | IWL_INFO(mvm, "error table is valid (%d)\n", | 1543 | IWL_INFO(mvm, "error table is valid (%d) with error (%d)\n", |
| 1476 | err_info.valid); | 1544 | err_info.valid, err_info.error_id); |
| 1477 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | 1545 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { |
| 1478 | struct cfg80211_wowlan_wakeup wakeup = { | 1546 | struct cfg80211_wowlan_wakeup wakeup = { |
| 1479 | .rfkill_release = true, | 1547 | .rfkill_release = true, |
| @@ -1481,7 +1549,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 1481 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | 1549 | ieee80211_report_wowlan_wakeup(vif, &wakeup, |
| 1482 | GFP_KERNEL); | 1550 | GFP_KERNEL); |
| 1483 | } | 1551 | } |
| 1484 | goto out_unlock; | 1552 | return ERR_PTR(-EIO); |
| 1485 | } | 1553 | } |
| 1486 | 1554 | ||
| 1487 | /* only for tracing for now */ | 1555 | /* only for tracing for now */ |
| @@ -1492,22 +1560,53 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 1492 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 1560 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
| 1493 | if (ret) { | 1561 | if (ret) { |
| 1494 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | 1562 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); |
| 1495 | goto out_unlock; | 1563 | return ERR_PTR(ret); |
| 1496 | } | 1564 | } |
| 1497 | 1565 | ||
| 1498 | /* RF-kill already asserted again... */ | 1566 | /* RF-kill already asserted again... */ |
| 1499 | if (!cmd.resp_pkt) | 1567 | if (!cmd.resp_pkt) { |
| 1500 | goto out_unlock; | 1568 | ret = -ERFKILL; |
| 1569 | goto out_free_resp; | ||
| 1570 | } | ||
| 1501 | 1571 | ||
| 1502 | status_size = sizeof(*fw_status); | 1572 | status_size = sizeof(*fw_status); |
| 1503 | 1573 | ||
| 1504 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); | 1574 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); |
| 1505 | if (len < status_size) { | 1575 | if (len < status_size) { |
| 1506 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1576 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
| 1577 | ret = -EIO; | ||
| 1507 | goto out_free_resp; | 1578 | goto out_free_resp; |
| 1508 | } | 1579 | } |
| 1509 | 1580 | ||
| 1510 | fw_status = (void *)cmd.resp_pkt->data; | 1581 | status = (void *)cmd.resp_pkt->data; |
| 1582 | if (len != (status_size + | ||
| 1583 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) { | ||
| 1584 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
| 1585 | ret = -EIO; | ||
| 1586 | goto out_free_resp; | ||
| 1587 | } | ||
| 1588 | |||
| 1589 | fw_status = kmemdup(status, len, GFP_KERNEL); | ||
| 1590 | |||
| 1591 | out_free_resp: | ||
| 1592 | iwl_free_resp(&cmd); | ||
| 1593 | return ret ? ERR_PTR(ret) : fw_status; | ||
| 1594 | } | ||
| 1595 | |||
| 1596 | /* releases the MVM mutex */ | ||
| 1597 | static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | ||
| 1598 | struct ieee80211_vif *vif) | ||
| 1599 | { | ||
| 1600 | struct iwl_wowlan_status_data status; | ||
| 1601 | struct iwl_wowlan_status *fw_status; | ||
| 1602 | int i; | ||
| 1603 | bool keep; | ||
| 1604 | struct ieee80211_sta *ap_sta; | ||
| 1605 | struct iwl_mvm_sta *mvm_ap_sta; | ||
| 1606 | |||
| 1607 | fw_status = iwl_mvm_get_wakeup_status(mvm, vif); | ||
| 1608 | if (IS_ERR_OR_NULL(fw_status)) | ||
| 1609 | goto out_unlock; | ||
| 1511 | 1610 | ||
| 1512 | status.pattern_number = le16_to_cpu(fw_status->pattern_number); | 1611 | status.pattern_number = le16_to_cpu(fw_status->pattern_number); |
| 1513 | for (i = 0; i < 8; i++) | 1612 | for (i = 0; i < 8; i++) |
| @@ -1520,17 +1619,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 1520 | le32_to_cpu(fw_status->wake_packet_bufsize); | 1619 | le32_to_cpu(fw_status->wake_packet_bufsize); |
| 1521 | status.wake_packet = fw_status->wake_packet; | 1620 | status.wake_packet = fw_status->wake_packet; |
| 1522 | 1621 | ||
| 1523 | if (len != status_size + ALIGN(status.wake_packet_bufsize, 4)) { | ||
| 1524 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
| 1525 | goto out_free_resp; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | /* still at hard-coded place 0 for D3 image */ | 1622 | /* still at hard-coded place 0 for D3 image */ |
| 1529 | ap_sta = rcu_dereference_protected( | 1623 | ap_sta = rcu_dereference_protected( |
| 1530 | mvm->fw_id_to_mac_id[0], | 1624 | mvm->fw_id_to_mac_id[0], |
| 1531 | lockdep_is_held(&mvm->mutex)); | 1625 | lockdep_is_held(&mvm->mutex)); |
| 1532 | if (IS_ERR_OR_NULL(ap_sta)) | 1626 | if (IS_ERR_OR_NULL(ap_sta)) |
| 1533 | goto out_free_resp; | 1627 | goto out_free; |
| 1534 | 1628 | ||
| 1535 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | 1629 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; |
| 1536 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | 1630 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { |
| @@ -1547,16 +1641,151 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 1547 | 1641 | ||
| 1548 | keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status); | 1642 | keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status); |
| 1549 | 1643 | ||
| 1550 | iwl_free_resp(&cmd); | 1644 | kfree(fw_status); |
| 1551 | return keep; | 1645 | return keep; |
| 1552 | 1646 | ||
| 1553 | out_free_resp: | 1647 | out_free: |
| 1554 | iwl_free_resp(&cmd); | 1648 | kfree(fw_status); |
| 1555 | out_unlock: | 1649 | out_unlock: |
| 1556 | mutex_unlock(&mvm->mutex); | 1650 | mutex_unlock(&mvm->mutex); |
| 1557 | return false; | 1651 | return false; |
| 1558 | } | 1652 | } |
| 1559 | 1653 | ||
| 1654 | struct iwl_mvm_nd_query_results { | ||
| 1655 | u32 matched_profiles; | ||
| 1656 | struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; | ||
| 1657 | }; | ||
| 1658 | |||
| 1659 | static int | ||
| 1660 | iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, | ||
| 1661 | struct iwl_mvm_nd_query_results *results) | ||
| 1662 | { | ||
| 1663 | struct iwl_scan_offload_profiles_query *query; | ||
| 1664 | struct iwl_host_cmd cmd = { | ||
| 1665 | .id = SCAN_OFFLOAD_PROFILES_QUERY_CMD, | ||
| 1666 | .flags = CMD_WANT_SKB, | ||
| 1667 | }; | ||
| 1668 | int ret, len; | ||
| 1669 | |||
| 1670 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
| 1671 | if (ret) { | ||
| 1672 | IWL_ERR(mvm, "failed to query matched profiles (%d)\n", ret); | ||
| 1673 | return ret; | ||
| 1674 | } | ||
| 1675 | |||
| 1676 | /* RF-kill already asserted again... */ | ||
| 1677 | if (!cmd.resp_pkt) { | ||
| 1678 | ret = -ERFKILL; | ||
| 1679 | goto out_free_resp; | ||
| 1680 | } | ||
| 1681 | |||
| 1682 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); | ||
| 1683 | if (len < sizeof(*query)) { | ||
| 1684 | IWL_ERR(mvm, "Invalid scan offload profiles query response!\n"); | ||
| 1685 | ret = -EIO; | ||
| 1686 | goto out_free_resp; | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | query = (void *)cmd.resp_pkt->data; | ||
| 1690 | |||
| 1691 | results->matched_profiles = le32_to_cpu(query->matched_profiles); | ||
| 1692 | memcpy(results->matches, query->matches, sizeof(results->matches)); | ||
| 1693 | |||
| 1694 | out_free_resp: | ||
| 1695 | iwl_free_resp(&cmd); | ||
| 1696 | return ret; | ||
| 1697 | } | ||
| 1698 | |||
| 1699 | static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, | ||
| 1700 | struct ieee80211_vif *vif) | ||
| 1701 | { | ||
| 1702 | struct cfg80211_wowlan_nd_info *net_detect = NULL; | ||
| 1703 | struct cfg80211_wowlan_wakeup wakeup = { | ||
| 1704 | .pattern_idx = -1, | ||
| 1705 | }; | ||
| 1706 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | ||
| 1707 | struct iwl_mvm_nd_query_results query; | ||
| 1708 | struct iwl_wowlan_status *fw_status; | ||
| 1709 | unsigned long matched_profiles; | ||
| 1710 | u32 reasons = 0; | ||
| 1711 | int i, j, n_matches, ret; | ||
| 1712 | |||
| 1713 | fw_status = iwl_mvm_get_wakeup_status(mvm, vif); | ||
| 1714 | if (!IS_ERR_OR_NULL(fw_status)) | ||
| 1715 | reasons = le32_to_cpu(fw_status->wakeup_reasons); | ||
| 1716 | |||
| 1717 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) | ||
| 1718 | wakeup.rfkill_release = true; | ||
| 1719 | |||
| 1720 | if (reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) | ||
| 1721 | goto out; | ||
| 1722 | |||
| 1723 | ret = iwl_mvm_netdetect_query_results(mvm, &query); | ||
| 1724 | if (ret || !query.matched_profiles) { | ||
| 1725 | wakeup_report = NULL; | ||
| 1726 | goto out; | ||
| 1727 | } | ||
| 1728 | |||
| 1729 | matched_profiles = query.matched_profiles; | ||
| 1730 | if (mvm->n_nd_match_sets) { | ||
| 1731 | n_matches = hweight_long(matched_profiles); | ||
| 1732 | } else { | ||
| 1733 | IWL_ERR(mvm, "no net detect match information available\n"); | ||
| 1734 | n_matches = 0; | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | net_detect = kzalloc(sizeof(*net_detect) + | ||
| 1738 | (n_matches * sizeof(net_detect->matches[0])), | ||
| 1739 | GFP_KERNEL); | ||
| 1740 | if (!net_detect || !n_matches) | ||
| 1741 | goto out_report_nd; | ||
| 1742 | |||
| 1743 | for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) { | ||
| 1744 | struct iwl_scan_offload_profile_match *fw_match; | ||
| 1745 | struct cfg80211_wowlan_nd_match *match; | ||
| 1746 | int n_channels = 0; | ||
| 1747 | |||
| 1748 | fw_match = &query.matches[i]; | ||
| 1749 | |||
| 1750 | for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; j++) | ||
| 1751 | n_channels += hweight8(fw_match->matching_channels[j]); | ||
| 1752 | |||
| 1753 | match = kzalloc(sizeof(*match) + | ||
| 1754 | (n_channels * sizeof(*match->channels)), | ||
| 1755 | GFP_KERNEL); | ||
| 1756 | if (!match) | ||
| 1757 | goto out_report_nd; | ||
| 1758 | |||
| 1759 | net_detect->matches[net_detect->n_matches++] = match; | ||
| 1760 | |||
| 1761 | match->ssid.ssid_len = mvm->nd_match_sets[i].ssid.ssid_len; | ||
| 1762 | memcpy(match->ssid.ssid, mvm->nd_match_sets[i].ssid.ssid, | ||
| 1763 | match->ssid.ssid_len); | ||
| 1764 | |||
| 1765 | if (mvm->n_nd_channels < n_channels) | ||
| 1766 | continue; | ||
| 1767 | |||
| 1768 | for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; j++) | ||
| 1769 | if (fw_match->matching_channels[j / 8] & (BIT(j % 8))) | ||
| 1770 | match->channels[match->n_channels++] = | ||
| 1771 | mvm->nd_channels[j]->center_freq; | ||
| 1772 | } | ||
| 1773 | |||
| 1774 | out_report_nd: | ||
| 1775 | wakeup.net_detect = net_detect; | ||
| 1776 | out: | ||
| 1777 | iwl_mvm_free_nd(mvm); | ||
| 1778 | |||
| 1779 | mutex_unlock(&mvm->mutex); | ||
| 1780 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | ||
| 1781 | |||
| 1782 | if (net_detect) { | ||
| 1783 | for (i = 0; i < net_detect->n_matches; i++) | ||
| 1784 | kfree(net_detect->matches[i]); | ||
| 1785 | kfree(net_detect); | ||
| 1786 | } | ||
| 1787 | } | ||
| 1788 | |||
| 1560 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) | 1789 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) |
| 1561 | { | 1790 | { |
| 1562 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1791 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| @@ -1590,9 +1819,6 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, | |||
| 1590 | 1819 | ||
| 1591 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | 1820 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) |
| 1592 | { | 1821 | { |
| 1593 | struct iwl_d3_iter_data resume_iter_data = { | ||
| 1594 | .mvm = mvm, | ||
| 1595 | }; | ||
| 1596 | struct ieee80211_vif *vif = NULL; | 1822 | struct ieee80211_vif *vif = NULL; |
| 1597 | int ret; | 1823 | int ret; |
| 1598 | enum iwl_d3_status d3_status; | 1824 | enum iwl_d3_status d3_status; |
| @@ -1601,15 +1827,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
| 1601 | mutex_lock(&mvm->mutex); | 1827 | mutex_lock(&mvm->mutex); |
| 1602 | 1828 | ||
| 1603 | /* get the BSS vif pointer again */ | 1829 | /* get the BSS vif pointer again */ |
| 1604 | ieee80211_iterate_active_interfaces_atomic( | 1830 | vif = iwl_mvm_get_bss_vif(mvm); |
| 1605 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 1831 | if (IS_ERR_OR_NULL(vif)) |
| 1606 | iwl_mvm_d3_iface_iterator, &resume_iter_data); | ||
| 1607 | |||
| 1608 | if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif)) | ||
| 1609 | goto out_unlock; | 1832 | goto out_unlock; |
| 1610 | 1833 | ||
| 1611 | vif = resume_iter_data.vif; | ||
| 1612 | |||
| 1613 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); | 1834 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); |
| 1614 | if (ret) | 1835 | if (ret) |
| 1615 | goto out_unlock; | 1836 | goto out_unlock; |
| @@ -1622,11 +1843,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
| 1622 | /* query SRAM first in case we want event logging */ | 1843 | /* query SRAM first in case we want event logging */ |
| 1623 | iwl_mvm_read_d3_sram(mvm); | 1844 | iwl_mvm_read_d3_sram(mvm); |
| 1624 | 1845 | ||
| 1625 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); | 1846 | if (mvm->net_detect) { |
| 1847 | iwl_mvm_query_netdetect_reasons(mvm, vif); | ||
| 1848 | } else { | ||
| 1849 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); | ||
| 1626 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1850 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| 1627 | if (keep) | 1851 | if (keep) |
| 1628 | mvm->keep_vif = vif; | 1852 | mvm->keep_vif = vif; |
| 1629 | #endif | 1853 | #endif |
| 1854 | } | ||
| 1630 | /* has unlocked the mutex, so skip that */ | 1855 | /* has unlocked the mutex, so skip that */ |
| 1631 | goto out; | 1856 | goto out; |
| 1632 | 1857 | ||
| @@ -1641,6 +1866,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
| 1641 | 1866 | ||
| 1642 | /* return 1 to reconfigure the device */ | 1867 | /* return 1 to reconfigure the device */ |
| 1643 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1868 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
| 1869 | set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status); | ||
| 1644 | return 1; | 1870 | return 1; |
| 1645 | } | 1871 | } |
| 1646 | 1872 | ||
| @@ -1648,18 +1874,10 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
| 1648 | { | 1874 | { |
| 1649 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1875 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 1650 | 1876 | ||
| 1651 | if (iwl_mvm_is_d0i3_supported(mvm)) { | 1877 | iwl_trans_resume(mvm->trans); |
| 1652 | bool exit_now; | ||
| 1653 | 1878 | ||
| 1654 | mutex_lock(&mvm->d0i3_suspend_mutex); | 1879 | if (iwl_mvm_is_d0i3_supported(mvm)) |
| 1655 | __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | ||
| 1656 | exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, | ||
| 1657 | &mvm->d0i3_suspend_flags); | ||
| 1658 | mutex_unlock(&mvm->d0i3_suspend_mutex); | ||
| 1659 | if (exit_now) | ||
| 1660 | _iwl_mvm_exit_d0i3(mvm); | ||
| 1661 | return 0; | 1880 | return 0; |
| 1662 | } | ||
| 1663 | 1881 | ||
| 1664 | return __iwl_mvm_resume(mvm, false); | 1882 | return __iwl_mvm_resume(mvm, false); |
| 1665 | } | 1883 | } |
| @@ -1739,7 +1957,9 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) | |||
| 1739 | int remaining_time = 10; | 1957 | int remaining_time = 10; |
| 1740 | 1958 | ||
| 1741 | mvm->d3_test_active = false; | 1959 | mvm->d3_test_active = false; |
| 1960 | rtnl_lock(); | ||
| 1742 | __iwl_mvm_resume(mvm, true); | 1961 | __iwl_mvm_resume(mvm, true); |
| 1962 | rtnl_unlock(); | ||
| 1743 | iwl_abort_notification_waits(&mvm->notif_wait); | 1963 | iwl_abort_notification_waits(&mvm->notif_wait); |
| 1744 | ieee80211_restart_hw(mvm->hw); | 1964 | ieee80211_restart_hw(mvm->hw); |
| 1745 | 1965 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 87e517bffedc..9aa2311a776c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -118,6 +120,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, | |||
| 118 | IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val); | 120 | IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val); |
| 119 | dbgfs_pm->uapsd_misbehaving = val; | 121 | dbgfs_pm->uapsd_misbehaving = val; |
| 120 | break; | 122 | break; |
| 123 | case MVM_DEBUGFS_PM_USE_PS_POLL: | ||
| 124 | IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val); | ||
| 125 | dbgfs_pm->use_ps_poll = val; | ||
| 126 | break; | ||
| 121 | } | 127 | } |
| 122 | } | 128 | } |
| 123 | 129 | ||
| @@ -168,6 +174,10 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, | |||
| 168 | if (sscanf(buf + 18, "%d", &val) != 1) | 174 | if (sscanf(buf + 18, "%d", &val) != 1) |
| 169 | return -EINVAL; | 175 | return -EINVAL; |
| 170 | param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING; | 176 | param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING; |
| 177 | } else if (!strncmp("use_ps_poll=", buf, 12)) { | ||
| 178 | if (sscanf(buf + 12, "%d", &val) != 1) | ||
| 179 | return -EINVAL; | ||
| 180 | param = MVM_DEBUGFS_PM_USE_PS_POLL; | ||
| 171 | } else { | 181 | } else { |
| 172 | return -EINVAL; | 182 | return -EINVAL; |
| 173 | } | 183 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 7d18f466fbb3..33bf915cd7ea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -119,78 +121,6 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, | |||
| 119 | return ret; | 121 | return ret; |
| 120 | } | 122 | } |
| 121 | 123 | ||
| 122 | static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) | ||
| 123 | { | ||
| 124 | struct iwl_mvm *mvm = inode->i_private; | ||
| 125 | int ret; | ||
| 126 | |||
| 127 | if (!mvm) | ||
| 128 | return -EINVAL; | ||
| 129 | |||
| 130 | mutex_lock(&mvm->mutex); | ||
| 131 | if (!mvm->fw_error_dump) { | ||
| 132 | ret = -ENODATA; | ||
| 133 | goto out; | ||
| 134 | } | ||
| 135 | |||
| 136 | file->private_data = mvm->fw_error_dump; | ||
| 137 | mvm->fw_error_dump = NULL; | ||
| 138 | ret = 0; | ||
| 139 | |||
| 140 | out: | ||
| 141 | mutex_unlock(&mvm->mutex); | ||
| 142 | return ret; | ||
| 143 | } | ||
| 144 | |||
| 145 | static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, | ||
| 146 | char __user *user_buf, | ||
| 147 | size_t count, loff_t *ppos) | ||
| 148 | { | ||
| 149 | struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; | ||
| 150 | ssize_t bytes_read = 0; | ||
| 151 | ssize_t bytes_read_trans = 0; | ||
| 152 | |||
| 153 | if (*ppos < dump_ptrs->op_mode_len) | ||
| 154 | bytes_read += | ||
| 155 | simple_read_from_buffer(user_buf, count, ppos, | ||
| 156 | dump_ptrs->op_mode_ptr, | ||
| 157 | dump_ptrs->op_mode_len); | ||
| 158 | |||
| 159 | if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len) | ||
| 160 | return bytes_read; | ||
| 161 | |||
| 162 | if (dump_ptrs->trans_ptr) { | ||
| 163 | *ppos -= dump_ptrs->op_mode_len; | ||
| 164 | bytes_read_trans = | ||
| 165 | simple_read_from_buffer(user_buf + bytes_read, | ||
| 166 | count - bytes_read, ppos, | ||
| 167 | dump_ptrs->trans_ptr->data, | ||
| 168 | dump_ptrs->trans_ptr->len); | ||
| 169 | *ppos += dump_ptrs->op_mode_len; | ||
| 170 | |||
| 171 | if (bytes_read_trans >= 0) | ||
| 172 | bytes_read += bytes_read_trans; | ||
| 173 | else if (!bytes_read) | ||
| 174 | /* propagate the failure */ | ||
| 175 | return bytes_read_trans; | ||
| 176 | } | ||
| 177 | |||
| 178 | return bytes_read; | ||
| 179 | |||
| 180 | } | ||
| 181 | |||
| 182 | static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, | ||
| 183 | struct file *file) | ||
| 184 | { | ||
| 185 | struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; | ||
| 186 | |||
| 187 | vfree(dump_ptrs->op_mode_ptr); | ||
| 188 | vfree(dump_ptrs->trans_ptr); | ||
| 189 | kfree(dump_ptrs); | ||
| 190 | |||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | 124 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, |
| 195 | size_t count, loff_t *ppos) | 125 | size_t count, loff_t *ppos) |
| 196 | { | 126 | { |
| @@ -257,6 +187,96 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, | |||
| 257 | return count; | 187 | return count; |
| 258 | } | 188 | } |
| 259 | 189 | ||
| 190 | static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file, | ||
| 191 | char __user *user_buf, | ||
| 192 | size_t count, loff_t *ppos) | ||
| 193 | { | ||
| 194 | struct iwl_mvm *mvm = file->private_data; | ||
| 195 | char buf[16]; | ||
| 196 | int pos; | ||
| 197 | |||
| 198 | if (!mvm->temperature_test) | ||
| 199 | pos = scnprintf(buf , sizeof(buf), "disabled\n"); | ||
| 200 | else | ||
| 201 | pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature); | ||
| 202 | |||
| 203 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
| 204 | } | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Set NIC Temperature | ||
| 208 | * Cause the driver to ignore the actual NIC temperature reported by the FW | ||
| 209 | * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN - | ||
| 210 | * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX | ||
| 211 | * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE | ||
| 212 | */ | ||
| 213 | static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, | ||
| 214 | char *buf, size_t count, | ||
| 215 | loff_t *ppos) | ||
| 216 | { | ||
| 217 | int temperature; | ||
| 218 | |||
| 219 | if (!mvm->ucode_loaded && !mvm->temperature_test) | ||
| 220 | return -EIO; | ||
| 221 | |||
| 222 | if (kstrtoint(buf, 10, &temperature)) | ||
| 223 | return -EINVAL; | ||
| 224 | /* not a legal temperature */ | ||
| 225 | if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX && | ||
| 226 | temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) || | ||
| 227 | temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN) | ||
| 228 | return -EINVAL; | ||
| 229 | |||
| 230 | mutex_lock(&mvm->mutex); | ||
| 231 | if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) { | ||
| 232 | if (!mvm->temperature_test) | ||
| 233 | goto out; | ||
| 234 | |||
| 235 | mvm->temperature_test = false; | ||
| 236 | /* Since we can't read the temp while awake, just set | ||
| 237 | * it to zero until we get the next RX stats from the | ||
| 238 | * firmware. | ||
| 239 | */ | ||
| 240 | mvm->temperature = 0; | ||
| 241 | } else { | ||
| 242 | mvm->temperature_test = true; | ||
| 243 | mvm->temperature = temperature; | ||
| 244 | } | ||
| 245 | IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n", | ||
| 246 | mvm->temperature_test ? "En" : "Dis" , | ||
| 247 | mvm->temperature); | ||
| 248 | /* handle the temperature change */ | ||
| 249 | iwl_mvm_tt_handler(mvm); | ||
| 250 | |||
| 251 | out: | ||
| 252 | mutex_unlock(&mvm->mutex); | ||
| 253 | |||
| 254 | return count; | ||
| 255 | } | ||
| 256 | |||
| 257 | static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, | ||
| 258 | char __user *user_buf, | ||
| 259 | size_t count, loff_t *ppos) | ||
| 260 | { | ||
| 261 | struct iwl_mvm *mvm = file->private_data; | ||
| 262 | char buf[16]; | ||
| 263 | int pos, temp; | ||
| 264 | |||
| 265 | if (!mvm->ucode_loaded) | ||
| 266 | return -EIO; | ||
| 267 | |||
| 268 | mutex_lock(&mvm->mutex); | ||
| 269 | temp = iwl_mvm_get_temp(mvm); | ||
| 270 | mutex_unlock(&mvm->mutex); | ||
| 271 | |||
| 272 | if (temp < 0) | ||
| 273 | return temp; | ||
| 274 | |||
| 275 | pos = scnprintf(buf , sizeof(buf), "%d\n", temp); | ||
| 276 | |||
| 277 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
| 278 | } | ||
| 279 | |||
| 260 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | 280 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, |
| 261 | size_t count, loff_t *ppos) | 281 | size_t count, loff_t *ppos) |
| 262 | { | 282 | { |
| @@ -916,7 +936,11 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
| 916 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) | 936 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) |
| 917 | return -EINVAL; | 937 | return -EINVAL; |
| 918 | 938 | ||
| 919 | mvm->scan_rx_ant = scan_rx_ant; | 939 | if (mvm->scan_rx_ant != scan_rx_ant) { |
| 940 | mvm->scan_rx_ant = scan_rx_ant; | ||
| 941 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
| 942 | iwl_mvm_config_scan(mvm); | ||
| 943 | } | ||
| 920 | 944 | ||
| 921 | return count; | 945 | return count; |
| 922 | } | 946 | } |
| @@ -1158,6 +1182,118 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, | |||
| 1158 | 1182 | ||
| 1159 | return ret; | 1183 | return ret; |
| 1160 | } | 1184 | } |
| 1185 | |||
| 1186 | #define MAX_NUM_ND_MATCHSETS 10 | ||
| 1187 | |||
| 1188 | static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf, | ||
| 1189 | size_t count, loff_t *ppos) | ||
| 1190 | { | ||
| 1191 | const char *seps = ",\n"; | ||
| 1192 | char *buf_ptr = buf; | ||
| 1193 | char *value_str = NULL; | ||
| 1194 | int ret, i; | ||
| 1195 | |||
| 1196 | /* TODO: don't free if write is being called several times in one go */ | ||
| 1197 | if (mvm->nd_config) { | ||
| 1198 | kfree(mvm->nd_config->match_sets); | ||
| 1199 | kfree(mvm->nd_config); | ||
| 1200 | mvm->nd_config = NULL; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) + | ||
| 1204 | (11 * sizeof(struct ieee80211_channel *)), | ||
| 1205 | GFP_KERNEL); | ||
| 1206 | if (!mvm->nd_config) { | ||
| 1207 | ret = -ENOMEM; | ||
| 1208 | goto out_free; | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | mvm->nd_config->n_channels = 11; | ||
| 1212 | mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20; | ||
| 1213 | mvm->nd_config->interval = 5; | ||
| 1214 | mvm->nd_config->min_rssi_thold = -80; | ||
| 1215 | for (i = 0; i < mvm->nd_config->n_channels; i++) | ||
| 1216 | mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i]; | ||
| 1217 | |||
| 1218 | mvm->nd_config->match_sets = | ||
| 1219 | kcalloc(MAX_NUM_ND_MATCHSETS, | ||
| 1220 | sizeof(*mvm->nd_config->match_sets), | ||
| 1221 | GFP_KERNEL); | ||
| 1222 | if (!mvm->nd_config->match_sets) { | ||
| 1223 | ret = -ENOMEM; | ||
| 1224 | goto out_free; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | while ((value_str = strsep(&buf_ptr, seps)) && | ||
| 1228 | strlen(value_str)) { | ||
| 1229 | struct cfg80211_match_set *set; | ||
| 1230 | |||
| 1231 | if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) { | ||
| 1232 | ret = -EINVAL; | ||
| 1233 | goto out_free; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets]; | ||
| 1237 | set->ssid.ssid_len = strlen(value_str); | ||
| 1238 | |||
| 1239 | if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
| 1240 | ret = -EINVAL; | ||
| 1241 | goto out_free; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len); | ||
| 1245 | |||
| 1246 | mvm->nd_config->n_match_sets++; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | ret = count; | ||
| 1250 | |||
| 1251 | if (mvm->nd_config->n_match_sets) | ||
| 1252 | goto out; | ||
| 1253 | |||
| 1254 | out_free: | ||
| 1255 | if (mvm->nd_config) | ||
| 1256 | kfree(mvm->nd_config->match_sets); | ||
| 1257 | kfree(mvm->nd_config); | ||
| 1258 | mvm->nd_config = NULL; | ||
| 1259 | out: | ||
| 1260 | return ret; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | static ssize_t | ||
| 1264 | iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf, | ||
| 1265 | size_t count, loff_t *ppos) | ||
| 1266 | { | ||
| 1267 | struct iwl_mvm *mvm = file->private_data; | ||
| 1268 | size_t bufsz, ret; | ||
| 1269 | char *buf; | ||
| 1270 | int i, n_match_sets, pos = 0; | ||
| 1271 | |||
| 1272 | n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0; | ||
| 1273 | |||
| 1274 | bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1; | ||
| 1275 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
| 1276 | if (!buf) | ||
| 1277 | return -ENOMEM; | ||
| 1278 | |||
| 1279 | for (i = 0; i < n_match_sets; i++) { | ||
| 1280 | if (pos + | ||
| 1281 | mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) { | ||
| 1282 | ret = -EIO; | ||
| 1283 | goto out; | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid, | ||
| 1287 | mvm->nd_config->match_sets[i].ssid.ssid_len); | ||
| 1288 | pos += mvm->nd_config->match_sets[i].ssid.ssid_len; | ||
| 1289 | buf[pos++] = '\n'; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
| 1293 | out: | ||
| 1294 | kfree(buf); | ||
| 1295 | return ret; | ||
| 1296 | } | ||
| 1161 | #endif | 1297 | #endif |
| 1162 | 1298 | ||
| 1163 | #define PRINT_MVM_REF(ref) do { \ | 1299 | #define PRINT_MVM_REF(ref) do { \ |
| @@ -1190,7 +1326,20 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | |||
| 1190 | PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); | 1326 | PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); |
| 1191 | PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); | 1327 | PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); |
| 1192 | PRINT_MVM_REF(IWL_MVM_REF_USER); | 1328 | PRINT_MVM_REF(IWL_MVM_REF_USER); |
| 1329 | PRINT_MVM_REF(IWL_MVM_REF_TX); | ||
| 1330 | PRINT_MVM_REF(IWL_MVM_REF_TX_AGG); | ||
| 1331 | PRINT_MVM_REF(IWL_MVM_REF_ADD_IF); | ||
| 1332 | PRINT_MVM_REF(IWL_MVM_REF_START_AP); | ||
| 1333 | PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED); | ||
| 1334 | PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX); | ||
| 1335 | PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS); | ||
| 1336 | PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL); | ||
| 1337 | PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ); | ||
| 1338 | PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE); | ||
| 1339 | PRINT_MVM_REF(IWL_MVM_REF_NMI); | ||
| 1340 | PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); | ||
| 1193 | PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); | 1341 | PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); |
| 1342 | PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); | ||
| 1194 | 1343 | ||
| 1195 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1344 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
| 1196 | } | 1345 | } |
| @@ -1296,6 +1445,8 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); | |||
| 1296 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); | 1445 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); |
| 1297 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); | 1446 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); |
| 1298 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); | 1447 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); |
| 1448 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); | ||
| 1449 | MVM_DEBUGFS_READ_FILE_OPS(nic_temp); | ||
| 1299 | MVM_DEBUGFS_READ_FILE_OPS(stations); | 1450 | MVM_DEBUGFS_READ_FILE_OPS(stations); |
| 1300 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | 1451 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); |
| 1301 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); | 1452 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); |
| @@ -1309,12 +1460,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); | |||
| 1309 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); | 1460 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); |
| 1310 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); | 1461 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); |
| 1311 | 1462 | ||
| 1312 | static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { | ||
| 1313 | .open = iwl_dbgfs_fw_error_dump_open, | ||
| 1314 | .read = iwl_dbgfs_fw_error_dump_read, | ||
| 1315 | .release = iwl_dbgfs_fw_error_dump_release, | ||
| 1316 | }; | ||
| 1317 | |||
| 1318 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | 1463 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING |
| 1319 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); | 1464 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); |
| 1320 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); | 1465 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); |
| @@ -1322,6 +1467,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); | |||
| 1322 | 1467 | ||
| 1323 | #ifdef CONFIG_PM_SLEEP | 1468 | #ifdef CONFIG_PM_SLEEP |
| 1324 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); | 1469 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); |
| 1470 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384); | ||
| 1325 | #endif | 1471 | #endif |
| 1326 | 1472 | ||
| 1327 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | 1473 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) |
| @@ -1336,8 +1482,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
| 1336 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); | 1482 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); |
| 1337 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); | 1483 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); |
| 1338 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | 1484 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); |
| 1485 | MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, | ||
| 1486 | S_IWUSR | S_IRUSR); | ||
| 1487 | MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); | ||
| 1339 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); | 1488 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); |
| 1340 | MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); | ||
| 1341 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); | 1489 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); |
| 1342 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); | 1490 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); |
| 1343 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, | 1491 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, |
| @@ -1378,8 +1526,16 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
| 1378 | if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, | 1526 | if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, |
| 1379 | mvm->debugfs_dir, &mvm->d3_wake_sysassert)) | 1527 | mvm->debugfs_dir, &mvm->d3_wake_sysassert)) |
| 1380 | goto err; | 1528 | goto err; |
| 1529 | MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | ||
| 1381 | #endif | 1530 | #endif |
| 1382 | 1531 | ||
| 1532 | if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR, | ||
| 1533 | mvm->debugfs_dir, | ||
| 1534 | &mvm->low_latency_agg_frame_limit)) | ||
| 1535 | goto err; | ||
| 1536 | if (!debugfs_create_u8("ps_disabled", S_IRUSR, | ||
| 1537 | mvm->debugfs_dir, &mvm->ps_disabled)) | ||
| 1538 | goto err; | ||
| 1383 | if (!debugfs_create_blob("nvm_hw", S_IRUSR, | 1539 | if (!debugfs_create_blob("nvm_hw", S_IRUSR, |
| 1384 | mvm->debugfs_dir, &mvm->nvm_hw_blob)) | 1540 | mvm->debugfs_dir, &mvm->nvm_hw_blob)) |
| 1385 | goto err; | 1541 | goto err; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h index e3a9774af495..8c4190e7e027 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.h +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 69875716dcdb..f3b11897991e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -82,6 +84,8 @@ | |||
| 82 | * @BT_COEX_SYNC2SCO: | 84 | * @BT_COEX_SYNC2SCO: |
| 83 | * @BT_COEX_CORUNNING: | 85 | * @BT_COEX_CORUNNING: |
| 84 | * @BT_COEX_MPLUT: | 86 | * @BT_COEX_MPLUT: |
| 87 | * @BT_COEX_TTC: | ||
| 88 | * @BT_COEX_RRC: | ||
| 85 | * | 89 | * |
| 86 | * The COEX_MODE must be set for each command. Even if it is not changed. | 90 | * The COEX_MODE must be set for each command. Even if it is not changed. |
| 87 | */ | 91 | */ |
| @@ -98,6 +102,8 @@ enum iwl_bt_coex_flags { | |||
| 98 | BT_COEX_SYNC2SCO = BIT(7), | 102 | BT_COEX_SYNC2SCO = BIT(7), |
| 99 | BT_COEX_CORUNNING = BIT(8), | 103 | BT_COEX_CORUNNING = BIT(8), |
| 100 | BT_COEX_MPLUT = BIT(9), | 104 | BT_COEX_MPLUT = BIT(9), |
| 105 | BT_COEX_TTC = BIT(20), | ||
| 106 | BT_COEX_RRC = BIT(21), | ||
| 101 | }; | 107 | }; |
| 102 | 108 | ||
| 103 | /* | 109 | /* |
| @@ -125,6 +131,8 @@ enum iwl_bt_coex_valid_bit_msk { | |||
| 125 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), | 131 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), |
| 126 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), | 132 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), |
| 127 | BT_VALID_SYNC_TO_SCO = BIT(18), | 133 | BT_VALID_SYNC_TO_SCO = BIT(18), |
| 134 | BT_VALID_TTC = BIT(20), | ||
| 135 | BT_VALID_RRC = BIT(21), | ||
| 128 | }; | 136 | }; |
| 129 | 137 | ||
| 130 | /** | 138 | /** |
| @@ -504,7 +512,8 @@ struct iwl_bt_coex_profile_notif_old { | |||
| 504 | u8 bt_agg_traffic_load; | 512 | u8 bt_agg_traffic_load; |
| 505 | u8 bt_ci_compliance; | 513 | u8 bt_ci_compliance; |
| 506 | u8 ttc_enabled; | 514 | u8 ttc_enabled; |
| 507 | __le16 reserved; | 515 | u8 rrc_enabled; |
| 516 | u8 reserved; | ||
| 508 | 517 | ||
| 509 | __le32 primary_ch_lut; | 518 | __le32 primary_ch_lut; |
| 510 | __le32 secondary_ch_lut; | 519 | __le32 secondary_ch_lut; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 13696fe419b7..6d3bea5c59d1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -239,16 +241,12 @@ enum iwl_wowlan_wakeup_filters { | |||
| 239 | IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), | 241 | IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), |
| 240 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ | 242 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ |
| 241 | 243 | ||
| 242 | struct iwl_wowlan_config_cmd_v2 { | 244 | struct iwl_wowlan_config_cmd { |
| 243 | __le32 wakeup_filter; | 245 | __le32 wakeup_filter; |
| 244 | __le16 non_qos_seq; | 246 | __le16 non_qos_seq; |
| 245 | __le16 qos_seq[8]; | 247 | __le16 qos_seq[8]; |
| 246 | u8 wowlan_ba_teardown_tids; | 248 | u8 wowlan_ba_teardown_tids; |
| 247 | u8 is_11n_connection; | 249 | u8 is_11n_connection; |
| 248 | } __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ | ||
| 249 | |||
| 250 | struct iwl_wowlan_config_cmd_v3 { | ||
| 251 | struct iwl_wowlan_config_cmd_v2 common; | ||
| 252 | u8 offloading_tid; | 250 | u8 offloading_tid; |
| 253 | u8 reserved[3]; | 251 | u8 reserved[3]; |
| 254 | } __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ | 252 | } __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index c3a8c86b550d..430020047b77 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -66,13 +68,46 @@ | |||
| 66 | 68 | ||
| 67 | /* Power Management Commands, Responses, Notifications */ | 69 | /* Power Management Commands, Responses, Notifications */ |
| 68 | 70 | ||
| 71 | /** | ||
| 72 | * enum iwl_ltr_config_flags - masks for LTR config command flags | ||
| 73 | * @LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status | ||
| 74 | * @LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow | ||
| 75 | * memory access | ||
| 76 | * @LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR | ||
| 77 | * reg change | ||
| 78 | * @LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from | ||
| 79 | * D0 to D3 | ||
| 80 | * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register | ||
| 81 | * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register | ||
| 82 | * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD | ||
| 83 | */ | ||
| 84 | enum iwl_ltr_config_flags { | ||
| 85 | LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0), | ||
| 86 | LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = BIT(1), | ||
| 87 | LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = BIT(2), | ||
| 88 | LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = BIT(3), | ||
| 89 | LTR_CFG_FLAG_SW_SET_SHORT = BIT(4), | ||
| 90 | LTR_CFG_FLAG_SW_SET_LONG = BIT(5), | ||
| 91 | LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), | ||
| 92 | }; | ||
| 93 | |||
| 94 | /** | ||
| 95 | * struct iwl_ltr_config_cmd - configures the LTR | ||
| 96 | * @flags: See %enum iwl_ltr_config_flags | ||
| 97 | */ | ||
| 98 | struct iwl_ltr_config_cmd { | ||
| 99 | __le32 flags; | ||
| 100 | __le32 static_long; | ||
| 101 | __le32 static_short; | ||
| 102 | } __packed; | ||
| 103 | |||
| 69 | /* Radio LP RX Energy Threshold measured in dBm */ | 104 | /* Radio LP RX Energy Threshold measured in dBm */ |
| 70 | #define POWER_LPRX_RSSI_THRESHOLD 75 | 105 | #define POWER_LPRX_RSSI_THRESHOLD 75 |
| 71 | #define POWER_LPRX_RSSI_THRESHOLD_MAX 94 | 106 | #define POWER_LPRX_RSSI_THRESHOLD_MAX 94 |
| 72 | #define POWER_LPRX_RSSI_THRESHOLD_MIN 30 | 107 | #define POWER_LPRX_RSSI_THRESHOLD_MIN 30 |
| 73 | 108 | ||
| 74 | /** | 109 | /** |
| 75 | * enum iwl_scan_flags - masks for power table command flags | 110 | * enum iwl_power_flags - masks for power table command flags |
| 76 | * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off | 111 | * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off |
| 77 | * receiver and transmitter. '0' - does not allow. | 112 | * receiver and transmitter. '0' - does not allow. |
| 78 | * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, | 113 | * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, |
| @@ -335,7 +370,7 @@ struct iwl_beacon_filter_cmd { | |||
| 335 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 | 370 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 |
| 336 | #define IWL_BF_DEBUG_FLAG_D0I3 0 | 371 | #define IWL_BF_DEBUG_FLAG_D0I3 0 |
| 337 | 372 | ||
| 338 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 | 373 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 0 |
| 339 | #define IWL_BF_ESCAPE_TIMER_D0I3 0 | 374 | #define IWL_BF_ESCAPE_TIMER_D0I3 0 |
| 340 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 | 375 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 |
| 341 | #define IWL_BF_ESCAPE_TIMER_MIN 0 | 376 | #define IWL_BF_ESCAPE_TIMER_MIN 0 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index c02a9e45ec5e..1f2acf47bfb2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -668,6 +670,8 @@ struct iwl_scan_channel_opt { | |||
| 668 | * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification | 670 | * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification |
| 669 | * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching | 671 | * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching |
| 670 | * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented | 672 | * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented |
| 673 | * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report | ||
| 674 | * and DS parameter set IEs into probe requests. | ||
| 671 | */ | 675 | */ |
| 672 | enum iwl_mvm_lmac_scan_flags { | 676 | enum iwl_mvm_lmac_scan_flags { |
| 673 | IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL = BIT(0), | 677 | IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL = BIT(0), |
| @@ -676,6 +680,7 @@ enum iwl_mvm_lmac_scan_flags { | |||
| 676 | IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE = BIT(3), | 680 | IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE = BIT(3), |
| 677 | IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = BIT(4), | 681 | IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = BIT(4), |
| 678 | IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED = BIT(5), | 682 | IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED = BIT(5), |
| 683 | IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED = BIT(6), | ||
| 679 | }; | 684 | }; |
| 680 | 685 | ||
| 681 | enum iwl_scan_priority { | 686 | enum iwl_scan_priority { |
| @@ -789,4 +794,301 @@ struct iwl_periodic_scan_complete { | |||
| 789 | __le32 reserved; | 794 | __le32 reserved; |
| 790 | } __packed; | 795 | } __packed; |
| 791 | 796 | ||
| 797 | /* UMAC Scan API */ | ||
| 798 | |||
| 799 | /** | ||
| 800 | * struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands | ||
| 801 | * @size: size of the command (not including header) | ||
| 802 | * @reserved0: for future use and alignment | ||
| 803 | * @ver: API version number | ||
| 804 | */ | ||
| 805 | struct iwl_mvm_umac_cmd_hdr { | ||
| 806 | __le16 size; | ||
| 807 | u8 reserved0; | ||
| 808 | u8 ver; | ||
| 809 | } __packed; | ||
| 810 | |||
| 811 | #define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8 | ||
| 812 | |||
| 813 | enum scan_config_flags { | ||
| 814 | SCAN_CONFIG_FLAG_ACTIVATE = BIT(0), | ||
| 815 | SCAN_CONFIG_FLAG_DEACTIVATE = BIT(1), | ||
| 816 | SCAN_CONFIG_FLAG_FORBID_CHUB_REQS = BIT(2), | ||
| 817 | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS = BIT(3), | ||
| 818 | SCAN_CONFIG_FLAG_SET_TX_CHAINS = BIT(8), | ||
| 819 | SCAN_CONFIG_FLAG_SET_RX_CHAINS = BIT(9), | ||
| 820 | SCAN_CONFIG_FLAG_SET_AUX_STA_ID = BIT(10), | ||
| 821 | SCAN_CONFIG_FLAG_SET_ALL_TIMES = BIT(11), | ||
| 822 | SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES = BIT(12), | ||
| 823 | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS = BIT(13), | ||
| 824 | SCAN_CONFIG_FLAG_SET_LEGACY_RATES = BIT(14), | ||
| 825 | SCAN_CONFIG_FLAG_SET_MAC_ADDR = BIT(15), | ||
| 826 | SCAN_CONFIG_FLAG_SET_FRAGMENTED = BIT(16), | ||
| 827 | SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED = BIT(17), | ||
| 828 | SCAN_CONFIG_FLAG_SET_CAM_MODE = BIT(18), | ||
| 829 | SCAN_CONFIG_FLAG_CLEAR_CAM_MODE = BIT(19), | ||
| 830 | SCAN_CONFIG_FLAG_SET_PROMISC_MODE = BIT(20), | ||
| 831 | SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE = BIT(21), | ||
| 832 | |||
| 833 | /* Bits 26-31 are for num of channels in channel_array */ | ||
| 834 | #define SCAN_CONFIG_N_CHANNELS(n) ((n) << 26) | ||
| 835 | }; | ||
| 836 | |||
| 837 | enum scan_config_rates { | ||
| 838 | /* OFDM basic rates */ | ||
| 839 | SCAN_CONFIG_RATE_6M = BIT(0), | ||
| 840 | SCAN_CONFIG_RATE_9M = BIT(1), | ||
| 841 | SCAN_CONFIG_RATE_12M = BIT(2), | ||
| 842 | SCAN_CONFIG_RATE_18M = BIT(3), | ||
| 843 | SCAN_CONFIG_RATE_24M = BIT(4), | ||
| 844 | SCAN_CONFIG_RATE_36M = BIT(5), | ||
| 845 | SCAN_CONFIG_RATE_48M = BIT(6), | ||
| 846 | SCAN_CONFIG_RATE_54M = BIT(7), | ||
| 847 | /* CCK basic rates */ | ||
| 848 | SCAN_CONFIG_RATE_1M = BIT(8), | ||
| 849 | SCAN_CONFIG_RATE_2M = BIT(9), | ||
| 850 | SCAN_CONFIG_RATE_5M = BIT(10), | ||
| 851 | SCAN_CONFIG_RATE_11M = BIT(11), | ||
| 852 | |||
| 853 | /* Bits 16-27 are for supported rates */ | ||
| 854 | #define SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16) | ||
| 855 | }; | ||
| 856 | |||
| 857 | enum iwl_channel_flags { | ||
| 858 | IWL_CHANNEL_FLAG_EBS = BIT(0), | ||
| 859 | IWL_CHANNEL_FLAG_ACCURATE_EBS = BIT(1), | ||
| 860 | IWL_CHANNEL_FLAG_EBS_ADD = BIT(2), | ||
| 861 | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = BIT(3), | ||
| 862 | }; | ||
| 863 | |||
| 864 | /** | ||
| 865 | * struct iwl_scan_config | ||
| 866 | * @hdr: umac command header | ||
| 867 | * @flags: enum scan_config_flags | ||
| 868 | * @tx_chains: valid_tx antenna - ANT_* definitions | ||
| 869 | * @rx_chains: valid_rx antenna - ANT_* definitions | ||
| 870 | * @legacy_rates: default legacy rates - enum scan_config_rates | ||
| 871 | * @out_of_channel_time: default max out of serving channel time | ||
| 872 | * @suspend_time: default max suspend time | ||
| 873 | * @dwell_active: default dwell time for active scan | ||
| 874 | * @dwell_passive: default dwell time for passive scan | ||
| 875 | * @dwell_fragmented: default dwell time for fragmented scan | ||
| 876 | * @reserved: for future use and alignment | ||
| 877 | * @mac_addr: default mac address to be used in probes | ||
| 878 | * @bcast_sta_id: the index of the station in the fw | ||
| 879 | * @channel_flags: default channel flags - enum iwl_channel_flags | ||
| 880 | * scan_config_channel_flag | ||
| 881 | * @channel_array: default supported channels | ||
| 882 | */ | ||
| 883 | struct iwl_scan_config { | ||
| 884 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
| 885 | __le32 flags; | ||
| 886 | __le32 tx_chains; | ||
| 887 | __le32 rx_chains; | ||
| 888 | __le32 legacy_rates; | ||
| 889 | __le32 out_of_channel_time; | ||
| 890 | __le32 suspend_time; | ||
| 891 | u8 dwell_active; | ||
| 892 | u8 dwell_passive; | ||
| 893 | u8 dwell_fragmented; | ||
| 894 | u8 reserved; | ||
| 895 | u8 mac_addr[ETH_ALEN]; | ||
| 896 | u8 bcast_sta_id; | ||
| 897 | u8 channel_flags; | ||
| 898 | u8 channel_array[]; | ||
| 899 | } __packed; /* SCAN_CONFIG_DB_CMD_API_S */ | ||
| 900 | |||
| 901 | /** | ||
| 902 | * iwl_umac_scan_flags | ||
| 903 | *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request | ||
| 904 | * can be preempted by other scan requests with higher priority. | ||
| 905 | * The low priority scan is aborted. | ||
| 906 | *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver | ||
| 907 | * when scan starts. | ||
| 908 | */ | ||
| 909 | enum iwl_umac_scan_flags { | ||
| 910 | IWL_UMAC_SCAN_FLAG_PREEMPTIVE = BIT(0), | ||
| 911 | IWL_UMAC_SCAN_FLAG_START_NOTIF = BIT(1), | ||
| 912 | }; | ||
| 913 | |||
| 914 | enum iwl_umac_scan_uid_offsets { | ||
| 915 | IWL_UMAC_SCAN_UID_TYPE_OFFSET = 0, | ||
| 916 | IWL_UMAC_SCAN_UID_SEQ_OFFSET = 8, | ||
| 917 | }; | ||
| 918 | |||
| 919 | enum iwl_umac_scan_general_flags { | ||
| 920 | IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC = BIT(0), | ||
| 921 | IWL_UMAC_SCAN_GEN_FLAGS_OVER_BT = BIT(1), | ||
| 922 | IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL = BIT(2), | ||
| 923 | IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE = BIT(3), | ||
| 924 | IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT = BIT(4), | ||
| 925 | IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE = BIT(5), | ||
| 926 | IWL_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = BIT(6), | ||
| 927 | IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = BIT(7), | ||
| 928 | IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8), | ||
| 929 | IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9) | ||
| 930 | }; | ||
| 931 | |||
| 932 | /** | ||
| 933 | * struct iwl_scan_channel_cfg_umac | ||
| 934 | * @flags: bitmap - 0-19: directed scan to i'th ssid. | ||
| 935 | * @channel_num: channel number 1-13 etc. | ||
| 936 | * @iter_count: repetition count for the channel. | ||
| 937 | * @iter_interval: interval between two scan interations on one channel. | ||
| 938 | */ | ||
| 939 | struct iwl_scan_channel_cfg_umac { | ||
| 940 | __le32 flags; | ||
| 941 | u8 channel_num; | ||
| 942 | u8 iter_count; | ||
| 943 | __le16 iter_interval; | ||
| 944 | } __packed; /* SCAN_CHANNEL_CFG_S_VER2 */ | ||
| 945 | |||
| 946 | /** | ||
| 947 | * struct iwl_scan_umac_schedule | ||
| 948 | * @interval: interval in seconds between scan iterations | ||
| 949 | * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop | ||
| 950 | * @reserved: for alignment and future use | ||
| 951 | */ | ||
| 952 | struct iwl_scan_umac_schedule { | ||
| 953 | __le16 interval; | ||
| 954 | u8 iter_count; | ||
| 955 | u8 reserved; | ||
| 956 | } __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */ | ||
| 957 | |||
| 958 | /** | ||
| 959 | * struct iwl_scan_req_umac_tail - the rest of the UMAC scan request command | ||
| 960 | * parameters following channels configuration array. | ||
| 961 | * @schedule: two scheduling plans. | ||
| 962 | * @delay: delay in TUs before starting the first scan iteration | ||
| 963 | * @reserved: for future use and alignment | ||
| 964 | * @preq: probe request with IEs blocks | ||
| 965 | * @direct_scan: list of SSIDs for directed active scan | ||
| 966 | */ | ||
| 967 | struct iwl_scan_req_umac_tail { | ||
| 968 | /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ | ||
| 969 | struct iwl_scan_umac_schedule schedule[2]; | ||
| 970 | __le16 delay; | ||
| 971 | __le16 reserved; | ||
| 972 | /* SCAN_PROBE_PARAMS_API_S_VER_1 */ | ||
| 973 | struct iwl_scan_probe_req preq; | ||
| 974 | struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; | ||
| 975 | } __packed; | ||
| 976 | |||
| 977 | /** | ||
| 978 | * struct iwl_scan_req_umac | ||
| 979 | * @hdr: umac command header | ||
| 980 | * @flags: &enum iwl_umac_scan_flags | ||
| 981 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
| 982 | * @ooc_priority: out of channel priority - &enum iwl_scan_priority | ||
| 983 | * @general_flags: &enum iwl_umac_scan_general_flags | ||
| 984 | * @reserved1: for future use and alignment | ||
| 985 | * @active_dwell: dwell time for active scan | ||
| 986 | * @passive_dwell: dwell time for passive scan | ||
| 987 | * @fragmented_dwell: dwell time for fragmented passive scan | ||
| 988 | * @max_out_time: max out of serving channel time | ||
| 989 | * @suspend_time: max suspend time | ||
| 990 | * @scan_priority: scan internal prioritization &enum iwl_scan_priority | ||
| 991 | * @channel_flags: &enum iwl_scan_channel_flags | ||
| 992 | * @n_channels: num of channels in scan request | ||
| 993 | * @reserved2: for future use and alignment | ||
| 994 | * @data: &struct iwl_scan_channel_cfg_umac and | ||
| 995 | * &struct iwl_scan_req_umac_tail | ||
| 996 | */ | ||
| 997 | struct iwl_scan_req_umac { | ||
| 998 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
| 999 | __le32 flags; | ||
| 1000 | __le32 uid; | ||
| 1001 | __le32 ooc_priority; | ||
| 1002 | /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ | ||
| 1003 | __le32 general_flags; | ||
| 1004 | u8 reserved1; | ||
| 1005 | u8 active_dwell; | ||
| 1006 | u8 passive_dwell; | ||
| 1007 | u8 fragmented_dwell; | ||
| 1008 | __le32 max_out_time; | ||
| 1009 | __le32 suspend_time; | ||
| 1010 | __le32 scan_priority; | ||
| 1011 | /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ | ||
| 1012 | u8 channel_flags; | ||
| 1013 | u8 n_channels; | ||
| 1014 | __le16 reserved2; | ||
| 1015 | u8 data[]; | ||
| 1016 | } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ | ||
| 1017 | |||
| 1018 | /** | ||
| 1019 | * struct iwl_umac_scan_abort | ||
| 1020 | * @hdr: umac command header | ||
| 1021 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
| 1022 | * @flags: reserved | ||
| 1023 | */ | ||
| 1024 | struct iwl_umac_scan_abort { | ||
| 1025 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
| 1026 | __le32 uid; | ||
| 1027 | __le32 flags; | ||
| 1028 | } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ | ||
| 1029 | |||
| 1030 | /** | ||
| 1031 | * struct iwl_umac_scan_complete | ||
| 1032 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
| 1033 | * @last_schedule: last scheduling line | ||
| 1034 | * @last_iter: last scan iteration number | ||
| 1035 | * @scan status: &enum iwl_scan_offload_complete_status | ||
| 1036 | * @ebs_status: &enum iwl_scan_ebs_status | ||
| 1037 | * @time_from_last_iter: time elapsed from last iteration | ||
| 1038 | * @reserved: for future use | ||
| 1039 | */ | ||
| 1040 | struct iwl_umac_scan_complete { | ||
| 1041 | __le32 uid; | ||
| 1042 | u8 last_schedule; | ||
| 1043 | u8 last_iter; | ||
| 1044 | u8 status; | ||
| 1045 | u8 ebs_status; | ||
| 1046 | __le32 time_from_last_iter; | ||
| 1047 | __le32 reserved; | ||
| 1048 | } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ | ||
| 1049 | |||
| 1050 | #define SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 5 | ||
| 1051 | /** | ||
| 1052 | * struct iwl_scan_offload_profile_match - match information | ||
| 1053 | * @bssid: matched bssid | ||
| 1054 | * @channel: channel where the match occurred | ||
| 1055 | * @energy: | ||
| 1056 | * @matching_feature: | ||
| 1057 | * @matching_channels: bitmap of channels that matched, referencing | ||
| 1058 | * the channels passed in tue scan offload request | ||
| 1059 | */ | ||
| 1060 | struct iwl_scan_offload_profile_match { | ||
| 1061 | u8 bssid[ETH_ALEN]; | ||
| 1062 | __le16 reserved; | ||
| 1063 | u8 channel; | ||
| 1064 | u8 energy; | ||
| 1065 | u8 matching_feature; | ||
| 1066 | u8 matching_channels[SCAN_OFFLOAD_MATCHING_CHANNELS_LEN]; | ||
| 1067 | } __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_1 */ | ||
| 1068 | |||
| 1069 | /** | ||
| 1070 | * struct iwl_scan_offload_profiles_query - match results query response | ||
| 1071 | * @matched_profiles: bitmap of matched profiles, referencing the | ||
| 1072 | * matches passed in the scan offload request | ||
| 1073 | * @last_scan_age: age of the last offloaded scan | ||
| 1074 | * @n_scans_done: number of offloaded scans done | ||
| 1075 | * @gp2_d0u: GP2 when D0U occurred | ||
| 1076 | * @gp2_invoked: GP2 when scan offload was invoked | ||
| 1077 | * @resume_while_scanning: not used | ||
| 1078 | * @self_recovery: obsolete | ||
| 1079 | * @reserved: reserved | ||
| 1080 | * @matches: array of match information, one for each match | ||
| 1081 | */ | ||
| 1082 | struct iwl_scan_offload_profiles_query { | ||
| 1083 | __le32 matched_profiles; | ||
| 1084 | __le32 last_scan_age; | ||
| 1085 | __le32 n_scans_done; | ||
| 1086 | __le32 gp2_d0u; | ||
| 1087 | __le32 gp2_invoked; | ||
| 1088 | u8 resume_while_scanning; | ||
| 1089 | u8 self_recovery; | ||
| 1090 | __le16 reserved; | ||
| 1091 | struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; | ||
| 1092 | } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */ | ||
| 1093 | |||
| 792 | #endif | 1094 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 47bd0406355d..21dd5b771660 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index d6073f67b212..5bca1f8bfebf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | |||
| @@ -66,6 +66,7 @@ | |||
| 66 | /** | 66 | /** |
| 67 | * enum iwl_tx_flags - bitmasks for tx_flags in TX command | 67 | * enum iwl_tx_flags - bitmasks for tx_flags in TX command |
| 68 | * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame | 68 | * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame |
| 69 | * @TX_CMD_FLG_WRITE_TX_POWER: update current tx power value in the mgmt frame | ||
| 69 | * @TX_CMD_FLG_ACK: expect ACK from receiving station | 70 | * @TX_CMD_FLG_ACK: expect ACK from receiving station |
| 70 | * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. | 71 | * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. |
| 71 | * Otherwise, use rate_n_flags from the TX command | 72 | * Otherwise, use rate_n_flags from the TX command |
| @@ -97,6 +98,7 @@ | |||
| 97 | */ | 98 | */ |
| 98 | enum iwl_tx_flags { | 99 | enum iwl_tx_flags { |
| 99 | TX_CMD_FLG_PROT_REQUIRE = BIT(0), | 100 | TX_CMD_FLG_PROT_REQUIRE = BIT(0), |
| 101 | TX_CMD_FLG_WRITE_TX_POWER = BIT(1), | ||
| 100 | TX_CMD_FLG_ACK = BIT(3), | 102 | TX_CMD_FLG_ACK = BIT(3), |
| 101 | TX_CMD_FLG_STA_RATE = BIT(4), | 103 | TX_CMD_FLG_STA_RATE = BIT(4), |
| 102 | TX_CMD_FLG_BAR = BIT(6), | 104 | TX_CMD_FLG_BAR = BIT(6), |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 9a922f3bd16b..88af6dd2ceaa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -73,16 +75,20 @@ | |||
| 73 | #include "fw-api-coex.h" | 75 | #include "fw-api-coex.h" |
| 74 | #include "fw-api-scan.h" | 76 | #include "fw-api-scan.h" |
| 75 | 77 | ||
| 76 | /* maximal number of Tx queues in any platform */ | ||
| 77 | #define IWL_MVM_MAX_QUEUES 20 | ||
| 78 | |||
| 79 | /* Tx queue numbers */ | 78 | /* Tx queue numbers */ |
| 80 | enum { | 79 | enum { |
| 81 | IWL_MVM_OFFCHANNEL_QUEUE = 8, | 80 | IWL_MVM_OFFCHANNEL_QUEUE = 8, |
| 82 | IWL_MVM_CMD_QUEUE = 9, | 81 | IWL_MVM_CMD_QUEUE = 9, |
| 83 | }; | 82 | }; |
| 84 | 83 | ||
| 85 | #define IWL_MVM_CMD_FIFO 7 | 84 | enum iwl_mvm_tx_fifo { |
| 85 | IWL_MVM_TX_FIFO_BK = 0, | ||
| 86 | IWL_MVM_TX_FIFO_BE, | ||
| 87 | IWL_MVM_TX_FIFO_VI, | ||
| 88 | IWL_MVM_TX_FIFO_VO, | ||
| 89 | IWL_MVM_TX_FIFO_MCAST = 5, | ||
| 90 | IWL_MVM_TX_FIFO_CMD = 7, | ||
| 91 | }; | ||
| 86 | 92 | ||
| 87 | #define IWL_MVM_STATION_COUNT 16 | 93 | #define IWL_MVM_STATION_COUNT 16 |
| 88 | 94 | ||
| @@ -100,6 +106,12 @@ enum { | |||
| 100 | DBG_CFG = 0x9, | 106 | DBG_CFG = 0x9, |
| 101 | ANTENNA_COUPLING_NOTIFICATION = 0xa, | 107 | ANTENNA_COUPLING_NOTIFICATION = 0xa, |
| 102 | 108 | ||
| 109 | /* UMAC scan commands */ | ||
| 110 | SCAN_CFG_CMD = 0xc, | ||
| 111 | SCAN_REQ_UMAC = 0xd, | ||
| 112 | SCAN_ABORT_UMAC = 0xe, | ||
| 113 | SCAN_COMPLETE_UMAC = 0xf, | ||
| 114 | |||
| 103 | /* station table */ | 115 | /* station table */ |
| 104 | ADD_STA_KEY = 0x17, | 116 | ADD_STA_KEY = 0x17, |
| 105 | ADD_STA = 0x18, | 117 | ADD_STA = 0x18, |
| @@ -110,9 +122,17 @@ enum { | |||
| 110 | TXPATH_FLUSH = 0x1e, | 122 | TXPATH_FLUSH = 0x1e, |
| 111 | MGMT_MCAST_KEY = 0x1f, | 123 | MGMT_MCAST_KEY = 0x1f, |
| 112 | 124 | ||
| 125 | /* scheduler config */ | ||
| 126 | SCD_QUEUE_CFG = 0x1d, | ||
| 127 | |||
| 113 | /* global key */ | 128 | /* global key */ |
| 114 | WEP_KEY = 0x20, | 129 | WEP_KEY = 0x20, |
| 115 | 130 | ||
| 131 | /* TDLS */ | ||
| 132 | TDLS_CHANNEL_SWITCH_CMD = 0x27, | ||
| 133 | TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, | ||
| 134 | TDLS_CONFIG_CMD = 0xa7, | ||
| 135 | |||
| 116 | /* MAC and Binding commands */ | 136 | /* MAC and Binding commands */ |
| 117 | MAC_CONTEXT_CMD = 0x28, | 137 | MAC_CONTEXT_CMD = 0x28, |
| 118 | TIME_EVENT_CMD = 0x29, /* both CMD and response */ | 138 | TIME_EVENT_CMD = 0x29, /* both CMD and response */ |
| @@ -148,6 +168,7 @@ enum { | |||
| 148 | /* Power - legacy power table command */ | 168 | /* Power - legacy power table command */ |
| 149 | POWER_TABLE_CMD = 0x77, | 169 | POWER_TABLE_CMD = 0x77, |
| 150 | PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, | 170 | PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, |
| 171 | LTR_CONFIG = 0xee, | ||
| 151 | 172 | ||
| 152 | /* Thermal Throttling*/ | 173 | /* Thermal Throttling*/ |
| 153 | REPLY_THERMAL_MNG_BACKOFF = 0x7e, | 174 | REPLY_THERMAL_MNG_BACKOFF = 0x7e, |
| @@ -180,10 +201,14 @@ enum { | |||
| 180 | /* Power - new power table command */ | 201 | /* Power - new power table command */ |
| 181 | MAC_PM_POWER_TABLE = 0xa9, | 202 | MAC_PM_POWER_TABLE = 0xa9, |
| 182 | 203 | ||
| 204 | MFUART_LOAD_NOTIFICATION = 0xb1, | ||
| 205 | |||
| 183 | REPLY_RX_PHY_CMD = 0xc0, | 206 | REPLY_RX_PHY_CMD = 0xc0, |
| 184 | REPLY_RX_MPDU_CMD = 0xc1, | 207 | REPLY_RX_MPDU_CMD = 0xc1, |
| 185 | BA_NOTIF = 0xc5, | 208 | BA_NOTIF = 0xc5, |
| 186 | 209 | ||
| 210 | MARKER_CMD = 0xcb, | ||
| 211 | |||
| 187 | /* BT Coex */ | 212 | /* BT Coex */ |
| 188 | BT_COEX_PRIO_TABLE = 0xcc, | 213 | BT_COEX_PRIO_TABLE = 0xcc, |
| 189 | BT_COEX_PROT_ENV = 0xcd, | 214 | BT_COEX_PROT_ENV = 0xcd, |
| @@ -197,6 +222,10 @@ enum { | |||
| 197 | REPLY_SF_CFG_CMD = 0xd1, | 222 | REPLY_SF_CFG_CMD = 0xd1, |
| 198 | REPLY_BEACON_FILTERING_CMD = 0xd2, | 223 | REPLY_BEACON_FILTERING_CMD = 0xd2, |
| 199 | 224 | ||
| 225 | /* DTS measurements */ | ||
| 226 | CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, | ||
| 227 | DTS_MEASUREMENT_NOTIFICATION = 0xdd, | ||
| 228 | |||
| 200 | REPLY_DEBUG_CMD = 0xf0, | 229 | REPLY_DEBUG_CMD = 0xf0, |
| 201 | DEBUG_LOG_MSG = 0xf7, | 230 | DEBUG_LOG_MSG = 0xf7, |
| 202 | 231 | ||
| @@ -220,11 +249,9 @@ enum { | |||
| 220 | WOWLAN_TX_POWER_PER_DB = 0xe6, | 249 | WOWLAN_TX_POWER_PER_DB = 0xe6, |
| 221 | 250 | ||
| 222 | /* and for NetDetect */ | 251 | /* and for NetDetect */ |
| 223 | NET_DETECT_CONFIG_CMD = 0x54, | 252 | SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, |
| 224 | NET_DETECT_PROFILES_QUERY_CMD = 0x56, | 253 | SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD = 0x58, |
| 225 | NET_DETECT_PROFILES_CMD = 0x57, | 254 | SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD = 0x59, |
| 226 | NET_DETECT_HOTSPOTS_CMD = 0x58, | ||
| 227 | NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59, | ||
| 228 | 255 | ||
| 229 | REPLY_MAX = 0xff, | 256 | REPLY_MAX = 0xff, |
| 230 | }; | 257 | }; |
| @@ -542,7 +569,7 @@ enum iwl_time_event_type { | |||
| 542 | TE_WIDI_TX_SYNC, | 569 | TE_WIDI_TX_SYNC, |
| 543 | 570 | ||
| 544 | /* Channel Switch NoA */ | 571 | /* Channel Switch NoA */ |
| 545 | TE_P2P_GO_CSA_NOA, | 572 | TE_CHANNEL_SWITCH_PERIOD, |
| 546 | 573 | ||
| 547 | TE_MAX | 574 | TE_MAX |
| 548 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ | 575 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ |
| @@ -1185,6 +1212,21 @@ struct iwl_missed_beacons_notif { | |||
| 1185 | } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ | 1212 | } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ |
| 1186 | 1213 | ||
| 1187 | /** | 1214 | /** |
| 1215 | * struct iwl_mfuart_load_notif - mfuart image version & status | ||
| 1216 | * ( MFUART_LOAD_NOTIFICATION = 0xb1 ) | ||
| 1217 | * @installed_ver: installed image version | ||
| 1218 | * @external_ver: external image version | ||
| 1219 | * @status: MFUART loading status | ||
| 1220 | * @duration: MFUART loading time | ||
| 1221 | */ | ||
| 1222 | struct iwl_mfuart_load_notif { | ||
| 1223 | __le32 installed_ver; | ||
| 1224 | __le32 external_ver; | ||
| 1225 | __le32 status; | ||
| 1226 | __le32 duration; | ||
| 1227 | } __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/ | ||
| 1228 | |||
| 1229 | /** | ||
| 1188 | * struct iwl_set_calib_default_cmd - set default value for calibration. | 1230 | * struct iwl_set_calib_default_cmd - set default value for calibration. |
| 1189 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) | 1231 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) |
| 1190 | * @calib_index: the calibration to set value for | 1232 | * @calib_index: the calibration to set value for |
| @@ -1307,6 +1349,38 @@ struct iwl_bcast_filter_cmd { | |||
| 1307 | struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; | 1349 | struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; |
| 1308 | } __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ | 1350 | } __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ |
| 1309 | 1351 | ||
| 1352 | /* | ||
| 1353 | * enum iwl_mvm_marker_id - maker ids | ||
| 1354 | * | ||
| 1355 | * The ids for different type of markers to insert into the usniffer logs | ||
| 1356 | */ | ||
| 1357 | enum iwl_mvm_marker_id { | ||
| 1358 | MARKER_ID_TX_FRAME_LATENCY = 1, | ||
| 1359 | }; /* MARKER_ID_API_E_VER_1 */ | ||
| 1360 | |||
| 1361 | /** | ||
| 1362 | * struct iwl_mvm_marker - mark info into the usniffer logs | ||
| 1363 | * | ||
| 1364 | * (MARKER_CMD = 0xcb) | ||
| 1365 | * | ||
| 1366 | * Mark the UTC time stamp into the usniffer logs together with additional | ||
| 1367 | * metadata, so the usniffer output can be parsed. | ||
| 1368 | * In the command response the ucode will return the GP2 time. | ||
| 1369 | * | ||
| 1370 | * @dw_len: The amount of dwords following this byte including this byte. | ||
| 1371 | * @marker_id: A unique marker id (iwl_mvm_marker_id). | ||
| 1372 | * @reserved: reserved. | ||
| 1373 | * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC | ||
| 1374 | * @metadata: additional meta data that will be written to the unsiffer log | ||
| 1375 | */ | ||
| 1376 | struct iwl_mvm_marker { | ||
| 1377 | u8 dwLen; | ||
| 1378 | u8 markerId; | ||
| 1379 | __le16 reserved; | ||
| 1380 | __le64 timestamp; | ||
| 1381 | __le32 metadata[0]; | ||
| 1382 | } __packed; /* MARKER_API_S_VER_1 */ | ||
| 1383 | |||
| 1310 | struct mvm_statistics_dbg { | 1384 | struct mvm_statistics_dbg { |
| 1311 | __le32 burst_check; | 1385 | __le32 burst_check; |
| 1312 | __le32 burst_count; | 1386 | __le32 burst_count; |
| @@ -1541,7 +1615,7 @@ enum iwl_sf_scenario { | |||
| 1541 | #define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ | 1615 | #define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ |
| 1542 | 1616 | ||
| 1543 | /* smart FIFO default values */ | 1617 | /* smart FIFO default values */ |
| 1544 | #define SF_W_MARK_SISO 4096 | 1618 | #define SF_W_MARK_SISO 6144 |
| 1545 | #define SF_W_MARK_MIMO2 8192 | 1619 | #define SF_W_MARK_MIMO2 8192 |
| 1546 | #define SF_W_MARK_MIMO3 6144 | 1620 | #define SF_W_MARK_MIMO3 6144 |
| 1547 | #define SF_W_MARK_LEGACY 4096 | 1621 | #define SF_W_MARK_LEGACY 4096 |
| @@ -1561,6 +1635,8 @@ enum iwl_sf_scenario { | |||
| 1561 | 1635 | ||
| 1562 | #define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ | 1636 | #define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ |
| 1563 | 1637 | ||
| 1638 | #define SF_CFG_DUMMY_NOTIF_OFF BIT(16) | ||
| 1639 | |||
| 1564 | /** | 1640 | /** |
| 1565 | * Smart Fifo configuration command. | 1641 | * Smart Fifo configuration command. |
| 1566 | * @state: smart fifo state, types listed in enum %iwl_sf_sate. | 1642 | * @state: smart fifo state, types listed in enum %iwl_sf_sate. |
| @@ -1576,4 +1652,230 @@ struct iwl_sf_cfg_cmd { | |||
| 1576 | __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; | 1652 | __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; |
| 1577 | } __packed; /* SF_CFG_API_S_VER_2 */ | 1653 | } __packed; /* SF_CFG_API_S_VER_2 */ |
| 1578 | 1654 | ||
| 1655 | /* DTS measurements */ | ||
| 1656 | |||
| 1657 | enum iwl_dts_measurement_flags { | ||
| 1658 | DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0), | ||
| 1659 | DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1), | ||
| 1660 | }; | ||
| 1661 | |||
| 1662 | /** | ||
| 1663 | * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements | ||
| 1664 | * | ||
| 1665 | * @flags: indicates which measurements we want as specified in &enum | ||
| 1666 | * iwl_dts_measurement_flags | ||
| 1667 | */ | ||
| 1668 | struct iwl_dts_measurement_cmd { | ||
| 1669 | __le32 flags; | ||
| 1670 | } __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */ | ||
| 1671 | |||
| 1672 | /** | ||
| 1673 | * iwl_dts_measurement_notif - notification received with the measurements | ||
| 1674 | * | ||
| 1675 | * @temp: the measured temperature | ||
| 1676 | * @voltage: the measured voltage | ||
| 1677 | */ | ||
| 1678 | struct iwl_dts_measurement_notif { | ||
| 1679 | __le32 temp; | ||
| 1680 | __le32 voltage; | ||
| 1681 | } __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ | ||
| 1682 | |||
| 1683 | /** | ||
| 1684 | * enum iwl_scd_control - scheduler config command control flags | ||
| 1685 | * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue | ||
| 1686 | * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW | ||
| 1687 | */ | ||
| 1688 | enum iwl_scd_control { | ||
| 1689 | IWL_SCD_CONTROL_RM_TID = BIT(4), | ||
| 1690 | IWL_SCD_CONTROL_SET_SSN = BIT(5), | ||
| 1691 | }; | ||
| 1692 | |||
| 1693 | /** | ||
| 1694 | * enum iwl_scd_flags - scheduler config command flags | ||
| 1695 | * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue | ||
| 1696 | * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue | ||
| 1697 | * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled | ||
| 1698 | */ | ||
| 1699 | enum iwl_scd_flags { | ||
| 1700 | IWL_SCD_FLAGS_SHARE_TID = BIT(0), | ||
| 1701 | IWL_SCD_FLAGS_SHARE_RA = BIT(1), | ||
| 1702 | IWL_SCD_FLAGS_DQA_ENABLED = BIT(2), | ||
| 1703 | }; | ||
| 1704 | |||
| 1705 | #define IWL_SCDQ_INVALID_STA 0xff | ||
| 1706 | |||
| 1707 | /** | ||
| 1708 | * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command | ||
| 1709 | * @token: dialog token addba - unused legacy | ||
| 1710 | * @sta_id: station id 4-bit | ||
| 1711 | * @tid: TID 0..7 | ||
| 1712 | * @scd_queue: TFD queue num 0 .. 31 | ||
| 1713 | * @enable: 1 queue enable, 0 queue disable | ||
| 1714 | * @aggregate: 1 aggregated queue, 0 otherwise | ||
| 1715 | * @tx_fifo: tx fifo num 0..7 | ||
| 1716 | * @window: up to 64 | ||
| 1717 | * @ssn: starting seq num 12-bit | ||
| 1718 | * @control: command control flags | ||
| 1719 | * @flags: flags - see &enum iwl_scd_flags | ||
| 1720 | * | ||
| 1721 | * Note that every time the command is sent, all parameters must | ||
| 1722 | * be filled with the exception of | ||
| 1723 | * - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN | ||
| 1724 | * - the window, which is only relevant when starting aggregation | ||
| 1725 | */ | ||
| 1726 | struct iwl_scd_txq_cfg_cmd { | ||
| 1727 | u8 token; | ||
| 1728 | u8 sta_id; | ||
| 1729 | u8 tid; | ||
| 1730 | u8 scd_queue; | ||
| 1731 | u8 enable; | ||
| 1732 | u8 aggregate; | ||
| 1733 | u8 tx_fifo; | ||
| 1734 | u8 window; | ||
| 1735 | __le16 ssn; | ||
| 1736 | u8 control; | ||
| 1737 | u8 flags; | ||
| 1738 | } __packed; | ||
| 1739 | |||
| 1740 | /*********************************** | ||
| 1741 | * TDLS API | ||
| 1742 | ***********************************/ | ||
| 1743 | |||
| 1744 | /* Type of TDLS request */ | ||
| 1745 | enum iwl_tdls_channel_switch_type { | ||
| 1746 | TDLS_SEND_CHAN_SW_REQ = 0, | ||
| 1747 | TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH, | ||
| 1748 | TDLS_MOVE_CH, | ||
| 1749 | }; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */ | ||
| 1750 | |||
| 1751 | /** | ||
| 1752 | * Switch timing sub-element in a TDLS channel-switch command | ||
| 1753 | * @frame_timestamp: GP2 timestamp of channel-switch request/response packet | ||
| 1754 | * received from peer | ||
| 1755 | * @max_offchan_duration: What amount of microseconds out of a DTIM is given | ||
| 1756 | * to the TDLS off-channel communication. For instance if the DTIM is | ||
| 1757 | * 200TU and the TDLS peer is to be given 25% of the time, the value | ||
| 1758 | * given will be 50TU, or 50 * 1024 if translated into microseconds. | ||
| 1759 | * @switch_time: switch time the peer sent in its channel switch timing IE | ||
| 1760 | * @switch_timout: switch timeout the peer sent in its channel switch timing IE | ||
| 1761 | */ | ||
| 1762 | struct iwl_tdls_channel_switch_timing { | ||
| 1763 | __le32 frame_timestamp; /* GP2 time of peer packet Rx */ | ||
| 1764 | __le32 max_offchan_duration; /* given in micro-seconds */ | ||
| 1765 | __le32 switch_time; /* given in micro-seconds */ | ||
| 1766 | __le32 switch_timeout; /* given in micro-seconds */ | ||
| 1767 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_TIMING_DATA_API_S_VER_1 */ | ||
| 1768 | |||
| 1769 | #define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200 | ||
| 1770 | |||
| 1771 | /** | ||
| 1772 | * TDLS channel switch frame template | ||
| 1773 | * | ||
| 1774 | * A template representing a TDLS channel-switch request or response frame | ||
| 1775 | * | ||
| 1776 | * @switch_time_offset: offset to the channel switch timing IE in the template | ||
| 1777 | * @tx_cmd: Tx parameters for the frame | ||
| 1778 | * @data: frame data | ||
| 1779 | */ | ||
| 1780 | struct iwl_tdls_channel_switch_frame { | ||
| 1781 | __le32 switch_time_offset; | ||
| 1782 | struct iwl_tx_cmd tx_cmd; | ||
| 1783 | u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE]; | ||
| 1784 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ | ||
| 1785 | |||
| 1786 | /** | ||
| 1787 | * TDLS channel switch command | ||
| 1788 | * | ||
| 1789 | * The command is sent to initiate a channel switch and also in response to | ||
| 1790 | * incoming TDLS channel-switch request/response packets from remote peers. | ||
| 1791 | * | ||
| 1792 | * @switch_type: see &enum iwl_tdls_channel_switch_type | ||
| 1793 | * @peer_sta_id: station id of TDLS peer | ||
| 1794 | * @ci: channel we switch to | ||
| 1795 | * @timing: timing related data for command | ||
| 1796 | * @frame: channel-switch request/response template, depending to switch_type | ||
| 1797 | */ | ||
| 1798 | struct iwl_tdls_channel_switch_cmd { | ||
| 1799 | u8 switch_type; | ||
| 1800 | __le32 peer_sta_id; | ||
| 1801 | struct iwl_fw_channel_info ci; | ||
| 1802 | struct iwl_tdls_channel_switch_timing timing; | ||
| 1803 | struct iwl_tdls_channel_switch_frame frame; | ||
| 1804 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ | ||
| 1805 | |||
| 1806 | /** | ||
| 1807 | * TDLS channel switch start notification | ||
| 1808 | * | ||
| 1809 | * @status: non-zero on success | ||
| 1810 | * @offchannel_duration: duration given in microseconds | ||
| 1811 | * @sta_id: peer currently performing the channel-switch with | ||
| 1812 | */ | ||
| 1813 | struct iwl_tdls_channel_switch_notif { | ||
| 1814 | __le32 status; | ||
| 1815 | __le32 offchannel_duration; | ||
| 1816 | __le32 sta_id; | ||
| 1817 | } __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */ | ||
| 1818 | |||
| 1819 | /** | ||
| 1820 | * TDLS station info | ||
| 1821 | * | ||
| 1822 | * @sta_id: station id of the TDLS peer | ||
| 1823 | * @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx | ||
| 1824 | * @tx_to_peer_ssn: initial SSN the FW should use for Tx on its TID vs the peer | ||
| 1825 | * @is_initiator: 1 if the peer is the TDLS link initiator, 0 otherwise | ||
| 1826 | */ | ||
| 1827 | struct iwl_tdls_sta_info { | ||
| 1828 | u8 sta_id; | ||
| 1829 | u8 tx_to_peer_tid; | ||
| 1830 | __le16 tx_to_peer_ssn; | ||
| 1831 | __le32 is_initiator; | ||
| 1832 | } __packed; /* TDLS_STA_INFO_VER_1 */ | ||
| 1833 | |||
| 1834 | /** | ||
| 1835 | * TDLS basic config command | ||
| 1836 | * | ||
| 1837 | * @id_and_color: MAC id and color being configured | ||
| 1838 | * @tdls_peer_count: amount of currently connected TDLS peers | ||
| 1839 | * @tx_to_ap_tid: TID reverved vs. the AP for FW based Tx | ||
| 1840 | * @tx_to_ap_ssn: initial SSN the FW should use for Tx on its TID vs. the AP | ||
| 1841 | * @sta_info: per-station info. Only the first tdls_peer_count entries are set | ||
| 1842 | * @pti_req_data_offset: offset of network-level data for the PTI template | ||
| 1843 | * @pti_req_tx_cmd: Tx parameters for PTI request template | ||
| 1844 | * @pti_req_template: PTI request template data | ||
| 1845 | */ | ||
| 1846 | struct iwl_tdls_config_cmd { | ||
| 1847 | __le32 id_and_color; /* mac id and color */ | ||
| 1848 | u8 tdls_peer_count; | ||
| 1849 | u8 tx_to_ap_tid; | ||
| 1850 | __le16 tx_to_ap_ssn; | ||
| 1851 | struct iwl_tdls_sta_info sta_info[IWL_MVM_TDLS_STA_COUNT]; | ||
| 1852 | |||
| 1853 | __le32 pti_req_data_offset; | ||
| 1854 | struct iwl_tx_cmd pti_req_tx_cmd; | ||
| 1855 | u8 pti_req_template[0]; | ||
| 1856 | } __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ | ||
| 1857 | |||
| 1858 | /** | ||
| 1859 | * TDLS per-station config information from FW | ||
| 1860 | * | ||
| 1861 | * @sta_id: station id of the TDLS peer | ||
| 1862 | * @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to | ||
| 1863 | * the peer | ||
| 1864 | */ | ||
| 1865 | struct iwl_tdls_config_sta_info_res { | ||
| 1866 | __le16 sta_id; | ||
| 1867 | __le16 tx_to_peer_last_seq; | ||
| 1868 | } __packed; /* TDLS_STA_INFO_RSP_VER_1 */ | ||
| 1869 | |||
| 1870 | /** | ||
| 1871 | * TDLS config information from FW | ||
| 1872 | * | ||
| 1873 | * @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP | ||
| 1874 | * @sta_info: per-station TDLS config information | ||
| 1875 | */ | ||
| 1876 | struct iwl_tdls_config_res { | ||
| 1877 | __le32 tx_to_ap_last_seq; | ||
| 1878 | struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT]; | ||
| 1879 | } __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */ | ||
| 1880 | |||
| 1579 | #endif /* __fw_api_h__ */ | 1881 | #endif /* __fw_api_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 883e702152d5..d0fa6e9ed590 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -184,7 +186,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
| 184 | static const u8 alive_cmd[] = { MVM_ALIVE }; | 186 | static const u8 alive_cmd[] = { MVM_ALIVE }; |
| 185 | struct iwl_sf_region st_fwrd_space; | 187 | struct iwl_sf_region st_fwrd_space; |
| 186 | 188 | ||
| 187 | fw = iwl_get_ucode_image(mvm, ucode_type); | 189 | if (ucode_type == IWL_UCODE_REGULAR && |
| 190 | iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_CUSTOM) && | ||
| 191 | iwl_fw_dbg_conf_enabled(mvm->fw, FW_DBG_CUSTOM)) | ||
| 192 | fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER); | ||
| 193 | else | ||
| 194 | fw = iwl_get_ucode_image(mvm, ucode_type); | ||
| 188 | if (WARN_ON(!fw)) | 195 | if (WARN_ON(!fw)) |
| 189 | return -EINVAL; | 196 | return -EINVAL; |
| 190 | mvm->cur_ucode = ucode_type; | 197 | mvm->cur_ucode = ucode_type; |
| @@ -225,6 +232,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
| 225 | st_fwrd_space.addr = mvm->sf_space.addr; | 232 | st_fwrd_space.addr = mvm->sf_space.addr; |
| 226 | st_fwrd_space.size = mvm->sf_space.size; | 233 | st_fwrd_space.size = mvm->sf_space.size; |
| 227 | ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space); | 234 | ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space); |
| 235 | if (ret) { | ||
| 236 | IWL_ERR(mvm, "Failed to update SF size. ret %d\n", ret); | ||
| 237 | return ret; | ||
| 238 | } | ||
| 228 | 239 | ||
| 229 | iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); | 240 | iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); |
| 230 | 241 | ||
| @@ -242,10 +253,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
| 242 | mvm->queue_to_mac80211[i] = i; | 253 | mvm->queue_to_mac80211[i] = i; |
| 243 | else | 254 | else |
| 244 | mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; | 255 | mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; |
| 245 | atomic_set(&mvm->queue_stop_count[i], 0); | ||
| 246 | } | 256 | } |
| 247 | 257 | ||
| 248 | mvm->transport_queue_stop = 0; | 258 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) |
| 259 | atomic_set(&mvm->mac80211_queue_stop_count[i], 0); | ||
| 249 | 260 | ||
| 250 | mvm->ucode_loaded = true; | 261 | mvm->ucode_loaded = true; |
| 251 | 262 | ||
| @@ -282,7 +293,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
| 282 | 293 | ||
| 283 | lockdep_assert_held(&mvm->mutex); | 294 | lockdep_assert_held(&mvm->mutex); |
| 284 | 295 | ||
| 285 | if (WARN_ON_ONCE(mvm->init_ucode_complete)) | 296 | if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating)) |
| 286 | return 0; | 297 | return 0; |
| 287 | 298 | ||
| 288 | iwl_init_notification_wait(&mvm->notif_wait, | 299 | iwl_init_notification_wait(&mvm->notif_wait, |
| @@ -332,6 +343,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
| 332 | goto out; | 343 | goto out; |
| 333 | } | 344 | } |
| 334 | 345 | ||
| 346 | mvm->calibrating = true; | ||
| 347 | |||
| 335 | /* Send TX valid antennas before triggering calibrations */ | 348 | /* Send TX valid antennas before triggering calibrations */ |
| 336 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); | 349 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
| 337 | if (ret) | 350 | if (ret) |
| @@ -356,11 +369,17 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
| 356 | MVM_UCODE_CALIB_TIMEOUT); | 369 | MVM_UCODE_CALIB_TIMEOUT); |
| 357 | if (!ret) | 370 | if (!ret) |
| 358 | mvm->init_ucode_complete = true; | 371 | mvm->init_ucode_complete = true; |
| 372 | |||
| 373 | if (ret && iwl_mvm_is_radio_killed(mvm)) { | ||
| 374 | IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); | ||
| 375 | ret = 1; | ||
| 376 | } | ||
| 359 | goto out; | 377 | goto out; |
| 360 | 378 | ||
| 361 | error: | 379 | error: |
| 362 | iwl_remove_notification(&mvm->notif_wait, &calib_wait); | 380 | iwl_remove_notification(&mvm->notif_wait, &calib_wait); |
| 363 | out: | 381 | out: |
| 382 | mvm->calibrating = false; | ||
| 364 | if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { | 383 | if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { |
| 365 | /* we want to debug INIT and we have no NVM - fake */ | 384 | /* we want to debug INIT and we have no NVM - fake */ |
| 366 | mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + | 385 | mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + |
| @@ -380,6 +399,42 @@ out: | |||
| 380 | return ret; | 399 | return ret; |
| 381 | } | 400 | } |
| 382 | 401 | ||
| 402 | static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, | ||
| 403 | enum iwl_fw_dbg_conf conf_id) | ||
| 404 | { | ||
| 405 | u8 *ptr; | ||
| 406 | int ret; | ||
| 407 | int i; | ||
| 408 | |||
| 409 | if (WARN_ONCE(conf_id >= ARRAY_SIZE(mvm->fw->dbg_conf_tlv), | ||
| 410 | "Invalid configuration %d\n", conf_id)) | ||
| 411 | return -EINVAL; | ||
| 412 | |||
| 413 | if (!mvm->fw->dbg_conf_tlv[conf_id]) | ||
| 414 | return -EINVAL; | ||
| 415 | |||
| 416 | if (mvm->fw_dbg_conf != FW_DBG_INVALID) | ||
| 417 | IWL_WARN(mvm, "FW already configured (%d) - re-configuring\n", | ||
| 418 | mvm->fw_dbg_conf); | ||
| 419 | |||
| 420 | /* Send all HCMDs for configuring the FW debug */ | ||
| 421 | ptr = (void *)&mvm->fw->dbg_conf_tlv[conf_id]->hcmd; | ||
| 422 | for (i = 0; i < mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { | ||
| 423 | struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr; | ||
| 424 | |||
| 425 | ret = iwl_mvm_send_cmd_pdu(mvm, cmd->id, 0, | ||
| 426 | le16_to_cpu(cmd->len), cmd->data); | ||
| 427 | if (ret) | ||
| 428 | return ret; | ||
| 429 | |||
| 430 | ptr += sizeof(*cmd); | ||
| 431 | ptr += le16_to_cpu(cmd->len); | ||
| 432 | } | ||
| 433 | |||
| 434 | mvm->fw_dbg_conf = conf_id; | ||
| 435 | return ret; | ||
| 436 | } | ||
| 437 | |||
| 383 | int iwl_mvm_up(struct iwl_mvm *mvm) | 438 | int iwl_mvm_up(struct iwl_mvm *mvm) |
| 384 | { | 439 | { |
| 385 | int ret, i; | 440 | int ret, i; |
| @@ -431,6 +486,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
| 431 | if (ret) | 486 | if (ret) |
| 432 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); | 487 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); |
| 433 | 488 | ||
| 489 | mvm->fw_dbg_conf = FW_DBG_INVALID; | ||
| 490 | iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM); | ||
| 491 | |||
| 434 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); | 492 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
| 435 | if (ret) | 493 | if (ret) |
| 436 | goto error; | 494 | goto error; |
| @@ -452,6 +510,11 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
| 452 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) | 510 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) |
| 453 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); | 511 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); |
| 454 | 512 | ||
| 513 | mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; | ||
| 514 | |||
| 515 | /* reset quota debouncing buffer - 0xff will yield invalid data */ | ||
| 516 | memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); | ||
| 517 | |||
| 455 | /* Add auxiliary station for scanning */ | 518 | /* Add auxiliary station for scanning */ |
| 456 | ret = iwl_mvm_add_aux_sta(mvm); | 519 | ret = iwl_mvm_add_aux_sta(mvm); |
| 457 | if (ret) | 520 | if (ret) |
| @@ -475,10 +538,25 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
| 475 | /* Initialize tx backoffs to the minimal possible */ | 538 | /* Initialize tx backoffs to the minimal possible */ |
| 476 | iwl_mvm_tt_tx_backoff(mvm, 0); | 539 | iwl_mvm_tt_tx_backoff(mvm, 0); |
| 477 | 540 | ||
| 541 | if (mvm->trans->ltr_enabled) { | ||
| 542 | struct iwl_ltr_config_cmd cmd = { | ||
| 543 | .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), | ||
| 544 | }; | ||
| 545 | |||
| 546 | WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, | ||
| 547 | sizeof(cmd), &cmd)); | ||
| 548 | } | ||
| 549 | |||
| 478 | ret = iwl_mvm_power_update_device(mvm); | 550 | ret = iwl_mvm_power_update_device(mvm); |
| 479 | if (ret) | 551 | if (ret) |
| 480 | goto error; | 552 | goto error; |
| 481 | 553 | ||
| 554 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
| 555 | ret = iwl_mvm_config_scan(mvm); | ||
| 556 | if (ret) | ||
| 557 | goto error; | ||
| 558 | } | ||
| 559 | |||
| 482 | /* allow FW/transport low power modes if not during restart */ | 560 | /* allow FW/transport low power modes if not during restart */ |
| 483 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 561 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
| 484 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | 562 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); |
| @@ -565,3 +643,19 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 565 | le32_to_cpu(radio_version->radio_dash)); | 643 | le32_to_cpu(radio_version->radio_dash)); |
| 566 | return 0; | 644 | return 0; |
| 567 | } | 645 | } |
| 646 | |||
| 647 | int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, | ||
| 648 | struct iwl_rx_cmd_buffer *rxb, | ||
| 649 | struct iwl_device_cmd *cmd) | ||
| 650 | { | ||
| 651 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
| 652 | struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; | ||
| 653 | |||
| 654 | IWL_DEBUG_INFO(mvm, | ||
| 655 | "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n", | ||
| 656 | le32_to_cpu(mfuart_notif->installed_ver), | ||
| 657 | le32_to_cpu(mfuart_notif->external_ver), | ||
| 658 | le32_to_cpu(mfuart_notif->status), | ||
| 659 | le32_to_cpu(mfuart_notif->duration)); | ||
| 660 | return 0; | ||
| 661 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 8242e689ddb1..f6d86ccce6a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -81,11 +83,15 @@ struct iwl_mvm_mac_iface_iterator_data { | |||
| 81 | struct ieee80211_vif *vif; | 83 | struct ieee80211_vif *vif; |
| 82 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; | 84 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; |
| 83 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; | 85 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; |
| 84 | unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)]; | ||
| 85 | enum iwl_tsf_id preferred_tsf; | 86 | enum iwl_tsf_id preferred_tsf; |
| 86 | bool found_vif; | 87 | bool found_vif; |
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 90 | struct iwl_mvm_hw_queues_iface_iterator_data { | ||
| 91 | struct ieee80211_vif *exclude_vif; | ||
| 92 | unsigned long used_hw_queues; | ||
| 93 | }; | ||
| 94 | |||
| 89 | static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, | 95 | static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, |
| 90 | struct ieee80211_vif *vif) | 96 | struct ieee80211_vif *vif) |
| 91 | { | 97 | { |
| @@ -192,12 +198,78 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, | |||
| 192 | data->preferred_tsf = NUM_TSF_IDS; | 198 | data->preferred_tsf = NUM_TSF_IDS; |
| 193 | } | 199 | } |
| 194 | 200 | ||
| 201 | /* | ||
| 202 | * Get the mask of the queues used by the vif | ||
| 203 | */ | ||
| 204 | u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) | ||
| 205 | { | ||
| 206 | u32 qmask = 0, ac; | ||
| 207 | |||
| 208 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) | ||
| 209 | return BIT(IWL_MVM_OFFCHANNEL_QUEUE); | ||
| 210 | |||
| 211 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 212 | qmask |= BIT(vif->hw_queue[ac]); | ||
| 213 | |||
| 214 | if (vif->type == NL80211_IFTYPE_AP) | ||
| 215 | qmask |= BIT(vif->cab_queue); | ||
| 216 | |||
| 217 | return qmask; | ||
| 218 | } | ||
| 219 | |||
| 220 | static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac, | ||
| 221 | struct ieee80211_vif *vif) | ||
| 222 | { | ||
| 223 | struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; | ||
| 224 | |||
| 225 | /* exclude the given vif */ | ||
| 226 | if (vif == data->exclude_vif) | ||
| 227 | return; | ||
| 228 | |||
| 229 | data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); | ||
| 230 | } | ||
| 231 | |||
| 232 | static void iwl_mvm_mac_sta_hw_queues_iter(void *_data, | ||
| 233 | struct ieee80211_sta *sta) | ||
| 234 | { | ||
| 235 | struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; | ||
| 236 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 237 | |||
| 238 | /* Mark the queues used by the sta */ | ||
| 239 | data->used_hw_queues |= mvmsta->tfd_queue_msk; | ||
| 240 | } | ||
| 241 | |||
| 242 | unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, | ||
| 243 | struct ieee80211_vif *exclude_vif) | ||
| 244 | { | ||
| 245 | struct iwl_mvm_hw_queues_iface_iterator_data data = { | ||
| 246 | .exclude_vif = exclude_vif, | ||
| 247 | .used_hw_queues = | ||
| 248 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | | ||
| 249 | BIT(mvm->aux_queue) | | ||
| 250 | BIT(IWL_MVM_CMD_QUEUE), | ||
| 251 | }; | ||
| 252 | |||
| 253 | lockdep_assert_held(&mvm->mutex); | ||
| 254 | |||
| 255 | /* mark all VIF used hw queues */ | ||
| 256 | ieee80211_iterate_active_interfaces_atomic( | ||
| 257 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 258 | iwl_mvm_iface_hw_queues_iter, &data); | ||
| 259 | |||
| 260 | /* don't assign the same hw queues as TDLS stations */ | ||
| 261 | ieee80211_iterate_stations_atomic(mvm->hw, | ||
| 262 | iwl_mvm_mac_sta_hw_queues_iter, | ||
| 263 | &data); | ||
| 264 | |||
| 265 | return data.used_hw_queues; | ||
| 266 | } | ||
| 267 | |||
| 195 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | 268 | static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, |
| 196 | struct ieee80211_vif *vif) | 269 | struct ieee80211_vif *vif) |
| 197 | { | 270 | { |
| 198 | struct iwl_mvm_mac_iface_iterator_data *data = _data; | 271 | struct iwl_mvm_mac_iface_iterator_data *data = _data; |
| 199 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 272 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 200 | u32 ac; | ||
| 201 | 273 | ||
| 202 | /* Iterator may already find the interface being added -- skip it */ | 274 | /* Iterator may already find the interface being added -- skip it */ |
| 203 | if (vif == data->vif) { | 275 | if (vif == data->vif) { |
| @@ -205,14 +277,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | |||
| 205 | return; | 277 | return; |
| 206 | } | 278 | } |
| 207 | 279 | ||
| 208 | /* Mark the queues used by the vif */ | ||
| 209 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 210 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
| 211 | __set_bit(vif->hw_queue[ac], data->used_hw_queues); | ||
| 212 | |||
| 213 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
| 214 | __set_bit(vif->cab_queue, data->used_hw_queues); | ||
| 215 | |||
| 216 | /* Mark MAC IDs as used by clearing the available bit, and | 280 | /* Mark MAC IDs as used by clearing the available bit, and |
| 217 | * (below) mark TSFs as used if their existing use is not | 281 | * (below) mark TSFs as used if their existing use is not |
| 218 | * compatible with the new interface type. | 282 | * compatible with the new interface type. |
| @@ -225,24 +289,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, | |||
| 225 | iwl_mvm_mac_tsf_id_iter(_data, mac, vif); | 289 | iwl_mvm_mac_tsf_id_iter(_data, mac, vif); |
| 226 | } | 290 | } |
| 227 | 291 | ||
| 228 | /* | ||
| 229 | * Get the mask of the queus used by the vif | ||
| 230 | */ | ||
| 231 | u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | ||
| 232 | struct ieee80211_vif *vif) | ||
| 233 | { | ||
| 234 | u32 qmask = 0, ac; | ||
| 235 | |||
| 236 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) | ||
| 237 | return BIT(IWL_MVM_OFFCHANNEL_QUEUE); | ||
| 238 | |||
| 239 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 240 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
| 241 | qmask |= BIT(vif->hw_queue[ac]); | ||
| 242 | |||
| 243 | return qmask; | ||
| 244 | } | ||
| 245 | |||
| 246 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, | 292 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, |
| 247 | struct ieee80211_vif *vif) | 293 | struct ieee80211_vif *vif) |
| 248 | { | 294 | { |
| @@ -277,15 +323,11 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
| 277 | .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, | 323 | .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, |
| 278 | /* no preference yet */ | 324 | /* no preference yet */ |
| 279 | .preferred_tsf = NUM_TSF_IDS, | 325 | .preferred_tsf = NUM_TSF_IDS, |
| 280 | .used_hw_queues = { | ||
| 281 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | | ||
| 282 | BIT(mvm->aux_queue) | | ||
| 283 | BIT(IWL_MVM_CMD_QUEUE) | ||
| 284 | }, | ||
| 285 | .found_vif = false, | 326 | .found_vif = false, |
| 286 | }; | 327 | }; |
| 287 | u32 ac; | 328 | u32 ac; |
| 288 | int ret, i; | 329 | int ret, i; |
| 330 | unsigned long used_hw_queues; | ||
| 289 | 331 | ||
| 290 | /* | 332 | /* |
| 291 | * Allocate a MAC ID and a TSF for this MAC, along with the queues | 333 | * Allocate a MAC ID and a TSF for this MAC, along with the queues |
| @@ -319,6 +361,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
| 319 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | 361 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
| 320 | iwl_mvm_mac_iface_iterator, &data); | 362 | iwl_mvm_mac_iface_iterator, &data); |
| 321 | 363 | ||
| 364 | used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, vif); | ||
| 365 | |||
| 322 | /* | 366 | /* |
| 323 | * In the case we're getting here during resume, it's similar to | 367 | * In the case we're getting here during resume, it's similar to |
| 324 | * firmware restart, and with RESUME_ALL the iterator will find | 368 | * firmware restart, and with RESUME_ALL the iterator will find |
| @@ -370,7 +414,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
| 370 | 414 | ||
| 371 | /* Find available queues, and allocate them to the ACs */ | 415 | /* Find available queues, and allocate them to the ACs */ |
| 372 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 416 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
| 373 | u8 queue = find_first_zero_bit(data.used_hw_queues, | 417 | u8 queue = find_first_zero_bit(&used_hw_queues, |
| 374 | mvm->first_agg_queue); | 418 | mvm->first_agg_queue); |
| 375 | 419 | ||
| 376 | if (queue >= mvm->first_agg_queue) { | 420 | if (queue >= mvm->first_agg_queue) { |
| @@ -379,13 +423,13 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
| 379 | goto exit_fail; | 423 | goto exit_fail; |
| 380 | } | 424 | } |
| 381 | 425 | ||
| 382 | __set_bit(queue, data.used_hw_queues); | 426 | __set_bit(queue, &used_hw_queues); |
| 383 | vif->hw_queue[ac] = queue; | 427 | vif->hw_queue[ac] = queue; |
| 384 | } | 428 | } |
| 385 | 429 | ||
| 386 | /* Allocate the CAB queue for softAP and GO interfaces */ | 430 | /* Allocate the CAB queue for softAP and GO interfaces */ |
| 387 | if (vif->type == NL80211_IFTYPE_AP) { | 431 | if (vif->type == NL80211_IFTYPE_AP) { |
| 388 | u8 queue = find_first_zero_bit(data.used_hw_queues, | 432 | u8 queue = find_first_zero_bit(&used_hw_queues, |
| 389 | mvm->first_agg_queue); | 433 | mvm->first_agg_queue); |
| 390 | 434 | ||
| 391 | if (queue >= mvm->first_agg_queue) { | 435 | if (queue >= mvm->first_agg_queue) { |
| @@ -427,17 +471,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 427 | 471 | ||
| 428 | switch (vif->type) { | 472 | switch (vif->type) { |
| 429 | case NL80211_IFTYPE_P2P_DEVICE: | 473 | case NL80211_IFTYPE_P2P_DEVICE: |
| 430 | iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE, | 474 | iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, |
| 431 | IWL_MVM_TX_FIFO_VO); | 475 | IWL_MVM_TX_FIFO_VO); |
| 432 | break; | 476 | break; |
| 433 | case NL80211_IFTYPE_AP: | 477 | case NL80211_IFTYPE_AP: |
| 434 | iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, | 478 | iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, |
| 435 | IWL_MVM_TX_FIFO_MCAST); | 479 | IWL_MVM_TX_FIFO_MCAST); |
| 436 | /* fall through */ | 480 | /* fall through */ |
| 437 | default: | 481 | default: |
| 438 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 482 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
| 439 | iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac], | 483 | iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], |
| 440 | iwl_mvm_ac_to_tx_fifo[ac]); | 484 | iwl_mvm_ac_to_tx_fifo[ac]); |
| 441 | break; | 485 | break; |
| 442 | } | 486 | } |
| 443 | 487 | ||
| @@ -452,14 +496,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 452 | 496 | ||
| 453 | switch (vif->type) { | 497 | switch (vif->type) { |
| 454 | case NL80211_IFTYPE_P2P_DEVICE: | 498 | case NL80211_IFTYPE_P2P_DEVICE: |
| 455 | iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE); | 499 | iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE); |
| 456 | break; | 500 | break; |
| 457 | case NL80211_IFTYPE_AP: | 501 | case NL80211_IFTYPE_AP: |
| 458 | iwl_trans_txq_disable(mvm->trans, vif->cab_queue); | 502 | iwl_mvm_disable_txq(mvm, vif->cab_queue); |
| 459 | /* fall through */ | 503 | /* fall through */ |
| 460 | default: | 504 | default: |
| 461 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 505 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
| 462 | iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]); | 506 | iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]); |
| 463 | } | 507 | } |
| 464 | } | 508 | } |
| 465 | 509 | ||
| @@ -586,6 +630,7 @@ static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm, | |||
| 586 | static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | 630 | static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, |
| 587 | struct ieee80211_vif *vif, | 631 | struct ieee80211_vif *vif, |
| 588 | struct iwl_mac_ctx_cmd *cmd, | 632 | struct iwl_mac_ctx_cmd *cmd, |
| 633 | const u8 *bssid_override, | ||
| 589 | u32 action) | 634 | u32 action) |
| 590 | { | 635 | { |
| 591 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 636 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| @@ -593,6 +638,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
| 593 | bool ht_enabled = !!(vif->bss_conf.ht_operation_mode & | 638 | bool ht_enabled = !!(vif->bss_conf.ht_operation_mode & |
| 594 | IEEE80211_HT_OP_MODE_PROTECTION); | 639 | IEEE80211_HT_OP_MODE_PROTECTION); |
| 595 | u8 cck_ack_rates, ofdm_ack_rates; | 640 | u8 cck_ack_rates, ofdm_ack_rates; |
| 641 | const u8 *bssid = bssid_override ?: vif->bss_conf.bssid; | ||
| 596 | int i; | 642 | int i; |
| 597 | 643 | ||
| 598 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | 644 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, |
| @@ -625,8 +671,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
| 625 | cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id); | 671 | cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id); |
| 626 | 672 | ||
| 627 | memcpy(cmd->node_addr, vif->addr, ETH_ALEN); | 673 | memcpy(cmd->node_addr, vif->addr, ETH_ALEN); |
| 628 | if (vif->bss_conf.bssid) | 674 | |
| 629 | memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN); | 675 | if (bssid) |
| 676 | memcpy(cmd->bssid_addr, bssid, ETH_ALEN); | ||
| 630 | else | 677 | else |
| 631 | eth_broadcast_addr(cmd->bssid_addr); | 678 | eth_broadcast_addr(cmd->bssid_addr); |
| 632 | 679 | ||
| @@ -695,7 +742,8 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, | |||
| 695 | 742 | ||
| 696 | static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, | 743 | static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, |
| 697 | struct ieee80211_vif *vif, | 744 | struct ieee80211_vif *vif, |
| 698 | u32 action, bool force_assoc_off) | 745 | u32 action, bool force_assoc_off, |
| 746 | const u8 *bssid_override) | ||
| 699 | { | 747 | { |
| 700 | struct iwl_mac_ctx_cmd cmd = {}; | 748 | struct iwl_mac_ctx_cmd cmd = {}; |
| 701 | struct iwl_mac_data_sta *ctxt_sta; | 749 | struct iwl_mac_data_sta *ctxt_sta; |
| @@ -703,7 +751,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, | |||
| 703 | WARN_ON(vif->type != NL80211_IFTYPE_STATION); | 751 | WARN_ON(vif->type != NL80211_IFTYPE_STATION); |
| 704 | 752 | ||
| 705 | /* Fill the common data for all mac context types */ | 753 | /* Fill the common data for all mac context types */ |
| 706 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 754 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, bssid_override, action); |
| 707 | 755 | ||
| 708 | if (vif->p2p) { | 756 | if (vif->p2p) { |
| 709 | struct ieee80211_p2p_noa_attr *noa = | 757 | struct ieee80211_p2p_noa_attr *noa = |
| @@ -784,7 +832,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, | |||
| 784 | 832 | ||
| 785 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); | 833 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); |
| 786 | 834 | ||
| 787 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 835 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); |
| 788 | 836 | ||
| 789 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC | | 837 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC | |
| 790 | MAC_FILTER_IN_CONTROL_AND_MGMT | | 838 | MAC_FILTER_IN_CONTROL_AND_MGMT | |
| @@ -805,7 +853,7 @@ static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, | |||
| 805 | 853 | ||
| 806 | WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); | 854 | WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); |
| 807 | 855 | ||
| 808 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 856 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); |
| 809 | 857 | ||
| 810 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON | | 858 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON | |
| 811 | MAC_FILTER_IN_PROBE_REQUEST); | 859 | MAC_FILTER_IN_PROBE_REQUEST); |
| @@ -844,7 +892,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, | |||
| 844 | 892 | ||
| 845 | WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); | 893 | WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); |
| 846 | 894 | ||
| 847 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 895 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); |
| 848 | 896 | ||
| 849 | cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); | 897 | cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); |
| 850 | 898 | ||
| @@ -1072,7 +1120,7 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, | |||
| 1072 | WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); | 1120 | WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); |
| 1073 | 1121 | ||
| 1074 | /* Fill the common data for all mac context types */ | 1122 | /* Fill the common data for all mac context types */ |
| 1075 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 1123 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); |
| 1076 | 1124 | ||
| 1077 | /* | 1125 | /* |
| 1078 | * pass probe requests and beacons from other APs (needed | 1126 | * pass probe requests and beacons from other APs (needed |
| @@ -1098,7 +1146,7 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, | |||
| 1098 | WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p); | 1146 | WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p); |
| 1099 | 1147 | ||
| 1100 | /* Fill the common data for all mac context types */ | 1148 | /* Fill the common data for all mac context types */ |
| 1101 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 1149 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); |
| 1102 | 1150 | ||
| 1103 | /* | 1151 | /* |
| 1104 | * pass probe requests and beacons from other APs (needed | 1152 | * pass probe requests and beacons from other APs (needed |
| @@ -1121,12 +1169,14 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, | |||
| 1121 | } | 1169 | } |
| 1122 | 1170 | ||
| 1123 | static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1171 | static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 1124 | u32 action, bool force_assoc_off) | 1172 | u32 action, bool force_assoc_off, |
| 1173 | const u8 *bssid_override) | ||
| 1125 | { | 1174 | { |
| 1126 | switch (vif->type) { | 1175 | switch (vif->type) { |
| 1127 | case NL80211_IFTYPE_STATION: | 1176 | case NL80211_IFTYPE_STATION: |
| 1128 | return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action, | 1177 | return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action, |
| 1129 | force_assoc_off); | 1178 | force_assoc_off, |
| 1179 | bssid_override); | ||
| 1130 | break; | 1180 | break; |
| 1131 | case NL80211_IFTYPE_AP: | 1181 | case NL80211_IFTYPE_AP: |
| 1132 | if (!vif->p2p) | 1182 | if (!vif->p2p) |
| @@ -1157,7 +1207,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 1157 | return -EIO; | 1207 | return -EIO; |
| 1158 | 1208 | ||
| 1159 | ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD, | 1209 | ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD, |
| 1160 | true); | 1210 | true, NULL); |
| 1161 | if (ret) | 1211 | if (ret) |
| 1162 | return ret; | 1212 | return ret; |
| 1163 | 1213 | ||
| @@ -1169,7 +1219,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 1169 | } | 1219 | } |
| 1170 | 1220 | ||
| 1171 | int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1221 | int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 1172 | bool force_assoc_off) | 1222 | bool force_assoc_off, const u8 *bssid_override) |
| 1173 | { | 1223 | { |
| 1174 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1224 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 1175 | 1225 | ||
| @@ -1178,7 +1228,7 @@ int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 1178 | return -EIO; | 1228 | return -EIO; |
| 1179 | 1229 | ||
| 1180 | return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY, | 1230 | return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY, |
| 1181 | force_assoc_off); | 1231 | force_assoc_off, bssid_override); |
| 1182 | } | 1232 | } |
| 1183 | 1233 | ||
| 1184 | int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 1234 | int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| @@ -1213,26 +1263,34 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 1213 | } | 1263 | } |
| 1214 | 1264 | ||
| 1215 | static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, | 1265 | static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, |
| 1216 | struct ieee80211_vif *csa_vif, u32 gp2) | 1266 | struct ieee80211_vif *csa_vif, u32 gp2, |
| 1267 | bool tx_success) | ||
| 1217 | { | 1268 | { |
| 1218 | struct iwl_mvm_vif *mvmvif = | 1269 | struct iwl_mvm_vif *mvmvif = |
| 1219 | iwl_mvm_vif_from_mac80211(csa_vif); | 1270 | iwl_mvm_vif_from_mac80211(csa_vif); |
| 1220 | 1271 | ||
| 1272 | /* Don't start to countdown from a failed beacon */ | ||
| 1273 | if (!tx_success && !mvmvif->csa_countdown) | ||
| 1274 | return; | ||
| 1275 | |||
| 1276 | mvmvif->csa_countdown = true; | ||
| 1277 | |||
| 1221 | if (!ieee80211_csa_is_complete(csa_vif)) { | 1278 | if (!ieee80211_csa_is_complete(csa_vif)) { |
| 1222 | int c = ieee80211_csa_update_counter(csa_vif); | 1279 | int c = ieee80211_csa_update_counter(csa_vif); |
| 1223 | 1280 | ||
| 1224 | iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); | 1281 | iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); |
| 1225 | if (csa_vif->p2p && | 1282 | if (csa_vif->p2p && |
| 1226 | !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { | 1283 | !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2 && |
| 1284 | tx_success) { | ||
| 1227 | u32 rel_time = (c + 1) * | 1285 | u32 rel_time = (c + 1) * |
| 1228 | csa_vif->bss_conf.beacon_int - | 1286 | csa_vif->bss_conf.beacon_int - |
| 1229 | IWL_MVM_CHANNEL_SWITCH_TIME; | 1287 | IWL_MVM_CHANNEL_SWITCH_TIME_GO; |
| 1230 | u32 apply_time = gp2 + rel_time * 1024; | 1288 | u32 apply_time = gp2 + rel_time * 1024; |
| 1231 | 1289 | ||
| 1232 | iwl_mvm_schedule_csa_noa(mvm, csa_vif, | 1290 | iwl_mvm_schedule_csa_period(mvm, csa_vif, |
| 1233 | IWL_MVM_CHANNEL_SWITCH_TIME - | 1291 | IWL_MVM_CHANNEL_SWITCH_TIME_GO - |
| 1234 | IWL_MVM_CHANNEL_SWITCH_MARGIN, | 1292 | IWL_MVM_CHANNEL_SWITCH_MARGIN, |
| 1235 | apply_time); | 1293 | apply_time); |
| 1236 | } | 1294 | } |
| 1237 | } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { | 1295 | } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { |
| 1238 | /* we don't have CSA NoA scheduled yet, switch now */ | 1296 | /* we don't have CSA NoA scheduled yet, switch now */ |
| @@ -1246,38 +1304,30 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
| 1246 | struct iwl_device_cmd *cmd) | 1304 | struct iwl_device_cmd *cmd) |
| 1247 | { | 1305 | { |
| 1248 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 1306 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
| 1307 | struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; | ||
| 1249 | struct iwl_mvm_tx_resp *beacon_notify_hdr; | 1308 | struct iwl_mvm_tx_resp *beacon_notify_hdr; |
| 1250 | struct ieee80211_vif *csa_vif; | 1309 | struct ieee80211_vif *csa_vif; |
| 1251 | struct ieee80211_vif *tx_blocked_vif; | 1310 | struct ieee80211_vif *tx_blocked_vif; |
| 1252 | u64 tsf; | 1311 | u16 status; |
| 1253 | 1312 | ||
| 1254 | lockdep_assert_held(&mvm->mutex); | 1313 | lockdep_assert_held(&mvm->mutex); |
| 1255 | 1314 | ||
| 1256 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) { | 1315 | beacon_notify_hdr = &beacon->beacon_notify_hdr; |
| 1257 | struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; | 1316 | mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); |
| 1258 | |||
| 1259 | beacon_notify_hdr = &beacon->beacon_notify_hdr; | ||
| 1260 | tsf = le64_to_cpu(beacon->tsf); | ||
| 1261 | mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); | ||
| 1262 | } else { | ||
| 1263 | struct iwl_beacon_notif *beacon = (void *)pkt->data; | ||
| 1264 | |||
| 1265 | beacon_notify_hdr = &beacon->beacon_notify_hdr; | ||
| 1266 | tsf = le64_to_cpu(beacon->tsf); | ||
| 1267 | } | ||
| 1268 | 1317 | ||
| 1318 | status = le16_to_cpu(beacon_notify_hdr->status.status) & TX_STATUS_MSK; | ||
| 1269 | IWL_DEBUG_RX(mvm, | 1319 | IWL_DEBUG_RX(mvm, |
| 1270 | "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", | 1320 | "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", |
| 1271 | le16_to_cpu(beacon_notify_hdr->status.status) & | 1321 | status, beacon_notify_hdr->failure_frame, |
| 1272 | TX_STATUS_MSK, | 1322 | le64_to_cpu(beacon->tsf), |
| 1273 | beacon_notify_hdr->failure_frame, tsf, | ||
| 1274 | mvm->ap_last_beacon_gp2, | 1323 | mvm->ap_last_beacon_gp2, |
| 1275 | le32_to_cpu(beacon_notify_hdr->initial_rate)); | 1324 | le32_to_cpu(beacon_notify_hdr->initial_rate)); |
| 1276 | 1325 | ||
| 1277 | csa_vif = rcu_dereference_protected(mvm->csa_vif, | 1326 | csa_vif = rcu_dereference_protected(mvm->csa_vif, |
| 1278 | lockdep_is_held(&mvm->mutex)); | 1327 | lockdep_is_held(&mvm->mutex)); |
| 1279 | if (unlikely(csa_vif && csa_vif->csa_active)) | 1328 | if (unlikely(csa_vif && csa_vif->csa_active)) |
| 1280 | iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); | 1329 | iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2, |
| 1330 | (status == TX_STATUS_SUCCESS)); | ||
| 1281 | 1331 | ||
| 1282 | tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, | 1332 | tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, |
| 1283 | lockdep_is_held(&mvm->mutex)); | 1333 | lockdep_is_held(&mvm->mutex)); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index cdc272d776e7..e880f9d4717b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -67,6 +69,7 @@ | |||
| 67 | #include <linux/etherdevice.h> | 69 | #include <linux/etherdevice.h> |
| 68 | #include <linux/ip.h> | 70 | #include <linux/ip.h> |
| 69 | #include <linux/if_arp.h> | 71 | #include <linux/if_arp.h> |
| 72 | #include <linux/devcoredump.h> | ||
| 70 | #include <net/mac80211.h> | 73 | #include <net/mac80211.h> |
| 71 | #include <net/ieee80211_radiotap.h> | 74 | #include <net/ieee80211_radiotap.h> |
| 72 | #include <net/tcp.h> | 75 | #include <net/tcp.h> |
| @@ -251,6 +254,26 @@ static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, | |||
| 251 | spin_unlock_bh(&mvm->refs_lock); | 254 | spin_unlock_bh(&mvm->refs_lock); |
| 252 | } | 255 | } |
| 253 | 256 | ||
| 257 | bool iwl_mvm_ref_taken(struct iwl_mvm *mvm) | ||
| 258 | { | ||
| 259 | int i; | ||
| 260 | bool taken = false; | ||
| 261 | |||
| 262 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
| 263 | return true; | ||
| 264 | |||
| 265 | spin_lock_bh(&mvm->refs_lock); | ||
| 266 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) { | ||
| 267 | if (mvm->refs[i]) { | ||
| 268 | taken = true; | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | spin_unlock_bh(&mvm->refs_lock); | ||
| 273 | |||
| 274 | return taken; | ||
| 275 | } | ||
| 276 | |||
| 254 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 277 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
| 255 | { | 278 | { |
| 256 | iwl_mvm_ref(mvm, ref_type); | 279 | iwl_mvm_ref(mvm, ref_type); |
| @@ -277,14 +300,6 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | |||
| 277 | } | 300 | } |
| 278 | } | 301 | } |
| 279 | 302 | ||
| 280 | static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm) | ||
| 281 | { | ||
| 282 | /* we create the 802.11 header and SSID element */ | ||
| 283 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) | ||
| 284 | return mvm->fw->ucode_capa.max_probe_length - 24 - 2; | ||
| 285 | return mvm->fw->ucode_capa.max_probe_length - 24 - 34; | ||
| 286 | } | ||
| 287 | |||
| 288 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 303 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
| 289 | { | 304 | { |
| 290 | struct ieee80211_hw *hw = mvm->hw; | 305 | struct ieee80211_hw *hw = mvm->hw; |
| @@ -302,14 +317,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 302 | IEEE80211_HW_TIMING_BEACON_ONLY | | 317 | IEEE80211_HW_TIMING_BEACON_ONLY | |
| 303 | IEEE80211_HW_CONNECTION_MONITOR | | 318 | IEEE80211_HW_CONNECTION_MONITOR | |
| 304 | IEEE80211_HW_CHANCTX_STA_CSA | | 319 | IEEE80211_HW_CHANCTX_STA_CSA | |
| 305 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | 320 | IEEE80211_HW_SUPPORTS_CLONED_SKBS; |
| 306 | IEEE80211_HW_SUPPORTS_STATIC_SMPS; | ||
| 307 | 321 | ||
| 308 | hw->queues = mvm->first_agg_queue; | 322 | hw->queues = mvm->first_agg_queue; |
| 309 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 323 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
| 310 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | | 324 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | |
| 311 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; | 325 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; |
| 312 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; | 326 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC | |
| 327 | IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED; | ||
| 313 | hw->rate_control_algorithm = "iwl-mvm-rs"; | 328 | hw->rate_control_algorithm = "iwl-mvm-rs"; |
| 314 | 329 | ||
| 315 | /* | 330 | /* |
| @@ -322,15 +337,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 322 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 337 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
| 323 | 338 | ||
| 324 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && | 339 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && |
| 325 | IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && | ||
| 326 | !iwlwifi_mod_params.uapsd_disable) { | 340 | !iwlwifi_mod_params.uapsd_disable) { |
| 327 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; | 341 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; |
| 328 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; | 342 | hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; |
| 329 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | 343 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; |
| 330 | } | 344 | } |
| 331 | 345 | ||
| 332 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 346 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || |
| 347 | mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
| 333 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; | 348 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; |
| 349 | hw->wiphy->features |= | ||
| 350 | NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | | ||
| 351 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; | ||
| 352 | } | ||
| 334 | 353 | ||
| 335 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); | 354 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); |
| 336 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); | 355 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); |
| @@ -350,8 +369,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 350 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | 369 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) |
| 351 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 370 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
| 352 | 371 | ||
| 353 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW) | 372 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
| 354 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | ||
| 355 | 373 | ||
| 356 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; | 374 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; |
| 357 | hw->wiphy->n_iface_combinations = | 375 | hw->wiphy->n_iface_combinations = |
| @@ -378,7 +396,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 378 | 396 | ||
| 379 | iwl_mvm_reset_phy_ctxts(mvm); | 397 | iwl_mvm_reset_phy_ctxts(mvm); |
| 380 | 398 | ||
| 381 | hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm); | 399 | hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm, false); |
| 382 | 400 | ||
| 383 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; | 401 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; |
| 384 | 402 | ||
| @@ -407,7 +425,26 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 407 | 425 | ||
| 408 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | | 426 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | |
| 409 | NL80211_FEATURE_LOW_PRIORITY_SCAN | | 427 | NL80211_FEATURE_LOW_PRIORITY_SCAN | |
| 410 | NL80211_FEATURE_P2P_GO_OPPPS; | 428 | NL80211_FEATURE_P2P_GO_OPPPS | |
| 429 | NL80211_FEATURE_DYNAMIC_SMPS | | ||
| 430 | NL80211_FEATURE_STATIC_SMPS | | ||
| 431 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION; | ||
| 432 | |||
| 433 | if (mvm->fw->ucode_capa.capa[0] & | ||
| 434 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) | ||
| 435 | hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION; | ||
| 436 | if (mvm->fw->ucode_capa.capa[0] & | ||
| 437 | IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT) | ||
| 438 | hw->wiphy->features |= NL80211_FEATURE_QUIET; | ||
| 439 | |||
| 440 | if (mvm->fw->ucode_capa.capa[0] & | ||
| 441 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT) | ||
| 442 | hw->wiphy->features |= | ||
| 443 | NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES; | ||
| 444 | |||
| 445 | if (mvm->fw->ucode_capa.capa[0] & | ||
| 446 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT) | ||
| 447 | hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES; | ||
| 411 | 448 | ||
| 412 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 449 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
| 413 | 450 | ||
| @@ -429,7 +466,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 429 | mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | 466 | mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
| 430 | WIPHY_WOWLAN_DISCONNECT | | 467 | WIPHY_WOWLAN_DISCONNECT | |
| 431 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | 468 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | |
| 432 | WIPHY_WOWLAN_RFKILL_RELEASE; | 469 | WIPHY_WOWLAN_RFKILL_RELEASE | |
| 470 | WIPHY_WOWLAN_NET_DETECT; | ||
| 433 | if (!iwlwifi_mod_params.sw_crypto) | 471 | if (!iwlwifi_mod_params.sw_crypto) |
| 434 | mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | 472 | mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | |
| 435 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | 473 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | |
| @@ -438,6 +476,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 438 | mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; | 476 | mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; |
| 439 | mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; | 477 | mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; |
| 440 | mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; | 478 | mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; |
| 479 | mvm->wowlan.max_nd_match_sets = IWL_SCAN_MAX_PROFILES; | ||
| 441 | mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; | 480 | mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; |
| 442 | hw->wiphy->wowlan = &mvm->wowlan; | 481 | hw->wiphy->wowlan = &mvm->wowlan; |
| 443 | } | 482 | } |
| @@ -452,6 +491,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
| 452 | if (ret) | 491 | if (ret) |
| 453 | return ret; | 492 | return ret; |
| 454 | 493 | ||
| 494 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_TDLS_SUPPORT) { | ||
| 495 | IWL_DEBUG_TDLS(mvm, "TDLS supported\n"); | ||
| 496 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; | ||
| 497 | } | ||
| 498 | |||
| 499 | if (mvm->fw->ucode_capa.capa[0] & | ||
| 500 | IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH) { | ||
| 501 | IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n"); | ||
| 502 | hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; | ||
| 503 | } | ||
| 504 | |||
| 455 | ret = ieee80211_register_hw(mvm->hw); | 505 | ret = ieee80211_register_hw(mvm->hw); |
| 456 | if (ret) | 506 | if (ret) |
| 457 | iwl_mvm_leds_exit(mvm); | 507 | iwl_mvm_leds_exit(mvm); |
| @@ -515,7 +565,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | |||
| 515 | } | 565 | } |
| 516 | 566 | ||
| 517 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && | 567 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && |
| 518 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) | 568 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && |
| 569 | !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) | ||
| 519 | goto drop; | 570 | goto drop; |
| 520 | 571 | ||
| 521 | /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ | 572 | /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ |
| @@ -667,8 +718,50 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | |||
| 667 | memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); | 718 | memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); |
| 668 | } | 719 | } |
| 669 | 720 | ||
| 670 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 721 | static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count, |
| 671 | static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | 722 | const void *data, size_t datalen) |
| 723 | { | ||
| 724 | const struct iwl_mvm_dump_ptrs *dump_ptrs = data; | ||
| 725 | ssize_t bytes_read; | ||
| 726 | ssize_t bytes_read_trans; | ||
| 727 | |||
| 728 | if (offset < dump_ptrs->op_mode_len) { | ||
| 729 | bytes_read = min_t(ssize_t, count, | ||
| 730 | dump_ptrs->op_mode_len - offset); | ||
| 731 | memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset, | ||
| 732 | bytes_read); | ||
| 733 | offset += bytes_read; | ||
| 734 | count -= bytes_read; | ||
| 735 | |||
| 736 | if (count == 0) | ||
| 737 | return bytes_read; | ||
| 738 | } else { | ||
| 739 | bytes_read = 0; | ||
| 740 | } | ||
| 741 | |||
| 742 | if (!dump_ptrs->trans_ptr) | ||
| 743 | return bytes_read; | ||
| 744 | |||
| 745 | offset -= dump_ptrs->op_mode_len; | ||
| 746 | bytes_read_trans = min_t(ssize_t, count, | ||
| 747 | dump_ptrs->trans_ptr->len - offset); | ||
| 748 | memcpy(buffer + bytes_read, | ||
| 749 | (u8 *)dump_ptrs->trans_ptr->data + offset, | ||
| 750 | bytes_read_trans); | ||
| 751 | |||
| 752 | return bytes_read + bytes_read_trans; | ||
| 753 | } | ||
| 754 | |||
| 755 | static void iwl_mvm_free_coredump(const void *data) | ||
| 756 | { | ||
| 757 | const struct iwl_mvm_dump_ptrs *fw_error_dump = data; | ||
| 758 | |||
| 759 | vfree(fw_error_dump->op_mode_ptr); | ||
| 760 | vfree(fw_error_dump->trans_ptr); | ||
| 761 | kfree(fw_error_dump); | ||
| 762 | } | ||
| 763 | |||
| 764 | void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | ||
| 672 | { | 765 | { |
| 673 | struct iwl_fw_error_dump_file *dump_file; | 766 | struct iwl_fw_error_dump_file *dump_file; |
| 674 | struct iwl_fw_error_dump_data *dump_data; | 767 | struct iwl_fw_error_dump_data *dump_data; |
| @@ -682,10 +775,7 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
| 682 | 775 | ||
| 683 | lockdep_assert_held(&mvm->mutex); | 776 | lockdep_assert_held(&mvm->mutex); |
| 684 | 777 | ||
| 685 | if (mvm->fw_error_dump) | 778 | fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); |
| 686 | return; | ||
| 687 | |||
| 688 | fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL); | ||
| 689 | if (!fw_error_dump) | 779 | if (!fw_error_dump) |
| 690 | return; | 780 | return; |
| 691 | 781 | ||
| @@ -760,24 +850,25 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
| 760 | if (fw_error_dump->trans_ptr) | 850 | if (fw_error_dump->trans_ptr) |
| 761 | file_len += fw_error_dump->trans_ptr->len; | 851 | file_len += fw_error_dump->trans_ptr->len; |
| 762 | dump_file->file_len = cpu_to_le32(file_len); | 852 | dump_file->file_len = cpu_to_le32(file_len); |
| 763 | mvm->fw_error_dump = fw_error_dump; | 853 | |
| 854 | dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, | ||
| 855 | GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); | ||
| 764 | } | 856 | } |
| 765 | #endif | ||
| 766 | 857 | ||
| 767 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | 858 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) |
| 768 | { | 859 | { |
| 769 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 860 | /* clear the D3 reconfig, we only need it to avoid dumping a |
| 770 | static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; | 861 | * firmware coredump on reconfiguration, we shouldn't do that |
| 771 | 862 | * on D3->D0 transition | |
| 772 | iwl_mvm_fw_error_dump(mvm); | 863 | */ |
| 773 | 864 | if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) | |
| 774 | /* notify the userspace about the error we had */ | 865 | iwl_mvm_fw_error_dump(mvm); |
| 775 | kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); | ||
| 776 | #endif | ||
| 777 | 866 | ||
| 778 | iwl_trans_stop_device(mvm->trans); | 867 | iwl_trans_stop_device(mvm->trans); |
| 779 | 868 | ||
| 780 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 869 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
| 870 | mvm->ps_disabled = false; | ||
| 871 | mvm->calibrating = false; | ||
| 781 | 872 | ||
| 782 | /* just in case one was running */ | 873 | /* just in case one was running */ |
| 783 | ieee80211_remain_on_channel_expired(mvm->hw); | 874 | ieee80211_remain_on_channel_expired(mvm->hw); |
| @@ -792,6 +883,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
| 792 | iwl_mvm_reset_phy_ctxts(mvm); | 883 | iwl_mvm_reset_phy_ctxts(mvm); |
| 793 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 884 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
| 794 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); | 885 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); |
| 886 | memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained)); | ||
| 795 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 887 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
| 796 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); | 888 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); |
| 797 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | 889 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); |
| @@ -805,16 +897,18 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
| 805 | * ucode_down ref until reconfig is complete */ | 897 | * ucode_down ref until reconfig is complete */ |
| 806 | iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); | 898 | iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); |
| 807 | 899 | ||
| 900 | /* clear any stale d0i3 state */ | ||
| 901 | clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | ||
| 902 | |||
| 808 | mvm->vif_count = 0; | 903 | mvm->vif_count = 0; |
| 809 | mvm->rx_ba_sessions = 0; | 904 | mvm->rx_ba_sessions = 0; |
| 810 | } | 905 | } |
| 811 | 906 | ||
| 812 | static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | 907 | int __iwl_mvm_mac_start(struct iwl_mvm *mvm) |
| 813 | { | 908 | { |
| 814 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 815 | int ret; | 909 | int ret; |
| 816 | 910 | ||
| 817 | mutex_lock(&mvm->mutex); | 911 | lockdep_assert_held(&mvm->mutex); |
| 818 | 912 | ||
| 819 | /* Clean up some internal and mac80211 state on restart */ | 913 | /* Clean up some internal and mac80211 state on restart */ |
| 820 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 914 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
| @@ -831,14 +925,23 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | |||
| 831 | iwl_mvm_d0i3_enable_tx(mvm, NULL); | 925 | iwl_mvm_d0i3_enable_tx(mvm, NULL); |
| 832 | } | 926 | } |
| 833 | 927 | ||
| 928 | return ret; | ||
| 929 | } | ||
| 930 | |||
| 931 | static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | ||
| 932 | { | ||
| 933 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 934 | int ret; | ||
| 935 | |||
| 936 | mutex_lock(&mvm->mutex); | ||
| 937 | ret = __iwl_mvm_mac_start(mvm); | ||
| 834 | mutex_unlock(&mvm->mutex); | 938 | mutex_unlock(&mvm->mutex); |
| 835 | 939 | ||
| 836 | return ret; | 940 | return ret; |
| 837 | } | 941 | } |
| 838 | 942 | ||
| 839 | static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | 943 | static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) |
| 840 | { | 944 | { |
| 841 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 842 | int ret; | 945 | int ret; |
| 843 | 946 | ||
| 844 | mutex_lock(&mvm->mutex); | 947 | mutex_lock(&mvm->mutex); |
| @@ -853,20 +956,61 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | |||
| 853 | /* allow transport/FW low power modes */ | 956 | /* allow transport/FW low power modes */ |
| 854 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | 957 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); |
| 855 | 958 | ||
| 959 | /* | ||
| 960 | * If we have TDLS peers, remove them. We don't know the last seqno/PN | ||
| 961 | * of packets the FW sent out, so we must reconnect. | ||
| 962 | */ | ||
| 963 | iwl_mvm_teardown_tdls_peers(mvm); | ||
| 964 | |||
| 856 | mutex_unlock(&mvm->mutex); | 965 | mutex_unlock(&mvm->mutex); |
| 857 | } | 966 | } |
| 858 | 967 | ||
| 859 | static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | 968 | static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) |
| 969 | { | ||
| 970 | bool exit_now; | ||
| 971 | |||
| 972 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
| 973 | return; | ||
| 974 | |||
| 975 | mutex_lock(&mvm->d0i3_suspend_mutex); | ||
| 976 | __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | ||
| 977 | exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, | ||
| 978 | &mvm->d0i3_suspend_flags); | ||
| 979 | mutex_unlock(&mvm->d0i3_suspend_mutex); | ||
| 980 | |||
| 981 | if (exit_now) { | ||
| 982 | IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); | ||
| 983 | _iwl_mvm_exit_d0i3(mvm); | ||
| 984 | } | ||
| 985 | } | ||
| 986 | |||
| 987 | static void | ||
| 988 | iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, | ||
| 989 | enum ieee80211_reconfig_type reconfig_type) | ||
| 860 | { | 990 | { |
| 861 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 991 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 862 | 992 | ||
| 863 | flush_work(&mvm->d0i3_exit_work); | 993 | switch (reconfig_type) { |
| 864 | flush_work(&mvm->async_handlers_wk); | 994 | case IEEE80211_RECONFIG_TYPE_RESTART: |
| 995 | iwl_mvm_restart_complete(mvm); | ||
| 996 | break; | ||
| 997 | case IEEE80211_RECONFIG_TYPE_SUSPEND: | ||
| 998 | iwl_mvm_resume_complete(mvm); | ||
| 999 | break; | ||
| 1000 | } | ||
| 1001 | } | ||
| 865 | 1002 | ||
| 866 | mutex_lock(&mvm->mutex); | 1003 | void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) |
| 1004 | { | ||
| 1005 | lockdep_assert_held(&mvm->mutex); | ||
| 867 | 1006 | ||
| 868 | /* disallow low power states when the FW is down */ | 1007 | /* |
| 869 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | 1008 | * Disallow low power states when the FW is down by taking |
| 1009 | * the UCODE_DOWN ref. in case of ongoing hw restart the | ||
| 1010 | * ref is already taken, so don't take it again. | ||
| 1011 | */ | ||
| 1012 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
| 1013 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | ||
| 870 | 1014 | ||
| 871 | /* async_handlers_wk is now blocked */ | 1015 | /* async_handlers_wk is now blocked */ |
| 872 | 1016 | ||
| @@ -882,8 +1026,27 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | |||
| 882 | /* async_handlers_list is empty and will stay empty: HW is stopped */ | 1026 | /* async_handlers_list is empty and will stay empty: HW is stopped */ |
| 883 | 1027 | ||
| 884 | /* the fw is stopped, the aux sta is dead: clean up driver state */ | 1028 | /* the fw is stopped, the aux sta is dead: clean up driver state */ |
| 885 | iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); | 1029 | iwl_mvm_del_aux_sta(mvm); |
| 1030 | |||
| 1031 | /* | ||
| 1032 | * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete() | ||
| 1033 | * won't be called in this case). | ||
| 1034 | */ | ||
| 1035 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | ||
| 1036 | |||
| 1037 | mvm->ucode_loaded = false; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | ||
| 1041 | { | ||
| 1042 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 886 | 1043 | ||
| 1044 | flush_work(&mvm->d0i3_exit_work); | ||
| 1045 | flush_work(&mvm->async_handlers_wk); | ||
| 1046 | flush_work(&mvm->fw_error_dump_wk); | ||
| 1047 | |||
| 1048 | mutex_lock(&mvm->mutex); | ||
| 1049 | __iwl_mvm_mac_stop(mvm); | ||
| 887 | mutex_unlock(&mvm->mutex); | 1050 | mutex_unlock(&mvm->mutex); |
| 888 | 1051 | ||
| 889 | /* | 1052 | /* |
| @@ -967,10 +1130,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
| 967 | */ | 1130 | */ |
| 968 | if (vif->type == NL80211_IFTYPE_AP || | 1131 | if (vif->type == NL80211_IFTYPE_AP || |
| 969 | vif->type == NL80211_IFTYPE_ADHOC) { | 1132 | vif->type == NL80211_IFTYPE_ADHOC) { |
| 970 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 1133 | ret = iwl_mvm_alloc_bcast_sta(mvm, vif); |
| 971 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, | ||
| 972 | qmask, | ||
| 973 | ieee80211_vif_type_p2p(vif)); | ||
| 974 | if (ret) { | 1134 | if (ret) { |
| 975 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); | 1135 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); |
| 976 | goto out_release; | 1136 | goto out_release; |
| @@ -1018,7 +1178,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
| 1018 | if (ret) | 1178 | if (ret) |
| 1019 | goto out_unref_phy; | 1179 | goto out_unref_phy; |
| 1020 | 1180 | ||
| 1021 | ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | 1181 | ret = iwl_mvm_add_bcast_sta(mvm, vif); |
| 1022 | if (ret) | 1182 | if (ret) |
| 1023 | goto out_unbind; | 1183 | goto out_unbind; |
| 1024 | 1184 | ||
| @@ -1059,14 +1219,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
| 1059 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, | 1219 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, |
| 1060 | struct ieee80211_vif *vif) | 1220 | struct ieee80211_vif *vif) |
| 1061 | { | 1221 | { |
| 1062 | u32 tfd_msk = 0, ac; | 1222 | u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); |
| 1063 | |||
| 1064 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 1065 | if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) | ||
| 1066 | tfd_msk |= BIT(vif->hw_queue[ac]); | ||
| 1067 | |||
| 1068 | if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) | ||
| 1069 | tfd_msk |= BIT(vif->cab_queue); | ||
| 1070 | 1223 | ||
| 1071 | if (tfd_msk) { | 1224 | if (tfd_msk) { |
| 1072 | mutex_lock(&mvm->mutex); | 1225 | mutex_lock(&mvm->mutex); |
| @@ -1122,13 +1275,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
| 1122 | mvm->noa_duration = 0; | 1275 | mvm->noa_duration = 0; |
| 1123 | } | 1276 | } |
| 1124 | #endif | 1277 | #endif |
| 1125 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | 1278 | iwl_mvm_dealloc_bcast_sta(mvm, vif); |
| 1126 | goto out_release; | 1279 | goto out_release; |
| 1127 | } | 1280 | } |
| 1128 | 1281 | ||
| 1129 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 1282 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
| 1130 | mvm->p2p_device_vif = NULL; | 1283 | mvm->p2p_device_vif = NULL; |
| 1131 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1284 | iwl_mvm_rm_bcast_sta(mvm, vif); |
| 1132 | iwl_mvm_binding_remove_vif(mvm, vif); | 1285 | iwl_mvm_binding_remove_vif(mvm, vif); |
| 1133 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | 1286 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
| 1134 | mvmvif->phy_ctxt = NULL; | 1287 | mvmvif->phy_ctxt = NULL; |
| @@ -1202,14 +1355,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, | |||
| 1202 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1355 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 1203 | struct iwl_mcast_filter_cmd *cmd; | 1356 | struct iwl_mcast_filter_cmd *cmd; |
| 1204 | struct netdev_hw_addr *addr; | 1357 | struct netdev_hw_addr *addr; |
| 1205 | int addr_count = netdev_hw_addr_list_count(mc_list); | 1358 | int addr_count; |
| 1206 | bool pass_all = false; | 1359 | bool pass_all; |
| 1207 | int len; | 1360 | int len; |
| 1208 | 1361 | ||
| 1209 | if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { | 1362 | addr_count = netdev_hw_addr_list_count(mc_list); |
| 1210 | pass_all = true; | 1363 | pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES || |
| 1364 | IWL_MVM_FW_MCAST_FILTER_PASS_ALL; | ||
| 1365 | if (pass_all) | ||
| 1211 | addr_count = 0; | 1366 | addr_count = 0; |
| 1212 | } | ||
| 1213 | 1367 | ||
| 1214 | len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); | 1368 | len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); |
| 1215 | cmd = kzalloc(len, GFP_ATOMIC); | 1369 | cmd = kzalloc(len, GFP_ATOMIC); |
| @@ -1361,6 +1515,9 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, | |||
| 1361 | .cmd = cmd, | 1515 | .cmd = cmd, |
| 1362 | }; | 1516 | }; |
| 1363 | 1517 | ||
| 1518 | if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL) | ||
| 1519 | return false; | ||
| 1520 | |||
| 1364 | memset(cmd, 0, sizeof(*cmd)); | 1521 | memset(cmd, 0, sizeof(*cmd)); |
| 1365 | cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); | 1522 | cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); |
| 1366 | cmd->max_macs = ARRAY_SIZE(cmd->macs); | 1523 | cmd->max_macs = ARRAY_SIZE(cmd->macs); |
| @@ -1409,28 +1566,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, | |||
| 1409 | } | 1566 | } |
| 1410 | #endif | 1567 | #endif |
| 1411 | 1568 | ||
| 1412 | static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) | ||
| 1413 | { | ||
| 1414 | struct ieee80211_sta *sta; | ||
| 1415 | struct iwl_mvm_sta *mvmsta; | ||
| 1416 | int i; | ||
| 1417 | |||
| 1418 | lockdep_assert_held(&mvm->mutex); | ||
| 1419 | |||
| 1420 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
| 1421 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
| 1422 | lockdep_is_held(&mvm->mutex)); | ||
| 1423 | if (!sta || IS_ERR(sta) || !sta->tdls) | ||
| 1424 | continue; | ||
| 1425 | |||
| 1426 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 1427 | ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, | ||
| 1428 | NL80211_TDLS_TEARDOWN, | ||
| 1429 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, | ||
| 1430 | GFP_KERNEL); | ||
| 1431 | } | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | 1569 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, |
| 1435 | struct ieee80211_vif *vif, | 1570 | struct ieee80211_vif *vif, |
| 1436 | struct ieee80211_bss_conf *bss_conf, | 1571 | struct ieee80211_bss_conf *bss_conf, |
| @@ -1447,10 +1582,23 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
| 1447 | if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) | 1582 | if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) |
| 1448 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); | 1583 | iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); |
| 1449 | 1584 | ||
| 1450 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); | 1585 | /* |
| 1586 | * If we're not associated yet, take the (new) BSSID before associating | ||
| 1587 | * so the firmware knows. If we're already associated, then use the old | ||
| 1588 | * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC | ||
| 1589 | * branch for disassociation below. | ||
| 1590 | */ | ||
| 1591 | if (changes & BSS_CHANGED_BSSID && !mvmvif->associated) | ||
| 1592 | memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN); | ||
| 1593 | |||
| 1594 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid); | ||
| 1451 | if (ret) | 1595 | if (ret) |
| 1452 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | 1596 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); |
| 1453 | 1597 | ||
| 1598 | /* after sending it once, adopt mac80211 data */ | ||
| 1599 | memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN); | ||
| 1600 | mvmvif->associated = bss_conf->assoc; | ||
| 1601 | |||
| 1454 | if (changes & BSS_CHANGED_ASSOC) { | 1602 | if (changes & BSS_CHANGED_ASSOC) { |
| 1455 | if (bss_conf->assoc) { | 1603 | if (bss_conf->assoc) { |
| 1456 | /* add quota for this interface */ | 1604 | /* add quota for this interface */ |
| @@ -1478,13 +1626,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
| 1478 | */ | 1626 | */ |
| 1479 | u32 dur = (11 * vif->bss_conf.beacon_int) / 10; | 1627 | u32 dur = (11 * vif->bss_conf.beacon_int) / 10; |
| 1480 | iwl_mvm_protect_session(mvm, vif, dur, dur, | 1628 | iwl_mvm_protect_session(mvm, vif, dur, dur, |
| 1481 | 5 * dur); | 1629 | 5 * dur, false); |
| 1482 | } | 1630 | } |
| 1483 | 1631 | ||
| 1484 | iwl_mvm_sf_update(mvm, vif, false); | 1632 | iwl_mvm_sf_update(mvm, vif, false); |
| 1485 | iwl_mvm_power_vif_assoc(mvm, vif); | 1633 | iwl_mvm_power_vif_assoc(mvm, vif); |
| 1486 | if (vif->p2p) | 1634 | if (vif->p2p) { |
| 1487 | iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); | 1635 | iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); |
| 1636 | iwl_mvm_update_smps(mvm, vif, | ||
| 1637 | IWL_MVM_SMPS_REQ_PROT, | ||
| 1638 | IEEE80211_SMPS_DYNAMIC); | ||
| 1639 | } | ||
| 1488 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 1640 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
| 1489 | /* | 1641 | /* |
| 1490 | * If update fails - SF might be running in associated | 1642 | * If update fails - SF might be running in associated |
| @@ -1508,6 +1660,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
| 1508 | 1660 | ||
| 1509 | if (vif->p2p) | 1661 | if (vif->p2p) |
| 1510 | iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); | 1662 | iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); |
| 1663 | |||
| 1664 | /* this will take the cleared BSSID from bss_conf */ | ||
| 1665 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | ||
| 1666 | if (ret) | ||
| 1667 | IWL_ERR(mvm, | ||
| 1668 | "failed to update MAC %pM (clear after unassoc)\n", | ||
| 1669 | vif->addr); | ||
| 1511 | } | 1670 | } |
| 1512 | 1671 | ||
| 1513 | iwl_mvm_recalc_multicast(mvm); | 1672 | iwl_mvm_recalc_multicast(mvm); |
| @@ -1604,7 +1763,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
| 1604 | 1763 | ||
| 1605 | /* Send the bcast station. At this stage the TBTT and DTIM time events | 1764 | /* Send the bcast station. At this stage the TBTT and DTIM time events |
| 1606 | * are added and applied to the scheduler */ | 1765 | * are added and applied to the scheduler */ |
| 1607 | ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | 1766 | ret = iwl_mvm_send_add_bcast_sta(mvm, vif); |
| 1608 | if (ret) | 1767 | if (ret) |
| 1609 | goto out_unbind; | 1768 | goto out_unbind; |
| 1610 | 1769 | ||
| @@ -1620,7 +1779,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
| 1620 | 1779 | ||
| 1621 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ | 1780 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
| 1622 | if (vif->p2p && mvm->p2p_device_vif) | 1781 | if (vif->p2p && mvm->p2p_device_vif) |
| 1623 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); | 1782 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); |
| 1624 | 1783 | ||
| 1625 | iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); | 1784 | iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); |
| 1626 | 1785 | ||
| @@ -1636,7 +1795,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
| 1636 | out_quota_failed: | 1795 | out_quota_failed: |
| 1637 | iwl_mvm_power_update_mac(mvm); | 1796 | iwl_mvm_power_update_mac(mvm); |
| 1638 | mvmvif->ap_ibss_active = false; | 1797 | mvmvif->ap_ibss_active = false; |
| 1639 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1798 | iwl_mvm_send_rm_bcast_sta(mvm, vif); |
| 1640 | out_unbind: | 1799 | out_unbind: |
| 1641 | iwl_mvm_binding_remove_vif(mvm, vif); | 1800 | iwl_mvm_binding_remove_vif(mvm, vif); |
| 1642 | out_remove: | 1801 | out_remove: |
| @@ -1678,10 +1837,10 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, | |||
| 1678 | 1837 | ||
| 1679 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ | 1838 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
| 1680 | if (vif->p2p && mvm->p2p_device_vif) | 1839 | if (vif->p2p && mvm->p2p_device_vif) |
| 1681 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); | 1840 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); |
| 1682 | 1841 | ||
| 1683 | iwl_mvm_update_quotas(mvm, NULL); | 1842 | iwl_mvm_update_quotas(mvm, NULL); |
| 1684 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1843 | iwl_mvm_send_rm_bcast_sta(mvm, vif); |
| 1685 | iwl_mvm_binding_remove_vif(mvm, vif); | 1844 | iwl_mvm_binding_remove_vif(mvm, vif); |
| 1686 | 1845 | ||
| 1687 | iwl_mvm_power_update_mac(mvm); | 1846 | iwl_mvm_power_update_mac(mvm); |
| @@ -1704,14 +1863,21 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, | |||
| 1704 | return; | 1863 | return; |
| 1705 | 1864 | ||
| 1706 | if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | | 1865 | if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | |
| 1707 | BSS_CHANGED_BANDWIDTH) && | 1866 | BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) && |
| 1708 | iwl_mvm_mac_ctxt_changed(mvm, vif, false)) | 1867 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL)) |
| 1709 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | 1868 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); |
| 1710 | 1869 | ||
| 1711 | /* Need to send a new beacon template to the FW */ | 1870 | /* Need to send a new beacon template to the FW */ |
| 1712 | if (changes & BSS_CHANGED_BEACON && | 1871 | if (changes & BSS_CHANGED_BEACON && |
| 1713 | iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) | 1872 | iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) |
| 1714 | IWL_WARN(mvm, "Failed updating beacon data\n"); | 1873 | IWL_WARN(mvm, "Failed updating beacon data\n"); |
| 1874 | |||
| 1875 | if (changes & BSS_CHANGED_TXPOWER) { | ||
| 1876 | IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", | ||
| 1877 | bss_conf->txpower); | ||
| 1878 | iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); | ||
| 1879 | } | ||
| 1880 | |||
| 1715 | } | 1881 | } |
| 1716 | 1882 | ||
| 1717 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | 1883 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, |
| @@ -1804,9 +1970,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
| 1804 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) | 1970 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) |
| 1805 | return -EINVAL; | 1971 | return -EINVAL; |
| 1806 | 1972 | ||
| 1807 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); | 1973 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { |
| 1808 | if (ret) | 1974 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); |
| 1809 | return ret; | 1975 | if (ret) |
| 1976 | return ret; | ||
| 1977 | } | ||
| 1810 | 1978 | ||
| 1811 | mutex_lock(&mvm->mutex); | 1979 | mutex_lock(&mvm->mutex); |
| 1812 | 1980 | ||
| @@ -1817,7 +1985,9 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
| 1817 | 1985 | ||
| 1818 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); | 1986 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); |
| 1819 | 1987 | ||
| 1820 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 1988 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) |
| 1989 | ret = iwl_mvm_scan_umac(mvm, vif, hw_req); | ||
| 1990 | else if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
| 1821 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); | 1991 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); |
| 1822 | else | 1992 | else |
| 1823 | ret = iwl_mvm_scan_request(mvm, vif, req); | 1993 | ret = iwl_mvm_scan_request(mvm, vif, req); |
| @@ -1935,48 +2105,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, | |||
| 1935 | mutex_unlock(&mvm->mutex); | 2105 | mutex_unlock(&mvm->mutex); |
| 1936 | } | 2106 | } |
| 1937 | 2107 | ||
| 1938 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
| 1939 | { | ||
| 1940 | struct ieee80211_sta *sta; | ||
| 1941 | struct iwl_mvm_sta *mvmsta; | ||
| 1942 | int count = 0; | ||
| 1943 | int i; | ||
| 1944 | |||
| 1945 | lockdep_assert_held(&mvm->mutex); | ||
| 1946 | |||
| 1947 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
| 1948 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
| 1949 | lockdep_is_held(&mvm->mutex)); | ||
| 1950 | if (!sta || IS_ERR(sta) || !sta->tdls) | ||
| 1951 | continue; | ||
| 1952 | |||
| 1953 | if (vif) { | ||
| 1954 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 1955 | if (mvmsta->vif != vif) | ||
| 1956 | continue; | ||
| 1957 | } | ||
| 1958 | |||
| 1959 | count++; | ||
| 1960 | } | ||
| 1961 | |||
| 1962 | return count; | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, | ||
| 1966 | struct ieee80211_vif *vif, | ||
| 1967 | bool sta_added) | ||
| 1968 | { | ||
| 1969 | int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); | ||
| 1970 | |||
| 1971 | /* | ||
| 1972 | * Disable ps when the first TDLS sta is added and re-enable it | ||
| 1973 | * when the last TDLS sta is removed | ||
| 1974 | */ | ||
| 1975 | if ((tdls_sta_cnt == 1 && sta_added) || | ||
| 1976 | (tdls_sta_cnt == 0 && !sta_added)) | ||
| 1977 | iwl_mvm_power_update_mac(mvm); | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | 2108 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, |
| 1981 | struct ieee80211_vif *vif, | 2109 | struct ieee80211_vif *vif, |
| 1982 | struct ieee80211_sta *sta, | 2110 | struct ieee80211_sta *sta, |
| @@ -2076,6 +2204,15 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
| 2076 | out_unlock: | 2204 | out_unlock: |
| 2077 | mutex_unlock(&mvm->mutex); | 2205 | mutex_unlock(&mvm->mutex); |
| 2078 | 2206 | ||
| 2207 | if (sta->tdls && ret == 0) { | ||
| 2208 | if (old_state == IEEE80211_STA_NOTEXIST && | ||
| 2209 | new_state == IEEE80211_STA_NONE) | ||
| 2210 | ieee80211_reserve_tid(sta, IWL_MVM_TDLS_FW_TID); | ||
| 2211 | else if (old_state == IEEE80211_STA_NONE && | ||
| 2212 | new_state == IEEE80211_STA_NOTEXIST) | ||
| 2213 | ieee80211_unreserve_tid(sta, IWL_MVM_TDLS_FW_TID); | ||
| 2214 | } | ||
| 2215 | |||
| 2079 | return ret; | 2216 | return ret; |
| 2080 | } | 2217 | } |
| 2081 | 2218 | ||
| @@ -2116,7 +2253,7 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, | |||
| 2116 | int ret; | 2253 | int ret; |
| 2117 | 2254 | ||
| 2118 | mutex_lock(&mvm->mutex); | 2255 | mutex_lock(&mvm->mutex); |
| 2119 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false); | 2256 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); |
| 2120 | mutex_unlock(&mvm->mutex); | 2257 | mutex_unlock(&mvm->mutex); |
| 2121 | return ret; | 2258 | return ret; |
| 2122 | } | 2259 | } |
| @@ -2144,33 +2281,12 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
| 2144 | 2281 | ||
| 2145 | mutex_lock(&mvm->mutex); | 2282 | mutex_lock(&mvm->mutex); |
| 2146 | /* Try really hard to protect the session and hear a beacon */ | 2283 | /* Try really hard to protect the session and hear a beacon */ |
| 2147 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); | 2284 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); |
| 2148 | mutex_unlock(&mvm->mutex); | 2285 | mutex_unlock(&mvm->mutex); |
| 2149 | 2286 | ||
| 2150 | iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); | 2287 | iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); |
| 2151 | } | 2288 | } |
| 2152 | 2289 | ||
| 2153 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | ||
| 2154 | struct ieee80211_vif *vif) | ||
| 2155 | { | ||
| 2156 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 2157 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; | ||
| 2158 | |||
| 2159 | /* | ||
| 2160 | * iwl_mvm_protect_session() reads directly from the device | ||
| 2161 | * (the system time), so make sure it is available. | ||
| 2162 | */ | ||
| 2163 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) | ||
| 2164 | return; | ||
| 2165 | |||
| 2166 | mutex_lock(&mvm->mutex); | ||
| 2167 | /* Protect the session to hear the TDLS setup response on the channel */ | ||
| 2168 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); | ||
| 2169 | mutex_unlock(&mvm->mutex); | ||
| 2170 | |||
| 2171 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | 2290 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, |
| 2175 | struct ieee80211_vif *vif, | 2291 | struct ieee80211_vif *vif, |
| 2176 | struct cfg80211_sched_scan_request *req, | 2292 | struct cfg80211_sched_scan_request *req, |
| @@ -2179,13 +2295,21 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
| 2179 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2295 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 2180 | int ret; | 2296 | int ret; |
| 2181 | 2297 | ||
| 2182 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); | 2298 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { |
| 2183 | if (ret) | 2299 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); |
| 2184 | return ret; | 2300 | if (ret) |
| 2301 | return ret; | ||
| 2302 | } | ||
| 2185 | 2303 | ||
| 2186 | mutex_lock(&mvm->mutex); | 2304 | mutex_lock(&mvm->mutex); |
| 2187 | 2305 | ||
| 2188 | if (!iwl_mvm_is_idle(mvm)) { | 2306 | /* Newest FW fixes sched scan while connected on another interface */ |
| 2307 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) { | ||
| 2308 | if (!vif->bss_conf.idle) { | ||
| 2309 | ret = -EBUSY; | ||
| 2310 | goto out; | ||
| 2311 | } | ||
| 2312 | } else if (!iwl_mvm_is_idle(mvm)) { | ||
| 2189 | ret = -EBUSY; | 2313 | ret = -EBUSY; |
| 2190 | goto out; | 2314 | goto out; |
| 2191 | } | 2315 | } |
| @@ -2195,27 +2319,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
| 2195 | goto out; | 2319 | goto out; |
| 2196 | } | 2320 | } |
| 2197 | 2321 | ||
| 2198 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | 2322 | ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies); |
| 2199 | |||
| 2200 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | ||
| 2201 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); | ||
| 2202 | if (ret) | ||
| 2203 | goto err; | ||
| 2204 | } | ||
| 2205 | |||
| 2206 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
| 2207 | if (ret) | 2323 | if (ret) |
| 2208 | goto err; | 2324 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
| 2209 | 2325 | ||
| 2210 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
| 2211 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); | ||
| 2212 | else | ||
| 2213 | ret = iwl_mvm_sched_scan_start(mvm, req); | ||
| 2214 | |||
| 2215 | if (!ret) | ||
| 2216 | goto out; | ||
| 2217 | err: | ||
| 2218 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
| 2219 | out: | 2326 | out: |
| 2220 | mutex_unlock(&mvm->mutex); | 2327 | mutex_unlock(&mvm->mutex); |
| 2221 | return ret; | 2328 | return ret; |
| @@ -2233,6 +2340,7 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | |||
| 2233 | iwl_mvm_wait_for_async_handlers(mvm); | 2340 | iwl_mvm_wait_for_async_handlers(mvm); |
| 2234 | 2341 | ||
| 2235 | return ret; | 2342 | return ret; |
| 2343 | |||
| 2236 | } | 2344 | } |
| 2237 | 2345 | ||
| 2238 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 2346 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
| @@ -2261,12 +2369,16 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | |||
| 2261 | break; | 2369 | break; |
| 2262 | case WLAN_CIPHER_SUITE_WEP40: | 2370 | case WLAN_CIPHER_SUITE_WEP40: |
| 2263 | case WLAN_CIPHER_SUITE_WEP104: | 2371 | case WLAN_CIPHER_SUITE_WEP104: |
| 2264 | /* | 2372 | /* For non-client mode, only use WEP keys for TX as we probably |
| 2265 | * Support for TX only, at least for now, so accept | 2373 | * don't have a station yet anyway and would then have to keep |
| 2266 | * the key and do nothing else. Then mac80211 will | 2374 | * track of the keys, linking them to each of the clients/peers |
| 2267 | * pass it for TX but we don't have to use it for RX. | 2375 | * as they appear. For now, don't do that, for performance WEP |
| 2376 | * offload doesn't really matter much, but we need it for some | ||
| 2377 | * other offload features in client mode. | ||
| 2268 | */ | 2378 | */ |
| 2269 | return 0; | 2379 | if (vif->type != NL80211_IFTYPE_STATION) |
| 2380 | return 0; | ||
| 2381 | break; | ||
| 2270 | default: | 2382 | default: |
| 2271 | /* currently FW supports only one optional cipher scheme */ | 2383 | /* currently FW supports only one optional cipher scheme */ |
| 2272 | if (hw->n_cipher_schemes && | 2384 | if (hw->n_cipher_schemes && |
| @@ -2402,14 +2514,19 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, | |||
| 2402 | /* Set the node address */ | 2514 | /* Set the node address */ |
| 2403 | memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); | 2515 | memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); |
| 2404 | 2516 | ||
| 2517 | lockdep_assert_held(&mvm->mutex); | ||
| 2518 | |||
| 2519 | spin_lock_bh(&mvm->time_event_lock); | ||
| 2520 | |||
| 2521 | if (WARN_ON(te_data->id == HOT_SPOT_CMD)) { | ||
| 2522 | spin_unlock_bh(&mvm->time_event_lock); | ||
| 2523 | return -EIO; | ||
| 2524 | } | ||
| 2525 | |||
| 2405 | te_data->vif = vif; | 2526 | te_data->vif = vif; |
| 2406 | te_data->duration = duration; | 2527 | te_data->duration = duration; |
| 2407 | te_data->id = HOT_SPOT_CMD; | 2528 | te_data->id = HOT_SPOT_CMD; |
| 2408 | 2529 | ||
| 2409 | lockdep_assert_held(&mvm->mutex); | ||
| 2410 | |||
| 2411 | spin_lock_bh(&mvm->time_event_lock); | ||
| 2412 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
| 2413 | spin_unlock_bh(&mvm->time_event_lock); | 2530 | spin_unlock_bh(&mvm->time_event_lock); |
| 2414 | 2531 | ||
| 2415 | /* | 2532 | /* |
| @@ -2465,22 +2582,29 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
| 2465 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | 2582 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, |
| 2466 | duration, type); | 2583 | duration, type); |
| 2467 | 2584 | ||
| 2585 | mutex_lock(&mvm->mutex); | ||
| 2586 | |||
| 2468 | switch (vif->type) { | 2587 | switch (vif->type) { |
| 2469 | case NL80211_IFTYPE_STATION: | 2588 | case NL80211_IFTYPE_STATION: |
| 2470 | /* Use aux roc framework (HS20) */ | 2589 | if (mvm->fw->ucode_capa.capa[0] & |
| 2471 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | 2590 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) { |
| 2472 | vif, duration); | 2591 | /* Use aux roc framework (HS20) */ |
| 2473 | return ret; | 2592 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, |
| 2593 | vif, duration); | ||
| 2594 | goto out_unlock; | ||
| 2595 | } | ||
| 2596 | IWL_ERR(mvm, "hotspot not supported\n"); | ||
| 2597 | ret = -EINVAL; | ||
| 2598 | goto out_unlock; | ||
| 2474 | case NL80211_IFTYPE_P2P_DEVICE: | 2599 | case NL80211_IFTYPE_P2P_DEVICE: |
| 2475 | /* handle below */ | 2600 | /* handle below */ |
| 2476 | break; | 2601 | break; |
| 2477 | default: | 2602 | default: |
| 2478 | IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); | 2603 | IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); |
| 2479 | return -EINVAL; | 2604 | ret = -EINVAL; |
| 2605 | goto out_unlock; | ||
| 2480 | } | 2606 | } |
| 2481 | 2607 | ||
| 2482 | mutex_lock(&mvm->mutex); | ||
| 2483 | |||
| 2484 | for (i = 0; i < NUM_PHY_CTX; i++) { | 2608 | for (i = 0; i < NUM_PHY_CTX; i++) { |
| 2485 | phy_ctxt = &mvm->phy_ctxts[i]; | 2609 | phy_ctxt = &mvm->phy_ctxts[i]; |
| 2486 | if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) | 2610 | if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) |
| @@ -2577,7 +2701,7 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) | |||
| 2577 | IWL_DEBUG_MAC80211(mvm, "enter\n"); | 2701 | IWL_DEBUG_MAC80211(mvm, "enter\n"); |
| 2578 | 2702 | ||
| 2579 | mutex_lock(&mvm->mutex); | 2703 | mutex_lock(&mvm->mutex); |
| 2580 | iwl_mvm_stop_p2p_roc(mvm); | 2704 | iwl_mvm_stop_roc(mvm); |
| 2581 | mutex_unlock(&mvm->mutex); | 2705 | mutex_unlock(&mvm->mutex); |
| 2582 | 2706 | ||
| 2583 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 2707 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
| @@ -2690,8 +2814,8 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
| 2690 | 2814 | ||
| 2691 | switch (vif->type) { | 2815 | switch (vif->type) { |
| 2692 | case NL80211_IFTYPE_AP: | 2816 | case NL80211_IFTYPE_AP: |
| 2693 | /* Unless it's a CSA flow we have nothing to do here */ | 2817 | /* only needed if we're switching chanctx (i.e. during CSA) */ |
| 2694 | if (vif->csa_active) { | 2818 | if (switching_chanctx) { |
| 2695 | mvmvif->ap_ibss_active = true; | 2819 | mvmvif->ap_ibss_active = true; |
| 2696 | break; | 2820 | break; |
| 2697 | } | 2821 | } |
| @@ -2703,7 +2827,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
| 2703 | ret = 0; | 2827 | ret = 0; |
| 2704 | goto out; | 2828 | goto out; |
| 2705 | case NL80211_IFTYPE_STATION: | 2829 | case NL80211_IFTYPE_STATION: |
| 2830 | break; | ||
| 2706 | case NL80211_IFTYPE_MONITOR: | 2831 | case NL80211_IFTYPE_MONITOR: |
| 2832 | /* always disable PS when a monitor interface is active */ | ||
| 2833 | mvmvif->ps_disabled = true; | ||
| 2707 | break; | 2834 | break; |
| 2708 | default: | 2835 | default: |
| 2709 | ret = -EINVAL; | 2836 | ret = -EINVAL; |
| @@ -2732,10 +2859,32 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
| 2732 | } | 2859 | } |
| 2733 | 2860 | ||
| 2734 | /* Handle binding during CSA */ | 2861 | /* Handle binding during CSA */ |
| 2735 | if ((vif->type == NL80211_IFTYPE_AP) || | 2862 | if (vif->type == NL80211_IFTYPE_AP) { |
| 2736 | (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) { | 2863 | iwl_mvm_update_quotas(mvm, NULL); |
| 2864 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | ||
| 2865 | } | ||
| 2866 | |||
| 2867 | if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) { | ||
| 2868 | u32 duration = 2 * vif->bss_conf.beacon_int; | ||
| 2869 | |||
| 2870 | /* iwl_mvm_protect_session() reads directly from the | ||
| 2871 | * device (the system time), so make sure it is | ||
| 2872 | * available. | ||
| 2873 | */ | ||
| 2874 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA); | ||
| 2875 | if (ret) | ||
| 2876 | goto out_remove_binding; | ||
| 2877 | |||
| 2878 | /* Protect the session to make sure we hear the first | ||
| 2879 | * beacon on the new channel. | ||
| 2880 | */ | ||
| 2881 | iwl_mvm_protect_session(mvm, vif, duration, duration, | ||
| 2882 | vif->bss_conf.beacon_int / 2, | ||
| 2883 | true); | ||
| 2884 | |||
| 2885 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); | ||
| 2886 | |||
| 2737 | iwl_mvm_update_quotas(mvm, NULL); | 2887 | iwl_mvm_update_quotas(mvm, NULL); |
| 2738 | iwl_mvm_mac_ctxt_changed(mvm, vif, false); | ||
| 2739 | } | 2888 | } |
| 2740 | 2889 | ||
| 2741 | goto out; | 2890 | goto out; |
| @@ -2779,12 +2928,15 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
| 2779 | goto out; | 2928 | goto out; |
| 2780 | case NL80211_IFTYPE_MONITOR: | 2929 | case NL80211_IFTYPE_MONITOR: |
| 2781 | mvmvif->monitor_active = false; | 2930 | mvmvif->monitor_active = false; |
| 2931 | mvmvif->ps_disabled = false; | ||
| 2782 | break; | 2932 | break; |
| 2783 | case NL80211_IFTYPE_AP: | 2933 | case NL80211_IFTYPE_AP: |
| 2784 | /* This part is triggered only during CSA */ | 2934 | /* This part is triggered only during CSA */ |
| 2785 | if (!vif->csa_active || !mvmvif->ap_ibss_active) | 2935 | if (!switching_chanctx || !mvmvif->ap_ibss_active) |
| 2786 | goto out; | 2936 | goto out; |
| 2787 | 2937 | ||
| 2938 | mvmvif->csa_countdown = false; | ||
| 2939 | |||
| 2788 | /* Set CS bit on all the stations */ | 2940 | /* Set CS bit on all the stations */ |
| 2789 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); | 2941 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); |
| 2790 | 2942 | ||
| @@ -2799,7 +2951,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
| 2799 | 2951 | ||
| 2800 | disabled_vif = vif; | 2952 | disabled_vif = vif; |
| 2801 | 2953 | ||
| 2802 | iwl_mvm_mac_ctxt_changed(mvm, vif, true); | 2954 | iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); |
| 2803 | break; | 2955 | break; |
| 2804 | default: | 2956 | default: |
| 2805 | break; | 2957 | break; |
| @@ -2824,18 +2976,12 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
| 2824 | mutex_unlock(&mvm->mutex); | 2976 | mutex_unlock(&mvm->mutex); |
| 2825 | } | 2977 | } |
| 2826 | 2978 | ||
| 2827 | static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, | 2979 | static int |
| 2828 | struct ieee80211_vif_chanctx_switch *vifs, | 2980 | iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm, |
| 2829 | int n_vifs, | 2981 | struct ieee80211_vif_chanctx_switch *vifs) |
| 2830 | enum ieee80211_chanctx_switch_mode mode) | ||
| 2831 | { | 2982 | { |
| 2832 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 2833 | int ret; | 2983 | int ret; |
| 2834 | 2984 | ||
| 2835 | /* we only support SWAP_CONTEXTS and with a single-vif right now */ | ||
| 2836 | if (mode != CHANCTX_SWMODE_SWAP_CONTEXTS || n_vifs > 1) | ||
| 2837 | return -EOPNOTSUPP; | ||
| 2838 | |||
| 2839 | mutex_lock(&mvm->mutex); | 2985 | mutex_lock(&mvm->mutex); |
| 2840 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); | 2986 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); |
| 2841 | __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); | 2987 | __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); |
| @@ -2864,15 +3010,51 @@ out_remove: | |||
| 2864 | __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); | 3010 | __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); |
| 2865 | 3011 | ||
| 2866 | out_reassign: | 3012 | out_reassign: |
| 2867 | ret = __iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx); | 3013 | if (__iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx)) { |
| 2868 | if (ret) { | ||
| 2869 | IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); | 3014 | IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); |
| 2870 | goto out_restart; | 3015 | goto out_restart; |
| 2871 | } | 3016 | } |
| 2872 | 3017 | ||
| 2873 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, | 3018 | if (__iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, |
| 3019 | true)) { | ||
| 3020 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); | ||
| 3021 | goto out_restart; | ||
| 3022 | } | ||
| 3023 | |||
| 3024 | goto out; | ||
| 3025 | |||
| 3026 | out_restart: | ||
| 3027 | /* things keep failing, better restart the hw */ | ||
| 3028 | iwl_mvm_nic_restart(mvm, false); | ||
| 3029 | |||
| 3030 | out: | ||
| 3031 | mutex_unlock(&mvm->mutex); | ||
| 3032 | |||
| 3033 | return ret; | ||
| 3034 | } | ||
| 3035 | |||
| 3036 | static int | ||
| 3037 | iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm, | ||
| 3038 | struct ieee80211_vif_chanctx_switch *vifs) | ||
| 3039 | { | ||
| 3040 | int ret; | ||
| 3041 | |||
| 3042 | mutex_lock(&mvm->mutex); | ||
| 3043 | __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); | ||
| 3044 | |||
| 3045 | ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx, | ||
| 2874 | true); | 3046 | true); |
| 2875 | if (ret) { | 3047 | if (ret) { |
| 3048 | IWL_ERR(mvm, | ||
| 3049 | "failed to assign new_ctx during channel switch\n"); | ||
| 3050 | goto out_reassign; | ||
| 3051 | } | ||
| 3052 | |||
| 3053 | goto out; | ||
| 3054 | |||
| 3055 | out_reassign: | ||
| 3056 | if (__iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, | ||
| 3057 | true)) { | ||
| 2876 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); | 3058 | IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); |
| 2877 | goto out_restart; | 3059 | goto out_restart; |
| 2878 | } | 3060 | } |
| @@ -2885,6 +3067,34 @@ out_restart: | |||
| 2885 | 3067 | ||
| 2886 | out: | 3068 | out: |
| 2887 | mutex_unlock(&mvm->mutex); | 3069 | mutex_unlock(&mvm->mutex); |
| 3070 | |||
| 3071 | return ret; | ||
| 3072 | } | ||
| 3073 | |||
| 3074 | static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, | ||
| 3075 | struct ieee80211_vif_chanctx_switch *vifs, | ||
| 3076 | int n_vifs, | ||
| 3077 | enum ieee80211_chanctx_switch_mode mode) | ||
| 3078 | { | ||
| 3079 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 3080 | int ret; | ||
| 3081 | |||
| 3082 | /* we only support a single-vif right now */ | ||
| 3083 | if (n_vifs > 1) | ||
| 3084 | return -EOPNOTSUPP; | ||
| 3085 | |||
| 3086 | switch (mode) { | ||
| 3087 | case CHANCTX_SWMODE_SWAP_CONTEXTS: | ||
| 3088 | ret = iwl_mvm_switch_vif_chanctx_swap(mvm, vifs); | ||
| 3089 | break; | ||
| 3090 | case CHANCTX_SWMODE_REASSIGN_VIF: | ||
| 3091 | ret = iwl_mvm_switch_vif_chanctx_reassign(mvm, vifs); | ||
| 3092 | break; | ||
| 3093 | default: | ||
| 3094 | ret = -EOPNOTSUPP; | ||
| 3095 | break; | ||
| 3096 | } | ||
| 3097 | |||
| 2888 | return ret; | 3098 | return ret; |
| 2889 | } | 3099 | } |
| 2890 | 3100 | ||
| @@ -2970,27 +3180,134 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, | |||
| 2970 | } | 3180 | } |
| 2971 | #endif | 3181 | #endif |
| 2972 | 3182 | ||
| 2973 | static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, | 3183 | static void iwl_mvm_channel_switch(struct ieee80211_hw *hw, |
| 2974 | struct ieee80211_vif *vif, | 3184 | struct ieee80211_vif *vif, |
| 2975 | struct cfg80211_chan_def *chandef) | 3185 | struct ieee80211_channel_switch *chsw) |
| 3186 | { | ||
| 3187 | /* By implementing this operation, we prevent mac80211 from | ||
| 3188 | * starting its own channel switch timer, so that we can call | ||
| 3189 | * ieee80211_chswitch_done() ourselves at the right time | ||
| 3190 | * (which is when the absence time event starts). | ||
| 3191 | */ | ||
| 3192 | |||
| 3193 | IWL_DEBUG_MAC80211(IWL_MAC80211_GET_MVM(hw), | ||
| 3194 | "dummy channel switch op\n"); | ||
| 3195 | } | ||
| 3196 | |||
| 3197 | static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, | ||
| 3198 | struct ieee80211_vif *vif, | ||
| 3199 | struct ieee80211_channel_switch *chsw) | ||
| 2976 | { | 3200 | { |
| 2977 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3201 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 2978 | struct ieee80211_vif *csa_vif; | 3202 | struct ieee80211_vif *csa_vif; |
| 3203 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 3204 | u32 apply_time; | ||
| 3205 | int ret; | ||
| 2979 | 3206 | ||
| 2980 | mutex_lock(&mvm->mutex); | 3207 | mutex_lock(&mvm->mutex); |
| 2981 | 3208 | ||
| 2982 | csa_vif = rcu_dereference_protected(mvm->csa_vif, | 3209 | IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n", |
| 2983 | lockdep_is_held(&mvm->mutex)); | 3210 | chsw->chandef.center_freq1); |
| 2984 | if (WARN(csa_vif && csa_vif->csa_active, | 3211 | |
| 2985 | "Another CSA is already in progress")) | 3212 | switch (vif->type) { |
| 3213 | case NL80211_IFTYPE_AP: | ||
| 3214 | csa_vif = | ||
| 3215 | rcu_dereference_protected(mvm->csa_vif, | ||
| 3216 | lockdep_is_held(&mvm->mutex)); | ||
| 3217 | if (WARN_ONCE(csa_vif && csa_vif->csa_active, | ||
| 3218 | "Another CSA is already in progress")) { | ||
| 3219 | ret = -EBUSY; | ||
| 3220 | goto out_unlock; | ||
| 3221 | } | ||
| 3222 | |||
| 3223 | rcu_assign_pointer(mvm->csa_vif, vif); | ||
| 3224 | |||
| 3225 | if (WARN_ONCE(mvmvif->csa_countdown, | ||
| 3226 | "Previous CSA countdown didn't complete")) { | ||
| 3227 | ret = -EBUSY; | ||
| 3228 | goto out_unlock; | ||
| 3229 | } | ||
| 3230 | |||
| 3231 | break; | ||
| 3232 | case NL80211_IFTYPE_STATION: | ||
| 3233 | /* Schedule the time event to a bit before beacon 1, | ||
| 3234 | * to make sure we're in the new channel when the | ||
| 3235 | * GO/AP arrives. | ||
| 3236 | */ | ||
| 3237 | apply_time = chsw->device_timestamp + | ||
| 3238 | ((vif->bss_conf.beacon_int * (chsw->count - 1) - | ||
| 3239 | IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024); | ||
| 3240 | |||
| 3241 | if (chsw->block_tx) | ||
| 3242 | iwl_mvm_csa_client_absent(mvm, vif); | ||
| 3243 | |||
| 3244 | iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int, | ||
| 3245 | apply_time); | ||
| 3246 | if (mvmvif->bf_data.bf_enabled) { | ||
| 3247 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); | ||
| 3248 | if (ret) | ||
| 3249 | goto out_unlock; | ||
| 3250 | } | ||
| 3251 | |||
| 3252 | break; | ||
| 3253 | default: | ||
| 3254 | break; | ||
| 3255 | } | ||
| 3256 | |||
| 3257 | mvmvif->ps_disabled = true; | ||
| 3258 | |||
| 3259 | ret = iwl_mvm_power_update_ps(mvm); | ||
| 3260 | if (ret) | ||
| 2986 | goto out_unlock; | 3261 | goto out_unlock; |
| 2987 | 3262 | ||
| 2988 | IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", | 3263 | /* we won't be on this channel any longer */ |
| 2989 | chandef->center_freq1); | 3264 | iwl_mvm_teardown_tdls_peers(mvm); |
| 2990 | rcu_assign_pointer(mvm->csa_vif, vif); | ||
| 2991 | 3265 | ||
| 2992 | out_unlock: | 3266 | out_unlock: |
| 2993 | mutex_unlock(&mvm->mutex); | 3267 | mutex_unlock(&mvm->mutex); |
| 3268 | |||
| 3269 | return ret; | ||
| 3270 | } | ||
| 3271 | |||
| 3272 | static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, | ||
| 3273 | struct ieee80211_vif *vif) | ||
| 3274 | { | ||
| 3275 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 3276 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 3277 | int ret; | ||
| 3278 | |||
| 3279 | mutex_lock(&mvm->mutex); | ||
| 3280 | |||
| 3281 | if (vif->type == NL80211_IFTYPE_STATION) { | ||
| 3282 | struct iwl_mvm_sta *mvmsta; | ||
| 3283 | |||
| 3284 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, | ||
| 3285 | mvmvif->ap_sta_id); | ||
| 3286 | |||
| 3287 | if (WARN_ON(!mvmsta)) { | ||
| 3288 | ret = -EIO; | ||
| 3289 | goto out_unlock; | ||
| 3290 | } | ||
| 3291 | |||
| 3292 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false); | ||
| 3293 | |||
| 3294 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | ||
| 3295 | |||
| 3296 | ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); | ||
| 3297 | if (ret) | ||
| 3298 | goto out_unlock; | ||
| 3299 | |||
| 3300 | iwl_mvm_stop_session_protection(mvm, vif); | ||
| 3301 | } | ||
| 3302 | |||
| 3303 | mvmvif->ps_disabled = false; | ||
| 3304 | |||
| 3305 | ret = iwl_mvm_power_update_ps(mvm); | ||
| 3306 | |||
| 3307 | out_unlock: | ||
| 3308 | mutex_unlock(&mvm->mutex); | ||
| 3309 | |||
| 3310 | return ret; | ||
| 2994 | } | 3311 | } |
| 2995 | 3312 | ||
| 2996 | static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, | 3313 | static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, |
| @@ -2999,33 +3316,52 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, | |||
| 2999 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3316 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 3000 | struct iwl_mvm_vif *mvmvif; | 3317 | struct iwl_mvm_vif *mvmvif; |
| 3001 | struct iwl_mvm_sta *mvmsta; | 3318 | struct iwl_mvm_sta *mvmsta; |
| 3319 | struct ieee80211_sta *sta; | ||
| 3320 | int i; | ||
| 3321 | u32 msk = 0; | ||
| 3002 | 3322 | ||
| 3003 | if (!vif || vif->type != NL80211_IFTYPE_STATION) | 3323 | if (!vif || vif->type != NL80211_IFTYPE_STATION) |
| 3004 | return; | 3324 | return; |
| 3005 | 3325 | ||
| 3006 | mutex_lock(&mvm->mutex); | 3326 | mutex_lock(&mvm->mutex); |
| 3007 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | 3327 | mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 3008 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); | ||
| 3009 | 3328 | ||
| 3010 | if (WARN_ON_ONCE(!mvmsta)) | 3329 | /* flush the AP-station and all TDLS peers */ |
| 3011 | goto done; | 3330 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { |
| 3331 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
| 3332 | lockdep_is_held(&mvm->mutex)); | ||
| 3333 | if (IS_ERR_OR_NULL(sta)) | ||
| 3334 | continue; | ||
| 3335 | |||
| 3336 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 3337 | if (mvmsta->vif != vif) | ||
| 3338 | continue; | ||
| 3339 | |||
| 3340 | /* make sure only TDLS peers or the AP are flushed */ | ||
| 3341 | WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls); | ||
| 3342 | |||
| 3343 | msk |= mvmsta->tfd_queue_msk; | ||
| 3344 | } | ||
| 3012 | 3345 | ||
| 3013 | if (drop) { | 3346 | if (drop) { |
| 3014 | if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) | 3347 | if (iwl_mvm_flush_tx_path(mvm, msk, true)) |
| 3015 | IWL_ERR(mvm, "flush request fail\n"); | 3348 | IWL_ERR(mvm, "flush request fail\n"); |
| 3349 | mutex_unlock(&mvm->mutex); | ||
| 3016 | } else { | 3350 | } else { |
| 3017 | iwl_trans_wait_tx_queue_empty(mvm->trans, | 3351 | mutex_unlock(&mvm->mutex); |
| 3018 | mvmsta->tfd_queue_msk); | 3352 | |
| 3353 | /* this can take a while, and we may need/want other operations | ||
| 3354 | * to succeed while doing this, so do it without the mutex held | ||
| 3355 | */ | ||
| 3356 | iwl_trans_wait_tx_queue_empty(mvm->trans, msk); | ||
| 3019 | } | 3357 | } |
| 3020 | done: | ||
| 3021 | mutex_unlock(&mvm->mutex); | ||
| 3022 | } | 3358 | } |
| 3023 | 3359 | ||
| 3024 | const struct ieee80211_ops iwl_mvm_hw_ops = { | 3360 | const struct ieee80211_ops iwl_mvm_hw_ops = { |
| 3025 | .tx = iwl_mvm_mac_tx, | 3361 | .tx = iwl_mvm_mac_tx, |
| 3026 | .ampdu_action = iwl_mvm_mac_ampdu_action, | 3362 | .ampdu_action = iwl_mvm_mac_ampdu_action, |
| 3027 | .start = iwl_mvm_mac_start, | 3363 | .start = iwl_mvm_mac_start, |
| 3028 | .restart_complete = iwl_mvm_mac_restart_complete, | 3364 | .reconfig_complete = iwl_mvm_mac_reconfig_complete, |
| 3029 | .stop = iwl_mvm_mac_stop, | 3365 | .stop = iwl_mvm_mac_stop, |
| 3030 | .add_interface = iwl_mvm_mac_add_interface, | 3366 | .add_interface = iwl_mvm_mac_add_interface, |
| 3031 | .remove_interface = iwl_mvm_mac_remove_interface, | 3367 | .remove_interface = iwl_mvm_mac_remove_interface, |
| @@ -3066,7 +3402,13 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { | |||
| 3066 | 3402 | ||
| 3067 | .set_tim = iwl_mvm_set_tim, | 3403 | .set_tim = iwl_mvm_set_tim, |
| 3068 | 3404 | ||
| 3069 | .channel_switch_beacon = iwl_mvm_channel_switch_beacon, | 3405 | .channel_switch = iwl_mvm_channel_switch, |
| 3406 | .pre_channel_switch = iwl_mvm_pre_channel_switch, | ||
| 3407 | .post_channel_switch = iwl_mvm_post_channel_switch, | ||
| 3408 | |||
| 3409 | .tdls_channel_switch = iwl_mvm_tdls_channel_switch, | ||
| 3410 | .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch, | ||
| 3411 | .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch, | ||
| 3070 | 3412 | ||
| 3071 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) | 3413 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) |
| 3072 | 3414 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2e73d3bd7757..d24660fb4ef2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -85,11 +87,17 @@ | |||
| 85 | /* A TimeUnit is 1024 microsecond */ | 87 | /* A TimeUnit is 1024 microsecond */ |
| 86 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 88 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
| 87 | 89 | ||
| 88 | /* | 90 | /* For GO, this value represents the number of TUs before CSA "beacon |
| 89 | * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" | 91 | * 0" TBTT when the CSA time-event needs to be scheduled to start. It |
| 90 | * TBTT. This value should be big enough to ensure that we switch in time. | 92 | * must be big enough to ensure that we switch in time. |
| 93 | */ | ||
| 94 | #define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 | ||
| 95 | |||
| 96 | /* For client, this value represents the number of TUs before CSA | ||
| 97 | * "beacon 1" TBTT, instead. This is because we don't know when the | ||
| 98 | * GO/AP will be in the new channel, so we switch early enough. | ||
| 91 | */ | 99 | */ |
| 92 | #define IWL_MVM_CHANNEL_SWITCH_TIME 40 | 100 | #define IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT 10 |
| 93 | 101 | ||
| 94 | /* | 102 | /* |
| 95 | * This value (in TUs) is used to fine tune the CSA NoA end time which should | 103 | * This value (in TUs) is used to fine tune the CSA NoA end time which should |
| @@ -103,14 +111,6 @@ | |||
| 103 | */ | 111 | */ |
| 104 | #define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3 | 112 | #define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3 |
| 105 | 113 | ||
| 106 | enum iwl_mvm_tx_fifo { | ||
| 107 | IWL_MVM_TX_FIFO_BK = 0, | ||
| 108 | IWL_MVM_TX_FIFO_BE, | ||
| 109 | IWL_MVM_TX_FIFO_VI, | ||
| 110 | IWL_MVM_TX_FIFO_VO, | ||
| 111 | IWL_MVM_TX_FIFO_MCAST = 5, | ||
| 112 | }; | ||
| 113 | |||
| 114 | extern const struct ieee80211_ops iwl_mvm_hw_ops; | 114 | extern const struct ieee80211_ops iwl_mvm_hw_ops; |
| 115 | 115 | ||
| 116 | /** | 116 | /** |
| @@ -186,10 +186,6 @@ enum iwl_power_scheme { | |||
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | #define IWL_CONN_MAX_LISTEN_INTERVAL 10 | 188 | #define IWL_CONN_MAX_LISTEN_INTERVAL 10 |
| 189 | #define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ | ||
| 190 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ | ||
| 191 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ | ||
| 192 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
| 193 | #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 | 189 | #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 |
| 194 | 190 | ||
| 195 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 191 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| @@ -203,6 +199,7 @@ enum iwl_dbgfs_pm_mask { | |||
| 203 | MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), | 199 | MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), |
| 204 | MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), | 200 | MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), |
| 205 | MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9), | 201 | MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9), |
| 202 | MVM_DEBUGFS_PM_USE_PS_POLL = BIT(10), | ||
| 206 | }; | 203 | }; |
| 207 | 204 | ||
| 208 | struct iwl_dbgfs_pm { | 205 | struct iwl_dbgfs_pm { |
| @@ -215,6 +212,7 @@ struct iwl_dbgfs_pm { | |||
| 215 | u32 lprx_rssi_threshold; | 212 | u32 lprx_rssi_threshold; |
| 216 | bool snooze_ena; | 213 | bool snooze_ena; |
| 217 | bool uapsd_misbehaving; | 214 | bool uapsd_misbehaving; |
| 215 | bool use_ps_poll; | ||
| 218 | int mask; | 216 | int mask; |
| 219 | }; | 217 | }; |
| 220 | 218 | ||
| @@ -253,6 +251,7 @@ struct iwl_dbgfs_bf { | |||
| 253 | enum iwl_mvm_smps_type_request { | 251 | enum iwl_mvm_smps_type_request { |
| 254 | IWL_MVM_SMPS_REQ_BT_COEX, | 252 | IWL_MVM_SMPS_REQ_BT_COEX, |
| 255 | IWL_MVM_SMPS_REQ_TT, | 253 | IWL_MVM_SMPS_REQ_TT, |
| 254 | IWL_MVM_SMPS_REQ_PROT, | ||
| 256 | NUM_IWL_MVM_SMPS_REQ, | 255 | NUM_IWL_MVM_SMPS_REQ, |
| 257 | }; | 256 | }; |
| 258 | 257 | ||
| @@ -276,6 +275,9 @@ enum iwl_mvm_ref_type { | |||
| 276 | IWL_MVM_REF_NMI, | 275 | IWL_MVM_REF_NMI, |
| 277 | IWL_MVM_REF_TM_CMD, | 276 | IWL_MVM_REF_TM_CMD, |
| 278 | IWL_MVM_REF_EXIT_WORK, | 277 | IWL_MVM_REF_EXIT_WORK, |
| 278 | IWL_MVM_REF_PROTECT_CSA, | ||
| 279 | |||
| 280 | /* update debugfs.c when changing this */ | ||
| 279 | 281 | ||
| 280 | IWL_MVM_REF_COUNT, | 282 | IWL_MVM_REF_COUNT, |
| 281 | }; | 283 | }; |
| @@ -293,7 +295,6 @@ enum iwl_bt_force_ant_mode { | |||
| 293 | * struct iwl_mvm_vif_bf_data - beacon filtering related data | 295 | * struct iwl_mvm_vif_bf_data - beacon filtering related data |
| 294 | * @bf_enabled: indicates if beacon filtering is enabled | 296 | * @bf_enabled: indicates if beacon filtering is enabled |
| 295 | * @ba_enabled: indicated if beacon abort is enabled | 297 | * @ba_enabled: indicated if beacon abort is enabled |
| 296 | * @last_beacon_signal: last beacon rssi signal in dbm | ||
| 297 | * @ave_beacon_signal: average beacon signal | 298 | * @ave_beacon_signal: average beacon signal |
| 298 | * @last_cqm_event: rssi of the last cqm event | 299 | * @last_cqm_event: rssi of the last cqm event |
| 299 | * @bt_coex_min_thold: minimum threshold for BT coex | 300 | * @bt_coex_min_thold: minimum threshold for BT coex |
| @@ -315,6 +316,9 @@ struct iwl_mvm_vif_bf_data { | |||
| 315 | * @id: between 0 and 3 | 316 | * @id: between 0 and 3 |
| 316 | * @color: to solve races upon MAC addition and removal | 317 | * @color: to solve races upon MAC addition and removal |
| 317 | * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA | 318 | * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA |
| 319 | * @bssid: BSSID for this (client) interface | ||
| 320 | * @associated: indicates that we're currently associated, used only for | ||
| 321 | * managing the firmware state in iwl_mvm_bss_info_changed_station() | ||
| 318 | * @uploaded: indicates the MAC context has been added to the device | 322 | * @uploaded: indicates the MAC context has been added to the device |
| 319 | * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface | 323 | * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface |
| 320 | * should get quota etc. | 324 | * should get quota etc. |
| @@ -323,6 +327,7 @@ struct iwl_mvm_vif_bf_data { | |||
| 323 | * interface should get quota etc. | 327 | * interface should get quota etc. |
| 324 | * @low_latency: indicates that this interface is in low-latency mode | 328 | * @low_latency: indicates that this interface is in low-latency mode |
| 325 | * (VMACLowLatencyMode) | 329 | * (VMACLowLatencyMode) |
| 330 | * @ps_disabled: indicates that this interface requires PS to be disabled | ||
| 326 | * @queue_params: QoS params for this MAC | 331 | * @queue_params: QoS params for this MAC |
| 327 | * @bcast_sta: station used for broadcast packets. Used by the following | 332 | * @bcast_sta: station used for broadcast packets. Used by the following |
| 328 | * vifs: P2P_DEVICE, GO and AP. | 333 | * vifs: P2P_DEVICE, GO and AP. |
| @@ -335,11 +340,15 @@ struct iwl_mvm_vif { | |||
| 335 | u16 color; | 340 | u16 color; |
| 336 | u8 ap_sta_id; | 341 | u8 ap_sta_id; |
| 337 | 342 | ||
| 343 | u8 bssid[ETH_ALEN]; | ||
| 344 | bool associated; | ||
| 345 | |||
| 338 | bool uploaded; | 346 | bool uploaded; |
| 339 | bool ap_ibss_active; | 347 | bool ap_ibss_active; |
| 340 | bool pm_enabled; | 348 | bool pm_enabled; |
| 341 | bool monitor_active; | 349 | bool monitor_active; |
| 342 | bool low_latency; | 350 | bool low_latency; |
| 351 | bool ps_disabled; | ||
| 343 | struct iwl_mvm_vif_bf_data bf_data; | 352 | struct iwl_mvm_vif_bf_data bf_data; |
| 344 | 353 | ||
| 345 | u32 ap_beacon_time; | 354 | u32 ap_beacon_time; |
| @@ -396,6 +405,9 @@ struct iwl_mvm_vif { | |||
| 396 | 405 | ||
| 397 | /* FW identified misbehaving AP */ | 406 | /* FW identified misbehaving AP */ |
| 398 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; | 407 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; |
| 408 | |||
| 409 | /* Indicates that CSA countdown may be started */ | ||
| 410 | bool csa_countdown; | ||
| 399 | }; | 411 | }; |
| 400 | 412 | ||
| 401 | static inline struct iwl_mvm_vif * | 413 | static inline struct iwl_mvm_vif * |
| @@ -512,6 +524,17 @@ enum { | |||
| 512 | D0I3_PENDING_WAKEUP, | 524 | D0I3_PENDING_WAKEUP, |
| 513 | }; | 525 | }; |
| 514 | 526 | ||
| 527 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE 0xff | ||
| 528 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100 | ||
| 529 | #define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200 | ||
| 530 | |||
| 531 | enum iwl_mvm_tdls_cs_state { | ||
| 532 | IWL_MVM_TDLS_SW_IDLE = 0, | ||
| 533 | IWL_MVM_TDLS_SW_REQ_SENT, | ||
| 534 | IWL_MVM_TDLS_SW_REQ_RCVD, | ||
| 535 | IWL_MVM_TDLS_SW_ACTIVE, | ||
| 536 | }; | ||
| 537 | |||
| 515 | struct iwl_mvm { | 538 | struct iwl_mvm { |
| 516 | /* for logger access */ | 539 | /* for logger access */ |
| 517 | struct device *dev; | 540 | struct device *dev; |
| @@ -541,6 +564,7 @@ struct iwl_mvm { | |||
| 541 | enum iwl_ucode_type cur_ucode; | 564 | enum iwl_ucode_type cur_ucode; |
| 542 | bool ucode_loaded; | 565 | bool ucode_loaded; |
| 543 | bool init_ucode_complete; | 566 | bool init_ucode_complete; |
| 567 | bool calibrating; | ||
| 544 | u32 error_event_table; | 568 | u32 error_event_table; |
| 545 | u32 log_event_table; | 569 | u32 log_event_table; |
| 546 | u32 umac_error_event_table; | 570 | u32 umac_error_event_table; |
| @@ -553,9 +577,8 @@ struct iwl_mvm { | |||
| 553 | 577 | ||
| 554 | struct mvm_statistics_rx rx_stats; | 578 | struct mvm_statistics_rx rx_stats; |
| 555 | 579 | ||
| 556 | unsigned long transport_queue_stop; | ||
| 557 | u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; | 580 | u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; |
| 558 | atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; | 581 | atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; |
| 559 | 582 | ||
| 560 | const char *nvm_file_name; | 583 | const char *nvm_file_name; |
| 561 | struct iwl_nvm_data *nvm_data; | 584 | struct iwl_nvm_data *nvm_data; |
| @@ -571,6 +594,7 @@ struct iwl_mvm { | |||
| 571 | struct work_struct sta_drained_wk; | 594 | struct work_struct sta_drained_wk; |
| 572 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; | 595 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; |
| 573 | atomic_t pending_frames[IWL_MVM_STATION_COUNT]; | 596 | atomic_t pending_frames[IWL_MVM_STATION_COUNT]; |
| 597 | u32 tfd_drained[IWL_MVM_STATION_COUNT]; | ||
| 574 | u8 rx_ba_sessions; | 598 | u8 rx_ba_sessions; |
| 575 | 599 | ||
| 576 | /* configured by mac80211 */ | 600 | /* configured by mac80211 */ |
| @@ -581,6 +605,10 @@ struct iwl_mvm { | |||
| 581 | void *scan_cmd; | 605 | void *scan_cmd; |
| 582 | struct iwl_mcast_filter_cmd *mcast_filter_cmd; | 606 | struct iwl_mcast_filter_cmd *mcast_filter_cmd; |
| 583 | 607 | ||
| 608 | /* UMAC scan tracking */ | ||
| 609 | u32 scan_uid[IWL_MVM_MAX_SIMULTANEOUS_SCANS]; | ||
| 610 | u8 scan_seq_num, sched_scan_seq_num; | ||
| 611 | |||
| 584 | /* rx chain antennas set through debugfs for the scan command */ | 612 | /* rx chain antennas set through debugfs for the scan command */ |
| 585 | u8 scan_rx_ant; | 613 | u8 scan_rx_ant; |
| 586 | 614 | ||
| @@ -641,7 +669,8 @@ struct iwl_mvm { | |||
| 641 | 669 | ||
| 642 | /* -1 for always, 0 for never, >0 for that many times */ | 670 | /* -1 for always, 0 for never, >0 for that many times */ |
| 643 | s8 restart_fw; | 671 | s8 restart_fw; |
| 644 | struct iwl_mvm_dump_ptrs *fw_error_dump; | 672 | struct work_struct fw_error_dump_wk; |
| 673 | enum iwl_fw_dbg_conf fw_dbg_conf; | ||
| 645 | 674 | ||
| 646 | #ifdef CONFIG_IWLWIFI_LEDS | 675 | #ifdef CONFIG_IWLWIFI_LEDS |
| 647 | struct led_classdev led; | 676 | struct led_classdev led; |
| @@ -652,6 +681,15 @@ struct iwl_mvm { | |||
| 652 | #ifdef CONFIG_PM_SLEEP | 681 | #ifdef CONFIG_PM_SLEEP |
| 653 | struct wiphy_wowlan_support wowlan; | 682 | struct wiphy_wowlan_support wowlan; |
| 654 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; | 683 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; |
| 684 | |||
| 685 | /* sched scan settings for net detect */ | ||
| 686 | struct cfg80211_sched_scan_request *nd_config; | ||
| 687 | struct ieee80211_scan_ies nd_ies; | ||
| 688 | struct cfg80211_match_set *nd_match_sets; | ||
| 689 | int n_nd_match_sets; | ||
| 690 | struct ieee80211_channel **nd_channels; | ||
| 691 | int n_nd_channels; | ||
| 692 | bool net_detect; | ||
| 655 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 693 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| 656 | u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ | 694 | u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ |
| 657 | bool d3_test_active; | 695 | bool d3_test_active; |
| @@ -694,6 +732,14 @@ struct iwl_mvm { | |||
| 694 | /* Thermal Throttling and CTkill */ | 732 | /* Thermal Throttling and CTkill */ |
| 695 | struct iwl_mvm_tt_mgmt thermal_throttle; | 733 | struct iwl_mvm_tt_mgmt thermal_throttle; |
| 696 | s32 temperature; /* Celsius */ | 734 | s32 temperature; /* Celsius */ |
| 735 | /* | ||
| 736 | * Debug option to set the NIC temperature. This option makes the | ||
| 737 | * driver think this is the actual NIC temperature, and ignore the | ||
| 738 | * real temperature that is received from the fw | ||
| 739 | */ | ||
| 740 | bool temperature_test; /* Debug test temperature is enabled */ | ||
| 741 | |||
| 742 | struct iwl_time_quota_cmd last_quota_cmd; | ||
| 697 | 743 | ||
| 698 | #ifdef CONFIG_NL80211_TESTMODE | 744 | #ifdef CONFIG_NL80211_TESTMODE |
| 699 | u32 noa_duration; | 745 | u32 noa_duration; |
| @@ -706,7 +752,7 @@ struct iwl_mvm { | |||
| 706 | u8 last_agg_queue; | 752 | u8 last_agg_queue; |
| 707 | 753 | ||
| 708 | /* Indicate if device power save is allowed */ | 754 | /* Indicate if device power save is allowed */ |
| 709 | bool ps_disabled; | 755 | u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */ |
| 710 | 756 | ||
| 711 | struct ieee80211_vif __rcu *csa_vif; | 757 | struct ieee80211_vif __rcu *csa_vif; |
| 712 | struct ieee80211_vif __rcu *csa_tx_blocked_vif; | 758 | struct ieee80211_vif __rcu *csa_tx_blocked_vif; |
| @@ -714,6 +760,30 @@ struct iwl_mvm { | |||
| 714 | 760 | ||
| 715 | /* system time of last beacon (for AP/GO interface) */ | 761 | /* system time of last beacon (for AP/GO interface) */ |
| 716 | u32 ap_last_beacon_gp2; | 762 | u32 ap_last_beacon_gp2; |
| 763 | |||
| 764 | u8 low_latency_agg_frame_limit; | ||
| 765 | |||
| 766 | /* TDLS channel switch data */ | ||
| 767 | struct { | ||
| 768 | struct delayed_work dwork; | ||
| 769 | enum iwl_mvm_tdls_cs_state state; | ||
| 770 | |||
| 771 | /* | ||
| 772 | * Current cs sta - might be different from periodic cs peer | ||
| 773 | * station. Value is meaningless when the cs-state is idle. | ||
| 774 | */ | ||
| 775 | u8 cur_sta_id; | ||
| 776 | |||
| 777 | /* TDLS periodic channel-switch peer */ | ||
| 778 | struct { | ||
| 779 | u8 sta_id; | ||
| 780 | u8 op_class; | ||
| 781 | bool initiator; /* are we the link initiator */ | ||
| 782 | struct cfg80211_chan_def chandef; | ||
| 783 | struct sk_buff *skb; /* ch sw template */ | ||
| 784 | u32 ch_sw_tm_ie; | ||
| 785 | } peer; | ||
| 786 | } tdls_cs; | ||
| 717 | }; | 787 | }; |
| 718 | 788 | ||
| 719 | /* Extract MVM priv from op_mode and _hw */ | 789 | /* Extract MVM priv from op_mode and _hw */ |
| @@ -730,6 +800,7 @@ enum iwl_mvm_status { | |||
| 730 | IWL_MVM_STATUS_IN_HW_RESTART, | 800 | IWL_MVM_STATUS_IN_HW_RESTART, |
| 731 | IWL_MVM_STATUS_IN_D0I3, | 801 | IWL_MVM_STATUS_IN_D0I3, |
| 732 | IWL_MVM_STATUS_ROC_AUX_RUNNING, | 802 | IWL_MVM_STATUS_ROC_AUX_RUNNING, |
| 803 | IWL_MVM_STATUS_D3_RECONFIG, | ||
| 733 | }; | 804 | }; |
| 734 | 805 | ||
| 735 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | 806 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) |
| @@ -738,6 +809,26 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | |||
| 738 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | 809 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); |
| 739 | } | 810 | } |
| 740 | 811 | ||
| 812 | /* Must be called with rcu_read_lock() held and it can only be | ||
| 813 | * released when mvmsta is not needed anymore. | ||
| 814 | */ | ||
| 815 | static inline struct iwl_mvm_sta * | ||
| 816 | iwl_mvm_sta_from_staid_rcu(struct iwl_mvm *mvm, u8 sta_id) | ||
| 817 | { | ||
| 818 | struct ieee80211_sta *sta; | ||
| 819 | |||
| 820 | if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) | ||
| 821 | return NULL; | ||
| 822 | |||
| 823 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
| 824 | |||
| 825 | /* This can happen if the station has been removed right now */ | ||
| 826 | if (IS_ERR_OR_NULL(sta)) | ||
| 827 | return NULL; | ||
| 828 | |||
| 829 | return iwl_mvm_sta_from_mac80211(sta); | ||
| 830 | } | ||
| 831 | |||
| 741 | static inline struct iwl_mvm_sta * | 832 | static inline struct iwl_mvm_sta * |
| 742 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) | 833 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) |
| 743 | { | 834 | { |
| @@ -762,6 +853,11 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) | |||
| 762 | (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); | 853 | (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); |
| 763 | } | 854 | } |
| 764 | 855 | ||
| 856 | static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm) | ||
| 857 | { | ||
| 858 | return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT; | ||
| 859 | } | ||
| 860 | |||
| 765 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | 861 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; |
| 766 | 862 | ||
| 767 | struct iwl_rate_info { | 863 | struct iwl_rate_info { |
| @@ -772,6 +868,9 @@ struct iwl_rate_info { | |||
| 772 | u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ | 868 | u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ |
| 773 | }; | 869 | }; |
| 774 | 870 | ||
| 871 | void __iwl_mvm_mac_stop(struct iwl_mvm *mvm); | ||
| 872 | int __iwl_mvm_mac_start(struct iwl_mvm *mvm); | ||
| 873 | |||
| 775 | /****************** | 874 | /****************** |
| 776 | * MVM Methods | 875 | * MVM Methods |
| 777 | ******************/ | 876 | ******************/ |
| @@ -803,6 +902,16 @@ int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, | |||
| 803 | int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | 902 | int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, |
| 804 | struct ieee80211_sta *sta); | 903 | struct ieee80211_sta *sta); |
| 805 | int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); | 904 | int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); |
| 905 | void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | ||
| 906 | struct iwl_tx_cmd *tx_cmd, | ||
| 907 | struct ieee80211_tx_info *info, u8 sta_id); | ||
| 908 | void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, | ||
| 909 | struct ieee80211_tx_info *info, | ||
| 910 | struct iwl_tx_cmd *tx_cmd, | ||
| 911 | struct sk_buff *skb_frag); | ||
| 912 | void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, | ||
| 913 | struct ieee80211_tx_info *info, | ||
| 914 | struct ieee80211_sta *sta, __le16 fc); | ||
| 806 | #ifdef CONFIG_IWLWIFI_DEBUG | 915 | #ifdef CONFIG_IWLWIFI_DEBUG |
| 807 | const char *iwl_mvm_get_tx_fail_reason(u32 status); | 916 | const char *iwl_mvm_get_tx_fail_reason(u32 status); |
| 808 | #else | 917 | #else |
| @@ -859,6 +968,8 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | |||
| 859 | struct iwl_device_cmd *cmd); | 968 | struct iwl_device_cmd *cmd); |
| 860 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 969 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
| 861 | struct iwl_device_cmd *cmd); | 970 | struct iwl_device_cmd *cmd); |
| 971 | int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
| 972 | struct iwl_device_cmd *cmd); | ||
| 862 | 973 | ||
| 863 | /* MVM PHY */ | 974 | /* MVM PHY */ |
| 864 | int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | 975 | int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, |
| @@ -872,16 +983,17 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, | |||
| 872 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, | 983 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, |
| 873 | struct iwl_mvm_phy_ctxt *ctxt); | 984 | struct iwl_mvm_phy_ctxt *ctxt); |
| 874 | int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); | 985 | int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); |
| 986 | u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef); | ||
| 987 | u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); | ||
| 875 | 988 | ||
| 876 | /* MAC (virtual interface) programming */ | 989 | /* MAC (virtual interface) programming */ |
| 877 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 990 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 878 | void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 991 | void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 879 | int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 992 | int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 880 | int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 993 | int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 881 | bool force_assoc_off); | 994 | bool force_assoc_off, const u8 *bssid_override); |
| 882 | int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 995 | int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 883 | u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | 996 | u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif); |
| 884 | struct ieee80211_vif *vif); | ||
| 885 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | 997 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, |
| 886 | struct ieee80211_vif *vif); | 998 | struct ieee80211_vif *vif); |
| 887 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | 999 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, |
| @@ -892,6 +1004,8 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | |||
| 892 | struct iwl_device_cmd *cmd); | 1004 | struct iwl_device_cmd *cmd); |
| 893 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, | 1005 | void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, |
| 894 | struct ieee80211_vif *vif); | 1006 | struct ieee80211_vif *vif); |
| 1007 | unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, | ||
| 1008 | struct ieee80211_vif *exclude_vif); | ||
| 895 | 1009 | ||
| 896 | /* Bindings */ | 1010 | /* Bindings */ |
| 897 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 1011 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| @@ -902,6 +1016,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
| 902 | struct ieee80211_vif *disabled_vif); | 1016 | struct ieee80211_vif *disabled_vif); |
| 903 | 1017 | ||
| 904 | /* Scanning */ | 1018 | /* Scanning */ |
| 1019 | int iwl_mvm_scan_size(struct iwl_mvm *mvm); | ||
| 905 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | 1020 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, |
| 906 | struct ieee80211_vif *vif, | 1021 | struct ieee80211_vif *vif, |
| 907 | struct cfg80211_scan_request *req); | 1022 | struct cfg80211_scan_request *req); |
| @@ -910,6 +1025,7 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 910 | int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 1025 | int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
| 911 | struct iwl_device_cmd *cmd); | 1026 | struct iwl_device_cmd *cmd); |
| 912 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm); | 1027 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm); |
| 1028 | int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan); | ||
| 913 | 1029 | ||
| 914 | /* Scheduled scan */ | 1030 | /* Scheduled scan */ |
| 915 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | 1031 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, |
| @@ -923,6 +1039,10 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, | |||
| 923 | struct cfg80211_sched_scan_request *req); | 1039 | struct cfg80211_sched_scan_request *req); |
| 924 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 1040 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
| 925 | struct cfg80211_sched_scan_request *req); | 1041 | struct cfg80211_sched_scan_request *req); |
| 1042 | int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm, | ||
| 1043 | struct ieee80211_vif *vif, | ||
| 1044 | struct cfg80211_sched_scan_request *req, | ||
| 1045 | struct ieee80211_scan_ies *ies); | ||
| 926 | int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify); | 1046 | int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify); |
| 927 | int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, | 1047 | int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, |
| 928 | struct iwl_rx_cmd_buffer *rxb, | 1048 | struct iwl_rx_cmd_buffer *rxb, |
| @@ -937,6 +1057,17 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 937 | struct cfg80211_sched_scan_request *req, | 1057 | struct cfg80211_sched_scan_request *req, |
| 938 | struct ieee80211_scan_ies *ies); | 1058 | struct ieee80211_scan_ies *ies); |
| 939 | 1059 | ||
| 1060 | /* UMAC scan */ | ||
| 1061 | int iwl_mvm_config_scan(struct iwl_mvm *mvm); | ||
| 1062 | int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
| 1063 | struct ieee80211_scan_request *req); | ||
| 1064 | int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
| 1065 | struct cfg80211_sched_scan_request *req, | ||
| 1066 | struct ieee80211_scan_ies *ies); | ||
| 1067 | int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | ||
| 1068 | struct iwl_rx_cmd_buffer *rxb, | ||
| 1069 | struct iwl_device_cmd *cmd); | ||
| 1070 | |||
| 940 | /* MVM debugfs */ | 1071 | /* MVM debugfs */ |
| 941 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1072 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| 942 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); | 1073 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); |
| @@ -964,10 +1095,14 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, | |||
| 964 | struct iwl_mvm_frame_stats *stats, | 1095 | struct iwl_mvm_frame_stats *stats, |
| 965 | u32 rate, bool agg); | 1096 | u32 rate, bool agg); |
| 966 | int rs_pretty_print_rate(char *buf, const u32 rate); | 1097 | int rs_pretty_print_rate(char *buf, const u32 rate); |
| 1098 | void rs_update_last_rssi(struct iwl_mvm *mvm, | ||
| 1099 | struct iwl_lq_sta *lq_sta, | ||
| 1100 | struct ieee80211_rx_status *rx_status); | ||
| 967 | 1101 | ||
| 968 | /* power management */ | 1102 | /* power management */ |
| 969 | int iwl_mvm_power_update_device(struct iwl_mvm *mvm); | 1103 | int iwl_mvm_power_update_device(struct iwl_mvm *mvm); |
| 970 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm); | 1104 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm); |
| 1105 | int iwl_mvm_power_update_ps(struct iwl_mvm *mvm); | ||
| 971 | int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1106 | int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 972 | char *buf, int bufsz); | 1107 | char *buf, int bufsz); |
| 973 | 1108 | ||
| @@ -1012,7 +1147,7 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
| 1012 | } | 1147 | } |
| 1013 | #endif | 1148 | #endif |
| 1014 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, | 1149 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, |
| 1015 | struct iwl_wowlan_config_cmd_v2 *cmd); | 1150 | struct iwl_wowlan_config_cmd *cmd); |
| 1016 | int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | 1151 | int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, |
| 1017 | struct ieee80211_vif *vif, | 1152 | struct ieee80211_vif *vif, |
| 1018 | bool disable_offloading, | 1153 | bool disable_offloading, |
| @@ -1022,6 +1157,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
| 1022 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1157 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
| 1023 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1158 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
| 1024 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1159 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
| 1160 | bool iwl_mvm_ref_taken(struct iwl_mvm *mvm); | ||
| 1025 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); | 1161 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); |
| 1026 | int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); | 1162 | int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); |
| 1027 | 1163 | ||
| @@ -1037,12 +1173,14 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, | |||
| 1037 | struct ieee80211_sta *sta); | 1173 | struct ieee80211_sta *sta); |
| 1038 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | 1174 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, |
| 1039 | struct ieee80211_sta *sta); | 1175 | struct ieee80211_sta *sta); |
| 1176 | bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant); | ||
| 1040 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm); | 1177 | bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm); |
| 1041 | bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, | 1178 | bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, |
| 1042 | enum ieee80211_band band); | 1179 | enum ieee80211_band band); |
| 1043 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, | 1180 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, |
| 1044 | struct ieee80211_tx_info *info, u8 ac); | 1181 | struct ieee80211_tx_info *info, u8 ac); |
| 1045 | 1182 | ||
| 1183 | bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant); | ||
| 1046 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); | 1184 | bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); |
| 1047 | void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); | 1185 | void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); |
| 1048 | int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); | 1186 | int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); |
| @@ -1120,23 +1258,90 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) | |||
| 1120 | return mvmvif->low_latency; | 1258 | return mvmvif->low_latency; |
| 1121 | } | 1259 | } |
| 1122 | 1260 | ||
| 1261 | /* hw scheduler queue config */ | ||
| 1262 | void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, | ||
| 1263 | const struct iwl_trans_txq_scd_cfg *cfg); | ||
| 1264 | void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue); | ||
| 1265 | |||
| 1266 | static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, | ||
| 1267 | u8 fifo) | ||
| 1268 | { | ||
| 1269 | struct iwl_trans_txq_scd_cfg cfg = { | ||
| 1270 | .fifo = fifo, | ||
| 1271 | .tid = IWL_MAX_TID_COUNT, | ||
| 1272 | .aggregate = false, | ||
| 1273 | .frame_limit = IWL_FRAME_LIMIT, | ||
| 1274 | }; | ||
| 1275 | |||
| 1276 | iwl_mvm_enable_txq(mvm, queue, 0, &cfg); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, | ||
| 1280 | int fifo, int sta_id, int tid, | ||
| 1281 | int frame_limit, u16 ssn) | ||
| 1282 | { | ||
| 1283 | struct iwl_trans_txq_scd_cfg cfg = { | ||
| 1284 | .fifo = fifo, | ||
| 1285 | .sta_id = sta_id, | ||
| 1286 | .tid = tid, | ||
| 1287 | .frame_limit = frame_limit, | ||
| 1288 | .aggregate = true, | ||
| 1289 | }; | ||
| 1290 | |||
| 1291 | iwl_mvm_enable_txq(mvm, queue, ssn, &cfg); | ||
| 1292 | } | ||
| 1293 | |||
| 1123 | /* Assoc status */ | 1294 | /* Assoc status */ |
| 1124 | bool iwl_mvm_is_idle(struct iwl_mvm *mvm); | 1295 | bool iwl_mvm_is_idle(struct iwl_mvm *mvm); |
| 1125 | 1296 | ||
| 1126 | /* Thermal management and CT-kill */ | 1297 | /* Thermal management and CT-kill */ |
| 1127 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); | 1298 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); |
| 1299 | void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); | ||
| 1300 | int iwl_mvm_temp_notif(struct iwl_mvm *mvm, | ||
| 1301 | struct iwl_rx_cmd_buffer *rxb, | ||
| 1302 | struct iwl_device_cmd *cmd); | ||
| 1128 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); | 1303 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); |
| 1129 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); | 1304 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); |
| 1130 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); | 1305 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); |
| 1131 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); | 1306 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); |
| 1307 | int iwl_mvm_get_temp(struct iwl_mvm *mvm); | ||
| 1132 | 1308 | ||
| 1133 | /* smart fifo */ | 1309 | /* smart fifo */ |
| 1134 | int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1310 | int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 1135 | bool added_vif); | 1311 | bool added_vif); |
| 1136 | 1312 | ||
| 1137 | /* TDLS */ | 1313 | /* TDLS */ |
| 1314 | |||
| 1315 | /* | ||
| 1316 | * We use TID 4 (VI) as a FW-used-only TID when TDLS connections are present. | ||
| 1317 | * This TID is marked as used vs the AP and all connected TDLS peers. | ||
| 1318 | */ | ||
| 1319 | #define IWL_MVM_TDLS_FW_TID 4 | ||
| 1320 | |||
| 1138 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 1321 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 1322 | void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm); | ||
| 1323 | void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
| 1324 | bool sta_added); | ||
| 1325 | void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | ||
| 1326 | struct ieee80211_vif *vif); | ||
| 1327 | int iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, | ||
| 1328 | struct ieee80211_vif *vif, | ||
| 1329 | struct ieee80211_sta *sta, u8 oper_class, | ||
| 1330 | struct cfg80211_chan_def *chandef, | ||
| 1331 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie); | ||
| 1332 | void iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, | ||
| 1333 | struct ieee80211_vif *vif, | ||
| 1334 | struct ieee80211_tdls_ch_sw_params *params); | ||
| 1335 | void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, | ||
| 1336 | struct ieee80211_vif *vif, | ||
| 1337 | struct ieee80211_sta *sta); | ||
| 1338 | int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
| 1339 | struct iwl_device_cmd *cmd); | ||
| 1340 | void iwl_mvm_tdls_ch_switch_work(struct work_struct *work); | ||
| 1341 | |||
| 1342 | struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); | ||
| 1139 | 1343 | ||
| 1140 | void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); | 1344 | void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); |
| 1345 | void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); | ||
| 1141 | 1346 | ||
| 1142 | #endif /* __IWL_MVM_H__ */ | 1347 | #endif /* __IWL_MVM_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index cfdd314fdd5d..d55fd8e3654c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -62,6 +64,7 @@ | |||
| 62 | *****************************************************************************/ | 64 | *****************************************************************************/ |
| 63 | #include <linux/firmware.h> | 65 | #include <linux/firmware.h> |
| 64 | #include "iwl-trans.h" | 66 | #include "iwl-trans.h" |
| 67 | #include "iwl-csr.h" | ||
| 65 | #include "mvm.h" | 68 | #include "mvm.h" |
| 66 | #include "iwl-eeprom-parse.h" | 69 | #include "iwl-eeprom-parse.h" |
| 67 | #include "iwl-eeprom-read.h" | 70 | #include "iwl-eeprom-read.h" |
| @@ -336,18 +339,22 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
| 336 | } *file_sec; | 339 | } *file_sec; |
| 337 | const u8 *eof, *temp; | 340 | const u8 *eof, *temp; |
| 338 | int max_section_size; | 341 | int max_section_size; |
| 342 | const __le32 *dword_buff; | ||
| 339 | 343 | ||
| 340 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) | 344 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) |
| 341 | #define NVM_WORD2_ID(x) (x >> 12) | 345 | #define NVM_WORD2_ID(x) (x >> 12) |
| 342 | #define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) | 346 | #define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) |
| 343 | #define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) | 347 | #define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) |
| 348 | #define NVM_HEADER_0 (0x2A504C54) | ||
| 349 | #define NVM_HEADER_1 (0x4E564D2A) | ||
| 350 | #define NVM_HEADER_SIZE (4 * sizeof(u32)) | ||
| 344 | 351 | ||
| 345 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); | 352 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); |
| 346 | 353 | ||
| 347 | /* Maximal size depends on HW family and step */ | 354 | /* Maximal size depends on HW family and step */ |
| 348 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) | 355 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) |
| 349 | max_section_size = IWL_MAX_NVM_SECTION_SIZE; | 356 | max_section_size = IWL_MAX_NVM_SECTION_SIZE; |
| 350 | else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */ | 357 | else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) |
| 351 | max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; | 358 | max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; |
| 352 | else /* Family 8000 B-step */ | 359 | else /* Family 8000 B-step */ |
| 353 | max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; | 360 | max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; |
| @@ -369,12 +376,6 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
| 369 | IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", | 376 | IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", |
| 370 | mvm->nvm_file_name, fw_entry->size); | 377 | mvm->nvm_file_name, fw_entry->size); |
| 371 | 378 | ||
| 372 | if (fw_entry->size < sizeof(*file_sec)) { | ||
| 373 | IWL_ERR(mvm, "NVM file too small\n"); | ||
| 374 | ret = -EINVAL; | ||
| 375 | goto out; | ||
| 376 | } | ||
| 377 | |||
| 378 | if (fw_entry->size > MAX_NVM_FILE_LEN) { | 379 | if (fw_entry->size > MAX_NVM_FILE_LEN) { |
| 379 | IWL_ERR(mvm, "NVM file too large\n"); | 380 | IWL_ERR(mvm, "NVM file too large\n"); |
| 380 | ret = -EINVAL; | 381 | ret = -EINVAL; |
| @@ -382,8 +383,25 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
| 382 | } | 383 | } |
| 383 | 384 | ||
| 384 | eof = fw_entry->data + fw_entry->size; | 385 | eof = fw_entry->data + fw_entry->size; |
| 385 | 386 | dword_buff = (__le32 *)fw_entry->data; | |
| 386 | file_sec = (void *)fw_entry->data; | 387 | |
| 388 | /* some NVM file will contain a header. | ||
| 389 | * The header is identified by 2 dwords header as follow: | ||
| 390 | * dword[0] = 0x2A504C54 | ||
| 391 | * dword[1] = 0x4E564D2A | ||
| 392 | * | ||
| 393 | * This header must be skipped when providing the NVM data to the FW. | ||
| 394 | */ | ||
| 395 | if (fw_entry->size > NVM_HEADER_SIZE && | ||
| 396 | dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && | ||
| 397 | dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { | ||
| 398 | file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE); | ||
| 399 | IWL_INFO(mvm, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); | ||
| 400 | IWL_INFO(mvm, "NVM Manufacturing date %08X\n", | ||
| 401 | le32_to_cpu(dword_buff[3])); | ||
| 402 | } else { | ||
| 403 | file_sec = (void *)fw_entry->data; | ||
| 404 | } | ||
| 387 | 405 | ||
| 388 | while (true) { | 406 | while (true) { |
| 389 | if (file_sec->data > eof) { | 407 | if (file_sec->data > eof) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c index 9bfb95e89cfb..68b0169c8892 100644 --- a/drivers/net/wireless/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -65,7 +67,7 @@ | |||
| 65 | #include "mvm.h" | 67 | #include "mvm.h" |
| 66 | 68 | ||
| 67 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, | 69 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, |
| 68 | struct iwl_wowlan_config_cmd_v2 *cmd) | 70 | struct iwl_wowlan_config_cmd *cmd) |
| 69 | { | 71 | { |
| 70 | int i; | 72 | int i; |
| 71 | 73 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 610dbcb0dc27..97dfba50c682 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -242,6 +244,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
| 242 | iwl_mvm_rx_scan_offload_complete_notif, true), | 244 | iwl_mvm_rx_scan_offload_complete_notif, true), |
| 243 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, | 245 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, |
| 244 | false), | 246 | false), |
| 247 | RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif, | ||
| 248 | true), | ||
| 245 | 249 | ||
| 246 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 250 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
| 247 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 251 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
| @@ -252,6 +256,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
| 252 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), | 256 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), |
| 253 | RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, | 257 | RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, |
| 254 | iwl_mvm_power_uapsd_misbehaving_ap_notif, false), | 258 | iwl_mvm_power_uapsd_misbehaving_ap_notif, false), |
| 259 | RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true), | ||
| 260 | |||
| 261 | RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, | ||
| 262 | true), | ||
| 263 | RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), | ||
| 264 | |||
| 255 | }; | 265 | }; |
| 256 | #undef RX_HANDLER | 266 | #undef RX_HANDLER |
| 257 | #define CMD(x) [x] = #x | 267 | #define CMD(x) [x] = #x |
| @@ -315,11 +325,9 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
| 315 | CMD(WOWLAN_KEK_KCK_MATERIAL), | 325 | CMD(WOWLAN_KEK_KCK_MATERIAL), |
| 316 | CMD(WOWLAN_GET_STATUSES), | 326 | CMD(WOWLAN_GET_STATUSES), |
| 317 | CMD(WOWLAN_TX_POWER_PER_DB), | 327 | CMD(WOWLAN_TX_POWER_PER_DB), |
| 318 | CMD(NET_DETECT_CONFIG_CMD), | 328 | CMD(SCAN_OFFLOAD_PROFILES_QUERY_CMD), |
| 319 | CMD(NET_DETECT_PROFILES_QUERY_CMD), | 329 | CMD(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), |
| 320 | CMD(NET_DETECT_PROFILES_CMD), | 330 | CMD(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), |
| 321 | CMD(NET_DETECT_HOTSPOTS_CMD), | ||
| 322 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), | ||
| 323 | CMD(CARD_STATE_NOTIFICATION), | 331 | CMD(CARD_STATE_NOTIFICATION), |
| 324 | CMD(MISSED_BEACONS_NOTIFICATION), | 332 | CMD(MISSED_BEACONS_NOTIFICATION), |
| 325 | CMD(BT_COEX_PRIO_TABLE), | 333 | CMD(BT_COEX_PRIO_TABLE), |
| @@ -330,14 +338,25 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
| 330 | CMD(BCAST_FILTER_CMD), | 338 | CMD(BCAST_FILTER_CMD), |
| 331 | CMD(REPLY_SF_CFG_CMD), | 339 | CMD(REPLY_SF_CFG_CMD), |
| 332 | CMD(REPLY_BEACON_FILTERING_CMD), | 340 | CMD(REPLY_BEACON_FILTERING_CMD), |
| 341 | CMD(CMD_DTS_MEASUREMENT_TRIGGER), | ||
| 342 | CMD(DTS_MEASUREMENT_NOTIFICATION), | ||
| 333 | CMD(REPLY_THERMAL_MNG_BACKOFF), | 343 | CMD(REPLY_THERMAL_MNG_BACKOFF), |
| 334 | CMD(MAC_PM_POWER_TABLE), | 344 | CMD(MAC_PM_POWER_TABLE), |
| 345 | CMD(LTR_CONFIG), | ||
| 335 | CMD(BT_COEX_CI), | 346 | CMD(BT_COEX_CI), |
| 336 | CMD(BT_COEX_UPDATE_SW_BOOST), | 347 | CMD(BT_COEX_UPDATE_SW_BOOST), |
| 337 | CMD(BT_COEX_UPDATE_CORUN_LUT), | 348 | CMD(BT_COEX_UPDATE_CORUN_LUT), |
| 338 | CMD(BT_COEX_UPDATE_REDUCED_TXP), | 349 | CMD(BT_COEX_UPDATE_REDUCED_TXP), |
| 339 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), | 350 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), |
| 340 | CMD(ANTENNA_COUPLING_NOTIFICATION), | 351 | CMD(ANTENNA_COUPLING_NOTIFICATION), |
| 352 | CMD(SCD_QUEUE_CFG), | ||
| 353 | CMD(SCAN_CFG_CMD), | ||
| 354 | CMD(SCAN_REQ_UMAC), | ||
| 355 | CMD(SCAN_ABORT_UMAC), | ||
| 356 | CMD(SCAN_COMPLETE_UMAC), | ||
| 357 | CMD(TDLS_CHANNEL_SWITCH_CMD), | ||
| 358 | CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION), | ||
| 359 | CMD(TDLS_CONFIG_CMD), | ||
| 341 | }; | 360 | }; |
| 342 | #undef CMD | 361 | #undef CMD |
| 343 | 362 | ||
| @@ -362,6 +381,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) | |||
| 362 | return 0; | 381 | return 0; |
| 363 | } | 382 | } |
| 364 | 383 | ||
| 384 | static void iwl_mvm_fw_error_dump_wk(struct work_struct *work); | ||
| 385 | |||
| 365 | static struct iwl_op_mode * | 386 | static struct iwl_op_mode * |
| 366 | iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | 387 | iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, |
| 367 | const struct iwl_fw *fw, struct dentry *dbgfs_dir) | 388 | const struct iwl_fw *fw, struct dentry *dbgfs_dir) |
| @@ -395,6 +416,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 395 | if (cfg->max_rx_agg_size) | 416 | if (cfg->max_rx_agg_size) |
| 396 | hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; | 417 | hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; |
| 397 | 418 | ||
| 419 | if (cfg->max_tx_agg_size) | ||
| 420 | hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; | ||
| 421 | |||
| 398 | op_mode = hw->priv; | 422 | op_mode = hw->priv; |
| 399 | op_mode->ops = &iwl_mvm_ops; | 423 | op_mode->ops = &iwl_mvm_ops; |
| 400 | 424 | ||
| @@ -415,6 +439,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 415 | mvm->first_agg_queue = 12; | 439 | mvm->first_agg_queue = 12; |
| 416 | } | 440 | } |
| 417 | mvm->sf_state = SF_UNINIT; | 441 | mvm->sf_state = SF_UNINIT; |
| 442 | mvm->low_latency_agg_frame_limit = 6; | ||
| 443 | mvm->cur_ucode = IWL_UCODE_INIT; | ||
| 418 | 444 | ||
| 419 | mutex_init(&mvm->mutex); | 445 | mutex_init(&mvm->mutex); |
| 420 | mutex_init(&mvm->d0i3_suspend_mutex); | 446 | mutex_init(&mvm->d0i3_suspend_mutex); |
| @@ -428,6 +454,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 428 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); | 454 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); |
| 429 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); | 455 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); |
| 430 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); | 456 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); |
| 457 | INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk); | ||
| 458 | INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); | ||
| 431 | 459 | ||
| 432 | spin_lock_init(&mvm->d0i3_tx_lock); | 460 | spin_lock_init(&mvm->d0i3_tx_lock); |
| 433 | spin_lock_init(&mvm->refs_lock); | 461 | spin_lock_init(&mvm->refs_lock); |
| @@ -456,7 +484,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 456 | trans_cfg.command_names = iwl_mvm_cmd_strings; | 484 | trans_cfg.command_names = iwl_mvm_cmd_strings; |
| 457 | 485 | ||
| 458 | trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; | 486 | trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; |
| 459 | trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO; | 487 | trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; |
| 488 | trans_cfg.scd_set_active = true; | ||
| 460 | 489 | ||
| 461 | snprintf(mvm->hw->wiphy->fw_version, | 490 | snprintf(mvm->hw->wiphy->fw_version, |
| 462 | sizeof(mvm->hw->wiphy->fw_version), | 491 | sizeof(mvm->hw->wiphy->fw_version), |
| @@ -467,6 +496,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 467 | 496 | ||
| 468 | trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; | 497 | trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; |
| 469 | trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); | 498 | trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); |
| 499 | trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv; | ||
| 500 | trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num; | ||
| 501 | memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv, | ||
| 502 | sizeof(trans->dbg_conf_tlv)); | ||
| 470 | 503 | ||
| 471 | /* set up notification wait support */ | 504 | /* set up notification wait support */ |
| 472 | iwl_notification_wait_init(&mvm->notif_wait); | 505 | iwl_notification_wait_init(&mvm->notif_wait); |
| @@ -494,7 +527,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 494 | goto out_free; | 527 | goto out_free; |
| 495 | 528 | ||
| 496 | /* | 529 | /* |
| 497 | * Even if nvm exists in the nvm_file driver should read agin the nvm | 530 | * Even if nvm exists in the nvm_file driver should read again the nvm |
| 498 | * from the nic because there might be entries that exist in the OTP | 531 | * from the nic because there might be entries that exist in the OTP |
| 499 | * and not in the file. | 532 | * and not in the file. |
| 500 | * for nics with no_power_up_nic_in_init: rely completley on nvm_file | 533 | * for nics with no_power_up_nic_in_init: rely completley on nvm_file |
| @@ -510,7 +543,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 510 | 543 | ||
| 511 | mutex_lock(&mvm->mutex); | 544 | mutex_lock(&mvm->mutex); |
| 512 | err = iwl_run_init_mvm_ucode(mvm, true); | 545 | err = iwl_run_init_mvm_ucode(mvm, true); |
| 513 | iwl_trans_stop_device(trans); | 546 | if (!err || !iwlmvm_mod_params.init_dbg) |
| 547 | iwl_trans_stop_device(trans); | ||
| 514 | mutex_unlock(&mvm->mutex); | 548 | mutex_unlock(&mvm->mutex); |
| 515 | /* returns 0 if successful, 1 if success but in rfkill */ | 549 | /* returns 0 if successful, 1 if success but in rfkill */ |
| 516 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { | 550 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { |
| @@ -519,16 +553,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
| 519 | } | 553 | } |
| 520 | } | 554 | } |
| 521 | 555 | ||
| 522 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 556 | scan_size = iwl_mvm_scan_size(mvm); |
| 523 | scan_size = sizeof(struct iwl_scan_req_unified_lmac) + | ||
| 524 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
| 525 | mvm->fw->ucode_capa.n_scan_channels + | ||
| 526 | sizeof(struct iwl_scan_probe_req); | ||
| 527 | else | ||
| 528 | scan_size = sizeof(struct iwl_scan_cmd) + | ||
| 529 | mvm->fw->ucode_capa.max_probe_length + | ||
| 530 | mvm->fw->ucode_capa.n_scan_channels * | ||
| 531 | sizeof(struct iwl_scan_channel); | ||
| 532 | 557 | ||
| 533 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); | 558 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); |
| 534 | if (!mvm->scan_cmd) | 559 | if (!mvm->scan_cmd) |
| @@ -573,16 +598,16 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
| 573 | ieee80211_unregister_hw(mvm->hw); | 598 | ieee80211_unregister_hw(mvm->hw); |
| 574 | 599 | ||
| 575 | kfree(mvm->scan_cmd); | 600 | kfree(mvm->scan_cmd); |
| 576 | if (mvm->fw_error_dump) { | ||
| 577 | vfree(mvm->fw_error_dump->op_mode_ptr); | ||
| 578 | vfree(mvm->fw_error_dump->trans_ptr); | ||
| 579 | kfree(mvm->fw_error_dump); | ||
| 580 | } | ||
| 581 | kfree(mvm->mcast_filter_cmd); | 601 | kfree(mvm->mcast_filter_cmd); |
| 582 | mvm->mcast_filter_cmd = NULL; | 602 | mvm->mcast_filter_cmd = NULL; |
| 583 | 603 | ||
| 584 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) | 604 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) |
| 585 | kfree(mvm->d3_resume_sram); | 605 | kfree(mvm->d3_resume_sram); |
| 606 | if (mvm->nd_config) { | ||
| 607 | kfree(mvm->nd_config->match_sets); | ||
| 608 | kfree(mvm->nd_config); | ||
| 609 | mvm->nd_config = NULL; | ||
| 610 | } | ||
| 586 | #endif | 611 | #endif |
| 587 | 612 | ||
| 588 | iwl_trans_op_mode_leave(mvm->trans); | 613 | iwl_trans_op_mode_leave(mvm->trans); |
| @@ -700,14 +725,13 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) | |||
| 700 | if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) | 725 | if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) |
| 701 | return; | 726 | return; |
| 702 | 727 | ||
| 703 | if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) { | 728 | if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) { |
| 704 | IWL_DEBUG_TX_QUEUES(mvm, | 729 | IWL_DEBUG_TX_QUEUES(mvm, |
| 705 | "queue %d (mac80211 %d) already stopped\n", | 730 | "queue %d (mac80211 %d) already stopped\n", |
| 706 | queue, mq); | 731 | queue, mq); |
| 707 | return; | 732 | return; |
| 708 | } | 733 | } |
| 709 | 734 | ||
| 710 | set_bit(mq, &mvm->transport_queue_stop); | ||
| 711 | ieee80211_stop_queue(mvm->hw, mq); | 735 | ieee80211_stop_queue(mvm->hw, mq); |
| 712 | } | 736 | } |
| 713 | 737 | ||
| @@ -719,15 +743,13 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) | |||
| 719 | if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) | 743 | if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) |
| 720 | return; | 744 | return; |
| 721 | 745 | ||
| 722 | if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) { | 746 | if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) { |
| 723 | IWL_DEBUG_TX_QUEUES(mvm, | 747 | IWL_DEBUG_TX_QUEUES(mvm, |
| 724 | "queue %d (mac80211 %d) already awake\n", | 748 | "queue %d (mac80211 %d) still stopped\n", |
| 725 | queue, mq); | 749 | queue, mq); |
| 726 | return; | 750 | return; |
| 727 | } | 751 | } |
| 728 | 752 | ||
| 729 | clear_bit(mq, &mvm->transport_queue_stop); | ||
| 730 | |||
| 731 | ieee80211_wake_queue(mvm->hw, mq); | 753 | ieee80211_wake_queue(mvm->hw, mq); |
| 732 | } | 754 | } |
| 733 | 755 | ||
| @@ -744,6 +766,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) | |||
| 744 | static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | 766 | static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) |
| 745 | { | 767 | { |
| 746 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 768 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
| 769 | bool calibrating = ACCESS_ONCE(mvm->calibrating); | ||
| 747 | 770 | ||
| 748 | if (state) | 771 | if (state) |
| 749 | set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | 772 | set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); |
| @@ -752,7 +775,15 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | |||
| 752 | 775 | ||
| 753 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); | 776 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); |
| 754 | 777 | ||
| 755 | return state && mvm->cur_ucode != IWL_UCODE_INIT; | 778 | /* iwl_run_init_mvm_ucode is waiting for results, abort it */ |
| 779 | if (calibrating) | ||
| 780 | iwl_abort_notification_waits(&mvm->notif_wait); | ||
| 781 | |||
| 782 | /* | ||
| 783 | * Stop the device if we run OPERATIONAL firmware or if we are in the | ||
| 784 | * middle of the calibrations. | ||
| 785 | */ | ||
| 786 | return state && (mvm->cur_ucode != IWL_UCODE_INIT || calibrating); | ||
| 756 | } | 787 | } |
| 757 | 788 | ||
| 758 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | 789 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) |
| @@ -781,6 +812,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk) | |||
| 781 | module_put(THIS_MODULE); | 812 | module_put(THIS_MODULE); |
| 782 | } | 813 | } |
| 783 | 814 | ||
| 815 | static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) | ||
| 816 | { | ||
| 817 | struct iwl_mvm *mvm = | ||
| 818 | container_of(work, struct iwl_mvm, fw_error_dump_wk); | ||
| 819 | |||
| 820 | mutex_lock(&mvm->mutex); | ||
| 821 | iwl_mvm_fw_error_dump(mvm); | ||
| 822 | mutex_unlock(&mvm->mutex); | ||
| 823 | } | ||
| 824 | |||
| 784 | void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) | 825 | void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) |
| 785 | { | 826 | { |
| 786 | iwl_abort_notification_waits(&mvm->notif_wait); | 827 | iwl_abort_notification_waits(&mvm->notif_wait); |
| @@ -846,6 +887,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) | |||
| 846 | if (fw_error && mvm->restart_fw > 0) | 887 | if (fw_error && mvm->restart_fw > 0) |
| 847 | mvm->restart_fw--; | 888 | mvm->restart_fw--; |
| 848 | ieee80211_restart_hw(mvm->hw); | 889 | ieee80211_restart_hw(mvm->hw); |
| 890 | } else if (fw_error) { | ||
| 891 | schedule_work(&mvm->fw_error_dump_wk); | ||
| 849 | } | 892 | } |
| 850 | } | 893 | } |
| 851 | 894 | ||
| @@ -961,7 +1004,7 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, | |||
| 961 | } | 1004 | } |
| 962 | 1005 | ||
| 963 | static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, | 1006 | static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, |
| 964 | struct iwl_wowlan_config_cmd_v3 *cmd, | 1007 | struct iwl_wowlan_config_cmd *cmd, |
| 965 | struct iwl_d0i3_iter_data *iter_data) | 1008 | struct iwl_d0i3_iter_data *iter_data) |
| 966 | { | 1009 | { |
| 967 | struct ieee80211_sta *ap_sta; | 1010 | struct ieee80211_sta *ap_sta; |
| @@ -977,14 +1020,14 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, | |||
| 977 | goto out; | 1020 | goto out; |
| 978 | 1021 | ||
| 979 | mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); | 1022 | mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); |
| 980 | cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported; | 1023 | cmd->is_11n_connection = ap_sta->ht_cap.ht_supported; |
| 981 | cmd->offloading_tid = iter_data->offloading_tid; | 1024 | cmd->offloading_tid = iter_data->offloading_tid; |
| 982 | 1025 | ||
| 983 | /* | 1026 | /* |
| 984 | * The d0i3 uCode takes care of the nonqos counters, | 1027 | * The d0i3 uCode takes care of the nonqos counters, |
| 985 | * so configure only the qos seq ones. | 1028 | * so configure only the qos seq ones. |
| 986 | */ | 1029 | */ |
| 987 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &cmd->common); | 1030 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, cmd); |
| 988 | out: | 1031 | out: |
| 989 | rcu_read_unlock(); | 1032 | rcu_read_unlock(); |
| 990 | } | 1033 | } |
| @@ -996,14 +1039,11 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | |||
| 996 | struct iwl_d0i3_iter_data d0i3_iter_data = { | 1039 | struct iwl_d0i3_iter_data d0i3_iter_data = { |
| 997 | .mvm = mvm, | 1040 | .mvm = mvm, |
| 998 | }; | 1041 | }; |
| 999 | struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = { | 1042 | struct iwl_wowlan_config_cmd wowlan_config_cmd = { |
| 1000 | .common = { | 1043 | .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | |
| 1001 | .wakeup_filter = | 1044 | IWL_WOWLAN_WAKEUP_BEACON_MISS | |
| 1002 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | | 1045 | IWL_WOWLAN_WAKEUP_LINK_CHANGE | |
| 1003 | IWL_WOWLAN_WAKEUP_BEACON_MISS | | 1046 | IWL_WOWLAN_WAKEUP_BCN_FILTERING), |
| 1004 | IWL_WOWLAN_WAKEUP_LINK_CHANGE | | ||
| 1005 | IWL_WOWLAN_WAKEUP_BCN_FILTERING), | ||
| 1006 | }, | ||
| 1007 | }; | 1047 | }; |
| 1008 | struct iwl_d3_manager_config d3_cfg_cmd = { | 1048 | struct iwl_d3_manager_config d3_cfg_cmd = { |
| 1009 | .min_sleep_time = cpu_to_le32(1000), | 1049 | .min_sleep_time = cpu_to_le32(1000), |
| @@ -1015,6 +1055,19 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | |||
| 1015 | set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | 1055 | set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); |
| 1016 | synchronize_net(); | 1056 | synchronize_net(); |
| 1017 | 1057 | ||
| 1058 | /* | ||
| 1059 | * iwl_mvm_ref_sync takes a reference before checking the flag. | ||
| 1060 | * so by checking there is no held reference we prevent a state | ||
| 1061 | * in which iwl_mvm_ref_sync continues successfully while we | ||
| 1062 | * configure the firmware to enter d0i3 | ||
| 1063 | */ | ||
| 1064 | if (iwl_mvm_ref_taken(mvm)) { | ||
| 1065 | IWL_DEBUG_RPM(mvm->trans, "abort d0i3 due to taken ref\n"); | ||
| 1066 | clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | ||
| 1067 | wake_up(&mvm->d0i3_exit_waitq); | ||
| 1068 | return 1; | ||
| 1069 | } | ||
| 1070 | |||
| 1018 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 1071 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
| 1019 | IEEE80211_IFACE_ITER_NORMAL, | 1072 | IEEE80211_IFACE_ITER_NORMAL, |
| 1020 | iwl_mvm_enter_d0i3_iterator, | 1073 | iwl_mvm_enter_d0i3_iterator, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 6cc243f7cf60..1c0d4a45c1a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -66,7 +68,7 @@ | |||
| 66 | #include "mvm.h" | 68 | #include "mvm.h" |
| 67 | 69 | ||
| 68 | /* Maps the driver specific channel width definition to the the fw values */ | 70 | /* Maps the driver specific channel width definition to the the fw values */ |
| 69 | static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) | 71 | u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) |
| 70 | { | 72 | { |
| 71 | switch (chandef->width) { | 73 | switch (chandef->width) { |
| 72 | case NL80211_CHAN_WIDTH_20_NOHT: | 74 | case NL80211_CHAN_WIDTH_20_NOHT: |
| @@ -88,7 +90,7 @@ static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) | |||
| 88 | * Maps the driver specific control channel position (relative to the center | 90 | * Maps the driver specific control channel position (relative to the center |
| 89 | * freq) definitions to the the fw values | 91 | * freq) definitions to the the fw values |
| 90 | */ | 92 | */ |
| 91 | static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) | 93 | u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) |
| 92 | { | 94 | { |
| 93 | switch (chandef->chan->center_freq - chandef->center_freq1) { | 95 | switch (chandef->chan->center_freq - chandef->center_freq1) { |
| 94 | case -70: | 96 | case -70: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d9769a23c68b..2620dd0c45f9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -198,8 +200,15 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, | |||
| 198 | } | 200 | } |
| 199 | } | 201 | } |
| 200 | 202 | ||
| 201 | if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) | 203 | if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) { |
| 204 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
| 205 | /* set advanced pm flag with no uapsd ACs to enable ps-poll */ | ||
| 206 | if (mvmvif->dbgfs_pm.use_ps_poll) | ||
| 207 | cmd->flags |= | ||
| 208 | cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); | ||
| 209 | #endif | ||
| 202 | return; | 210 | return; |
| 211 | } | ||
| 203 | 212 | ||
| 204 | cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK); | 213 | cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK); |
| 205 | 214 | ||
| @@ -277,13 +286,50 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, | |||
| 277 | return true; | 286 | return true; |
| 278 | } | 287 | } |
| 279 | 288 | ||
| 289 | static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi) | ||
| 290 | { | ||
| 291 | int numerator; | ||
| 292 | int dtim_interval = dtimper * bi; | ||
| 293 | |||
| 294 | if (WARN_ON(!dtim_interval)) | ||
| 295 | return 0; | ||
| 296 | |||
| 297 | if (dtimper == 1) { | ||
| 298 | if (bi > 100) | ||
| 299 | numerator = 408; | ||
| 300 | else | ||
| 301 | numerator = 510; | ||
| 302 | } else if (dtimper < 10) { | ||
| 303 | numerator = 612; | ||
| 304 | } else { | ||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | return max(1, (numerator / dtim_interval)); | ||
| 308 | } | ||
| 309 | |||
| 310 | static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) | ||
| 311 | { | ||
| 312 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 313 | struct ieee80211_channel *chan; | ||
| 314 | bool radar_detect = false; | ||
| 315 | |||
| 316 | rcu_read_lock(); | ||
| 317 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
| 318 | WARN_ON(!chanctx_conf); | ||
| 319 | if (chanctx_conf) { | ||
| 320 | chan = chanctx_conf->def.chan; | ||
| 321 | radar_detect = chan->flags & IEEE80211_CHAN_RADAR; | ||
| 322 | } | ||
| 323 | rcu_read_unlock(); | ||
| 324 | |||
| 325 | return radar_detect; | ||
| 326 | } | ||
| 327 | |||
| 280 | static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | 328 | static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, |
| 281 | struct ieee80211_vif *vif, | 329 | struct ieee80211_vif *vif, |
| 282 | struct iwl_mac_power_cmd *cmd) | 330 | struct iwl_mac_power_cmd *cmd) |
| 283 | { | 331 | { |
| 284 | struct ieee80211_chanctx_conf *chanctx_conf; | 332 | int dtimper, bi; |
| 285 | struct ieee80211_channel *chan; | ||
| 286 | int dtimper, dtimper_msec; | ||
| 287 | int keep_alive; | 333 | int keep_alive; |
| 288 | bool radar_detect = false; | 334 | bool radar_detect = false; |
| 289 | struct iwl_mvm_vif *mvmvif __maybe_unused = | 335 | struct iwl_mvm_vif *mvmvif __maybe_unused = |
| @@ -292,6 +338,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
| 292 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | 338 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, |
| 293 | mvmvif->color)); | 339 | mvmvif->color)); |
| 294 | dtimper = vif->bss_conf.dtim_period; | 340 | dtimper = vif->bss_conf.dtim_period; |
| 341 | bi = vif->bss_conf.beacon_int; | ||
| 295 | 342 | ||
| 296 | /* | 343 | /* |
| 297 | * Regardless of power management state the driver must set | 344 | * Regardless of power management state the driver must set |
| @@ -299,10 +346,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
| 299 | * immediately after association. Check that keep alive period | 346 | * immediately after association. Check that keep alive period |
| 300 | * is at least 3 * DTIM | 347 | * is at least 3 * DTIM |
| 301 | */ | 348 | */ |
| 302 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | 349 | keep_alive = DIV_ROUND_UP(ieee80211_tu_to_usec(3 * dtimper * bi), |
| 303 | keep_alive = max_t(int, 3 * dtimper_msec, | 350 | USEC_PER_SEC); |
| 304 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | 351 | keep_alive = max(keep_alive, POWER_KEEP_ALIVE_PERIOD_SEC); |
| 305 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
| 306 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | 352 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); |
| 307 | 353 | ||
| 308 | if (mvm->ps_disabled) | 354 | if (mvm->ps_disabled) |
| @@ -311,7 +357,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
| 311 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 357 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
| 312 | 358 | ||
| 313 | if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || | 359 | if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || |
| 314 | !mvmvif->pm_enabled) | 360 | !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) |
| 315 | return; | 361 | return; |
| 316 | 362 | ||
| 317 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | 363 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); |
| @@ -324,21 +370,17 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
| 324 | } | 370 | } |
| 325 | 371 | ||
| 326 | /* Check if radar detection is required on current channel */ | 372 | /* Check if radar detection is required on current channel */ |
| 327 | rcu_read_lock(); | 373 | radar_detect = iwl_mvm_power_is_radar(vif); |
| 328 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
| 329 | WARN_ON(!chanctx_conf); | ||
| 330 | if (chanctx_conf) { | ||
| 331 | chan = chanctx_conf->def.chan; | ||
| 332 | radar_detect = chan->flags & IEEE80211_CHAN_RADAR; | ||
| 333 | } | ||
| 334 | rcu_read_unlock(); | ||
| 335 | 374 | ||
| 336 | /* Check skip over DTIM conditions */ | 375 | /* Check skip over DTIM conditions */ |
| 337 | if (!radar_detect && (dtimper <= 10) && | 376 | if (!radar_detect && (dtimper < 10) && |
| 338 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || | 377 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || |
| 339 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | 378 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { |
| 340 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 379 | cmd->skip_dtim_periods = |
| 341 | cmd->skip_dtim_periods = 3; | 380 | iwl_mvm_power_get_skip_over_dtim(dtimper, bi); |
| 381 | if (cmd->skip_dtim_periods) | ||
| 382 | cmd->flags |= | ||
| 383 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
| 342 | } | 384 | } |
| 343 | 385 | ||
| 344 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { | 386 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { |
| @@ -492,17 +534,33 @@ struct iwl_power_vifs { | |||
| 492 | bool bss_active; | 534 | bool bss_active; |
| 493 | bool ap_active; | 535 | bool ap_active; |
| 494 | bool monitor_active; | 536 | bool monitor_active; |
| 495 | bool bss_tdls; | ||
| 496 | bool p2p_tdls; | ||
| 497 | }; | 537 | }; |
| 498 | 538 | ||
| 499 | static void iwl_mvm_power_iterator(void *_data, u8 *mac, | 539 | static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, |
| 500 | struct ieee80211_vif *vif) | 540 | struct ieee80211_vif *vif) |
| 501 | { | 541 | { |
| 502 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 542 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 503 | struct iwl_power_vifs *power_iterator = _data; | ||
| 504 | 543 | ||
| 505 | mvmvif->pm_enabled = false; | 544 | mvmvif->pm_enabled = false; |
| 545 | } | ||
| 546 | |||
| 547 | static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac, | ||
| 548 | struct ieee80211_vif *vif) | ||
| 549 | { | ||
| 550 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 551 | bool *disable_ps = _data; | ||
| 552 | |||
| 553 | if (mvmvif->phy_ctxt) | ||
| 554 | if (mvmvif->phy_ctxt->id < MAX_PHYS) | ||
| 555 | *disable_ps |= mvmvif->ps_disabled; | ||
| 556 | } | ||
| 557 | |||
| 558 | static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, | ||
| 559 | struct ieee80211_vif *vif) | ||
| 560 | { | ||
| 561 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 562 | struct iwl_power_vifs *power_iterator = _data; | ||
| 563 | |||
| 506 | switch (ieee80211_vif_type_p2p(vif)) { | 564 | switch (ieee80211_vif_type_p2p(vif)) { |
| 507 | case NL80211_IFTYPE_P2P_DEVICE: | 565 | case NL80211_IFTYPE_P2P_DEVICE: |
| 508 | break; | 566 | break; |
| @@ -530,8 +588,6 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, | |||
| 530 | /* only a single MAC of the same type */ | 588 | /* only a single MAC of the same type */ |
| 531 | WARN_ON(power_iterator->p2p_vif); | 589 | WARN_ON(power_iterator->p2p_vif); |
| 532 | power_iterator->p2p_vif = vif; | 590 | power_iterator->p2p_vif = vif; |
| 533 | power_iterator->p2p_tdls = | ||
| 534 | !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); | ||
| 535 | if (mvmvif->phy_ctxt) | 591 | if (mvmvif->phy_ctxt) |
| 536 | if (mvmvif->phy_ctxt->id < MAX_PHYS) | 592 | if (mvmvif->phy_ctxt->id < MAX_PHYS) |
| 537 | power_iterator->p2p_active = true; | 593 | power_iterator->p2p_active = true; |
| @@ -541,8 +597,6 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, | |||
| 541 | /* only a single MAC of the same type */ | 597 | /* only a single MAC of the same type */ |
| 542 | WARN_ON(power_iterator->bss_vif); | 598 | WARN_ON(power_iterator->bss_vif); |
| 543 | power_iterator->bss_vif = vif; | 599 | power_iterator->bss_vif = vif; |
| 544 | power_iterator->bss_tdls = | ||
| 545 | !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); | ||
| 546 | if (mvmvif->phy_ctxt) | 600 | if (mvmvif->phy_ctxt) |
| 547 | if (mvmvif->phy_ctxt->id < MAX_PHYS) | 601 | if (mvmvif->phy_ctxt->id < MAX_PHYS) |
| 548 | power_iterator->bss_active = true; | 602 | power_iterator->bss_active = true; |
| @@ -558,9 +612,8 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, | |||
| 558 | } | 612 | } |
| 559 | } | 613 | } |
| 560 | 614 | ||
| 561 | static void | 615 | static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, |
| 562 | iwl_mvm_power_set_pm(struct iwl_mvm *mvm, | 616 | struct iwl_power_vifs *vifs) |
| 563 | struct iwl_power_vifs *vifs) | ||
| 564 | { | 617 | { |
| 565 | struct iwl_mvm_vif *bss_mvmvif = NULL; | 618 | struct iwl_mvm_vif *bss_mvmvif = NULL; |
| 566 | struct iwl_mvm_vif *p2p_mvmvif = NULL; | 619 | struct iwl_mvm_vif *p2p_mvmvif = NULL; |
| @@ -570,10 +623,11 @@ iwl_mvm_power_set_pm(struct iwl_mvm *mvm, | |||
| 570 | 623 | ||
| 571 | lockdep_assert_held(&mvm->mutex); | 624 | lockdep_assert_held(&mvm->mutex); |
| 572 | 625 | ||
| 573 | /* get vifs info + set pm_enable to false */ | 626 | /* set pm_enable to false */ |
| 574 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 627 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
| 575 | IEEE80211_IFACE_ITER_NORMAL, | 628 | IEEE80211_IFACE_ITER_NORMAL, |
| 576 | iwl_mvm_power_iterator, vifs); | 629 | iwl_mvm_power_disable_pm_iterator, |
| 630 | NULL); | ||
| 577 | 631 | ||
| 578 | if (vifs->bss_vif) | 632 | if (vifs->bss_vif) |
| 579 | bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif); | 633 | bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif); |
| @@ -585,15 +639,13 @@ iwl_mvm_power_set_pm(struct iwl_mvm *mvm, | |||
| 585 | ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); | 639 | ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); |
| 586 | 640 | ||
| 587 | /* enable PM on bss if bss stand alone */ | 641 | /* enable PM on bss if bss stand alone */ |
| 588 | if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active && | 642 | if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { |
| 589 | !vifs->bss_tdls) { | ||
| 590 | bss_mvmvif->pm_enabled = true; | 643 | bss_mvmvif->pm_enabled = true; |
| 591 | return; | 644 | return; |
| 592 | } | 645 | } |
| 593 | 646 | ||
| 594 | /* enable PM on p2p if p2p stand alone */ | 647 | /* enable PM on p2p if p2p stand alone */ |
| 595 | if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active && | 648 | if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { |
| 596 | !vifs->p2p_tdls) { | ||
| 597 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) | 649 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) |
| 598 | p2p_mvmvif->pm_enabled = true; | 650 | p2p_mvmvif->pm_enabled = true; |
| 599 | return; | 651 | return; |
| @@ -816,32 +868,92 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | |||
| 816 | return ret; | 868 | return ret; |
| 817 | } | 869 | } |
| 818 | 870 | ||
| 819 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) | 871 | static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm) |
| 872 | { | ||
| 873 | bool disable_ps; | ||
| 874 | int ret; | ||
| 875 | |||
| 876 | /* disable PS if CAM */ | ||
| 877 | disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM); | ||
| 878 | /* ...or if any of the vifs require PS to be off */ | ||
| 879 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
| 880 | IEEE80211_IFACE_ITER_NORMAL, | ||
| 881 | iwl_mvm_power_ps_disabled_iterator, | ||
| 882 | &disable_ps); | ||
| 883 | |||
| 884 | /* update device power state if it has changed */ | ||
| 885 | if (mvm->ps_disabled != disable_ps) { | ||
| 886 | bool old_ps_disabled = mvm->ps_disabled; | ||
| 887 | |||
| 888 | mvm->ps_disabled = disable_ps; | ||
| 889 | ret = iwl_mvm_power_update_device(mvm); | ||
| 890 | if (ret) { | ||
| 891 | mvm->ps_disabled = old_ps_disabled; | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | } | ||
| 895 | |||
| 896 | return 0; | ||
| 897 | } | ||
| 898 | |||
| 899 | static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, | ||
| 900 | struct iwl_power_vifs *vifs) | ||
| 820 | { | 901 | { |
| 821 | struct iwl_mvm_vif *mvmvif; | 902 | struct iwl_mvm_vif *mvmvif; |
| 903 | bool ba_enable; | ||
| 904 | |||
| 905 | if (!vifs->bf_vif) | ||
| 906 | return 0; | ||
| 907 | |||
| 908 | mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif); | ||
| 909 | |||
| 910 | ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || | ||
| 911 | !vifs->bf_vif->bss_conf.ps || | ||
| 912 | iwl_mvm_vif_low_latency(mvmvif)); | ||
| 913 | |||
| 914 | return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable); | ||
| 915 | } | ||
| 916 | |||
| 917 | int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) | ||
| 918 | { | ||
| 919 | struct iwl_power_vifs vifs = { | ||
| 920 | .mvm = mvm, | ||
| 921 | }; | ||
| 922 | int ret; | ||
| 923 | |||
| 924 | lockdep_assert_held(&mvm->mutex); | ||
| 925 | |||
| 926 | /* get vifs info */ | ||
| 927 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
| 928 | IEEE80211_IFACE_ITER_NORMAL, | ||
| 929 | iwl_mvm_power_get_vifs_iterator, &vifs); | ||
| 930 | |||
| 931 | ret = iwl_mvm_power_set_ps(mvm); | ||
| 932 | if (ret) | ||
| 933 | return ret; | ||
| 934 | |||
| 935 | return iwl_mvm_power_set_ba(mvm, &vifs); | ||
| 936 | } | ||
| 937 | |||
| 938 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) | ||
| 939 | { | ||
| 822 | struct iwl_power_vifs vifs = { | 940 | struct iwl_power_vifs vifs = { |
| 823 | .mvm = mvm, | 941 | .mvm = mvm, |
| 824 | }; | 942 | }; |
| 825 | bool ba_enable; | ||
| 826 | int ret; | 943 | int ret; |
| 827 | 944 | ||
| 828 | lockdep_assert_held(&mvm->mutex); | 945 | lockdep_assert_held(&mvm->mutex); |
| 829 | 946 | ||
| 947 | /* get vifs info */ | ||
| 948 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
| 949 | IEEE80211_IFACE_ITER_NORMAL, | ||
| 950 | iwl_mvm_power_get_vifs_iterator, &vifs); | ||
| 951 | |||
| 830 | iwl_mvm_power_set_pm(mvm, &vifs); | 952 | iwl_mvm_power_set_pm(mvm, &vifs); |
| 831 | 953 | ||
| 832 | /* disable PS if CAM */ | 954 | ret = iwl_mvm_power_set_ps(mvm); |
| 833 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { | 955 | if (ret) |
| 834 | mvm->ps_disabled = true; | 956 | return ret; |
| 835 | } else { | ||
| 836 | /* don't update device power state unless we add / remove monitor */ | ||
| 837 | if (vifs.monitor_vif) { | ||
| 838 | if (vifs.monitor_active) | ||
| 839 | mvm->ps_disabled = true; | ||
| 840 | ret = iwl_mvm_power_update_device(mvm); | ||
| 841 | if (ret) | ||
| 842 | return ret; | ||
| 843 | } | ||
| 844 | } | ||
| 845 | 957 | ||
| 846 | if (vifs.bss_vif) { | 958 | if (vifs.bss_vif) { |
| 847 | ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif); | 959 | ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif); |
| @@ -855,16 +967,7 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) | |||
| 855 | return ret; | 967 | return ret; |
| 856 | } | 968 | } |
| 857 | 969 | ||
| 858 | if (!vifs.bf_vif) | 970 | return iwl_mvm_power_set_ba(mvm, &vifs); |
| 859 | return 0; | ||
| 860 | |||
| 861 | mvmvif = iwl_mvm_vif_from_mac80211(vifs.bf_vif); | ||
| 862 | |||
| 863 | ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled || | ||
| 864 | !vifs.bf_vif->bss_conf.ps || | ||
| 865 | iwl_mvm_vif_low_latency(mvmvif)); | ||
| 866 | |||
| 867 | return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable); | ||
| 868 | } | 971 | } |
| 869 | 972 | ||
| 870 | int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, | 973 | int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, |
| @@ -883,17 +986,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, | |||
| 883 | 986 | ||
| 884 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 987 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
| 885 | if (enable) { | 988 | if (enable) { |
| 886 | /* configure skip over dtim up to 300 msec */ | 989 | /* configure skip over dtim up to 306TU - 314 msec */ |
| 887 | int dtimper = vif->bss_conf.dtim_period ?: 1; | 990 | int dtimper = vif->bss_conf.dtim_period ?: 1; |
| 888 | int dtimper_msec = dtimper * vif->bss_conf.beacon_int; | 991 | int dtimper_tu = dtimper * vif->bss_conf.beacon_int; |
| 992 | bool radar_detect = iwl_mvm_power_is_radar(vif); | ||
| 889 | 993 | ||
| 890 | if (WARN_ON(!dtimper_msec)) | 994 | if (WARN_ON(!dtimper_tu)) |
| 891 | return 0; | 995 | return 0; |
| 892 | 996 | ||
| 893 | cmd.skip_dtim_periods = 300 / dtimper_msec; | 997 | /* Check skip over DTIM conditions */ |
| 894 | if (cmd.skip_dtim_periods) | 998 | /* TODO: check that multicast wake lock is off */ |
| 895 | cmd.flags |= | 999 | if (!radar_detect && (dtimper < 10)) { |
| 896 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 1000 | cmd.skip_dtim_periods = 306 / dtimper_tu; |
| 1001 | if (cmd.skip_dtim_periods) | ||
| 1002 | cmd.flags |= cpu_to_le16( | ||
| 1003 | POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
| 1004 | } | ||
| 897 | } | 1005 | } |
| 898 | iwl_mvm_power_log(mvm, &cmd); | 1006 | iwl_mvm_power_log(mvm, &cmd); |
| 899 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1007 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 4e20b3ce2b6a..dbb2594390e9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -161,6 +163,9 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, | |||
| 161 | quota *= (beacon_int - mvm->noa_duration); | 163 | quota *= (beacon_int - mvm->noa_duration); |
| 162 | quota /= beacon_int; | 164 | quota /= beacon_int; |
| 163 | 165 | ||
| 166 | IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n", | ||
| 167 | le32_to_cpu(cmd->quotas[i].quota), quota); | ||
| 168 | |||
| 164 | cmd->quotas[i].quota = cpu_to_le32(quota); | 169 | cmd->quotas[i].quota = cpu_to_le32(quota); |
| 165 | } | 170 | } |
| 166 | #endif | 171 | #endif |
| @@ -170,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
| 170 | struct ieee80211_vif *disabled_vif) | 175 | struct ieee80211_vif *disabled_vif) |
| 171 | { | 176 | { |
| 172 | struct iwl_time_quota_cmd cmd = {}; | 177 | struct iwl_time_quota_cmd cmd = {}; |
| 173 | int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; | 178 | int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat; |
| 174 | struct iwl_mvm_quota_iterator_data data = { | 179 | struct iwl_mvm_quota_iterator_data data = { |
| 175 | .n_interfaces = {}, | 180 | .n_interfaces = {}, |
| 176 | .colors = { -1, -1, -1, -1 }, | 181 | .colors = { -1, -1, -1, -1 }, |
| 177 | .disabled_vif = disabled_vif, | 182 | .disabled_vif = disabled_vif, |
| 178 | }; | 183 | }; |
| 184 | struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd; | ||
| 185 | bool send = false; | ||
| 179 | 186 | ||
| 180 | lockdep_assert_held(&mvm->mutex); | 187 | lockdep_assert_held(&mvm->mutex); |
| 181 | 188 | ||
| @@ -222,6 +229,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
| 222 | quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; | 229 | quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; |
| 223 | quota_rem = QUOTA_100 - n_non_lowlat * quota - | 230 | quota_rem = QUOTA_100 - n_non_lowlat * quota - |
| 224 | QUOTA_LOWLAT_MIN; | 231 | QUOTA_LOWLAT_MIN; |
| 232 | IWL_DEBUG_QUOTA(mvm, | ||
| 233 | "quota: low-latency binding active, remaining quota per other binding: %d\n", | ||
| 234 | quota); | ||
| 225 | } else if (num_active_macs) { | 235 | } else if (num_active_macs) { |
| 226 | /* | 236 | /* |
| 227 | * There are 0 or more than 1 low latency bindings, or all the | 237 | * There are 0 or more than 1 low latency bindings, or all the |
| @@ -230,6 +240,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
| 230 | */ | 240 | */ |
| 231 | quota = QUOTA_100 / num_active_macs; | 241 | quota = QUOTA_100 / num_active_macs; |
| 232 | quota_rem = QUOTA_100 % num_active_macs; | 242 | quota_rem = QUOTA_100 % num_active_macs; |
| 243 | IWL_DEBUG_QUOTA(mvm, | ||
| 244 | "quota: splitting evenly per binding: %d\n", | ||
| 245 | quota); | ||
| 233 | } else { | 246 | } else { |
| 234 | /* values don't really matter - won't be used */ | 247 | /* values don't really matter - won't be used */ |
| 235 | quota = 0; | 248 | quota = 0; |
| @@ -271,6 +284,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
| 271 | for (i = 0; i < MAX_BINDINGS; i++) { | 284 | for (i = 0; i < MAX_BINDINGS; i++) { |
| 272 | if (le32_to_cpu(cmd.quotas[i].quota) != 0) { | 285 | if (le32_to_cpu(cmd.quotas[i].quota) != 0) { |
| 273 | le32_add_cpu(&cmd.quotas[i].quota, quota_rem); | 286 | le32_add_cpu(&cmd.quotas[i].quota, quota_rem); |
| 287 | IWL_DEBUG_QUOTA(mvm, | ||
| 288 | "quota: giving remainder of %d to binding %d\n", | ||
| 289 | quota_rem, i); | ||
| 274 | break; | 290 | break; |
| 275 | } | 291 | } |
| 276 | } | 292 | } |
| @@ -279,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
| 279 | 295 | ||
| 280 | /* check that we have non-zero quota for all valid bindings */ | 296 | /* check that we have non-zero quota for all valid bindings */ |
| 281 | for (i = 0; i < MAX_BINDINGS; i++) { | 297 | for (i = 0; i < MAX_BINDINGS; i++) { |
| 298 | if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color) | ||
| 299 | send = true; | ||
| 300 | if (cmd.quotas[i].max_duration != last->quotas[i].max_duration) | ||
| 301 | send = true; | ||
| 302 | if (abs((int)le32_to_cpu(cmd.quotas[i].quota) - | ||
| 303 | (int)le32_to_cpu(last->quotas[i].quota)) | ||
| 304 | > IWL_MVM_QUOTA_THRESHOLD) | ||
| 305 | send = true; | ||
| 282 | if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID)) | 306 | if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID)) |
| 283 | continue; | 307 | continue; |
| 284 | WARN_ONCE(cmd.quotas[i].quota == 0, | 308 | WARN_ONCE(cmd.quotas[i].quota == 0, |
| 285 | "zero quota on binding %d\n", i); | 309 | "zero quota on binding %d\n", i); |
| 286 | } | 310 | } |
| 287 | 311 | ||
| 288 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, | 312 | if (!send) { |
| 289 | sizeof(cmd), &cmd); | 313 | /* don't send a practically unchanged command, the firmware has |
| 290 | if (ret) | 314 | * to re-initialize a lot of state and that can have an adverse |
| 291 | IWL_ERR(mvm, "Failed to send quota: %d\n", ret); | 315 | * impact on it |
| 292 | return ret; | 316 | */ |
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); | ||
| 321 | |||
| 322 | if (err) | ||
| 323 | IWL_ERR(mvm, "Failed to send quota: %d\n", err); | ||
| 324 | else | ||
| 325 | mvm->last_quota_cmd = cmd; | ||
| 326 | return err; | ||
| 293 | } | 327 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index c70e959bf0e3..30ceb67ed7a7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /****************************************************************************** | 1 | /****************************************************************************** |
| 2 | * | 2 | * |
| 3 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 4 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 4 | * | 5 | * |
| 5 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of version 2 of the GNU General Public License as | 7 | * under the terms of version 2 of the GNU General Public License as |
| @@ -157,6 +158,12 @@ struct rs_tx_column { | |||
| 157 | allow_column_func_t checks[MAX_COLUMN_CHECKS]; | 158 | allow_column_func_t checks[MAX_COLUMN_CHECKS]; |
| 158 | }; | 159 | }; |
| 159 | 160 | ||
| 161 | static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
| 162 | struct iwl_scale_tbl_info *tbl) | ||
| 163 | { | ||
| 164 | return iwl_mvm_bt_coex_is_ant_avail(mvm, tbl->rate.ant); | ||
| 165 | } | ||
| 166 | |||
| 160 | static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 167 | static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
| 161 | struct iwl_scale_tbl_info *tbl) | 168 | struct iwl_scale_tbl_info *tbl) |
| 162 | { | 169 | { |
| @@ -217,6 +224,9 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
| 217 | RS_COLUMN_INVALID, | 224 | RS_COLUMN_INVALID, |
| 218 | RS_COLUMN_INVALID, | 225 | RS_COLUMN_INVALID, |
| 219 | }, | 226 | }, |
| 227 | .checks = { | ||
| 228 | rs_ant_allow, | ||
| 229 | }, | ||
| 220 | }, | 230 | }, |
| 221 | [RS_COLUMN_LEGACY_ANT_B] = { | 231 | [RS_COLUMN_LEGACY_ANT_B] = { |
| 222 | .mode = RS_LEGACY, | 232 | .mode = RS_LEGACY, |
| @@ -230,6 +240,9 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
| 230 | RS_COLUMN_INVALID, | 240 | RS_COLUMN_INVALID, |
| 231 | RS_COLUMN_INVALID, | 241 | RS_COLUMN_INVALID, |
| 232 | }, | 242 | }, |
| 243 | .checks = { | ||
| 244 | rs_ant_allow, | ||
| 245 | }, | ||
| 233 | }, | 246 | }, |
| 234 | [RS_COLUMN_SISO_ANT_A] = { | 247 | [RS_COLUMN_SISO_ANT_A] = { |
| 235 | .mode = RS_SISO, | 248 | .mode = RS_SISO, |
| @@ -245,6 +258,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
| 245 | }, | 258 | }, |
| 246 | .checks = { | 259 | .checks = { |
| 247 | rs_siso_allow, | 260 | rs_siso_allow, |
| 261 | rs_ant_allow, | ||
| 248 | }, | 262 | }, |
| 249 | }, | 263 | }, |
| 250 | [RS_COLUMN_SISO_ANT_B] = { | 264 | [RS_COLUMN_SISO_ANT_B] = { |
| @@ -261,6 +275,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
| 261 | }, | 275 | }, |
| 262 | .checks = { | 276 | .checks = { |
| 263 | rs_siso_allow, | 277 | rs_siso_allow, |
| 278 | rs_ant_allow, | ||
| 264 | }, | 279 | }, |
| 265 | }, | 280 | }, |
| 266 | [RS_COLUMN_SISO_ANT_A_SGI] = { | 281 | [RS_COLUMN_SISO_ANT_A_SGI] = { |
| @@ -278,6 +293,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
| 278 | }, | 293 | }, |
| 279 | .checks = { | 294 | .checks = { |
| 280 | rs_siso_allow, | 295 | rs_siso_allow, |
| 296 | rs_ant_allow, | ||
| 281 | rs_sgi_allow, | 297 | rs_sgi_allow, |
| 282 | }, | 298 | }, |
| 283 | }, | 299 | }, |
| @@ -296,6 +312,7 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
| 296 | }, | 312 | }, |
| 297 | .checks = { | 313 | .checks = { |
| 298 | rs_siso_allow, | 314 | rs_siso_allow, |
| 315 | rs_ant_allow, | ||
| 299 | rs_sgi_allow, | 316 | rs_sgi_allow, |
| 300 | }, | 317 | }, |
| 301 | }, | 318 | }, |
| @@ -376,9 +393,9 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
| 376 | } | 393 | } |
| 377 | 394 | ||
| 378 | static void rs_rate_scale_perform(struct iwl_mvm *mvm, | 395 | static void rs_rate_scale_perform(struct iwl_mvm *mvm, |
| 379 | struct sk_buff *skb, | 396 | struct ieee80211_sta *sta, |
| 380 | struct ieee80211_sta *sta, | 397 | struct iwl_lq_sta *lq_sta, |
| 381 | struct iwl_lq_sta *lq_sta); | 398 | int tid); |
| 382 | static void rs_fill_lq_cmd(struct iwl_mvm *mvm, | 399 | static void rs_fill_lq_cmd(struct iwl_mvm *mvm, |
| 383 | struct ieee80211_sta *sta, | 400 | struct ieee80211_sta *sta, |
| 384 | struct iwl_lq_sta *lq_sta, | 401 | struct iwl_lq_sta *lq_sta, |
| @@ -504,10 +521,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) | |||
| 504 | static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, | 521 | static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, |
| 505 | const char *prefix) | 522 | const char *prefix) |
| 506 | { | 523 | { |
| 507 | IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n", | 524 | IWL_DEBUG_RATE(mvm, |
| 525 | "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC: %d\n", | ||
| 508 | prefix, rs_pretty_lq_type(rate->type), | 526 | prefix, rs_pretty_lq_type(rate->type), |
| 509 | rate->index, rs_pretty_ant(rate->ant), | 527 | rate->index, rs_pretty_ant(rate->ant), |
| 510 | rate->bw, rate->sgi); | 528 | rate->bw, rate->sgi, rate->ldpc, rate->stbc); |
| 511 | } | 529 | } |
| 512 | 530 | ||
| 513 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) | 531 | static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) |
| @@ -671,8 +689,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, | |||
| 671 | return -EINVAL; | 689 | return -EINVAL; |
| 672 | 690 | ||
| 673 | if (tbl->column != RS_COLUMN_INVALID) { | 691 | if (tbl->column != RS_COLUMN_INVALID) { |
| 674 | lq_sta->tx_stats[tbl->column][scale_index].total += attempts; | 692 | struct lq_sta_pers *pers = &lq_sta->pers; |
| 675 | lq_sta->tx_stats[tbl->column][scale_index].success += successes; | 693 | |
| 694 | pers->tx_stats[tbl->column][scale_index].total += attempts; | ||
| 695 | pers->tx_stats[tbl->column][scale_index].success += successes; | ||
| 676 | } | 696 | } |
| 677 | 697 | ||
| 678 | /* Select window for current tx bit rate */ | 698 | /* Select window for current tx bit rate */ |
| @@ -738,9 +758,17 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, | |||
| 738 | IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); | 758 | IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); |
| 739 | } | 759 | } |
| 740 | 760 | ||
| 761 | if (is_siso(rate) && rate->stbc) { | ||
| 762 | /* To enable STBC we need to set both a flag and ANT_AB */ | ||
| 763 | ucode_rate |= RATE_MCS_ANT_AB_MSK; | ||
| 764 | ucode_rate |= RATE_MCS_VHT_STBC_MSK; | ||
| 765 | } | ||
| 766 | |||
| 741 | ucode_rate |= rate->bw; | 767 | ucode_rate |= rate->bw; |
| 742 | if (rate->sgi) | 768 | if (rate->sgi) |
| 743 | ucode_rate |= RATE_MCS_SGI_MSK; | 769 | ucode_rate |= RATE_MCS_SGI_MSK; |
| 770 | if (rate->ldpc) | ||
| 771 | ucode_rate |= RATE_MCS_LDPC_MSK; | ||
| 744 | 772 | ||
| 745 | return ucode_rate; | 773 | return ucode_rate; |
| 746 | } | 774 | } |
| @@ -778,6 +806,10 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
| 778 | /* HT or VHT */ | 806 | /* HT or VHT */ |
| 779 | if (ucode_rate & RATE_MCS_SGI_MSK) | 807 | if (ucode_rate & RATE_MCS_SGI_MSK) |
| 780 | rate->sgi = true; | 808 | rate->sgi = true; |
| 809 | if (ucode_rate & RATE_MCS_LDPC_MSK) | ||
| 810 | rate->ldpc = true; | ||
| 811 | if (ucode_rate & RATE_MCS_VHT_STBC_MSK) | ||
| 812 | rate->stbc = true; | ||
| 781 | 813 | ||
| 782 | rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; | 814 | rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; |
| 783 | 815 | ||
| @@ -787,7 +819,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
| 787 | 819 | ||
| 788 | if (nss == 1) { | 820 | if (nss == 1) { |
| 789 | rate->type = LQ_HT_SISO; | 821 | rate->type = LQ_HT_SISO; |
| 790 | WARN_ON_ONCE(num_of_ant != 1); | 822 | WARN_ON_ONCE(!rate->stbc && num_of_ant != 1); |
| 791 | } else if (nss == 2) { | 823 | } else if (nss == 2) { |
| 792 | rate->type = LQ_HT_MIMO2; | 824 | rate->type = LQ_HT_MIMO2; |
| 793 | WARN_ON_ONCE(num_of_ant != 2); | 825 | WARN_ON_ONCE(num_of_ant != 2); |
| @@ -800,7 +832,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, | |||
| 800 | 832 | ||
| 801 | if (nss == 1) { | 833 | if (nss == 1) { |
| 802 | rate->type = LQ_VHT_SISO; | 834 | rate->type = LQ_VHT_SISO; |
| 803 | WARN_ON_ONCE(num_of_ant != 1); | 835 | WARN_ON_ONCE(!rate->stbc && num_of_ant != 1); |
| 804 | } else if (nss == 2) { | 836 | } else if (nss == 2) { |
| 805 | rate->type = LQ_VHT_MIMO2; | 837 | rate->type = LQ_VHT_MIMO2; |
| 806 | WARN_ON_ONCE(num_of_ant != 2); | 838 | WARN_ON_ONCE(num_of_ant != 2); |
| @@ -964,13 +996,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, | |||
| 964 | rate->index > IWL_RATE_MCS_9_INDEX); | 996 | rate->index > IWL_RATE_MCS_9_INDEX); |
| 965 | 997 | ||
| 966 | rate->index = rs_ht_to_legacy[rate->index]; | 998 | rate->index = rs_ht_to_legacy[rate->index]; |
| 999 | rate->ldpc = false; | ||
| 967 | } else { | 1000 | } else { |
| 968 | /* Downgrade to SISO with same MCS if in MIMO */ | 1001 | /* Downgrade to SISO with same MCS if in MIMO */ |
| 969 | rate->type = is_vht_mimo2(rate) ? | 1002 | rate->type = is_vht_mimo2(rate) ? |
| 970 | LQ_VHT_SISO : LQ_HT_SISO; | 1003 | LQ_VHT_SISO : LQ_HT_SISO; |
| 971 | } | 1004 | } |
| 972 | 1005 | ||
| 973 | |||
| 974 | if (num_of_ant(rate->ant) > 1) | 1006 | if (num_of_ant(rate->ant) > 1) |
| 975 | rate->ant = first_antenna(mvm->fw->valid_tx_ant); | 1007 | rate->ant = first_antenna(mvm->fw->valid_tx_ant); |
| 976 | 1008 | ||
| @@ -985,7 +1017,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, | |||
| 985 | static inline bool rs_rate_match(struct rs_rate *a, | 1017 | static inline bool rs_rate_match(struct rs_rate *a, |
| 986 | struct rs_rate *b) | 1018 | struct rs_rate *b) |
| 987 | { | 1019 | { |
| 988 | return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi); | 1020 | bool ant_match; |
| 1021 | |||
| 1022 | if (a->stbc) | ||
| 1023 | ant_match = (b->ant == ANT_A || b->ant == ANT_B); | ||
| 1024 | else | ||
| 1025 | ant_match = (a->ant == b->ant); | ||
| 1026 | |||
| 1027 | return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi) | ||
| 1028 | && ant_match; | ||
| 989 | } | 1029 | } |
| 990 | 1030 | ||
| 991 | static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) | 1031 | static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) |
| @@ -1000,27 +1040,35 @@ static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) | |||
| 1000 | return RATE_MCS_CHAN_WIDTH_20; | 1040 | return RATE_MCS_CHAN_WIDTH_20; |
| 1001 | } | 1041 | } |
| 1002 | 1042 | ||
| 1003 | /* | 1043 | static u8 rs_get_tid(struct ieee80211_hdr *hdr) |
| 1004 | * mac80211 sends us Tx status | 1044 | { |
| 1005 | */ | 1045 | u8 tid = IWL_MAX_TID_COUNT; |
| 1006 | static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | 1046 | |
| 1007 | struct ieee80211_sta *sta, void *priv_sta, | 1047 | if (ieee80211_is_data_qos(hdr->frame_control)) { |
| 1008 | struct sk_buff *skb) | 1048 | u8 *qc = ieee80211_get_qos_ctl(hdr); |
| 1049 | tid = qc[0] & 0xf; | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | if (unlikely(tid > IWL_MAX_TID_COUNT)) | ||
| 1053 | tid = IWL_MAX_TID_COUNT; | ||
| 1054 | |||
| 1055 | return tid; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
| 1059 | int tid, struct ieee80211_tx_info *info) | ||
| 1009 | { | 1060 | { |
| 1010 | int legacy_success; | 1061 | int legacy_success; |
| 1011 | int retries; | 1062 | int retries; |
| 1012 | int mac_index, i; | 1063 | int mac_index, i; |
| 1013 | struct iwl_lq_sta *lq_sta = priv_sta; | ||
| 1014 | struct iwl_lq_cmd *table; | 1064 | struct iwl_lq_cmd *table; |
| 1015 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 1016 | struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r; | ||
| 1017 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
| 1018 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 1019 | enum mac80211_rate_control_flags mac_flags; | 1065 | enum mac80211_rate_control_flags mac_flags; |
| 1020 | u32 ucode_rate; | 1066 | u32 ucode_rate; |
| 1021 | struct rs_rate rate; | 1067 | struct rs_rate rate; |
| 1022 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; | 1068 | struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; |
| 1023 | u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0]; | 1069 | u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0]; |
| 1070 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 1071 | struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta; | ||
| 1024 | 1072 | ||
| 1025 | /* Treat uninitialized rate scaling data same as non-existing. */ | 1073 | /* Treat uninitialized rate scaling data same as non-existing. */ |
| 1026 | if (!lq_sta) { | 1074 | if (!lq_sta) { |
| @@ -1038,10 +1086,6 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
| 1038 | return; | 1086 | return; |
| 1039 | } | 1087 | } |
| 1040 | #endif | 1088 | #endif |
| 1041 | if (!ieee80211_is_data(hdr->frame_control) || | ||
| 1042 | info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
| 1043 | return; | ||
| 1044 | |||
| 1045 | /* This packet was aggregated but doesn't carry status info */ | 1089 | /* This packet was aggregated but doesn't carry status info */ |
| 1046 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 1090 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
| 1047 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | 1091 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) |
| @@ -1082,12 +1126,13 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
| 1082 | 1126 | ||
| 1083 | if (time_after(jiffies, | 1127 | if (time_after(jiffies, |
| 1084 | (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { | 1128 | (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { |
| 1085 | int tid; | 1129 | int t; |
| 1130 | |||
| 1086 | IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); | 1131 | IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); |
| 1087 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) | 1132 | for (t = 0; t < IWL_MAX_TID_COUNT; t++) |
| 1088 | ieee80211_stop_tx_ba_session(sta, tid); | 1133 | ieee80211_stop_tx_ba_session(sta, t); |
| 1089 | 1134 | ||
| 1090 | iwl_mvm_rs_rate_init(mvm, sta, sband->band, false); | 1135 | iwl_mvm_rs_rate_init(mvm, sta, info->band, false); |
| 1091 | return; | 1136 | return; |
| 1092 | } | 1137 | } |
| 1093 | lq_sta->last_tx = jiffies; | 1138 | lq_sta->last_tx = jiffies; |
| @@ -1126,16 +1171,15 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
| 1126 | /* Rate did match, so reset the missed_rate_counter */ | 1171 | /* Rate did match, so reset the missed_rate_counter */ |
| 1127 | lq_sta->missed_rate_counter = 0; | 1172 | lq_sta->missed_rate_counter = 0; |
| 1128 | 1173 | ||
| 1129 | /* Figure out if rate scale algorithm is in active or search table */ | 1174 | if (!lq_sta->search_better_tbl) { |
| 1130 | if (rs_rate_match(&rate, | ||
| 1131 | &(lq_sta->lq_info[lq_sta->active_tbl].rate))) { | ||
| 1132 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1175 | curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
| 1133 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1176 | other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
| 1134 | } else if (rs_rate_match(&rate, | 1177 | } else { |
| 1135 | &lq_sta->lq_info[1 - lq_sta->active_tbl].rate)) { | ||
| 1136 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); | 1178 | curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); |
| 1137 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1179 | other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
| 1138 | } else { | 1180 | } |
| 1181 | |||
| 1182 | if (WARN_ON_ONCE(!rs_rate_match(&rate, &curr_tbl->rate))) { | ||
| 1139 | IWL_DEBUG_RATE(mvm, | 1183 | IWL_DEBUG_RATE(mvm, |
| 1140 | "Neither active nor search matches tx rate\n"); | 1184 | "Neither active nor search matches tx rate\n"); |
| 1141 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1185 | tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
| @@ -1160,6 +1204,13 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
| 1160 | * first index into rate scale table. | 1204 | * first index into rate scale table. |
| 1161 | */ | 1205 | */ |
| 1162 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | 1206 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { |
| 1207 | /* ampdu_ack_len = 0 marks no BA was received. In this case | ||
| 1208 | * treat it as a single frame loss as we don't want the success | ||
| 1209 | * ratio to dip too quickly because a BA wasn't received | ||
| 1210 | */ | ||
| 1211 | if (info->status.ampdu_ack_len == 0) | ||
| 1212 | info->status.ampdu_len = 1; | ||
| 1213 | |||
| 1163 | ucode_rate = le32_to_cpu(table->rs_table[0]); | 1214 | ucode_rate = le32_to_cpu(table->rs_table[0]); |
| 1164 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); | 1215 | rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); |
| 1165 | rs_collect_tx_data(lq_sta, curr_tbl, rate.index, | 1216 | rs_collect_tx_data(lq_sta, curr_tbl, rate.index, |
| @@ -1214,8 +1265,28 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
| 1214 | IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); | 1265 | IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); |
| 1215 | done: | 1266 | done: |
| 1216 | /* See if there's a better rate or modulation mode to try. */ | 1267 | /* See if there's a better rate or modulation mode to try. */ |
| 1217 | if (sta && sta->supp_rates[sband->band]) | 1268 | if (sta->supp_rates[info->band]) |
| 1218 | rs_rate_scale_perform(mvm, skb, sta, lq_sta); | 1269 | rs_rate_scale_perform(mvm, sta, lq_sta, tid); |
| 1270 | } | ||
| 1271 | |||
| 1272 | /* | ||
| 1273 | * mac80211 sends us Tx status | ||
| 1274 | */ | ||
| 1275 | static void rs_mac80211_tx_status(void *mvm_r, | ||
| 1276 | struct ieee80211_supported_band *sband, | ||
| 1277 | struct ieee80211_sta *sta, void *priv_sta, | ||
| 1278 | struct sk_buff *skb) | ||
| 1279 | { | ||
| 1280 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 1281 | struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r; | ||
| 1282 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
| 1283 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 1284 | |||
| 1285 | if (!ieee80211_is_data(hdr->frame_control) || | ||
| 1286 | info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
| 1287 | return; | ||
| 1288 | |||
| 1289 | iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info); | ||
| 1219 | } | 1290 | } |
| 1220 | 1291 | ||
| 1221 | /* | 1292 | /* |
| @@ -1486,22 +1557,6 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm, | |||
| 1486 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); | 1557 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); |
| 1487 | } | 1558 | } |
| 1488 | 1559 | ||
| 1489 | static u8 rs_get_tid(struct iwl_lq_sta *lq_data, | ||
| 1490 | struct ieee80211_hdr *hdr) | ||
| 1491 | { | ||
| 1492 | u8 tid = IWL_MAX_TID_COUNT; | ||
| 1493 | |||
| 1494 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
| 1495 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
| 1496 | tid = qc[0] & 0xf; | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | if (unlikely(tid > IWL_MAX_TID_COUNT)) | ||
| 1500 | tid = IWL_MAX_TID_COUNT; | ||
| 1501 | |||
| 1502 | return tid; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, | 1560 | static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, |
| 1506 | struct iwl_lq_sta *lq_sta, | 1561 | struct iwl_lq_sta *lq_sta, |
| 1507 | struct ieee80211_sta *sta, | 1562 | struct ieee80211_sta *sta, |
| @@ -1608,6 +1663,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, | |||
| 1608 | else | 1663 | else |
| 1609 | rate->type = LQ_LEGACY_G; | 1664 | rate->type = LQ_LEGACY_G; |
| 1610 | 1665 | ||
| 1666 | rate->bw = RATE_MCS_CHAN_WIDTH_20; | ||
| 1667 | rate->ldpc = false; | ||
| 1611 | rate_mask = lq_sta->active_legacy_rate; | 1668 | rate_mask = lq_sta->active_legacy_rate; |
| 1612 | } else if (column->mode == RS_SISO) { | 1669 | } else if (column->mode == RS_SISO) { |
| 1613 | rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; | 1670 | rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; |
| @@ -1619,7 +1676,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, | |||
| 1619 | WARN_ON_ONCE("Bad column mode"); | 1676 | WARN_ON_ONCE("Bad column mode"); |
| 1620 | } | 1677 | } |
| 1621 | 1678 | ||
| 1622 | rate->bw = rs_bw_from_sta_bw(sta); | 1679 | if (column->mode != RS_LEGACY) { |
| 1680 | rate->bw = rs_bw_from_sta_bw(sta); | ||
| 1681 | rate->ldpc = lq_sta->ldpc; | ||
| 1682 | } | ||
| 1683 | |||
| 1623 | search_tbl->column = col_id; | 1684 | search_tbl->column = col_id; |
| 1624 | rs_set_expected_tpt_table(lq_sta, search_tbl); | 1685 | rs_set_expected_tpt_table(lq_sta, search_tbl); |
| 1625 | 1686 | ||
| @@ -1738,6 +1799,29 @@ out: | |||
| 1738 | return action; | 1799 | return action; |
| 1739 | } | 1800 | } |
| 1740 | 1801 | ||
| 1802 | static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
| 1803 | struct iwl_lq_sta *lq_sta) | ||
| 1804 | { | ||
| 1805 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 1806 | struct ieee80211_vif *vif = mvmsta->vif; | ||
| 1807 | bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION && | ||
| 1808 | !vif->bss_conf.ps); | ||
| 1809 | |||
| 1810 | /* Our chip supports Tx STBC and the peer is an HT/VHT STA which | ||
| 1811 | * supports STBC of at least 1*SS | ||
| 1812 | */ | ||
| 1813 | if (!lq_sta->stbc) | ||
| 1814 | return false; | ||
| 1815 | |||
| 1816 | if (!mvm->ps_disabled && !sta_ps_disabled) | ||
| 1817 | return false; | ||
| 1818 | |||
| 1819 | if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) | ||
| 1820 | return false; | ||
| 1821 | |||
| 1822 | return true; | ||
| 1823 | } | ||
| 1824 | |||
| 1741 | static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, | 1825 | static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, |
| 1742 | int *weaker, int *stronger) | 1826 | int *weaker, int *stronger) |
| 1743 | { | 1827 | { |
| @@ -1939,12 +2023,10 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, | |||
| 1939 | * Do rate scaling and search for new modulation mode. | 2023 | * Do rate scaling and search for new modulation mode. |
| 1940 | */ | 2024 | */ |
| 1941 | static void rs_rate_scale_perform(struct iwl_mvm *mvm, | 2025 | static void rs_rate_scale_perform(struct iwl_mvm *mvm, |
| 1942 | struct sk_buff *skb, | ||
| 1943 | struct ieee80211_sta *sta, | 2026 | struct ieee80211_sta *sta, |
| 1944 | struct iwl_lq_sta *lq_sta) | 2027 | struct iwl_lq_sta *lq_sta, |
| 2028 | int tid) | ||
| 1945 | { | 2029 | { |
| 1946 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 1947 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 1948 | int low = IWL_RATE_INVALID; | 2030 | int low = IWL_RATE_INVALID; |
| 1949 | int high = IWL_RATE_INVALID; | 2031 | int high = IWL_RATE_INVALID; |
| 1950 | int index; | 2032 | int index; |
| @@ -1961,29 +2043,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
| 1961 | u8 done_search = 0; | 2043 | u8 done_search = 0; |
| 1962 | u16 high_low; | 2044 | u16 high_low; |
| 1963 | s32 sr; | 2045 | s32 sr; |
| 1964 | u8 tid = IWL_MAX_TID_COUNT; | ||
| 1965 | u8 prev_agg = lq_sta->is_agg; | 2046 | u8 prev_agg = lq_sta->is_agg; |
| 1966 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; | 2047 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; |
| 1967 | struct iwl_mvm_tid_data *tid_data; | 2048 | struct iwl_mvm_tid_data *tid_data; |
| 1968 | struct rs_rate *rate; | 2049 | struct rs_rate *rate; |
| 1969 | 2050 | ||
| 1970 | /* Send management frames and NO_ACK data using lowest rate. */ | 2051 | lq_sta->is_agg = !!sta_priv->agg_tids; |
| 1971 | /* TODO: this could probably be improved.. */ | ||
| 1972 | if (!ieee80211_is_data(hdr->frame_control) || | ||
| 1973 | info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
| 1974 | return; | ||
| 1975 | |||
| 1976 | tid = rs_get_tid(lq_sta, hdr); | ||
| 1977 | if ((tid != IWL_MAX_TID_COUNT) && | ||
| 1978 | (lq_sta->tx_agg_tid_en & (1 << tid))) { | ||
| 1979 | tid_data = &sta_priv->tid_data[tid]; | ||
| 1980 | if (tid_data->state == IWL_AGG_OFF) | ||
| 1981 | lq_sta->is_agg = 0; | ||
| 1982 | else | ||
| 1983 | lq_sta->is_agg = 1; | ||
| 1984 | } else { | ||
| 1985 | lq_sta->is_agg = 0; | ||
| 1986 | } | ||
| 1987 | 2052 | ||
| 1988 | /* | 2053 | /* |
| 1989 | * Select rate-scale / modulation-mode table to work with in | 2054 | * Select rate-scale / modulation-mode table to work with in |
| @@ -2030,18 +2095,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
| 2030 | return; | 2095 | return; |
| 2031 | } | 2096 | } |
| 2032 | 2097 | ||
| 2033 | /* force user max rate if set by user */ | 2098 | /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ |
| 2034 | if ((lq_sta->max_rate_idx != -1) && | ||
| 2035 | (lq_sta->max_rate_idx < index)) { | ||
| 2036 | index = lq_sta->max_rate_idx; | ||
| 2037 | update_lq = 1; | ||
| 2038 | window = &(tbl->win[index]); | ||
| 2039 | IWL_DEBUG_RATE(mvm, | ||
| 2040 | "Forcing user max rate %d\n", | ||
| 2041 | index); | ||
| 2042 | goto lq_update; | ||
| 2043 | } | ||
| 2044 | |||
| 2045 | window = &(tbl->win[index]); | 2099 | window = &(tbl->win[index]); |
| 2046 | 2100 | ||
| 2047 | /* | 2101 | /* |
| @@ -2129,10 +2183,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
| 2129 | low = high_low & 0xff; | 2183 | low = high_low & 0xff; |
| 2130 | high = (high_low >> 8) & 0xff; | 2184 | high = (high_low >> 8) & 0xff; |
| 2131 | 2185 | ||
| 2132 | /* If user set max rate, dont allow higher than user constrain */ | 2186 | /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ |
| 2133 | if ((lq_sta->max_rate_idx != -1) && | ||
| 2134 | (lq_sta->max_rate_idx < high)) | ||
| 2135 | high = IWL_RATE_INVALID; | ||
| 2136 | 2187 | ||
| 2137 | sr = window->success_ratio; | 2188 | sr = window->success_ratio; |
| 2138 | 2189 | ||
| @@ -2294,6 +2345,110 @@ out: | |||
| 2294 | lq_sta->last_txrate_idx = index; | 2345 | lq_sta->last_txrate_idx = index; |
| 2295 | } | 2346 | } |
| 2296 | 2347 | ||
| 2348 | struct rs_init_rate_info { | ||
| 2349 | s8 rssi; | ||
| 2350 | u8 rate_idx; | ||
| 2351 | }; | ||
| 2352 | |||
| 2353 | static const struct rs_init_rate_info rs_init_rates_24ghz[] = { | ||
| 2354 | { -60, IWL_RATE_54M_INDEX }, | ||
| 2355 | { -64, IWL_RATE_48M_INDEX }, | ||
| 2356 | { -68, IWL_RATE_36M_INDEX }, | ||
| 2357 | { -80, IWL_RATE_24M_INDEX }, | ||
| 2358 | { -84, IWL_RATE_18M_INDEX }, | ||
| 2359 | { -85, IWL_RATE_12M_INDEX }, | ||
| 2360 | { -86, IWL_RATE_11M_INDEX }, | ||
| 2361 | { -88, IWL_RATE_5M_INDEX }, | ||
| 2362 | { -90, IWL_RATE_2M_INDEX }, | ||
| 2363 | { S8_MIN, IWL_RATE_1M_INDEX }, | ||
| 2364 | }; | ||
| 2365 | |||
| 2366 | static const struct rs_init_rate_info rs_init_rates_5ghz[] = { | ||
| 2367 | { -60, IWL_RATE_54M_INDEX }, | ||
| 2368 | { -64, IWL_RATE_48M_INDEX }, | ||
| 2369 | { -72, IWL_RATE_36M_INDEX }, | ||
| 2370 | { -80, IWL_RATE_24M_INDEX }, | ||
| 2371 | { -84, IWL_RATE_18M_INDEX }, | ||
| 2372 | { -85, IWL_RATE_12M_INDEX }, | ||
| 2373 | { -87, IWL_RATE_9M_INDEX }, | ||
| 2374 | { S8_MIN, IWL_RATE_6M_INDEX }, | ||
| 2375 | }; | ||
| 2376 | |||
| 2377 | /* Choose an initial legacy rate and antenna to use based on the RSSI | ||
| 2378 | * of last Rx | ||
| 2379 | */ | ||
| 2380 | static void rs_get_initial_rate(struct iwl_mvm *mvm, | ||
| 2381 | struct iwl_lq_sta *lq_sta, | ||
| 2382 | enum ieee80211_band band, | ||
| 2383 | struct rs_rate *rate) | ||
| 2384 | { | ||
| 2385 | int i, nentries; | ||
| 2386 | s8 best_rssi = S8_MIN; | ||
| 2387 | u8 best_ant = ANT_NONE; | ||
| 2388 | u8 valid_tx_ant = mvm->fw->valid_tx_ant; | ||
| 2389 | const struct rs_init_rate_info *initial_rates; | ||
| 2390 | |||
| 2391 | for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { | ||
| 2392 | if (!(lq_sta->pers.chains & BIT(i))) | ||
| 2393 | continue; | ||
| 2394 | |||
| 2395 | if (lq_sta->pers.chain_signal[i] > best_rssi) { | ||
| 2396 | best_rssi = lq_sta->pers.chain_signal[i]; | ||
| 2397 | best_ant = BIT(i); | ||
| 2398 | } | ||
| 2399 | } | ||
| 2400 | |||
| 2401 | IWL_DEBUG_RATE(mvm, "Best ANT: %s Best RSSI: %d\n", | ||
| 2402 | rs_pretty_ant(best_ant), best_rssi); | ||
| 2403 | |||
| 2404 | if (best_ant != ANT_A && best_ant != ANT_B) | ||
| 2405 | rate->ant = first_antenna(valid_tx_ant); | ||
| 2406 | else | ||
| 2407 | rate->ant = best_ant; | ||
| 2408 | |||
| 2409 | rate->sgi = false; | ||
| 2410 | rate->ldpc = false; | ||
| 2411 | rate->bw = RATE_MCS_CHAN_WIDTH_20; | ||
| 2412 | |||
| 2413 | rate->index = find_first_bit(&lq_sta->active_legacy_rate, | ||
| 2414 | BITS_PER_LONG); | ||
| 2415 | |||
| 2416 | if (band == IEEE80211_BAND_5GHZ) { | ||
| 2417 | rate->type = LQ_LEGACY_A; | ||
| 2418 | initial_rates = rs_init_rates_5ghz; | ||
| 2419 | nentries = ARRAY_SIZE(rs_init_rates_5ghz); | ||
| 2420 | } else { | ||
| 2421 | rate->type = LQ_LEGACY_G; | ||
| 2422 | initial_rates = rs_init_rates_24ghz; | ||
| 2423 | nentries = ARRAY_SIZE(rs_init_rates_24ghz); | ||
| 2424 | } | ||
| 2425 | |||
| 2426 | if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) { | ||
| 2427 | for (i = 0; i < nentries; i++) { | ||
| 2428 | int rate_idx = initial_rates[i].rate_idx; | ||
| 2429 | if ((best_rssi >= initial_rates[i].rssi) && | ||
| 2430 | (BIT(rate_idx) & lq_sta->active_legacy_rate)) { | ||
| 2431 | rate->index = rate_idx; | ||
| 2432 | break; | ||
| 2433 | } | ||
| 2434 | } | ||
| 2435 | } | ||
| 2436 | |||
| 2437 | IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index, | ||
| 2438 | rs_pretty_ant(rate->ant)); | ||
| 2439 | } | ||
| 2440 | |||
| 2441 | /* Save info about RSSI of last Rx */ | ||
| 2442 | void rs_update_last_rssi(struct iwl_mvm *mvm, | ||
| 2443 | struct iwl_lq_sta *lq_sta, | ||
| 2444 | struct ieee80211_rx_status *rx_status) | ||
| 2445 | { | ||
| 2446 | lq_sta->pers.chains = rx_status->chains; | ||
| 2447 | lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0]; | ||
| 2448 | lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1]; | ||
| 2449 | lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2]; | ||
| 2450 | } | ||
| 2451 | |||
| 2297 | /** | 2452 | /** |
| 2298 | * rs_initialize_lq - Initialize a station's hardware rate table | 2453 | * rs_initialize_lq - Initialize a station's hardware rate table |
| 2299 | * | 2454 | * |
| @@ -2316,17 +2471,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
| 2316 | { | 2471 | { |
| 2317 | struct iwl_scale_tbl_info *tbl; | 2472 | struct iwl_scale_tbl_info *tbl; |
| 2318 | struct rs_rate *rate; | 2473 | struct rs_rate *rate; |
| 2319 | int i; | ||
| 2320 | u8 active_tbl = 0; | 2474 | u8 active_tbl = 0; |
| 2321 | u8 valid_tx_ant; | ||
| 2322 | 2475 | ||
| 2323 | if (!sta || !lq_sta) | 2476 | if (!sta || !lq_sta) |
| 2324 | return; | 2477 | return; |
| 2325 | 2478 | ||
| 2326 | i = lq_sta->last_txrate_idx; | ||
| 2327 | |||
| 2328 | valid_tx_ant = mvm->fw->valid_tx_ant; | ||
| 2329 | |||
| 2330 | if (!lq_sta->search_better_tbl) | 2479 | if (!lq_sta->search_better_tbl) |
| 2331 | active_tbl = lq_sta->active_tbl; | 2480 | active_tbl = lq_sta->active_tbl; |
| 2332 | else | 2481 | else |
| @@ -2335,17 +2484,8 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
| 2335 | tbl = &(lq_sta->lq_info[active_tbl]); | 2484 | tbl = &(lq_sta->lq_info[active_tbl]); |
| 2336 | rate = &tbl->rate; | 2485 | rate = &tbl->rate; |
| 2337 | 2486 | ||
| 2338 | if ((i < 0) || (i >= IWL_RATE_COUNT)) | 2487 | rs_get_initial_rate(mvm, lq_sta, band, rate); |
| 2339 | i = 0; | 2488 | lq_sta->last_txrate_idx = rate->index; |
| 2340 | |||
| 2341 | rate->index = i; | ||
| 2342 | rate->ant = first_antenna(valid_tx_ant); | ||
| 2343 | rate->sgi = false; | ||
| 2344 | rate->bw = RATE_MCS_CHAN_WIDTH_20; | ||
| 2345 | if (band == IEEE80211_BAND_5GHZ) | ||
| 2346 | rate->type = LQ_LEGACY_A; | ||
| 2347 | else | ||
| 2348 | rate->type = LQ_LEGACY_G; | ||
| 2349 | 2489 | ||
| 2350 | WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); | 2490 | WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); |
| 2351 | if (rate->ant == ANT_A) | 2491 | if (rate->ant == ANT_A) |
| @@ -2363,23 +2503,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | |||
| 2363 | struct ieee80211_tx_rate_control *txrc) | 2503 | struct ieee80211_tx_rate_control *txrc) |
| 2364 | { | 2504 | { |
| 2365 | struct sk_buff *skb = txrc->skb; | 2505 | struct sk_buff *skb = txrc->skb; |
| 2366 | struct ieee80211_supported_band *sband = txrc->sband; | ||
| 2367 | struct iwl_op_mode *op_mode __maybe_unused = | 2506 | struct iwl_op_mode *op_mode __maybe_unused = |
| 2368 | (struct iwl_op_mode *)mvm_r; | 2507 | (struct iwl_op_mode *)mvm_r; |
| 2369 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); | 2508 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); |
| 2370 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2509 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 2371 | struct iwl_lq_sta *lq_sta = mvm_sta; | 2510 | struct iwl_lq_sta *lq_sta = mvm_sta; |
| 2372 | 2511 | ||
| 2373 | /* Get max rate if user set max rate */ | 2512 | /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ |
| 2374 | if (lq_sta) { | ||
| 2375 | lq_sta->max_rate_idx = txrc->max_rate_idx; | ||
| 2376 | if ((sband->band == IEEE80211_BAND_5GHZ) && | ||
| 2377 | (lq_sta->max_rate_idx != -1)) | ||
| 2378 | lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; | ||
| 2379 | if ((lq_sta->max_rate_idx < 0) || | ||
| 2380 | (lq_sta->max_rate_idx >= IWL_RATE_COUNT)) | ||
| 2381 | lq_sta->max_rate_idx = -1; | ||
| 2382 | } | ||
| 2383 | 2513 | ||
| 2384 | /* Treat uninitialized rate scaling data same as non-existing. */ | 2514 | /* Treat uninitialized rate scaling data same as non-existing. */ |
| 2385 | if (lq_sta && !lq_sta->pers.drv) { | 2515 | if (lq_sta && !lq_sta->pers.drv) { |
| @@ -2412,6 +2542,8 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, | |||
| 2412 | lq_sta->pers.dbg_fixed_rate = 0; | 2542 | lq_sta->pers.dbg_fixed_rate = 0; |
| 2413 | lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID; | 2543 | lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID; |
| 2414 | #endif | 2544 | #endif |
| 2545 | lq_sta->pers.chains = 0; | ||
| 2546 | memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); | ||
| 2415 | 2547 | ||
| 2416 | return &sta_priv->lq_sta; | 2548 | return &sta_priv->lq_sta; |
| 2417 | } | 2549 | } |
| @@ -2580,7 +2712,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
| 2580 | * previous packets? Need to have IEEE 802.1X auth succeed immediately | 2712 | * previous packets? Need to have IEEE 802.1X auth succeed immediately |
| 2581 | * after assoc.. */ | 2713 | * after assoc.. */ |
| 2582 | 2714 | ||
| 2583 | lq_sta->max_rate_idx = -1; | ||
| 2584 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; | 2715 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; |
| 2585 | lq_sta->band = sband->band; | 2716 | lq_sta->band = sband->band; |
| 2586 | /* | 2717 | /* |
| @@ -2609,11 +2740,31 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
| 2609 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; | 2740 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; |
| 2610 | 2741 | ||
| 2611 | lq_sta->is_vht = false; | 2742 | lq_sta->is_vht = false; |
| 2743 | if (mvm->cfg->ht_params->ldpc && | ||
| 2744 | (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) | ||
| 2745 | lq_sta->ldpc = true; | ||
| 2746 | |||
| 2747 | if (mvm->cfg->ht_params->stbc && | ||
| 2748 | (num_of_ant(mvm->fw->valid_tx_ant) > 1) && | ||
| 2749 | (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) | ||
| 2750 | lq_sta->stbc = true; | ||
| 2612 | } else { | 2751 | } else { |
| 2613 | rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); | 2752 | rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); |
| 2614 | lq_sta->is_vht = true; | 2753 | lq_sta->is_vht = true; |
| 2754 | |||
| 2755 | if (mvm->cfg->ht_params->ldpc && | ||
| 2756 | (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) | ||
| 2757 | lq_sta->ldpc = true; | ||
| 2758 | |||
| 2759 | if (mvm->cfg->ht_params->stbc && | ||
| 2760 | (num_of_ant(mvm->fw->valid_tx_ant) > 1) && | ||
| 2761 | (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) | ||
| 2762 | lq_sta->stbc = true; | ||
| 2615 | } | 2763 | } |
| 2616 | 2764 | ||
| 2765 | if (IWL_MVM_RS_DISABLE_MIMO) | ||
| 2766 | lq_sta->active_mimo2_rate = 0; | ||
| 2767 | |||
| 2617 | lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, | 2768 | lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, |
| 2618 | BITS_PER_LONG); | 2769 | BITS_PER_LONG); |
| 2619 | lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, | 2770 | lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, |
| @@ -2621,11 +2772,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
| 2621 | lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, | 2772 | lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, |
| 2622 | BITS_PER_LONG); | 2773 | BITS_PER_LONG); |
| 2623 | 2774 | ||
| 2624 | IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n", | 2775 | IWL_DEBUG_RATE(mvm, |
| 2776 | "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n", | ||
| 2625 | lq_sta->active_legacy_rate, | 2777 | lq_sta->active_legacy_rate, |
| 2626 | lq_sta->active_siso_rate, | 2778 | lq_sta->active_siso_rate, |
| 2627 | lq_sta->active_mimo2_rate, | 2779 | lq_sta->active_mimo2_rate, |
| 2628 | lq_sta->is_vht); | 2780 | lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc); |
| 2629 | IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", | 2781 | IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", |
| 2630 | lq_sta->max_legacy_rate_idx, | 2782 | lq_sta->max_legacy_rate_idx, |
| 2631 | lq_sta->max_siso_rate_idx, | 2783 | lq_sta->max_siso_rate_idx, |
| @@ -2638,11 +2790,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
| 2638 | 2790 | ||
| 2639 | /* as default allow aggregation for all tids */ | 2791 | /* as default allow aggregation for all tids */ |
| 2640 | lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; | 2792 | lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; |
| 2641 | |||
| 2642 | /* Set last_txrate_idx to lowest rate */ | ||
| 2643 | lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); | ||
| 2644 | if (sband->band == IEEE80211_BAND_5GHZ) | ||
| 2645 | lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; | ||
| 2646 | lq_sta->is_agg = 0; | 2793 | lq_sta->is_agg = 0; |
| 2647 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 2794 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| 2648 | iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); | 2795 | iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); |
| @@ -2678,6 +2825,7 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, | |||
| 2678 | int i; | 2825 | int i; |
| 2679 | int num_rates = ARRAY_SIZE(lq_cmd->rs_table); | 2826 | int num_rates = ARRAY_SIZE(lq_cmd->rs_table); |
| 2680 | __le32 ucode_rate_le32 = cpu_to_le32(ucode_rate); | 2827 | __le32 ucode_rate_le32 = cpu_to_le32(ucode_rate); |
| 2828 | u8 ant = (ucode_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; | ||
| 2681 | 2829 | ||
| 2682 | for (i = 0; i < num_rates; i++) | 2830 | for (i = 0; i < num_rates; i++) |
| 2683 | lq_cmd->rs_table[i] = ucode_rate_le32; | 2831 | lq_cmd->rs_table[i] = ucode_rate_le32; |
| @@ -2688,6 +2836,13 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, | |||
| 2688 | lq_cmd->mimo_delim = num_rates - 1; | 2836 | lq_cmd->mimo_delim = num_rates - 1; |
| 2689 | else | 2837 | else |
| 2690 | lq_cmd->mimo_delim = 0; | 2838 | lq_cmd->mimo_delim = 0; |
| 2839 | |||
| 2840 | lq_cmd->reduced_tpc = 0; | ||
| 2841 | |||
| 2842 | if (num_of_ant(ant) == 1) | ||
| 2843 | lq_cmd->single_stream_ant_msk = ant; | ||
| 2844 | |||
| 2845 | lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; | ||
| 2691 | } | 2846 | } |
| 2692 | #endif /* CONFIG_MAC80211_DEBUGFS */ | 2847 | #endif /* CONFIG_MAC80211_DEBUGFS */ |
| 2693 | 2848 | ||
| @@ -2746,6 +2901,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, | |||
| 2746 | * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps | 2901 | * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps |
| 2747 | */ | 2902 | */ |
| 2748 | static void rs_build_rates_table(struct iwl_mvm *mvm, | 2903 | static void rs_build_rates_table(struct iwl_mvm *mvm, |
| 2904 | struct ieee80211_sta *sta, | ||
| 2749 | struct iwl_lq_sta *lq_sta, | 2905 | struct iwl_lq_sta *lq_sta, |
| 2750 | const struct rs_rate *initial_rate) | 2906 | const struct rs_rate *initial_rate) |
| 2751 | { | 2907 | { |
| @@ -2758,6 +2914,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, | |||
| 2758 | memcpy(&rate, initial_rate, sizeof(rate)); | 2914 | memcpy(&rate, initial_rate, sizeof(rate)); |
| 2759 | 2915 | ||
| 2760 | valid_tx_ant = mvm->fw->valid_tx_ant; | 2916 | valid_tx_ant = mvm->fw->valid_tx_ant; |
| 2917 | rate.stbc = rs_stbc_allow(mvm, sta, lq_sta); | ||
| 2761 | 2918 | ||
| 2762 | if (is_siso(&rate)) { | 2919 | if (is_siso(&rate)) { |
| 2763 | num_rates = RS_INITIAL_SISO_NUM_RATES; | 2920 | num_rates = RS_INITIAL_SISO_NUM_RATES; |
| @@ -2811,31 +2968,55 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, | |||
| 2811 | const struct rs_rate *initial_rate) | 2968 | const struct rs_rate *initial_rate) |
| 2812 | { | 2969 | { |
| 2813 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; | 2970 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; |
| 2814 | u8 ant = initial_rate->ant; | 2971 | struct iwl_mvm_sta *mvmsta; |
| 2972 | struct iwl_mvm_vif *mvmvif; | ||
| 2973 | |||
| 2974 | lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
| 2975 | lq_cmd->agg_time_limit = | ||
| 2976 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
| 2815 | 2977 | ||
| 2816 | #ifdef CONFIG_MAC80211_DEBUGFS | 2978 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 2817 | if (lq_sta->pers.dbg_fixed_rate) { | 2979 | if (lq_sta->pers.dbg_fixed_rate) { |
| 2818 | rs_build_rates_table_from_fixed(mvm, lq_cmd, | 2980 | rs_build_rates_table_from_fixed(mvm, lq_cmd, |
| 2819 | lq_sta->band, | 2981 | lq_sta->band, |
| 2820 | lq_sta->pers.dbg_fixed_rate); | 2982 | lq_sta->pers.dbg_fixed_rate); |
| 2821 | lq_cmd->reduced_tpc = 0; | 2983 | return; |
| 2822 | ant = (lq_sta->pers.dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >> | 2984 | } |
| 2823 | RATE_MCS_ANT_POS; | ||
| 2824 | } else | ||
| 2825 | #endif | 2985 | #endif |
| 2826 | rs_build_rates_table(mvm, lq_sta, initial_rate); | 2986 | if (WARN_ON_ONCE(!sta || !initial_rate)) |
| 2987 | return; | ||
| 2827 | 2988 | ||
| 2828 | if (num_of_ant(ant) == 1) | 2989 | rs_build_rates_table(mvm, sta, lq_sta, initial_rate); |
| 2829 | lq_cmd->single_stream_ant_msk = ant; | ||
| 2830 | 2990 | ||
| 2831 | lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; | 2991 | if (num_of_ant(initial_rate->ant) == 1) |
| 2832 | lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | 2992 | lq_cmd->single_stream_ant_msk = initial_rate->ant; |
| 2833 | 2993 | ||
| 2834 | lq_cmd->agg_time_limit = | 2994 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
| 2835 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | 2995 | mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); |
| 2996 | |||
| 2997 | if (num_of_ant(initial_rate->ant) == 1) | ||
| 2998 | lq_cmd->single_stream_ant_msk = initial_rate->ant; | ||
| 2836 | 2999 | ||
| 2837 | if (sta) | 3000 | lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize; |
| 2838 | lq_cmd->agg_time_limit = | 3001 | |
| 3002 | /* | ||
| 3003 | * In case of low latency, tell the firwmare to leave a frame in the | ||
| 3004 | * Tx Fifo so that it can start a transaction in the same TxOP. This | ||
| 3005 | * basically allows the firmware to send bursts. | ||
| 3006 | */ | ||
| 3007 | if (iwl_mvm_vif_low_latency(mvmvif)) { | ||
| 3008 | lq_cmd->agg_frame_cnt_limit--; | ||
| 3009 | |||
| 3010 | if (mvm->low_latency_agg_frame_limit) | ||
| 3011 | lq_cmd->agg_frame_cnt_limit = | ||
| 3012 | min(lq_cmd->agg_frame_cnt_limit, | ||
| 3013 | mvm->low_latency_agg_frame_limit); | ||
| 3014 | } | ||
| 3015 | |||
| 3016 | if (mvmsta->vif->p2p) | ||
| 3017 | lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK; | ||
| 3018 | |||
| 3019 | lq_cmd->agg_time_limit = | ||
| 2839 | cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); | 3020 | cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); |
| 2840 | } | 3021 | } |
| 2841 | 3022 | ||
| @@ -2932,10 +3113,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, | |||
| 2932 | lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate); | 3113 | lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate); |
| 2933 | 3114 | ||
| 2934 | if (lq_sta->pers.dbg_fixed_rate) { | 3115 | if (lq_sta->pers.dbg_fixed_rate) { |
| 2935 | struct rs_rate rate; | 3116 | rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL); |
| 2936 | rs_rate_from_ucode_rate(lq_sta->pers.dbg_fixed_rate, | ||
| 2937 | lq_sta->band, &rate); | ||
| 2938 | rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate); | ||
| 2939 | iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false); | 3117 | iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false); |
| 2940 | } | 3118 | } |
| 2941 | } | 3119 | } |
| @@ -3002,8 +3180,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
| 3002 | (is_ht20(rate)) ? "20MHz" : | 3180 | (is_ht20(rate)) ? "20MHz" : |
| 3003 | (is_ht40(rate)) ? "40MHz" : | 3181 | (is_ht40(rate)) ? "40MHz" : |
| 3004 | (is_ht80(rate)) ? "80Mhz" : "BAD BW"); | 3182 | (is_ht80(rate)) ? "80Mhz" : "BAD BW"); |
| 3005 | desc += sprintf(buff+desc, " %s %s\n", | 3183 | desc += sprintf(buff+desc, " %s %s %s\n", |
| 3006 | (rate->sgi) ? "SGI" : "NGI", | 3184 | (rate->sgi) ? "SGI" : "NGI", |
| 3185 | (rate->ldpc) ? "LDPC" : "BCC", | ||
| 3007 | (lq_sta->is_agg) ? "AGG on" : ""); | 3186 | (lq_sta->is_agg) ? "AGG on" : ""); |
| 3008 | } | 3187 | } |
| 3009 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", | 3188 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", |
| @@ -3151,7 +3330,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file, | |||
| 3151 | "%s,", column_name[col]); | 3330 | "%s,", column_name[col]); |
| 3152 | 3331 | ||
| 3153 | for (rate = 0; rate < IWL_RATE_COUNT; rate++) { | 3332 | for (rate = 0; rate < IWL_RATE_COUNT; rate++) { |
| 3154 | stats = &(lq_sta->tx_stats[col][rate]); | 3333 | stats = &(lq_sta->pers.tx_stats[col][rate]); |
| 3155 | pos += scnprintf(pos, endpos - pos, | 3334 | pos += scnprintf(pos, endpos - pos, |
| 3156 | "%llu/%llu,", | 3335 | "%llu/%llu,", |
| 3157 | stats->success, | 3336 | stats->success, |
| @@ -3170,7 +3349,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file, | |||
| 3170 | size_t count, loff_t *ppos) | 3349 | size_t count, loff_t *ppos) |
| 3171 | { | 3350 | { |
| 3172 | struct iwl_lq_sta *lq_sta = file->private_data; | 3351 | struct iwl_lq_sta *lq_sta = file->private_data; |
| 3173 | memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats)); | 3352 | memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats)); |
| 3174 | 3353 | ||
| 3175 | return count; | 3354 | return count; |
| 3176 | } | 3355 | } |
| @@ -3216,7 +3395,7 @@ static void rs_rate_init_stub(void *mvm_r, | |||
| 3216 | 3395 | ||
| 3217 | static const struct rate_control_ops rs_mvm_ops = { | 3396 | static const struct rate_control_ops rs_mvm_ops = { |
| 3218 | .name = RS_NAME, | 3397 | .name = RS_NAME, |
| 3219 | .tx_status = rs_tx_status, | 3398 | .tx_status = rs_mac80211_tx_status, |
| 3220 | .get_rate = rs_get_rate, | 3399 | .get_rate = rs_get_rate, |
| 3221 | .rate_init = rs_rate_init_stub, | 3400 | .rate_init = rs_rate_init_stub, |
| 3222 | .alloc = rs_alloc, | 3401 | .alloc = rs_alloc, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index f27b9d687a25..defd70a6d9e6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
| @@ -207,6 +207,8 @@ struct rs_rate { | |||
| 207 | u8 ant; | 207 | u8 ant; |
| 208 | u32 bw; | 208 | u32 bw; |
| 209 | bool sgi; | 209 | bool sgi; |
| 210 | bool ldpc; | ||
| 211 | bool stbc; | ||
| 210 | }; | 212 | }; |
| 211 | 213 | ||
| 212 | 214 | ||
| @@ -329,10 +331,10 @@ struct iwl_lq_sta { | |||
| 329 | */ | 331 | */ |
| 330 | u64 last_tx; | 332 | u64 last_tx; |
| 331 | bool is_vht; | 333 | bool is_vht; |
| 334 | bool ldpc; /* LDPC Rx is supported by the STA */ | ||
| 335 | bool stbc; /* Tx STBC is supported by chip and Rx by STA */ | ||
| 332 | enum ieee80211_band band; | 336 | enum ieee80211_band band; |
| 333 | 337 | ||
| 334 | struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; | ||
| 335 | |||
| 336 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ | 338 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ |
| 337 | unsigned long active_legacy_rate; | 339 | unsigned long active_legacy_rate; |
| 338 | unsigned long active_siso_rate; | 340 | unsigned long active_siso_rate; |
| @@ -343,7 +345,6 @@ struct iwl_lq_sta { | |||
| 343 | u8 max_siso_rate_idx; | 345 | u8 max_siso_rate_idx; |
| 344 | u8 max_mimo2_rate_idx; | 346 | u8 max_mimo2_rate_idx; |
| 345 | 347 | ||
| 346 | s8 max_rate_idx; /* Max rate set by user */ | ||
| 347 | u8 missed_rate_counter; | 348 | u8 missed_rate_counter; |
| 348 | 349 | ||
| 349 | struct iwl_lq_cmd lq; | 350 | struct iwl_lq_cmd lq; |
| @@ -361,11 +362,14 @@ struct iwl_lq_sta { | |||
| 361 | int tpc_reduce; | 362 | int tpc_reduce; |
| 362 | 363 | ||
| 363 | /* persistent fields - initialized only once - keep last! */ | 364 | /* persistent fields - initialized only once - keep last! */ |
| 364 | struct { | 365 | struct lq_sta_pers { |
| 365 | #ifdef CONFIG_MAC80211_DEBUGFS | 366 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 366 | u32 dbg_fixed_rate; | 367 | u32 dbg_fixed_rate; |
| 367 | u8 dbg_fixed_txp_reduction; | 368 | u8 dbg_fixed_txp_reduction; |
| 368 | #endif | 369 | #endif |
| 370 | u8 chains; | ||
| 371 | s8 chain_signal[IEEE80211_MAX_CHAINS]; | ||
| 372 | struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; | ||
| 369 | struct iwl_mvm *drv; | 373 | struct iwl_mvm *drv; |
| 370 | } pers; | 374 | } pers; |
| 371 | }; | 375 | }; |
| @@ -374,6 +378,10 @@ struct iwl_lq_sta { | |||
| 374 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 378 | void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
| 375 | enum ieee80211_band band, bool init); | 379 | enum ieee80211_band band, bool init); |
| 376 | 380 | ||
| 381 | /* Notify RS about Tx status */ | ||
| 382 | void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||
| 383 | int tid, struct ieee80211_tx_info *info); | ||
| 384 | |||
| 377 | /** | 385 | /** |
| 378 | * iwl_rate_control_register - Register the rate control algorithm callbacks | 386 | * iwl_rate_control_register - Register the rate control algorithm callbacks |
| 379 | * | 387 | * |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index bf5cd8c8b0f7..94b6e7297a1e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -94,27 +96,27 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 94 | * Adds the rxb to a new skb and give it to mac80211 | 96 | * Adds the rxb to a new skb and give it to mac80211 |
| 95 | */ | 97 | */ |
| 96 | static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | 98 | static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, |
| 99 | struct sk_buff *skb, | ||
| 97 | struct ieee80211_hdr *hdr, u16 len, | 100 | struct ieee80211_hdr *hdr, u16 len, |
| 98 | u32 ampdu_status, | 101 | u32 ampdu_status, u8 crypt_len, |
| 99 | struct iwl_rx_cmd_buffer *rxb, | 102 | struct iwl_rx_cmd_buffer *rxb) |
| 100 | struct ieee80211_rx_status *stats) | ||
| 101 | { | 103 | { |
| 102 | struct sk_buff *skb; | ||
| 103 | unsigned int hdrlen, fraglen; | 104 | unsigned int hdrlen, fraglen; |
| 104 | 105 | ||
| 105 | /* Dont use dev_alloc_skb(), we'll have enough headroom once | ||
| 106 | * ieee80211_hdr pulled. | ||
| 107 | */ | ||
| 108 | skb = alloc_skb(128, GFP_ATOMIC); | ||
| 109 | if (!skb) { | ||
| 110 | IWL_ERR(mvm, "alloc_skb failed\n"); | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | /* If frame is small enough to fit in skb->head, pull it completely. | 106 | /* If frame is small enough to fit in skb->head, pull it completely. |
| 114 | * If not, only pull ieee80211_hdr so that splice() or TCP coalesce | 107 | * If not, only pull ieee80211_hdr (including crypto if present, and |
| 115 | * are more efficient. | 108 | * an additional 8 bytes for SNAP/ethertype, see below) so that |
| 109 | * splice() or TCP coalesce are more efficient. | ||
| 110 | * | ||
| 111 | * Since, in addition, ieee80211_data_to_8023() always pull in at | ||
| 112 | * least 8 bytes (possibly more for mesh) we can do the same here | ||
| 113 | * to save the cost of doing it later. That still doesn't pull in | ||
| 114 | * the actual IP header since the typical case has a SNAP header. | ||
| 115 | * If the latter changes (there are efforts in the standards group | ||
| 116 | * to do so) we should revisit this and ieee80211_data_to_8023(). | ||
| 116 | */ | 117 | */ |
| 117 | hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); | 118 | hdrlen = (len <= skb_tailroom(skb)) ? len : |
| 119 | sizeof(*hdr) + crypt_len + 8; | ||
| 118 | 120 | ||
| 119 | memcpy(skb_put(skb, hdrlen), hdr, hdrlen); | 121 | memcpy(skb_put(skb, hdrlen), hdr, hdrlen); |
| 120 | fraglen = len - hdrlen; | 122 | fraglen = len - hdrlen; |
| @@ -127,8 +129,6 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
| 127 | fraglen, rxb->truesize); | 129 | fraglen, rxb->truesize); |
| 128 | } | 130 | } |
| 129 | 131 | ||
| 130 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||
| 131 | |||
| 132 | ieee80211_rx(mvm->hw, skb); | 132 | ieee80211_rx(mvm->hw, skb); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| @@ -183,7 +183,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, | |||
| 183 | static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | 183 | static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, |
| 184 | struct ieee80211_hdr *hdr, | 184 | struct ieee80211_hdr *hdr, |
| 185 | struct ieee80211_rx_status *stats, | 185 | struct ieee80211_rx_status *stats, |
| 186 | u32 rx_pkt_status) | 186 | u32 rx_pkt_status, |
| 187 | u8 *crypt_len) | ||
| 187 | { | 188 | { |
| 188 | if (!ieee80211_has_protected(hdr->frame_control) || | 189 | if (!ieee80211_has_protected(hdr->frame_control) || |
| 189 | (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == | 190 | (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == |
| @@ -203,12 +204,14 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | |||
| 203 | 204 | ||
| 204 | stats->flag |= RX_FLAG_DECRYPTED; | 205 | stats->flag |= RX_FLAG_DECRYPTED; |
| 205 | IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n"); | 206 | IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n"); |
| 207 | *crypt_len = IEEE80211_CCMP_HDR_LEN; | ||
| 206 | return 0; | 208 | return 0; |
| 207 | 209 | ||
| 208 | case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: | 210 | case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: |
| 209 | /* Don't drop the frame and decrypt it in SW */ | 211 | /* Don't drop the frame and decrypt it in SW */ |
| 210 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) | 212 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) |
| 211 | return 0; | 213 | return 0; |
| 214 | *crypt_len = IEEE80211_TKIP_IV_LEN; | ||
| 212 | /* fall through if TTAK OK */ | 215 | /* fall through if TTAK OK */ |
| 213 | 216 | ||
| 214 | case RX_MPDU_RES_STATUS_SEC_WEP_ENC: | 217 | case RX_MPDU_RES_STATUS_SEC_WEP_ENC: |
| @@ -216,6 +219,9 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, | |||
| 216 | return -1; | 219 | return -1; |
| 217 | 220 | ||
| 218 | stats->flag |= RX_FLAG_DECRYPTED; | 221 | stats->flag |= RX_FLAG_DECRYPTED; |
| 222 | if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == | ||
| 223 | RX_MPDU_RES_STATUS_SEC_WEP_ENC) | ||
| 224 | *crypt_len = IEEE80211_WEP_IV_LEN; | ||
| 219 | return 0; | 225 | return 0; |
| 220 | 226 | ||
| 221 | case RX_MPDU_RES_STATUS_SEC_EXT_ENC: | 227 | case RX_MPDU_RES_STATUS_SEC_EXT_ENC: |
| @@ -240,14 +246,17 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 240 | struct iwl_device_cmd *cmd) | 246 | struct iwl_device_cmd *cmd) |
| 241 | { | 247 | { |
| 242 | struct ieee80211_hdr *hdr; | 248 | struct ieee80211_hdr *hdr; |
| 243 | struct ieee80211_rx_status rx_status = {}; | 249 | struct ieee80211_rx_status *rx_status; |
| 244 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 250 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
| 245 | struct iwl_rx_phy_info *phy_info; | 251 | struct iwl_rx_phy_info *phy_info; |
| 246 | struct iwl_rx_mpdu_res_start *rx_res; | 252 | struct iwl_rx_mpdu_res_start *rx_res; |
| 253 | struct ieee80211_sta *sta; | ||
| 254 | struct sk_buff *skb; | ||
| 247 | u32 len; | 255 | u32 len; |
| 248 | u32 ampdu_status; | 256 | u32 ampdu_status; |
| 249 | u32 rate_n_flags; | 257 | u32 rate_n_flags; |
| 250 | u32 rx_pkt_status; | 258 | u32 rx_pkt_status; |
| 259 | u8 crypt_len = 0; | ||
| 251 | 260 | ||
| 252 | phy_info = &mvm->last_phy_info; | 261 | phy_info = &mvm->last_phy_info; |
| 253 | rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; | 262 | rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; |
| @@ -256,37 +265,32 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 256 | rx_pkt_status = le32_to_cpup((__le32 *) | 265 | rx_pkt_status = le32_to_cpup((__le32 *) |
| 257 | (pkt->data + sizeof(*rx_res) + len)); | 266 | (pkt->data + sizeof(*rx_res) + len)); |
| 258 | 267 | ||
| 259 | memset(&rx_status, 0, sizeof(rx_status)); | 268 | /* Dont use dev_alloc_skb(), we'll have enough headroom once |
| 260 | 269 | * ieee80211_hdr pulled. | |
| 261 | /* | ||
| 262 | * We have tx blocked stations (with CS bit). If we heard frames from | ||
| 263 | * a blocked station on a new channel we can TX to it again. | ||
| 264 | */ | 270 | */ |
| 265 | if (unlikely(mvm->csa_tx_block_bcn_timeout)) { | 271 | skb = alloc_skb(128, GFP_ATOMIC); |
| 266 | struct ieee80211_sta *sta; | 272 | if (!skb) { |
| 267 | 273 | IWL_ERR(mvm, "alloc_skb failed\n"); | |
| 268 | rcu_read_lock(); | 274 | return 0; |
| 269 | |||
| 270 | sta = ieee80211_find_sta( | ||
| 271 | rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2); | ||
| 272 | if (sta) | ||
| 273 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); | ||
| 274 | |||
| 275 | rcu_read_unlock(); | ||
| 276 | } | 275 | } |
| 277 | 276 | ||
| 277 | rx_status = IEEE80211_SKB_RXCB(skb); | ||
| 278 | |||
| 278 | /* | 279 | /* |
| 279 | * drop the packet if it has failed being decrypted by HW | 280 | * drop the packet if it has failed being decrypted by HW |
| 280 | */ | 281 | */ |
| 281 | if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) { | 282 | if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status, |
| 283 | &crypt_len)) { | ||
| 282 | IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", | 284 | IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", |
| 283 | rx_pkt_status); | 285 | rx_pkt_status); |
| 286 | kfree_skb(skb); | ||
| 284 | return 0; | 287 | return 0; |
| 285 | } | 288 | } |
| 286 | 289 | ||
| 287 | if ((unlikely(phy_info->cfg_phy_cnt > 20))) { | 290 | if ((unlikely(phy_info->cfg_phy_cnt > 20))) { |
| 288 | IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", | 291 | IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", |
| 289 | phy_info->cfg_phy_cnt); | 292 | phy_info->cfg_phy_cnt); |
| 293 | kfree_skb(skb); | ||
| 290 | return 0; | 294 | return 0; |
| 291 | } | 295 | } |
| 292 | 296 | ||
| @@ -297,35 +301,57 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 297 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || | 301 | if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || |
| 298 | !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { | 302 | !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { |
| 299 | IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); | 303 | IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); |
| 300 | rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; | 304 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; |
| 301 | } | 305 | } |
| 302 | 306 | ||
| 303 | /* This will be used in several places later */ | 307 | /* This will be used in several places later */ |
| 304 | rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); | 308 | rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); |
| 305 | 309 | ||
| 306 | /* rx_status carries information about the packet to mac80211 */ | 310 | /* rx_status carries information about the packet to mac80211 */ |
| 307 | rx_status.mactime = le64_to_cpu(phy_info->timestamp); | 311 | rx_status->mactime = le64_to_cpu(phy_info->timestamp); |
| 308 | rx_status.device_timestamp = le32_to_cpu(phy_info->system_timestamp); | 312 | rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp); |
| 309 | rx_status.band = | 313 | rx_status->band = |
| 310 | (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? | 314 | (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? |
| 311 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | 315 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; |
| 312 | rx_status.freq = | 316 | rx_status->freq = |
| 313 | ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), | 317 | ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), |
| 314 | rx_status.band); | 318 | rx_status->band); |
| 315 | /* | 319 | /* |
| 316 | * TSF as indicated by the fw is at INA time, but mac80211 expects the | 320 | * TSF as indicated by the fw is at INA time, but mac80211 expects the |
| 317 | * TSF at the beginning of the MPDU. | 321 | * TSF at the beginning of the MPDU. |
| 318 | */ | 322 | */ |
| 319 | /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ | 323 | /*rx_status->flag |= RX_FLAG_MACTIME_MPDU;*/ |
| 320 | 324 | ||
| 321 | iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); | 325 | iwl_mvm_get_signal_strength(mvm, phy_info, rx_status); |
| 322 | 326 | ||
| 323 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, | 327 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal, |
| 324 | (unsigned long long)rx_status.mactime); | 328 | (unsigned long long)rx_status->mactime); |
| 329 | |||
| 330 | rcu_read_lock(); | ||
| 331 | /* | ||
| 332 | * We have tx blocked stations (with CS bit). If we heard frames from | ||
| 333 | * a blocked station on a new channel we can TX to it again. | ||
| 334 | */ | ||
| 335 | if (unlikely(mvm->csa_tx_block_bcn_timeout)) { | ||
| 336 | sta = ieee80211_find_sta( | ||
| 337 | rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2); | ||
| 338 | if (sta) | ||
| 339 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); | ||
| 340 | } | ||
| 341 | |||
| 342 | /* This is fine since we don't support multiple AP interfaces */ | ||
| 343 | sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); | ||
| 344 | if (sta) { | ||
| 345 | struct iwl_mvm_sta *mvmsta; | ||
| 346 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 347 | rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); | ||
| 348 | } | ||
| 349 | |||
| 350 | rcu_read_unlock(); | ||
| 325 | 351 | ||
| 326 | /* set the preamble flag if appropriate */ | 352 | /* set the preamble flag if appropriate */ |
| 327 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) | 353 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) |
| 328 | rx_status.flag |= RX_FLAG_SHORTPRE; | 354 | rx_status->flag |= RX_FLAG_SHORTPRE; |
| 329 | 355 | ||
| 330 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { | 356 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { |
| 331 | /* | 357 | /* |
| @@ -333,8 +359,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 333 | * together since we get a single PHY response | 359 | * together since we get a single PHY response |
| 334 | * from the firmware for all of them | 360 | * from the firmware for all of them |
| 335 | */ | 361 | */ |
| 336 | rx_status.flag |= RX_FLAG_AMPDU_DETAILS; | 362 | rx_status->flag |= RX_FLAG_AMPDU_DETAILS; |
| 337 | rx_status.ampdu_reference = mvm->ampdu_ref; | 363 | rx_status->ampdu_reference = mvm->ampdu_ref; |
| 338 | } | 364 | } |
| 339 | 365 | ||
| 340 | /* Set up the HT phy flags */ | 366 | /* Set up the HT phy flags */ |
| @@ -342,50 +368,50 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 342 | case RATE_MCS_CHAN_WIDTH_20: | 368 | case RATE_MCS_CHAN_WIDTH_20: |
| 343 | break; | 369 | break; |
| 344 | case RATE_MCS_CHAN_WIDTH_40: | 370 | case RATE_MCS_CHAN_WIDTH_40: |
| 345 | rx_status.flag |= RX_FLAG_40MHZ; | 371 | rx_status->flag |= RX_FLAG_40MHZ; |
| 346 | break; | 372 | break; |
| 347 | case RATE_MCS_CHAN_WIDTH_80: | 373 | case RATE_MCS_CHAN_WIDTH_80: |
| 348 | rx_status.vht_flag |= RX_VHT_FLAG_80MHZ; | 374 | rx_status->vht_flag |= RX_VHT_FLAG_80MHZ; |
| 349 | break; | 375 | break; |
| 350 | case RATE_MCS_CHAN_WIDTH_160: | 376 | case RATE_MCS_CHAN_WIDTH_160: |
| 351 | rx_status.vht_flag |= RX_VHT_FLAG_160MHZ; | 377 | rx_status->vht_flag |= RX_VHT_FLAG_160MHZ; |
| 352 | break; | 378 | break; |
| 353 | } | 379 | } |
| 354 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 380 | if (rate_n_flags & RATE_MCS_SGI_MSK) |
| 355 | rx_status.flag |= RX_FLAG_SHORT_GI; | 381 | rx_status->flag |= RX_FLAG_SHORT_GI; |
| 356 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) | 382 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) |
| 357 | rx_status.flag |= RX_FLAG_HT_GF; | 383 | rx_status->flag |= RX_FLAG_HT_GF; |
| 358 | if (rate_n_flags & RATE_MCS_LDPC_MSK) | 384 | if (rate_n_flags & RATE_MCS_LDPC_MSK) |
| 359 | rx_status.flag |= RX_FLAG_LDPC; | 385 | rx_status->flag |= RX_FLAG_LDPC; |
| 360 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 386 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
| 361 | u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> | 387 | u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> |
| 362 | RATE_MCS_STBC_POS; | 388 | RATE_MCS_STBC_POS; |
| 363 | rx_status.flag |= RX_FLAG_HT; | 389 | rx_status->flag |= RX_FLAG_HT; |
| 364 | rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; | 390 | rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; |
| 365 | rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; | 391 | rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; |
| 366 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | 392 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { |
| 367 | u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> | 393 | u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> |
| 368 | RATE_MCS_STBC_POS; | 394 | RATE_MCS_STBC_POS; |
| 369 | rx_status.vht_nss = | 395 | rx_status->vht_nss = |
| 370 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | 396 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> |
| 371 | RATE_VHT_MCS_NSS_POS) + 1; | 397 | RATE_VHT_MCS_NSS_POS) + 1; |
| 372 | rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | 398 | rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; |
| 373 | rx_status.flag |= RX_FLAG_VHT; | 399 | rx_status->flag |= RX_FLAG_VHT; |
| 374 | rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; | 400 | rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; |
| 375 | if (rate_n_flags & RATE_MCS_BF_MSK) | 401 | if (rate_n_flags & RATE_MCS_BF_MSK) |
| 376 | rx_status.vht_flag |= RX_VHT_FLAG_BF; | 402 | rx_status->vht_flag |= RX_VHT_FLAG_BF; |
| 377 | } else { | 403 | } else { |
| 378 | rx_status.rate_idx = | 404 | rx_status->rate_idx = |
| 379 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | 405 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, |
| 380 | rx_status.band); | 406 | rx_status->band); |
| 381 | } | 407 | } |
| 382 | 408 | ||
| 383 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 409 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
| 384 | iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, | 410 | iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, |
| 385 | rx_status.flag & RX_FLAG_AMPDU_DETAILS); | 411 | rx_status->flag & RX_FLAG_AMPDU_DETAILS); |
| 386 | #endif | 412 | #endif |
| 387 | iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, | 413 | iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, |
| 388 | rxb, &rx_status); | 414 | crypt_len, rxb); |
| 389 | return 0; | 415 | return 0; |
| 390 | } | 416 | } |
| 391 | 417 | ||
| @@ -491,10 +517,8 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | |||
| 491 | .mvm = mvm, | 517 | .mvm = mvm, |
| 492 | }; | 518 | }; |
| 493 | 519 | ||
| 494 | if (mvm->temperature != le32_to_cpu(common->temperature)) { | 520 | iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(common->temperature)); |
| 495 | mvm->temperature = le32_to_cpu(common->temperature); | 521 | |
| 496 | iwl_mvm_tt_handler(mvm); | ||
| 497 | } | ||
| 498 | iwl_mvm_update_rx_statistics(mvm, stats); | 522 | iwl_mvm_update_rx_statistics(mvm, stats); |
| 499 | 523 | ||
| 500 | ieee80211_iterate_active_interfaces(mvm->hw, | 524 | ieee80211_iterate_active_interfaces(mvm->hw, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 004b1f5d0314..e5294d01181e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -81,15 +83,29 @@ struct iwl_mvm_scan_params { | |||
| 81 | } dwell[IEEE80211_NUM_BANDS]; | 83 | } dwell[IEEE80211_NUM_BANDS]; |
| 82 | }; | 84 | }; |
| 83 | 85 | ||
| 86 | enum iwl_umac_scan_uid_type { | ||
| 87 | IWL_UMAC_SCAN_UID_REG_SCAN = BIT(0), | ||
| 88 | IWL_UMAC_SCAN_UID_SCHED_SCAN = BIT(1), | ||
| 89 | IWL_UMAC_SCAN_UID_ALL = IWL_UMAC_SCAN_UID_REG_SCAN | | ||
| 90 | IWL_UMAC_SCAN_UID_SCHED_SCAN, | ||
| 91 | }; | ||
| 92 | |||
| 93 | static int iwl_umac_scan_stop(struct iwl_mvm *mvm, | ||
| 94 | enum iwl_umac_scan_uid_type type, bool notify); | ||
| 95 | |||
| 96 | static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) | ||
| 97 | { | ||
| 98 | if (mvm->scan_rx_ant != ANT_NONE) | ||
| 99 | return mvm->scan_rx_ant; | ||
| 100 | return mvm->fw->valid_rx_ant; | ||
| 101 | } | ||
| 102 | |||
| 84 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | 103 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) |
| 85 | { | 104 | { |
| 86 | u16 rx_chain; | 105 | u16 rx_chain; |
| 87 | u8 rx_ant; | 106 | u8 rx_ant; |
| 88 | 107 | ||
| 89 | if (mvm->scan_rx_ant != ANT_NONE) | 108 | rx_ant = iwl_mvm_scan_rx_ant(mvm); |
| 90 | rx_ant = mvm->scan_rx_ant; | ||
| 91 | else | ||
| 92 | rx_ant = mvm->fw->valid_rx_ant; | ||
| 93 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | 109 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; |
| 94 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | 110 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; |
| 95 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; | 111 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; |
| @@ -158,8 +174,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, | |||
| 158 | static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) | 174 | static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) |
| 159 | { | 175 | { |
| 160 | if (band == IEEE80211_BAND_2GHZ) | 176 | if (band == IEEE80211_BAND_2GHZ) |
| 161 | return 30 + 3 * (n_ssids + 1); | 177 | return 20 + 3 * (n_ssids + 1); |
| 162 | return 20 + 2 * (n_ssids + 1); | 178 | return 10 + 2 * (n_ssids + 1); |
| 163 | } | 179 | } |
| 164 | 180 | ||
| 165 | static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) | 181 | static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) |
| @@ -268,7 +284,8 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, | |||
| 268 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 284 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 269 | bool *global_bound = data; | 285 | bool *global_bound = data; |
| 270 | 286 | ||
| 271 | if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS) | 287 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt && |
| 288 | mvmvif->phy_ctxt->id < MAX_PHYS) | ||
| 272 | *global_bound = true; | 289 | *global_bound = true; |
| 273 | } | 290 | } |
| 274 | 291 | ||
| @@ -279,6 +296,7 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, | |||
| 279 | { | 296 | { |
| 280 | bool global_bound = false; | 297 | bool global_bound = false; |
| 281 | enum ieee80211_band band; | 298 | enum ieee80211_band band; |
| 299 | u8 frag_passive_dwell = 0; | ||
| 282 | 300 | ||
| 283 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 301 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
| 284 | IEEE80211_IFACE_ITER_NORMAL, | 302 | IEEE80211_IFACE_ITER_NORMAL, |
| @@ -288,12 +306,36 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, | |||
| 288 | if (!global_bound) | 306 | if (!global_bound) |
| 289 | goto not_bound; | 307 | goto not_bound; |
| 290 | 308 | ||
| 291 | params->suspend_time = 100; | 309 | params->suspend_time = 30; |
| 292 | params->max_out_time = 600; | 310 | params->max_out_time = 170; |
| 293 | 311 | ||
| 294 | if (iwl_mvm_low_latency(mvm)) { | 312 | if (iwl_mvm_low_latency(mvm)) { |
| 295 | params->suspend_time = 250; | 313 | if (mvm->fw->ucode_capa.api[0] & |
| 296 | params->max_out_time = 250; | 314 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN) { |
| 315 | params->suspend_time = 105; | ||
| 316 | params->max_out_time = 70; | ||
| 317 | frag_passive_dwell = 20; | ||
| 318 | } else { | ||
| 319 | params->suspend_time = 120; | ||
| 320 | params->max_out_time = 120; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] & | ||
| 325 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) { | ||
| 326 | /* | ||
| 327 | * P2P device scan should not be fragmented to avoid negative | ||
| 328 | * impact on P2P device discovery. Configure max_out_time to be | ||
| 329 | * equal to dwell time on passive channel. Take a longest | ||
| 330 | * possible value, one that corresponds to 2GHz band | ||
| 331 | */ | ||
| 332 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | ||
| 333 | u32 passive_dwell = | ||
| 334 | iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ); | ||
| 335 | params->max_out_time = passive_dwell; | ||
| 336 | } else { | ||
| 337 | params->passive_fragmented = true; | ||
| 338 | } | ||
| 297 | } | 339 | } |
| 298 | 340 | ||
| 299 | if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | 341 | if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
| @@ -302,12 +344,69 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, | |||
| 302 | not_bound: | 344 | not_bound: |
| 303 | 345 | ||
| 304 | for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { | 346 | for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { |
| 305 | params->dwell[band].passive = iwl_mvm_get_passive_dwell(band); | 347 | if (params->passive_fragmented) |
| 348 | params->dwell[band].passive = frag_passive_dwell; | ||
| 349 | else | ||
| 350 | params->dwell[band].passive = | ||
| 351 | iwl_mvm_get_passive_dwell(band); | ||
| 306 | params->dwell[band].active = iwl_mvm_get_active_dwell(band, | 352 | params->dwell[band].active = iwl_mvm_get_active_dwell(band, |
| 307 | n_ssids); | 353 | n_ssids); |
| 308 | } | 354 | } |
| 309 | } | 355 | } |
| 310 | 356 | ||
| 357 | static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) | ||
| 358 | { | ||
| 359 | /* require rrm scan whenever the fw supports it */ | ||
| 360 | return mvm->fw->ucode_capa.capa[0] & | ||
| 361 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT; | ||
| 362 | } | ||
| 363 | |||
| 364 | static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm, | ||
| 365 | bool is_sched_scan) | ||
| 366 | { | ||
| 367 | int max_probe_len; | ||
| 368 | |||
| 369 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
| 370 | max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE; | ||
| 371 | else | ||
| 372 | max_probe_len = mvm->fw->ucode_capa.max_probe_length; | ||
| 373 | |||
| 374 | /* we create the 802.11 header and SSID element */ | ||
| 375 | max_probe_len -= 24 + 2; | ||
| 376 | |||
| 377 | /* basic ssid is added only for hw_scan with and old api */ | ||
| 378 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) && | ||
| 379 | !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) && | ||
| 380 | !is_sched_scan) | ||
| 381 | max_probe_len -= 32; | ||
| 382 | |||
| 383 | /* DS parameter set element is added on 2.4GHZ band if required */ | ||
| 384 | if (iwl_mvm_rrm_scan_needed(mvm)) | ||
| 385 | max_probe_len -= 3; | ||
| 386 | |||
| 387 | return max_probe_len; | ||
| 388 | } | ||
| 389 | |||
| 390 | int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan) | ||
| 391 | { | ||
| 392 | int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan); | ||
| 393 | |||
| 394 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) | ||
| 395 | return max_ie_len; | ||
| 396 | |||
| 397 | /* TODO: [BUG] This function should return the maximum allowed size of | ||
| 398 | * scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs | ||
| 399 | * in the same command. So the correct implementation of this function | ||
| 400 | * is just iwl_mvm_max_scan_ie_fw_cmd_room() / 2. Currently the scan | ||
| 401 | * command has only 512 bytes and it would leave us with about 240 | ||
| 402 | * bytes for scan IEs, which is clearly not enough. So meanwhile | ||
| 403 | * we will report an incorrect value. This may result in a failure to | ||
| 404 | * issue a scan in unified_scan_lmac and unified_sched_scan_lmac | ||
| 405 | * functions with -ENOBUFS, if a large enough probe will be provided. | ||
| 406 | */ | ||
| 407 | return max_ie_len; | ||
| 408 | } | ||
| 409 | |||
| 311 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | 410 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, |
| 312 | struct ieee80211_vif *vif, | 411 | struct ieee80211_vif *vif, |
| 313 | struct cfg80211_scan_request *req) | 412 | struct cfg80211_scan_request *req) |
| @@ -379,7 +478,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
| 379 | basic_ssid ? 1 : 0); | 478 | basic_ssid ? 1 : 0); |
| 380 | 479 | ||
| 381 | cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | | 480 | cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | |
| 382 | TX_CMD_FLG_BT_DIS); | 481 | 3 << TX_CMD_FLG_BT_PRIO_POS); |
| 482 | |||
| 383 | cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; | 483 | cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; |
| 384 | cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); | 484 | cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); |
| 385 | cmd->tx_cmd.rate_n_flags = | 485 | cmd->tx_cmd.rate_n_flags = |
| @@ -455,23 +555,17 @@ int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, | |||
| 455 | struct iwl_device_cmd *cmd) | 555 | struct iwl_device_cmd *cmd) |
| 456 | { | 556 | { |
| 457 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 557 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
| 458 | u8 client_bitmap = 0; | ||
| 459 | 558 | ||
| 460 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | 559 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) && |
| 560 | !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | ||
| 461 | struct iwl_sched_scan_results *notif = (void *)pkt->data; | 561 | struct iwl_sched_scan_results *notif = (void *)pkt->data; |
| 462 | 562 | ||
| 463 | client_bitmap = notif->client_bitmap; | 563 | if (!(notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN)) |
| 564 | return 0; | ||
| 464 | } | 565 | } |
| 465 | 566 | ||
| 466 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || | 567 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); |
| 467 | client_bitmap & SCAN_CLIENT_SCHED_SCAN) { | 568 | ieee80211_sched_scan_results(mvm->hw); |
| 468 | if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { | ||
| 469 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); | ||
| 470 | ieee80211_sched_scan_results(mvm->hw); | ||
| 471 | } else { | ||
| 472 | IWL_DEBUG_SCAN(mvm, "Scan results\n"); | ||
| 473 | } | ||
| 474 | } | ||
| 475 | 569 | ||
| 476 | return 0; | 570 | return 0; |
| 477 | } | 571 | } |
| @@ -521,16 +615,6 @@ static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm) | |||
| 521 | SCAN_COMPLETE_NOTIFICATION }; | 615 | SCAN_COMPLETE_NOTIFICATION }; |
| 522 | int ret; | 616 | int ret; |
| 523 | 617 | ||
| 524 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | ||
| 525 | return 0; | ||
| 526 | |||
| 527 | if (iwl_mvm_is_radio_killed(mvm)) { | ||
| 528 | ieee80211_scan_completed(mvm->hw, true); | ||
| 529 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 530 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, | 618 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, |
| 535 | scan_abort_notif, | 619 | scan_abort_notif, |
| 536 | ARRAY_SIZE(scan_abort_notif), | 620 | ARRAY_SIZE(scan_abort_notif), |
| @@ -591,6 +675,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | |||
| 591 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 675 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
| 592 | ieee80211_scan_completed(mvm->hw, | 676 | ieee80211_scan_completed(mvm->hw, |
| 593 | status == IWL_SCAN_OFFLOAD_ABORTED); | 677 | status == IWL_SCAN_OFFLOAD_ABORTED); |
| 678 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 594 | } | 679 | } |
| 595 | 680 | ||
| 596 | mvm->last_ebs_successful = !ebs_status; | 681 | mvm->last_ebs_successful = !ebs_status; |
| @@ -892,6 +977,20 @@ free_blacklist: | |||
| 892 | return ret; | 977 | return ret; |
| 893 | } | 978 | } |
| 894 | 979 | ||
| 980 | static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm, | ||
| 981 | struct cfg80211_sched_scan_request *req) | ||
| 982 | { | ||
| 983 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | ||
| 984 | IWL_DEBUG_SCAN(mvm, | ||
| 985 | "Sending scheduled scan with filtering, n_match_sets %d\n", | ||
| 986 | req->n_match_sets); | ||
| 987 | return false; | ||
| 988 | } | ||
| 989 | |||
| 990 | IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n"); | ||
| 991 | return true; | ||
| 992 | } | ||
| 993 | |||
| 895 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 994 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
| 896 | struct cfg80211_sched_scan_request *req) | 995 | struct cfg80211_sched_scan_request *req) |
| 897 | { | 996 | { |
| @@ -907,15 +1006,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | |||
| 907 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, | 1006 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, |
| 908 | }; | 1007 | }; |
| 909 | 1008 | ||
| 910 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | 1009 | if (iwl_mvm_scan_pass_all(mvm, req)) |
| 911 | IWL_DEBUG_SCAN(mvm, | ||
| 912 | "Sending scheduled scan with filtering, filter len %d\n", | ||
| 913 | req->n_match_sets); | ||
| 914 | } else { | ||
| 915 | IWL_DEBUG_SCAN(mvm, | ||
| 916 | "Sending Scheduled scan without filtering\n"); | ||
| 917 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); | 1010 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); |
| 918 | } | ||
| 919 | 1011 | ||
| 920 | if (mvm->last_ebs_successful && | 1012 | if (mvm->last_ebs_successful && |
| 921 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) | 1013 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) |
| @@ -926,6 +1018,38 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | |||
| 926 | sizeof(scan_req), &scan_req); | 1018 | sizeof(scan_req), &scan_req); |
| 927 | } | 1019 | } |
| 928 | 1020 | ||
| 1021 | int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm, | ||
| 1022 | struct ieee80211_vif *vif, | ||
| 1023 | struct cfg80211_sched_scan_request *req, | ||
| 1024 | struct ieee80211_scan_ies *ies) | ||
| 1025 | { | ||
| 1026 | int ret; | ||
| 1027 | |||
| 1028 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
| 1029 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
| 1030 | if (ret) | ||
| 1031 | return ret; | ||
| 1032 | ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies); | ||
| 1033 | } else if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | ||
| 1034 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
| 1035 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
| 1036 | if (ret) | ||
| 1037 | return ret; | ||
| 1038 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); | ||
| 1039 | } else { | ||
| 1040 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
| 1041 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); | ||
| 1042 | if (ret) | ||
| 1043 | return ret; | ||
| 1044 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
| 1045 | if (ret) | ||
| 1046 | return ret; | ||
| 1047 | ret = iwl_mvm_sched_scan_start(mvm, req); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | return ret; | ||
| 1051 | } | ||
| 1052 | |||
| 929 | static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm) | 1053 | static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm) |
| 930 | { | 1054 | { |
| 931 | int ret; | 1055 | int ret; |
| @@ -970,6 +1094,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
| 970 | 1094 | ||
| 971 | lockdep_assert_held(&mvm->mutex); | 1095 | lockdep_assert_held(&mvm->mutex); |
| 972 | 1096 | ||
| 1097 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
| 1098 | return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN, | ||
| 1099 | notify); | ||
| 1100 | |||
| 973 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && | 1101 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && |
| 974 | (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || | 1102 | (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || |
| 975 | mvm->scan_status != IWL_MVM_SCAN_OS)) { | 1103 | mvm->scan_status != IWL_MVM_SCAN_OS)) { |
| @@ -1000,8 +1128,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
| 1000 | /* | 1128 | /* |
| 1001 | * Clear the scan status so the next scan requests will succeed. This | 1129 | * Clear the scan status so the next scan requests will succeed. This |
| 1002 | * also ensures the Rx handler doesn't do anything, as the scan was | 1130 | * also ensures the Rx handler doesn't do anything, as the scan was |
| 1003 | * stopped from above. | 1131 | * stopped from above. Since the rx handler won't do anything now, |
| 1132 | * we have to release the scan reference here. | ||
| 1004 | */ | 1133 | */ |
| 1134 | if (mvm->scan_status == IWL_MVM_SCAN_OS) | ||
| 1135 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 1136 | |||
| 1005 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 1137 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
| 1006 | 1138 | ||
| 1007 | if (notify) { | 1139 | if (notify) { |
| @@ -1053,20 +1185,64 @@ iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm, | |||
| 1053 | } | 1185 | } |
| 1054 | } | 1186 | } |
| 1055 | 1187 | ||
| 1188 | static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies, | ||
| 1189 | size_t len, u8 *const pos) | ||
| 1190 | { | ||
| 1191 | static const u8 before_ds_params[] = { | ||
| 1192 | WLAN_EID_SSID, | ||
| 1193 | WLAN_EID_SUPP_RATES, | ||
| 1194 | WLAN_EID_REQUEST, | ||
| 1195 | WLAN_EID_EXT_SUPP_RATES, | ||
| 1196 | }; | ||
| 1197 | size_t offs; | ||
| 1198 | u8 *newpos = pos; | ||
| 1199 | |||
| 1200 | if (!iwl_mvm_rrm_scan_needed(mvm)) { | ||
| 1201 | memcpy(newpos, ies, len); | ||
| 1202 | return newpos + len; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | offs = ieee80211_ie_split(ies, len, | ||
| 1206 | before_ds_params, | ||
| 1207 | ARRAY_SIZE(before_ds_params), | ||
| 1208 | 0); | ||
| 1209 | |||
| 1210 | memcpy(newpos, ies, offs); | ||
| 1211 | newpos += offs; | ||
| 1212 | |||
| 1213 | /* Add a placeholder for DS Parameter Set element */ | ||
| 1214 | *newpos++ = WLAN_EID_DS_PARAMS; | ||
| 1215 | *newpos++ = 1; | ||
| 1216 | *newpos++ = 0; | ||
| 1217 | |||
| 1218 | memcpy(newpos, ies + offs, len - offs); | ||
| 1219 | newpos += len - offs; | ||
| 1220 | |||
| 1221 | return newpos; | ||
| 1222 | } | ||
| 1223 | |||
| 1056 | static void | 1224 | static void |
| 1057 | iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1225 | iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
| 1058 | struct ieee80211_scan_ies *ies, | 1226 | struct ieee80211_scan_ies *ies, |
| 1059 | struct iwl_scan_req_unified_lmac *cmd) | 1227 | struct iwl_scan_probe_req *preq, |
| 1228 | const u8 *mac_addr, const u8 *mac_addr_mask) | ||
| 1060 | { | 1229 | { |
| 1061 | struct iwl_scan_probe_req *preq = (void *)(cmd->data + | ||
| 1062 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
| 1063 | mvm->fw->ucode_capa.n_scan_channels); | ||
| 1064 | struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; | 1230 | struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; |
| 1065 | u8 *pos; | 1231 | u8 *pos, *newpos; |
| 1232 | |||
| 1233 | /* | ||
| 1234 | * Unfortunately, right now the offload scan doesn't support randomising | ||
| 1235 | * within the firmware, so until the firmware API is ready we implement | ||
| 1236 | * it in the driver. This means that the scan iterations won't really be | ||
| 1237 | * random, only when it's restarted, but at least that helps a bit. | ||
| 1238 | */ | ||
| 1239 | if (mac_addr) | ||
| 1240 | get_random_mask_addr(frame->sa, mac_addr, mac_addr_mask); | ||
| 1241 | else | ||
| 1242 | memcpy(frame->sa, vif->addr, ETH_ALEN); | ||
| 1066 | 1243 | ||
| 1067 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | 1244 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); |
| 1068 | eth_broadcast_addr(frame->da); | 1245 | eth_broadcast_addr(frame->da); |
| 1069 | memcpy(frame->sa, vif->addr, ETH_ALEN); | ||
| 1070 | eth_broadcast_addr(frame->bssid); | 1246 | eth_broadcast_addr(frame->bssid); |
| 1071 | frame->seq_ctrl = 0; | 1247 | frame->seq_ctrl = 0; |
| 1072 | 1248 | ||
| @@ -1077,11 +1253,14 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 1077 | preq->mac_header.offset = 0; | 1253 | preq->mac_header.offset = 0; |
| 1078 | preq->mac_header.len = cpu_to_le16(24 + 2); | 1254 | preq->mac_header.len = cpu_to_le16(24 + 2); |
| 1079 | 1255 | ||
| 1080 | memcpy(pos, ies->ies[IEEE80211_BAND_2GHZ], | 1256 | /* Insert ds parameter set element on 2.4 GHz band */ |
| 1081 | ies->len[IEEE80211_BAND_2GHZ]); | 1257 | newpos = iwl_mvm_copy_and_insert_ds_elem(mvm, |
| 1258 | ies->ies[IEEE80211_BAND_2GHZ], | ||
| 1259 | ies->len[IEEE80211_BAND_2GHZ], | ||
| 1260 | pos); | ||
| 1082 | preq->band_data[0].offset = cpu_to_le16(pos - preq->buf); | 1261 | preq->band_data[0].offset = cpu_to_le16(pos - preq->buf); |
| 1083 | preq->band_data[0].len = cpu_to_le16(ies->len[IEEE80211_BAND_2GHZ]); | 1262 | preq->band_data[0].len = cpu_to_le16(newpos - pos); |
| 1084 | pos += ies->len[IEEE80211_BAND_2GHZ]; | 1263 | pos = newpos; |
| 1085 | 1264 | ||
| 1086 | memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ], | 1265 | memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ], |
| 1087 | ies->len[IEEE80211_BAND_5GHZ]); | 1266 | ies->len[IEEE80211_BAND_5GHZ]); |
| @@ -1100,10 +1279,11 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, | |||
| 1100 | struct iwl_mvm_scan_params *params) | 1279 | struct iwl_mvm_scan_params *params) |
| 1101 | { | 1280 | { |
| 1102 | memset(cmd, 0, ksize(cmd)); | 1281 | memset(cmd, 0, ksize(cmd)); |
| 1103 | cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active; | 1282 | cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; |
| 1104 | cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive; | 1283 | cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; |
| 1105 | /* TODO: Use params; now fragmented isn't used. */ | 1284 | if (params->passive_fragmented) |
| 1106 | cmd->fragmented_dwell = 0; | 1285 | cmd->fragmented_dwell = |
| 1286 | params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
| 1107 | cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm); | 1287 | cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm); |
| 1108 | cmd->max_out_time = cpu_to_le32(params->max_out_time); | 1288 | cmd->max_out_time = cpu_to_le32(params->max_out_time); |
| 1109 | cmd->suspend_time = cpu_to_le32(params->suspend_time); | 1289 | cmd->suspend_time = cpu_to_le32(params->suspend_time); |
| @@ -1121,6 +1301,10 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, | |||
| 1121 | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | | 1301 | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | |
| 1122 | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); | 1302 | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); |
| 1123 | } | 1303 | } |
| 1304 | |||
| 1305 | if (iwl_mvm_rrm_scan_needed(mvm)) | ||
| 1306 | cmd->scan_flags |= | ||
| 1307 | cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED); | ||
| 1124 | } | 1308 | } |
| 1125 | 1309 | ||
| 1126 | int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | 1310 | int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, |
| @@ -1137,9 +1321,10 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
| 1137 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 1321 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
| 1138 | }; | 1322 | }; |
| 1139 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; | 1323 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; |
| 1324 | struct iwl_scan_probe_req *preq; | ||
| 1140 | struct iwl_mvm_scan_params params = {}; | 1325 | struct iwl_mvm_scan_params params = {}; |
| 1141 | u32 flags; | 1326 | u32 flags; |
| 1142 | int ssid_bitmap = 0; | 1327 | u32 ssid_bitmap = 0; |
| 1143 | int ret, i; | 1328 | int ret, i; |
| 1144 | 1329 | ||
| 1145 | lockdep_assert_held(&mvm->mutex); | 1330 | lockdep_assert_held(&mvm->mutex); |
| @@ -1148,13 +1333,12 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
| 1148 | if (WARN_ON(mvm->scan_cmd == NULL)) | 1333 | if (WARN_ON(mvm->scan_cmd == NULL)) |
| 1149 | return -ENOMEM; | 1334 | return -ENOMEM; |
| 1150 | 1335 | ||
| 1151 | if (WARN_ON_ONCE(req->req.n_ssids > PROBE_OPTION_MAX || | 1336 | if (req->req.n_ssids > PROBE_OPTION_MAX || |
| 1152 | req->ies.common_ie_len + req->ies.len[0] + | 1337 | req->ies.common_ie_len + req->ies.len[NL80211_BAND_2GHZ] + |
| 1153 | req->ies.len[1] + 24 + 2 > | 1338 | req->ies.len[NL80211_BAND_5GHZ] > |
| 1154 | SCAN_OFFLOAD_PROBE_REQ_SIZE || | 1339 | iwl_mvm_max_scan_ie_fw_cmd_room(mvm, false) || |
| 1155 | req->req.n_channels > | 1340 | req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels) |
| 1156 | mvm->fw->ucode_capa.n_scan_channels)) | 1341 | return -ENOBUFS; |
| 1157 | return -1; | ||
| 1158 | 1342 | ||
| 1159 | mvm->scan_status = IWL_MVM_SCAN_OS; | 1343 | mvm->scan_status = IWL_MVM_SCAN_OS; |
| 1160 | 1344 | ||
| @@ -1176,7 +1360,7 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
| 1176 | if (req->req.n_ssids == 0) | 1360 | if (req->req.n_ssids == 0) |
| 1177 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; | 1361 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; |
| 1178 | 1362 | ||
| 1179 | cmd->scan_flags = cpu_to_le32(flags); | 1363 | cmd->scan_flags |= cpu_to_le32(flags); |
| 1180 | 1364 | ||
| 1181 | cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band); | 1365 | cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band); |
| 1182 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | 1366 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | |
| @@ -1199,7 +1383,13 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
| 1199 | req->req.n_channels, ssid_bitmap, | 1383 | req->req.n_channels, ssid_bitmap, |
| 1200 | cmd); | 1384 | cmd); |
| 1201 | 1385 | ||
| 1202 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, cmd); | 1386 | preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * |
| 1387 | mvm->fw->ucode_capa.n_scan_channels); | ||
| 1388 | |||
| 1389 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq, | ||
| 1390 | req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
| 1391 | req->req.mac_addr : NULL, | ||
| 1392 | req->req.mac_addr_mask); | ||
| 1203 | 1393 | ||
| 1204 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | 1394 | ret = iwl_mvm_send_cmd(mvm, &hcmd); |
| 1205 | if (!ret) { | 1395 | if (!ret) { |
| @@ -1232,6 +1422,7 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 1232 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 1422 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
| 1233 | }; | 1423 | }; |
| 1234 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; | 1424 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; |
| 1425 | struct iwl_scan_probe_req *preq; | ||
| 1235 | struct iwl_mvm_scan_params params = {}; | 1426 | struct iwl_mvm_scan_params params = {}; |
| 1236 | int ret; | 1427 | int ret; |
| 1237 | u32 flags = 0, ssid_bitmap = 0; | 1428 | u32 flags = 0, ssid_bitmap = 0; |
| @@ -1242,10 +1433,11 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 1242 | if (WARN_ON(mvm->scan_cmd == NULL)) | 1433 | if (WARN_ON(mvm->scan_cmd == NULL)) |
| 1243 | return -ENOMEM; | 1434 | return -ENOMEM; |
| 1244 | 1435 | ||
| 1245 | if (WARN_ON_ONCE(req->n_ssids > PROBE_OPTION_MAX || | 1436 | if (req->n_ssids > PROBE_OPTION_MAX || |
| 1246 | ies->common_ie_len + ies->len[0] + ies->len[1] + 24 + 2 | 1437 | ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + |
| 1247 | > SCAN_OFFLOAD_PROBE_REQ_SIZE || | 1438 | ies->len[NL80211_BAND_5GHZ] > |
| 1248 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels)) | 1439 | iwl_mvm_max_scan_ie_fw_cmd_room(mvm, true) || |
| 1440 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) | ||
| 1249 | return -ENOBUFS; | 1441 | return -ENOBUFS; |
| 1250 | 1442 | ||
| 1251 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, ¶ms); | 1443 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, ¶ms); |
| @@ -1254,15 +1446,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 1254 | 1446 | ||
| 1255 | cmd->n_channels = (u8)req->n_channels; | 1447 | cmd->n_channels = (u8)req->n_channels; |
| 1256 | 1448 | ||
| 1257 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | 1449 | if (iwl_mvm_scan_pass_all(mvm, req)) |
| 1258 | IWL_DEBUG_SCAN(mvm, | ||
| 1259 | "Sending scheduled scan with filtering, n_match_sets %d\n", | ||
| 1260 | req->n_match_sets); | ||
| 1261 | } else { | ||
| 1262 | IWL_DEBUG_SCAN(mvm, | ||
| 1263 | "Sending Scheduled scan without filtering\n"); | ||
| 1264 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; | 1450 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; |
| 1265 | } | ||
| 1266 | 1451 | ||
| 1267 | if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) | 1452 | if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) |
| 1268 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; | 1453 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; |
| @@ -1273,7 +1458,7 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 1273 | if (req->n_ssids == 0) | 1458 | if (req->n_ssids == 0) |
| 1274 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; | 1459 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; |
| 1275 | 1460 | ||
| 1276 | cmd->scan_flags = cpu_to_le32(flags); | 1461 | cmd->scan_flags |= cpu_to_le32(flags); |
| 1277 | 1462 | ||
| 1278 | cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band); | 1463 | cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band); |
| 1279 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | 1464 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | |
| @@ -1292,7 +1477,13 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 1292 | iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, | 1477 | iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, |
| 1293 | ssid_bitmap, cmd); | 1478 | ssid_bitmap, cmd); |
| 1294 | 1479 | ||
| 1295 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, cmd); | 1480 | preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * |
| 1481 | mvm->fw->ucode_capa.n_scan_channels); | ||
| 1482 | |||
| 1483 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq, | ||
| 1484 | req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
| 1485 | req->mac_addr : NULL, | ||
| 1486 | req->mac_addr_mask); | ||
| 1296 | 1487 | ||
| 1297 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | 1488 | ret = iwl_mvm_send_cmd(mvm, &hcmd); |
| 1298 | if (!ret) { | 1489 | if (!ret) { |
| @@ -1314,7 +1505,594 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
| 1314 | 1505 | ||
| 1315 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | 1506 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) |
| 1316 | { | 1507 | { |
| 1508 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
| 1509 | return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN, | ||
| 1510 | true); | ||
| 1511 | |||
| 1512 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | ||
| 1513 | return 0; | ||
| 1514 | |||
| 1515 | if (iwl_mvm_is_radio_killed(mvm)) { | ||
| 1516 | ieee80211_scan_completed(mvm->hw, true); | ||
| 1517 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 1518 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
| 1519 | return 0; | ||
| 1520 | } | ||
| 1521 | |||
| 1317 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 1522 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
| 1318 | return iwl_mvm_scan_offload_stop(mvm, true); | 1523 | return iwl_mvm_scan_offload_stop(mvm, true); |
| 1319 | return iwl_mvm_cancel_regular_scan(mvm); | 1524 | return iwl_mvm_cancel_regular_scan(mvm); |
| 1320 | } | 1525 | } |
| 1526 | |||
| 1527 | /* UMAC scan API */ | ||
| 1528 | |||
| 1529 | struct iwl_umac_scan_done { | ||
| 1530 | struct iwl_mvm *mvm; | ||
| 1531 | enum iwl_umac_scan_uid_type type; | ||
| 1532 | }; | ||
| 1533 | |||
| 1534 | static int rate_to_scan_rate_flag(unsigned int rate) | ||
| 1535 | { | ||
| 1536 | static const int rate_to_scan_rate[IWL_RATE_COUNT] = { | ||
| 1537 | [IWL_RATE_1M_INDEX] = SCAN_CONFIG_RATE_1M, | ||
| 1538 | [IWL_RATE_2M_INDEX] = SCAN_CONFIG_RATE_2M, | ||
| 1539 | [IWL_RATE_5M_INDEX] = SCAN_CONFIG_RATE_5M, | ||
| 1540 | [IWL_RATE_11M_INDEX] = SCAN_CONFIG_RATE_11M, | ||
| 1541 | [IWL_RATE_6M_INDEX] = SCAN_CONFIG_RATE_6M, | ||
| 1542 | [IWL_RATE_9M_INDEX] = SCAN_CONFIG_RATE_9M, | ||
| 1543 | [IWL_RATE_12M_INDEX] = SCAN_CONFIG_RATE_12M, | ||
| 1544 | [IWL_RATE_18M_INDEX] = SCAN_CONFIG_RATE_18M, | ||
| 1545 | [IWL_RATE_24M_INDEX] = SCAN_CONFIG_RATE_24M, | ||
| 1546 | [IWL_RATE_36M_INDEX] = SCAN_CONFIG_RATE_36M, | ||
| 1547 | [IWL_RATE_48M_INDEX] = SCAN_CONFIG_RATE_48M, | ||
| 1548 | [IWL_RATE_54M_INDEX] = SCAN_CONFIG_RATE_54M, | ||
| 1549 | }; | ||
| 1550 | |||
| 1551 | return rate_to_scan_rate[rate]; | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | static __le32 iwl_mvm_scan_config_rates(struct iwl_mvm *mvm) | ||
| 1555 | { | ||
| 1556 | struct ieee80211_supported_band *band; | ||
| 1557 | unsigned int rates = 0; | ||
| 1558 | int i; | ||
| 1559 | |||
| 1560 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
| 1561 | for (i = 0; i < band->n_bitrates; i++) | ||
| 1562 | rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); | ||
| 1563 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
| 1564 | for (i = 0; i < band->n_bitrates; i++) | ||
| 1565 | rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); | ||
| 1566 | |||
| 1567 | /* Set both basic rates and supported rates */ | ||
| 1568 | rates |= SCAN_CONFIG_SUPPORTED_RATE(rates); | ||
| 1569 | |||
| 1570 | return cpu_to_le32(rates); | ||
| 1571 | } | ||
| 1572 | |||
| 1573 | int iwl_mvm_config_scan(struct iwl_mvm *mvm) | ||
| 1574 | { | ||
| 1575 | |||
| 1576 | struct iwl_scan_config *scan_config; | ||
| 1577 | struct ieee80211_supported_band *band; | ||
| 1578 | int num_channels = | ||
| 1579 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + | ||
| 1580 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | ||
| 1581 | int ret, i, j = 0, cmd_size, data_size; | ||
| 1582 | struct iwl_host_cmd cmd = { | ||
| 1583 | .id = SCAN_CFG_CMD, | ||
| 1584 | }; | ||
| 1585 | |||
| 1586 | if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) | ||
| 1587 | return -ENOBUFS; | ||
| 1588 | |||
| 1589 | cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels; | ||
| 1590 | |||
| 1591 | scan_config = kzalloc(cmd_size, GFP_KERNEL); | ||
| 1592 | if (!scan_config) | ||
| 1593 | return -ENOMEM; | ||
| 1594 | |||
| 1595 | data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr); | ||
| 1596 | scan_config->hdr.size = cpu_to_le16(data_size); | ||
| 1597 | scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE | | ||
| 1598 | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | | ||
| 1599 | SCAN_CONFIG_FLAG_SET_TX_CHAINS | | ||
| 1600 | SCAN_CONFIG_FLAG_SET_RX_CHAINS | | ||
| 1601 | SCAN_CONFIG_FLAG_SET_ALL_TIMES | | ||
| 1602 | SCAN_CONFIG_FLAG_SET_LEGACY_RATES | | ||
| 1603 | SCAN_CONFIG_FLAG_SET_MAC_ADDR | | ||
| 1604 | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| | ||
| 1605 | SCAN_CONFIG_N_CHANNELS(num_channels)); | ||
| 1606 | scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant); | ||
| 1607 | scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); | ||
| 1608 | scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm); | ||
| 1609 | scan_config->out_of_channel_time = cpu_to_le32(170); | ||
| 1610 | scan_config->suspend_time = cpu_to_le32(30); | ||
| 1611 | scan_config->dwell_active = 20; | ||
| 1612 | scan_config->dwell_passive = 110; | ||
| 1613 | scan_config->dwell_fragmented = 20; | ||
| 1614 | |||
| 1615 | memcpy(&scan_config->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); | ||
| 1616 | |||
| 1617 | scan_config->bcast_sta_id = mvm->aux_sta.sta_id; | ||
| 1618 | scan_config->channel_flags = IWL_CHANNEL_FLAG_EBS | | ||
| 1619 | IWL_CHANNEL_FLAG_ACCURATE_EBS | | ||
| 1620 | IWL_CHANNEL_FLAG_EBS_ADD | | ||
| 1621 | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; | ||
| 1622 | |||
| 1623 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
| 1624 | for (i = 0; i < band->n_channels; i++, j++) | ||
| 1625 | scan_config->channel_array[j] = band->channels[i].center_freq; | ||
| 1626 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
| 1627 | for (i = 0; i < band->n_channels; i++, j++) | ||
| 1628 | scan_config->channel_array[j] = band->channels[i].center_freq; | ||
| 1629 | |||
| 1630 | cmd.data[0] = scan_config; | ||
| 1631 | cmd.len[0] = cmd_size; | ||
| 1632 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | ||
| 1633 | |||
| 1634 | IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); | ||
| 1635 | |||
| 1636 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
| 1637 | |||
| 1638 | kfree(scan_config); | ||
| 1639 | return ret; | ||
| 1640 | } | ||
| 1641 | |||
| 1642 | static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid) | ||
| 1643 | { | ||
| 1644 | int i; | ||
| 1645 | |||
| 1646 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) | ||
| 1647 | if (mvm->scan_uid[i] == uid) | ||
| 1648 | return i; | ||
| 1649 | |||
| 1650 | return i; | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm) | ||
| 1654 | { | ||
| 1655 | return iwl_mvm_find_scan_uid(mvm, 0); | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm, | ||
| 1659 | enum iwl_umac_scan_uid_type type) | ||
| 1660 | { | ||
| 1661 | int i; | ||
| 1662 | |||
| 1663 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) | ||
| 1664 | if (mvm->scan_uid[i] & type) | ||
| 1665 | return true; | ||
| 1666 | |||
| 1667 | return false; | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm, | ||
| 1671 | enum iwl_umac_scan_uid_type type) | ||
| 1672 | { | ||
| 1673 | u32 uid; | ||
| 1674 | |||
| 1675 | /* make sure exactly one bit is on in scan type */ | ||
| 1676 | WARN_ON(hweight8(type) != 1); | ||
| 1677 | |||
| 1678 | /* | ||
| 1679 | * Make sure scan uids are unique. If one scan lasts long time while | ||
| 1680 | * others are completing frequently, the seq number will wrap up and | ||
| 1681 | * we may have more than one scan with the same uid. | ||
| 1682 | */ | ||
| 1683 | do { | ||
| 1684 | uid = type | (mvm->scan_seq_num << | ||
| 1685 | IWL_UMAC_SCAN_UID_SEQ_OFFSET); | ||
| 1686 | mvm->scan_seq_num++; | ||
| 1687 | } while (iwl_mvm_find_scan_uid(mvm, uid) < | ||
| 1688 | IWL_MVM_MAX_SIMULTANEOUS_SCANS); | ||
| 1689 | |||
| 1690 | IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid); | ||
| 1691 | |||
| 1692 | return uid; | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | static void | ||
| 1696 | iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm, | ||
| 1697 | struct iwl_scan_req_umac *cmd, | ||
| 1698 | struct iwl_mvm_scan_params *params) | ||
| 1699 | { | ||
| 1700 | memset(cmd, 0, ksize(cmd)); | ||
| 1701 | cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) - | ||
| 1702 | sizeof(struct iwl_mvm_umac_cmd_hdr)); | ||
| 1703 | cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; | ||
| 1704 | cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
| 1705 | if (params->passive_fragmented) | ||
| 1706 | cmd->fragmented_dwell = | ||
| 1707 | params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
| 1708 | cmd->max_out_time = cpu_to_le32(params->max_out_time); | ||
| 1709 | cmd->suspend_time = cpu_to_le32(params->suspend_time); | ||
| 1710 | cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); | ||
| 1711 | } | ||
| 1712 | |||
| 1713 | static void | ||
| 1714 | iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, | ||
| 1715 | struct ieee80211_channel **channels, | ||
| 1716 | int n_channels, u32 ssid_bitmap, | ||
| 1717 | struct iwl_scan_req_umac *cmd) | ||
| 1718 | { | ||
| 1719 | struct iwl_scan_channel_cfg_umac *channel_cfg = (void *)&cmd->data; | ||
| 1720 | int i; | ||
| 1721 | |||
| 1722 | for (i = 0; i < n_channels; i++) { | ||
| 1723 | channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); | ||
| 1724 | channel_cfg[i].channel_num = channels[i]->hw_value; | ||
| 1725 | channel_cfg[i].iter_count = 1; | ||
| 1726 | channel_cfg[i].iter_interval = 0; | ||
| 1727 | } | ||
| 1728 | } | ||
| 1729 | |||
| 1730 | static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids, | ||
| 1731 | struct cfg80211_ssid *ssids, | ||
| 1732 | int fragmented) | ||
| 1733 | { | ||
| 1734 | int flags = 0; | ||
| 1735 | |||
| 1736 | if (n_ssids == 0) | ||
| 1737 | flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE; | ||
| 1738 | |||
| 1739 | if (n_ssids == 1 && ssids[0].ssid_len != 0) | ||
| 1740 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; | ||
| 1741 | |||
| 1742 | if (fragmented) | ||
| 1743 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; | ||
| 1744 | |||
| 1745 | if (iwl_mvm_rrm_scan_needed(mvm)) | ||
| 1746 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED; | ||
| 1747 | |||
| 1748 | return flags; | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
| 1752 | struct ieee80211_scan_request *req) | ||
| 1753 | { | ||
| 1754 | struct iwl_host_cmd hcmd = { | ||
| 1755 | .id = SCAN_REQ_UMAC, | ||
| 1756 | .len = { iwl_mvm_scan_size(mvm), }, | ||
| 1757 | .data = { mvm->scan_cmd, }, | ||
| 1758 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
| 1759 | }; | ||
| 1760 | struct iwl_scan_req_umac *cmd = mvm->scan_cmd; | ||
| 1761 | struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data + | ||
| 1762 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
| 1763 | mvm->fw->ucode_capa.n_scan_channels; | ||
| 1764 | struct iwl_mvm_scan_params params = {}; | ||
| 1765 | u32 uid, flags; | ||
| 1766 | u32 ssid_bitmap = 0; | ||
| 1767 | int ret, i, uid_idx; | ||
| 1768 | |||
| 1769 | lockdep_assert_held(&mvm->mutex); | ||
| 1770 | |||
| 1771 | uid_idx = iwl_mvm_find_free_scan_uid(mvm); | ||
| 1772 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
| 1773 | return -EBUSY; | ||
| 1774 | |||
| 1775 | /* we should have failed registration if scan_cmd was NULL */ | ||
| 1776 | if (WARN_ON(mvm->scan_cmd == NULL)) | ||
| 1777 | return -ENOMEM; | ||
| 1778 | |||
| 1779 | if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX || | ||
| 1780 | req->ies.common_ie_len + | ||
| 1781 | req->ies.len[NL80211_BAND_2GHZ] + | ||
| 1782 | req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 > | ||
| 1783 | SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels > | ||
| 1784 | mvm->fw->ucode_capa.n_scan_channels)) | ||
| 1785 | return -ENOBUFS; | ||
| 1786 | |||
| 1787 | iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags, | ||
| 1788 | ¶ms); | ||
| 1789 | |||
| 1790 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
| 1791 | |||
| 1792 | uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN); | ||
| 1793 | mvm->scan_uid[uid_idx] = uid; | ||
| 1794 | cmd->uid = cpu_to_le32(uid); | ||
| 1795 | |||
| 1796 | cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); | ||
| 1797 | |||
| 1798 | flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids, | ||
| 1799 | req->req.ssids, | ||
| 1800 | params.passive_fragmented); | ||
| 1801 | |||
| 1802 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | ||
| 1803 | |||
| 1804 | cmd->general_flags = cpu_to_le32(flags); | ||
| 1805 | cmd->n_channels = req->req.n_channels; | ||
| 1806 | |||
| 1807 | for (i = 0; i < req->req.n_ssids; i++) | ||
| 1808 | ssid_bitmap |= BIT(i); | ||
| 1809 | |||
| 1810 | iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels, | ||
| 1811 | req->req.n_channels, ssid_bitmap, cmd); | ||
| 1812 | |||
| 1813 | sec_part->schedule[0].iter_count = 1; | ||
| 1814 | sec_part->delay = 0; | ||
| 1815 | |||
| 1816 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq, | ||
| 1817 | req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
| 1818 | req->req.mac_addr : NULL, | ||
| 1819 | req->req.mac_addr_mask); | ||
| 1820 | |||
| 1821 | iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids, | ||
| 1822 | req->req.n_ssids, 0); | ||
| 1823 | |||
| 1824 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
| 1825 | if (!ret) { | ||
| 1826 | IWL_DEBUG_SCAN(mvm, | ||
| 1827 | "Scan request was sent successfully\n"); | ||
| 1828 | } else { | ||
| 1829 | /* | ||
| 1830 | * If the scan failed, it usually means that the FW was unable | ||
| 1831 | * to allocate the time events. Warn on it, but maybe we | ||
| 1832 | * should try to send the command again with different params. | ||
| 1833 | */ | ||
| 1834 | IWL_ERR(mvm, "Scan failed! ret %d\n", ret); | ||
| 1835 | } | ||
| 1836 | return ret; | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
| 1840 | struct cfg80211_sched_scan_request *req, | ||
| 1841 | struct ieee80211_scan_ies *ies) | ||
| 1842 | { | ||
| 1843 | |||
| 1844 | struct iwl_host_cmd hcmd = { | ||
| 1845 | .id = SCAN_REQ_UMAC, | ||
| 1846 | .len = { iwl_mvm_scan_size(mvm), }, | ||
| 1847 | .data = { mvm->scan_cmd, }, | ||
| 1848 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
| 1849 | }; | ||
| 1850 | struct iwl_scan_req_umac *cmd = mvm->scan_cmd; | ||
| 1851 | struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data + | ||
| 1852 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
| 1853 | mvm->fw->ucode_capa.n_scan_channels; | ||
| 1854 | struct iwl_mvm_scan_params params = {}; | ||
| 1855 | u32 uid, flags; | ||
| 1856 | u32 ssid_bitmap = 0; | ||
| 1857 | int ret, uid_idx; | ||
| 1858 | |||
| 1859 | lockdep_assert_held(&mvm->mutex); | ||
| 1860 | |||
| 1861 | uid_idx = iwl_mvm_find_free_scan_uid(mvm); | ||
| 1862 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
| 1863 | return -EBUSY; | ||
| 1864 | |||
| 1865 | /* we should have failed registration if scan_cmd was NULL */ | ||
| 1866 | if (WARN_ON(mvm->scan_cmd == NULL)) | ||
| 1867 | return -ENOMEM; | ||
| 1868 | |||
| 1869 | if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX || | ||
| 1870 | ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + | ||
| 1871 | ies->len[NL80211_BAND_5GHZ] + 24 + 2 > | ||
| 1872 | SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels > | ||
| 1873 | mvm->fw->ucode_capa.n_scan_channels)) | ||
| 1874 | return -ENOBUFS; | ||
| 1875 | |||
| 1876 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, | ||
| 1877 | ¶ms); | ||
| 1878 | |||
| 1879 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
| 1880 | |||
| 1881 | cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); | ||
| 1882 | |||
| 1883 | uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN); | ||
| 1884 | mvm->scan_uid[uid_idx] = uid; | ||
| 1885 | cmd->uid = cpu_to_le32(uid); | ||
| 1886 | |||
| 1887 | cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW); | ||
| 1888 | |||
| 1889 | flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids, | ||
| 1890 | params.passive_fragmented); | ||
| 1891 | |||
| 1892 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC; | ||
| 1893 | |||
| 1894 | if (iwl_mvm_scan_pass_all(mvm, req)) | ||
| 1895 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | ||
| 1896 | else | ||
| 1897 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH; | ||
| 1898 | |||
| 1899 | cmd->general_flags = cpu_to_le32(flags); | ||
| 1900 | |||
| 1901 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT && | ||
| 1902 | mvm->last_ebs_successful) | ||
| 1903 | cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | | ||
| 1904 | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | | ||
| 1905 | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; | ||
| 1906 | |||
| 1907 | cmd->n_channels = req->n_channels; | ||
| 1908 | |||
| 1909 | iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap, | ||
| 1910 | false); | ||
| 1911 | |||
| 1912 | /* This API uses bits 0-19 instead of 1-20. */ | ||
| 1913 | ssid_bitmap = ssid_bitmap >> 1; | ||
| 1914 | |||
| 1915 | iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels, | ||
| 1916 | ssid_bitmap, cmd); | ||
| 1917 | |||
| 1918 | sec_part->schedule[0].interval = | ||
| 1919 | cpu_to_le16(req->interval / MSEC_PER_SEC); | ||
| 1920 | sec_part->schedule[0].iter_count = 0xff; | ||
| 1921 | |||
| 1922 | sec_part->delay = 0; | ||
| 1923 | |||
| 1924 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq, | ||
| 1925 | req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ? | ||
| 1926 | req->mac_addr : NULL, | ||
| 1927 | req->mac_addr_mask); | ||
| 1928 | |||
| 1929 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
| 1930 | if (!ret) { | ||
| 1931 | IWL_DEBUG_SCAN(mvm, | ||
| 1932 | "Sched scan request was sent successfully\n"); | ||
| 1933 | } else { | ||
| 1934 | /* | ||
| 1935 | * If the scan failed, it usually means that the FW was unable | ||
| 1936 | * to allocate the time events. Warn on it, but maybe we | ||
| 1937 | * should try to send the command again with different params. | ||
| 1938 | */ | ||
| 1939 | IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret); | ||
| 1940 | } | ||
| 1941 | return ret; | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | ||
| 1945 | struct iwl_rx_cmd_buffer *rxb, | ||
| 1946 | struct iwl_device_cmd *cmd) | ||
| 1947 | { | ||
| 1948 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
| 1949 | struct iwl_umac_scan_complete *notif = (void *)pkt->data; | ||
| 1950 | u32 uid = __le32_to_cpu(notif->uid); | ||
| 1951 | bool sched = !!(uid & IWL_UMAC_SCAN_UID_SCHED_SCAN); | ||
| 1952 | int uid_idx = iwl_mvm_find_scan_uid(mvm, uid); | ||
| 1953 | |||
| 1954 | /* | ||
| 1955 | * Scan uid may be set to zero in case of scan abort request from above. | ||
| 1956 | */ | ||
| 1957 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
| 1958 | return 0; | ||
| 1959 | |||
| 1960 | IWL_DEBUG_SCAN(mvm, | ||
| 1961 | "Scan completed, uid %u type %s, status %s, EBS status %s\n", | ||
| 1962 | uid, sched ? "sched" : "regular", | ||
| 1963 | notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? | ||
| 1964 | "completed" : "aborted", | ||
| 1965 | notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? | ||
| 1966 | "success" : "failed"); | ||
| 1967 | |||
| 1968 | mvm->last_ebs_successful = !notif->ebs_status; | ||
| 1969 | mvm->scan_uid[uid_idx] = 0; | ||
| 1970 | |||
| 1971 | if (!sched) { | ||
| 1972 | ieee80211_scan_completed(mvm->hw, | ||
| 1973 | notif->status == | ||
| 1974 | IWL_SCAN_OFFLOAD_ABORTED); | ||
| 1975 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 1976 | } else if (!iwl_mvm_find_scan_type(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN)) { | ||
| 1977 | ieee80211_sched_scan_stopped(mvm->hw); | ||
| 1978 | } else { | ||
| 1979 | IWL_DEBUG_SCAN(mvm, "Another sched scan is running\n"); | ||
| 1980 | } | ||
| 1981 | |||
| 1982 | return 0; | ||
| 1983 | } | ||
| 1984 | |||
| 1985 | static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait, | ||
| 1986 | struct iwl_rx_packet *pkt, void *data) | ||
| 1987 | { | ||
| 1988 | struct iwl_umac_scan_done *scan_done = data; | ||
| 1989 | struct iwl_umac_scan_complete *notif = (void *)pkt->data; | ||
| 1990 | u32 uid = __le32_to_cpu(notif->uid); | ||
| 1991 | int uid_idx = iwl_mvm_find_scan_uid(scan_done->mvm, uid); | ||
| 1992 | |||
| 1993 | if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC)) | ||
| 1994 | return false; | ||
| 1995 | |||
| 1996 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
| 1997 | return false; | ||
| 1998 | |||
| 1999 | /* | ||
| 2000 | * Clear scan uid of scans that was aborted from above and completed | ||
| 2001 | * in FW so the RX handler does nothing. | ||
| 2002 | */ | ||
| 2003 | scan_done->mvm->scan_uid[uid_idx] = 0; | ||
| 2004 | |||
| 2005 | return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | static int iwl_umac_scan_abort_one(struct iwl_mvm *mvm, u32 uid) | ||
| 2009 | { | ||
| 2010 | struct iwl_umac_scan_abort cmd = { | ||
| 2011 | .hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) - | ||
| 2012 | sizeof(struct iwl_mvm_umac_cmd_hdr)), | ||
| 2013 | .uid = cpu_to_le32(uid), | ||
| 2014 | }; | ||
| 2015 | |||
| 2016 | lockdep_assert_held(&mvm->mutex); | ||
| 2017 | |||
| 2018 | IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); | ||
| 2019 | |||
| 2020 | return iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd); | ||
| 2021 | } | ||
| 2022 | |||
| 2023 | static int iwl_umac_scan_stop(struct iwl_mvm *mvm, | ||
| 2024 | enum iwl_umac_scan_uid_type type, bool notify) | ||
| 2025 | { | ||
| 2026 | struct iwl_notification_wait wait_scan_done; | ||
| 2027 | static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, }; | ||
| 2028 | struct iwl_umac_scan_done scan_done = { | ||
| 2029 | .mvm = mvm, | ||
| 2030 | .type = type, | ||
| 2031 | }; | ||
| 2032 | int i, ret = -EIO; | ||
| 2033 | |||
| 2034 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | ||
| 2035 | scan_done_notif, | ||
| 2036 | ARRAY_SIZE(scan_done_notif), | ||
| 2037 | iwl_scan_umac_done_check, &scan_done); | ||
| 2038 | |||
| 2039 | IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type); | ||
| 2040 | |||
| 2041 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) { | ||
| 2042 | if (mvm->scan_uid[i] & type) { | ||
| 2043 | int err; | ||
| 2044 | |||
| 2045 | if (iwl_mvm_is_radio_killed(mvm) && | ||
| 2046 | (type & IWL_UMAC_SCAN_UID_REG_SCAN)) { | ||
| 2047 | ieee80211_scan_completed(mvm->hw, true); | ||
| 2048 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 2049 | break; | ||
| 2050 | } | ||
| 2051 | |||
| 2052 | err = iwl_umac_scan_abort_one(mvm, mvm->scan_uid[i]); | ||
| 2053 | if (!err) | ||
| 2054 | ret = 0; | ||
| 2055 | } | ||
| 2056 | } | ||
| 2057 | |||
| 2058 | if (ret) { | ||
| 2059 | IWL_DEBUG_SCAN(mvm, "Couldn't stop scan\n"); | ||
| 2060 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); | ||
| 2061 | return ret; | ||
| 2062 | } | ||
| 2063 | |||
| 2064 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); | ||
| 2065 | if (ret) | ||
| 2066 | return ret; | ||
| 2067 | |||
| 2068 | if (notify) { | ||
| 2069 | if (type & IWL_UMAC_SCAN_UID_SCHED_SCAN) | ||
| 2070 | ieee80211_sched_scan_stopped(mvm->hw); | ||
| 2071 | if (type & IWL_UMAC_SCAN_UID_REG_SCAN) { | ||
| 2072 | ieee80211_scan_completed(mvm->hw, true); | ||
| 2073 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
| 2074 | } | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | return ret; | ||
| 2078 | } | ||
| 2079 | |||
| 2080 | int iwl_mvm_scan_size(struct iwl_mvm *mvm) | ||
| 2081 | { | ||
| 2082 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
| 2083 | return sizeof(struct iwl_scan_req_umac) + | ||
| 2084 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
| 2085 | mvm->fw->ucode_capa.n_scan_channels + | ||
| 2086 | sizeof(struct iwl_scan_req_umac_tail); | ||
| 2087 | |||
| 2088 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
| 2089 | return sizeof(struct iwl_scan_req_unified_lmac) + | ||
| 2090 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
| 2091 | mvm->fw->ucode_capa.n_scan_channels + | ||
| 2092 | sizeof(struct iwl_scan_probe_req); | ||
| 2093 | |||
| 2094 | return sizeof(struct iwl_scan_cmd) + | ||
| 2095 | mvm->fw->ucode_capa.max_probe_length + | ||
| 2096 | mvm->fw->ucode_capa.n_scan_channels * | ||
| 2097 | sizeof(struct iwl_scan_channel); | ||
| 2098 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index e843b67f2201..7eb78e2c240a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -177,6 +179,10 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, | |||
| 177 | struct ieee80211_sta *sta; | 179 | struct ieee80211_sta *sta; |
| 178 | int ret = 0; | 180 | int ret = 0; |
| 179 | 181 | ||
| 182 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF && | ||
| 183 | mvm->cfg->disable_dummy_notification) | ||
| 184 | sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); | ||
| 185 | |||
| 180 | /* | 186 | /* |
| 181 | * If an associated AP sta changed its antenna configuration, the state | 187 | * If an associated AP sta changed its antenna configuration, the state |
| 182 | * will remain FULL_ON but SF parameters need to be reconsidered. | 188 | * will remain FULL_ON but SF parameters need to be reconsidered. |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 763548880399..d86fe432e51f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -202,6 +204,56 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
| 202 | return ret; | 204 | return ret; |
| 203 | } | 205 | } |
| 204 | 206 | ||
| 207 | static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, | ||
| 208 | struct ieee80211_sta *sta) | ||
| 209 | { | ||
| 210 | unsigned long used_hw_queues; | ||
| 211 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 212 | u32 ac; | ||
| 213 | |||
| 214 | lockdep_assert_held(&mvm->mutex); | ||
| 215 | |||
| 216 | used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, NULL); | ||
| 217 | |||
| 218 | /* Find available queues, and allocate them to the ACs */ | ||
| 219 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
| 220 | u8 queue = find_first_zero_bit(&used_hw_queues, | ||
| 221 | mvm->first_agg_queue); | ||
| 222 | |||
| 223 | if (queue >= mvm->first_agg_queue) { | ||
| 224 | IWL_ERR(mvm, "Failed to allocate STA queue\n"); | ||
| 225 | return -EBUSY; | ||
| 226 | } | ||
| 227 | |||
| 228 | __set_bit(queue, &used_hw_queues); | ||
| 229 | mvmsta->hw_queue[ac] = queue; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* Found a place for all queues - enable them */ | ||
| 233 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
| 234 | iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], | ||
| 235 | iwl_mvm_ac_to_tx_fifo[ac]); | ||
| 236 | mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); | ||
| 237 | } | ||
| 238 | |||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, | ||
| 243 | struct ieee80211_sta *sta) | ||
| 244 | { | ||
| 245 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 246 | unsigned long sta_msk; | ||
| 247 | int i; | ||
| 248 | |||
| 249 | lockdep_assert_held(&mvm->mutex); | ||
| 250 | |||
| 251 | /* disable the TDLS STA-specific queues */ | ||
| 252 | sta_msk = mvmsta->tfd_queue_msk; | ||
| 253 | for_each_set_bit(i, &sta_msk, sizeof(sta_msk)) | ||
| 254 | iwl_mvm_disable_txq(mvm, i); | ||
| 255 | } | ||
| 256 | |||
| 205 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | 257 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, |
| 206 | struct ieee80211_vif *vif, | 258 | struct ieee80211_vif *vif, |
| 207 | struct ieee80211_sta *sta) | 259 | struct ieee80211_sta *sta) |
| @@ -235,9 +287,17 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
| 235 | atomic_set(&mvm->pending_frames[sta_id], 0); | 287 | atomic_set(&mvm->pending_frames[sta_id], 0); |
| 236 | mvm_sta->tid_disable_agg = 0; | 288 | mvm_sta->tid_disable_agg = 0; |
| 237 | mvm_sta->tfd_queue_msk = 0; | 289 | mvm_sta->tfd_queue_msk = 0; |
| 238 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | 290 | |
| 239 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) | 291 | /* allocate new queues for a TDLS station */ |
| 240 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); | 292 | if (sta->tdls) { |
| 293 | ret = iwl_mvm_tdls_sta_init(mvm, sta); | ||
| 294 | if (ret) | ||
| 295 | return ret; | ||
| 296 | } else { | ||
| 297 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | ||
| 298 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) | ||
| 299 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); | ||
| 300 | } | ||
| 241 | 301 | ||
| 242 | /* for HW restart - reset everything but the sequence number */ | 302 | /* for HW restart - reset everything but the sequence number */ |
| 243 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | 303 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { |
| @@ -245,19 +305,28 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
| 245 | memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i])); | 305 | memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i])); |
| 246 | mvm_sta->tid_data[i].seq_number = seq; | 306 | mvm_sta->tid_data[i].seq_number = seq; |
| 247 | } | 307 | } |
| 308 | mvm_sta->agg_tids = 0; | ||
| 248 | 309 | ||
| 249 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); | 310 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); |
| 250 | if (ret) | 311 | if (ret) |
| 251 | return ret; | 312 | goto err; |
| 252 | 313 | ||
| 253 | /* The first station added is the AP, the others are TDLS STAs */ | 314 | if (vif->type == NL80211_IFTYPE_STATION) { |
| 254 | if (vif->type == NL80211_IFTYPE_STATION && | 315 | if (!sta->tdls) { |
| 255 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | 316 | WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT); |
| 256 | mvmvif->ap_sta_id = sta_id; | 317 | mvmvif->ap_sta_id = sta_id; |
| 318 | } else { | ||
| 319 | WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT); | ||
| 320 | } | ||
| 321 | } | ||
| 257 | 322 | ||
| 258 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); | 323 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); |
| 259 | 324 | ||
| 260 | return 0; | 325 | return 0; |
| 326 | |||
| 327 | err: | ||
| 328 | iwl_mvm_tdls_sta_deinit(mvm, sta); | ||
| 329 | return ret; | ||
| 261 | } | 330 | } |
| 262 | 331 | ||
| 263 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | 332 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, |
| @@ -391,6 +460,17 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) | |||
| 391 | } | 460 | } |
| 392 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); | 461 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); |
| 393 | clear_bit(sta_id, mvm->sta_drained); | 462 | clear_bit(sta_id, mvm->sta_drained); |
| 463 | |||
| 464 | if (mvm->tfd_drained[sta_id]) { | ||
| 465 | unsigned long i, msk = mvm->tfd_drained[sta_id]; | ||
| 466 | |||
| 467 | for_each_set_bit(i, &msk, sizeof(msk)) | ||
| 468 | iwl_mvm_disable_txq(mvm, i); | ||
| 469 | |||
| 470 | mvm->tfd_drained[sta_id] = 0; | ||
| 471 | IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n", | ||
| 472 | sta_id, msk); | ||
| 473 | } | ||
| 394 | } | 474 | } |
| 395 | 475 | ||
| 396 | mutex_unlock(&mvm->mutex); | 476 | mutex_unlock(&mvm->mutex); |
| @@ -424,6 +504,15 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
| 424 | } | 504 | } |
| 425 | 505 | ||
| 426 | /* | 506 | /* |
| 507 | * This shouldn't happen - the TDLS channel switch should be canceled | ||
| 508 | * before the STA is removed. | ||
| 509 | */ | ||
| 510 | if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) { | ||
| 511 | mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; | ||
| 512 | cancel_delayed_work(&mvm->tdls_cs.dwork); | ||
| 513 | } | ||
| 514 | |||
| 515 | /* | ||
| 427 | * Make sure that the tx response code sees the station as -EBUSY and | 516 | * Make sure that the tx response code sees the station as -EBUSY and |
| 428 | * calls the drain worker. | 517 | * calls the drain worker. |
| 429 | */ | 518 | */ |
| @@ -436,9 +525,22 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
| 436 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | 525 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], |
| 437 | ERR_PTR(-EBUSY)); | 526 | ERR_PTR(-EBUSY)); |
| 438 | spin_unlock_bh(&mvm_sta->lock); | 527 | spin_unlock_bh(&mvm_sta->lock); |
| 528 | |||
| 529 | /* disable TDLS sta queues on drain complete */ | ||
| 530 | if (sta->tdls) { | ||
| 531 | mvm->tfd_drained[mvm_sta->sta_id] = | ||
| 532 | mvm_sta->tfd_queue_msk; | ||
| 533 | IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", | ||
| 534 | mvm_sta->sta_id); | ||
| 535 | } | ||
| 536 | |||
| 439 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); | 537 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); |
| 440 | } else { | 538 | } else { |
| 441 | spin_unlock_bh(&mvm_sta->lock); | 539 | spin_unlock_bh(&mvm_sta->lock); |
| 540 | |||
| 541 | if (sta->tdls) | ||
| 542 | iwl_mvm_tdls_sta_deinit(mvm, sta); | ||
| 543 | |||
| 442 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); | 544 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); |
| 443 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); | 545 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); |
| 444 | } | 546 | } |
| @@ -458,8 +560,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, | |||
| 458 | return ret; | 560 | return ret; |
| 459 | } | 561 | } |
| 460 | 562 | ||
| 461 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | 563 | static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, |
| 462 | u32 qmask, enum nl80211_iftype iftype) | 564 | struct iwl_mvm_int_sta *sta, |
| 565 | u32 qmask, enum nl80211_iftype iftype) | ||
| 463 | { | 566 | { |
| 464 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 567 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
| 465 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); | 568 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); |
| @@ -474,7 +577,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | |||
| 474 | return 0; | 577 | return 0; |
| 475 | } | 578 | } |
| 476 | 579 | ||
| 477 | void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) | 580 | static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, |
| 581 | struct iwl_mvm_int_sta *sta) | ||
| 478 | { | 582 | { |
| 479 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); | 583 | RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); |
| 480 | memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); | 584 | memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); |
| @@ -527,8 +631,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | |||
| 527 | lockdep_assert_held(&mvm->mutex); | 631 | lockdep_assert_held(&mvm->mutex); |
| 528 | 632 | ||
| 529 | /* Map Aux queue to fifo - needs to happen before adding Aux station */ | 633 | /* Map Aux queue to fifo - needs to happen before adding Aux station */ |
| 530 | iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue, | 634 | iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, |
| 531 | IWL_MVM_TX_FIFO_MCAST); | 635 | IWL_MVM_TX_FIFO_MCAST); |
| 532 | 636 | ||
| 533 | /* Allocate aux station and assign to it the aux queue */ | 637 | /* Allocate aux station and assign to it the aux queue */ |
| 534 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), | 638 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), |
| @@ -544,6 +648,13 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | |||
| 544 | return ret; | 648 | return ret; |
| 545 | } | 649 | } |
| 546 | 650 | ||
| 651 | void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm) | ||
| 652 | { | ||
| 653 | lockdep_assert_held(&mvm->mutex); | ||
| 654 | |||
| 655 | iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); | ||
| 656 | } | ||
| 657 | |||
| 547 | /* | 658 | /* |
| 548 | * Send the add station command for the vif's broadcast station. | 659 | * Send the add station command for the vif's broadcast station. |
| 549 | * Assumes that the station was already allocated. | 660 | * Assumes that the station was already allocated. |
| @@ -552,10 +663,10 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | |||
| 552 | * @vif: the interface to which the broadcast station is added | 663 | * @vif: the interface to which the broadcast station is added |
| 553 | * @bsta: the broadcast station to add. | 664 | * @bsta: the broadcast station to add. |
| 554 | */ | 665 | */ |
| 555 | int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 666 | int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 556 | struct iwl_mvm_int_sta *bsta) | ||
| 557 | { | 667 | { |
| 558 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 668 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 669 | struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; | ||
| 559 | static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | 670 | static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| 560 | const u8 *baddr = _baddr; | 671 | const u8 *baddr = _baddr; |
| 561 | 672 | ||
| @@ -573,19 +684,40 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 573 | 684 | ||
| 574 | /* Send the FW a request to remove the station from it's internal data | 685 | /* Send the FW a request to remove the station from it's internal data |
| 575 | * structures, but DO NOT remove the entry from the local data structures. */ | 686 | * structures, but DO NOT remove the entry from the local data structures. */ |
| 576 | int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, | 687 | int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 577 | struct iwl_mvm_int_sta *bsta) | ||
| 578 | { | 688 | { |
| 689 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 579 | int ret; | 690 | int ret; |
| 580 | 691 | ||
| 581 | lockdep_assert_held(&mvm->mutex); | 692 | lockdep_assert_held(&mvm->mutex); |
| 582 | 693 | ||
| 583 | ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); | 694 | ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id); |
| 584 | if (ret) | 695 | if (ret) |
| 585 | IWL_WARN(mvm, "Failed sending remove station\n"); | 696 | IWL_WARN(mvm, "Failed sending remove station\n"); |
| 586 | return ret; | 697 | return ret; |
| 587 | } | 698 | } |
| 588 | 699 | ||
| 700 | int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
| 701 | { | ||
| 702 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 703 | u32 qmask; | ||
| 704 | |||
| 705 | lockdep_assert_held(&mvm->mutex); | ||
| 706 | |||
| 707 | qmask = iwl_mvm_mac_get_queues_mask(vif); | ||
| 708 | |||
| 709 | /* | ||
| 710 | * The firmware defines the TFD queue mask to only be relevant | ||
| 711 | * for *unicast* queues, so the multicast (CAB) queue shouldn't | ||
| 712 | * be included. | ||
| 713 | */ | ||
| 714 | if (vif->type == NL80211_IFTYPE_AP) | ||
| 715 | qmask &= ~BIT(vif->cab_queue); | ||
| 716 | |||
| 717 | return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask, | ||
| 718 | ieee80211_vif_type_p2p(vif)); | ||
| 719 | } | ||
| 720 | |||
| 589 | /* Allocate a new station entry for the broadcast station to the given vif, | 721 | /* Allocate a new station entry for the broadcast station to the given vif, |
| 590 | * and send it to the FW. | 722 | * and send it to the FW. |
| 591 | * Note that each P2P mac should have its own broadcast station. | 723 | * Note that each P2P mac should have its own broadcast station. |
| @@ -593,45 +725,47 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, | |||
| 593 | * @mvm: the mvm component | 725 | * @mvm: the mvm component |
| 594 | * @vif: the interface to which the broadcast station is added | 726 | * @vif: the interface to which the broadcast station is added |
| 595 | * @bsta: the broadcast station to add. */ | 727 | * @bsta: the broadcast station to add. */ |
| 596 | int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 728 | int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 597 | struct iwl_mvm_int_sta *bsta) | ||
| 598 | { | 729 | { |
| 599 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 730 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 600 | static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | 731 | struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; |
| 601 | u32 qmask; | ||
| 602 | int ret; | 732 | int ret; |
| 603 | 733 | ||
| 604 | lockdep_assert_held(&mvm->mutex); | 734 | lockdep_assert_held(&mvm->mutex); |
| 605 | 735 | ||
| 606 | qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 736 | ret = iwl_mvm_alloc_bcast_sta(mvm, vif); |
| 607 | ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask, | ||
| 608 | ieee80211_vif_type_p2p(vif)); | ||
| 609 | if (ret) | 737 | if (ret) |
| 610 | return ret; | 738 | return ret; |
| 611 | 739 | ||
| 612 | ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, | 740 | ret = iwl_mvm_send_add_bcast_sta(mvm, vif); |
| 613 | mvmvif->id, mvmvif->color); | ||
| 614 | 741 | ||
| 615 | if (ret) | 742 | if (ret) |
| 616 | iwl_mvm_dealloc_int_sta(mvm, bsta); | 743 | iwl_mvm_dealloc_int_sta(mvm, bsta); |
| 744 | |||
| 617 | return ret; | 745 | return ret; |
| 618 | } | 746 | } |
| 619 | 747 | ||
| 748 | void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
| 749 | { | ||
| 750 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 751 | |||
| 752 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | ||
| 753 | } | ||
| 754 | |||
| 620 | /* | 755 | /* |
| 621 | * Send the FW a request to remove the station from it's internal data | 756 | * Send the FW a request to remove the station from it's internal data |
| 622 | * structures, and in addition remove it from the local data structure. | 757 | * structures, and in addition remove it from the local data structure. |
| 623 | */ | 758 | */ |
| 624 | int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta) | 759 | int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 625 | { | 760 | { |
| 626 | int ret; | 761 | int ret; |
| 627 | 762 | ||
| 628 | lockdep_assert_held(&mvm->mutex); | 763 | lockdep_assert_held(&mvm->mutex); |
| 629 | 764 | ||
| 630 | ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id); | 765 | ret = iwl_mvm_send_rm_bcast_sta(mvm, vif); |
| 631 | if (ret) | 766 | |
| 632 | return ret; | 767 | iwl_mvm_dealloc_bcast_sta(mvm, vif); |
| 633 | 768 | ||
| 634 | iwl_mvm_dealloc_int_sta(mvm, bsta); | ||
| 635 | return ret; | 769 | return ret; |
| 636 | } | 770 | } |
| 637 | 771 | ||
| @@ -834,12 +968,16 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 834 | int queue, fifo, ret; | 968 | int queue, fifo, ret; |
| 835 | u16 ssn; | 969 | u16 ssn; |
| 836 | 970 | ||
| 971 | BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE) | ||
| 972 | != IWL_MAX_TID_COUNT); | ||
| 973 | |||
| 837 | buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); | 974 | buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); |
| 838 | 975 | ||
| 839 | spin_lock_bh(&mvmsta->lock); | 976 | spin_lock_bh(&mvmsta->lock); |
| 840 | ssn = tid_data->ssn; | 977 | ssn = tid_data->ssn; |
| 841 | queue = tid_data->txq_id; | 978 | queue = tid_data->txq_id; |
| 842 | tid_data->state = IWL_AGG_ON; | 979 | tid_data->state = IWL_AGG_ON; |
| 980 | mvmsta->agg_tids |= BIT(tid); | ||
| 843 | tid_data->ssn = 0xffff; | 981 | tid_data->ssn = 0xffff; |
| 844 | spin_unlock_bh(&mvmsta->lock); | 982 | spin_unlock_bh(&mvmsta->lock); |
| 845 | 983 | ||
| @@ -849,8 +987,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 849 | if (ret) | 987 | if (ret) |
| 850 | return -EIO; | 988 | return -EIO; |
| 851 | 989 | ||
| 852 | iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid, | 990 | iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid, |
| 853 | buf_size, ssn); | 991 | buf_size, ssn); |
| 854 | 992 | ||
| 855 | /* | 993 | /* |
| 856 | * Even though in theory the peer could have different | 994 | * Even though in theory the peer could have different |
| @@ -894,6 +1032,8 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 894 | IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n", | 1032 | IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n", |
| 895 | mvmsta->sta_id, tid, txq_id, tid_data->state); | 1033 | mvmsta->sta_id, tid, txq_id, tid_data->state); |
| 896 | 1034 | ||
| 1035 | mvmsta->agg_tids &= ~BIT(tid); | ||
| 1036 | |||
| 897 | switch (tid_data->state) { | 1037 | switch (tid_data->state) { |
| 898 | case IWL_AGG_ON: | 1038 | case IWL_AGG_ON: |
| 899 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); | 1039 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
| @@ -910,8 +1050,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 910 | } | 1050 | } |
| 911 | 1051 | ||
| 912 | tid_data->ssn = 0xffff; | 1052 | tid_data->ssn = 0xffff; |
| 913 | iwl_trans_txq_disable(mvm->trans, txq_id); | 1053 | tid_data->state = IWL_AGG_OFF; |
| 914 | /* fall through */ | 1054 | mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE; |
| 1055 | spin_unlock_bh(&mvmsta->lock); | ||
| 1056 | |||
| 1057 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
| 1058 | |||
| 1059 | iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); | ||
| 1060 | |||
| 1061 | iwl_mvm_disable_txq(mvm, txq_id); | ||
| 1062 | return 0; | ||
| 915 | case IWL_AGG_STARTING: | 1063 | case IWL_AGG_STARTING: |
| 916 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | 1064 | case IWL_EMPTYING_HW_QUEUE_ADDBA: |
| 917 | /* | 1065 | /* |
| @@ -959,13 +1107,16 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 959 | mvmsta->sta_id, tid, txq_id, tid_data->state); | 1107 | mvmsta->sta_id, tid, txq_id, tid_data->state); |
| 960 | old_state = tid_data->state; | 1108 | old_state = tid_data->state; |
| 961 | tid_data->state = IWL_AGG_OFF; | 1109 | tid_data->state = IWL_AGG_OFF; |
| 1110 | mvmsta->agg_tids &= ~BIT(tid); | ||
| 962 | spin_unlock_bh(&mvmsta->lock); | 1111 | spin_unlock_bh(&mvmsta->lock); |
| 963 | 1112 | ||
| 964 | if (old_state >= IWL_AGG_ON) { | 1113 | if (old_state >= IWL_AGG_ON) { |
| 965 | if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) | 1114 | if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) |
| 966 | IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); | 1115 | IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); |
| 967 | 1116 | ||
| 968 | iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); | 1117 | iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); |
| 1118 | |||
| 1119 | iwl_mvm_disable_txq(mvm, tid_data->txq_id); | ||
| 969 | } | 1120 | } |
| 970 | 1121 | ||
| 971 | mvm->queue_to_mac80211[tid_data->txq_id] = | 1122 | mvm->queue_to_mac80211[tid_data->txq_id] = |
| @@ -1015,15 +1166,16 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | |||
| 1015 | 1166 | ||
| 1016 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | 1167 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, |
| 1017 | struct iwl_mvm_sta *mvm_sta, | 1168 | struct iwl_mvm_sta *mvm_sta, |
| 1018 | struct ieee80211_key_conf *keyconf, | 1169 | struct ieee80211_key_conf *keyconf, bool mcast, |
| 1019 | u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, | 1170 | u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) |
| 1020 | u32 cmd_flags) | ||
| 1021 | { | 1171 | { |
| 1022 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | 1172 | struct iwl_mvm_add_sta_key_cmd cmd = {}; |
| 1023 | __le16 key_flags; | 1173 | __le16 key_flags; |
| 1024 | int ret, status; | 1174 | int ret; |
| 1175 | u32 status; | ||
| 1025 | u16 keyidx; | 1176 | u16 keyidx; |
| 1026 | int i; | 1177 | int i; |
| 1178 | u8 sta_id = mvm_sta->sta_id; | ||
| 1027 | 1179 | ||
| 1028 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | 1180 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & |
| 1029 | STA_KEY_FLG_KEYID_MSK; | 1181 | STA_KEY_FLG_KEYID_MSK; |
| @@ -1042,12 +1194,18 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | |||
| 1042 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); | 1194 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); |
| 1043 | memcpy(cmd.key, keyconf->key, keyconf->keylen); | 1195 | memcpy(cmd.key, keyconf->key, keyconf->keylen); |
| 1044 | break; | 1196 | break; |
| 1197 | case WLAN_CIPHER_SUITE_WEP104: | ||
| 1198 | key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES); | ||
| 1199 | case WLAN_CIPHER_SUITE_WEP40: | ||
| 1200 | key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); | ||
| 1201 | memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); | ||
| 1202 | break; | ||
| 1045 | default: | 1203 | default: |
| 1046 | key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); | 1204 | key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); |
| 1047 | memcpy(cmd.key, keyconf->key, keyconf->keylen); | 1205 | memcpy(cmd.key, keyconf->key, keyconf->keylen); |
| 1048 | } | 1206 | } |
| 1049 | 1207 | ||
| 1050 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | 1208 | if (mcast) |
| 1051 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | 1209 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); |
| 1052 | 1210 | ||
| 1053 | cmd.key_offset = keyconf->hw_key_idx; | 1211 | cmd.key_offset = keyconf->hw_key_idx; |
| @@ -1139,17 +1297,88 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, | |||
| 1139 | return NULL; | 1297 | return NULL; |
| 1140 | } | 1298 | } |
| 1141 | 1299 | ||
| 1300 | static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | ||
| 1301 | struct ieee80211_vif *vif, | ||
| 1302 | struct ieee80211_sta *sta, | ||
| 1303 | struct ieee80211_key_conf *keyconf, | ||
| 1304 | bool mcast) | ||
| 1305 | { | ||
| 1306 | struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); | ||
| 1307 | int ret; | ||
| 1308 | const u8 *addr; | ||
| 1309 | struct ieee80211_key_seq seq; | ||
| 1310 | u16 p1k[5]; | ||
| 1311 | |||
| 1312 | switch (keyconf->cipher) { | ||
| 1313 | case WLAN_CIPHER_SUITE_TKIP: | ||
| 1314 | addr = iwl_mvm_get_mac_addr(mvm, vif, sta); | ||
| 1315 | /* get phase 1 key from mac80211 */ | ||
| 1316 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
| 1317 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
| 1318 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | ||
| 1319 | seq.tkip.iv32, p1k, 0); | ||
| 1320 | break; | ||
| 1321 | case WLAN_CIPHER_SUITE_CCMP: | ||
| 1322 | case WLAN_CIPHER_SUITE_WEP40: | ||
| 1323 | case WLAN_CIPHER_SUITE_WEP104: | ||
| 1324 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | ||
| 1325 | 0, NULL, 0); | ||
| 1326 | break; | ||
| 1327 | default: | ||
| 1328 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, | ||
| 1329 | 0, NULL, 0); | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | return ret; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, | ||
| 1336 | struct ieee80211_key_conf *keyconf, | ||
| 1337 | bool mcast) | ||
| 1338 | { | ||
| 1339 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | ||
| 1340 | __le16 key_flags; | ||
| 1341 | int ret; | ||
| 1342 | u32 status; | ||
| 1343 | |||
| 1344 | key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | ||
| 1345 | STA_KEY_FLG_KEYID_MSK); | ||
| 1346 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | ||
| 1347 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | ||
| 1348 | |||
| 1349 | if (mcast) | ||
| 1350 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | ||
| 1351 | |||
| 1352 | cmd.key_flags = key_flags; | ||
| 1353 | cmd.key_offset = keyconf->hw_key_idx; | ||
| 1354 | cmd.sta_id = sta_id; | ||
| 1355 | |||
| 1356 | status = ADD_STA_SUCCESS; | ||
| 1357 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), | ||
| 1358 | &cmd, &status); | ||
| 1359 | |||
| 1360 | switch (status) { | ||
| 1361 | case ADD_STA_SUCCESS: | ||
| 1362 | IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); | ||
| 1363 | break; | ||
| 1364 | default: | ||
| 1365 | ret = -EIO; | ||
| 1366 | IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); | ||
| 1367 | break; | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | return ret; | ||
| 1371 | } | ||
| 1372 | |||
| 1142 | int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | 1373 | int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, |
| 1143 | struct ieee80211_vif *vif, | 1374 | struct ieee80211_vif *vif, |
| 1144 | struct ieee80211_sta *sta, | 1375 | struct ieee80211_sta *sta, |
| 1145 | struct ieee80211_key_conf *keyconf, | 1376 | struct ieee80211_key_conf *keyconf, |
| 1146 | bool have_key_offset) | 1377 | bool have_key_offset) |
| 1147 | { | 1378 | { |
| 1148 | struct iwl_mvm_sta *mvm_sta; | 1379 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
| 1380 | u8 sta_id; | ||
| 1149 | int ret; | 1381 | int ret; |
| 1150 | u8 *addr, sta_id; | ||
| 1151 | struct ieee80211_key_seq seq; | ||
| 1152 | u16 p1k[5]; | ||
| 1153 | 1382 | ||
| 1154 | lockdep_assert_held(&mvm->mutex); | 1383 | lockdep_assert_held(&mvm->mutex); |
| 1155 | 1384 | ||
| @@ -1178,8 +1407,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
| 1178 | } | 1407 | } |
| 1179 | } | 1408 | } |
| 1180 | 1409 | ||
| 1181 | mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; | 1410 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) |
| 1182 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||
| 1183 | return -EINVAL; | 1411 | return -EINVAL; |
| 1184 | 1412 | ||
| 1185 | if (!have_key_offset) { | 1413 | if (!have_key_offset) { |
| @@ -1193,26 +1421,26 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
| 1193 | return -ENOSPC; | 1421 | return -ENOSPC; |
| 1194 | } | 1422 | } |
| 1195 | 1423 | ||
| 1196 | switch (keyconf->cipher) { | 1424 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast); |
| 1197 | case WLAN_CIPHER_SUITE_TKIP: | 1425 | if (ret) { |
| 1198 | addr = iwl_mvm_get_mac_addr(mvm, vif, sta); | 1426 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); |
| 1199 | /* get phase 1 key from mac80211 */ | 1427 | goto end; |
| 1200 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
| 1201 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
| 1202 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
| 1203 | seq.tkip.iv32, p1k, 0); | ||
| 1204 | break; | ||
| 1205 | case WLAN_CIPHER_SUITE_CCMP: | ||
| 1206 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||
| 1207 | 0, NULL, 0); | ||
| 1208 | break; | ||
| 1209 | default: | ||
| 1210 | ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, | ||
| 1211 | sta_id, 0, NULL, 0); | ||
| 1212 | } | 1428 | } |
| 1213 | 1429 | ||
| 1214 | if (ret) | 1430 | /* |
| 1215 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | 1431 | * For WEP, the same key is used for multicast and unicast. Upload it |
| 1432 | * again, using the same key offset, and now pointing the other one | ||
| 1433 | * to the same key slot (offset). | ||
| 1434 | * If this fails, remove the original as well. | ||
| 1435 | */ | ||
| 1436 | if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
| 1437 | keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { | ||
| 1438 | ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast); | ||
| 1439 | if (ret) { | ||
| 1440 | __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | ||
| 1441 | __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); | ||
| 1442 | } | ||
| 1443 | } | ||
| 1216 | 1444 | ||
| 1217 | end: | 1445 | end: |
| 1218 | IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", | 1446 | IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", |
| @@ -1226,11 +1454,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
| 1226 | struct ieee80211_sta *sta, | 1454 | struct ieee80211_sta *sta, |
| 1227 | struct ieee80211_key_conf *keyconf) | 1455 | struct ieee80211_key_conf *keyconf) |
| 1228 | { | 1456 | { |
| 1229 | struct iwl_mvm_sta *mvm_sta; | 1457 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
| 1230 | struct iwl_mvm_add_sta_key_cmd cmd = {}; | ||
| 1231 | __le16 key_flags; | ||
| 1232 | int ret, status; | ||
| 1233 | u8 sta_id; | 1458 | u8 sta_id; |
| 1459 | int ret; | ||
| 1234 | 1460 | ||
| 1235 | lockdep_assert_held(&mvm->mutex); | 1461 | lockdep_assert_held(&mvm->mutex); |
| 1236 | 1462 | ||
| @@ -1243,8 +1469,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
| 1243 | if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 1469 | if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
| 1244 | return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); | 1470 | return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); |
| 1245 | 1471 | ||
| 1246 | ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); | 1472 | if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) { |
| 1247 | if (!ret) { | ||
| 1248 | IWL_ERR(mvm, "offset %d not used in fw key table.\n", | 1473 | IWL_ERR(mvm, "offset %d not used in fw key table.\n", |
| 1249 | keyconf->hw_key_idx); | 1474 | keyconf->hw_key_idx); |
| 1250 | return -ENOENT; | 1475 | return -ENOENT; |
| @@ -1270,35 +1495,17 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
| 1270 | } | 1495 | } |
| 1271 | } | 1496 | } |
| 1272 | 1497 | ||
| 1273 | mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv; | 1498 | if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) |
| 1274 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||
| 1275 | return -EINVAL; | 1499 | return -EINVAL; |
| 1276 | 1500 | ||
| 1277 | key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | 1501 | ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); |
| 1278 | STA_KEY_FLG_KEYID_MSK); | 1502 | if (ret) |
| 1279 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | 1503 | return ret; |
| 1280 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | ||
| 1281 | |||
| 1282 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
| 1283 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | ||
| 1284 | |||
| 1285 | cmd.key_flags = key_flags; | ||
| 1286 | cmd.key_offset = keyconf->hw_key_idx; | ||
| 1287 | cmd.sta_id = sta_id; | ||
| 1288 | |||
| 1289 | status = ADD_STA_SUCCESS; | ||
| 1290 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), | ||
| 1291 | &cmd, &status); | ||
| 1292 | 1504 | ||
| 1293 | switch (status) { | 1505 | /* delete WEP key twice to get rid of (now useless) offset */ |
| 1294 | case ADD_STA_SUCCESS: | 1506 | if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || |
| 1295 | IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); | 1507 | keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) |
| 1296 | break; | 1508 | ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, !mcast); |
| 1297 | default: | ||
| 1298 | ret = -EIO; | ||
| 1299 | IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); | ||
| 1300 | break; | ||
| 1301 | } | ||
| 1302 | 1509 | ||
| 1303 | return ret; | 1510 | return ret; |
| 1304 | } | 1511 | } |
| @@ -1311,6 +1518,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
| 1311 | { | 1518 | { |
| 1312 | struct iwl_mvm_sta *mvm_sta; | 1519 | struct iwl_mvm_sta *mvm_sta; |
| 1313 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1520 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); |
| 1521 | bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); | ||
| 1314 | 1522 | ||
| 1315 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) | 1523 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) |
| 1316 | return; | 1524 | return; |
| @@ -1325,8 +1533,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
| 1325 | } | 1533 | } |
| 1326 | } | 1534 | } |
| 1327 | 1535 | ||
| 1328 | mvm_sta = (void *)sta->drv_priv; | 1536 | mvm_sta = iwl_mvm_sta_from_mac80211(sta); |
| 1329 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | 1537 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, |
| 1330 | iv32, phase1key, CMD_ASYNC); | 1538 | iv32, phase1key, CMD_ASYNC); |
| 1331 | rcu_read_unlock(); | 1539 | rcu_read_unlock(); |
| 1332 | } | 1540 | } |
| @@ -1524,3 +1732,18 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, | |||
| 1524 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); | 1732 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); |
| 1525 | } | 1733 | } |
| 1526 | } | 1734 | } |
| 1735 | |||
| 1736 | void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
| 1737 | { | ||
| 1738 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 1739 | struct iwl_mvm_sta *mvmsta; | ||
| 1740 | |||
| 1741 | rcu_read_lock(); | ||
| 1742 | |||
| 1743 | mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id); | ||
| 1744 | |||
| 1745 | if (!WARN_ON(!mvmsta)) | ||
| 1746 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); | ||
| 1747 | |||
| 1748 | rcu_read_unlock(); | ||
| 1749 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 3b1c8bd6cb54..d8f48975ad08 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -262,6 +264,7 @@ enum iwl_mvm_agg_state { | |||
| 262 | * the first packet to be sent in legacy HW queue in Tx AGG stop flow. | 264 | * the first packet to be sent in legacy HW queue in Tx AGG stop flow. |
| 263 | * Basically when next_reclaimed reaches ssn, we can tell mac80211 that | 265 | * Basically when next_reclaimed reaches ssn, we can tell mac80211 that |
| 264 | * we are ready to finish the Tx AGG stop / start flow. | 266 | * we are ready to finish the Tx AGG stop / start flow. |
| 267 | * @tx_time: medium time consumed by this A-MPDU | ||
| 265 | */ | 268 | */ |
| 266 | struct iwl_mvm_tid_data { | 269 | struct iwl_mvm_tid_data { |
| 267 | u16 seq_number; | 270 | u16 seq_number; |
| @@ -272,6 +275,7 @@ struct iwl_mvm_tid_data { | |||
| 272 | enum iwl_mvm_agg_state state; | 275 | enum iwl_mvm_agg_state state; |
| 273 | u16 txq_id; | 276 | u16 txq_id; |
| 274 | u16 ssn; | 277 | u16 ssn; |
| 278 | u16 tx_time; | ||
| 275 | }; | 279 | }; |
| 276 | 280 | ||
| 277 | static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | 281 | static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) |
| @@ -284,6 +288,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | |||
| 284 | * struct iwl_mvm_sta - representation of a station in the driver | 288 | * struct iwl_mvm_sta - representation of a station in the driver |
| 285 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) | 289 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) |
| 286 | * @tfd_queue_msk: the tfd queues used by the station | 290 | * @tfd_queue_msk: the tfd queues used by the station |
| 291 | * @hw_queue: per-AC mapping of the TFD queues used by station | ||
| 287 | * @mac_id_n_color: the MAC context this station is linked to | 292 | * @mac_id_n_color: the MAC context this station is linked to |
| 288 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for | 293 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for |
| 289 | * tid. | 294 | * tid. |
| @@ -297,6 +302,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | |||
| 297 | * @tx_protection: reference counter for controlling the Tx protection. | 302 | * @tx_protection: reference counter for controlling the Tx protection. |
| 298 | * @tt_tx_protection: is thermal throttling enable Tx protection? | 303 | * @tt_tx_protection: is thermal throttling enable Tx protection? |
| 299 | * @disable_tx: is tx to this STA disabled? | 304 | * @disable_tx: is tx to this STA disabled? |
| 305 | * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) | ||
| 300 | * | 306 | * |
| 301 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) | 307 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) |
| 302 | * in the structure for use by driver. This structure is placed in that | 308 | * in the structure for use by driver. This structure is placed in that |
| @@ -306,6 +312,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | |||
| 306 | struct iwl_mvm_sta { | 312 | struct iwl_mvm_sta { |
| 307 | u32 sta_id; | 313 | u32 sta_id; |
| 308 | u32 tfd_queue_msk; | 314 | u32 tfd_queue_msk; |
| 315 | u8 hw_queue[IEEE80211_NUM_ACS]; | ||
| 309 | u32 mac_id_n_color; | 316 | u32 mac_id_n_color; |
| 310 | u16 tid_disable_agg; | 317 | u16 tid_disable_agg; |
| 311 | u8 max_agg_bufsize; | 318 | u8 max_agg_bufsize; |
| @@ -321,6 +328,7 @@ struct iwl_mvm_sta { | |||
| 321 | bool tt_tx_protection; | 328 | bool tt_tx_protection; |
| 322 | 329 | ||
| 323 | bool disable_tx; | 330 | bool disable_tx; |
| 331 | u8 agg_tids; | ||
| 324 | }; | 332 | }; |
| 325 | 333 | ||
| 326 | static inline struct iwl_mvm_sta * | 334 | static inline struct iwl_mvm_sta * |
| @@ -387,17 +395,15 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 387 | struct ieee80211_sta *sta, u16 tid); | 395 | struct ieee80211_sta *sta, u16 tid); |
| 388 | 396 | ||
| 389 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); | 397 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); |
| 390 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | 398 | void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm); |
| 391 | u32 qmask, enum nl80211_iftype iftype); | 399 | |
| 392 | void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, | 400 | int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 393 | struct iwl_mvm_int_sta *sta); | 401 | int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 394 | int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 402 | int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 395 | struct iwl_mvm_int_sta *bsta); | 403 | int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 396 | int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, | 404 | int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 397 | struct iwl_mvm_int_sta *bsta); | 405 | void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
| 398 | int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 406 | |
| 399 | struct iwl_mvm_int_sta *bsta); | ||
| 400 | int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta); | ||
| 401 | void iwl_mvm_sta_drained_wk(struct work_struct *wk); | 407 | void iwl_mvm_sta_drained_wk(struct work_struct *wk); |
| 402 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | 408 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, |
| 403 | struct ieee80211_sta *sta); | 409 | struct ieee80211_sta *sta); |
| @@ -416,5 +422,6 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, | |||
| 416 | void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, | 422 | void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, |
| 417 | struct iwl_mvm_vif *mvmvif, | 423 | struct iwl_mvm_vif *mvmvif, |
| 418 | bool disable); | 424 | bool disable); |
| 425 | void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
| 419 | 426 | ||
| 420 | #endif /* __sta_h__ */ | 427 | #endif /* __sta_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c new file mode 100644 index 000000000000..c0e00bae5bd0 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c | |||
| @@ -0,0 +1,706 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * | ||
| 3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
| 4 | * redistributing this file, you may do so under either license. | ||
| 5 | * | ||
| 6 | * GPL LICENSE SUMMARY | ||
| 7 | * | ||
| 8 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of version 2 of the GNU General Public License as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
| 22 | * USA | ||
| 23 | * | ||
| 24 | * The full GNU General Public License is included in this distribution | ||
| 25 | * in the file called COPYING. | ||
| 26 | * | ||
| 27 | * Contact Information: | ||
| 28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
| 29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
| 30 | * | ||
| 31 | * BSD LICENSE | ||
| 32 | * | ||
| 33 | * Copyright(c) 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | ||
| 35 | * | ||
| 36 | * Redistribution and use in source and binary forms, with or without | ||
| 37 | * modification, are permitted provided that the following conditions | ||
| 38 | * are met: | ||
| 39 | * | ||
| 40 | * * Redistributions of source code must retain the above copyright | ||
| 41 | * notice, this list of conditions and the following disclaimer. | ||
| 42 | * * Redistributions in binary form must reproduce the above copyright | ||
| 43 | * notice, this list of conditions and the following disclaimer in | ||
| 44 | * the documentation and/or other materials provided with the | ||
| 45 | * distribution. | ||
| 46 | * * Neither the name Intel Corporation nor the names of its | ||
| 47 | * contributors may be used to endorse or promote products derived | ||
| 48 | * from this software without specific prior written permission. | ||
| 49 | * | ||
| 50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| 55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| 56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| 57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| 58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| 59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 61 | * | ||
| 62 | *****************************************************************************/ | ||
| 63 | |||
| 64 | #include <linux/etherdevice.h> | ||
| 65 | #include "mvm.h" | ||
| 66 | #include "time-event.h" | ||
| 67 | |||
| 68 | #define TU_TO_US(x) (x * 1024) | ||
| 69 | #define TU_TO_MS(x) (TU_TO_US(x) / 1000) | ||
| 70 | |||
| 71 | void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) | ||
| 72 | { | ||
| 73 | struct ieee80211_sta *sta; | ||
| 74 | struct iwl_mvm_sta *mvmsta; | ||
| 75 | int i; | ||
| 76 | |||
| 77 | lockdep_assert_held(&mvm->mutex); | ||
| 78 | |||
| 79 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
| 80 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
| 81 | lockdep_is_held(&mvm->mutex)); | ||
| 82 | if (!sta || IS_ERR(sta) || !sta->tdls) | ||
| 83 | continue; | ||
| 84 | |||
| 85 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 86 | ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, | ||
| 87 | NL80211_TDLS_TEARDOWN, | ||
| 88 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, | ||
| 89 | GFP_KERNEL); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
| 94 | { | ||
| 95 | struct ieee80211_sta *sta; | ||
| 96 | struct iwl_mvm_sta *mvmsta; | ||
| 97 | int count = 0; | ||
| 98 | int i; | ||
| 99 | |||
| 100 | lockdep_assert_held(&mvm->mutex); | ||
| 101 | |||
| 102 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
| 103 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
| 104 | lockdep_is_held(&mvm->mutex)); | ||
| 105 | if (!sta || IS_ERR(sta) || !sta->tdls) | ||
| 106 | continue; | ||
| 107 | |||
| 108 | if (vif) { | ||
| 109 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 110 | if (mvmsta->vif != vif) | ||
| 111 | continue; | ||
| 112 | } | ||
| 113 | |||
| 114 | count++; | ||
| 115 | } | ||
| 116 | |||
| 117 | return count; | ||
| 118 | } | ||
| 119 | |||
| 120 | static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
| 121 | { | ||
| 122 | struct iwl_rx_packet *pkt; | ||
| 123 | struct iwl_tdls_config_res *resp; | ||
| 124 | struct iwl_tdls_config_cmd tdls_cfg_cmd = {}; | ||
| 125 | struct iwl_host_cmd cmd = { | ||
| 126 | .id = TDLS_CONFIG_CMD, | ||
| 127 | .flags = CMD_WANT_SKB, | ||
| 128 | .data = { &tdls_cfg_cmd, }, | ||
| 129 | .len = { sizeof(struct iwl_tdls_config_cmd), }, | ||
| 130 | }; | ||
| 131 | struct ieee80211_sta *sta; | ||
| 132 | int ret, i, cnt; | ||
| 133 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 134 | |||
| 135 | lockdep_assert_held(&mvm->mutex); | ||
| 136 | |||
| 137 | tdls_cfg_cmd.id_and_color = | ||
| 138 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
| 139 | tdls_cfg_cmd.tx_to_ap_tid = IWL_MVM_TDLS_FW_TID; | ||
| 140 | tdls_cfg_cmd.tx_to_ap_ssn = cpu_to_le16(0); /* not used for now */ | ||
| 141 | |||
| 142 | /* for now the Tx cmd is empty and unused */ | ||
| 143 | |||
| 144 | /* populate TDLS peer data */ | ||
| 145 | cnt = 0; | ||
| 146 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
| 147 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
| 148 | lockdep_is_held(&mvm->mutex)); | ||
| 149 | if (IS_ERR_OR_NULL(sta) || !sta->tdls) | ||
| 150 | continue; | ||
| 151 | |||
| 152 | tdls_cfg_cmd.sta_info[cnt].sta_id = i; | ||
| 153 | tdls_cfg_cmd.sta_info[cnt].tx_to_peer_tid = | ||
| 154 | IWL_MVM_TDLS_FW_TID; | ||
| 155 | tdls_cfg_cmd.sta_info[cnt].tx_to_peer_ssn = cpu_to_le16(0); | ||
| 156 | tdls_cfg_cmd.sta_info[cnt].is_initiator = | ||
| 157 | cpu_to_le32(sta->tdls_initiator ? 1 : 0); | ||
| 158 | |||
| 159 | cnt++; | ||
| 160 | } | ||
| 161 | |||
| 162 | tdls_cfg_cmd.tdls_peer_count = cnt; | ||
| 163 | IWL_DEBUG_TDLS(mvm, "send TDLS config to FW for %d peers\n", cnt); | ||
| 164 | |||
| 165 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
| 166 | if (WARN_ON_ONCE(ret)) | ||
| 167 | return; | ||
| 168 | |||
| 169 | pkt = cmd.resp_pkt; | ||
| 170 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
| 171 | IWL_ERR(mvm, "Bad return from TDLS_CONFIG_COMMAND (0x%08X)\n", | ||
| 172 | pkt->hdr.flags); | ||
| 173 | goto exit; | ||
| 174 | } | ||
| 175 | |||
| 176 | if (WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp))) | ||
| 177 | goto exit; | ||
| 178 | |||
| 179 | /* we don't really care about the response at this point */ | ||
| 180 | |||
| 181 | exit: | ||
| 182 | iwl_free_resp(&cmd); | ||
| 183 | } | ||
| 184 | |||
| 185 | void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
| 186 | bool sta_added) | ||
| 187 | { | ||
| 188 | int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); | ||
| 189 | |||
| 190 | /* when the first peer joins, send a power update first */ | ||
| 191 | if (tdls_sta_cnt == 1 && sta_added) | ||
| 192 | iwl_mvm_power_update_mac(mvm); | ||
| 193 | |||
| 194 | /* configure the FW with TDLS peer info */ | ||
| 195 | iwl_mvm_tdls_config(mvm, vif); | ||
| 196 | |||
| 197 | /* when the last peer leaves, send a power update last */ | ||
| 198 | if (tdls_sta_cnt == 0 && !sta_added) | ||
| 199 | iwl_mvm_power_update_mac(mvm); | ||
| 200 | } | ||
| 201 | |||
| 202 | void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | ||
| 203 | struct ieee80211_vif *vif) | ||
| 204 | { | ||
| 205 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 206 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; | ||
| 207 | |||
| 208 | /* | ||
| 209 | * iwl_mvm_protect_session() reads directly from the device | ||
| 210 | * (the system time), so make sure it is available. | ||
| 211 | */ | ||
| 212 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) | ||
| 213 | return; | ||
| 214 | |||
| 215 | mutex_lock(&mvm->mutex); | ||
| 216 | /* Protect the session to hear the TDLS setup response on the channel */ | ||
| 217 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); | ||
| 218 | mutex_unlock(&mvm->mutex); | ||
| 219 | |||
| 220 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); | ||
| 221 | } | ||
| 222 | |||
| 223 | static const char * | ||
| 224 | iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state) | ||
| 225 | { | ||
| 226 | switch (state) { | ||
| 227 | case IWL_MVM_TDLS_SW_IDLE: | ||
| 228 | return "IDLE"; | ||
| 229 | case IWL_MVM_TDLS_SW_REQ_SENT: | ||
| 230 | return "REQ SENT"; | ||
| 231 | case IWL_MVM_TDLS_SW_REQ_RCVD: | ||
| 232 | return "REQ RECEIVED"; | ||
| 233 | case IWL_MVM_TDLS_SW_ACTIVE: | ||
| 234 | return "ACTIVE"; | ||
| 235 | } | ||
| 236 | |||
| 237 | return NULL; | ||
| 238 | } | ||
| 239 | |||
| 240 | static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, | ||
| 241 | enum iwl_mvm_tdls_cs_state state) | ||
| 242 | { | ||
| 243 | if (mvm->tdls_cs.state == state) | ||
| 244 | return; | ||
| 245 | |||
| 246 | IWL_DEBUG_TDLS(mvm, "TDLS channel switch state: %s -> %s\n", | ||
| 247 | iwl_mvm_tdls_cs_state_str(mvm->tdls_cs.state), | ||
| 248 | iwl_mvm_tdls_cs_state_str(state)); | ||
| 249 | mvm->tdls_cs.state = state; | ||
| 250 | |||
| 251 | if (state == IWL_MVM_TDLS_SW_IDLE) | ||
| 252 | mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; | ||
| 253 | } | ||
| 254 | |||
| 255 | int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||
| 256 | struct iwl_device_cmd *cmd) | ||
| 257 | { | ||
| 258 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
| 259 | struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data; | ||
| 260 | struct ieee80211_sta *sta; | ||
| 261 | unsigned int delay; | ||
| 262 | struct iwl_mvm_sta *mvmsta; | ||
| 263 | struct ieee80211_vif *vif; | ||
| 264 | u32 sta_id = le32_to_cpu(notif->sta_id); | ||
| 265 | |||
| 266 | lockdep_assert_held(&mvm->mutex); | ||
| 267 | |||
| 268 | /* can fail sometimes */ | ||
| 269 | if (!le32_to_cpu(notif->status)) { | ||
| 270 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); | ||
| 271 | goto out; | ||
| 272 | } | ||
| 273 | |||
| 274 | if (WARN_ON(sta_id >= IWL_MVM_STATION_COUNT)) | ||
| 275 | goto out; | ||
| 276 | |||
| 277 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
| 278 | lockdep_is_held(&mvm->mutex)); | ||
| 279 | /* the station may not be here, but if it is, it must be a TDLS peer */ | ||
| 280 | if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls)) | ||
| 281 | goto out; | ||
| 282 | |||
| 283 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 284 | vif = mvmsta->vif; | ||
| 285 | |||
| 286 | /* | ||
| 287 | * Update state and possibly switch again after this is over (DTIM). | ||
| 288 | * Also convert TU to msec. | ||
| 289 | */ | ||
| 290 | delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); | ||
| 291 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
| 292 | msecs_to_jiffies(delay)); | ||
| 293 | |||
| 294 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); | ||
| 295 | |||
| 296 | out: | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | static int | ||
| 301 | iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, | ||
| 302 | enum iwl_tdls_channel_switch_type type, | ||
| 303 | const u8 *peer, bool peer_initiator) | ||
| 304 | { | ||
| 305 | bool same_peer = false; | ||
| 306 | int ret = 0; | ||
| 307 | |||
| 308 | /* get the existing peer if it's there */ | ||
| 309 | if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE && | ||
| 310 | mvm->tdls_cs.cur_sta_id != IWL_MVM_STATION_COUNT) { | ||
| 311 | struct ieee80211_sta *sta = rcu_dereference_protected( | ||
| 312 | mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], | ||
| 313 | lockdep_is_held(&mvm->mutex)); | ||
| 314 | if (!IS_ERR_OR_NULL(sta)) | ||
| 315 | same_peer = ether_addr_equal(peer, sta->addr); | ||
| 316 | } | ||
| 317 | |||
| 318 | switch (mvm->tdls_cs.state) { | ||
| 319 | case IWL_MVM_TDLS_SW_IDLE: | ||
| 320 | /* | ||
| 321 | * might be spurious packet from the peer after the switch is | ||
| 322 | * already done | ||
| 323 | */ | ||
| 324 | if (type == TDLS_MOVE_CH) | ||
| 325 | ret = -EINVAL; | ||
| 326 | break; | ||
| 327 | case IWL_MVM_TDLS_SW_REQ_SENT: | ||
| 328 | /* | ||
| 329 | * We received a ch-switch request while an outgoing one is | ||
| 330 | * pending. Allow it to proceed if the other peer is the same | ||
| 331 | * one we sent to, and we are not the link initiator. | ||
| 332 | */ | ||
| 333 | if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) { | ||
| 334 | if (!same_peer) | ||
| 335 | ret = -EBUSY; | ||
| 336 | else if (!peer_initiator) /* we are the initiator */ | ||
| 337 | ret = -EBUSY; | ||
| 338 | } | ||
| 339 | break; | ||
| 340 | case IWL_MVM_TDLS_SW_REQ_RCVD: | ||
| 341 | /* as above, allow the link initiator to proceed */ | ||
| 342 | if (type == TDLS_SEND_CHAN_SW_REQ) { | ||
| 343 | if (!same_peer) | ||
| 344 | ret = -EBUSY; | ||
| 345 | else if (peer_initiator) /* they are the initiator */ | ||
| 346 | ret = -EBUSY; | ||
| 347 | } else if (type == TDLS_MOVE_CH) { | ||
| 348 | ret = -EINVAL; | ||
| 349 | } | ||
| 350 | break; | ||
| 351 | case IWL_MVM_TDLS_SW_ACTIVE: | ||
| 352 | /* we don't allow initiations during active channel switch */ | ||
| 353 | if (type == TDLS_SEND_CHAN_SW_REQ) | ||
| 354 | ret = -EINVAL; | ||
| 355 | break; | ||
| 356 | } | ||
| 357 | |||
| 358 | if (ret) | ||
| 359 | IWL_DEBUG_TDLS(mvm, | ||
| 360 | "Invalid TDLS action %d state %d peer %pM same_peer %d initiator %d\n", | ||
| 361 | type, mvm->tdls_cs.state, peer, same_peer, | ||
| 362 | peer_initiator); | ||
| 363 | |||
| 364 | return ret; | ||
| 365 | } | ||
| 366 | |||
| 367 | static int | ||
| 368 | iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, | ||
| 369 | struct ieee80211_vif *vif, | ||
| 370 | enum iwl_tdls_channel_switch_type type, | ||
| 371 | const u8 *peer, bool peer_initiator, | ||
| 372 | u8 oper_class, | ||
| 373 | struct cfg80211_chan_def *chandef, | ||
| 374 | u32 timestamp, u16 switch_time, | ||
| 375 | u16 switch_timeout, struct sk_buff *skb, | ||
| 376 | u32 ch_sw_tm_ie) | ||
| 377 | { | ||
| 378 | struct ieee80211_sta *sta; | ||
| 379 | struct iwl_mvm_sta *mvmsta; | ||
| 380 | struct ieee80211_tx_info *info; | ||
| 381 | struct ieee80211_hdr *hdr; | ||
| 382 | struct iwl_tdls_channel_switch_cmd cmd = {0}; | ||
| 383 | int ret; | ||
| 384 | |||
| 385 | lockdep_assert_held(&mvm->mutex); | ||
| 386 | |||
| 387 | ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator); | ||
| 388 | if (ret) | ||
| 389 | return ret; | ||
| 390 | |||
| 391 | if (!skb || WARN_ON(skb->len > IWL_TDLS_CH_SW_FRAME_MAX_SIZE)) { | ||
| 392 | ret = -EINVAL; | ||
| 393 | goto out; | ||
| 394 | } | ||
| 395 | |||
| 396 | cmd.switch_type = type; | ||
| 397 | cmd.timing.frame_timestamp = cpu_to_le32(timestamp); | ||
| 398 | cmd.timing.switch_time = cpu_to_le32(switch_time); | ||
| 399 | cmd.timing.switch_timeout = cpu_to_le32(switch_timeout); | ||
| 400 | |||
| 401 | rcu_read_lock(); | ||
| 402 | sta = ieee80211_find_sta(vif, peer); | ||
| 403 | if (!sta) { | ||
| 404 | rcu_read_unlock(); | ||
| 405 | ret = -ENOENT; | ||
| 406 | goto out; | ||
| 407 | } | ||
| 408 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 409 | cmd.peer_sta_id = cpu_to_le32(mvmsta->sta_id); | ||
| 410 | |||
| 411 | if (!chandef) { | ||
| 412 | if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && | ||
| 413 | mvm->tdls_cs.peer.chandef.chan) { | ||
| 414 | /* actually moving to the channel */ | ||
| 415 | chandef = &mvm->tdls_cs.peer.chandef; | ||
| 416 | } else if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_ACTIVE && | ||
| 417 | type == TDLS_MOVE_CH) { | ||
| 418 | /* we need to return to base channel */ | ||
| 419 | struct ieee80211_chanctx_conf *chanctx = | ||
| 420 | rcu_dereference(vif->chanctx_conf); | ||
| 421 | |||
| 422 | if (WARN_ON_ONCE(!chanctx)) { | ||
| 423 | rcu_read_unlock(); | ||
| 424 | goto out; | ||
| 425 | } | ||
| 426 | |||
| 427 | chandef = &chanctx->def; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | if (chandef) { | ||
| 432 | cmd.ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ? | ||
| 433 | PHY_BAND_24 : PHY_BAND_5); | ||
| 434 | cmd.ci.channel = chandef->chan->hw_value; | ||
| 435 | cmd.ci.width = iwl_mvm_get_channel_width(chandef); | ||
| 436 | cmd.ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); | ||
| 437 | } | ||
| 438 | |||
| 439 | /* keep quota calculation simple for now - 50% of DTIM for TDLS */ | ||
| 440 | cmd.timing.max_offchan_duration = | ||
| 441 | cpu_to_le32(TU_TO_US(vif->bss_conf.dtim_period * | ||
| 442 | vif->bss_conf.beacon_int) / 2); | ||
| 443 | |||
| 444 | /* Switch time is the first element in the switch-timing IE. */ | ||
| 445 | cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2); | ||
| 446 | |||
| 447 | info = IEEE80211_SKB_CB(skb); | ||
| 448 | if (info->control.hw_key) | ||
| 449 | iwl_mvm_set_tx_cmd_crypto(mvm, info, &cmd.frame.tx_cmd, skb); | ||
| 450 | |||
| 451 | iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info, | ||
| 452 | mvmsta->sta_id); | ||
| 453 | |||
| 454 | hdr = (void *)skb->data; | ||
| 455 | iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta, | ||
| 456 | hdr->frame_control); | ||
| 457 | rcu_read_unlock(); | ||
| 458 | |||
| 459 | memcpy(cmd.frame.data, skb->data, skb->len); | ||
| 460 | |||
| 461 | ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, | ||
| 462 | sizeof(cmd), &cmd); | ||
| 463 | if (ret) { | ||
| 464 | IWL_ERR(mvm, "Failed to send TDLS_CHANNEL_SWITCH cmd: %d\n", | ||
| 465 | ret); | ||
| 466 | goto out; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* channel switch has started, update state */ | ||
| 470 | if (type != TDLS_MOVE_CH) { | ||
| 471 | mvm->tdls_cs.cur_sta_id = mvmsta->sta_id; | ||
| 472 | iwl_mvm_tdls_update_cs_state(mvm, | ||
| 473 | type == TDLS_SEND_CHAN_SW_REQ ? | ||
| 474 | IWL_MVM_TDLS_SW_REQ_SENT : | ||
| 475 | IWL_MVM_TDLS_SW_REQ_RCVD); | ||
| 476 | } | ||
| 477 | |||
| 478 | out: | ||
| 479 | |||
| 480 | /* channel switch failed - we are idle */ | ||
| 481 | if (ret) | ||
| 482 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); | ||
| 483 | |||
| 484 | return ret; | ||
| 485 | } | ||
| 486 | |||
| 487 | void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) | ||
| 488 | { | ||
| 489 | struct iwl_mvm *mvm; | ||
| 490 | struct ieee80211_sta *sta; | ||
| 491 | struct iwl_mvm_sta *mvmsta; | ||
| 492 | struct ieee80211_vif *vif; | ||
| 493 | unsigned int delay; | ||
| 494 | int ret; | ||
| 495 | |||
| 496 | mvm = container_of(work, struct iwl_mvm, tdls_cs.dwork.work); | ||
| 497 | mutex_lock(&mvm->mutex); | ||
| 498 | |||
| 499 | /* called after an active channel switch has finished or timed-out */ | ||
| 500 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); | ||
| 501 | |||
| 502 | /* station might be gone, in that case do nothing */ | ||
| 503 | if (mvm->tdls_cs.peer.sta_id == IWL_MVM_STATION_COUNT) | ||
| 504 | goto out; | ||
| 505 | |||
| 506 | sta = rcu_dereference_protected( | ||
| 507 | mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id], | ||
| 508 | lockdep_is_held(&mvm->mutex)); | ||
| 509 | /* the station may not be here, but if it is, it must be a TDLS peer */ | ||
| 510 | if (!sta || IS_ERR(sta) || WARN_ON(!sta->tdls)) | ||
| 511 | goto out; | ||
| 512 | |||
| 513 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 514 | vif = mvmsta->vif; | ||
| 515 | ret = iwl_mvm_tdls_config_channel_switch(mvm, vif, | ||
| 516 | TDLS_SEND_CHAN_SW_REQ, | ||
| 517 | sta->addr, | ||
| 518 | mvm->tdls_cs.peer.initiator, | ||
| 519 | mvm->tdls_cs.peer.op_class, | ||
| 520 | &mvm->tdls_cs.peer.chandef, | ||
| 521 | 0, 0, 0, | ||
| 522 | mvm->tdls_cs.peer.skb, | ||
| 523 | mvm->tdls_cs.peer.ch_sw_tm_ie); | ||
| 524 | if (ret) | ||
| 525 | IWL_ERR(mvm, "Not sending TDLS channel switch: %d\n", ret); | ||
| 526 | |||
| 527 | /* retry after a DTIM if we failed sending now */ | ||
| 528 | delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); | ||
| 529 | queue_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
| 530 | msecs_to_jiffies(delay)); | ||
| 531 | out: | ||
| 532 | mutex_unlock(&mvm->mutex); | ||
| 533 | } | ||
| 534 | |||
| 535 | int | ||
| 536 | iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, | ||
| 537 | struct ieee80211_vif *vif, | ||
| 538 | struct ieee80211_sta *sta, u8 oper_class, | ||
| 539 | struct cfg80211_chan_def *chandef, | ||
| 540 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie) | ||
| 541 | { | ||
| 542 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 543 | struct iwl_mvm_sta *mvmsta; | ||
| 544 | unsigned int delay; | ||
| 545 | int ret; | ||
| 546 | |||
| 547 | mutex_lock(&mvm->mutex); | ||
| 548 | |||
| 549 | IWL_DEBUG_TDLS(mvm, "TDLS channel switch with %pM ch %d width %d\n", | ||
| 550 | sta->addr, chandef->chan->center_freq, chandef->width); | ||
| 551 | |||
| 552 | /* we only support a single peer for channel switching */ | ||
| 553 | if (mvm->tdls_cs.peer.sta_id != IWL_MVM_STATION_COUNT) { | ||
| 554 | IWL_DEBUG_TDLS(mvm, | ||
| 555 | "Existing peer. Can't start switch with %pM\n", | ||
| 556 | sta->addr); | ||
| 557 | ret = -EBUSY; | ||
| 558 | goto out; | ||
| 559 | } | ||
| 560 | |||
| 561 | ret = iwl_mvm_tdls_config_channel_switch(mvm, vif, | ||
| 562 | TDLS_SEND_CHAN_SW_REQ, | ||
| 563 | sta->addr, sta->tdls_initiator, | ||
| 564 | oper_class, chandef, 0, 0, 0, | ||
| 565 | tmpl_skb, ch_sw_tm_ie); | ||
| 566 | if (ret) | ||
| 567 | goto out; | ||
| 568 | |||
| 569 | /* | ||
| 570 | * Mark the peer as "in tdls switch" for this vif. We only allow a | ||
| 571 | * single such peer per vif. | ||
| 572 | */ | ||
| 573 | mvm->tdls_cs.peer.skb = skb_copy(tmpl_skb, GFP_KERNEL); | ||
| 574 | if (!mvm->tdls_cs.peer.skb) { | ||
| 575 | ret = -ENOMEM; | ||
| 576 | goto out; | ||
| 577 | } | ||
| 578 | |||
| 579 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
| 580 | mvm->tdls_cs.peer.sta_id = mvmsta->sta_id; | ||
| 581 | mvm->tdls_cs.peer.chandef = *chandef; | ||
| 582 | mvm->tdls_cs.peer.initiator = sta->tdls_initiator; | ||
| 583 | mvm->tdls_cs.peer.op_class = oper_class; | ||
| 584 | mvm->tdls_cs.peer.ch_sw_tm_ie = ch_sw_tm_ie; | ||
| 585 | |||
| 586 | /* | ||
| 587 | * Wait for 2 DTIM periods before attempting the next switch. The next | ||
| 588 | * switch will be made sooner if the current one completes before that. | ||
| 589 | */ | ||
| 590 | delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period * | ||
| 591 | vif->bss_conf.beacon_int); | ||
| 592 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
| 593 | msecs_to_jiffies(delay)); | ||
| 594 | |||
| 595 | out: | ||
| 596 | mutex_unlock(&mvm->mutex); | ||
| 597 | return ret; | ||
| 598 | } | ||
| 599 | |||
| 600 | void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, | ||
| 601 | struct ieee80211_vif *vif, | ||
| 602 | struct ieee80211_sta *sta) | ||
| 603 | { | ||
| 604 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 605 | struct ieee80211_sta *cur_sta; | ||
| 606 | bool wait_for_phy = false; | ||
| 607 | |||
| 608 | mutex_lock(&mvm->mutex); | ||
| 609 | |||
| 610 | IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr); | ||
| 611 | |||
| 612 | /* we only support a single peer for channel switching */ | ||
| 613 | if (mvm->tdls_cs.peer.sta_id == IWL_MVM_STATION_COUNT) { | ||
| 614 | IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr); | ||
| 615 | goto out; | ||
| 616 | } | ||
| 617 | |||
| 618 | cur_sta = rcu_dereference_protected( | ||
| 619 | mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id], | ||
| 620 | lockdep_is_held(&mvm->mutex)); | ||
| 621 | /* make sure it's the same peer */ | ||
| 622 | if (cur_sta != sta) | ||
| 623 | goto out; | ||
| 624 | |||
| 625 | /* | ||
| 626 | * If we're currently in a switch because of the now canceled peer, | ||
| 627 | * wait a DTIM here to make sure the phy is back on the base channel. | ||
| 628 | * We can't otherwise force it. | ||
| 629 | */ | ||
| 630 | if (mvm->tdls_cs.cur_sta_id == mvm->tdls_cs.peer.sta_id && | ||
| 631 | mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE) | ||
| 632 | wait_for_phy = true; | ||
| 633 | |||
| 634 | mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; | ||
| 635 | dev_kfree_skb(mvm->tdls_cs.peer.skb); | ||
| 636 | mvm->tdls_cs.peer.skb = NULL; | ||
| 637 | |||
| 638 | out: | ||
| 639 | mutex_unlock(&mvm->mutex); | ||
| 640 | |||
| 641 | /* make sure the phy is on the base channel */ | ||
| 642 | if (wait_for_phy) | ||
| 643 | msleep(TU_TO_MS(vif->bss_conf.dtim_period * | ||
| 644 | vif->bss_conf.beacon_int)); | ||
| 645 | |||
| 646 | /* flush the channel switch state */ | ||
| 647 | flush_delayed_work(&mvm->tdls_cs.dwork); | ||
| 648 | |||
| 649 | IWL_DEBUG_TDLS(mvm, "TDLS ending channel switch with %pM\n", sta->addr); | ||
| 650 | } | ||
| 651 | |||
| 652 | void | ||
| 653 | iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, | ||
| 654 | struct ieee80211_vif *vif, | ||
| 655 | struct ieee80211_tdls_ch_sw_params *params) | ||
| 656 | { | ||
| 657 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 658 | enum iwl_tdls_channel_switch_type type; | ||
| 659 | unsigned int delay; | ||
| 660 | |||
| 661 | mutex_lock(&mvm->mutex); | ||
| 662 | |||
| 663 | IWL_DEBUG_TDLS(mvm, | ||
| 664 | "Received TDLS ch switch action %d from %pM status %d\n", | ||
| 665 | params->action_code, params->sta->addr, params->status); | ||
| 666 | |||
| 667 | /* | ||
| 668 | * we got a non-zero status from a peer we were switching to - move to | ||
| 669 | * the idle state and retry again later | ||
| 670 | */ | ||
| 671 | if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE && | ||
| 672 | params->status != 0 && | ||
| 673 | mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && | ||
| 674 | mvm->tdls_cs.cur_sta_id != IWL_MVM_STATION_COUNT) { | ||
| 675 | struct ieee80211_sta *cur_sta; | ||
| 676 | |||
| 677 | /* make sure it's the same peer */ | ||
| 678 | cur_sta = rcu_dereference_protected( | ||
| 679 | mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], | ||
| 680 | lockdep_is_held(&mvm->mutex)); | ||
| 681 | if (cur_sta == params->sta) { | ||
| 682 | iwl_mvm_tdls_update_cs_state(mvm, | ||
| 683 | IWL_MVM_TDLS_SW_IDLE); | ||
| 684 | goto retry; | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | type = (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST) ? | ||
| 689 | TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH : TDLS_MOVE_CH; | ||
| 690 | |||
| 691 | iwl_mvm_tdls_config_channel_switch(mvm, vif, type, params->sta->addr, | ||
| 692 | params->sta->tdls_initiator, 0, | ||
| 693 | params->chandef, params->timestamp, | ||
| 694 | params->switch_time, | ||
| 695 | params->switch_timeout, | ||
| 696 | params->tmpl_skb, | ||
| 697 | params->ch_sw_tm_ie); | ||
| 698 | |||
| 699 | retry: | ||
| 700 | /* register a timeout in case we don't succeed in switching */ | ||
| 701 | delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int * | ||
| 702 | 1024 / 1000; | ||
| 703 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | ||
| 704 | msecs_to_jiffies(delay)); | ||
| 705 | mutex_unlock(&mvm->mutex); | ||
| 706 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/testmode.h b/drivers/net/wireless/iwlwifi/mvm/testmode.h index 0241665925f7..79ab6beb6b26 100644 --- a/drivers/net/wireless/iwlwifi/mvm/testmode.h +++ b/drivers/net/wireless/iwlwifi/mvm/testmode.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 33e5041f1efc..54fafbf9a711 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -189,6 +191,35 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, | |||
| 189 | return true; | 191 | return true; |
| 190 | } | 192 | } |
| 191 | 193 | ||
| 194 | static void | ||
| 195 | iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, | ||
| 196 | struct iwl_mvm_time_event_data *te_data, | ||
| 197 | struct iwl_time_event_notif *notif) | ||
| 198 | { | ||
| 199 | if (!le32_to_cpu(notif->status)) { | ||
| 200 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); | ||
| 201 | iwl_mvm_te_clear_data(mvm, te_data); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | switch (te_data->vif->type) { | ||
| 206 | case NL80211_IFTYPE_AP: | ||
| 207 | iwl_mvm_csa_noa_start(mvm); | ||
| 208 | break; | ||
| 209 | case NL80211_IFTYPE_STATION: | ||
| 210 | iwl_mvm_csa_client_absent(mvm, te_data->vif); | ||
| 211 | ieee80211_chswitch_done(te_data->vif, true); | ||
| 212 | break; | ||
| 213 | default: | ||
| 214 | /* should never happen */ | ||
| 215 | WARN_ON_ONCE(1); | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* we don't need it anymore */ | ||
| 220 | iwl_mvm_te_clear_data(mvm, te_data); | ||
| 221 | } | ||
| 222 | |||
| 192 | /* | 223 | /* |
| 193 | * Handles a FW notification for an event that is known to the driver. | 224 | * Handles a FW notification for an event that is known to the driver. |
| 194 | * | 225 | * |
| @@ -250,14 +281,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
| 250 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | 281 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); |
| 251 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); | 282 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); |
| 252 | ieee80211_ready_on_channel(mvm->hw); | 283 | ieee80211_ready_on_channel(mvm->hw); |
| 253 | } else if (te_data->vif->type == NL80211_IFTYPE_AP) { | 284 | } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) { |
| 254 | if (le32_to_cpu(notif->status)) | 285 | iwl_mvm_te_handle_notify_csa(mvm, te_data, notif); |
| 255 | iwl_mvm_csa_noa_start(mvm); | ||
| 256 | else | ||
| 257 | IWL_DEBUG_TE(mvm, "CSA NOA failed to start\n"); | ||
| 258 | |||
| 259 | /* we don't need it anymore */ | ||
| 260 | iwl_mvm_te_clear_data(mvm, te_data); | ||
| 261 | } | 286 | } |
| 262 | } else { | 287 | } else { |
| 263 | IWL_WARN(mvm, "Got TE with unknown action\n"); | 288 | IWL_WARN(mvm, "Got TE with unknown action\n"); |
| @@ -303,8 +328,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, | |||
| 303 | te_data->running = false; | 328 | te_data->running = false; |
| 304 | te_data->vif = NULL; | 329 | te_data->vif = NULL; |
| 305 | te_data->uid = 0; | 330 | te_data->uid = 0; |
| 331 | te_data->id = TE_MAX; | ||
| 306 | } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) { | 332 | } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) { |
| 307 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | ||
| 308 | set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); | 333 | set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); |
| 309 | te_data->running = true; | 334 | te_data->running = true; |
| 310 | ieee80211_ready_on_channel(mvm->hw); /* Start TE */ | 335 | ieee80211_ready_on_channel(mvm->hw); /* Start TE */ |
| @@ -348,6 +373,38 @@ unlock: | |||
| 348 | return 0; | 373 | return 0; |
| 349 | } | 374 | } |
| 350 | 375 | ||
| 376 | static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait, | ||
| 377 | struct iwl_rx_packet *pkt, void *data) | ||
| 378 | { | ||
| 379 | struct iwl_mvm *mvm = | ||
| 380 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
| 381 | struct iwl_mvm_time_event_data *te_data = data; | ||
| 382 | struct iwl_time_event_notif *resp; | ||
| 383 | int resp_len = iwl_rx_packet_payload_len(pkt); | ||
| 384 | |||
| 385 | if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION)) | ||
| 386 | return true; | ||
| 387 | |||
| 388 | if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { | ||
| 389 | IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n"); | ||
| 390 | return true; | ||
| 391 | } | ||
| 392 | |||
| 393 | resp = (void *)pkt->data; | ||
| 394 | |||
| 395 | /* te_data->uid is already set in the TIME_EVENT_CMD response */ | ||
| 396 | if (le32_to_cpu(resp->unique_id) != te_data->uid) | ||
| 397 | return false; | ||
| 398 | |||
| 399 | IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n", | ||
| 400 | te_data->uid); | ||
| 401 | if (!resp->status) | ||
| 402 | IWL_ERR(mvm, | ||
| 403 | "TIME_EVENT_NOTIFICATION received but not executed\n"); | ||
| 404 | |||
| 405 | return true; | ||
| 406 | } | ||
| 407 | |||
| 351 | static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, | 408 | static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, |
| 352 | struct iwl_rx_packet *pkt, void *data) | 409 | struct iwl_rx_packet *pkt, void *data) |
| 353 | { | 410 | { |
| @@ -441,10 +498,12 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | |||
| 441 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 498 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, |
| 442 | struct ieee80211_vif *vif, | 499 | struct ieee80211_vif *vif, |
| 443 | u32 duration, u32 min_duration, | 500 | u32 duration, u32 min_duration, |
| 444 | u32 max_delay) | 501 | u32 max_delay, bool wait_for_notif) |
| 445 | { | 502 | { |
| 446 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 503 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 447 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 504 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
| 505 | const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; | ||
| 506 | struct iwl_notification_wait wait_te_notif; | ||
| 448 | struct iwl_time_event_cmd time_cmd = {}; | 507 | struct iwl_time_event_cmd time_cmd = {}; |
| 449 | 508 | ||
| 450 | lockdep_assert_held(&mvm->mutex); | 509 | lockdep_assert_held(&mvm->mutex); |
| @@ -489,21 +548,35 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
| 489 | TE_V2_NOTIF_HOST_EVENT_END | | 548 | TE_V2_NOTIF_HOST_EVENT_END | |
| 490 | T2_V2_START_IMMEDIATELY); | 549 | T2_V2_START_IMMEDIATELY); |
| 491 | 550 | ||
| 492 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 551 | if (!wait_for_notif) { |
| 552 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | ||
| 553 | return; | ||
| 554 | } | ||
| 555 | |||
| 556 | /* | ||
| 557 | * Create notification_wait for the TIME_EVENT_NOTIFICATION to use | ||
| 558 | * right after we send the time event | ||
| 559 | */ | ||
| 560 | iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif, | ||
| 561 | te_notif_response, | ||
| 562 | ARRAY_SIZE(te_notif_response), | ||
| 563 | iwl_mvm_te_notif, te_data); | ||
| 564 | |||
| 565 | /* If TE was sent OK - wait for the notification that started */ | ||
| 566 | if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) { | ||
| 567 | IWL_ERR(mvm, "Failed to add TE to protect session\n"); | ||
| 568 | iwl_remove_notification(&mvm->notif_wait, &wait_te_notif); | ||
| 569 | } else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif, | ||
| 570 | TU_TO_JIFFIES(max_delay))) { | ||
| 571 | IWL_ERR(mvm, "Failed to protect session until TE\n"); | ||
| 572 | } | ||
| 493 | } | 573 | } |
| 494 | 574 | ||
| 495 | /* | 575 | static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, |
| 496 | * Explicit request to remove a time event. The removal of a time event needs to | 576 | struct iwl_mvm_time_event_data *te_data, |
| 497 | * be synchronized with the flow of a time event's end notification, which also | 577 | u32 *uid) |
| 498 | * removes the time event from the op mode data structures. | ||
| 499 | */ | ||
| 500 | void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | ||
| 501 | struct iwl_mvm_vif *mvmvif, | ||
| 502 | struct iwl_mvm_time_event_data *te_data) | ||
| 503 | { | 578 | { |
| 504 | struct iwl_time_event_cmd time_cmd = {}; | 579 | u32 id; |
| 505 | u32 id, uid; | ||
| 506 | int ret; | ||
| 507 | 580 | ||
| 508 | /* | 581 | /* |
| 509 | * It is possible that by the time we got to this point the time | 582 | * It is possible that by the time we got to this point the time |
| @@ -512,7 +585,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
| 512 | spin_lock_bh(&mvm->time_event_lock); | 585 | spin_lock_bh(&mvm->time_event_lock); |
| 513 | 586 | ||
| 514 | /* Save time event uid before clearing its data */ | 587 | /* Save time event uid before clearing its data */ |
| 515 | uid = te_data->uid; | 588 | *uid = te_data->uid; |
| 516 | id = te_data->id; | 589 | id = te_data->id; |
| 517 | 590 | ||
| 518 | /* | 591 | /* |
| @@ -527,10 +600,59 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
| 527 | * send a removal command. | 600 | * send a removal command. |
| 528 | */ | 601 | */ |
| 529 | if (id == TE_MAX) { | 602 | if (id == TE_MAX) { |
| 530 | IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid); | 603 | IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid); |
| 531 | return; | 604 | return false; |
| 532 | } | 605 | } |
| 533 | 606 | ||
| 607 | return true; | ||
| 608 | } | ||
| 609 | |||
| 610 | /* | ||
| 611 | * Explicit request to remove a aux roc time event. The removal of a time | ||
| 612 | * event needs to be synchronized with the flow of a time event's end | ||
| 613 | * notification, which also removes the time event from the op mode | ||
| 614 | * data structures. | ||
| 615 | */ | ||
| 616 | static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm, | ||
| 617 | struct iwl_mvm_vif *mvmvif, | ||
| 618 | struct iwl_mvm_time_event_data *te_data) | ||
| 619 | { | ||
| 620 | struct iwl_hs20_roc_req aux_cmd = {}; | ||
| 621 | u32 uid; | ||
| 622 | int ret; | ||
| 623 | |||
| 624 | if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid)) | ||
| 625 | return; | ||
| 626 | |||
| 627 | aux_cmd.event_unique_id = cpu_to_le32(uid); | ||
| 628 | aux_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); | ||
| 629 | aux_cmd.id_and_color = | ||
| 630 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||
| 631 | IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n", | ||
| 632 | le32_to_cpu(aux_cmd.event_unique_id)); | ||
| 633 | ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, | ||
| 634 | sizeof(aux_cmd), &aux_cmd); | ||
| 635 | |||
| 636 | if (WARN_ON(ret)) | ||
| 637 | return; | ||
| 638 | } | ||
| 639 | |||
| 640 | /* | ||
| 641 | * Explicit request to remove a time event. The removal of a time event needs to | ||
| 642 | * be synchronized with the flow of a time event's end notification, which also | ||
| 643 | * removes the time event from the op mode data structures. | ||
| 644 | */ | ||
| 645 | void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | ||
| 646 | struct iwl_mvm_vif *mvmvif, | ||
| 647 | struct iwl_mvm_time_event_data *te_data) | ||
| 648 | { | ||
| 649 | struct iwl_time_event_cmd time_cmd = {}; | ||
| 650 | u32 uid; | ||
| 651 | int ret; | ||
| 652 | |||
| 653 | if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid)) | ||
| 654 | return; | ||
| 655 | |||
| 534 | /* When we remove a TE, the UID is to be set in the id field */ | 656 | /* When we remove a TE, the UID is to be set in the id field */ |
| 535 | time_cmd.id = cpu_to_le32(uid); | 657 | time_cmd.id = cpu_to_le32(uid); |
| 536 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); | 658 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE); |
| @@ -609,13 +731,17 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 609 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 731 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
| 610 | } | 732 | } |
| 611 | 733 | ||
| 612 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | 734 | void iwl_mvm_stop_roc(struct iwl_mvm *mvm) |
| 613 | { | 735 | { |
| 614 | struct iwl_mvm_vif *mvmvif; | 736 | struct iwl_mvm_vif *mvmvif; |
| 615 | struct iwl_mvm_time_event_data *te_data; | 737 | struct iwl_mvm_time_event_data *te_data; |
| 738 | bool is_p2p = false; | ||
| 616 | 739 | ||
| 617 | lockdep_assert_held(&mvm->mutex); | 740 | lockdep_assert_held(&mvm->mutex); |
| 618 | 741 | ||
| 742 | mvmvif = NULL; | ||
| 743 | spin_lock_bh(&mvm->time_event_lock); | ||
| 744 | |||
| 619 | /* | 745 | /* |
| 620 | * Iterate over the list of time events and find the time event that is | 746 | * Iterate over the list of time events and find the time event that is |
| 621 | * associated with a P2P_DEVICE interface. | 747 | * associated with a P2P_DEVICE interface. |
| @@ -623,29 +749,48 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | |||
| 623 | * event at any given time and this time event coresponds to a ROC | 749 | * event at any given time and this time event coresponds to a ROC |
| 624 | * request | 750 | * request |
| 625 | */ | 751 | */ |
| 626 | mvmvif = NULL; | ||
| 627 | spin_lock_bh(&mvm->time_event_lock); | ||
| 628 | list_for_each_entry(te_data, &mvm->time_event_list, list) { | 752 | list_for_each_entry(te_data, &mvm->time_event_list, list) { |
| 629 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 753 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE && |
| 754 | te_data->running) { | ||
| 630 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | 755 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); |
| 631 | break; | 756 | is_p2p = true; |
| 757 | goto remove_te; | ||
| 758 | } | ||
| 759 | } | ||
| 760 | |||
| 761 | /* | ||
| 762 | * Iterate over the list of aux roc time events and find the time | ||
| 763 | * event that is associated with a BSS interface. | ||
| 764 | * This assumes that a BSS interface can have only a single time | ||
| 765 | * event at any given time and this time event coresponds to a ROC | ||
| 766 | * request | ||
| 767 | */ | ||
| 768 | list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { | ||
| 769 | if (te_data->running) { | ||
| 770 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | ||
| 771 | goto remove_te; | ||
| 632 | } | 772 | } |
| 633 | } | 773 | } |
| 774 | |||
| 775 | remove_te: | ||
| 634 | spin_unlock_bh(&mvm->time_event_lock); | 776 | spin_unlock_bh(&mvm->time_event_lock); |
| 635 | 777 | ||
| 636 | if (!mvmvif) { | 778 | if (!mvmvif) { |
| 637 | IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n"); | 779 | IWL_WARN(mvm, "No remain on channel event\n"); |
| 638 | return; | 780 | return; |
| 639 | } | 781 | } |
| 640 | 782 | ||
| 641 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | 783 | if (is_p2p) |
| 784 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | ||
| 785 | else | ||
| 786 | iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); | ||
| 642 | 787 | ||
| 643 | iwl_mvm_roc_finished(mvm); | 788 | iwl_mvm_roc_finished(mvm); |
| 644 | } | 789 | } |
| 645 | 790 | ||
| 646 | int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, | 791 | int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, |
| 647 | struct ieee80211_vif *vif, | 792 | struct ieee80211_vif *vif, |
| 648 | u32 duration, u32 apply_time) | 793 | u32 duration, u32 apply_time) |
| 649 | { | 794 | { |
| 650 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 795 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 651 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 796 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
| @@ -654,14 +799,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, | |||
| 654 | lockdep_assert_held(&mvm->mutex); | 799 | lockdep_assert_held(&mvm->mutex); |
| 655 | 800 | ||
| 656 | if (te_data->running) { | 801 | if (te_data->running) { |
| 657 | IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n"); | 802 | IWL_DEBUG_TE(mvm, "CS period is already scheduled\n"); |
| 658 | return -EBUSY; | 803 | return -EBUSY; |
| 659 | } | 804 | } |
| 660 | 805 | ||
| 661 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 806 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); |
| 662 | time_cmd.id_and_color = | 807 | time_cmd.id_and_color = |
| 663 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 808 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
| 664 | time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA); | 809 | time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD); |
| 665 | time_cmd.apply_time = cpu_to_le32(apply_time); | 810 | time_cmd.apply_time = cpu_to_le32(apply_time); |
| 666 | time_cmd.max_frags = TE_V2_FRAG_NONE; | 811 | time_cmd.max_frags = TE_V2_FRAG_NONE; |
| 667 | time_cmd.duration = cpu_to_le32(duration); | 812 | time_cmd.duration = cpu_to_le32(duration); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index 2f48a90d4ad3..6f6b35db3ab8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -124,10 +126,12 @@ | |||
| 124 | * @min_duration: will start a new session if the current session will end | 126 | * @min_duration: will start a new session if the current session will end |
| 125 | * in less than min_duration. | 127 | * in less than min_duration. |
| 126 | * @max_delay: maximum delay before starting the time event (in TU) | 128 | * @max_delay: maximum delay before starting the time event (in TU) |
| 129 | * @wait_for_notif: true if it is required that a time event notification be | ||
| 130 | * waited for (that the time event has been scheduled before returning) | ||
| 127 | * | 131 | * |
| 128 | * This function can be used to start a session protection which means that the | 132 | * This function can be used to start a session protection which means that the |
| 129 | * fw will stay on the channel for %duration_ms milliseconds. This function | 133 | * fw will stay on the channel for %duration_ms milliseconds. This function |
| 130 | * will block (sleep) until the session starts. This function can also be used | 134 | * can block (sleep) until the session starts. This function can also be used |
| 131 | * to extend a currently running session. | 135 | * to extend a currently running session. |
| 132 | * This function is meant to be used for BSS association for example, where we | 136 | * This function is meant to be used for BSS association for example, where we |
| 133 | * want to make sure that the fw stays on the channel during the association. | 137 | * want to make sure that the fw stays on the channel during the association. |
| @@ -135,7 +139,7 @@ | |||
| 135 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 139 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, |
| 136 | struct ieee80211_vif *vif, | 140 | struct ieee80211_vif *vif, |
| 137 | u32 duration, u32 min_duration, | 141 | u32 duration, u32 min_duration, |
| 138 | u32 max_delay); | 142 | u32 max_delay, bool wait_for_notif); |
| 139 | 143 | ||
| 140 | /** | 144 | /** |
| 141 | * iwl_mvm_stop_session_protection - cancel the session protection. | 145 | * iwl_mvm_stop_session_protection - cancel the session protection. |
| @@ -178,14 +182,14 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
| 178 | int duration, enum ieee80211_roc_type type); | 182 | int duration, enum ieee80211_roc_type type); |
| 179 | 183 | ||
| 180 | /** | 184 | /** |
| 181 | * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity | 185 | * iwl_mvm_stop_roc - stop remain on channel functionality |
| 182 | * @mvm: the mvm component | 186 | * @mvm: the mvm component |
| 183 | * | 187 | * |
| 184 | * This function can be used to cancel an ongoing ROC session. | 188 | * This function can be used to cancel an ongoing ROC session. |
| 185 | * The function is async, it will instruct the FW to stop serving the ROC | 189 | * The function is async, it will instruct the FW to stop serving the ROC |
| 186 | * session, but will not wait for the actual stopping of the session. | 190 | * session, but will not wait for the actual stopping of the session. |
| 187 | */ | 191 | */ |
| 188 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm); | 192 | void iwl_mvm_stop_roc(struct iwl_mvm *mvm); |
| 189 | 193 | ||
| 190 | /** | 194 | /** |
| 191 | * iwl_mvm_remove_time_event - general function to clean up of time event | 195 | * iwl_mvm_remove_time_event - general function to clean up of time event |
| @@ -215,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | |||
| 215 | void iwl_mvm_roc_done_wk(struct work_struct *wk); | 219 | void iwl_mvm_roc_done_wk(struct work_struct *wk); |
| 216 | 220 | ||
| 217 | /** | 221 | /** |
| 218 | * iwl_mvm_schedule_csa_noa - request NoA for channel switch | 222 | * iwl_mvm_schedule_csa_period - request channel switch absence period |
| 219 | * @mvm: the mvm component | 223 | * @mvm: the mvm component |
| 220 | * @vif: the virtual interface for which the channel switch is issued | 224 | * @vif: the virtual interface for which the channel switch is issued |
| 221 | * @duration: the duration of the NoA in TU. | 225 | * @duration: the duration of the NoA in TU. |
| @@ -224,9 +228,9 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk); | |||
| 224 | * This function is used to schedule NoA time event and is used to perform | 228 | * This function is used to schedule NoA time event and is used to perform |
| 225 | * the channel switch flow. | 229 | * the channel switch flow. |
| 226 | */ | 230 | */ |
| 227 | int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, | 231 | int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, |
| 228 | struct ieee80211_vif *vif, | 232 | struct ieee80211_vif *vif, |
| 229 | u32 duration, u32 apply_time); | 233 | u32 duration, u32 apply_time); |
| 230 | 234 | ||
| 231 | /** | 235 | /** |
| 232 | * iwl_mvm_te_scheduled - check if the fw received the TE cmd | 236 | * iwl_mvm_te_scheduled - check if the fw received the TE cmd |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 0464599c111e..2b1e61fac34a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -62,268 +64,149 @@ | |||
| 62 | *****************************************************************************/ | 64 | *****************************************************************************/ |
| 63 | 65 | ||
| 64 | #include "mvm.h" | 66 | #include "mvm.h" |
| 65 | #include "iwl-config.h" | ||
| 66 | #include "iwl-io.h" | ||
| 67 | #include "iwl-csr.h" | ||
| 68 | #include "iwl-prph.h" | ||
| 69 | |||
| 70 | #define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ | ||
| 71 | /* VBG - Voltage Band Gap error data (temperature offset) */ | ||
| 72 | #define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2) | ||
| 73 | #define MEAS_VBG_MIN_VAL 2300 | ||
| 74 | #define MEAS_VBG_MAX_VAL 3000 | ||
| 75 | #define MEAS_VBG_DEFAULT_VAL 2700 | ||
| 76 | #define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE) | ||
| 77 | #define MIN_TEMPERATURE 0 | ||
| 78 | #define MAX_TEMPERATURE 125 | ||
| 79 | #define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1) | ||
| 80 | #define PTAT_DIGITAL_VALUE_MIN_VALUE 0 | ||
| 81 | #define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF | ||
| 82 | #define DTS_VREFS_NUM 5 | ||
| 83 | static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags) | ||
| 84 | { | ||
| 85 | return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >> | ||
| 86 | DTS_DIODE_REG_FLAGS_VREFS_ID_POS; | ||
| 87 | } | ||
| 88 | 67 | ||
| 89 | #define CALC_VREFS_MIN_DIFF 43 | 68 | #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ |
| 90 | #define CALC_VREFS_MAX_DIFF 51 | ||
| 91 | #define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF) | ||
| 92 | #define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF | ||
| 93 | #define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23 | ||
| 94 | |||
| 95 | /* | ||
| 96 | * @digital_value: The diode's digital-value sampled (temperature/voltage) | ||
| 97 | * @vref_low: The lower voltage-reference (the vref just below the diode's | ||
| 98 | * sampled digital-value) | ||
| 99 | * @vref_high: The higher voltage-reference (the vref just above the diode's | ||
| 100 | * sampled digital-value) | ||
| 101 | * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref) | ||
| 102 | * bits[6:2]: Reserved. | ||
| 103 | * bits[7:7]: Indicates completion of at least 1 successful sample | ||
| 104 | * since last DTS reset. | ||
| 105 | */ | ||
| 106 | struct iwl_mvm_dts_diode_bits { | ||
| 107 | u8 digital_value; | ||
| 108 | u8 vref_low; | ||
| 109 | u8 vref_high; | ||
| 110 | u8 flags; | ||
| 111 | } __packed; | ||
| 112 | |||
| 113 | union dts_diode_results { | ||
| 114 | u32 reg_value; | ||
| 115 | struct iwl_mvm_dts_diode_bits bits; | ||
| 116 | } __packed; | ||
| 117 | |||
| 118 | static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm) | ||
| 119 | { | ||
| 120 | struct iwl_nvm_section calib_sec; | ||
| 121 | const __le16 *calib; | ||
| 122 | u16 vbg; | ||
| 123 | 69 | ||
| 124 | /* TODO: move parsing to NVM code */ | 70 | static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) |
| 125 | calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION]; | 71 | { |
| 126 | calib = (__le16 *)calib_sec.data; | 72 | u32 duration = mvm->thermal_throttle.params->ct_kill_duration; |
| 127 | 73 | ||
| 128 | vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); | 74 | if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) |
| 75 | return; | ||
| 129 | 76 | ||
| 130 | if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) | 77 | IWL_ERR(mvm, "Enter CT Kill\n"); |
| 131 | vbg = MEAS_VBG_DEFAULT_VAL; | 78 | iwl_mvm_set_hw_ctkill_state(mvm, true); |
| 132 | 79 | ||
| 133 | return vbg; | 80 | /* Don't schedule an exit work if we're in test mode, since |
| 81 | * the temperature will not change unless we manually set it | ||
| 82 | * again (or disable testing). | ||
| 83 | */ | ||
| 84 | if (!mvm->temperature_test) | ||
| 85 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | ||
| 86 | round_jiffies_relative(duration * HZ)); | ||
| 134 | } | 87 | } |
| 135 | 88 | ||
| 136 | static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) | 89 | static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) |
| 137 | { | 90 | { |
| 138 | const u8 *calib; | 91 | if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) |
| 139 | u8 ptat, pa1, pa2, median; | 92 | return; |
| 140 | |||
| 141 | /* TODO: move parsing to NVM code */ | ||
| 142 | calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; | ||
| 143 | ptat = calib[OTP_DTS_DIODE_DEVIATION * 2]; | ||
| 144 | pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1]; | ||
| 145 | pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2]; | ||
| 146 | |||
| 147 | /* get the median: */ | ||
| 148 | if (ptat > pa1) { | ||
| 149 | if (ptat > pa2) | ||
| 150 | median = (pa1 > pa2) ? pa1 : pa2; | ||
| 151 | else | ||
| 152 | median = ptat; | ||
| 153 | } else { | ||
| 154 | if (pa1 > pa2) | ||
| 155 | median = (ptat > pa2) ? ptat : pa2; | ||
| 156 | else | ||
| 157 | median = pa1; | ||
| 158 | } | ||
| 159 | 93 | ||
| 160 | return ptat - median; | 94 | IWL_ERR(mvm, "Exit CT Kill\n"); |
| 95 | iwl_mvm_set_hw_ctkill_state(mvm, false); | ||
| 161 | } | 96 | } |
| 162 | 97 | ||
| 163 | static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) | 98 | void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp) |
| 164 | { | 99 | { |
| 165 | /* Calibrate the PTAT digital value, based on PTAT deviation data: */ | 100 | /* ignore the notification if we are in test mode */ |
| 166 | s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); | 101 | if (mvm->temperature_test) |
| 102 | return; | ||
| 167 | 103 | ||
| 168 | if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE) | 104 | if (mvm->temperature == temp) |
| 169 | new_val = PTAT_DIGITAL_VALUE_MAX_VALUE; | 105 | return; |
| 170 | else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE) | ||
| 171 | new_val = PTAT_DIGITAL_VALUE_MIN_VALUE; | ||
| 172 | 106 | ||
| 173 | return new_val; | 107 | mvm->temperature = temp; |
| 108 | iwl_mvm_tt_handler(mvm); | ||
| 174 | } | 109 | } |
| 175 | 110 | ||
| 176 | static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, | 111 | static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, |
| 177 | union dts_diode_results *avg_ptat) | 112 | struct iwl_rx_packet *pkt) |
| 178 | { | 113 | { |
| 179 | u8 vrefs_results[DTS_VREFS_NUM]; | 114 | struct iwl_dts_measurement_notif *notif; |
| 180 | u8 low_vref_index = 0, flags; | 115 | int len = iwl_rx_packet_payload_len(pkt); |
| 181 | u32 reg; | 116 | int temp; |
| 182 | |||
| 183 | reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG); | ||
| 184 | memcpy(vrefs_results, ®, sizeof(reg)); | ||
| 185 | reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG); | ||
| 186 | vrefs_results[4] = reg & 0xff; | ||
| 187 | |||
| 188 | if (avg_ptat->bits.digital_value < vrefs_results[0] || | ||
| 189 | avg_ptat->bits.digital_value > vrefs_results[4]) | ||
| 190 | return false; | ||
| 191 | |||
| 192 | if (avg_ptat->bits.digital_value > vrefs_results[3]) | ||
| 193 | low_vref_index = 3; | ||
| 194 | else if (avg_ptat->bits.digital_value > vrefs_results[2]) | ||
| 195 | low_vref_index = 2; | ||
| 196 | else if (avg_ptat->bits.digital_value > vrefs_results[1]) | ||
| 197 | low_vref_index = 1; | ||
| 198 | |||
| 199 | avg_ptat->bits.vref_low = vrefs_results[low_vref_index]; | ||
| 200 | avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1]; | ||
| 201 | flags = avg_ptat->bits.flags; | ||
| 202 | avg_ptat->bits.flags = | ||
| 203 | (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) | | ||
| 204 | (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID); | ||
| 205 | return true; | ||
| 206 | } | ||
| 207 | 117 | ||
| 208 | /* | 118 | if (WARN_ON_ONCE(len != sizeof(*notif))) { |
| 209 | * return true it the results are valid, and false otherwise. | 119 | IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); |
| 210 | */ | 120 | return -EINVAL; |
| 211 | static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm, | 121 | } |
| 212 | union dts_diode_results *avg_ptat) | ||
| 213 | { | ||
| 214 | u32 reg; | ||
| 215 | u8 tmp; | ||
| 216 | |||
| 217 | /* fill the diode value and pass_once with avg-reg results */ | ||
| 218 | reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG); | ||
| 219 | reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE; | ||
| 220 | avg_ptat->reg_value = reg; | ||
| 221 | |||
| 222 | /* calibrate the PTAT digital value */ | ||
| 223 | tmp = avg_ptat->bits.digital_value; | ||
| 224 | tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp); | ||
| 225 | avg_ptat->bits.digital_value = tmp; | ||
| 226 | |||
| 227 | /* | ||
| 228 | * fill vrefs fields, based on the avgVrefs results | ||
| 229 | * and the diode value | ||
| 230 | */ | ||
| 231 | return dts_get_adjacent_vrefs(mvm, avg_ptat) && | ||
| 232 | DTS_DIODE_VALID(avg_ptat->bits.flags); | ||
| 233 | } | ||
| 234 | 122 | ||
| 235 | static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, | 123 | notif = (void *)pkt->data; |
| 236 | u16 volt_band_gap) | ||
| 237 | { | ||
| 238 | u32 tmp_result; | ||
| 239 | u8 vrefs_diff; | ||
| 240 | /* | ||
| 241 | * For temperature calculation (at the end, shift right by 23) | ||
| 242 | * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) } | ||
| 243 | * (D2-D1) == 43 44 45 46 47 48 49 50 51 | ||
| 244 | */ | ||
| 245 | static const u16 calc_lut[CALC_LUT_SIZE] = { | ||
| 246 | 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828, | ||
| 247 | }; | ||
| 248 | 124 | ||
| 249 | /* | 125 | temp = le32_to_cpu(notif->temp); |
| 250 | * The diff between the high and low voltage-references is assumed | ||
| 251 | * to be strictly be in range of [60,68] | ||
| 252 | */ | ||
| 253 | vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low; | ||
| 254 | 126 | ||
| 255 | if (vrefs_diff < CALC_VREFS_MIN_DIFF || | 127 | /* shouldn't be negative, but since it's s32, make sure it isn't */ |
| 256 | vrefs_diff > CALC_VREFS_MAX_DIFF) | 128 | if (WARN_ON_ONCE(temp < 0)) |
| 257 | return TEMPERATURE_ERROR; | 129 | temp = 0; |
| 258 | 130 | ||
| 259 | /* calculate the result: */ | 131 | IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp); |
| 260 | tmp_result = | ||
| 261 | vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9); | ||
| 262 | tmp_result += avg_ptat.bits.digital_value; | ||
| 263 | tmp_result -= avg_ptat.bits.vref_high; | ||
| 264 | 132 | ||
| 265 | /* multiply by the LUT value (based on the diff) */ | 133 | return temp; |
| 266 | tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET]; | 134 | } |
| 267 | 135 | ||
| 268 | /* | 136 | static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, |
| 269 | * Get the BandGap (the voltage refereces source) error data | 137 | struct iwl_rx_packet *pkt, void *data) |
| 270 | * (temperature offset) | 138 | { |
| 271 | */ | 139 | struct iwl_mvm *mvm = |
| 272 | tmp_result *= volt_band_gap; | 140 | container_of(notif_wait, struct iwl_mvm, notif_wait); |
| 141 | int *temp = data; | ||
| 142 | int ret; | ||
| 273 | 143 | ||
| 274 | /* | 144 | ret = iwl_mvm_temp_notif_parse(mvm, pkt); |
| 275 | * here, tmp_result value can be up to 32-bits. We want to right-shift | 145 | if (ret < 0) |
| 276 | * it *without* sign-extend. | 146 | return true; |
| 277 | */ | ||
| 278 | tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET; | ||
| 279 | 147 | ||
| 280 | /* | 148 | *temp = ret; |
| 281 | * at this point, tmp_result should be in the range: | 149 | |
| 282 | * 200 <= tmp_result <= 365 | 150 | return true; |
| 283 | */ | ||
| 284 | return (s16)tmp_result - 240; | ||
| 285 | } | 151 | } |
| 286 | 152 | ||
| 287 | static s32 check_nic_temperature(struct iwl_mvm *mvm) | 153 | int iwl_mvm_temp_notif(struct iwl_mvm *mvm, |
| 154 | struct iwl_rx_cmd_buffer *rxb, | ||
| 155 | struct iwl_device_cmd *cmd) | ||
| 288 | { | 156 | { |
| 289 | u16 volt_band_gap; | 157 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
| 290 | union dts_diode_results avg_ptat; | 158 | int temp; |
| 291 | |||
| 292 | volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm); | ||
| 293 | |||
| 294 | /* disable DTS */ | ||
| 295 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); | ||
| 296 | 159 | ||
| 297 | /* SV initialization */ | 160 | /* the notification is handled synchronously in ctkill, so skip here */ |
| 298 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1); | 161 | if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) |
| 299 | iwl_write_prph(mvm->trans, DTSC_CFG_MODE, | 162 | return 0; |
| 300 | DTSC_CFG_MODE_PERIODIC); | ||
| 301 | 163 | ||
| 302 | /* wait for results */ | 164 | temp = iwl_mvm_temp_notif_parse(mvm, pkt); |
| 303 | msleep(100); | 165 | if (temp < 0) |
| 304 | if (!dts_read_ptat_avg_results(mvm, &avg_ptat)) | 166 | return 0; |
| 305 | return TEMPERATURE_ERROR; | ||
| 306 | 167 | ||
| 307 | /* disable DTS */ | 168 | iwl_mvm_tt_temp_changed(mvm, temp); |
| 308 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); | ||
| 309 | 169 | ||
| 310 | return calculate_nic_temperature(avg_ptat, volt_band_gap); | 170 | return 0; |
| 311 | } | 171 | } |
| 312 | 172 | ||
| 313 | static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) | 173 | static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) |
| 314 | { | 174 | { |
| 315 | u32 duration = mvm->thermal_throttle.params->ct_kill_duration; | 175 | struct iwl_dts_measurement_cmd cmd = { |
| 176 | .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), | ||
| 177 | }; | ||
| 316 | 178 | ||
| 317 | IWL_ERR(mvm, "Enter CT Kill\n"); | 179 | return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0, |
| 318 | iwl_mvm_set_hw_ctkill_state(mvm, true); | 180 | sizeof(cmd), &cmd); |
| 319 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | ||
| 320 | round_jiffies_relative(duration * HZ)); | ||
| 321 | } | 181 | } |
| 322 | 182 | ||
| 323 | static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) | 183 | int iwl_mvm_get_temp(struct iwl_mvm *mvm) |
| 324 | { | 184 | { |
| 325 | IWL_ERR(mvm, "Exit CT Kill\n"); | 185 | struct iwl_notification_wait wait_temp_notif; |
| 326 | iwl_mvm_set_hw_ctkill_state(mvm, false); | 186 | static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; |
| 187 | int ret, temp; | ||
| 188 | |||
| 189 | lockdep_assert_held(&mvm->mutex); | ||
| 190 | |||
| 191 | iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, | ||
| 192 | temp_notif, ARRAY_SIZE(temp_notif), | ||
| 193 | iwl_mvm_temp_notif_wait, &temp); | ||
| 194 | |||
| 195 | ret = iwl_mvm_get_temp_cmd(mvm); | ||
| 196 | if (ret) { | ||
| 197 | IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret); | ||
| 198 | iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); | ||
| 199 | return ret; | ||
| 200 | } | ||
| 201 | |||
| 202 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, | ||
| 203 | IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); | ||
| 204 | if (ret) { | ||
| 205 | IWL_ERR(mvm, "Getting the temperature timed out\n"); | ||
| 206 | return ret; | ||
| 207 | } | ||
| 208 | |||
| 209 | return temp; | ||
| 327 | } | 210 | } |
| 328 | 211 | ||
| 329 | static void check_exit_ctkill(struct work_struct *work) | 212 | static void check_exit_ctkill(struct work_struct *work) |
| @@ -338,28 +221,36 @@ static void check_exit_ctkill(struct work_struct *work) | |||
| 338 | 221 | ||
| 339 | duration = tt->params->ct_kill_duration; | 222 | duration = tt->params->ct_kill_duration; |
| 340 | 223 | ||
| 224 | mutex_lock(&mvm->mutex); | ||
| 225 | |||
| 226 | if (__iwl_mvm_mac_start(mvm)) | ||
| 227 | goto reschedule; | ||
| 228 | |||
| 341 | /* make sure the device is available for direct read/writes */ | 229 | /* make sure the device is available for direct read/writes */ |
| 342 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) | 230 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) { |
| 231 | __iwl_mvm_mac_stop(mvm); | ||
| 343 | goto reschedule; | 232 | goto reschedule; |
| 233 | } | ||
| 344 | 234 | ||
| 345 | iwl_trans_start_hw(mvm->trans); | 235 | temp = iwl_mvm_get_temp(mvm); |
| 346 | temp = check_nic_temperature(mvm); | ||
| 347 | iwl_trans_stop_device(mvm->trans); | ||
| 348 | 236 | ||
| 349 | iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); | 237 | iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); |
| 350 | 238 | ||
| 351 | if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { | 239 | __iwl_mvm_mac_stop(mvm); |
| 352 | IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); | 240 | |
| 241 | if (temp < 0) | ||
| 353 | goto reschedule; | 242 | goto reschedule; |
| 354 | } | 243 | |
| 355 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); | 244 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); |
| 356 | 245 | ||
| 357 | if (temp <= tt->params->ct_kill_exit) { | 246 | if (temp <= tt->params->ct_kill_exit) { |
| 247 | mutex_unlock(&mvm->mutex); | ||
| 358 | iwl_mvm_exit_ctkill(mvm); | 248 | iwl_mvm_exit_ctkill(mvm); |
| 359 | return; | 249 | return; |
| 360 | } | 250 | } |
| 361 | 251 | ||
| 362 | reschedule: | 252 | reschedule: |
| 253 | mutex_unlock(&mvm->mutex); | ||
| 363 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | 254 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, |
| 364 | round_jiffies(duration * HZ)); | 255 | round_jiffies(duration * HZ)); |
| 365 | } | 256 | } |
| @@ -444,6 +335,12 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm) | |||
| 444 | return; | 335 | return; |
| 445 | } | 336 | } |
| 446 | 337 | ||
| 338 | if (params->support_ct_kill && | ||
| 339 | temperature <= tt->params->ct_kill_exit) { | ||
| 340 | iwl_mvm_exit_ctkill(mvm); | ||
| 341 | return; | ||
| 342 | } | ||
| 343 | |||
| 447 | if (params->support_dynamic_smps) { | 344 | if (params->support_dynamic_smps) { |
| 448 | if (!tt->dynamic_smps && | 345 | if (!tt->dynamic_smps && |
| 449 | temperature >= params->dynamic_smps_entry) { | 346 | temperature >= params->dynamic_smps_entry) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 9ee410bf6da2..4f15d9decc81 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -71,9 +73,9 @@ | |||
| 71 | /* | 73 | /* |
| 72 | * Sets most of the Tx cmd's fields | 74 | * Sets most of the Tx cmd's fields |
| 73 | */ | 75 | */ |
| 74 | static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | 76 | void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, |
| 75 | struct iwl_tx_cmd *tx_cmd, | 77 | struct iwl_tx_cmd *tx_cmd, |
| 76 | struct ieee80211_tx_info *info, u8 sta_id) | 78 | struct ieee80211_tx_info *info, u8 sta_id) |
| 77 | { | 79 | { |
| 78 | struct ieee80211_hdr *hdr = (void *)skb->data; | 80 | struct ieee80211_hdr *hdr = (void *)skb->data; |
| 79 | __le16 fc = hdr->frame_control; | 81 | __le16 fc = hdr->frame_control; |
| @@ -131,6 +133,11 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
| 131 | !is_multicast_ether_addr(ieee80211_get_DA(hdr))) | 133 | !is_multicast_ether_addr(ieee80211_get_DA(hdr))) |
| 132 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; | 134 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; |
| 133 | 135 | ||
| 136 | if ((mvm->fw->ucode_capa.capa[0] & | ||
| 137 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) && | ||
| 138 | ieee80211_action_contains_tpc(skb)) | ||
| 139 | tx_flags |= TX_CMD_FLG_WRITE_TX_POWER; | ||
| 140 | |||
| 134 | tx_cmd->tx_flags = cpu_to_le32(tx_flags); | 141 | tx_cmd->tx_flags = cpu_to_le32(tx_flags); |
| 135 | /* Total # bytes to be transmitted */ | 142 | /* Total # bytes to be transmitted */ |
| 136 | tx_cmd->len = cpu_to_le16((u16)skb->len); | 143 | tx_cmd->len = cpu_to_le16((u16)skb->len); |
| @@ -142,11 +149,9 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
| 142 | /* | 149 | /* |
| 143 | * Sets the fields in the Tx cmd that are rate related | 150 | * Sets the fields in the Tx cmd that are rate related |
| 144 | */ | 151 | */ |
| 145 | static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | 152 | void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, |
| 146 | struct iwl_tx_cmd *tx_cmd, | 153 | struct ieee80211_tx_info *info, |
| 147 | struct ieee80211_tx_info *info, | 154 | struct ieee80211_sta *sta, __le16 fc) |
| 148 | struct ieee80211_sta *sta, | ||
| 149 | __le16 fc) | ||
| 150 | { | 155 | { |
| 151 | u32 rate_flags; | 156 | u32 rate_flags; |
| 152 | int rate_idx; | 157 | int rate_idx; |
| @@ -168,14 +173,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
| 168 | 173 | ||
| 169 | /* | 174 | /* |
| 170 | * for data packets, rate info comes from the table inside the fw. This | 175 | * for data packets, rate info comes from the table inside the fw. This |
| 171 | * table is controlled by LINK_QUALITY commands. Exclude ctrl port | 176 | * table is controlled by LINK_QUALITY commands |
| 172 | * frames like EAPOLs which should be treated as mgmt frames. This | ||
| 173 | * avoids them being sent initially in high rates which increases the | ||
| 174 | * chances for completion of the 4-Way handshake. | ||
| 175 | */ | 177 | */ |
| 176 | 178 | ||
| 177 | if (ieee80211_is_data(fc) && sta && | 179 | if (ieee80211_is_data(fc) && sta) { |
| 178 | !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) { | ||
| 179 | tx_cmd->initial_rate_index = 0; | 180 | tx_cmd->initial_rate_index = 0; |
| 180 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); | 181 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); |
| 181 | return; | 182 | return; |
| @@ -186,8 +187,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
| 186 | 187 | ||
| 187 | /* HT rate doesn't make sense for a non data frame */ | 188 | /* HT rate doesn't make sense for a non data frame */ |
| 188 | WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS, | 189 | WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS, |
| 189 | "Got an HT rate for a non data frame 0x%x\n", | 190 | "Got an HT rate (flags:0x%x/mcs:%d) for a non data frame (fc:0x%x)\n", |
| 190 | info->control.rates[0].flags); | 191 | info->control.rates[0].flags, |
| 192 | info->control.rates[0].idx, | ||
| 193 | le16_to_cpu(fc)); | ||
| 191 | 194 | ||
| 192 | rate_idx = info->control.rates[0].idx; | 195 | rate_idx = info->control.rates[0].idx; |
| 193 | /* if the rate isn't a well known legacy rate, take the lowest one */ | 196 | /* if the rate isn't a well known legacy rate, take the lowest one */ |
| @@ -211,7 +214,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
| 211 | 214 | ||
| 212 | if (info->band == IEEE80211_BAND_2GHZ && | 215 | if (info->band == IEEE80211_BAND_2GHZ && |
| 213 | !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) | 216 | !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) |
| 214 | rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS; | 217 | rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS; |
| 215 | else | 218 | else |
| 216 | rate_flags = | 219 | rate_flags = |
| 217 | BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; | 220 | BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; |
| @@ -227,10 +230,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
| 227 | /* | 230 | /* |
| 228 | * Sets the fields in the Tx cmd that are crypto related | 231 | * Sets the fields in the Tx cmd that are crypto related |
| 229 | */ | 232 | */ |
| 230 | static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, | 233 | void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, |
| 231 | struct ieee80211_tx_info *info, | 234 | struct ieee80211_tx_info *info, |
| 232 | struct iwl_tx_cmd *tx_cmd, | 235 | struct iwl_tx_cmd *tx_cmd, |
| 233 | struct sk_buff *skb_frag) | 236 | struct sk_buff *skb_frag) |
| 234 | { | 237 | { |
| 235 | struct ieee80211_key_conf *keyconf = info->control.hw_key; | 238 | struct ieee80211_key_conf *keyconf = info->control.hw_key; |
| 236 | 239 | ||
| @@ -421,6 +424,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
| 421 | 424 | ||
| 422 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); | 425 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); |
| 423 | 426 | ||
| 427 | if (sta->tdls) { | ||
| 428 | /* default to TID 0 for non-QoS packets */ | ||
| 429 | u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid; | ||
| 430 | |||
| 431 | txq_id = mvmsta->hw_queue[tid_to_mac80211_ac[tdls_tid]]; | ||
| 432 | } | ||
| 433 | |||
| 424 | if (is_ampdu) { | 434 | if (is_ampdu) { |
| 425 | if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) | 435 | if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) |
| 426 | goto drop_unlock_sta; | 436 | goto drop_unlock_sta; |
| @@ -486,11 +496,11 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, | |||
| 486 | IWL_DEBUG_TX_QUEUES(mvm, | 496 | IWL_DEBUG_TX_QUEUES(mvm, |
| 487 | "Can continue DELBA flow ssn = next_recl = %d\n", | 497 | "Can continue DELBA flow ssn = next_recl = %d\n", |
| 488 | tid_data->next_reclaimed); | 498 | tid_data->next_reclaimed); |
| 489 | iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); | 499 | iwl_mvm_disable_txq(mvm, tid_data->txq_id); |
| 490 | tid_data->state = IWL_AGG_OFF; | 500 | tid_data->state = IWL_AGG_OFF; |
| 491 | /* | 501 | /* |
| 492 | * we can't hold the mutex - but since we are after a sequence | 502 | * we can't hold the mutex - but since we are after a sequence |
| 493 | * point (call to iwl_trans_txq_disable), so we don't even need | 503 | * point (call to iwl_mvm_disable_txq(), so we don't even need |
| 494 | * a memory barrier. | 504 | * a memory barrier. |
| 495 | */ | 505 | */ |
| 496 | mvm->queue_to_mac80211[tid_data->txq_id] = | 506 | mvm->queue_to_mac80211[tid_data->txq_id] = |
| @@ -655,6 +665,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
| 655 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); | 665 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); |
| 656 | } | 666 | } |
| 657 | 667 | ||
| 668 | /* | ||
| 669 | * TODO: this is not accurate if we are freeing more than one | ||
| 670 | * packet. | ||
| 671 | */ | ||
| 672 | info->status.tx_time = | ||
| 673 | le16_to_cpu(tx_resp->wireless_media_time); | ||
| 658 | BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); | 674 | BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); |
| 659 | info->status.status_driver_data[0] = | 675 | info->status.status_driver_data[0] = |
| 660 | (void *)(uintptr_t)tx_resp->reduced_tpc; | 676 | (void *)(uintptr_t)tx_resp->reduced_tpc; |
| @@ -847,6 +863,8 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, | |||
| 847 | mvmsta->tid_data[tid].rate_n_flags = | 863 | mvmsta->tid_data[tid].rate_n_flags = |
| 848 | le32_to_cpu(tx_resp->initial_rate); | 864 | le32_to_cpu(tx_resp->initial_rate); |
| 849 | mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc; | 865 | mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc; |
| 866 | mvmsta->tid_data[tid].tx_time = | ||
| 867 | le16_to_cpu(tx_resp->wireless_media_time); | ||
| 850 | } | 868 | } |
| 851 | 869 | ||
| 852 | rcu_read_unlock(); | 870 | rcu_read_unlock(); |
| @@ -866,6 +884,21 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 866 | return 0; | 884 | return 0; |
| 867 | } | 885 | } |
| 868 | 886 | ||
| 887 | static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, | ||
| 888 | struct iwl_mvm_ba_notif *ba_notif, | ||
| 889 | struct iwl_mvm_tid_data *tid_data) | ||
| 890 | { | ||
| 891 | info->flags |= IEEE80211_TX_STAT_AMPDU; | ||
| 892 | info->status.ampdu_ack_len = ba_notif->txed_2_done; | ||
| 893 | info->status.ampdu_len = ba_notif->txed; | ||
| 894 | iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags, | ||
| 895 | info); | ||
| 896 | /* TODO: not accounted if the whole A-MPDU failed */ | ||
| 897 | info->status.tx_time = tid_data->tx_time; | ||
| 898 | info->status.status_driver_data[0] = | ||
| 899 | (void *)(uintptr_t)tid_data->reduced_tpc; | ||
| 900 | } | ||
| 901 | |||
| 869 | int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 902 | int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
| 870 | struct iwl_device_cmd *cmd) | 903 | struct iwl_device_cmd *cmd) |
| 871 | { | 904 | { |
| @@ -952,21 +985,37 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
| 952 | */ | 985 | */ |
| 953 | info->flags |= IEEE80211_TX_STAT_ACK; | 986 | info->flags |= IEEE80211_TX_STAT_ACK; |
| 954 | 987 | ||
| 955 | if (freed == 1) { | 988 | /* this is the first skb we deliver in this batch */ |
| 956 | /* this is the first skb we deliver in this batch */ | 989 | /* put the rate scaling data there */ |
| 957 | /* put the rate scaling data there */ | 990 | if (freed == 1) |
| 958 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 991 | iwl_mvm_tx_info_from_ba_notif(info, ba_notif, tid_data); |
| 959 | info->status.ampdu_ack_len = ba_notif->txed_2_done; | ||
| 960 | info->status.ampdu_len = ba_notif->txed; | ||
| 961 | iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags, | ||
| 962 | info); | ||
| 963 | info->status.status_driver_data[0] = | ||
| 964 | (void *)(uintptr_t)tid_data->reduced_tpc; | ||
| 965 | } | ||
| 966 | } | 992 | } |
| 967 | 993 | ||
| 968 | spin_unlock_bh(&mvmsta->lock); | 994 | spin_unlock_bh(&mvmsta->lock); |
| 969 | 995 | ||
| 996 | /* We got a BA notif with 0 acked or scd_ssn didn't progress which is | ||
| 997 | * possible (i.e. first MPDU in the aggregation wasn't acked) | ||
| 998 | * Still it's important to update RS about sent vs. acked. | ||
| 999 | */ | ||
| 1000 | if (skb_queue_empty(&reclaimed_skbs)) { | ||
| 1001 | struct ieee80211_tx_info ba_info = {}; | ||
| 1002 | struct ieee80211_chanctx_conf *chanctx_conf = NULL; | ||
| 1003 | |||
| 1004 | if (mvmsta->vif) | ||
| 1005 | chanctx_conf = | ||
| 1006 | rcu_dereference(mvmsta->vif->chanctx_conf); | ||
| 1007 | |||
| 1008 | if (WARN_ON_ONCE(!chanctx_conf)) | ||
| 1009 | goto out; | ||
| 1010 | |||
| 1011 | ba_info.band = chanctx_conf->def.chan->band; | ||
| 1012 | iwl_mvm_tx_info_from_ba_notif(&ba_info, ba_notif, tid_data); | ||
| 1013 | |||
| 1014 | IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n"); | ||
| 1015 | iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | out: | ||
| 970 | rcu_read_unlock(); | 1019 | rcu_read_unlock(); |
| 971 | 1020 | ||
| 972 | while (!skb_queue_empty(&reclaimed_skbs)) { | 1021 | while (!skb_queue_empty(&reclaimed_skbs)) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index ac249da8a22b..e56e77ef5d2e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -387,15 +389,19 @@ struct iwl_error_event_table { | |||
| 387 | struct iwl_umac_error_event_table { | 389 | struct iwl_umac_error_event_table { |
| 388 | u32 valid; /* (nonzero) valid, (0) log is empty */ | 390 | u32 valid; /* (nonzero) valid, (0) log is empty */ |
| 389 | u32 error_id; /* type of error */ | 391 | u32 error_id; /* type of error */ |
| 390 | u32 pc; /* program counter */ | ||
| 391 | u32 blink1; /* branch link */ | 392 | u32 blink1; /* branch link */ |
| 392 | u32 blink2; /* branch link */ | 393 | u32 blink2; /* branch link */ |
| 393 | u32 ilink1; /* interrupt link */ | 394 | u32 ilink1; /* interrupt link */ |
| 394 | u32 ilink2; /* interrupt link */ | 395 | u32 ilink2; /* interrupt link */ |
| 395 | u32 data1; /* error-specific data */ | 396 | u32 data1; /* error-specific data */ |
| 396 | u32 data2; /* error-specific data */ | 397 | u32 data2; /* error-specific data */ |
| 397 | u32 line; /* source code line of error */ | 398 | u32 data3; /* error-specific data */ |
| 398 | u32 umac_ver; /* umac version */ | 399 | u32 umac_fw_ver; /* UMAC version */ |
| 400 | u32 umac_fw_api_ver; /* UMAC FW API ver */ | ||
| 401 | u32 frame_pointer; /* core register 27*/ | ||
| 402 | u32 stack_pointer; /* core register 28 */ | ||
| 403 | u32 cmd_header; /* latest host cmd sent to UMAC */ | ||
| 404 | u32 nic_isr_pref; /* ISR status register */ | ||
| 399 | } __packed; | 405 | } __packed; |
| 400 | 406 | ||
| 401 | #define ERROR_START_OFFSET (1 * sizeof(u32)) | 407 | #define ERROR_START_OFFSET (1 * sizeof(u32)) |
| @@ -409,7 +415,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) | |||
| 409 | 415 | ||
| 410 | base = mvm->umac_error_event_table; | 416 | base = mvm->umac_error_event_table; |
| 411 | 417 | ||
| 412 | if (base < 0x800000 || base >= 0x80C000) { | 418 | if (base < 0x800000) { |
| 413 | IWL_ERR(mvm, | 419 | IWL_ERR(mvm, |
| 414 | "Not valid error log pointer 0x%08X for %s uCode\n", | 420 | "Not valid error log pointer 0x%08X for %s uCode\n", |
| 415 | base, | 421 | base, |
| @@ -428,14 +434,19 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) | |||
| 428 | 434 | ||
| 429 | IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, | 435 | IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, |
| 430 | desc_lookup(table.error_id)); | 436 | desc_lookup(table.error_id)); |
| 431 | IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc); | ||
| 432 | IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); | 437 | IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); |
| 433 | IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); | 438 | IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); |
| 434 | IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); | 439 | IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); |
| 435 | IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); | 440 | IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); |
| 436 | IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); | 441 | IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); |
| 437 | IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); | 442 | IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); |
| 438 | IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver); | 443 | IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3); |
| 444 | IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_fw_ver); | ||
| 445 | IWL_ERR(mvm, "0x%08X | umac api version\n", table.umac_fw_api_ver); | ||
| 446 | IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer); | ||
| 447 | IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer); | ||
| 448 | IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header); | ||
| 449 | IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref); | ||
| 439 | } | 450 | } |
| 440 | 451 | ||
| 441 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | 452 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) |
| @@ -519,6 +530,52 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | |||
| 519 | iwl_mvm_dump_umac_error_log(mvm); | 530 | iwl_mvm_dump_umac_error_log(mvm); |
| 520 | } | 531 | } |
| 521 | 532 | ||
| 533 | void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, | ||
| 534 | const struct iwl_trans_txq_scd_cfg *cfg) | ||
| 535 | { | ||
| 536 | if (iwl_mvm_is_dqa_supported(mvm)) { | ||
| 537 | struct iwl_scd_txq_cfg_cmd cmd = { | ||
| 538 | .scd_queue = queue, | ||
| 539 | .enable = 1, | ||
| 540 | .window = cfg->frame_limit, | ||
| 541 | .sta_id = cfg->sta_id, | ||
| 542 | .ssn = cpu_to_le16(ssn), | ||
| 543 | .tx_fifo = cfg->fifo, | ||
| 544 | .aggregate = cfg->aggregate, | ||
| 545 | .flags = IWL_SCD_FLAGS_DQA_ENABLED, | ||
| 546 | .tid = cfg->tid, | ||
| 547 | .control = IWL_SCD_CONTROL_SET_SSN, | ||
| 548 | }; | ||
| 549 | int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, | ||
| 550 | sizeof(cmd), &cmd); | ||
| 551 | if (ret) | ||
| 552 | IWL_ERR(mvm, | ||
| 553 | "Failed to configure queue %d on FIFO %d\n", | ||
| 554 | queue, cfg->fifo); | ||
| 555 | } | ||
| 556 | |||
| 557 | iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, | ||
| 558 | iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg); | ||
| 559 | } | ||
| 560 | |||
| 561 | void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue) | ||
| 562 | { | ||
| 563 | iwl_trans_txq_disable(mvm->trans, queue, | ||
| 564 | !iwl_mvm_is_dqa_supported(mvm)); | ||
| 565 | |||
| 566 | if (iwl_mvm_is_dqa_supported(mvm)) { | ||
| 567 | struct iwl_scd_txq_cfg_cmd cmd = { | ||
| 568 | .scd_queue = queue, | ||
| 569 | .enable = 0, | ||
| 570 | }; | ||
| 571 | int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC, | ||
| 572 | sizeof(cmd), &cmd); | ||
| 573 | if (ret) | ||
| 574 | IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", | ||
| 575 | queue, ret); | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 522 | /** | 579 | /** |
| 523 | * iwl_mvm_send_lq_cmd() - Send link quality command | 580 | * iwl_mvm_send_lq_cmd() - Send link quality command |
| 524 | * @init: This command is sent as part of station initialization right | 581 | * @init: This command is sent as part of station initialization right |
| @@ -677,3 +734,40 @@ bool iwl_mvm_is_idle(struct iwl_mvm *mvm) | |||
| 677 | 734 | ||
| 678 | return idle; | 735 | return idle; |
| 679 | } | 736 | } |
| 737 | |||
| 738 | struct iwl_bss_iter_data { | ||
| 739 | struct ieee80211_vif *vif; | ||
| 740 | bool error; | ||
| 741 | }; | ||
| 742 | |||
| 743 | static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac, | ||
| 744 | struct ieee80211_vif *vif) | ||
| 745 | { | ||
| 746 | struct iwl_bss_iter_data *data = _data; | ||
| 747 | |||
| 748 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
| 749 | return; | ||
| 750 | |||
| 751 | if (data->vif) { | ||
| 752 | data->error = true; | ||
| 753 | return; | ||
| 754 | } | ||
| 755 | |||
| 756 | data->vif = vif; | ||
| 757 | } | ||
| 758 | |||
| 759 | struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm) | ||
| 760 | { | ||
| 761 | struct iwl_bss_iter_data bss_iter_data = {}; | ||
| 762 | |||
| 763 | ieee80211_iterate_active_interfaces_atomic( | ||
| 764 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
| 765 | iwl_mvm_bss_iface_iterator, &bss_iter_data); | ||
| 766 | |||
| 767 | if (bss_iter_data.error) { | ||
| 768 | IWL_ERR(mvm, "More than one managed interface active!\n"); | ||
| 769 | return ERR_PTR(-EINVAL); | ||
| 770 | } | ||
| 771 | |||
| 772 | return bss_iter_data.vif; | ||
| 773 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 073a68b97a72..2f0c4b170344 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -273,6 +275,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { | |||
| 273 | {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, | 275 | {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, |
| 274 | {IWL_PCI_DEVICE(0x08B1, 0x4072, iwl7260_2ac_cfg)}, | 276 | {IWL_PCI_DEVICE(0x08B1, 0x4072, iwl7260_2ac_cfg)}, |
| 275 | {IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)}, | 277 | {IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)}, |
| 278 | {IWL_PCI_DEVICE(0x08B1, 0x4C60, iwl7260_2ac_cfg)}, | ||
| 279 | {IWL_PCI_DEVICE(0x08B1, 0x4C70, iwl7260_2ac_cfg)}, | ||
| 276 | {IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)}, | 280 | {IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)}, |
| 277 | {IWL_PCI_DEVICE(0x08B1, 0x406A, iwl7260_2n_cfg)}, | 281 | {IWL_PCI_DEVICE(0x08B1, 0x406A, iwl7260_2n_cfg)}, |
| 278 | {IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)}, | 282 | {IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)}, |
| @@ -316,6 +320,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { | |||
| 316 | {IWL_PCI_DEVICE(0x08B1, 0xC770, iwl7260_2ac_cfg)}, | 320 | {IWL_PCI_DEVICE(0x08B1, 0xC770, iwl7260_2ac_cfg)}, |
| 317 | {IWL_PCI_DEVICE(0x08B1, 0xC760, iwl7260_2n_cfg)}, | 321 | {IWL_PCI_DEVICE(0x08B1, 0xC760, iwl7260_2n_cfg)}, |
| 318 | {IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)}, | 322 | {IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)}, |
| 323 | {IWL_PCI_DEVICE(0x08B1, 0xCC70, iwl7260_2ac_cfg)}, | ||
| 324 | {IWL_PCI_DEVICE(0x08B1, 0xCC60, iwl7260_2ac_cfg)}, | ||
| 319 | {IWL_PCI_DEVICE(0x08B2, 0xC272, iwl7260_2ac_cfg)}, | 325 | {IWL_PCI_DEVICE(0x08B2, 0xC272, iwl7260_2ac_cfg)}, |
| 320 | {IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)}, | 326 | {IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)}, |
| 321 | {IWL_PCI_DEVICE(0x08B2, 0xC26A, iwl7260_n_cfg)}, | 327 | {IWL_PCI_DEVICE(0x08B2, 0xC26A, iwl7260_n_cfg)}, |
| @@ -361,7 +367,11 @@ static const struct pci_device_id iwl_hw_card_ids[] = { | |||
| 361 | 367 | ||
| 362 | /* 3165 Series */ | 368 | /* 3165 Series */ |
| 363 | {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, | 369 | {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, |
| 370 | {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, | ||
| 371 | {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)}, | ||
| 364 | {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, | 372 | {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, |
| 373 | {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)}, | ||
| 374 | {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)}, | ||
| 365 | 375 | ||
| 366 | /* 7265 Series */ | 376 | /* 7265 Series */ |
| 367 | {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, | 377 | {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, |
| @@ -403,6 +413,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { | |||
| 403 | 413 | ||
| 404 | /* 8000 Series */ | 414 | /* 8000 Series */ |
| 405 | {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, | 415 | {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, |
| 416 | {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, | ||
| 406 | {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, | 417 | {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, |
| 407 | #endif /* CONFIG_IWLMVM */ | 418 | #endif /* CONFIG_IWLMVM */ |
| 408 | 419 | ||
| @@ -492,6 +503,7 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {} | |||
| 492 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 503 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 493 | { | 504 | { |
| 494 | const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | 505 | const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); |
| 506 | const struct iwl_cfg *cfg_7265d __maybe_unused = NULL; | ||
| 495 | struct iwl_trans *iwl_trans; | 507 | struct iwl_trans *iwl_trans; |
| 496 | struct iwl_trans_pcie *trans_pcie; | 508 | struct iwl_trans_pcie *trans_pcie; |
| 497 | int ret; | 509 | int ret; |
| @@ -500,6 +512,25 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 500 | if (IS_ERR(iwl_trans)) | 512 | if (IS_ERR(iwl_trans)) |
| 501 | return PTR_ERR(iwl_trans); | 513 | return PTR_ERR(iwl_trans); |
| 502 | 514 | ||
| 515 | #if IS_ENABLED(CONFIG_IWLMVM) | ||
| 516 | /* | ||
| 517 | * special-case 7265D, it has the same PCI IDs. | ||
| 518 | * | ||
| 519 | * Note that because we already pass the cfg to the transport above, | ||
| 520 | * all the parameters that the transport uses must, until that is | ||
| 521 | * changed, be identical to the ones in the 7265D configuration. | ||
| 522 | */ | ||
| 523 | if (cfg == &iwl7265_2ac_cfg) | ||
| 524 | cfg_7265d = &iwl7265d_2ac_cfg; | ||
| 525 | else if (cfg == &iwl7265_2n_cfg) | ||
| 526 | cfg_7265d = &iwl7265d_2n_cfg; | ||
| 527 | else if (cfg == &iwl7265_n_cfg) | ||
| 528 | cfg_7265d = &iwl7265d_n_cfg; | ||
| 529 | if (cfg_7265d && | ||
| 530 | (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) | ||
| 531 | cfg = cfg_7265d; | ||
| 532 | #endif | ||
| 533 | |||
| 503 | pci_set_drvdata(pdev, iwl_trans); | 534 | pci_set_drvdata(pdev, iwl_trans); |
| 504 | 535 | ||
| 505 | trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); | 536 | trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 78f72c34438a..1aea6b66c594 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /****************************************************************************** | 1 | /****************************************************************************** |
| 2 | * | 2 | * |
| 3 | * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. |
| 4 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 4 | * | 5 | * |
| 5 | * Portions of this file are derived from the ipw3945 project, as well | 6 | * Portions of this file are derived from the ipw3945 project, as well |
| 6 | * as portions of the ieee80211 subsystem header files. | 7 | * as portions of the ieee80211 subsystem header files. |
| @@ -256,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) | |||
| 256 | * @cmd_queue - command queue number | 257 | * @cmd_queue - command queue number |
| 257 | * @rx_buf_size_8k: 8 kB RX buffer size | 258 | * @rx_buf_size_8k: 8 kB RX buffer size |
| 258 | * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) | 259 | * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) |
| 260 | * @scd_set_active: should the transport configure the SCD for HCMD queue | ||
| 259 | * @rx_page_order: page order for receive buffer size | 261 | * @rx_page_order: page order for receive buffer size |
| 260 | * @wd_timeout: queue watchdog timeout (jiffies) | 262 | * @wd_timeout: queue watchdog timeout (jiffies) |
| 261 | * @reg_lock: protect hw register access | 263 | * @reg_lock: protect hw register access |
| @@ -305,6 +307,7 @@ struct iwl_trans_pcie { | |||
| 305 | 307 | ||
| 306 | bool rx_buf_size_8k; | 308 | bool rx_buf_size_8k; |
| 307 | bool bc_table_dword; | 309 | bool bc_table_dword; |
| 310 | bool scd_set_active; | ||
| 308 | u32 rx_page_order; | 311 | u32 rx_page_order; |
| 309 | 312 | ||
| 310 | const char *const *command_names; | 313 | const char *const *command_names; |
| @@ -364,9 +367,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans); | |||
| 364 | void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); | 367 | void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); |
| 365 | int iwl_pcie_tx_stop(struct iwl_trans *trans); | 368 | int iwl_pcie_tx_stop(struct iwl_trans *trans); |
| 366 | void iwl_pcie_tx_free(struct iwl_trans *trans); | 369 | void iwl_pcie_tx_free(struct iwl_trans *trans); |
| 367 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, | 370 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, |
| 368 | int sta_id, int tid, int frame_limit, u16 ssn); | 371 | const struct iwl_trans_txq_scd_cfg *cfg); |
| 369 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue); | 372 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, |
| 373 | bool configure_scd); | ||
| 370 | int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | 374 | int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, |
| 371 | struct iwl_device_cmd *dev_cmd, int txq_id); | 375 | struct iwl_device_cmd *dev_cmd, int txq_id); |
| 372 | void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); | 376 | void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a2698e5e062c..7b7e2f223fb2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /****************************************************************************** | 1 | /****************************************************************************** |
| 2 | * | 2 | * |
| 3 | * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. |
| 4 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 4 | * | 5 | * |
| 5 | * Portions of this file are derived from the ipw3945 project, as well | 6 | * Portions of this file are derived from the ipw3945 project, as well |
| 6 | * as portions of the ieee80211 subsystem header files. | 7 | * as portions of the ieee80211 subsystem header files. |
| @@ -639,7 +640,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, | |||
| 639 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); | 640 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); |
| 640 | 641 | ||
| 641 | if (reclaim) { | 642 | if (reclaim) { |
| 642 | kfree(txq->entries[cmd_index].free_buf); | 643 | kzfree(txq->entries[cmd_index].free_buf); |
| 643 | txq->entries[cmd_index].free_buf = NULL; | 644 | txq->entries[cmd_index].free_buf = NULL; |
| 644 | } | 645 | } |
| 645 | 646 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 06e04aaf61ee..523fe0c88dcb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * GPL LICENSE SUMMARY | 6 | * GPL LICENSE SUMMARY |
| 7 | * | 7 | * |
| 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. |
| 9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 9 | * | 10 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of version 2 of the GNU General Public License as | 12 | * it under the terms of version 2 of the GNU General Public License as |
| @@ -31,6 +32,7 @@ | |||
| 31 | * BSD LICENSE | 32 | * BSD LICENSE |
| 32 | * | 33 | * |
| 33 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. | 34 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
| 35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 34 | * All rights reserved. | 36 | * All rights reserved. |
| 35 | * | 37 | * |
| 36 | * Redistribution and use in source and binary forms, with or without | 38 | * Redistribution and use in source and binary forms, with or without |
| @@ -76,6 +78,11 @@ | |||
| 76 | #include "iwl-agn-hw.h" | 78 | #include "iwl-agn-hw.h" |
| 77 | #include "iwl-fw-error-dump.h" | 79 | #include "iwl-fw-error-dump.h" |
| 78 | #include "internal.h" | 80 | #include "internal.h" |
| 81 | #include "iwl-fh.h" | ||
| 82 | |||
| 83 | /* extended range in FW SRAM */ | ||
| 84 | #define IWL_FW_MEM_EXTENDED_START 0x40000 | ||
| 85 | #define IWL_FW_MEM_EXTENDED_END 0x57FFF | ||
| 79 | 86 | ||
| 80 | static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) | 87 | static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) |
| 81 | { | 88 | { |
| @@ -131,7 +138,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) | |||
| 131 | break; | 138 | break; |
| 132 | } | 139 | } |
| 133 | 140 | ||
| 134 | if (!page) | 141 | if (WARN_ON_ONCE(!page)) |
| 135 | return; | 142 | return; |
| 136 | 143 | ||
| 137 | trans_pcie->fw_mon_page = page; | 144 | trans_pcie->fw_mon_page = page; |
| @@ -172,6 +179,7 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans) | |||
| 172 | { | 179 | { |
| 173 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 180 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 174 | u16 lctl; | 181 | u16 lctl; |
| 182 | u16 cap; | ||
| 175 | 183 | ||
| 176 | /* | 184 | /* |
| 177 | * HW bug W/A for instability in PCIe bus L0S->L1 transition. | 185 | * HW bug W/A for instability in PCIe bus L0S->L1 transition. |
| @@ -182,16 +190,17 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans) | |||
| 182 | * power savings, even without L1. | 190 | * power savings, even without L1. |
| 183 | */ | 191 | */ |
| 184 | pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); | 192 | pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); |
| 185 | if (lctl & PCI_EXP_LNKCTL_ASPM_L1) { | 193 | if (lctl & PCI_EXP_LNKCTL_ASPM_L1) |
| 186 | /* L1-ASPM enabled; disable(!) L0S */ | ||
| 187 | iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); | 194 | iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); |
| 188 | dev_info(trans->dev, "L1 Enabled; Disabling L0S\n"); | 195 | else |
| 189 | } else { | ||
| 190 | /* L1-ASPM disabled; enable(!) L0S */ | ||
| 191 | iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); | 196 | iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); |
| 192 | dev_info(trans->dev, "L1 Disabled; Enabling L0S\n"); | ||
| 193 | } | ||
| 194 | trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); | 197 | trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); |
| 198 | |||
| 199 | pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); | ||
| 200 | trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; | ||
| 201 | dev_info(trans->dev, "L1 %sabled - LTR %sabled\n", | ||
| 202 | (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", | ||
| 203 | trans->ltr_enabled ? "En" : "Dis"); | ||
| 195 | } | 204 | } |
| 196 | 205 | ||
| 197 | /* | 206 | /* |
| @@ -426,7 +435,7 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) | |||
| 426 | ret = iwl_poll_bit(trans, CSR_RESET, | 435 | ret = iwl_poll_bit(trans, CSR_RESET, |
| 427 | CSR_RESET_REG_FLAG_MASTER_DISABLED, | 436 | CSR_RESET_REG_FLAG_MASTER_DISABLED, |
| 428 | CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); | 437 | CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); |
| 429 | if (ret) | 438 | if (ret < 0) |
| 430 | IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); | 439 | IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); |
| 431 | 440 | ||
| 432 | IWL_DEBUG_INFO(trans, "stop master\n"); | 441 | IWL_DEBUG_INFO(trans, "stop master\n"); |
| @@ -508,6 +517,9 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) | |||
| 508 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, | 517 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, |
| 509 | HW_READY_TIMEOUT); | 518 | HW_READY_TIMEOUT); |
| 510 | 519 | ||
| 520 | if (ret >= 0) | ||
| 521 | iwl_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE); | ||
| 522 | |||
| 511 | IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : ""); | 523 | IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : ""); |
| 512 | return ret; | 524 | return ret; |
| 513 | } | 525 | } |
| @@ -542,7 +554,7 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) | |||
| 542 | msleep(25); | 554 | msleep(25); |
| 543 | } | 555 | } |
| 544 | 556 | ||
| 545 | IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter); | 557 | IWL_ERR(trans, "Couldn't prepare the card\n"); |
| 546 | 558 | ||
| 547 | return ret; | 559 | return ret; |
| 548 | } | 560 | } |
| @@ -602,7 +614,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
| 602 | { | 614 | { |
| 603 | u8 *v_addr; | 615 | u8 *v_addr; |
| 604 | dma_addr_t p_addr; | 616 | dma_addr_t p_addr; |
| 605 | u32 offset, chunk_sz = section->len; | 617 | u32 offset, chunk_sz = min_t(u32, FH_MEM_TB_MAX_LENGTH, section->len); |
| 606 | int ret = 0; | 618 | int ret = 0; |
| 607 | 619 | ||
| 608 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", | 620 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", |
| @@ -620,14 +632,28 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
| 620 | } | 632 | } |
| 621 | 633 | ||
| 622 | for (offset = 0; offset < section->len; offset += chunk_sz) { | 634 | for (offset = 0; offset < section->len; offset += chunk_sz) { |
| 623 | u32 copy_size; | 635 | u32 copy_size, dst_addr; |
| 636 | bool extended_addr = false; | ||
| 624 | 637 | ||
| 625 | copy_size = min_t(u32, chunk_sz, section->len - offset); | 638 | copy_size = min_t(u32, chunk_sz, section->len - offset); |
| 639 | dst_addr = section->offset + offset; | ||
| 640 | |||
| 641 | if (dst_addr >= IWL_FW_MEM_EXTENDED_START && | ||
| 642 | dst_addr <= IWL_FW_MEM_EXTENDED_END) | ||
| 643 | extended_addr = true; | ||
| 644 | |||
| 645 | if (extended_addr) | ||
| 646 | iwl_set_bits_prph(trans, LMPM_CHICK, | ||
| 647 | LMPM_CHICK_EXTENDED_ADDR_SPACE); | ||
| 626 | 648 | ||
| 627 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); | 649 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); |
| 628 | ret = iwl_pcie_load_firmware_chunk(trans, | 650 | ret = iwl_pcie_load_firmware_chunk(trans, dst_addr, p_addr, |
| 629 | section->offset + offset, | 651 | copy_size); |
| 630 | p_addr, copy_size); | 652 | |
| 653 | if (extended_addr) | ||
| 654 | iwl_clear_bits_prph(trans, LMPM_CHICK, | ||
| 655 | LMPM_CHICK_EXTENDED_ADDR_SPACE); | ||
| 656 | |||
| 631 | if (ret) { | 657 | if (ret) { |
| 632 | IWL_ERR(trans, | 658 | IWL_ERR(trans, |
| 633 | "Could not load the [%d] uCode section\n", | 659 | "Could not load the [%d] uCode section\n", |
| @@ -640,14 +666,14 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
| 640 | return ret; | 666 | return ret; |
| 641 | } | 667 | } |
| 642 | 668 | ||
| 643 | static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, | 669 | static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, |
| 644 | const struct fw_img *image, | 670 | const struct fw_img *image, |
| 645 | int cpu, | 671 | int cpu, |
| 646 | int *first_ucode_section) | 672 | int *first_ucode_section) |
| 647 | { | 673 | { |
| 648 | int shift_param; | 674 | int shift_param; |
| 649 | int i, ret = 0; | 675 | int i, ret = 0, sec_num = 0x1; |
| 650 | u32 last_read_idx = 0; | 676 | u32 val, last_read_idx = 0; |
| 651 | 677 | ||
| 652 | if (cpu == 1) { | 678 | if (cpu == 1) { |
| 653 | shift_param = 0; | 679 | shift_param = 0; |
| @@ -668,21 +694,16 @@ static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, | |||
| 668 | break; | 694 | break; |
| 669 | } | 695 | } |
| 670 | 696 | ||
| 671 | if (i == (*first_ucode_section) + 1) | ||
| 672 | /* set CPU to started */ | ||
| 673 | iwl_set_bits_prph(trans, | ||
| 674 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
| 675 | LMPM_CPU_HDRS_LOADING_COMPLETED | ||
| 676 | << shift_param); | ||
| 677 | |||
| 678 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | 697 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); |
| 679 | if (ret) | 698 | if (ret) |
| 680 | return ret; | 699 | return ret; |
| 700 | |||
| 701 | /* Notify the ucode of the loaded section number and status */ | ||
| 702 | val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS); | ||
| 703 | val = val | (sec_num << shift_param); | ||
| 704 | iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val); | ||
| 705 | sec_num = (sec_num << 1) | 0x1; | ||
| 681 | } | 706 | } |
| 682 | /* image loading complete */ | ||
| 683 | iwl_set_bits_prph(trans, | ||
| 684 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
| 685 | LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param); | ||
| 686 | 707 | ||
| 687 | *first_ucode_section = last_read_idx; | 708 | *first_ucode_section = last_read_idx; |
| 688 | 709 | ||
| @@ -735,49 +756,78 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, | |||
| 735 | return 0; | 756 | return 0; |
| 736 | } | 757 | } |
| 737 | 758 | ||
| 738 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | 759 | static void iwl_pcie_apply_destination(struct iwl_trans *trans) |
| 739 | const struct fw_img *image) | ||
| 740 | { | 760 | { |
| 741 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 761 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 742 | int ret = 0; | 762 | const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv; |
| 743 | int first_ucode_section; | 763 | int i; |
| 744 | 764 | ||
| 745 | IWL_DEBUG_FW(trans, | 765 | if (dest->version) |
| 746 | "working with %s image\n", | 766 | IWL_ERR(trans, |
| 747 | image->is_secure ? "Secured" : "Non Secured"); | 767 | "DBG DEST version is %d - expect issues\n", |
| 748 | IWL_DEBUG_FW(trans, | 768 | dest->version); |
| 749 | "working with %s CPU\n", | ||
| 750 | image->is_dual_cpus ? "Dual" : "Single"); | ||
| 751 | 769 | ||
| 752 | /* configure the ucode to be ready to get the secured image */ | 770 | IWL_INFO(trans, "Applying debug destination %s\n", |
| 753 | if (image->is_secure) { | 771 | get_fw_dbg_mode_string(dest->monitor_mode)); |
| 754 | /* set secure boot inspector addresses */ | ||
| 755 | iwl_write_prph(trans, | ||
| 756 | LMPM_SECURE_INSPECTOR_CODE_ADDR, | ||
| 757 | LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE); | ||
| 758 | 772 | ||
| 759 | iwl_write_prph(trans, | 773 | if (dest->monitor_mode == EXTERNAL_MODE) |
| 760 | LMPM_SECURE_INSPECTOR_DATA_ADDR, | 774 | iwl_pcie_alloc_fw_monitor(trans); |
| 761 | LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE); | 775 | else |
| 776 | IWL_WARN(trans, "PCI should have external buffer debug\n"); | ||
| 762 | 777 | ||
| 763 | /* set CPU1 header address */ | 778 | for (i = 0; i < trans->dbg_dest_reg_num; i++) { |
| 764 | iwl_write_prph(trans, | 779 | u32 addr = le32_to_cpu(dest->reg_ops[i].addr); |
| 765 | LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR, | 780 | u32 val = le32_to_cpu(dest->reg_ops[i].val); |
| 766 | LMPM_SECURE_CPU1_HDR_MEM_SPACE); | ||
| 767 | 781 | ||
| 768 | /* load to FW the binary Secured sections of CPU1 */ | 782 | switch (dest->reg_ops[i].op) { |
| 769 | ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1, | 783 | case CSR_ASSIGN: |
| 770 | &first_ucode_section); | 784 | iwl_write32(trans, addr, val); |
| 771 | if (ret) | 785 | break; |
| 772 | return ret; | 786 | case CSR_SETBIT: |
| 787 | iwl_set_bit(trans, addr, BIT(val)); | ||
| 788 | break; | ||
| 789 | case CSR_CLEARBIT: | ||
| 790 | iwl_clear_bit(trans, addr, BIT(val)); | ||
| 791 | break; | ||
| 792 | case PRPH_ASSIGN: | ||
| 793 | iwl_write_prph(trans, addr, val); | ||
| 794 | break; | ||
| 795 | case PRPH_SETBIT: | ||
| 796 | iwl_set_bits_prph(trans, addr, BIT(val)); | ||
| 797 | break; | ||
| 798 | case PRPH_CLEARBIT: | ||
| 799 | iwl_clear_bits_prph(trans, addr, BIT(val)); | ||
| 800 | break; | ||
| 801 | default: | ||
| 802 | IWL_ERR(trans, "FW debug - unknown OP %d\n", | ||
| 803 | dest->reg_ops[i].op); | ||
| 804 | break; | ||
| 805 | } | ||
| 806 | } | ||
| 773 | 807 | ||
| 774 | } else { | 808 | if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { |
| 775 | /* load to FW the binary Non secured sections of CPU1 */ | 809 | iwl_write_prph(trans, le32_to_cpu(dest->base_reg), |
| 776 | ret = iwl_pcie_load_cpu_sections(trans, image, 1, | 810 | trans_pcie->fw_mon_phys >> dest->base_shift); |
| 777 | &first_ucode_section); | 811 | iwl_write_prph(trans, le32_to_cpu(dest->end_reg), |
| 778 | if (ret) | 812 | (trans_pcie->fw_mon_phys + |
| 779 | return ret; | 813 | trans_pcie->fw_mon_size) >> dest->end_shift); |
| 780 | } | 814 | } |
| 815 | } | ||
| 816 | |||
| 817 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | ||
| 818 | const struct fw_img *image) | ||
| 819 | { | ||
| 820 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
| 821 | int ret = 0; | ||
| 822 | int first_ucode_section; | ||
| 823 | |||
| 824 | IWL_DEBUG_FW(trans, "working with %s CPU\n", | ||
| 825 | image->is_dual_cpus ? "Dual" : "Single"); | ||
| 826 | |||
| 827 | /* load to FW the binary non secured sections of CPU1 */ | ||
| 828 | ret = iwl_pcie_load_cpu_sections(trans, image, 1, &first_ucode_section); | ||
| 829 | if (ret) | ||
| 830 | return ret; | ||
| 781 | 831 | ||
| 782 | if (image->is_dual_cpus) { | 832 | if (image->is_dual_cpus) { |
| 783 | /* set CPU2 header address */ | 833 | /* set CPU2 header address */ |
| @@ -786,13 +836,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
| 786 | LMPM_SECURE_CPU2_HDR_MEM_SPACE); | 836 | LMPM_SECURE_CPU2_HDR_MEM_SPACE); |
| 787 | 837 | ||
| 788 | /* load to FW the binary sections of CPU2 */ | 838 | /* load to FW the binary sections of CPU2 */ |
| 789 | if (image->is_secure) | 839 | ret = iwl_pcie_load_cpu_sections(trans, image, 2, |
| 790 | ret = iwl_pcie_load_cpu_secured_sections( | 840 | &first_ucode_section); |
| 791 | trans, image, 2, | ||
| 792 | &first_ucode_section); | ||
| 793 | else | ||
| 794 | ret = iwl_pcie_load_cpu_sections(trans, image, 2, | ||
| 795 | &first_ucode_section); | ||
| 796 | if (ret) | 841 | if (ret) |
| 797 | return ret; | 842 | return ret; |
| 798 | } | 843 | } |
| @@ -809,6 +854,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
| 809 | (trans_pcie->fw_mon_phys + | 854 | (trans_pcie->fw_mon_phys + |
| 810 | trans_pcie->fw_mon_size) >> 4); | 855 | trans_pcie->fw_mon_size) >> 4); |
| 811 | } | 856 | } |
| 857 | } else if (trans->dbg_dest_tlv) { | ||
| 858 | iwl_pcie_apply_destination(trans); | ||
| 812 | } | 859 | } |
| 813 | 860 | ||
| 814 | /* release CPU reset */ | 861 | /* release CPU reset */ |
| @@ -817,18 +864,50 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
| 817 | else | 864 | else |
| 818 | iwl_write32(trans, CSR_RESET, 0); | 865 | iwl_write32(trans, CSR_RESET, 0); |
| 819 | 866 | ||
| 820 | if (image->is_secure) { | 867 | return 0; |
| 821 | /* wait for image verification to complete */ | 868 | } |
| 822 | ret = iwl_poll_prph_bit(trans, | ||
| 823 | LMPM_SECURE_BOOT_CPU1_STATUS_ADDR, | ||
| 824 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
| 825 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
| 826 | LMPM_SECURE_TIME_OUT); | ||
| 827 | 869 | ||
| 828 | if (ret < 0) { | 870 | static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, |
| 829 | IWL_ERR(trans, "Time out on secure boot process\n"); | 871 | const struct fw_img *image) |
| 830 | return ret; | 872 | { |
| 831 | } | 873 | int ret = 0; |
| 874 | int first_ucode_section; | ||
| 875 | u32 reg; | ||
| 876 | |||
| 877 | IWL_DEBUG_FW(trans, "working with %s CPU\n", | ||
| 878 | image->is_dual_cpus ? "Dual" : "Single"); | ||
| 879 | |||
| 880 | /* configure the ucode to be ready to get the secured image */ | ||
| 881 | /* release CPU reset */ | ||
| 882 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); | ||
| 883 | |||
| 884 | /* load to FW the binary Secured sections of CPU1 */ | ||
| 885 | ret = iwl_pcie_load_cpu_sections_8000b(trans, image, 1, | ||
| 886 | &first_ucode_section); | ||
| 887 | if (ret) | ||
| 888 | return ret; | ||
| 889 | |||
| 890 | /* load to FW the binary sections of CPU2 */ | ||
| 891 | ret = iwl_pcie_load_cpu_sections_8000b(trans, image, 2, | ||
| 892 | &first_ucode_section); | ||
| 893 | if (ret) | ||
| 894 | return ret; | ||
| 895 | |||
| 896 | /* Notify FW loading is done */ | ||
| 897 | iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); | ||
| 898 | |||
| 899 | /* wait for image verification to complete */ | ||
| 900 | ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0, | ||
| 901 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
| 902 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
| 903 | LMPM_SECURE_TIME_OUT); | ||
| 904 | if (ret < 0) { | ||
| 905 | reg = iwl_read_prph(trans, | ||
| 906 | LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0); | ||
| 907 | |||
| 908 | IWL_ERR(trans, "Timeout on secure boot process, reg = %x\n", | ||
| 909 | reg); | ||
| 910 | return ret; | ||
| 832 | } | 911 | } |
| 833 | 912 | ||
| 834 | return 0; | 913 | return 0; |
| @@ -880,7 +959,11 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, | |||
| 880 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 959 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
| 881 | 960 | ||
| 882 | /* Load the given image to the HW */ | 961 | /* Load the given image to the HW */ |
| 883 | return iwl_pcie_load_given_ucode(trans, fw); | 962 | if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && |
| 963 | (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)) | ||
| 964 | return iwl_pcie_load_given_ucode_8000b(trans, fw); | ||
| 965 | else | ||
| 966 | return iwl_pcie_load_given_ucode(trans, fw); | ||
| 884 | } | 967 | } |
| 885 | 968 | ||
| 886 | static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) | 969 | static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) |
| @@ -911,7 +994,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
| 911 | * restart. So don't process again if the device is | 994 | * restart. So don't process again if the device is |
| 912 | * already dead. | 995 | * already dead. |
| 913 | */ | 996 | */ |
| 914 | if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) { | 997 | if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { |
| 998 | IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n"); | ||
| 915 | iwl_pcie_tx_stop(trans); | 999 | iwl_pcie_tx_stop(trans); |
| 916 | iwl_pcie_rx_stop(trans); | 1000 | iwl_pcie_rx_stop(trans); |
| 917 | 1001 | ||
| @@ -928,20 +1012,25 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
| 928 | /* Stop the device, and put it in low power state */ | 1012 | /* Stop the device, and put it in low power state */ |
| 929 | iwl_pcie_apm_stop(trans); | 1013 | iwl_pcie_apm_stop(trans); |
| 930 | 1014 | ||
| 931 | /* Upon stop, the APM issues an interrupt if HW RF kill is set. | 1015 | /* stop and reset the on-board processor */ |
| 932 | * Clean again the interrupt here | 1016 | iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
| 1017 | udelay(20); | ||
| 1018 | |||
| 1019 | /* | ||
| 1020 | * Upon stop, the APM issues an interrupt if HW RF kill is set. | ||
| 1021 | * This is a bug in certain verions of the hardware. | ||
| 1022 | * Certain devices also keep sending HW RF kill interrupt all | ||
| 1023 | * the time, unless the interrupt is ACKed even if the interrupt | ||
| 1024 | * should be masked. Re-ACK all the interrupts here. | ||
| 933 | */ | 1025 | */ |
| 934 | spin_lock(&trans_pcie->irq_lock); | 1026 | spin_lock(&trans_pcie->irq_lock); |
| 935 | iwl_disable_interrupts(trans); | 1027 | iwl_disable_interrupts(trans); |
| 936 | spin_unlock(&trans_pcie->irq_lock); | 1028 | spin_unlock(&trans_pcie->irq_lock); |
| 937 | 1029 | ||
| 938 | /* stop and reset the on-board processor */ | ||
| 939 | iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | ||
| 940 | 1030 | ||
| 941 | /* clear all status bits */ | 1031 | /* clear all status bits */ |
| 942 | clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); | 1032 | clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); |
| 943 | clear_bit(STATUS_INT_ENABLED, &trans->status); | 1033 | clear_bit(STATUS_INT_ENABLED, &trans->status); |
| 944 | clear_bit(STATUS_DEVICE_ENABLED, &trans->status); | ||
| 945 | clear_bit(STATUS_TPOWER_PMI, &trans->status); | 1034 | clear_bit(STATUS_TPOWER_PMI, &trans->status); |
| 946 | clear_bit(STATUS_RFKILL, &trans->status); | 1035 | clear_bit(STATUS_RFKILL, &trans->status); |
| 947 | 1036 | ||
| @@ -970,6 +1059,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
| 970 | clear_bit(STATUS_RFKILL, &trans->status); | 1059 | clear_bit(STATUS_RFKILL, &trans->status); |
| 971 | if (hw_rfkill != was_hw_rfkill) | 1060 | if (hw_rfkill != was_hw_rfkill) |
| 972 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); | 1061 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
| 1062 | |||
| 1063 | /* re-take ownership to prevent other users from stealing the deivce */ | ||
| 1064 | iwl_pcie_prepare_card_hw(trans); | ||
| 973 | } | 1065 | } |
| 974 | 1066 | ||
| 975 | void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) | 1067 | void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) |
| @@ -1019,14 +1111,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |||
| 1019 | return 0; | 1111 | return 0; |
| 1020 | } | 1112 | } |
| 1021 | 1113 | ||
| 1022 | iwl_pcie_set_pwr(trans, false); | ||
| 1023 | |||
| 1024 | val = iwl_read32(trans, CSR_RESET); | ||
| 1025 | if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { | ||
| 1026 | *status = IWL_D3_STATUS_RESET; | ||
| 1027 | return 0; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /* | 1114 | /* |
| 1031 | * Also enables interrupts - none will happen as the device doesn't | 1115 | * Also enables interrupts - none will happen as the device doesn't |
| 1032 | * know we're waking it up, only when the opmode actually tells it | 1116 | * know we're waking it up, only when the opmode actually tells it |
| @@ -1037,15 +1121,20 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |||
| 1037 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 1121 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
| 1038 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | 1122 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
| 1039 | 1123 | ||
| 1124 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
| 1125 | udelay(2); | ||
| 1126 | |||
| 1040 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | 1127 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, |
| 1041 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 1128 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
| 1042 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | 1129 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
| 1043 | 25000); | 1130 | 25000); |
| 1044 | if (ret) { | 1131 | if (ret < 0) { |
| 1045 | IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); | 1132 | IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); |
| 1046 | return ret; | 1133 | return ret; |
| 1047 | } | 1134 | } |
| 1048 | 1135 | ||
| 1136 | iwl_pcie_set_pwr(trans, false); | ||
| 1137 | |||
| 1049 | iwl_trans_pcie_tx_reset(trans); | 1138 | iwl_trans_pcie_tx_reset(trans); |
| 1050 | 1139 | ||
| 1051 | ret = iwl_pcie_rx_init(trans); | 1140 | ret = iwl_pcie_rx_init(trans); |
| @@ -1054,7 +1143,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |||
| 1054 | return ret; | 1143 | return ret; |
| 1055 | } | 1144 | } |
| 1056 | 1145 | ||
| 1057 | *status = IWL_D3_STATUS_ALIVE; | 1146 | val = iwl_read32(trans, CSR_RESET); |
| 1147 | if (val & CSR_RESET_REG_FLAG_NEVO_RESET) | ||
| 1148 | *status = IWL_D3_STATUS_RESET; | ||
| 1149 | else | ||
| 1150 | *status = IWL_D3_STATUS_ALIVE; | ||
| 1151 | |||
| 1058 | return 0; | 1152 | return 0; |
| 1059 | } | 1153 | } |
| 1060 | 1154 | ||
| @@ -1169,6 +1263,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, | |||
| 1169 | 1263 | ||
| 1170 | trans_pcie->command_names = trans_cfg->command_names; | 1264 | trans_pcie->command_names = trans_cfg->command_names; |
| 1171 | trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; | 1265 | trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; |
| 1266 | trans_pcie->scd_set_active = trans_cfg->scd_set_active; | ||
| 1172 | 1267 | ||
| 1173 | /* Initialize NAPI here - it should be before registering to mac80211 | 1268 | /* Initialize NAPI here - it should be before registering to mac80211 |
| 1174 | * in the opmode but after the HW struct is allocated. | 1269 | * in the opmode but after the HW struct is allocated. |
| @@ -1231,6 +1326,8 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, | |||
| 1231 | /* this bit wakes up the NIC */ | 1326 | /* this bit wakes up the NIC */ |
| 1232 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | 1327 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, |
| 1233 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 1328 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
| 1329 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
| 1330 | udelay(2); | ||
| 1234 | 1331 | ||
| 1235 | /* | 1332 | /* |
| 1236 | * These bits say the device is running, and should keep running for | 1333 | * These bits say the device is running, and should keep running for |
| @@ -1762,6 +1859,13 @@ err: | |||
| 1762 | IWL_ERR(trans, "failed to create the trans debugfs entry\n"); | 1859 | IWL_ERR(trans, "failed to create the trans debugfs entry\n"); |
| 1763 | return -ENOMEM; | 1860 | return -ENOMEM; |
| 1764 | } | 1861 | } |
| 1862 | #else | ||
| 1863 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | ||
| 1864 | struct dentry *dir) | ||
| 1865 | { | ||
| 1866 | return 0; | ||
| 1867 | } | ||
| 1868 | #endif /*CONFIG_IWLWIFI_DEBUGFS */ | ||
| 1765 | 1869 | ||
| 1766 | static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) | 1870 | static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) |
| 1767 | { | 1871 | { |
| @@ -1889,8 +1993,7 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, | |||
| 1889 | int reg; | 1993 | int reg; |
| 1890 | __le32 *val; | 1994 | __le32 *val; |
| 1891 | 1995 | ||
| 1892 | prph_len += sizeof(*data) + sizeof(*prph) + | 1996 | prph_len += sizeof(**data) + sizeof(*prph) + num_bytes_in_chunk; |
| 1893 | num_bytes_in_chunk; | ||
| 1894 | 1997 | ||
| 1895 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); | 1998 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); |
| 1896 | (*data)->len = cpu_to_le32(sizeof(*prph) + | 1999 | (*data)->len = cpu_to_le32(sizeof(*prph) + |
| @@ -1933,6 +2036,31 @@ static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, | |||
| 1933 | return csr_len; | 2036 | return csr_len; |
| 1934 | } | 2037 | } |
| 1935 | 2038 | ||
| 2039 | static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, | ||
| 2040 | struct iwl_fw_error_dump_data **data) | ||
| 2041 | { | ||
| 2042 | u32 fh_regs_len = FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND; | ||
| 2043 | unsigned long flags; | ||
| 2044 | __le32 *val; | ||
| 2045 | int i; | ||
| 2046 | |||
| 2047 | if (!iwl_trans_grab_nic_access(trans, false, &flags)) | ||
| 2048 | return 0; | ||
| 2049 | |||
| 2050 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FH_REGS); | ||
| 2051 | (*data)->len = cpu_to_le32(fh_regs_len); | ||
| 2052 | val = (void *)(*data)->data; | ||
| 2053 | |||
| 2054 | for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; i += sizeof(u32)) | ||
| 2055 | *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); | ||
| 2056 | |||
| 2057 | iwl_trans_release_nic_access(trans, &flags); | ||
| 2058 | |||
| 2059 | *data = iwl_fw_error_next_data(*data); | ||
| 2060 | |||
| 2061 | return sizeof(**data) + fh_regs_len; | ||
| 2062 | } | ||
| 2063 | |||
| 1936 | static | 2064 | static |
| 1937 | struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | 2065 | struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) |
| 1938 | { | 2066 | { |
| @@ -1942,6 +2070,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | |||
| 1942 | struct iwl_fw_error_dump_txcmd *txcmd; | 2070 | struct iwl_fw_error_dump_txcmd *txcmd; |
| 1943 | struct iwl_trans_dump_data *dump_data; | 2071 | struct iwl_trans_dump_data *dump_data; |
| 1944 | u32 len; | 2072 | u32 len; |
| 2073 | u32 monitor_len; | ||
| 1945 | int i, ptr; | 2074 | int i, ptr; |
| 1946 | 2075 | ||
| 1947 | /* transport dump header */ | 2076 | /* transport dump header */ |
| @@ -1964,10 +2093,34 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | |||
| 1964 | num_bytes_in_chunk; | 2093 | num_bytes_in_chunk; |
| 1965 | } | 2094 | } |
| 1966 | 2095 | ||
| 2096 | /* FH registers */ | ||
| 2097 | len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); | ||
| 2098 | |||
| 1967 | /* FW monitor */ | 2099 | /* FW monitor */ |
| 1968 | if (trans_pcie->fw_mon_page) | 2100 | if (trans_pcie->fw_mon_page) { |
| 2101 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + | ||
| 2102 | trans_pcie->fw_mon_size; | ||
| 2103 | monitor_len = trans_pcie->fw_mon_size; | ||
| 2104 | } else if (trans->dbg_dest_tlv) { | ||
| 2105 | u32 base, end; | ||
| 2106 | |||
| 2107 | base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); | ||
| 2108 | end = le32_to_cpu(trans->dbg_dest_tlv->end_reg); | ||
| 2109 | |||
| 2110 | base = iwl_read_prph(trans, base) << | ||
| 2111 | trans->dbg_dest_tlv->base_shift; | ||
| 2112 | end = iwl_read_prph(trans, end) << | ||
| 2113 | trans->dbg_dest_tlv->end_shift; | ||
| 2114 | |||
| 2115 | /* Make "end" point to the actual end */ | ||
| 2116 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
| 2117 | end += (1 << trans->dbg_dest_tlv->end_shift); | ||
| 2118 | monitor_len = end - base; | ||
| 1969 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + | 2119 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + |
| 1970 | trans_pcie->fw_mon_size; | 2120 | monitor_len; |
| 2121 | } else { | ||
| 2122 | monitor_len = 0; | ||
| 2123 | } | ||
| 1971 | 2124 | ||
| 1972 | dump_data = vzalloc(len); | 2125 | dump_data = vzalloc(len); |
| 1973 | if (!dump_data) | 2126 | if (!dump_data) |
| @@ -2004,49 +2157,77 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | |||
| 2004 | 2157 | ||
| 2005 | len += iwl_trans_pcie_dump_prph(trans, &data); | 2158 | len += iwl_trans_pcie_dump_prph(trans, &data); |
| 2006 | len += iwl_trans_pcie_dump_csr(trans, &data); | 2159 | len += iwl_trans_pcie_dump_csr(trans, &data); |
| 2160 | len += iwl_trans_pcie_fh_regs_dump(trans, &data); | ||
| 2007 | /* data is already pointing to the next section */ | 2161 | /* data is already pointing to the next section */ |
| 2008 | 2162 | ||
| 2009 | if (trans_pcie->fw_mon_page) { | 2163 | if ((trans_pcie->fw_mon_page && |
| 2164 | trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || | ||
| 2165 | trans->dbg_dest_tlv) { | ||
| 2010 | struct iwl_fw_error_dump_fw_mon *fw_mon_data; | 2166 | struct iwl_fw_error_dump_fw_mon *fw_mon_data; |
| 2167 | u32 base, write_ptr, wrap_cnt; | ||
| 2168 | |||
| 2169 | /* If there was a dest TLV - use the values from there */ | ||
| 2170 | if (trans->dbg_dest_tlv) { | ||
| 2171 | write_ptr = | ||
| 2172 | le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); | ||
| 2173 | wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); | ||
| 2174 | base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); | ||
| 2175 | } else { | ||
| 2176 | base = MON_BUFF_BASE_ADDR; | ||
| 2177 | write_ptr = MON_BUFF_WRPTR; | ||
| 2178 | wrap_cnt = MON_BUFF_CYCLE_CNT; | ||
| 2179 | } | ||
| 2011 | 2180 | ||
| 2012 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); | 2181 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); |
| 2013 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + | ||
| 2014 | sizeof(*fw_mon_data)); | ||
| 2015 | fw_mon_data = (void *)data->data; | 2182 | fw_mon_data = (void *)data->data; |
| 2016 | fw_mon_data->fw_mon_wr_ptr = | 2183 | fw_mon_data->fw_mon_wr_ptr = |
| 2017 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR)); | 2184 | cpu_to_le32(iwl_read_prph(trans, write_ptr)); |
| 2018 | fw_mon_data->fw_mon_cycle_cnt = | 2185 | fw_mon_data->fw_mon_cycle_cnt = |
| 2019 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_CYCLE_CNT)); | 2186 | cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); |
| 2020 | fw_mon_data->fw_mon_base_ptr = | 2187 | fw_mon_data->fw_mon_base_ptr = |
| 2021 | cpu_to_le32(iwl_read_prph(trans, MON_BUFF_BASE_ADDR)); | 2188 | cpu_to_le32(iwl_read_prph(trans, base)); |
| 2022 | 2189 | ||
| 2023 | /* | 2190 | len += sizeof(*data) + sizeof(*fw_mon_data); |
| 2024 | * The firmware is now asserted, it won't write anything to | 2191 | if (trans_pcie->fw_mon_page) { |
| 2025 | * the buffer. CPU can take ownership to fetch the data. | 2192 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + |
| 2026 | * The buffer will be handed back to the device before the | 2193 | sizeof(*fw_mon_data)); |
| 2027 | * firmware will be restarted. | 2194 | |
| 2028 | */ | 2195 | /* |
| 2029 | dma_sync_single_for_cpu(trans->dev, trans_pcie->fw_mon_phys, | 2196 | * The firmware is now asserted, it won't write anything |
| 2030 | trans_pcie->fw_mon_size, | 2197 | * to the buffer. CPU can take ownership to fetch the |
| 2031 | DMA_FROM_DEVICE); | 2198 | * data. The buffer will be handed back to the device |
| 2032 | memcpy(fw_mon_data->data, page_address(trans_pcie->fw_mon_page), | 2199 | * before the firmware will be restarted. |
| 2033 | trans_pcie->fw_mon_size); | 2200 | */ |
| 2034 | 2201 | dma_sync_single_for_cpu(trans->dev, | |
| 2035 | len += sizeof(*data) + sizeof(*fw_mon_data) + | 2202 | trans_pcie->fw_mon_phys, |
| 2036 | trans_pcie->fw_mon_size; | 2203 | trans_pcie->fw_mon_size, |
| 2204 | DMA_FROM_DEVICE); | ||
| 2205 | memcpy(fw_mon_data->data, | ||
| 2206 | page_address(trans_pcie->fw_mon_page), | ||
| 2207 | trans_pcie->fw_mon_size); | ||
| 2208 | |||
| 2209 | len += trans_pcie->fw_mon_size; | ||
| 2210 | } else { | ||
| 2211 | /* If we are here then the buffer is internal */ | ||
| 2212 | |||
| 2213 | /* | ||
| 2214 | * Update pointers to reflect actual values after | ||
| 2215 | * shifting | ||
| 2216 | */ | ||
| 2217 | base = iwl_read_prph(trans, base) << | ||
| 2218 | trans->dbg_dest_tlv->base_shift; | ||
| 2219 | iwl_trans_read_mem(trans, base, fw_mon_data->data, | ||
| 2220 | monitor_len / sizeof(u32)); | ||
| 2221 | data->len = cpu_to_le32(sizeof(*fw_mon_data) + | ||
| 2222 | monitor_len); | ||
| 2223 | len += monitor_len; | ||
| 2224 | } | ||
| 2037 | } | 2225 | } |
| 2038 | 2226 | ||
| 2039 | dump_data->len = len; | 2227 | dump_data->len = len; |
| 2040 | 2228 | ||
| 2041 | return dump_data; | 2229 | return dump_data; |
| 2042 | } | 2230 | } |
| 2043 | #else | ||
| 2044 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | ||
| 2045 | struct dentry *dir) | ||
| 2046 | { | ||
| 2047 | return 0; | ||
| 2048 | } | ||
| 2049 | #endif /*CONFIG_IWLWIFI_DEBUGFS */ | ||
| 2050 | 2231 | ||
| 2051 | static const struct iwl_trans_ops trans_ops_pcie = { | 2232 | static const struct iwl_trans_ops trans_ops_pcie = { |
| 2052 | .start_hw = iwl_trans_pcie_start_hw, | 2233 | .start_hw = iwl_trans_pcie_start_hw, |
| @@ -2083,9 +2264,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { | |||
| 2083 | .release_nic_access = iwl_trans_pcie_release_nic_access, | 2264 | .release_nic_access = iwl_trans_pcie_release_nic_access, |
| 2084 | .set_bits_mask = iwl_trans_pcie_set_bits_mask, | 2265 | .set_bits_mask = iwl_trans_pcie_set_bits_mask, |
| 2085 | 2266 | ||
| 2086 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
| 2087 | .dump_data = iwl_trans_pcie_dump_data, | 2267 | .dump_data = iwl_trans_pcie_dump_data, |
| 2088 | #endif | ||
| 2089 | }; | 2268 | }; |
| 2090 | 2269 | ||
| 2091 | struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | 2270 | struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, |
| @@ -2187,7 +2366,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
| 2187 | */ | 2366 | */ |
| 2188 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | 2367 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) |
| 2189 | trans->hw_rev = (trans->hw_rev & 0xfff0) | | 2368 | trans->hw_rev = (trans->hw_rev & 0xfff0) | |
| 2190 | ((trans->hw_rev << 2) & 0xc); | 2369 | (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); |
| 2191 | 2370 | ||
| 2192 | trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; | 2371 | trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; |
| 2193 | snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), | 2372 | snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 6acccb19c4f3..8a6c7a084aa1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /****************************************************************************** | 1 | /****************************************************************************** |
| 2 | * | 2 | * |
| 3 | * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. | 3 | * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. |
| 4 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
| 4 | * | 5 | * |
| 5 | * Portions of this file are derived from the ipw3945 project, as well | 6 | * Portions of this file are derived from the ipw3945 project, as well |
| 6 | * as portions of the ieee80211 subsystem header files. | 7 | * as portions of the ieee80211 subsystem header files. |
| @@ -34,6 +35,7 @@ | |||
| 34 | #include "iwl-csr.h" | 35 | #include "iwl-csr.h" |
| 35 | #include "iwl-prph.h" | 36 | #include "iwl-prph.h" |
| 36 | #include "iwl-io.h" | 37 | #include "iwl-io.h" |
| 38 | #include "iwl-scd.h" | ||
| 37 | #include "iwl-op-mode.h" | 39 | #include "iwl-op-mode.h" |
| 38 | #include "internal.h" | 40 | #include "internal.h" |
| 39 | /* FIXME: need to abstract out TX command (once we know what it looks like) */ | 41 | /* FIXME: need to abstract out TX command (once we know what it looks like) */ |
| @@ -618,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) | |||
| 618 | /* De-alloc array of command/tx buffers */ | 620 | /* De-alloc array of command/tx buffers */ |
| 619 | if (txq_id == trans_pcie->cmd_queue) | 621 | if (txq_id == trans_pcie->cmd_queue) |
| 620 | for (i = 0; i < txq->q.n_window; i++) { | 622 | for (i = 0; i < txq->q.n_window; i++) { |
| 621 | kfree(txq->entries[i].cmd); | 623 | kzfree(txq->entries[i].cmd); |
| 622 | kfree(txq->entries[i].free_buf); | 624 | kzfree(txq->entries[i].free_buf); |
| 623 | } | 625 | } |
| 624 | 626 | ||
| 625 | /* De-alloc circular buffer of TFDs */ | 627 | /* De-alloc circular buffer of TFDs */ |
| @@ -644,17 +646,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) | |||
| 644 | memset(txq, 0, sizeof(*txq)); | 646 | memset(txq, 0, sizeof(*txq)); |
| 645 | } | 647 | } |
| 646 | 648 | ||
| 647 | /* | ||
| 648 | * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask | ||
| 649 | */ | ||
| 650 | static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask) | ||
| 651 | { | ||
| 652 | struct iwl_trans_pcie __maybe_unused *trans_pcie = | ||
| 653 | IWL_TRANS_GET_PCIE_TRANS(trans); | ||
| 654 | |||
| 655 | iwl_write_prph(trans, SCD_TXFACT, mask); | ||
| 656 | } | ||
| 657 | |||
| 658 | void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) | 649 | void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) |
| 659 | { | 650 | { |
| 660 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 651 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| @@ -692,7 +683,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) | |||
| 692 | trans_pcie->cmd_fifo); | 683 | trans_pcie->cmd_fifo); |
| 693 | 684 | ||
| 694 | /* Activate all Tx DMA/FIFO channels */ | 685 | /* Activate all Tx DMA/FIFO channels */ |
| 695 | iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7)); | 686 | iwl_scd_activate_fifos(trans); |
| 696 | 687 | ||
| 697 | /* Enable DMA channel */ | 688 | /* Enable DMA channel */ |
| 698 | for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++) | 689 | for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++) |
| @@ -745,7 +736,7 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans) | |||
| 745 | /* Turn off all Tx DMA fifos */ | 736 | /* Turn off all Tx DMA fifos */ |
| 746 | spin_lock(&trans_pcie->irq_lock); | 737 | spin_lock(&trans_pcie->irq_lock); |
| 747 | 738 | ||
| 748 | iwl_pcie_txq_set_sched(trans, 0); | 739 | iwl_scd_deactivate_fifos(trans); |
| 749 | 740 | ||
| 750 | /* Stop each Tx DMA channel, and wait for it to be idle */ | 741 | /* Stop each Tx DMA channel, and wait for it to be idle */ |
| 751 | for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { | 742 | for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { |
| @@ -886,7 +877,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) | |||
| 886 | spin_lock(&trans_pcie->irq_lock); | 877 | spin_lock(&trans_pcie->irq_lock); |
| 887 | 878 | ||
| 888 | /* Turn off all Tx DMA fifos */ | 879 | /* Turn off all Tx DMA fifos */ |
| 889 | iwl_write_prph(trans, SCD_TXFACT, 0); | 880 | iwl_scd_deactivate_fifos(trans); |
| 890 | 881 | ||
| 891 | /* Tell NIC where to find the "keep warm" buffer */ | 882 | /* Tell NIC where to find the "keep warm" buffer */ |
| 892 | iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, | 883 | iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, |
| @@ -998,6 +989,65 @@ out: | |||
| 998 | spin_unlock_bh(&txq->lock); | 989 | spin_unlock_bh(&txq->lock); |
| 999 | } | 990 | } |
| 1000 | 991 | ||
| 992 | static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans) | ||
| 993 | { | ||
| 994 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
| 995 | int ret; | ||
| 996 | |||
| 997 | lockdep_assert_held(&trans_pcie->reg_lock); | ||
| 998 | |||
| 999 | if (trans_pcie->cmd_in_flight) | ||
| 1000 | return 0; | ||
| 1001 | |||
| 1002 | trans_pcie->cmd_in_flight = true; | ||
| 1003 | |||
| 1004 | /* | ||
| 1005 | * wake up the NIC to make sure that the firmware will see the host | ||
| 1006 | * command - we will let the NIC sleep once all the host commands | ||
| 1007 | * returned. This needs to be done only on NICs that have | ||
| 1008 | * apmg_wake_up_wa set. | ||
| 1009 | */ | ||
| 1010 | if (trans->cfg->base_params->apmg_wake_up_wa) { | ||
| 1011 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | ||
| 1012 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
| 1013 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
| 1014 | udelay(2); | ||
| 1015 | |||
| 1016 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | ||
| 1017 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | ||
| 1018 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | ||
| 1019 | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), | ||
| 1020 | 15000); | ||
| 1021 | if (ret < 0) { | ||
| 1022 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
| 1023 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
| 1024 | trans_pcie->cmd_in_flight = false; | ||
| 1025 | IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); | ||
| 1026 | return -EIO; | ||
| 1027 | } | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | return 0; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) | ||
| 1034 | { | ||
| 1035 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
| 1036 | |||
| 1037 | lockdep_assert_held(&trans_pcie->reg_lock); | ||
| 1038 | |||
| 1039 | if (WARN_ON(!trans_pcie->cmd_in_flight)) | ||
| 1040 | return 0; | ||
| 1041 | |||
| 1042 | trans_pcie->cmd_in_flight = false; | ||
| 1043 | |||
| 1044 | if (trans->cfg->base_params->apmg_wake_up_wa) | ||
| 1045 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
| 1046 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
| 1047 | |||
| 1048 | return 0; | ||
| 1049 | } | ||
| 1050 | |||
| 1001 | /* | 1051 | /* |
| 1002 | * iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd | 1052 | * iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd |
| 1003 | * | 1053 | * |
| @@ -1033,14 +1083,9 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) | |||
| 1033 | } | 1083 | } |
| 1034 | } | 1084 | } |
| 1035 | 1085 | ||
| 1036 | if (trans->cfg->base_params->apmg_wake_up_wa && | 1086 | if (q->read_ptr == q->write_ptr) { |
| 1037 | q->read_ptr == q->write_ptr) { | ||
| 1038 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); | 1087 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); |
| 1039 | WARN_ON(!trans_pcie->cmd_in_flight); | 1088 | iwl_pcie_clear_cmd_in_flight(trans); |
| 1040 | trans_pcie->cmd_in_flight = false; | ||
| 1041 | __iwl_trans_pcie_clear_bit(trans, | ||
| 1042 | CSR_GP_CNTRL, | ||
| 1043 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
| 1044 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); | 1089 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); |
| 1045 | } | 1090 | } |
| 1046 | 1091 | ||
| @@ -1072,55 +1117,53 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, | |||
| 1072 | return 0; | 1117 | return 0; |
| 1073 | } | 1118 | } |
| 1074 | 1119 | ||
| 1075 | static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans, | ||
| 1076 | u16 txq_id) | ||
| 1077 | { | ||
| 1078 | /* Simply stop the queue, but don't change any configuration; | ||
| 1079 | * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ | ||
| 1080 | iwl_write_prph(trans, | ||
| 1081 | SCD_QUEUE_STATUS_BITS(txq_id), | ||
| 1082 | (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| | ||
| 1083 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | /* Receiver address (actually, Rx station's index into station table), | 1120 | /* Receiver address (actually, Rx station's index into station table), |
| 1087 | * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ | 1121 | * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ |
| 1088 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) | 1122 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) |
| 1089 | 1123 | ||
| 1090 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, | 1124 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, |
| 1091 | int sta_id, int tid, int frame_limit, u16 ssn) | 1125 | const struct iwl_trans_txq_scd_cfg *cfg) |
| 1092 | { | 1126 | { |
| 1093 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1127 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 1128 | int fifo = -1; | ||
| 1094 | 1129 | ||
| 1095 | if (test_and_set_bit(txq_id, trans_pcie->queue_used)) | 1130 | if (test_and_set_bit(txq_id, trans_pcie->queue_used)) |
| 1096 | WARN_ONCE(1, "queue %d already used - expect issues", txq_id); | 1131 | WARN_ONCE(1, "queue %d already used - expect issues", txq_id); |
| 1097 | 1132 | ||
| 1098 | /* Stop this Tx queue before configuring it */ | 1133 | if (cfg) { |
| 1099 | iwl_pcie_txq_set_inactive(trans, txq_id); | 1134 | fifo = cfg->fifo; |
| 1100 | 1135 | ||
| 1101 | /* Set this queue as a chain-building queue unless it is CMD queue */ | 1136 | /* Disable the scheduler prior configuring the cmd queue */ |
| 1102 | if (txq_id != trans_pcie->cmd_queue) | 1137 | if (txq_id == trans_pcie->cmd_queue && |
| 1103 | iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); | 1138 | trans_pcie->scd_set_active) |
| 1139 | iwl_scd_enable_set_active(trans, 0); | ||
| 1104 | 1140 | ||
| 1105 | /* If this queue is mapped to a certain station: it is an AGG queue */ | 1141 | /* Stop this Tx queue before configuring it */ |
| 1106 | if (sta_id >= 0) { | 1142 | iwl_scd_txq_set_inactive(trans, txq_id); |
| 1107 | u16 ra_tid = BUILD_RAxTID(sta_id, tid); | ||
| 1108 | 1143 | ||
| 1109 | /* Map receiver-address / traffic-ID to this queue */ | 1144 | /* Set this queue as a chain-building queue unless it is CMD */ |
| 1110 | iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); | 1145 | if (txq_id != trans_pcie->cmd_queue) |
| 1146 | iwl_scd_txq_set_chain(trans, txq_id); | ||
| 1111 | 1147 | ||
| 1112 | /* enable aggregations for the queue */ | 1148 | if (cfg->aggregate) { |
| 1113 | iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); | 1149 | u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid); |
| 1114 | trans_pcie->txq[txq_id].ampdu = true; | ||
| 1115 | } else { | ||
| 1116 | /* | ||
| 1117 | * disable aggregations for the queue, this will also make the | ||
| 1118 | * ra_tid mapping configuration irrelevant since it is now a | ||
| 1119 | * non-AGG queue. | ||
| 1120 | */ | ||
| 1121 | iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); | ||
| 1122 | 1150 | ||
| 1123 | ssn = trans_pcie->txq[txq_id].q.read_ptr; | 1151 | /* Map receiver-address / traffic-ID to this queue */ |
| 1152 | iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id); | ||
| 1153 | |||
| 1154 | /* enable aggregations for the queue */ | ||
| 1155 | iwl_scd_txq_enable_agg(trans, txq_id); | ||
| 1156 | trans_pcie->txq[txq_id].ampdu = true; | ||
| 1157 | } else { | ||
| 1158 | /* | ||
| 1159 | * disable aggregations for the queue, this will also | ||
| 1160 | * make the ra_tid mapping configuration irrelevant | ||
| 1161 | * since it is now a non-AGG queue. | ||
| 1162 | */ | ||
| 1163 | iwl_scd_txq_disable_agg(trans, txq_id); | ||
| 1164 | |||
| 1165 | ssn = trans_pcie->txq[txq_id].q.read_ptr; | ||
| 1166 | } | ||
| 1124 | } | 1167 | } |
| 1125 | 1168 | ||
| 1126 | /* Place first TFD at index corresponding to start sequence number. | 1169 | /* Place first TFD at index corresponding to start sequence number. |
| @@ -1128,32 +1171,44 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, | |||
| 1128 | trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); | 1171 | trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); |
| 1129 | trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); | 1172 | trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); |
| 1130 | 1173 | ||
| 1131 | iwl_write_direct32(trans, HBUS_TARG_WRPTR, | 1174 | if (cfg) { |
| 1132 | (ssn & 0xff) | (txq_id << 8)); | 1175 | u8 frame_limit = cfg->frame_limit; |
| 1133 | iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); | ||
| 1134 | 1176 | ||
| 1135 | /* Set up Tx window size and frame limit for this queue */ | 1177 | iwl_write_direct32(trans, HBUS_TARG_WRPTR, |
| 1136 | iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + | 1178 | (ssn & 0xff) | (txq_id << 8)); |
| 1137 | SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0); | 1179 | iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); |
| 1138 | iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + | 1180 | |
| 1181 | /* Set up Tx window size and frame limit for this queue */ | ||
| 1182 | iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + | ||
| 1183 | SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0); | ||
| 1184 | iwl_trans_write_mem32(trans, | ||
| 1185 | trans_pcie->scd_base_addr + | ||
| 1139 | SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), | 1186 | SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), |
| 1140 | ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & | 1187 | ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & |
| 1141 | SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | | 1188 | SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | |
| 1142 | ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & | 1189 | ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & |
| 1143 | SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); | 1190 | SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); |
| 1144 | 1191 | ||
| 1145 | /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ | 1192 | /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */ |
| 1146 | iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), | 1193 | iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), |
| 1147 | (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | | 1194 | (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | |
| 1148 | (fifo << SCD_QUEUE_STTS_REG_POS_TXF) | | 1195 | (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | |
| 1149 | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | | 1196 | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | |
| 1150 | SCD_QUEUE_STTS_REG_MSK); | 1197 | SCD_QUEUE_STTS_REG_MSK); |
| 1198 | |||
| 1199 | /* enable the scheduler for this queue (only) */ | ||
| 1200 | if (txq_id == trans_pcie->cmd_queue && | ||
| 1201 | trans_pcie->scd_set_active) | ||
| 1202 | iwl_scd_enable_set_active(trans, BIT(txq_id)); | ||
| 1203 | } | ||
| 1204 | |||
| 1151 | trans_pcie->txq[txq_id].active = true; | 1205 | trans_pcie->txq[txq_id].active = true; |
| 1152 | IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", | 1206 | IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", |
| 1153 | txq_id, fifo, ssn & 0xff); | 1207 | txq_id, fifo, ssn & 0xff); |
| 1154 | } | 1208 | } |
| 1155 | 1209 | ||
| 1156 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) | 1210 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, |
| 1211 | bool configure_scd) | ||
| 1157 | { | 1212 | { |
| 1158 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1213 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 1159 | u32 stts_addr = trans_pcie->scd_base_addr + | 1214 | u32 stts_addr = trans_pcie->scd_base_addr + |
| @@ -1172,10 +1227,12 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) | |||
| 1172 | return; | 1227 | return; |
| 1173 | } | 1228 | } |
| 1174 | 1229 | ||
| 1175 | iwl_pcie_txq_set_inactive(trans, txq_id); | 1230 | if (configure_scd) { |
| 1231 | iwl_scd_txq_set_inactive(trans, txq_id); | ||
| 1176 | 1232 | ||
| 1177 | iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, | 1233 | iwl_trans_write_mem(trans, stts_addr, (void *)zero_val, |
| 1178 | ARRAY_SIZE(zero_val)); | 1234 | ARRAY_SIZE(zero_val)); |
| 1235 | } | ||
| 1179 | 1236 | ||
| 1180 | iwl_pcie_txq_unmap(trans, txq_id); | 1237 | iwl_pcie_txq_unmap(trans, txq_id); |
| 1181 | trans_pcie->txq[txq_id].ampdu = false; | 1238 | trans_pcie->txq[txq_id].ampdu = false; |
| @@ -1406,7 +1463,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1406 | 1463 | ||
| 1407 | out_meta->flags = cmd->flags; | 1464 | out_meta->flags = cmd->flags; |
| 1408 | if (WARN_ON_ONCE(txq->entries[idx].free_buf)) | 1465 | if (WARN_ON_ONCE(txq->entries[idx].free_buf)) |
| 1409 | kfree(txq->entries[idx].free_buf); | 1466 | kzfree(txq->entries[idx].free_buf); |
| 1410 | txq->entries[idx].free_buf = dup_buf; | 1467 | txq->entries[idx].free_buf = dup_buf; |
| 1411 | 1468 | ||
| 1412 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); | 1469 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); |
| @@ -1416,32 +1473,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1416 | mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); | 1473 | mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); |
| 1417 | 1474 | ||
| 1418 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); | 1475 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); |
| 1419 | 1476 | ret = iwl_pcie_set_cmd_in_flight(trans); | |
| 1420 | /* | 1477 | if (ret < 0) { |
| 1421 | * wake up the NIC to make sure that the firmware will see the host | 1478 | idx = ret; |
| 1422 | * command - we will let the NIC sleep once all the host commands | 1479 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); |
| 1423 | * returned. This needs to be done only on NICs that have | 1480 | goto out; |
| 1424 | * apmg_wake_up_wa set. | ||
| 1425 | */ | ||
| 1426 | if (trans->cfg->base_params->apmg_wake_up_wa && | ||
| 1427 | !trans_pcie->cmd_in_flight) { | ||
| 1428 | trans_pcie->cmd_in_flight = true; | ||
| 1429 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | ||
| 1430 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
| 1431 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | ||
| 1432 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | ||
| 1433 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | ||
| 1434 | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), | ||
| 1435 | 15000); | ||
| 1436 | if (ret < 0) { | ||
| 1437 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
| 1438 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
| 1439 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); | ||
| 1440 | trans_pcie->cmd_in_flight = false; | ||
| 1441 | IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); | ||
| 1442 | idx = -EIO; | ||
| 1443 | goto out; | ||
| 1444 | } | ||
| 1445 | } | 1481 | } |
| 1446 | 1482 | ||
| 1447 | /* Increment and update queue's write index */ | 1483 | /* Increment and update queue's write index */ |
