]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi...
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 12 Feb 2013 17:51:08 +0000 (12:51 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 12 Feb 2013 17:51:08 +0000 (12:51 -0500)
Conflicts:
drivers/net/wireless/iwlwifi/mvm/mac80211.c

1  2 
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c

index 0fccf725a2e6e81e4cbba273dda99c784672087c,ebbfcf47c7323a7711f07c0d7c2a7e45b0af2019..323e4a33fcaca4efb94b8bdeb815d223893b3f54
@@@ -151,7 -151,8 +151,7 @@@ int iwlagn_mac_setup_register(struct iw
                    IEEE80211_HW_QUEUE_CONTROL |
                    IEEE80211_HW_SUPPORTS_PS |
                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
 -                  IEEE80211_HW_WANT_MONITOR_VIF |
 -                  IEEE80211_HW_SCAN_WHILE_IDLE;
 +                  IEEE80211_HW_WANT_MONITOR_VIF;
  
        hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
        hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
@@@ -441,52 -442,154 +441,154 @@@ static int iwlagn_mac_suspend(struct ie
        return ret;
  }
  
+ struct iwl_resume_data {
+       struct iwl_priv *priv;
+       struct iwlagn_wowlan_status *cmd;
+       bool valid;
+ };
+ static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait,
+                                struct iwl_rx_packet *pkt, void *data)
+ {
+       struct iwl_resume_data *resume_data = data;
+       struct iwl_priv *priv = resume_data->priv;
+       u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       if (len - 4 != sizeof(*resume_data->cmd)) {
+               IWL_ERR(priv, "rx wrong size data\n");
+               return true;
+       }
+       memcpy(resume_data->cmd, pkt->data, sizeof(*resume_data->cmd));
+       resume_data->valid = true;
+       return true;
+ }
  static int iwlagn_mac_resume(struct ieee80211_hw *hw)
  {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct ieee80211_vif *vif;
-       unsigned long flags;
-       u32 base, status = 0xffffffff;
-       int ret = -EIO;
+       u32 base;
+       int ret;
+       enum iwl_d3_status d3_status;
+       struct error_table_start {
+               /* cf. struct iwl_error_event_table */
+               u32 valid;
+               u32 error_id;
+       } err_info;
+       struct iwl_notification_wait status_wait;
+       static const u8 status_cmd[] = {
+               REPLY_WOWLAN_GET_STATUS,
+       };
+       struct iwlagn_wowlan_status status_data = {};
+       struct iwl_resume_data resume_data = {
+               .priv = priv,
+               .cmd = &status_data,
+               .valid = false,
+       };
+       struct cfg80211_wowlan_wakeup wakeup = {
+               .pattern_idx = -1,
+       };
+ #ifdef CONFIG_IWLWIFI_DEBUGFS
+       const struct fw_img *img;
+ #endif
  
        IWL_DEBUG_MAC80211(priv, "enter\n");
        mutex_lock(&priv->mutex);
  
-       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
+       vif = ctx->vif;
+       ret = iwl_trans_d3_resume(priv->trans, &d3_status);
+       if (ret)
+               goto out_unlock;
+       if (d3_status != IWL_D3_STATUS_ALIVE) {
+               IWL_INFO(priv, "Device was reset during suspend\n");
+               goto out_unlock;
+       }
  
        base = priv->device_pointers.error_event_table;
-       if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) {
-                       iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
-                       status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-                       iwl_trans_release_nic_access(priv->trans, &flags);
-                       ret = 0;
+       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+               IWL_WARN(priv, "Invalid error table during resume!\n");
+               goto out_unlock;
+       }
+       iwl_trans_read_mem_bytes(priv->trans, base,
+                                &err_info, sizeof(err_info));
+       if (err_info.valid) {
+               IWL_INFO(priv, "error table is valid (%d, 0x%x)\n",
+                        err_info.valid, err_info.error_id);
+               if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+                       wakeup.rfkill_release = true;
+                       ieee80211_report_wowlan_wakeup(vif, &wakeup,
+                                                      GFP_KERNEL);
                }
+               goto out_unlock;
+       }
  
  #ifdef CONFIG_IWLWIFI_DEBUGFS
-               if (ret == 0) {
-                       const struct fw_img *img;
-                       img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
-                       if (!priv->wowlan_sram) {
-                               priv->wowlan_sram =
-                                  kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
-                                               GFP_KERNEL);
-                       }
-                       if (priv->wowlan_sram)
-                               iwl_trans_read_mem(
-                                     priv->trans, 0x800000,
-                                     priv->wowlan_sram,
-                                     img->sec[IWL_UCODE_SECTION_DATA].len / 4);
-               }
+       img = &priv->fw->img[IWL_UCODE_WOWLAN];
+       if (!priv->wowlan_sram)
+               priv->wowlan_sram =
+                       kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
+                               GFP_KERNEL);
+       if (priv->wowlan_sram)
+               iwl_trans_read_mem(priv->trans, 0x800000,
+                                  priv->wowlan_sram,
+                                  img->sec[IWL_UCODE_SECTION_DATA].len / 4);
  #endif
