diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 517 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 128 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-csr.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-debugfs.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c | 6 |
11 files changed, 705 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index e77f91380a4a..3bee0f119bcd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -400,6 +400,7 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
400 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 400 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; |
401 | struct ieee80211_tx_info *info; | 401 | struct ieee80211_tx_info *info; |
402 | struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | 402 | struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; |
403 | struct ieee80211_hdr *hdr; | ||
403 | struct iwl_tx_info *txb; | 404 | struct iwl_tx_info *txb; |
404 | u32 status = le16_to_cpu(tx_resp->status.status); | 405 | u32 status = le16_to_cpu(tx_resp->status.status); |
405 | int tid; | 406 | int tid; |
@@ -426,6 +427,11 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
426 | IWLAGN_TX_RES_RA_POS; | 427 | IWLAGN_TX_RES_RA_POS; |
427 | 428 | ||
428 | spin_lock_irqsave(&priv->sta_lock, flags); | 429 | spin_lock_irqsave(&priv->sta_lock, flags); |
430 | |||
431 | hdr = (void *)txb->skb->data; | ||
432 | if (!ieee80211_is_data_qos(hdr->frame_control)) | ||
433 | priv->last_seq_ctl = tx_resp->seq_ctl; | ||
434 | |||
429 | if (txq->sched_retry) { | 435 | if (txq->sched_retry) { |
430 | const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp); | 436 | const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp); |
431 | struct iwl_ht_agg *agg; | 437 | struct iwl_ht_agg *agg; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 71487487d603..d78a4659dbff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
@@ -855,6 +855,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | |||
855 | iwl_wake_any_queue(priv, ctx); | 855 | iwl_wake_any_queue(priv, ctx); |
856 | } | 856 | } |
857 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 857 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
858 | |||
859 | if (ctx->ctxid == IWL_RXON_CTX_BSS) | ||
860 | priv->have_rekey_data = false; | ||
858 | } | 861 | } |
859 | 862 | ||
860 | iwlagn_bt_coex_rssi_monitor(priv); | 863 | iwlagn_bt_coex_rssi_monitor(priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 946d3a16e494..a895a099d086 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | |||
@@ -513,14 +513,21 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, | |||
513 | return -EIO; | 513 | return -EIO; |
514 | } | 514 | } |
515 | 515 | ||
516 | ret = iwl_verify_ucode(priv, image); | 516 | /* |
517 | if (ret) { | 517 | * This step takes a long time (60-80ms!!) and |
518 | priv->ucode_type = old_type; | 518 | * WoWLAN image should be loaded quickly, so |
519 | return ret; | 519 | * skip it for WoWLAN. |
520 | } | 520 | */ |
521 | if (ucode_type != IWL_UCODE_WOWLAN) { | ||
522 | ret = iwl_verify_ucode(priv, image); | ||
523 | if (ret) { | ||
524 | priv->ucode_type = old_type; | ||
525 | return ret; | ||
526 | } | ||
521 | 527 | ||
522 | /* delay a bit to give rfkill time to run */ | 528 | /* delay a bit to give rfkill time to run */ |
523 | msleep(5); | 529 | msleep(5); |
530 | } | ||
524 | 531 | ||
525 | ret = iwlagn_alive_notify(priv); | 532 | ret = iwlagn_alive_notify(priv); |
526 | if (ret) { | 533 | if (ret) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0bab19563394..299acb491f0d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -593,6 +593,7 @@ static void iwl_dealloc_ucode(struct iwl_priv *priv) | |||
593 | { | 593 | { |
594 | iwl_free_fw_img(priv, &priv->ucode_rt); | 594 | iwl_free_fw_img(priv, &priv->ucode_rt); |
595 | iwl_free_fw_img(priv, &priv->ucode_init); | 595 | iwl_free_fw_img(priv, &priv->ucode_init); |
596 | iwl_free_fw_img(priv, &priv->ucode_wowlan); | ||
596 | } | 597 | } |
597 | 598 | ||
598 | static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc, | 599 | static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc, |
@@ -662,8 +663,9 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) | |||
662 | } | 663 | } |
663 | 664 | ||
664 | struct iwlagn_firmware_pieces { | 665 | struct iwlagn_firmware_pieces { |
665 | const void *inst, *data, *init, *init_data; | 666 | const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; |
666 | size_t inst_size, data_size, init_size, init_data_size; | 667 | size_t inst_size, data_size, init_size, init_data_size, |
668 | wowlan_inst_size, wowlan_data_size; | ||
667 | 669 | ||
668 | u32 build; | 670 | u32 build; |
669 | 671 | ||
@@ -902,6 +904,14 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
902 | goto invalid_tlv_len; | 904 | goto invalid_tlv_len; |
903 | priv->enhance_sensitivity_table = true; | 905 | priv->enhance_sensitivity_table = true; |
904 | break; | 906 | break; |
907 | case IWL_UCODE_TLV_WOWLAN_INST: | ||
908 | pieces->wowlan_inst = tlv_data; | ||
909 | pieces->wowlan_inst_size = tlv_len; | ||
910 | break; | ||
911 | case IWL_UCODE_TLV_WOWLAN_DATA: | ||
912 | pieces->wowlan_data = tlv_data; | ||
913 | pieces->wowlan_data_size = tlv_len; | ||
914 | break; | ||
905 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: | 915 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: |
906 | if (tlv_len != sizeof(u32)) | 916 | if (tlv_len != sizeof(u32)) |
907 | goto invalid_tlv_len; | 917 | goto invalid_tlv_len; |
@@ -1096,6 +1106,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1096 | goto err_pci_alloc; | 1106 | goto err_pci_alloc; |
1097 | } | 1107 | } |
1098 | 1108 | ||
1109 | /* WoWLAN instructions and data */ | ||
1110 | if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { | ||
1111 | if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.code, | ||
1112 | pieces.wowlan_inst, | ||
1113 | pieces.wowlan_inst_size)) | ||
1114 | goto err_pci_alloc; | ||
1115 | if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.data, | ||
1116 | pieces.wowlan_data, | ||
1117 | pieces.wowlan_data_size)) | ||
1118 | goto err_pci_alloc; | ||
1119 | } | ||
1120 | |||
1099 | /* Now that we can no longer fail, copy information */ | 1121 | /* Now that we can no longer fail, copy information */ |
1100 | 1122 | ||
1101 | /* | 1123 | /* |
@@ -1698,7 +1720,7 @@ int iwl_alive_start(struct iwl_priv *priv) | |||
1698 | /* Configure Tx antenna selection based on H/W config */ | 1720 | /* Configure Tx antenna selection based on H/W config */ |
1699 | iwlagn_send_tx_ant_config(priv, priv->cfg->valid_tx_ant); | 1721 | iwlagn_send_tx_ant_config(priv, priv->cfg->valid_tx_ant); |
1700 | 1722 | ||
1701 | if (iwl_is_associated_ctx(ctx)) { | 1723 | if (iwl_is_associated_ctx(ctx) && !priv->wowlan) { |
1702 | struct iwl_rxon_cmd *active_rxon = | 1724 | struct iwl_rxon_cmd *active_rxon = |
1703 | (struct iwl_rxon_cmd *)&ctx->active; | 1725 | (struct iwl_rxon_cmd *)&ctx->active; |
1704 | /* apply any changes in staging */ | 1726 | /* apply any changes in staging */ |
@@ -1713,7 +1735,10 @@ int iwl_alive_start(struct iwl_priv *priv) | |||
1713 | iwlagn_set_rxon_chain(priv, ctx); | 1735 | iwlagn_set_rxon_chain(priv, ctx); |
1714 | } | 1736 | } |
1715 | 1737 | ||
1716 | iwl_reset_run_time_calib(priv); | 1738 | if (!priv->wowlan) { |
1739 | /* WoWLAN ucode will not reply in the same way, skip it */ | ||
1740 | iwl_reset_run_time_calib(priv); | ||
1741 | } | ||
1717 | 1742 | ||
1718 | set_bit(STATUS_READY, &priv->status); | 1743 | set_bit(STATUS_READY, &priv->status); |
1719 | 1744 | ||
@@ -2153,6 +2178,23 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, | |||
2153 | WIPHY_FLAG_DISABLE_BEACON_HINTS | | 2178 | WIPHY_FLAG_DISABLE_BEACON_HINTS | |
2154 | WIPHY_FLAG_IBSS_RSN; | 2179 | WIPHY_FLAG_IBSS_RSN; |
2155 | 2180 | ||
2181 | if (priv->ucode_wowlan.code.len && device_can_wakeup(priv->bus->dev)) { | ||
2182 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | ||
2183 | WIPHY_WOWLAN_DISCONNECT | | ||
2184 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | ||
2185 | WIPHY_WOWLAN_RFKILL_RELEASE; | ||
2186 | if (!iwlagn_mod_params.sw_crypto) | ||
2187 | hw->wiphy->wowlan.flags |= | ||
2188 | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | ||
2189 | WIPHY_WOWLAN_GTK_REKEY_FAILURE; | ||
2190 | |||
2191 | hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS; | ||
2192 | hw->wiphy->wowlan.pattern_min_len = | ||
2193 | IWLAGN_WOWLAN_MIN_PATTERN_LEN; | ||
2194 | hw->wiphy->wowlan.pattern_max_len = | ||
2195 | IWLAGN_WOWLAN_MAX_PATTERN_LEN; | ||
2196 | } | ||
2197 | |||
2156 | if (iwlagn_mod_params.power_save) | 2198 | if (iwlagn_mod_params.power_save) |
2157 | hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | 2199 | hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; |
2158 | else | 2200 | else |
@@ -2237,6 +2279,467 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) | |||
2237 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 2279 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
2238 | } | 2280 | } |
2239 | 2281 | ||
2282 | static int iwlagn_send_patterns(struct iwl_priv *priv, | ||
2283 | struct cfg80211_wowlan *wowlan) | ||
2284 | { | ||
2285 | struct iwlagn_wowlan_patterns_cmd *pattern_cmd; | ||
2286 | struct iwl_host_cmd cmd = { | ||
2287 | .id = REPLY_WOWLAN_PATTERNS, | ||
2288 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | ||
2289 | .flags = CMD_SYNC, | ||
2290 | }; | ||
2291 | int i, err; | ||
2292 | |||
2293 | if (!wowlan->n_patterns) | ||
2294 | return 0; | ||
2295 | |||
2296 | cmd.len[0] = sizeof(*pattern_cmd) + | ||
2297 | wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern); | ||
2298 | |||
2299 | pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL); | ||
2300 | if (!pattern_cmd) | ||
2301 | return -ENOMEM; | ||
2302 | |||
2303 | pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns); | ||
2304 | |||
2305 | for (i = 0; i < wowlan->n_patterns; i++) { | ||
2306 | int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); | ||
2307 | |||
2308 | memcpy(&pattern_cmd->patterns[i].mask, | ||
2309 | wowlan->patterns[i].mask, mask_len); | ||
2310 | memcpy(&pattern_cmd->patterns[i].pattern, | ||
2311 | wowlan->patterns[i].pattern, | ||
2312 | wowlan->patterns[i].pattern_len); | ||
2313 | pattern_cmd->patterns[i].mask_size = mask_len; | ||
2314 | pattern_cmd->patterns[i].pattern_size = | ||
2315 | wowlan->patterns[i].pattern_len; | ||
2316 | } | ||
2317 | |||
2318 | cmd.data[0] = pattern_cmd; | ||
2319 | err = trans_send_cmd(&priv->trans, &cmd); | ||
2320 | kfree(pattern_cmd); | ||
2321 | return err; | ||
2322 | } | ||
2323 | |||
2324 | static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, | ||
2325 | struct ieee80211_vif *vif, | ||
2326 | struct cfg80211_gtk_rekey_data *data) | ||
2327 | { | ||
2328 | struct iwl_priv *priv = hw->priv; | ||
2329 | |||
2330 | if (iwlagn_mod_params.sw_crypto) | ||
2331 | return; | ||
2332 | |||
2333 | mutex_lock(&priv->mutex); | ||
2334 | |||
2335 | if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif) | ||
2336 | goto out; | ||
2337 | |||
2338 | memcpy(priv->kek, data->kek, NL80211_KEK_LEN); | ||
2339 | memcpy(priv->kck, data->kck, NL80211_KCK_LEN); | ||
2340 | priv->replay_ctr = cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr)); | ||
2341 | priv->have_rekey_data = true; | ||
2342 | |||
2343 | out: | ||
2344 | mutex_unlock(&priv->mutex); | ||
2345 | } | ||
2346 | |||
2347 | struct wowlan_key_data { | ||
2348 | struct iwl_rxon_context *ctx; | ||
2349 | struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc; | ||
2350 | struct iwlagn_wowlan_tkip_params_cmd *tkip; | ||
2351 | const u8 *bssid; | ||
2352 | bool error, use_rsc_tsc, use_tkip; | ||
2353 | }; | ||
2354 | |||
2355 | static void iwlagn_convert_p1k(u16 *p1k, __le16 *out) | ||
2356 | { | ||
2357 | int i; | ||
2358 | |||
2359 | for (i = 0; i < IWLAGN_P1K_SIZE; i++) | ||
2360 | out[i] = cpu_to_le16(p1k[i]); | ||
2361 | } | ||
2362 | |||
2363 | static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, | ||
2364 | struct ieee80211_vif *vif, | ||
2365 | struct ieee80211_sta *sta, | ||
2366 | struct ieee80211_key_conf *key, | ||
2367 | void *_data) | ||
2368 | { | ||
2369 | struct iwl_priv *priv = hw->priv; | ||
2370 | struct wowlan_key_data *data = _data; | ||
2371 | struct iwl_rxon_context *ctx = data->ctx; | ||
2372 | struct aes_sc *aes_sc, *aes_tx_sc = NULL; | ||
2373 | struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL; | ||
2374 | struct iwlagn_p1k_cache *rx_p1ks; | ||
2375 | u8 *rx_mic_key; | ||
2376 | struct ieee80211_key_seq seq; | ||
2377 | u32 cur_rx_iv32 = 0; | ||
2378 | u16 p1k[IWLAGN_P1K_SIZE]; | ||
2379 | int ret, i; | ||
2380 | |||
2381 | mutex_lock(&priv->mutex); | ||
2382 | |||
2383 | if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
2384 | key->cipher == WLAN_CIPHER_SUITE_WEP104) && | ||
2385 | !sta && !ctx->key_mapping_keys) | ||
2386 | ret = iwl_set_default_wep_key(priv, ctx, key); | ||
2387 | else | ||
2388 | ret = iwl_set_dynamic_key(priv, ctx, key, sta); | ||
2389 | |||
2390 | if (ret) { | ||
2391 | IWL_ERR(priv, "Error setting key during suspend!\n"); | ||
2392 | data->error = true; | ||
2393 | } | ||
2394 | |||
2395 | switch (key->cipher) { | ||
2396 | case WLAN_CIPHER_SUITE_TKIP: | ||
2397 | if (sta) { | ||
2398 | tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc; | ||
2399 | tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc; | ||
2400 | |||
2401 | rx_p1ks = data->tkip->rx_uni; | ||
2402 | |||
2403 | ieee80211_get_key_tx_seq(key, &seq); | ||
2404 | tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16); | ||
2405 | tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32); | ||
2406 | |||
2407 | ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k); | ||
2408 | iwlagn_convert_p1k(p1k, data->tkip->tx.p1k); | ||
2409 | |||
2410 | memcpy(data->tkip->mic_keys.tx, | ||
2411 | &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], | ||
2412 | IWLAGN_MIC_KEY_SIZE); | ||
2413 | |||
2414 | rx_mic_key = data->tkip->mic_keys.rx_unicast; | ||
2415 | } else { | ||
2416 | tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc; | ||
2417 | rx_p1ks = data->tkip->rx_multi; | ||
2418 | rx_mic_key = data->tkip->mic_keys.rx_mcast; | ||
2419 | } | ||
2420 | |||
2421 | /* | ||
2422 | * For non-QoS this relies on the fact that both the uCode and | ||
2423 | * mac80211 use TID 0 (as they need to to avoid replay attacks) | ||
2424 | * for checking the IV in the frames. | ||
2425 | */ | ||
2426 | for (i = 0; i < IWLAGN_NUM_RSC; i++) { | ||
2427 | ieee80211_get_key_rx_seq(key, i, &seq); | ||
2428 | tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16); | ||
2429 | tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); | ||
2430 | /* wrapping isn't allowed, AP must rekey */ | ||
2431 | if (seq.tkip.iv32 > cur_rx_iv32) | ||
2432 | cur_rx_iv32 = seq.tkip.iv32; | ||
2433 | } | ||
2434 | |||
2435 | ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k); | ||
2436 | iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k); | ||
2437 | ieee80211_get_tkip_rx_p1k(key, data->bssid, | ||
2438 | cur_rx_iv32 + 1, p1k); | ||
2439 | iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k); | ||
2440 | |||
2441 | memcpy(rx_mic_key, | ||
2442 | &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], | ||
2443 | IWLAGN_MIC_KEY_SIZE); | ||
2444 | |||
2445 | data->use_tkip = true; | ||
2446 | data->use_rsc_tsc = true; | ||
2447 | break; | ||
2448 | case WLAN_CIPHER_SUITE_CCMP: | ||
2449 | if (sta) { | ||
2450 | u8 *pn = seq.ccmp.pn; | ||
2451 | |||
2452 | aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc; | ||
2453 | aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc; | ||
2454 | |||
2455 | ieee80211_get_key_tx_seq(key, &seq); | ||
2456 | aes_tx_sc->pn = cpu_to_le64( | ||
2457 | (u64)pn[5] | | ||
2458 | ((u64)pn[4] << 8) | | ||
2459 | ((u64)pn[3] << 16) | | ||
2460 | ((u64)pn[2] << 24) | | ||
2461 | ((u64)pn[1] << 32) | | ||
2462 | ((u64)pn[0] << 40)); | ||
2463 | } else | ||
2464 | aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc; | ||
2465 | |||
2466 | /* | ||
2467 | * For non-QoS this relies on the fact that both the uCode and | ||
2468 | * mac80211 use TID 0 for checking the IV in the frames. | ||
2469 | */ | ||
2470 | for (i = 0; i < IWLAGN_NUM_RSC; i++) { | ||
2471 | u8 *pn = seq.ccmp.pn; | ||
2472 | |||
2473 | ieee80211_get_key_rx_seq(key, i, &seq); | ||
2474 | aes_sc->pn = cpu_to_le64( | ||
2475 | (u64)pn[5] | | ||
2476 | ((u64)pn[4] << 8) | | ||
2477 | ((u64)pn[3] << 16) | | ||
2478 | ((u64)pn[2] << 24) | | ||
2479 | ((u64)pn[1] << 32) | | ||
2480 | ((u64)pn[0] << 40)); | ||
2481 | } | ||
2482 | data->use_rsc_tsc = true; | ||
2483 | break; | ||
2484 | } | ||
2485 | |||
2486 | mutex_unlock(&priv->mutex); | ||
2487 | } | ||
2488 | |||
2489 | static int iwlagn_mac_suspend(struct ieee80211_hw *hw, | ||
2490 | struct cfg80211_wowlan *wowlan) | ||
2491 | { | ||
2492 | struct iwl_priv *priv = hw->priv; | ||
2493 | struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd; | ||
2494 | struct iwl_rxon_cmd rxon; | ||
2495 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
2496 | struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd; | ||
2497 | struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {}; | ||
2498 | struct wowlan_key_data key_data = { | ||
2499 | .ctx = ctx, | ||
2500 | .bssid = ctx->active.bssid_addr, | ||
2501 | .use_rsc_tsc = false, | ||
2502 | .tkip = &tkip_cmd, | ||
2503 | .use_tkip = false, | ||
2504 | }; | ||
2505 | int ret, i; | ||
2506 | u16 seq; | ||
2507 | |||
2508 | if (WARN_ON(!wowlan)) | ||
2509 | return -EINVAL; | ||
2510 | |||
2511 | mutex_lock(&priv->mutex); | ||
2512 | |||
2513 | /* Don't attempt WoWLAN when not associated, tear down instead. */ | ||
2514 | if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION || | ||
2515 | !iwl_is_associated_ctx(ctx)) { | ||
2516 | ret = 1; | ||
2517 | goto out; | ||
2518 | } | ||
2519 | |||
2520 | key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); | ||
2521 | if (!key_data.rsc_tsc) { | ||
2522 | ret = -ENOMEM; | ||
2523 | goto out; | ||
2524 | } | ||
2525 | |||
2526 | memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd)); | ||
2527 | |||
2528 | /* | ||
2529 | * We know the last used seqno, and the uCode expects to know that | ||
2530 | * one, it will increment before TX. | ||
2531 | */ | ||
2532 | seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ; | ||
2533 | wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq); | ||
2534 | |||
2535 | /* | ||
2536 | * For QoS counters, we store the one to use next, so subtract 0x10 | ||
2537 | * since the uCode will add 0x10 before using the value. | ||
2538 | */ | ||
2539 | for (i = 0; i < 8; i++) { | ||
2540 | seq = priv->stations[IWL_AP_ID].tid[i].seq_number; | ||
2541 | seq -= 0x10; | ||
2542 | wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq); | ||
2543 | } | ||
2544 | |||
2545 | if (wowlan->disconnect) | ||
2546 | wakeup_filter_cmd.enabled |= | ||
2547 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS | | ||
2548 | IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE); | ||
2549 | if (wowlan->magic_pkt) | ||
2550 | wakeup_filter_cmd.enabled |= | ||
2551 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET); | ||
2552 | if (wowlan->gtk_rekey_failure) | ||
2553 | wakeup_filter_cmd.enabled |= | ||
2554 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL); | ||
2555 | if (wowlan->eap_identity_req) | ||
2556 | wakeup_filter_cmd.enabled |= | ||
2557 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ); | ||
2558 | if (wowlan->four_way_handshake) | ||
2559 | wakeup_filter_cmd.enabled |= | ||
2560 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE); | ||
2561 | if (wowlan->rfkill_release) | ||
2562 | wakeup_filter_cmd.enabled |= | ||
2563 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_RFKILL); | ||
2564 | if (wowlan->n_patterns) | ||
2565 | wakeup_filter_cmd.enabled |= | ||
2566 | cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH); | ||
2567 | |||
2568 | iwl_scan_cancel_timeout(priv, 200); | ||
2569 | |||
2570 | memcpy(&rxon, &ctx->active, sizeof(rxon)); | ||
2571 | |||
2572 | trans_stop_device(&priv->trans); | ||
2573 | |||
2574 | priv->wowlan = true; | ||
2575 | |||
2576 | ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan, | ||
2577 | IWL_UCODE_WOWLAN); | ||
2578 | if (ret) | ||
2579 | goto error; | ||
2580 | |||
2581 | /* now configure WoWLAN ucode */ | ||
2582 | ret = iwl_alive_start(priv); | ||
2583 | if (ret) | ||
2584 | goto error; | ||
2585 | |||
2586 | memcpy(&ctx->staging, &rxon, sizeof(rxon)); | ||
2587 | ret = iwlagn_commit_rxon(priv, ctx); | ||
2588 | if (ret) | ||
2589 | goto error; | ||
2590 | |||
2591 | ret = iwl_power_update_mode(priv, true); | ||
2592 | if (ret) | ||
2593 | goto error; | ||
2594 | |||
2595 | if (!iwlagn_mod_params.sw_crypto) { | ||
2596 | /* mark all keys clear */ | ||
2597 | priv->ucode_key_table = 0; | ||
2598 | ctx->key_mapping_keys = 0; | ||
2599 | |||
2600 | /* | ||
2601 | * This needs to be unlocked due to lock ordering | ||
2602 | * constraints. Since we're in the suspend path | ||
2603 | * that isn't really a problem though. | ||
2604 | */ | ||
2605 | mutex_unlock(&priv->mutex); | ||
2606 | ieee80211_iter_keys(priv->hw, ctx->vif, | ||
2607 | iwlagn_wowlan_program_keys, | ||
2608 | &key_data); | ||
2609 | mutex_lock(&priv->mutex); | ||
2610 | if (key_data.error) { | ||
2611 | ret = -EIO; | ||
2612 | goto error; | ||
2613 | } | ||
2614 | |||
2615 | if (key_data.use_rsc_tsc) { | ||
2616 | struct iwl_host_cmd rsc_tsc_cmd = { | ||
2617 | .id = REPLY_WOWLAN_TSC_RSC_PARAMS, | ||
2618 | .flags = CMD_SYNC, | ||
2619 | .data[0] = key_data.rsc_tsc, | ||
2620 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | ||
2621 | .len[0] = sizeof(*key_data.rsc_tsc), | ||
2622 | }; | ||
2623 | |||
2624 | ret = trans_send_cmd(&priv->trans, &rsc_tsc_cmd); | ||
2625 | if (ret) | ||
2626 | goto error; | ||
2627 | } | ||
2628 | |||
2629 | if (key_data.use_tkip) { | ||
2630 | ret = trans_send_cmd_pdu(&priv->trans, | ||
2631 | REPLY_WOWLAN_TKIP_PARAMS, | ||
2632 | CMD_SYNC, sizeof(tkip_cmd), | ||
2633 | &tkip_cmd); | ||
2634 | if (ret) | ||
2635 | goto error; | ||
2636 | } | ||
2637 | |||
2638 | if (priv->have_rekey_data) { | ||
2639 | memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); | ||
2640 | memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN); | ||
2641 | kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN); | ||
2642 | memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN); | ||
2643 | kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN); | ||
2644 | kek_kck_cmd.replay_ctr = priv->replay_ctr; | ||
2645 | |||
2646 | ret = trans_send_cmd_pdu(&priv->trans, | ||
2647 | REPLY_WOWLAN_KEK_KCK_MATERIAL, | ||
2648 | CMD_SYNC, sizeof(kek_kck_cmd), | ||
2649 | &kek_kck_cmd); | ||
2650 | if (ret) | ||
2651 | goto error; | ||
2652 | } | ||
2653 | } | ||
2654 | |||
2655 | ret = trans_send_cmd_pdu(&priv->trans, REPLY_WOWLAN_WAKEUP_FILTER, | ||
2656 | CMD_SYNC, sizeof(wakeup_filter_cmd), | ||
2657 | &wakeup_filter_cmd); | ||
2658 | if (ret) | ||
2659 | goto error; | ||
2660 | |||
2661 | ret = iwlagn_send_patterns(priv, wowlan); | ||
2662 | if (ret) | ||
2663 | goto error; | ||
2664 | |||
2665 | device_set_wakeup_enable(priv->bus->dev, true); | ||
2666 | |||
2667 | /* Now let the ucode operate on its own */ | ||
2668 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
2669 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
2670 | |||
2671 | goto out; | ||
2672 | |||
2673 | error: | ||
2674 | priv->wowlan = false; | ||
2675 | iwlagn_prepare_restart(priv); | ||
2676 | ieee80211_restart_hw(priv->hw); | ||
2677 | out: | ||
2678 | mutex_unlock(&priv->mutex); | ||
2679 | kfree(key_data.rsc_tsc); | ||
2680 | return ret; | ||
2681 | } | ||
2682 | |||
2683 | static int iwlagn_mac_resume(struct ieee80211_hw *hw) | ||
2684 | { | ||
2685 | struct iwl_priv *priv = hw->priv; | ||
2686 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
2687 | struct ieee80211_vif *vif; | ||
2688 | unsigned long flags; | ||
2689 | u32 base, status = 0xffffffff; | ||
2690 | int ret = -EIO; | ||
2691 | |||
2692 | mutex_lock(&priv->mutex); | ||
2693 | |||
2694 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | ||
2695 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
2696 | |||
2697 | base = priv->device_pointers.error_event_table; | ||
2698 | if (iwlagn_hw_valid_rtc_data_addr(base)) { | ||
2699 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
2700 | ret = iwl_grab_nic_access_silent(priv); | ||
2701 | if (ret == 0) { | ||
2702 | iwl_write32(priv, HBUS_TARG_MEM_RADDR, base); | ||
2703 | status = iwl_read32(priv, HBUS_TARG_MEM_RDAT); | ||
2704 | iwl_release_nic_access(priv); | ||
2705 | } | ||
2706 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
2707 | |||
2708 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
2709 | if (ret == 0) { | ||
2710 | if (!priv->wowlan_sram) | ||
2711 | priv->wowlan_sram = | ||
2712 | kzalloc(priv->ucode_wowlan.data.len, | ||
2713 | GFP_KERNEL); | ||
2714 | |||
2715 | if (priv->wowlan_sram) | ||
2716 | _iwl_read_targ_mem_words( | ||
2717 | priv, 0x800000, priv->wowlan_sram, | ||
2718 | priv->ucode_wowlan.data.len / 4); | ||
2719 | } | ||
2720 | #endif | ||
2721 | } | ||
2722 | |||
2723 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ | ||
2724 | vif = ctx->vif; | ||
2725 | |||
2726 | priv->wowlan = false; | ||
2727 | |||
2728 | device_set_wakeup_enable(priv->bus->dev, false); | ||
2729 | |||
2730 | iwlagn_prepare_restart(priv); | ||
2731 | |||
2732 | memset((void *)&ctx->active, 0, sizeof(ctx->active)); | ||
2733 | iwl_connection_init_rx_config(priv, ctx); | ||
2734 | iwlagn_set_rxon_chain(priv, ctx); | ||
2735 | |||
2736 | mutex_unlock(&priv->mutex); | ||
2737 | |||
2738 | ieee80211_resume_disconnect(vif); | ||
2739 | |||
2740 | return 1; | ||
2741 | } | ||
2742 | |||
2240 | static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 2743 | static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
2241 | { | 2744 | { |
2242 | struct iwl_priv *priv = hw->priv; | 2745 | struct iwl_priv *priv = hw->priv; |
@@ -2926,6 +3429,9 @@ static void iwl_uninit_drv(struct iwl_priv *priv) | |||
2926 | iwl_free_channel_map(priv); | 3429 | iwl_free_channel_map(priv); |
2927 | kfree(priv->scan_cmd); | 3430 | kfree(priv->scan_cmd); |
2928 | kfree(priv->beacon_cmd); | 3431 | kfree(priv->beacon_cmd); |
3432 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
3433 | kfree(priv->wowlan_sram); | ||
3434 | #endif | ||
2929 | } | 3435 | } |
2930 | 3436 | ||
2931 | static void iwl_mac_rssi_callback(struct ieee80211_hw *hw, | 3437 | static void iwl_mac_rssi_callback(struct ieee80211_hw *hw, |
@@ -2955,6 +3461,8 @@ struct ieee80211_ops iwlagn_hw_ops = { | |||
2955 | .tx = iwlagn_mac_tx, | 3461 | .tx = iwlagn_mac_tx, |
2956 | .start = iwlagn_mac_start, | 3462 | .start = iwlagn_mac_start, |
2957 | .stop = iwlagn_mac_stop, | 3463 | .stop = iwlagn_mac_stop, |
3464 | .suspend = iwlagn_mac_suspend, | ||
3465 | .resume = iwlagn_mac_resume, | ||
2958 | .add_interface = iwl_mac_add_interface, | 3466 | .add_interface = iwl_mac_add_interface, |
2959 | .remove_interface = iwl_mac_remove_interface, | 3467 | .remove_interface = iwl_mac_remove_interface, |
2960 | .change_interface = iwl_mac_change_interface, | 3468 | .change_interface = iwl_mac_change_interface, |
@@ -2962,6 +3470,7 @@ struct ieee80211_ops iwlagn_hw_ops = { | |||
2962 | .configure_filter = iwlagn_configure_filter, | 3470 | .configure_filter = iwlagn_configure_filter, |
2963 | .set_key = iwlagn_mac_set_key, | 3471 | .set_key = iwlagn_mac_set_key, |
2964 | .update_tkip_key = iwlagn_mac_update_tkip_key, | 3472 | .update_tkip_key = iwlagn_mac_update_tkip_key, |
3473 | .set_rekey_data = iwlagn_mac_set_rekey_data, | ||
2965 | .conf_tx = iwl_mac_conf_tx, | 3474 | .conf_tx = iwl_mac_conf_tx, |
2966 | .bss_info_changed = iwlagn_bss_info_changed, | 3475 | .bss_info_changed = iwlagn_bss_info_changed, |
2967 | .ampdu_action = iwlagn_mac_ampdu_action, | 3476 | .ampdu_action = iwlagn_mac_ampdu_action, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index b58985373a71..5769ca5cebca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -188,6 +188,13 @@ enum { | |||
188 | REPLY_WIPAN_NOA_NOTIFICATION = 0xbc, | 188 | REPLY_WIPAN_NOA_NOTIFICATION = 0xbc, |
189 | REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd, | 189 | REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd, |
190 | 190 | ||
191 | REPLY_WOWLAN_PATTERNS = 0xe0, | ||
192 | REPLY_WOWLAN_WAKEUP_FILTER = 0xe1, | ||
193 | REPLY_WOWLAN_TSC_RSC_PARAMS = 0xe2, | ||
194 | REPLY_WOWLAN_TKIP_PARAMS = 0xe3, | ||
195 | REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4, | ||
196 | REPLY_WOWLAN_GET_STATUS = 0xe5, | ||
197 | |||
191 | REPLY_MAX = 0xff | 198 | REPLY_MAX = 0xff |
192 | }; | 199 | }; |
193 | 200 | ||
@@ -3764,6 +3771,127 @@ struct iwl_bt_coex_prot_env_cmd { | |||
3764 | u8 reserved[2]; | 3771 | u8 reserved[2]; |
3765 | } __attribute__((packed)); | 3772 | } __attribute__((packed)); |
3766 | 3773 | ||
3774 | /* | ||
3775 | * REPLY_WOWLAN_PATTERNS | ||
3776 | */ | ||
3777 | #define IWLAGN_WOWLAN_MIN_PATTERN_LEN 16 | ||
3778 | #define IWLAGN_WOWLAN_MAX_PATTERN_LEN 128 | ||
3779 | |||
3780 | struct iwlagn_wowlan_pattern { | ||
3781 | u8 mask[IWLAGN_WOWLAN_MAX_PATTERN_LEN / 8]; | ||
3782 | u8 pattern[IWLAGN_WOWLAN_MAX_PATTERN_LEN]; | ||
3783 | u8 mask_size; | ||
3784 | u8 pattern_size; | ||
3785 | __le16 reserved; | ||
3786 | } __packed; | ||
3787 | |||
3788 | #define IWLAGN_WOWLAN_MAX_PATTERNS 20 | ||
3789 | |||
3790 | struct iwlagn_wowlan_patterns_cmd { | ||
3791 | __le32 n_patterns; | ||
3792 | struct iwlagn_wowlan_pattern patterns[]; | ||
3793 | } __packed; | ||
3794 | |||
3795 | /* | ||
3796 | * REPLY_WOWLAN_WAKEUP_FILTER | ||
3797 | */ | ||
3798 | enum iwlagn_wowlan_wakeup_filters { | ||
3799 | IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0), | ||
3800 | IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH = BIT(1), | ||
3801 | IWLAGN_WOWLAN_WAKEUP_BEACON_MISS = BIT(2), | ||
3802 | IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE = BIT(3), | ||
3803 | IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL = BIT(4), | ||
3804 | IWLAGN_WOWLAN_WAKEUP_RFKILL = BIT(5), | ||
3805 | IWLAGN_WOWLAN_WAKEUP_UCODE_ERROR = BIT(6), | ||
3806 | IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ = BIT(7), | ||
3807 | IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE = BIT(8), | ||
3808 | IWLAGN_WOWLAN_WAKEUP_ALWAYS = BIT(9), | ||
3809 | IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT = BIT(10), | ||
3810 | }; | ||
3811 | |||
3812 | struct iwlagn_wowlan_wakeup_filter_cmd { | ||
3813 | __le32 enabled; | ||
3814 | __le16 non_qos_seq; | ||
3815 | u8 min_sleep_seconds; | ||
3816 | u8 reserved; | ||
3817 | __le16 qos_seq[8]; | ||
3818 | }; | ||
3819 | |||
3820 | /* | ||
3821 | * REPLY_WOWLAN_TSC_RSC_PARAMS | ||
3822 | */ | ||
3823 | #define IWLAGN_NUM_RSC 16 | ||
3824 | |||
3825 | struct tkip_sc { | ||
3826 | __le16 iv16; | ||
3827 | __le16 pad; | ||
3828 | __le32 iv32; | ||
3829 | } __packed; | ||
3830 | |||
3831 | struct iwlagn_tkip_rsc_tsc { | ||
3832 | struct tkip_sc unicast_rsc[IWLAGN_NUM_RSC]; | ||
3833 | struct tkip_sc multicast_rsc[IWLAGN_NUM_RSC]; | ||
3834 | struct tkip_sc tsc; | ||
3835 | } __packed; | ||
3836 | |||
3837 | struct aes_sc { | ||
3838 | __le64 pn; | ||
3839 | } __packed; | ||
3840 | |||
3841 | struct iwlagn_aes_rsc_tsc { | ||
3842 | struct aes_sc unicast_rsc[IWLAGN_NUM_RSC]; | ||
3843 | struct aes_sc multicast_rsc[IWLAGN_NUM_RSC]; | ||
3844 | struct aes_sc tsc; | ||
3845 | } __packed; | ||
3846 | |||
3847 | union iwlagn_all_tsc_rsc { | ||
3848 | struct iwlagn_tkip_rsc_tsc tkip; | ||
3849 | struct iwlagn_aes_rsc_tsc aes; | ||
3850 | }; | ||
3851 | |||
3852 | struct iwlagn_wowlan_rsc_tsc_params_cmd { | ||
3853 | union iwlagn_all_tsc_rsc all_tsc_rsc; | ||
3854 | } __packed; | ||
3855 | |||
3856 | /* | ||
3857 | * REPLY_WOWLAN_TKIP_PARAMS | ||
3858 | */ | ||
3859 | #define IWLAGN_MIC_KEY_SIZE 8 | ||
3860 | #define IWLAGN_P1K_SIZE 5 | ||
3861 | struct iwlagn_mic_keys { | ||
3862 | u8 tx[IWLAGN_MIC_KEY_SIZE]; | ||
3863 | u8 rx_unicast[IWLAGN_MIC_KEY_SIZE]; | ||
3864 | u8 rx_mcast[IWLAGN_MIC_KEY_SIZE]; | ||
3865 | } __packed; | ||
3866 | |||
3867 | struct iwlagn_p1k_cache { | ||
3868 | __le16 p1k[IWLAGN_P1K_SIZE]; | ||
3869 | } __packed; | ||
3870 | |||
3871 | #define IWLAGN_NUM_RX_P1K_CACHE 2 | ||
3872 | |||
3873 | struct iwlagn_wowlan_tkip_params_cmd { | ||
3874 | struct iwlagn_mic_keys mic_keys; | ||
3875 | struct iwlagn_p1k_cache tx; | ||
3876 | struct iwlagn_p1k_cache rx_uni[IWLAGN_NUM_RX_P1K_CACHE]; | ||
3877 | struct iwlagn_p1k_cache rx_multi[IWLAGN_NUM_RX_P1K_CACHE]; | ||
3878 | } __packed; | ||
3879 | |||
3880 | /* | ||
3881 | * REPLY_WOWLAN_KEK_KCK_MATERIAL | ||
3882 | */ | ||
3883 | |||
3884 | #define IWLAGN_KCK_MAX_SIZE 32 | ||
3885 | #define IWLAGN_KEK_MAX_SIZE 32 | ||
3886 | |||
3887 | struct iwlagn_wowlan_kek_kck_material_cmd { | ||
3888 | u8 kck[IWLAGN_KCK_MAX_SIZE]; | ||
3889 | u8 kek[IWLAGN_KEK_MAX_SIZE]; | ||
3890 | __le16 kck_len; | ||
3891 | __le16 kek_len; | ||
3892 | __le64 replay_ctr; | ||
3893 | } __packed; | ||
3894 | |||
3767 | /****************************************************************************** | 3895 | /****************************************************************************** |
3768 | * (13) | 3896 | * (13) |
3769 | * Union of all expected notifications/responses: | 3897 | * Union of all expected notifications/responses: |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9b9f462ea0ff..2f42547622d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1903,8 +1903,12 @@ int iwl_suspend(struct iwl_priv *priv) | |||
1903 | * first but since iwl_mac_stop() has no knowledge of who the caller is, | 1903 | * first but since iwl_mac_stop() has no knowledge of who the caller is, |
1904 | * it will not call apm_ops.stop() to stop the DMA operation. | 1904 | * it will not call apm_ops.stop() to stop the DMA operation. |
1905 | * Calling apm_ops.stop here to make sure we stop the DMA. | 1905 | * Calling apm_ops.stop here to make sure we stop the DMA. |
1906 | * | ||
1907 | * But of course ... if we have configured WoWLAN then we did other | ||
1908 | * things already :-) | ||
1906 | */ | 1909 | */ |
1907 | iwl_apm_stop(priv); | 1910 | if (!priv->wowlan) |
1911 | iwl_apm_stop(priv); | ||
1908 | 1912 | ||
1909 | return 0; | 1913 | return 0; |
1910 | } | 1914 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 5ab90ba7a024..d6dbb0423045 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -351,6 +351,7 @@ | |||
351 | #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) | 351 | #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) |
352 | #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) | 352 | #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) |
353 | #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) | 353 | #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) |
354 | #define CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE (0x00000020) | ||
354 | 355 | ||
355 | /* GP Driver */ | 356 | /* GP Driver */ |
356 | #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003) | 357 | #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 17aebf08dff8..ec1485b2d3fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -322,6 +322,19 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, | |||
322 | return count; | 322 | return count; |
323 | } | 323 | } |
324 | 324 | ||
325 | static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file, | ||
326 | char __user *user_buf, | ||
327 | size_t count, loff_t *ppos) | ||
328 | { | ||
329 | struct iwl_priv *priv = file->private_data; | ||
330 | |||
331 | if (!priv->wowlan_sram) | ||
332 | return -ENODATA; | ||
333 | |||
334 | return simple_read_from_buffer(user_buf, count, ppos, | ||
335 | priv->wowlan_sram, | ||
336 | priv->ucode_wowlan.data.len); | ||
337 | } | ||
325 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | 338 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, |
326 | size_t count, loff_t *ppos) | 339 | size_t count, loff_t *ppos) |
327 | { | 340 | { |
@@ -856,6 +869,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, | |||
856 | } | 869 | } |
857 | 870 | ||
858 | DEBUGFS_READ_WRITE_FILE_OPS(sram); | 871 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
872 | DEBUGFS_READ_FILE_OPS(wowlan_sram); | ||
859 | DEBUGFS_READ_WRITE_FILE_OPS(log_event); | 873 | DEBUGFS_READ_WRITE_FILE_OPS(log_event); |
860 | DEBUGFS_READ_FILE_OPS(nvm); | 874 | DEBUGFS_READ_FILE_OPS(nvm); |
861 | DEBUGFS_READ_FILE_OPS(stations); | 875 | DEBUGFS_READ_FILE_OPS(stations); |
@@ -2667,6 +2681,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
2667 | 2681 | ||
2668 | DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); | 2682 | DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); |
2669 | DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); | 2683 | DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); |
2684 | DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR); | ||
2670 | DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR); | 2685 | DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR); |
2671 | DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); | 2686 | DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); |
2672 | DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); | 2687 | DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c27380440b66..fc2387342456 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -551,7 +551,8 @@ enum iwl_ucode_tlv_type { | |||
551 | IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, | 551 | IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, |
552 | IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, | 552 | IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, |
553 | IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, | 553 | IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, |
554 | /* 16 and 17 reserved for future use */ | 554 | IWL_UCODE_TLV_WOWLAN_INST = 16, |
555 | IWL_UCODE_TLV_WOWLAN_DATA = 17, | ||
555 | IWL_UCODE_TLV_FLAGS = 18, | 556 | IWL_UCODE_TLV_FLAGS = 18, |
556 | }; | 557 | }; |
557 | 558 | ||
@@ -1284,6 +1285,7 @@ struct iwl_priv { | |||
1284 | 1285 | ||
1285 | struct fw_img ucode_rt; | 1286 | struct fw_img ucode_rt; |
1286 | struct fw_img ucode_init; | 1287 | struct fw_img ucode_init; |
1288 | struct fw_img ucode_wowlan; | ||
1287 | 1289 | ||
1288 | enum iwlagn_ucode_type ucode_type; | 1290 | enum iwlagn_ucode_type ucode_type; |
1289 | u8 ucode_write_complete; /* the image write is complete */ | 1291 | u8 ucode_write_complete; /* the image write is complete */ |
@@ -1356,6 +1358,8 @@ struct iwl_priv { | |||
1356 | 1358 | ||
1357 | u8 mac80211_registered; | 1359 | u8 mac80211_registered; |
1358 | 1360 | ||
1361 | bool wowlan; | ||
1362 | |||
1359 | /* eeprom -- this is in the card's little endian byte order */ | 1363 | /* eeprom -- this is in the card's little endian byte order */ |
1360 | u8 *eeprom; | 1364 | u8 *eeprom; |
1361 | int nvm_device_type; | 1365 | int nvm_device_type; |
@@ -1508,6 +1512,7 @@ struct iwl_priv { | |||
1508 | struct dentry *debugfs_dir; | 1512 | struct dentry *debugfs_dir; |
1509 | u32 dbgfs_sram_offset, dbgfs_sram_len; | 1513 | u32 dbgfs_sram_offset, dbgfs_sram_len; |
1510 | bool disable_ht40; | 1514 | bool disable_ht40; |
1515 | void *wowlan_sram; | ||
1511 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 1516 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
1512 | 1517 | ||
1513 | struct work_struct txpower_work; | 1518 | struct work_struct txpower_work; |
@@ -1528,6 +1533,11 @@ struct iwl_priv { | |||
1528 | u32 tm_fixed_rate; | 1533 | u32 tm_fixed_rate; |
1529 | #endif | 1534 | #endif |
1530 | 1535 | ||
1536 | /* WoWLAN GTK rekey data */ | ||
1537 | u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; | ||
1538 | __le64 replay_ctr; | ||
1539 | __le16 last_seq_ctl; | ||
1540 | bool have_rekey_data; | ||
1531 | }; /*iwl_priv */ | 1541 | }; /*iwl_priv */ |
1532 | 1542 | ||
1533 | static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) | 1543 | static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index de4f33304edb..3ec619c6881c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -347,7 +347,9 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, | |||
347 | 347 | ||
348 | dtimper = priv->hw->conf.ps_dtim_period ?: 1; | 348 | dtimper = priv->hw->conf.ps_dtim_period ?: 1; |
349 | 349 | ||
350 | if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) | 350 | if (priv->wowlan) |
351 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); | ||
352 | else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) | ||
351 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); | 353 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); |
352 | else if (iwl_tt_is_low_power_state(priv)) { | 354 | else if (iwl_tt_is_low_power_state(priv)) { |
353 | /* in thermal throttling low power state */ | 355 | /* in thermal throttling low power state */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c index 27f78fed2ec2..a6b2b1db0b1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c | |||
@@ -866,6 +866,12 @@ const char *get_cmd_string(u8 cmd) | |||
866 | IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); | 866 | IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); |
867 | IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); | 867 | IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); |
868 | IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); | 868 | IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); |
869 | IWL_CMD(REPLY_WOWLAN_PATTERNS); | ||
870 | IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER); | ||
871 | IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS); | ||
872 | IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); | ||
873 | IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); | ||
874 | IWL_CMD(REPLY_WOWLAN_GET_STATUS); | ||
869 | default: | 875 | default: |
870 | return "UNKNOWN"; | 876 | return "UNKNOWN"; |
871 | 877 | ||