diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/sta.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-devtrace.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-phy-db.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/d3.c | 104 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw.c | 133 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rx.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/tx.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/internal.h | 35 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/rx.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/tx.c | 299 |
18 files changed, 370 insertions, 385 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 94ef33838bc6..b775769f8322 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -151,7 +151,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
151 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); | 151 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); |
152 | 152 | ||
153 | if (!(flags & CMD_ASYNC)) { | 153 | if (!(flags & CMD_ASYNC)) { |
154 | cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; | 154 | cmd.flags |= CMD_WANT_SKB; |
155 | might_sleep(); | 155 | might_sleep(); |
156 | } | 156 | } |
157 | 157 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 9a0f45ec9e01..81aa91fab5aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h | |||
@@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data, | |||
349 | TRACE_EVENT(iwlwifi_dev_hcmd, | 349 | TRACE_EVENT(iwlwifi_dev_hcmd, |
350 | TP_PROTO(const struct device *dev, | 350 | TP_PROTO(const struct device *dev, |
351 | struct iwl_host_cmd *cmd, u16 total_size, | 351 | struct iwl_host_cmd *cmd, u16 total_size, |
352 | const void *hdr, size_t hdr_len), | 352 | struct iwl_cmd_header *hdr), |
353 | TP_ARGS(dev, cmd, total_size, hdr, hdr_len), | 353 | TP_ARGS(dev, cmd, total_size, hdr), |
354 | TP_STRUCT__entry( | 354 | TP_STRUCT__entry( |
355 | DEV_ENTRY | 355 | DEV_ENTRY |
356 | __dynamic_array(u8, hcmd, total_size) | 356 | __dynamic_array(u8, hcmd, total_size) |
357 | __field(u32, flags) | 357 | __field(u32, flags) |
358 | ), | 358 | ), |
359 | TP_fast_assign( | 359 | TP_fast_assign( |
360 | int i, offset = hdr_len; | 360 | int i, offset = sizeof(*hdr); |
361 | 361 | ||
362 | DEV_ASSIGN; | 362 | DEV_ASSIGN; |
363 | __entry->flags = cmd->flags; | 363 | __entry->flags = cmd->flags; |
364 | memcpy(__get_dynamic_array(hcmd), hdr, hdr_len); | 364 | memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); |
365 | 365 | ||
366 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 366 | for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { |
367 | if (!cmd->len[i]) | 367 | if (!cmd->len[i]) |
368 | continue; | 368 | continue; |
369 | if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) | ||
370 | continue; | ||
371 | memcpy((u8 *)__get_dynamic_array(hcmd) + offset, | 369 | memcpy((u8 *)__get_dynamic_array(hcmd) + offset, |
372 | cmd->data[i], cmd->len[i]); | 370 | cmd->data[i], cmd->len[i]); |
373 | offset += cmd->len[i]; | 371 | offset += cmd->len[i]; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6f228bb2b844..fbfd2d137117 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -1102,7 +1102,6 @@ void iwl_drv_stop(struct iwl_drv *drv) | |||
1102 | 1102 | ||
1103 | /* shared module parameters */ | 1103 | /* shared module parameters */ |
1104 | struct iwl_mod_params iwlwifi_mod_params = { | 1104 | struct iwl_mod_params iwlwifi_mod_params = { |
1105 | .amsdu_size_8K = 1, | ||
1106 | .restart_fw = 1, | 1105 | .restart_fw = 1, |
1107 | .plcp_check = true, | 1106 | .plcp_check = true, |
1108 | .bt_coex_active = true, | 1107 | .bt_coex_active = true, |
@@ -1207,7 +1206,7 @@ MODULE_PARM_DESC(11n_disable, | |||
1207 | "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); | 1206 | "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); |
1208 | module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, | 1207 | module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, |
1209 | int, S_IRUGO); | 1208 | int, S_IRUGO); |
1210 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); | 1209 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)"); |
1211 | module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO); | 1210 | module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO); |
1212 | MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); | 1211 | MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); |
1213 | 1212 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index e5e3a79eae2f..2c2a729092f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -91,7 +91,7 @@ enum iwl_power_level { | |||
91 | * @sw_crypto: using hardware encryption, default = 0 | 91 | * @sw_crypto: using hardware encryption, default = 0 |
92 | * @disable_11n: disable 11n capabilities, default = 0, | 92 | * @disable_11n: disable 11n capabilities, default = 0, |
93 | * use IWL_DISABLE_HT_* constants | 93 | * use IWL_DISABLE_HT_* constants |
94 | * @amsdu_size_8K: enable 8K amsdu size, default = 1 | 94 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 |
95 | * @restart_fw: restart firmware, default = 1 | 95 | * @restart_fw: restart firmware, default = 1 |
96 | * @plcp_check: enable plcp health check, default = true | 96 | * @plcp_check: enable plcp health check, default = true |
97 | * @wd_disable: enable stuck queue check, default = 0 | 97 | * @wd_disable: enable stuck queue check, default = 0 |
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index 14fc8d39fc28..3392011a8768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c | |||
@@ -136,12 +136,6 @@ struct iwl_calib_res_notif_phy_db { | |||
136 | u8 data[]; | 136 | u8 data[]; |
137 | } __packed; | 137 | } __packed; |
138 | 138 | ||
139 | #define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587) | ||
140 | static inline void iwl_phy_db_test_pic(__le32 pic) | ||
141 | { | ||
142 | WARN_ON(IWL_PHY_DB_STATIC_PIC != pic); | ||
143 | } | ||
144 | |||
145 | struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) | 139 | struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) |
146 | { | 140 | { |
147 | struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), | 141 | struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), |
@@ -260,11 +254,6 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, | |||
260 | (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; | 254 | (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; |
261 | } | 255 | } |
262 | 256 | ||
263 | /* Test PIC */ | ||
264 | if (type != IWL_PHY_DB_CFG) | ||
265 | iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) + | ||
266 | (size / sizeof(__le32)) - 1)); | ||
267 | |||
268 | IWL_DEBUG_INFO(phy_db->trans, | 257 | IWL_DEBUG_INFO(phy_db->trans, |
269 | "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", | 258 | "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", |
270 | __func__, __LINE__, type, size); | 259 | __func__, __LINE__, type, size); |
@@ -372,11 +361,6 @@ int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, | |||
372 | *size = entry->size; | 361 | *size = entry->size; |
373 | } | 362 | } |
374 | 363 | ||
375 | /* Test PIC */ | ||
376 | if (type != IWL_PHY_DB_CFG) | ||
377 | iwl_phy_db_test_pic(*(((__le32 *)*data) + | ||
378 | (*size / sizeof(__le32)) - 1)); | ||
379 | |||
380 | IWL_DEBUG_INFO(phy_db->trans, | 364 | IWL_DEBUG_INFO(phy_db->trans, |
381 | "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", | 365 | "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", |
382 | __func__, __LINE__, type, *size); | 366 | __func__, __LINE__, type, *size); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8c7bec6b9a0b..0cac2b7af78b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -186,19 +186,13 @@ struct iwl_rx_packet { | |||
186 | * @CMD_ASYNC: Return right away and don't want for the response | 186 | * @CMD_ASYNC: Return right away and don't want for the response |
187 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the | 187 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the |
188 | * response. The caller needs to call iwl_free_resp when done. | 188 | * response. The caller needs to call iwl_free_resp when done. |
189 | * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the | ||
190 | * response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be | ||
191 | * copied. The pointer passed to the response handler is in the transport | ||
192 | * ownership and don't need to be freed by the op_mode. This also means | ||
193 | * that the pointer is invalidated after the op_mode's handler returns. | ||
194 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. | 189 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. |
195 | */ | 190 | */ |
196 | enum CMD_MODE { | 191 | enum CMD_MODE { |
197 | CMD_SYNC = 0, | 192 | CMD_SYNC = 0, |
198 | CMD_ASYNC = BIT(0), | 193 | CMD_ASYNC = BIT(0), |
199 | CMD_WANT_SKB = BIT(1), | 194 | CMD_WANT_SKB = BIT(1), |
200 | CMD_WANT_HCMD = BIT(2), | 195 | CMD_ON_DEMAND = BIT(2), |
201 | CMD_ON_DEMAND = BIT(3), | ||
202 | }; | 196 | }; |
203 | 197 | ||
204 | #define DEF_CMD_PAYLOAD_SIZE 320 | 198 | #define DEF_CMD_PAYLOAD_SIZE 320 |
@@ -217,7 +211,11 @@ struct iwl_device_cmd { | |||
217 | 211 | ||
218 | #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) | 212 | #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) |
219 | 213 | ||
220 | #define IWL_MAX_CMD_TFDS 2 | 214 | /* |
215 | * number of transfer buffers (fragments) per transmit frame descriptor; | ||
216 | * this is just the driver's idea, the hardware supports 20 | ||
217 | */ | ||
218 | #define IWL_MAX_CMD_TBS_PER_TFD 2 | ||
221 | 219 | ||
222 | /** | 220 | /** |
223 | * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command | 221 | * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command |
@@ -254,15 +252,15 @@ enum iwl_hcmd_dataflag { | |||
254 | * @id: id of the host command | 252 | * @id: id of the host command |
255 | */ | 253 | */ |
256 | struct iwl_host_cmd { | 254 | struct iwl_host_cmd { |
257 | const void *data[IWL_MAX_CMD_TFDS]; | 255 | const void *data[IWL_MAX_CMD_TBS_PER_TFD]; |
258 | struct iwl_rx_packet *resp_pkt; | 256 | struct iwl_rx_packet *resp_pkt; |
259 | unsigned long _rx_page_addr; | 257 | unsigned long _rx_page_addr; |
260 | u32 _rx_page_order; | 258 | u32 _rx_page_order; |
261 | int handler_status; | 259 | int handler_status; |
262 | 260 | ||
263 | u32 flags; | 261 | u32 flags; |
264 | u16 len[IWL_MAX_CMD_TFDS]; | 262 | u16 len[IWL_MAX_CMD_TBS_PER_TFD]; |
265 | u8 dataflags[IWL_MAX_CMD_TFDS]; | 263 | u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD]; |
266 | u8 id; | 264 | u8 id; |
267 | }; | 265 | }; |
268 | 266 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index c64d864799cd..994c8c263dc0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -61,6 +61,7 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | 63 | ||
64 | #include <linux/etherdevice.h> | ||
64 | #include <net/cfg80211.h> | 65 | #include <net/cfg80211.h> |
65 | #include <net/ipv6.h> | 66 | #include <net/ipv6.h> |
66 | #include "iwl-modparams.h" | 67 | #include "iwl-modparams.h" |
@@ -192,6 +193,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | |||
192 | sizeof(wkc), &wkc); | 193 | sizeof(wkc), &wkc); |
193 | data->error = ret != 0; | 194 | data->error = ret != 0; |
194 | 195 | ||
196 | mvm->ptk_ivlen = key->iv_len; | ||
197 | mvm->ptk_icvlen = key->icv_len; | ||
198 | mvm->gtk_ivlen = key->iv_len; | ||
199 | mvm->gtk_icvlen = key->icv_len; | ||
200 | |||
195 | /* don't upload key again */ | 201 | /* don't upload key again */ |
196 | goto out_unlock; | 202 | goto out_unlock; |
197 | } | 203 | } |
@@ -304,9 +310,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | |||
304 | */ | 310 | */ |
305 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | 311 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { |
306 | key->hw_key_idx = 0; | 312 | key->hw_key_idx = 0; |
313 | mvm->ptk_ivlen = key->iv_len; | ||
314 | mvm->ptk_icvlen = key->icv_len; | ||
307 | } else { | 315 | } else { |
308 | data->gtk_key_idx++; | 316 | data->gtk_key_idx++; |
309 | key->hw_key_idx = data->gtk_key_idx; | 317 | key->hw_key_idx = data->gtk_key_idx; |
318 | mvm->gtk_ivlen = key->iv_len; | ||
319 | mvm->gtk_icvlen = key->icv_len; | ||
310 | } | 320 | } |
311 | 321 | ||
312 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); | 322 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); |
@@ -649,6 +659,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
649 | /* We reprogram keys and shouldn't allocate new key indices */ | 659 | /* We reprogram keys and shouldn't allocate new key indices */ |
650 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 660 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
651 | 661 | ||
662 | mvm->ptk_ivlen = 0; | ||
663 | mvm->ptk_icvlen = 0; | ||
664 | mvm->ptk_ivlen = 0; | ||
665 | mvm->ptk_icvlen = 0; | ||
666 | |||
652 | /* | 667 | /* |
653 | * The D3 firmware still hardcodes the AP station ID for the | 668 | * The D3 firmware still hardcodes the AP station ID for the |
654 | * BSS we're associated with as 0. As a result, we have to move | 669 | * BSS we're associated with as 0. As a result, we have to move |
@@ -783,7 +798,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
783 | struct iwl_wowlan_status *status; | 798 | struct iwl_wowlan_status *status; |
784 | u32 reasons; | 799 | u32 reasons; |
785 | int ret, len; | 800 | int ret, len; |
786 | bool pkt8023 = false; | ||
787 | struct sk_buff *pkt = NULL; | 801 | struct sk_buff *pkt = NULL; |
788 | 802 | ||
789 | iwl_trans_read_mem_bytes(mvm->trans, base, | 803 | iwl_trans_read_mem_bytes(mvm->trans, base, |
@@ -824,7 +838,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
824 | status = (void *)cmd.resp_pkt->data; | 838 | status = (void *)cmd.resp_pkt->data; |
825 | 839 | ||
826 | if (len - sizeof(struct iwl_cmd_header) != | 840 | if (len - sizeof(struct iwl_cmd_header) != |
827 | sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { | 841 | sizeof(*status) + |
842 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { | ||
828 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 843 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
829 | goto out; | 844 | goto out; |
830 | } | 845 | } |
@@ -836,61 +851,96 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
836 | goto report; | 851 | goto report; |
837 | } | 852 | } |
838 | 853 | ||
839 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { | 854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) |
840 | wakeup.magic_pkt = true; | 855 | wakeup.magic_pkt = true; |
841 | pkt8023 = true; | ||
842 | } | ||
843 | 856 | ||
844 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { | 857 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) |
845 | wakeup.pattern_idx = | 858 | wakeup.pattern_idx = |
846 | le16_to_cpu(status->pattern_number); | 859 | le16_to_cpu(status->pattern_number); |
847 | pkt8023 = true; | ||
848 | } | ||
849 | 860 | ||
850 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | 861 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | |
851 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | 862 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) |
852 | wakeup.disconnect = true; | 863 | wakeup.disconnect = true; |
853 | 864 | ||
854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { | 865 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) |
855 | wakeup.gtk_rekey_failure = true; | 866 | wakeup.gtk_rekey_failure = true; |
856 | pkt8023 = true; | ||
857 | } | ||
858 | 867 | ||
859 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { | 868 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) |
860 | wakeup.rfkill_release = true; | 869 | wakeup.rfkill_release = true; |
861 | pkt8023 = true; | ||
862 | } | ||
863 | 870 | ||
864 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { | 871 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) |
865 | wakeup.eap_identity_req = true; | 872 | wakeup.eap_identity_req = true; |
866 | pkt8023 = true; | ||
867 | } | ||
868 | 873 | ||
869 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { | 874 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) |
870 | wakeup.four_way_handshake = true; | 875 | wakeup.four_way_handshake = true; |
871 | pkt8023 = true; | ||
872 | } | ||
873 | 876 | ||
874 | if (status->wake_packet_bufsize) { | 877 | if (status->wake_packet_bufsize) { |
875 | u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); | 878 | int pktsize = le32_to_cpu(status->wake_packet_bufsize); |
876 | u32 pktlen = le32_to_cpu(status->wake_packet_length); | 879 | int pktlen = le32_to_cpu(status->wake_packet_length); |
880 | const u8 *pktdata = status->wake_packet; | ||
881 | struct ieee80211_hdr *hdr = (void *)pktdata; | ||
882 | int truncated = pktlen - pktsize; | ||
883 | |||
884 | /* this would be a firmware bug */ | ||
885 | if (WARN_ON_ONCE(truncated < 0)) | ||
886 | truncated = 0; | ||
887 | |||
888 | if (ieee80211_is_data(hdr->frame_control)) { | ||
889 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
890 | int ivlen = 0, icvlen = 4; /* also FCS */ | ||
877 | 891 | ||
878 | if (pkt8023) { | ||
879 | pkt = alloc_skb(pktsize, GFP_KERNEL); | 892 | pkt = alloc_skb(pktsize, GFP_KERNEL); |
880 | if (!pkt) | 893 | if (!pkt) |
881 | goto report; | 894 | goto report; |
882 | memcpy(skb_put(pkt, pktsize), status->wake_packet, | 895 | |
883 | pktsize); | 896 | memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); |
897 | pktdata += hdrlen; | ||
898 | pktsize -= hdrlen; | ||
899 | |||
900 | if (ieee80211_has_protected(hdr->frame_control)) { | ||
901 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
902 | ivlen = mvm->gtk_ivlen; | ||
903 | icvlen += mvm->gtk_icvlen; | ||
904 | } else { | ||
905 | ivlen = mvm->ptk_ivlen; | ||
906 | icvlen += mvm->ptk_icvlen; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | /* if truncated, FCS/ICV is (partially) gone */ | ||
911 | if (truncated >= icvlen) { | ||
912 | icvlen = 0; | ||
913 | truncated -= icvlen; | ||
914 | } else { | ||
915 | icvlen -= truncated; | ||
916 | truncated = 0; | ||
917 | } | ||
918 | |||
919 | pktsize -= ivlen + icvlen; | ||
920 | pktdata += ivlen; | ||
921 | |||
922 | memcpy(skb_put(pkt, pktsize), pktdata, pktsize); | ||
923 | |||
884 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) | 924 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) |
885 | goto report; | 925 | goto report; |
886 | wakeup.packet = pkt->data; | 926 | wakeup.packet = pkt->data; |
887 | wakeup.packet_present_len = pkt->len; | 927 | wakeup.packet_present_len = pkt->len; |
888 | wakeup.packet_len = pkt->len - (pktlen - pktsize); | 928 | wakeup.packet_len = pkt->len - truncated; |
889 | wakeup.packet_80211 = false; | 929 | wakeup.packet_80211 = false; |
890 | } else { | 930 | } else { |
931 | int fcslen = 4; | ||
932 | |||
933 | if (truncated >= 4) { | ||
934 | truncated -= 4; | ||
935 | fcslen = 0; | ||
936 | } else { | ||
937 | fcslen -= truncated; | ||
938 | truncated = 0; | ||
939 | } | ||
940 | pktsize -= fcslen; | ||
891 | wakeup.packet = status->wake_packet; | 941 | wakeup.packet = status->wake_packet; |
892 | wakeup.packet_present_len = pktsize; | 942 | wakeup.packet_present_len = pktsize; |
893 | wakeup.packet_len = pktlen; | 943 | wakeup.packet_len = pktlen - truncated; |
894 | wakeup.packet_80211 = true; | 944 | wakeup.packet_80211 = true; |
895 | } | 945 | } |
896 | } | 946 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 23eebda848b0..2adb61f103f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -762,18 +762,20 @@ struct iwl_phy_context_cmd { | |||
762 | #define IWL_RX_INFO_PHY_CNT 8 | 762 | #define IWL_RX_INFO_PHY_CNT 8 |
763 | #define IWL_RX_INFO_AGC_IDX 1 | 763 | #define IWL_RX_INFO_AGC_IDX 1 |
764 | #define IWL_RX_INFO_RSSI_AB_IDX 2 | 764 | #define IWL_RX_INFO_RSSI_AB_IDX 2 |
765 | #define IWL_RX_INFO_RSSI_C_IDX 3 | 765 | #define IWL_OFDM_AGC_A_MSK 0x0000007f |
766 | #define IWL_OFDM_AGC_DB_MSK 0xfe00 | 766 | #define IWL_OFDM_AGC_A_POS 0 |
767 | #define IWL_OFDM_AGC_DB_POS 9 | 767 | #define IWL_OFDM_AGC_B_MSK 0x00003f80 |
768 | #define IWL_OFDM_AGC_B_POS 7 | ||
769 | #define IWL_OFDM_AGC_CODE_MSK 0x3fe00000 | ||
770 | #define IWL_OFDM_AGC_CODE_POS 20 | ||
768 | #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff | 771 | #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff |
769 | #define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 | ||
770 | #define IWL_OFDM_RSSI_A_POS 0 | 772 | #define IWL_OFDM_RSSI_A_POS 0 |
773 | #define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 | ||
774 | #define IWL_OFDM_RSSI_ALLBAND_A_POS 8 | ||
771 | #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 | 775 | #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 |
772 | #define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 | ||
773 | #define IWL_OFDM_RSSI_B_POS 16 | 776 | #define IWL_OFDM_RSSI_B_POS 16 |
774 | #define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff | 777 | #define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 |
775 | #define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 | 778 | #define IWL_OFDM_RSSI_ALLBAND_B_POS 24 |
776 | #define IWL_OFDM_RSSI_C_POS 0 | ||
777 | 779 | ||
778 | /** | 780 | /** |
779 | * struct iwl_rx_phy_info - phy info | 781 | * struct iwl_rx_phy_info - phy info |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d3d959db03a9..500f818dba04 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -79,17 +79,8 @@ | |||
79 | #define UCODE_VALID_OK cpu_to_le32(0x1) | 79 | #define UCODE_VALID_OK cpu_to_le32(0x1) |
80 | 80 | ||
81 | /* Default calibration values for WkP - set to INIT image w/o running */ | 81 | /* Default calibration values for WkP - set to INIT image w/o running */ |
82 | static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, | ||
83 | 0x00, 0x18, 0x00 }; | ||
84 | static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, | ||
85 | 0x7f, 0x7f, 0x7f }; | ||
86 | static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; | ||
87 | static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, | ||
88 | 0x00 }; | ||
89 | static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 }; | ||
90 | static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; | 82 | static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; |
91 | static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; | 83 | static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; |
92 | static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 }; | ||
93 | 84 | ||
94 | struct iwl_calib_default_data { | 85 | struct iwl_calib_default_data { |
95 | u16 size; | 86 | u16 size; |
@@ -99,12 +90,7 @@ struct iwl_calib_default_data { | |||
99 | #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} | 90 | #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} |
100 | 91 | ||
101 | static const struct iwl_calib_default_data wkp_calib_default_data[12] = { | 92 | static const struct iwl_calib_default_data wkp_calib_default_data[12] = { |
102 | [5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), | ||
103 | [6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), | ||
104 | [7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), | ||
105 | [8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq), | ||
106 | [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), | 93 | [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), |
107 | [10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq), | ||
108 | [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), | 94 | [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), |
109 | }; | 95 | }; |
110 | 96 | ||
@@ -241,20 +227,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
241 | 227 | ||
242 | return 0; | 228 | return 0; |
243 | } | 229 | } |
244 | #define IWL_HW_REV_ID_RAINBOW 0x2 | ||
245 | #define IWL_PROJ_TYPE_LHP 0x5 | ||
246 | |||
247 | static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) | ||
248 | { | ||
249 | struct iwl_nvm_data *data = mvm->nvm_data; | ||
250 | /* Temp calls to static definitions, will be changed to CSR calls */ | ||
251 | u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; | ||
252 | u8 project_type = IWL_PROJ_TYPE_LHP; | ||
253 | |||
254 | return data->radio_cfg_dash | (data->radio_cfg_step << 2) | | ||
255 | (hw_rev_id << 4) | ((project_type & 0x7f) << 6) | | ||
256 | (data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); | ||
257 | } | ||
258 | 230 | ||
259 | static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | 231 | static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) |
260 | { | 232 | { |
@@ -262,7 +234,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | |||
262 | enum iwl_ucode_type ucode_type = mvm->cur_ucode; | 234 | enum iwl_ucode_type ucode_type = mvm->cur_ucode; |
263 | 235 | ||
264 | /* Set parameters */ | 236 | /* Set parameters */ |
265 | phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); | 237 | phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config); |
266 | phy_cfg_cmd.calib_control.event_trigger = | 238 | phy_cfg_cmd.calib_control.event_trigger = |
267 | mvm->fw->default_calib[ucode_type].event_trigger; | 239 | mvm->fw->default_calib[ucode_type].event_trigger; |
268 | phy_cfg_cmd.calib_control.flow_trigger = | 240 | phy_cfg_cmd.calib_control.flow_trigger = |
@@ -275,103 +247,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | |||
275 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); | 247 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); |
276 | } | 248 | } |
277 | 249 | ||
278 | /* Starting with the new PHY DB implementation - New calibs are enabled */ | ||
279 | /* Value - 0x405e7 */ | ||
280 | #define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\ | ||
281 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
282 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
283 | IWL_CALIB_CFG_DC_IDX |\ | ||
284 | IWL_CALIB_CFG_BB_FILTER_IDX |\ | ||
285 | IWL_CALIB_CFG_LO_LEAKAGE_IDX |\ | ||
286 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
287 | IWL_CALIB_CFG_RX_IQ_IDX |\ | ||
288 | IWL_CALIB_CFG_AGC_IDX) | ||
289 | |||
290 | #define IWL_CALIB_DEFAULT_EVENT_INIT 0x0 | ||
291 | |||
292 | /* Value 0x41567 */ | ||
293 | #define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\ | ||
294 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
295 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
296 | IWL_CALIB_CFG_BB_FILTER_IDX |\ | ||
297 | IWL_CALIB_CFG_DC_IDX |\ | ||
298 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
299 | IWL_CALIB_CFG_RX_IQ_IDX |\ | ||
300 | IWL_CALIB_CFG_SENSITIVITY_IDX |\ | ||
301 | IWL_CALIB_CFG_AGC_IDX) | ||
302 | |||
303 | #define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\ | ||
304 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
305 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
306 | IWL_CALIB_CFG_TX_PWR_IDX |\ | ||
307 | IWL_CALIB_CFG_DC_IDX |\ | ||
308 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
309 | IWL_CALIB_CFG_SENSITIVITY_IDX) | ||
310 | |||
311 | /* | ||
312 | * Sets the calibrations trigger values that will be sent to the FW for runtime | ||
313 | * and init calibrations. | ||
314 | * The ones given in the FW TLV are not correct. | ||
315 | */ | ||
316 | static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) | ||
317 | { | ||
318 | struct iwl_tlv_calib_ctrl default_calib; | ||
319 | |||
320 | /* | ||
321 | * WkP FW TLV calib bits are wrong, overwrite them. | ||
322 | * This defines the dynamic calibrations which are implemented in the | ||
323 | * uCode both for init(flow) calculation and event driven calibs. | ||
324 | */ | ||
325 | |||
326 | /* Init Image */ | ||
327 | default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); | ||
328 | default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); | ||
329 | |||
330 | if (default_calib.event_trigger != | ||
331 | mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) | ||
332 | IWL_ERR(mvm, | ||
333 | "Updating the event calib for INIT image: 0x%x -> 0x%x\n", | ||
334 | mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, | ||
335 | default_calib.event_trigger); | ||
336 | if (default_calib.flow_trigger != | ||
337 | mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) | ||
338 | IWL_ERR(mvm, | ||
339 | "Updating the flow calib for INIT image: 0x%x -> 0x%x\n", | ||
340 | mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, | ||
341 | default_calib.flow_trigger); | ||
342 | |||
343 | memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], | ||
344 | &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); | ||
345 | IWL_ERR(mvm, | ||
346 | "Setting uCode init calibrations event 0x%x, trigger 0x%x\n", | ||
347 | default_calib.event_trigger, | ||
348 | default_calib.flow_trigger); | ||
349 | |||
350 | /* Run time image */ | ||
351 | default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); | ||
352 | default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); | ||
353 | |||
354 | if (default_calib.event_trigger != | ||
355 | mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) | ||
356 | IWL_ERR(mvm, | ||
357 | "Updating the event calib for RT image: 0x%x -> 0x%x\n", | ||
358 | mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, | ||
359 | default_calib.event_trigger); | ||
360 | if (default_calib.flow_trigger != | ||
361 | mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) | ||
362 | IWL_ERR(mvm, | ||
363 | "Updating the flow calib for RT image: 0x%x -> 0x%x\n", | ||
364 | mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, | ||
365 | default_calib.flow_trigger); | ||
366 | |||
367 | memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], | ||
368 | &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); | ||
369 | IWL_ERR(mvm, | ||
370 | "Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", | ||
371 | default_calib.event_trigger, | ||
372 | default_calib.flow_trigger); | ||
373 | } | ||
374 | |||
375 | static int iwl_set_default_calibrations(struct iwl_mvm *mvm) | 250 | static int iwl_set_default_calibrations(struct iwl_mvm *mvm) |
376 | { | 251 | { |
377 | u8 cmd_raw[16]; /* holds the variable size commands */ | 252 | u8 cmd_raw[16]; /* holds the variable size commands */ |
@@ -446,8 +321,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
446 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); | 321 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); |
447 | WARN_ON(ret); | 322 | WARN_ON(ret); |
448 | 323 | ||
449 | /* Override the calibrations from TLV and the const of fw */ | 324 | /* Send TX valid antennas before triggering calibrations */ |
450 | iwl_set_default_calib_trigger(mvm); | 325 | ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); |
326 | if (ret) | ||
327 | goto error; | ||
451 | 328 | ||
452 | /* WkP doesn't have all calibrations, need to set default values */ | 329 | /* WkP doesn't have all calibrations, need to set default values */ |
453 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | 330 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e8264e11b12d..7e169b085afe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -557,11 +557,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
557 | return ret; | 557 | return ret; |
558 | } | 558 | } |
559 | 559 | ||
560 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | 560 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, |
561 | struct ieee80211_vif *vif) | 561 | struct ieee80211_vif *vif) |
562 | { | 562 | { |
563 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
564 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
565 | u32 tfd_msk = 0, ac; | 563 | u32 tfd_msk = 0, ac; |
566 | 564 | ||
567 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 565 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
@@ -594,12 +592,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
594 | */ | 592 | */ |
595 | flush_work(&mvm->sta_drained_wk); | 593 | flush_work(&mvm->sta_drained_wk); |
596 | } | 594 | } |
595 | } | ||
596 | |||
597 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | ||
598 | struct ieee80211_vif *vif) | ||
599 | { | ||
600 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
601 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
602 | |||
603 | iwl_mvm_prepare_mac_removal(mvm, vif); | ||
597 | 604 | ||
598 | mutex_lock(&mvm->mutex); | 605 | mutex_lock(&mvm->mutex); |
599 | 606 | ||
600 | /* | 607 | /* |
601 | * For AP/GO interface, the tear down of the resources allocated to the | 608 | * For AP/GO interface, the tear down of the resources allocated to the |
602 | * interface should be handled as part of the bss_info_changed flow. | 609 | * interface is be handled as part of the stop_ap flow. |
603 | */ | 610 | */ |
604 | if (vif->type == NL80211_IFTYPE_AP) { | 611 | if (vif->type == NL80211_IFTYPE_AP) { |
605 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | 612 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); |
@@ -763,6 +770,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
763 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 770 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
764 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 771 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
765 | 772 | ||
773 | iwl_mvm_prepare_mac_removal(mvm, vif); | ||
774 | |||
766 | mutex_lock(&mvm->mutex); | 775 | mutex_lock(&mvm->mutex); |
767 | 776 | ||
768 | mvmvif->ap_active = false; | 777 | mvmvif->ap_active = false; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4e339ccfa800..bdae700c769e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -80,7 +80,8 @@ | |||
80 | 80 | ||
81 | #define IWL_INVALID_MAC80211_QUEUE 0xff | 81 | #define IWL_INVALID_MAC80211_QUEUE 0xff |
82 | #define IWL_MVM_MAX_ADDRESSES 2 | 82 | #define IWL_MVM_MAX_ADDRESSES 2 |
83 | #define IWL_RSSI_OFFSET 44 | 83 | /* RSSI offset for WkP */ |
84 | #define IWL_RSSI_OFFSET 50 | ||
84 | 85 | ||
85 | enum iwl_mvm_tx_fifo { | 86 | enum iwl_mvm_tx_fifo { |
86 | IWL_MVM_TX_FIFO_BK = 0, | 87 | IWL_MVM_TX_FIFO_BK = 0, |
@@ -327,6 +328,10 @@ struct iwl_mvm { | |||
327 | struct led_classdev led; | 328 | struct led_classdev led; |
328 | 329 | ||
329 | struct ieee80211_vif *p2p_device_vif; | 330 | struct ieee80211_vif *p2p_device_vif; |
331 | |||
332 | #ifdef CONFIG_PM_SLEEP | ||
333 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; | ||
334 | #endif | ||
330 | }; | 335 | }; |
331 | 336 | ||
332 | /* Extract MVM priv from op_mode and _hw */ | 337 | /* Extract MVM priv from op_mode and _hw */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index aa59adf87db3..d0f9c1e0475e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -624,12 +624,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | |||
624 | ieee80211_free_txskb(mvm->hw, skb); | 624 | ieee80211_free_txskb(mvm->hw, skb); |
625 | } | 625 | } |
626 | 626 | ||
627 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | 627 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) |
628 | { | 628 | { |
629 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
630 | |||
631 | iwl_mvm_dump_nic_error_log(mvm); | ||
632 | |||
633 | iwl_abort_notification_waits(&mvm->notif_wait); | 629 | iwl_abort_notification_waits(&mvm->notif_wait); |
634 | 630 | ||
635 | /* | 631 | /* |
@@ -663,9 +659,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | |||
663 | } | 659 | } |
664 | } | 660 | } |
665 | 661 | ||
662 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | ||
663 | { | ||
664 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
665 | |||
666 | iwl_mvm_dump_nic_error_log(mvm); | ||
667 | |||
668 | iwl_mvm_nic_restart(mvm); | ||
669 | } | ||
670 | |||
666 | static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) | 671 | static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) |
667 | { | 672 | { |
673 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
674 | |||
668 | WARN_ON(1); | 675 | WARN_ON(1); |
676 | iwl_mvm_nic_restart(mvm); | ||
669 | } | 677 | } |
670 | 678 | ||
671 | static const struct iwl_op_mode_ops iwl_mvm_ops = { | 679 | static const struct iwl_op_mode_ops iwl_mvm_ops = { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 3f40ab05bbd8..b0b190d0ec23 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
131 | static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, | 131 | static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, |
132 | struct iwl_rx_phy_info *phy_info) | 132 | struct iwl_rx_phy_info *phy_info) |
133 | { | 133 | { |
134 | u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; | 134 | int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; |
135 | int rssi_all_band_a, rssi_all_band_b; | ||
136 | u32 agc_a, agc_b, max_agc; | ||
135 | u32 val; | 137 | u32 val; |
136 | 138 | ||
137 | /* Find max rssi among 3 possible receivers. | 139 | /* Find max rssi among 2 possible receivers. |
138 | * These values are measured by the Digital Signal Processor (DSP). | 140 | * These values are measured by the Digital Signal Processor (DSP). |
139 | * They should stay fairly constant even as the signal strength varies, | 141 | * They should stay fairly constant even as the signal strength varies, |
140 | * if the radio's Automatic Gain Control (AGC) is working right. | 142 | * if the radio's Automatic Gain Control (AGC) is working right. |
141 | * AGC value (see below) will provide the "interesting" info. | 143 | * AGC value (see below) will provide the "interesting" info. |
142 | */ | 144 | */ |
145 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | ||
146 | agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; | ||
147 | agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; | ||
148 | max_agc = max_t(u32, agc_a, agc_b); | ||
149 | |||
143 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); | 150 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); |
144 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; | 151 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; |
145 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; | 152 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; |
146 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); | 153 | rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> |
147 | rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; | 154 | IWL_OFDM_RSSI_ALLBAND_A_POS; |
148 | 155 | rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> | |
149 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | 156 | IWL_OFDM_RSSI_ALLBAND_B_POS; |
150 | agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; | ||
151 | 157 | ||
152 | max_rssi = max_t(u32, rssi_a, rssi_b); | 158 | /* |
153 | max_rssi = max_t(u32, max_rssi, rssi_c); | 159 | * dBm = rssi dB - agc dB - constant. |
160 | * Higher AGC (higher radio gain) means lower signal. | ||
161 | */ | ||
162 | rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; | ||
163 | rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; | ||
164 | max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); | ||
154 | 165 | ||
155 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", | 166 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", |
156 | rssi_a, rssi_b, rssi_c, max_rssi, agc_db); | 167 | rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); |
157 | 168 | ||
158 | /* dBm = max_rssi dB - agc dB - constant. | 169 | return max_rssi_dbm; |
159 | * Higher AGC (higher radio gain) means lower signal. */ | ||
160 | return max_rssi - agc_db - IWL_RSSI_OFFSET; | ||
161 | } | 170 | } |
162 | 171 | ||
163 | /* | 172 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 861a7f9f8e7f..274f44e2ef60 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -770,6 +770,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
770 | u16 txq_id; | 770 | u16 txq_id; |
771 | int err; | 771 | int err; |
772 | 772 | ||
773 | |||
774 | /* | ||
775 | * If mac80211 is cleaning its state, then say that we finished since | ||
776 | * our state has been cleared anyway. | ||
777 | */ | ||
778 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
779 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
780 | return 0; | ||
781 | } | ||
782 | |||
773 | spin_lock_bh(&mvmsta->lock); | 783 | spin_lock_bh(&mvmsta->lock); |
774 | 784 | ||
775 | txq_id = tid_data->txq_id; | 785 | txq_id = tid_data->txq_id; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6b67ce3f679c..6645efe5c03e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -607,12 +607,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
607 | 607 | ||
608 | /* Single frame failure in an AMPDU queue => send BAR */ | 608 | /* Single frame failure in an AMPDU queue => send BAR */ |
609 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE && | 609 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE && |
610 | !(info->flags & IEEE80211_TX_STAT_ACK)) { | 610 | !(info->flags & IEEE80211_TX_STAT_ACK)) |
611 | /* there must be only one skb in the skb_list */ | ||
612 | WARN_ON_ONCE(skb_freed > 1 || | ||
613 | !skb_queue_empty(&skbs)); | ||
614 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | 611 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; |
615 | } | ||
616 | 612 | ||
617 | /* W/A FW bug: seq_ctl is wrong when the queue is flushed */ | 613 | /* W/A FW bug: seq_ctl is wrong when the queue is flushed */ |
618 | if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { | 614 | if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index aa2a39a637dd..148843e7f34f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -137,10 +137,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) | |||
137 | struct iwl_cmd_meta { | 137 | struct iwl_cmd_meta { |
138 | /* only for SYNC commands, iff the reply skb is wanted */ | 138 | /* only for SYNC commands, iff the reply skb is wanted */ |
139 | struct iwl_host_cmd *source; | 139 | struct iwl_host_cmd *source; |
140 | |||
141 | DEFINE_DMA_UNMAP_ADDR(mapping); | ||
142 | DEFINE_DMA_UNMAP_LEN(len); | ||
143 | |||
144 | u32 flags; | 140 | u32 flags; |
145 | }; | 141 | }; |
146 | 142 | ||
@@ -182,19 +178,39 @@ struct iwl_queue { | |||
182 | #define TFD_TX_CMD_SLOTS 256 | 178 | #define TFD_TX_CMD_SLOTS 256 |
183 | #define TFD_CMD_SLOTS 32 | 179 | #define TFD_CMD_SLOTS 32 |
184 | 180 | ||
181 | /* | ||
182 | * The FH will write back to the first TB only, so we need | ||
183 | * to copy some data into the buffer regardless of whether | ||
184 | * it should be mapped or not. This indicates how big the | ||
185 | * first TB must be to include the scratch buffer. Since | ||
186 | * the scratch is 4 bytes at offset 12, it's 16 now. If we | ||
187 | * make it bigger then allocations will be bigger and copy | ||
188 | * slower, so that's probably not useful. | ||
189 | */ | ||
190 | #define IWL_HCMD_SCRATCHBUF_SIZE 16 | ||
191 | |||
185 | struct iwl_pcie_txq_entry { | 192 | struct iwl_pcie_txq_entry { |
186 | struct iwl_device_cmd *cmd; | 193 | struct iwl_device_cmd *cmd; |
187 | struct iwl_device_cmd *copy_cmd; | ||
188 | struct sk_buff *skb; | 194 | struct sk_buff *skb; |
189 | /* buffer to free after command completes */ | 195 | /* buffer to free after command completes */ |
190 | const void *free_buf; | 196 | const void *free_buf; |
191 | struct iwl_cmd_meta meta; | 197 | struct iwl_cmd_meta meta; |
192 | }; | 198 | }; |
193 | 199 | ||
200 | struct iwl_pcie_txq_scratch_buf { | ||
201 | struct iwl_cmd_header hdr; | ||
202 | u8 buf[8]; | ||
203 | __le32 scratch; | ||
204 | }; | ||
205 | |||
194 | /** | 206 | /** |
195 | * struct iwl_txq - Tx Queue for DMA | 207 | * struct iwl_txq - Tx Queue for DMA |
196 | * @q: generic Rx/Tx queue descriptor | 208 | * @q: generic Rx/Tx queue descriptor |
197 | * @tfds: transmit frame descriptors (DMA memory) | 209 | * @tfds: transmit frame descriptors (DMA memory) |
210 | * @scratchbufs: start of command headers, including scratch buffers, for | ||
211 | * the writeback -- this is DMA memory and an array holding one buffer | ||
212 | * for each command on the queue | ||
213 | * @scratchbufs_dma: DMA address for the scratchbufs start | ||
198 | * @entries: transmit entries (driver state) | 214 | * @entries: transmit entries (driver state) |
199 | * @lock: queue lock | 215 | * @lock: queue lock |
200 | * @stuck_timer: timer that fires if queue gets stuck | 216 | * @stuck_timer: timer that fires if queue gets stuck |
@@ -208,6 +224,8 @@ struct iwl_pcie_txq_entry { | |||
208 | struct iwl_txq { | 224 | struct iwl_txq { |
209 | struct iwl_queue q; | 225 | struct iwl_queue q; |
210 | struct iwl_tfd *tfds; | 226 | struct iwl_tfd *tfds; |
227 | struct iwl_pcie_txq_scratch_buf *scratchbufs; | ||
228 | dma_addr_t scratchbufs_dma; | ||
211 | struct iwl_pcie_txq_entry *entries; | 229 | struct iwl_pcie_txq_entry *entries; |
212 | spinlock_t lock; | 230 | spinlock_t lock; |
213 | struct timer_list stuck_timer; | 231 | struct timer_list stuck_timer; |
@@ -216,6 +234,13 @@ struct iwl_txq { | |||
216 | u8 active; | 234 | u8 active; |
217 | }; | 235 | }; |
218 | 236 | ||
237 | static inline dma_addr_t | ||
238 | iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) | ||
239 | { | ||
240 | return txq->scratchbufs_dma + | ||
241 | sizeof(struct iwl_pcie_txq_scratch_buf) * idx; | ||
242 | } | ||
243 | |||
219 | /** | 244 | /** |
220 | * struct iwl_trans_pcie - PCIe transport specific data | 245 | * struct iwl_trans_pcie - PCIe transport specific data |
221 | * @rxq: all the RX queue data | 246 | * @rxq: all the RX queue data |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index b0ae06d2456f..567e67ad1f61 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -637,22 +637,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, | |||
637 | index = SEQ_TO_INDEX(sequence); | 637 | index = SEQ_TO_INDEX(sequence); |
638 | cmd_index = get_cmd_index(&txq->q, index); | 638 | cmd_index = get_cmd_index(&txq->q, index); |
639 | 639 | ||
640 | if (reclaim) { | 640 | if (reclaim) |
641 | struct iwl_pcie_txq_entry *ent; | 641 | cmd = txq->entries[cmd_index].cmd; |
642 | ent = &txq->entries[cmd_index]; | 642 | else |
643 | cmd = ent->copy_cmd; | ||
644 | WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); | ||
645 | } else { | ||
646 | cmd = NULL; | 643 | cmd = NULL; |
647 | } | ||
648 | 644 | ||
649 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); | 645 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); |
650 | 646 | ||
651 | if (reclaim) { | 647 | if (reclaim) { |
652 | /* The original command isn't needed any more */ | ||
653 | kfree(txq->entries[cmd_index].copy_cmd); | ||
654 | txq->entries[cmd_index].copy_cmd = NULL; | ||
655 | /* nor is the duplicated part of the command */ | ||
656 | kfree(txq->entries[cmd_index].free_buf); | 648 | kfree(txq->entries[cmd_index].free_buf); |
657 | txq->entries[cmd_index].free_buf = NULL; | 649 | txq->entries[cmd_index].free_buf = NULL; |
658 | } | 650 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8e9e3212fe78..8595c16f74de 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -191,12 +191,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) | |||
191 | } | 191 | } |
192 | 192 | ||
193 | for (i = q->read_ptr; i != q->write_ptr; | 193 | for (i = q->read_ptr; i != q->write_ptr; |
194 | i = iwl_queue_inc_wrap(i, q->n_bd)) { | 194 | i = iwl_queue_inc_wrap(i, q->n_bd)) |
195 | struct iwl_tx_cmd *tx_cmd = | ||
196 | (struct iwl_tx_cmd *)txq->entries[i].cmd->payload; | ||
197 | IWL_ERR(trans, "scratch %d = 0x%08x\n", i, | 195 | IWL_ERR(trans, "scratch %d = 0x%08x\n", i, |
198 | get_unaligned_le32(&tx_cmd->scratch)); | 196 | le32_to_cpu(txq->scratchbufs[i].scratch)); |
199 | } | ||
200 | 197 | ||
201 | iwl_op_mode_nic_error(trans->op_mode); | 198 | iwl_op_mode_nic_error(trans->op_mode); |
202 | } | 199 | } |
@@ -367,8 +364,8 @@ static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd) | |||
367 | } | 364 | } |
368 | 365 | ||
369 | static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, | 366 | static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, |
370 | struct iwl_cmd_meta *meta, struct iwl_tfd *tfd, | 367 | struct iwl_cmd_meta *meta, |
371 | enum dma_data_direction dma_dir) | 368 | struct iwl_tfd *tfd) |
372 | { | 369 | { |
373 | int i; | 370 | int i; |
374 | int num_tbs; | 371 | int num_tbs; |
@@ -382,17 +379,12 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, | |||
382 | return; | 379 | return; |
383 | } | 380 | } |
384 | 381 | ||
385 | /* Unmap tx_cmd */ | 382 | /* first TB is never freed - it's the scratchbuf data */ |
386 | if (num_tbs) | ||
387 | dma_unmap_single(trans->dev, | ||
388 | dma_unmap_addr(meta, mapping), | ||
389 | dma_unmap_len(meta, len), | ||
390 | DMA_BIDIRECTIONAL); | ||
391 | 383 | ||
392 | /* Unmap chunks, if any. */ | ||
393 | for (i = 1; i < num_tbs; i++) | 384 | for (i = 1; i < num_tbs; i++) |
394 | dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), | 385 | dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), |
395 | iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir); | 386 | iwl_pcie_tfd_tb_get_len(tfd, i), |
387 | DMA_TO_DEVICE); | ||
396 | 388 | ||
397 | tfd->num_tbs = 0; | 389 | tfd->num_tbs = 0; |
398 | } | 390 | } |
@@ -406,8 +398,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, | |||
406 | * Does NOT advance any TFD circular buffer read/write indexes | 398 | * Does NOT advance any TFD circular buffer read/write indexes |
407 | * Does NOT free the TFD itself (which is within circular buffer) | 399 | * Does NOT free the TFD itself (which is within circular buffer) |
408 | */ | 400 | */ |
409 | static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, | 401 | static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) |
410 | enum dma_data_direction dma_dir) | ||
411 | { | 402 | { |
412 | struct iwl_tfd *tfd_tmp = txq->tfds; | 403 | struct iwl_tfd *tfd_tmp = txq->tfds; |
413 | 404 | ||
@@ -418,8 +409,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq, | |||
418 | lockdep_assert_held(&txq->lock); | 409 | lockdep_assert_held(&txq->lock); |
419 | 410 | ||
420 | /* We have only q->n_window txq->entries, but we use q->n_bd tfds */ | 411 | /* We have only q->n_window txq->entries, but we use q->n_bd tfds */ |
421 | iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr], | 412 | iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr]); |
422 | dma_dir); | ||
423 | 413 | ||
424 | /* free SKB */ | 414 | /* free SKB */ |
425 | if (txq->entries) { | 415 | if (txq->entries) { |
@@ -479,6 +469,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans, | |||
479 | { | 469 | { |
480 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 470 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
481 | size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; | 471 | size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; |
472 | size_t scratchbuf_sz; | ||
482 | int i; | 473 | int i; |
483 | 474 | ||
484 | if (WARN_ON(txq->entries || txq->tfds)) | 475 | if (WARN_ON(txq->entries || txq->tfds)) |
@@ -514,9 +505,25 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans, | |||
514 | IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz); | 505 | IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz); |
515 | goto error; | 506 | goto error; |
516 | } | 507 | } |
508 | |||
509 | BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs)); | ||
510 | BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) != | ||
511 | sizeof(struct iwl_cmd_header) + | ||
512 | offsetof(struct iwl_tx_cmd, scratch)); | ||
513 | |||
514 | scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num; | ||
515 | |||
516 | txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz, | ||
517 | &txq->scratchbufs_dma, | ||
518 | GFP_KERNEL); | ||
519 | if (!txq->scratchbufs) | ||
520 | goto err_free_tfds; | ||
521 | |||
517 | txq->q.id = txq_id; | 522 | txq->q.id = txq_id; |
518 | 523 | ||
519 | return 0; | 524 | return 0; |
525 | err_free_tfds: | ||
526 | dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->q.dma_addr); | ||
520 | error: | 527 | error: |
521 | if (txq->entries && txq_id == trans_pcie->cmd_queue) | 528 | if (txq->entries && txq_id == trans_pcie->cmd_queue) |
522 | for (i = 0; i < slots_num; i++) | 529 | for (i = 0; i < slots_num; i++) |
@@ -565,22 +572,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) | |||
565 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 572 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
566 | struct iwl_txq *txq = &trans_pcie->txq[txq_id]; | 573 | struct iwl_txq *txq = &trans_pcie->txq[txq_id]; |
567 | struct iwl_queue *q = &txq->q; | 574 | struct iwl_queue *q = &txq->q; |
568 | enum dma_data_direction dma_dir; | ||
569 | 575 | ||
570 | if (!q->n_bd) | 576 | if (!q->n_bd) |
571 | return; | 577 | return; |
572 | 578 | ||
573 | /* In the command queue, all the TBs are mapped as BIDI | ||
574 | * so unmap them as such. | ||
575 | */ | ||
576 | if (txq_id == trans_pcie->cmd_queue) | ||
577 | dma_dir = DMA_BIDIRECTIONAL; | ||
578 | else | ||
579 | dma_dir = DMA_TO_DEVICE; | ||
580 | |||
581 | spin_lock_bh(&txq->lock); | 579 | spin_lock_bh(&txq->lock); |
582 | while (q->write_ptr != q->read_ptr) { | 580 | while (q->write_ptr != q->read_ptr) { |
583 | iwl_pcie_txq_free_tfd(trans, txq, dma_dir); | 581 | iwl_pcie_txq_free_tfd(trans, txq); |
584 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); | 582 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); |
585 | } | 583 | } |
586 | spin_unlock_bh(&txq->lock); | 584 | spin_unlock_bh(&txq->lock); |
@@ -610,7 +608,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) | |||
610 | if (txq_id == trans_pcie->cmd_queue) | 608 | if (txq_id == trans_pcie->cmd_queue) |
611 | for (i = 0; i < txq->q.n_window; i++) { | 609 | for (i = 0; i < txq->q.n_window; i++) { |
612 | kfree(txq->entries[i].cmd); | 610 | kfree(txq->entries[i].cmd); |
613 | kfree(txq->entries[i].copy_cmd); | ||
614 | kfree(txq->entries[i].free_buf); | 611 | kfree(txq->entries[i].free_buf); |
615 | } | 612 | } |
616 | 613 | ||
@@ -619,6 +616,10 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) | |||
619 | dma_free_coherent(dev, sizeof(struct iwl_tfd) * | 616 | dma_free_coherent(dev, sizeof(struct iwl_tfd) * |
620 | txq->q.n_bd, txq->tfds, txq->q.dma_addr); | 617 | txq->q.n_bd, txq->tfds, txq->q.dma_addr); |
621 | txq->q.dma_addr = 0; | 618 | txq->q.dma_addr = 0; |
619 | |||
620 | dma_free_coherent(dev, | ||
621 | sizeof(*txq->scratchbufs) * txq->q.n_window, | ||
622 | txq->scratchbufs, txq->scratchbufs_dma); | ||
622 | } | 623 | } |
623 | 624 | ||
624 | kfree(txq->entries); | 625 | kfree(txq->entries); |
@@ -962,7 +963,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
962 | 963 | ||
963 | iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); | 964 | iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); |
964 | 965 | ||
965 | iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE); | 966 | iwl_pcie_txq_free_tfd(trans, txq); |
966 | } | 967 | } |
967 | 968 | ||
968 | iwl_pcie_txq_progress(trans_pcie, txq); | 969 | iwl_pcie_txq_progress(trans_pcie, txq); |
@@ -1152,20 +1153,37 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1152 | void *dup_buf = NULL; | 1153 | void *dup_buf = NULL; |
1153 | dma_addr_t phys_addr; | 1154 | dma_addr_t phys_addr; |
1154 | int idx; | 1155 | int idx; |
1155 | u16 copy_size, cmd_size; | 1156 | u16 copy_size, cmd_size, scratch_size; |
1156 | bool had_nocopy = false; | 1157 | bool had_nocopy = false; |
1157 | int i; | 1158 | int i; |
1158 | u32 cmd_pos; | 1159 | u32 cmd_pos; |
1160 | const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; | ||
1161 | u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; | ||
1159 | 1162 | ||
1160 | copy_size = sizeof(out_cmd->hdr); | 1163 | copy_size = sizeof(out_cmd->hdr); |
1161 | cmd_size = sizeof(out_cmd->hdr); | 1164 | cmd_size = sizeof(out_cmd->hdr); |
1162 | 1165 | ||
1163 | /* need one for the header if the first is NOCOPY */ | 1166 | /* need one for the header if the first is NOCOPY */ |
1164 | BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); | 1167 | BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); |
1168 | |||
1169 | for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { | ||
1170 | cmddata[i] = cmd->data[i]; | ||
1171 | cmdlen[i] = cmd->len[i]; | ||
1165 | 1172 | ||
1166 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | ||
1167 | if (!cmd->len[i]) | 1173 | if (!cmd->len[i]) |
1168 | continue; | 1174 | continue; |
1175 | |||
1176 | /* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ | ||
1177 | if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { | ||
1178 | int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; | ||
1179 | |||
1180 | if (copy > cmdlen[i]) | ||
1181 | copy = cmdlen[i]; | ||
1182 | cmdlen[i] -= copy; | ||
1183 | cmddata[i] += copy; | ||
1184 | copy_size += copy; | ||
1185 | } | ||
1186 | |||
1169 | if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { | 1187 | if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { |
1170 | had_nocopy = true; | 1188 | had_nocopy = true; |
1171 | if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { | 1189 | if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { |
@@ -1185,7 +1203,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1185 | goto free_dup_buf; | 1203 | goto free_dup_buf; |
1186 | } | 1204 | } |
1187 | 1205 | ||
1188 | dup_buf = kmemdup(cmd->data[i], cmd->len[i], | 1206 | dup_buf = kmemdup(cmddata[i], cmdlen[i], |
1189 | GFP_ATOMIC); | 1207 | GFP_ATOMIC); |
1190 | if (!dup_buf) | 1208 | if (!dup_buf) |
1191 | return -ENOMEM; | 1209 | return -ENOMEM; |
@@ -1195,7 +1213,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1195 | idx = -EINVAL; | 1213 | idx = -EINVAL; |
1196 | goto free_dup_buf; | 1214 | goto free_dup_buf; |
1197 | } | 1215 | } |
1198 | copy_size += cmd->len[i]; | 1216 | copy_size += cmdlen[i]; |
1199 | } | 1217 | } |
1200 | cmd_size += cmd->len[i]; | 1218 | cmd_size += cmd->len[i]; |
1201 | } | 1219 | } |
@@ -1242,30 +1260,30 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1242 | 1260 | ||
1243 | /* and copy the data that needs to be copied */ | 1261 | /* and copy the data that needs to be copied */ |
1244 | cmd_pos = offsetof(struct iwl_device_cmd, payload); | 1262 | cmd_pos = offsetof(struct iwl_device_cmd, payload); |
1245 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 1263 | copy_size = sizeof(out_cmd->hdr); |
1246 | if (!cmd->len[i]) | 1264 | for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { |
1265 | int copy = 0; | ||
1266 | |||
1267 | if (!cmd->len) | ||
1247 | continue; | 1268 | continue; |
1248 | if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | | ||
1249 | IWL_HCMD_DFL_DUP)) | ||
1250 | break; | ||
1251 | memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); | ||
1252 | cmd_pos += cmd->len[i]; | ||
1253 | } | ||
1254 | 1269 | ||
1255 | WARN_ON_ONCE(txq->entries[idx].copy_cmd); | 1270 | /* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */ |
1271 | if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) { | ||
1272 | copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size; | ||
1256 | 1273 | ||
1257 | /* | 1274 | if (copy > cmd->len[i]) |
1258 | * since out_cmd will be the source address of the FH, it will write | 1275 | copy = cmd->len[i]; |
1259 | * the retry count there. So when the user needs to receivce the HCMD | 1276 | } |
1260 | * that corresponds to the response in the response handler, it needs | 1277 | |
1261 | * to set CMD_WANT_HCMD. | 1278 | /* copy everything if not nocopy/dup */ |
1262 | */ | 1279 | if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | |
1263 | if (cmd->flags & CMD_WANT_HCMD) { | 1280 | IWL_HCMD_DFL_DUP))) |
1264 | txq->entries[idx].copy_cmd = | 1281 | copy = cmd->len[i]; |
1265 | kmemdup(out_cmd, cmd_pos, GFP_ATOMIC); | 1282 | |
1266 | if (unlikely(!txq->entries[idx].copy_cmd)) { | 1283 | if (copy) { |
1267 | idx = -ENOMEM; | 1284 | memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); |
1268 | goto out; | 1285 | cmd_pos += copy; |
1286 | copy_size += copy; | ||
1269 | } | 1287 | } |
1270 | } | 1288 | } |
1271 | 1289 | ||
@@ -1275,22 +1293,35 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1275 | out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), | 1293 | out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), |
1276 | cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); | 1294 | cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); |
1277 | 1295 | ||
1278 | phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, | 1296 | /* start the TFD with the scratchbuf */ |
1279 | DMA_BIDIRECTIONAL); | 1297 | scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE); |
1280 | if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { | 1298 | memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size); |
1281 | idx = -ENOMEM; | 1299 | iwl_pcie_txq_build_tfd(trans, txq, |
1282 | goto out; | 1300 | iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr), |
1283 | } | 1301 | scratch_size, 1); |
1284 | 1302 | ||
1285 | dma_unmap_addr_set(out_meta, mapping, phys_addr); | 1303 | /* map first command fragment, if any remains */ |
1286 | dma_unmap_len_set(out_meta, len, copy_size); | 1304 | if (copy_size > scratch_size) { |
1305 | phys_addr = dma_map_single(trans->dev, | ||
1306 | ((u8 *)&out_cmd->hdr) + scratch_size, | ||
1307 | copy_size - scratch_size, | ||
1308 | DMA_TO_DEVICE); | ||
1309 | if (dma_mapping_error(trans->dev, phys_addr)) { | ||
1310 | iwl_pcie_tfd_unmap(trans, out_meta, | ||
1311 | &txq->tfds[q->write_ptr]); | ||
1312 | idx = -ENOMEM; | ||
1313 | goto out; | ||
1314 | } | ||
1287 | 1315 | ||
1288 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); | 1316 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, |
1317 | copy_size - scratch_size, 0); | ||
1318 | } | ||
1289 | 1319 | ||
1290 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 1320 | /* map the remaining (adjusted) nocopy/dup fragments */ |
1291 | const void *data = cmd->data[i]; | 1321 | for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { |
1322 | const void *data = cmddata[i]; | ||
1292 | 1323 | ||
1293 | if (!cmd->len[i]) | 1324 | if (!cmdlen[i]) |
1294 | continue; | 1325 | continue; |
1295 | if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | | 1326 | if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | |
1296 | IWL_HCMD_DFL_DUP))) | 1327 | IWL_HCMD_DFL_DUP))) |
@@ -1298,16 +1329,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1298 | if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) | 1329 | if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) |
1299 | data = dup_buf; | 1330 | data = dup_buf; |
1300 | phys_addr = dma_map_single(trans->dev, (void *)data, | 1331 | phys_addr = dma_map_single(trans->dev, (void *)data, |
1301 | cmd->len[i], DMA_BIDIRECTIONAL); | 1332 | cmdlen[i], DMA_TO_DEVICE); |
1302 | if (dma_mapping_error(trans->dev, phys_addr)) { | 1333 | if (dma_mapping_error(trans->dev, phys_addr)) { |
1303 | iwl_pcie_tfd_unmap(trans, out_meta, | 1334 | iwl_pcie_tfd_unmap(trans, out_meta, |
1304 | &txq->tfds[q->write_ptr], | 1335 | &txq->tfds[q->write_ptr]); |
1305 | DMA_BIDIRECTIONAL); | ||
1306 | idx = -ENOMEM; | 1336 | idx = -ENOMEM; |
1307 | goto out; | 1337 | goto out; |
1308 | } | 1338 | } |
1309 | 1339 | ||
1310 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0); | 1340 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0); |
1311 | } | 1341 | } |
1312 | 1342 | ||
1313 | out_meta->flags = cmd->flags; | 1343 | out_meta->flags = cmd->flags; |
@@ -1317,8 +1347,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1317 | 1347 | ||
1318 | txq->need_update = 1; | 1348 | txq->need_update = 1; |
1319 | 1349 | ||
1320 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, | 1350 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); |
1321 | &out_cmd->hdr, copy_size); | ||
1322 | 1351 | ||
1323 | /* start timer if queue currently empty */ | 1352 | /* start timer if queue currently empty */ |
1324 | if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) | 1353 | if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) |
@@ -1377,7 +1406,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1377 | cmd = txq->entries[cmd_index].cmd; | 1406 | cmd = txq->entries[cmd_index].cmd; |
1378 | meta = &txq->entries[cmd_index].meta; | 1407 | meta = &txq->entries[cmd_index].meta; |
1379 | 1408 | ||
1380 | iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); | 1409 | iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]); |
1381 | 1410 | ||
1382 | /* Input error checking is done when commands are added to queue. */ | 1411 | /* Input error checking is done when commands are added to queue. */ |
1383 | if (meta->flags & CMD_WANT_SKB) { | 1412 | if (meta->flags & CMD_WANT_SKB) { |
@@ -1556,10 +1585,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1556 | struct iwl_cmd_meta *out_meta; | 1585 | struct iwl_cmd_meta *out_meta; |
1557 | struct iwl_txq *txq; | 1586 | struct iwl_txq *txq; |
1558 | struct iwl_queue *q; | 1587 | struct iwl_queue *q; |
1559 | dma_addr_t phys_addr = 0; | 1588 | dma_addr_t tb0_phys, tb1_phys, scratch_phys; |
1560 | dma_addr_t txcmd_phys; | 1589 | void *tb1_addr; |
1561 | dma_addr_t scratch_phys; | 1590 | u16 len, tb1_len, tb2_len; |
1562 | u16 len, firstlen, secondlen; | ||
1563 | u8 wait_write_ptr = 0; | 1591 | u8 wait_write_ptr = 0; |
1564 | __le16 fc = hdr->frame_control; | 1592 | __le16 fc = hdr->frame_control; |
1565 | u8 hdr_len = ieee80211_hdrlen(fc); | 1593 | u8 hdr_len = ieee80211_hdrlen(fc); |
@@ -1597,85 +1625,80 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1597 | cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | | 1625 | cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | |
1598 | INDEX_TO_SEQ(q->write_ptr))); | 1626 | INDEX_TO_SEQ(q->write_ptr))); |
1599 | 1627 | ||
1628 | tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr); | ||
1629 | scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + | ||
1630 | offsetof(struct iwl_tx_cmd, scratch); | ||
1631 | |||
1632 | tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); | ||
1633 | tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); | ||
1634 | |||
1600 | /* Set up first empty entry in queue's array of Tx/cmd buffers */ | 1635 | /* Set up first empty entry in queue's array of Tx/cmd buffers */ |
1601 | out_meta = &txq->entries[q->write_ptr].meta; | 1636 | out_meta = &txq->entries[q->write_ptr].meta; |
1602 | 1637 | ||
1603 | /* | 1638 | /* |
1604 | * Use the first empty entry in this queue's command buffer array | 1639 | * The second TB (tb1) points to the remainder of the TX command |
1605 | * to contain the Tx command and MAC header concatenated together | 1640 | * and the 802.11 header - dword aligned size |
1606 | * (payload data will be in another buffer). | 1641 | * (This calculation modifies the TX command, so do it before the |
1607 | * Size of this varies, due to varying MAC header length. | 1642 | * setup of the first TB) |
1608 | * If end is not dword aligned, we'll have 2 extra bytes at the end | ||
1609 | * of the MAC header (device reads on dword boundaries). | ||
1610 | * We'll tell device about this padding later. | ||
1611 | */ | 1643 | */ |
1612 | len = sizeof(struct iwl_tx_cmd) + | 1644 | len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + |
1613 | sizeof(struct iwl_cmd_header) + hdr_len; | 1645 | hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; |
1614 | firstlen = (len + 3) & ~3; | 1646 | tb1_len = (len + 3) & ~3; |
1615 | 1647 | ||
1616 | /* Tell NIC about any 2-byte padding after MAC header */ | 1648 | /* Tell NIC about any 2-byte padding after MAC header */ |
1617 | if (firstlen != len) | 1649 | if (tb1_len != len) |
1618 | tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; | 1650 | tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; |
1619 | 1651 | ||
1620 | /* Physical address of this Tx command's header (not MAC header!), | 1652 | /* The first TB points to the scratchbuf data - min_copy bytes */ |
1621 | * within command buffer array. */ | 1653 | memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr, |
1622 | txcmd_phys = dma_map_single(trans->dev, | 1654 | IWL_HCMD_SCRATCHBUF_SIZE); |
1623 | &dev_cmd->hdr, firstlen, | 1655 | iwl_pcie_txq_build_tfd(trans, txq, tb0_phys, |
1624 | DMA_BIDIRECTIONAL); | 1656 | IWL_HCMD_SCRATCHBUF_SIZE, 1); |
1625 | if (unlikely(dma_mapping_error(trans->dev, txcmd_phys))) | ||
1626 | goto out_err; | ||
1627 | dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | ||
1628 | dma_unmap_len_set(out_meta, len, firstlen); | ||
1629 | 1657 | ||
1630 | if (!ieee80211_has_morefrags(fc)) { | 1658 | /* there must be data left over for TB1 or this code must be changed */ |
1631 | txq->need_update = 1; | 1659 | BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE); |
1632 | } else { | 1660 | |
1633 | wait_write_ptr = 1; | 1661 | /* map the data for TB1 */ |
1634 | txq->need_update = 0; | 1662 | tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE; |
1635 | } | 1663 | tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); |
1664 | if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) | ||
1665 | goto out_err; | ||
1666 | iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, 0); | ||
1636 | 1667 | ||
1637 | /* Set up TFD's 2nd entry to point directly to remainder of skb, | 1668 | /* |
1638 | * if any (802.11 null frames have no payload). */ | 1669 | * Set up TFD's third entry to point directly to remainder |
1639 | secondlen = skb->len - hdr_len; | 1670 | * of skb, if any (802.11 null frames have no payload). |
1640 | if (secondlen > 0) { | 1671 | */ |
1641 | phys_addr = dma_map_single(trans->dev, skb->data + hdr_len, | 1672 | tb2_len = skb->len - hdr_len; |
1642 | secondlen, DMA_TO_DEVICE); | 1673 | if (tb2_len > 0) { |
1643 | if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { | 1674 | dma_addr_t tb2_phys = dma_map_single(trans->dev, |
1644 | dma_unmap_single(trans->dev, | 1675 | skb->data + hdr_len, |
1645 | dma_unmap_addr(out_meta, mapping), | 1676 | tb2_len, DMA_TO_DEVICE); |
1646 | dma_unmap_len(out_meta, len), | 1677 | if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { |
1647 | DMA_BIDIRECTIONAL); | 1678 | iwl_pcie_tfd_unmap(trans, out_meta, |
1679 | &txq->tfds[q->write_ptr]); | ||
1648 | goto out_err; | 1680 | goto out_err; |
1649 | } | 1681 | } |
1682 | iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, 0); | ||
1650 | } | 1683 | } |
1651 | 1684 | ||
1652 | /* Attach buffers to TFD */ | ||
1653 | iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1); | ||
1654 | if (secondlen > 0) | ||
1655 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0); | ||
1656 | |||
1657 | scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + | ||
1658 | offsetof(struct iwl_tx_cmd, scratch); | ||
1659 | |||
1660 | /* take back ownership of DMA buffer to enable update */ | ||
1661 | dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen, | ||
1662 | DMA_BIDIRECTIONAL); | ||
1663 | tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); | ||
1664 | tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); | ||
1665 | |||
1666 | /* Set up entry for this TFD in Tx byte-count array */ | 1685 | /* Set up entry for this TFD in Tx byte-count array */ |
1667 | iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); | 1686 | iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); |
1668 | 1687 | ||
1669 | dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen, | ||
1670 | DMA_BIDIRECTIONAL); | ||
1671 | |||
1672 | trace_iwlwifi_dev_tx(trans->dev, skb, | 1688 | trace_iwlwifi_dev_tx(trans->dev, skb, |
1673 | &txq->tfds[txq->q.write_ptr], | 1689 | &txq->tfds[txq->q.write_ptr], |
1674 | sizeof(struct iwl_tfd), | 1690 | sizeof(struct iwl_tfd), |
1675 | &dev_cmd->hdr, firstlen, | 1691 | &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, |
1676 | skb->data + hdr_len, secondlen); | 1692 | skb->data + hdr_len, tb2_len); |
1677 | trace_iwlwifi_dev_tx_data(trans->dev, skb, | 1693 | trace_iwlwifi_dev_tx_data(trans->dev, skb, |
1678 | skb->data + hdr_len, secondlen); | 1694 | skb->data + hdr_len, tb2_len); |
1695 | |||
1696 | if (!ieee80211_has_morefrags(fc)) { | ||
1697 | txq->need_update = 1; | ||
1698 | } else { | ||
1699 | wait_write_ptr = 1; | ||
1700 | txq->need_update = 0; | ||
1701 | } | ||
1679 | 1702 | ||
1680 | /* start timer if queue currently empty */ | 1703 | /* start timer if queue currently empty */ |
1681 | if (txq->need_update && q->read_ptr == q->write_ptr && | 1704 | if (txq->need_update && q->read_ptr == q->write_ptr && |