-       }
  
-       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
-       vif = ctx->vif;
+       /*
+        * This is very strange. The GET_STATUS command is sent but the device
+        * doesn't reply properly, it seems it doesn't close the RBD so one is
+        * always left open ... As a result, we need to send another command
+        * and have to reset the driver afterwards. As we need to switch to
+        * runtime firmware again that'll happen.
+        */
+       iwl_init_notification_wait(&priv->notif_wait, &status_wait, status_cmd,
+                                  ARRAY_SIZE(status_cmd), iwl_resume_status_fn,
+                                  &resume_data);
+       iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL);
+       iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL);
+       /* an RBD is left open in the firmware now! */
+       ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5);
+       if (ret)
+               goto out_unlock;
+       if (resume_data.valid && priv->contexts[IWL_RXON_CTX_BSS].vif) {
+               u32 reasons = le32_to_cpu(status_data.wakeup_reason);
+               struct cfg80211_wowlan_wakeup *wakeup_report;
+               IWL_INFO(priv, "WoWLAN wakeup reason(s): 0x%.8x\n", reasons);
+               if (reasons) {
+                       if (reasons & IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET)
+                               wakeup.magic_pkt = true;
+                       if (reasons & IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH)
+                               wakeup.pattern_idx = status_data.pattern_number;
+                       if (reasons & (IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+                                      IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE))
+                               wakeup.disconnect = true;
+                       if (reasons & IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL)
+                               wakeup.gtk_rekey_failure = true;
+                       if (reasons & IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ)
+                               wakeup.eap_identity_req = true;
+                       if (reasons & IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE)
+                               wakeup.four_way_handshake = true;
+                       wakeup_report = &wakeup;
+               } else {
+                       wakeup_report = NULL;
+               }
+               ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
+       }
  
        priv->wowlan = false;
  
        iwl_connection_init_rx_config(priv, ctx);
        iwlagn_set_rxon_chain(priv, ctx);
  
+  out_unlock:
        mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
  
index bbb8a5b35662b29855e08baffd853158241ce723,5bdcbcfee0c58ea70af3e10fbed2b20f5ec07127..e27eb9724112043884729c123a638aa838e9241c
@@@ -113,7 -113,7 +113,7 @@@ int iwl_mvm_mac_setup_register(struct i
                    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                    IEEE80211_HW_QUEUE_CONTROL |
                    IEEE80211_HW_WANT_MONITOR_VIF |
 -                  IEEE80211_HW_SCAN_WHILE_IDLE |
 +                  IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
                    IEEE80211_HW_SUPPORTS_PS |
                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
                    IEEE80211_HW_AMPDU_AGGREGATION;
@@@ -474,7 -474,7 +474,7 @@@ static int iwl_mvm_mac_add_interface(st
        if (mvm->vif_count > 1) {
                IWL_DEBUG_MAC80211(mvm,
                                   "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces(
+               ieee80211_iterate_active_interfaces_atomic(
                                            mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
                                            iwl_mvm_pm_disable_iterator, mvm);
@@@ -670,8 -670,6 +670,6 @@@ static void iwl_mvm_bss_info_changed_st
                                IWL_ERR(mvm, "failed to update quotas\n");
                                return;
                        }
-                       iwl_mvm_remove_time_event(mvm, mvmvif,
-                                                 &mvmvif->time_event_data);
                } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
                        /* remove AP station now that the MAC is unassoc */
                        ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
                        if (ret)
                                IWL_ERR(mvm, "failed to update quotas\n");
                }
+       } else if (changes & BSS_CHANGED_DTIM_PERIOD) {
+               /*
+                * We received a beacon _after_ association so
+                * remove the session protection.
+                */
+               iwl_mvm_remove_time_event(mvm, mvmvif,
+                                         &mvmvif->time_event_data);
        } else if (changes & BSS_CHANGED_PS) {
                /*
                 * TODO: remove this temporary code.
@@@ -921,8 -926,10 +926,10 @@@ static int iwl_mvm_mac_sta_state(struc
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC) {
-               iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band);
-               ret = 0;
+               ret = iwl_mvm_update_sta(mvm, vif, sta);
+               if (ret == 0)
+                       iwl_mvm_rs_rate_init(mvm, sta,
+                                            mvmvif->phy_ctxt->channel->band);
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTHORIZED) {
                ret = 0;