diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b1aad306efa9..312099099ed3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -34,9 +34,6 @@ | |||
34 | #include "iwl-core.h" | 34 | #include "iwl-core.h" |
35 | #include "iwl-sta.h" | 35 | #include "iwl-sta.h" |
36 | 36 | ||
37 | #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ | ||
38 | #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ | ||
39 | |||
40 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | 37 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) |
41 | { | 38 | { |
42 | int i; | 39 | int i; |
@@ -495,37 +492,102 @@ out: | |||
495 | } | 492 | } |
496 | 493 | ||
497 | /** | 494 | /** |
498 | * iwl_clear_stations_table - Clear the driver's station table | 495 | * iwl_clear_ucode_stations() - clear entire station table driver and/or ucode |
499 | * | 496 | * @priv: |
500 | * NOTE: This does not clear or otherwise alter the device's station table. | 497 | * @force: If set then the uCode station table needs to be cleared here. If |
498 | * not set then the uCode station table has already been cleared, | ||
499 | * for example after sending it a RXON command without ASSOC bit | ||
500 | * set, and we just need to change driver state here. | ||
501 | */ | 501 | */ |
502 | void iwl_clear_stations_table(struct iwl_priv *priv) | 502 | void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force) |
503 | { | 503 | { |
504 | unsigned long flags; | ||
505 | int i; | 504 | int i; |
505 | unsigned long flags_spin; | ||
506 | bool cleared = false; | ||
507 | |||
508 | IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver%s\n", | ||
509 | force ? " and ucode" : ""); | ||
510 | |||
511 | if (force) { | ||
512 | if (!iwl_is_ready(priv)) { | ||
513 | /* | ||
514 | * If device is not ready at this point the station | ||
515 | * table is likely already empty (uCode not ready | ||
516 | * to receive station requests) or will soon be | ||
517 | * due to interface going down. | ||
518 | */ | ||
519 | IWL_DEBUG_INFO(priv, "Unable to remove stations from device - device not ready\n"); | ||
520 | } else { | ||
521 | iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL); | ||
522 | } | ||
523 | } | ||
506 | 524 | ||
507 | spin_lock_irqsave(&priv->sta_lock, flags); | 525 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
526 | if (force) { | ||
527 | IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n"); | ||
528 | priv->num_stations = 0; | ||
529 | memset(priv->stations, 0, sizeof(priv->stations)); | ||
530 | } else { | ||
531 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
532 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { | ||
533 | IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d \n", i); | ||
534 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
535 | cleared = true; | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
540 | |||
541 | if (!cleared) | ||
542 | IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n"); | ||
543 | } | ||
544 | EXPORT_SYMBOL(iwl_clear_ucode_stations); | ||
508 | 545 | ||
509 | if (iwl_is_alive(priv) && | 546 | /** |
510 | !test_bit(STATUS_EXIT_PENDING, &priv->status) && | 547 | * iwl_restore_stations() - Restore driver known stations to device |
511 | iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) | 548 | * |
512 | IWL_ERR(priv, "Couldn't clear the station table\n"); | 549 | * All stations considered active by driver, but not present in ucode, is |
550 | * restored. | ||
551 | */ | ||
552 | void iwl_restore_stations(struct iwl_priv *priv) | ||
553 | { | ||
554 | unsigned long flags_spin; | ||
555 | int i; | ||
556 | bool found = false; | ||
513 | 557 | ||
514 | priv->num_stations = 0; | 558 | if (!iwl_is_ready(priv)) { |
515 | memset(priv->stations, 0, sizeof(priv->stations)); | 559 | IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n"); |
560 | return; | ||
561 | } | ||
516 | 562 | ||
517 | /* clean ucode key table bit map */ | 563 | IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); |
518 | priv->ucode_key_table = 0; | 564 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
565 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
566 | if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && | ||
567 | !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { | ||
568 | IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", | ||
569 | priv->stations[i].sta.sta.addr); | ||
570 | priv->stations[i].sta.mode = 0; | ||
571 | priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; | ||
572 | found = true; | ||
573 | } | ||
574 | } | ||
519 | 575 | ||
520 | /* keep track of static keys */ | 576 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
521 | for (i = 0; i < WEP_KEYS_MAX ; i++) { | 577 | if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { |
522 | if (priv->wep_keys[i].key_size) | 578 | iwl_send_add_sta(priv, &priv->stations[i].sta, |
523 | set_bit(i, &priv->ucode_key_table); | 579 | CMD_ASYNC); |
580 | priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
581 | } | ||
524 | } | 582 | } |
525 | 583 | ||
526 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 584 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
585 | if (!found) | ||
586 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n"); | ||
587 | else | ||
588 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... in progress.\n"); | ||
527 | } | 589 | } |
528 | EXPORT_SYMBOL(iwl_clear_stations_table); | 590 | EXPORT_SYMBOL(iwl_restore_stations); |
529 | 591 | ||
530 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 592 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) |
531 | { | 593 | { |