Merge remote-tracking branch 'iwlwifi-fixes/master' into HEAD
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 13 May 2014 10:51:53 +0000 (13:51 +0300)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 13 May 2014 10:51:53 +0000 (13:51 +0300)
1  2 
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index 72f73a3abc7162976c962084264392e95e487d99,4b0b8b6571eeb8624eebbcd75a87c12b1cb9e013..cc6ddc45b416b26fe27df7926ab67f99b5ab63a0
@@@ -276,7 -276,6 +276,7 @@@ int iwl_mvm_mac_setup_register(struct i
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_TIMING_BEACON_ONLY |
                    IEEE80211_HW_CONNECTION_MONITOR |
 +                  IEEE80211_HW_SUPPORTS_UAPSD |
                    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                    IEEE80211_HW_SUPPORTS_STATIC_SMPS;
  
                                    IEEE80211_RADIOTAP_MCS_HAVE_STBC;
        hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
        hw->rate_control_algorithm = "iwl-mvm-rs";
 +      hw->uapsd_queues = IWL_UAPSD_AC_INFO;
 +      hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
  
        /*
         * Enable 11w if advertised by firmware and software crypto
            !iwlwifi_mod_params.sw_crypto)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
  
 -      if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) {
 -              hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
 -              hw->uapsd_queues = IWL_UAPSD_AC_INFO;
 -              hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
 -      }
 +      /* Disable uAPSD due to firmware issues */
 +      if (true)
 +              hw->flags &= ~IEEE80211_HW_SUPPORTS_UAPSD;
  
        hw->sta_data_size = sizeof(struct iwl_mvm_sta);
        hw->vif_data_size = sizeof(struct iwl_mvm_vif);
                BIT(NL80211_IFTYPE_P2P_CLIENT) |
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_P2P_GO) |
 -              BIT(NL80211_IFTYPE_P2P_DEVICE);
 -
 -      /* IBSS has bugs in older versions */
 -      if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
 -              hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 +              BIT(NL80211_IFTYPE_P2P_DEVICE) |
 +              BIT(NL80211_IFTYPE_ADHOC);
  
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
        hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
                hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
  
 +      if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW)
 +              hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 +
        hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
        hw->wiphy->n_iface_combinations =
                ARRAY_SIZE(iwl_mvm_iface_combinations);
        else
                hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
  
 -      if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) {
 -              hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 -              hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
 -              hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
 -              /* we create the 802.11 header and zero length SSID IE. */
 -              hw->wiphy->max_sched_scan_ie_len =
 -                                      SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
 -      }
 +      hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 +      hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
 +      hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
 +      /* we create the 802.11 header and zero length SSID IE. */
 +      hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
  
        hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
                               NL80211_FEATURE_P2P_GO_OPPPS;
        }
  
  #ifdef CONFIG_PM_SLEEP
 -      if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
 +      if (iwl_mvm_is_d0i3_supported(mvm) &&
 +          device_can_wakeup(mvm->trans->dev)) {
 +              mvm->wowlan.flags = WIPHY_WOWLAN_ANY;
 +              hw->wiphy->wowlan = &mvm->wowlan;
 +      } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
            mvm->trans->ops->d3_suspend &&
            mvm->trans->ops->d3_resume &&
            device_can_wakeup(mvm->trans->dev)) {
@@@ -542,22 -540,13 +542,22 @@@ static int iwl_mvm_mac_ampdu_action(str
                return -EACCES;
  
        /* return from D0i3 before starting a new Tx aggregation */
 -      if (action == IEEE80211_AMPDU_TX_START) {
 +      switch (action) {
 +      case IEEE80211_AMPDU_TX_START:
 +      case IEEE80211_AMPDU_TX_STOP_CONT:
 +      case IEEE80211_AMPDU_TX_STOP_FLUSH:
 +      case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 +      case IEEE80211_AMPDU_TX_OPERATIONAL:
                iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG);
                tx_agg_ref = true;
  
                /*
 -               * wait synchronously until D0i3 exit to get the correct
 -               * sequence number for the tid
 +               * for tx start, wait synchronously until D0i3 exit to
 +               * get the correct sequence number for the tid.
 +               * additionally, some other ampdu actions use direct
 +               * target access, which is not handled automatically
 +               * by the trans layer (unlike commands), so wait for
 +               * d0i3 exit in these cases as well.
                 */
                if (!wait_event_timeout(mvm->d0i3_exit_waitq,
                          !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) {
                        iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG);
                        return -EIO;
                }
 +              break;
 +      default:
 +              break;
        }
  
        mutex_lock(&mvm->mutex);
@@@ -841,7 -827,8 +841,7 @@@ static int iwl_mvm_mac_add_interface(st
                goto out_remove_mac;
  
        if (!mvm->bf_allowed_vif &&
 -          vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
 -          mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){
 +          vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
                mvm->bf_allowed_vif = mvmvif;
                vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
                                     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
@@@ -1020,7 -1007,7 +1020,7 @@@ static void iwl_mvm_mc_iface_iterator(v
        memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
        len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);
  
-       ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC, len, cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd);
        if (ret)
                IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);
  }
@@@ -1036,7 -1023,7 +1036,7 @@@ static void iwl_mvm_recalc_multicast(st
        if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))
                return;
  
-       ieee80211_iterate_active_interfaces(
+       ieee80211_iterate_active_interfaces_atomic(
                mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
                iwl_mvm_mc_iface_iterator, &iter_data);
  }
@@@ -1236,10 -1223,6 +1236,10 @@@ static int iwl_mvm_configure_bcast_filt
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
                return 0;
  
 +      /* bcast filtering isn't supported for P2P client */
 +      if (vif->p2p)
 +              return 0;
 +
        if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
                return 0;
  
@@@ -1364,7 -1347,7 +1364,7 @@@ static void iwl_mvm_bss_info_changed_st
        }
  
        if (changes & BSS_CHANGED_CQM) {
 -              IWL_DEBUG_MAC80211(mvm, "cqm info_changed");
 +              IWL_DEBUG_MAC80211(mvm, "cqm info_changed\n");
                /* reset cqm events tracking */
                mvmvif->bf_data.last_cqm_event = 0;
                ret = iwl_mvm_update_beacon_filter(mvm, vif, false, CMD_SYNC);
        }
  
        if (changes & BSS_CHANGED_ARP_FILTER) {
 -              IWL_DEBUG_MAC80211(mvm, "arp filter changed");
 +              IWL_DEBUG_MAC80211(mvm, "arp filter changed\n");
                iwl_mvm_configure_bcast_filter(mvm, vif);
        }
  }
@@@ -1512,9 -1495,6 +1512,9 @@@ static void iwl_mvm_bss_info_changed(st
  
        mutex_lock(&mvm->mutex);
  
 +      if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
 +              iwl_mvm_sched_scan_stop(mvm, true);
 +
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);
@@@ -1545,7 -1525,7 +1545,7 @@@ static int iwl_mvm_mac_hw_scan(struct i
  
        switch (mvm->scan_status) {
        case IWL_MVM_SCAN_SCHED:
 -              ret = iwl_mvm_sched_scan_stop(mvm);
 +              ret = iwl_mvm_sched_scan_stop(mvm, true);
                if (ret) {
                        ret = -EBUSY;
                        goto out;
@@@ -1717,11 -1697,6 +1717,11 @@@ static int iwl_mvm_mac_sta_state(struc
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
 +              /*
 +               * EBS may be disabled due to previous failures reported by FW.
 +               * Reset EBS status here assuming environment has been changed.
 +               */
 +              mvm->last_ebs_successful = true;
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC) {
@@@ -1832,6 -1807,11 +1832,11 @@@ static int iwl_mvm_mac_sched_scan_start
  
        mutex_lock(&mvm->mutex);
  
+       if (iwl_mvm_is_associated(mvm)) {
+               ret = -EBUSY;
+               goto out;
+       }
        switch (mvm->scan_status) {
        case IWL_MVM_SCAN_OS:
                IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
@@@ -1885,7 -1865,7 +1890,7 @@@ static int iwl_mvm_mac_sched_scan_stop(
        int ret;
  
        mutex_lock(&mvm->mutex);
 -      ret = iwl_mvm_sched_scan_stop(mvm);
 +      ret = iwl_mvm_sched_scan_stop(mvm, false);
        mutex_unlock(&mvm->mutex);
        iwl_mvm_wait_for_async_handlers(mvm);
  
@@@ -2204,11 -2184,6 +2209,11 @@@ static int iwl_mvm_assign_vif_chanctx(s
  
        switch (vif->type) {
        case NL80211_IFTYPE_AP:
 +              /* Unless it's a CSA flow we have nothing to do here */
 +              if (vif->csa_active) {
 +                      mvmvif->ap_ibss_active = true;
 +                      break;
 +              }
        case NL80211_IFTYPE_ADHOC:
                /*
                 * The AP binding flow is handled as part of the start_ap flow
                        goto out_remove_binding;
        }
  
 +      /* Handle binding during CSA */
 +      if (vif->type == NL80211_IFTYPE_AP) {
 +              iwl_mvm_update_quotas(mvm, vif);
 +              iwl_mvm_mac_ctxt_changed(mvm, vif);
 +      }
 +
        goto out_unlock;
  
   out_remove_binding:
@@@ -2275,20 -2244,13 +2280,20 @@@ static void iwl_mvm_unassign_vif_chanct
        iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
  
        switch (vif->type) {
 -      case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_ADHOC:
                goto out_unlock;
        case NL80211_IFTYPE_MONITOR:
                mvmvif->monitor_active = false;
                iwl_mvm_update_quotas(mvm, NULL);
                break;
 +      case NL80211_IFTYPE_AP:
 +              /* This part is triggered only during CSA */
 +              if (!vif->csa_active || !mvmvif->ap_ibss_active)
 +                      goto out_unlock;
 +
 +              mvmvif->ap_ibss_active = false;
 +              iwl_mvm_update_quotas(mvm, NULL);
 +              /*TODO: bt_coex notification here? */
        default:
                break;
        }
@@@ -2384,53 -2346,6 +2389,53 @@@ static int iwl_mvm_mac_testmode_cmd(str
  }
  #endif
  
 +static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw,
 +                                        struct ieee80211_vif *vif,
 +                                        struct cfg80211_chan_def *chandef)
 +{
 +      struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 +
 +      mutex_lock(&mvm->mutex);
 +      if (WARN(mvm->csa_vif && mvm->csa_vif->csa_active,
 +               "Another CSA is already in progress"))
 +              goto out_unlock;
 +
 +      IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n",
 +                         chandef->center_freq1);
 +      mvm->csa_vif = vif;
 +
 +out_unlock:
 +      mutex_unlock(&mvm->mutex);
 +}
 +
 +static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
 +                            struct ieee80211_vif *vif, u32 queues, bool drop)
 +{
 +      struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 +      struct iwl_mvm_vif *mvmvif;
 +      struct iwl_mvm_sta *mvmsta;
 +
 +      if (!vif || vif->type != NL80211_IFTYPE_STATION)
 +              return;
 +
 +      mutex_lock(&mvm->mutex);
 +      mvmvif = iwl_mvm_vif_from_mac80211(vif);
 +      mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
 +
 +      if (WARN_ON_ONCE(!mvmsta))
 +              goto done;
 +
 +      if (drop) {
 +              if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
 +                      IWL_ERR(mvm, "flush request fail\n");
 +      } else {
 +              iwl_trans_wait_tx_queue_empty(mvm->trans,
 +                                            mvmsta->tfd_queue_msk);
 +      }
 +done:
 +      mutex_unlock(&mvm->mutex);
 +}
 +
  const struct ieee80211_ops iwl_mvm_hw_ops = {
        .tx = iwl_mvm_mac_tx,
        .ampdu_action = iwl_mvm_mac_ampdu_action,
        .sta_rc_update = iwl_mvm_sta_rc_update,
        .conf_tx = iwl_mvm_mac_conf_tx,
        .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
 +      .flush = iwl_mvm_mac_flush,
        .sched_scan_start = iwl_mvm_mac_sched_scan_start,
        .sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
        .set_key = iwl_mvm_mac_set_key,
  
        .set_tim = iwl_mvm_set_tim,
  
 +      .channel_switch_beacon = iwl_mvm_channel_switch_beacon,
 +
        CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
  
  #ifdef CONFIG_PM_SLEEP
index 78f3328066dda3fbb0bc297b2bf9ac9955e0033d,84c75a1b267e2f6c31c2aefb0c25de140a792125..a7d27fb3704486c309f4fabe01efced1f7667def
@@@ -164,6 -164,7 +164,6 @@@ enum iwl_dbgfs_pm_mask 
        MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS = BIT(2),
        MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3),
        MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4),
 -      MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5),
        MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
        MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
        MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
@@@ -176,6 -177,7 +176,6 @@@ struct iwl_dbgfs_pm 
        u32 tx_data_timeout;
        bool skip_over_dtim;
        u8 skip_dtim_periods;
 -      bool disable_power_off;
        bool lprx_ena;
        u32 lprx_rssi_threshold;
        bool snooze_ena;
@@@ -230,7 -232,6 +230,7 @@@ enum iwl_mvm_ref_type 
        IWL_MVM_REF_USER,
        IWL_MVM_REF_TX,
        IWL_MVM_REF_TX_AGG,
 +      IWL_MVM_REF_EXIT_WORK,
  
        IWL_MVM_REF_COUNT,
  };
@@@ -264,7 -265,6 +264,7 @@@ struct iwl_mvm_vif_bf_data 
   * @uploaded: indicates the MAC context has been added to the device
   * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
   *    should get quota etc.
 + * @pm_enabled - Indicate if MAC power management is allowed
   * @monitor_active: indicates that monitor context is configured, and that the
   *    interface should get quota etc.
   * @low_latency: indicates that this interface is in low-latency mode
@@@ -283,7 -283,6 +283,7 @@@ struct iwl_mvm_vif 
  
        bool uploaded;
        bool ap_ibss_active;
 +      bool pm_enabled;
        bool monitor_active;
        bool low_latency;
        struct iwl_mvm_vif_bf_data bf_data;
@@@ -452,11 -451,6 +452,11 @@@ struct iwl_mvm_frame_stats 
        int last_frame_idx;
  };
  
 +enum {
 +      D0I3_DEFER_WAKEUP,
 +      D0I3_PENDING_WAKEUP,
 +};
 +
  struct iwl_mvm {
        /* for logger access */
        struct device *dev;
        u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
        atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
  
 +      const char *nvm_file_name;
        struct iwl_nvm_data *nvm_data;
        /* NVM sections */
        struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS];
        /* Internal station */
        struct iwl_mvm_int_sta aux_sta;
  
 +      bool last_ebs_successful;
 +
        u8 scan_last_antenna_idx; /* to toggle TX between antennas */
        u8 mgmt_last_antenna_idx;
  
        void *fw_error_dump;
        void *fw_error_sram;
        u32 fw_error_sram_len;
 +      u32 *fw_error_rxf;
 +      u32 fw_error_rxf_len;
  
 +#ifdef CONFIG_IWLWIFI_LEDS
        struct led_classdev led;
 +#endif
  
        struct ieee80211_vif *p2p_device_vif;
  
        bool d0i3_offloading;
        struct work_struct d0i3_exit_work;
        struct sk_buff_head d0i3_tx;
 +      /* protect d0i3_suspend_flags */
 +      struct mutex d0i3_suspend_mutex;
 +      unsigned long d0i3_suspend_flags;
        /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */
        spinlock_t d0i3_tx_lock;
        wait_queue_head_t d0i3_exit_waitq;
  
        /* Indicate if device power save is allowed */
        bool ps_disabled;
 -      /* Indicate if device power management is allowed */
 -      bool pm_disabled;
 +
 +      struct ieee80211_vif *csa_vif;
  };
  
  /* Extract MVM priv from op_mode and _hw */
@@@ -721,7 -705,6 +721,7 @@@ void iwl_mvm_dump_nic_error_log(struct 
  #ifdef CONFIG_IWLWIFI_DEBUGFS
  void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
  void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm);
 +void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm);
  #endif
  u8 first_antenna(u8 mask);
  u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
@@@ -762,7 -745,7 +762,7 @@@ int iwl_mvm_rx_statistics(struct iwl_mv
                          struct iwl_device_cmd *cmd);
  
  /* NVM */
 -int iwl_nvm_init(struct iwl_mvm *mvm);
 +int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
  int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
  
  int iwl_mvm_up(struct iwl_mvm *mvm);
@@@ -857,7 -840,7 +857,7 @@@ int iwl_mvm_config_sched_scan_profiles(
                                       struct cfg80211_sched_scan_request *req);
  int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                             struct cfg80211_sched_scan_request *req);
 -int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
 +int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify);
  int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
                                  struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd);
@@@ -891,6 -874,8 +891,6 @@@ void iwl_mvm_update_frame_stats(struct 
  int rs_pretty_print_rate(char *buf, const u32 rate);
  
  /* power management */
 -int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
 -
  int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
  int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
  int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@@ -901,18 -886,8 +901,18 @@@ int iwl_mvm_power_uapsd_misbehaving_ap_
                                             struct iwl_rx_cmd_buffer *rxb,
                                             struct iwl_device_cmd *cmd);
  
 +#ifdef CONFIG_IWLWIFI_LEDS
  int iwl_mvm_leds_init(struct iwl_mvm *mvm);
  void iwl_mvm_leds_exit(struct iwl_mvm *mvm);
 +#else
 +static inline int iwl_mvm_leds_init(struct iwl_mvm *mvm)
 +{
 +      return 0;
 +}
 +static inline void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
 +{
 +}
 +#endif
  
  /* D3 (WoWLAN, NetDetect) */
  int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
@@@ -947,9 -922,9 +947,9 @@@ int iwl_mvm_send_proto_offload(struct i
  void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
  void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
  void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
 +int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
  
  /* BT Coex */
 -int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
  int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
  int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
                             struct iwl_rx_cmd_buffer *rxb,
@@@ -961,8 -936,6 +961,8 @@@ u16 iwl_mvm_coex_agg_time_limit(struct 
                                struct ieee80211_sta *sta);
  bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
                                     struct ieee80211_sta *sta);
 +bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
 +                                  enum ieee80211_band band);
  u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
                           struct ieee80211_tx_info *info, u8 ac);
  int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable);
@@@ -1030,6 -1003,9 +1030,9 @@@ static inline bool iwl_mvm_vif_low_late
        return mvmvif->low_latency;
  }
  
+ /* Assoc status */
+ bool iwl_mvm_is_associated(struct iwl_mvm *mvm);
  /* Thermal management and CT-kill */
  void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
  void iwl_mvm_tt_handler(struct iwl_mvm *mvm);
index 4c3577e773a5d912fa5fe688eb24707133573d47,6fdbef9696d8f6e34b5fea258c40bd7b6b433f2b..9cd0309216df77ba64b8c99948e1a7a4bc8999e2
@@@ -64,7 -64,6 +64,7 @@@
  
  #include "iwl-debug.h"
  #include "iwl-io.h"
 +#include "iwl-prph.h"
  
  #include "mvm.h"
  #include "fw-api-rs.h"
@@@ -470,8 -469,6 +470,8 @@@ void iwl_mvm_dump_nic_error_log(struct 
                        mvm->status, table.valid);
        }
  
 +      /* Do not change this output - scripts rely on it */
 +
        IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
  
        trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
                iwl_mvm_dump_umac_error_log(mvm);
  }
  
 +#ifdef CONFIG_IWLWIFI_DEBUGFS
  void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm)
  {
        const struct fw_img *img;
        u32 ofs, sram_len;
        void *sram;
  
 -      if (!mvm->ucode_loaded || mvm->fw_error_sram)
 +      if (!mvm->ucode_loaded || mvm->fw_error_sram || mvm->fw_error_dump)
                return;
  
        img = &mvm->fw->img[mvm->cur_ucode];
        mvm->fw_error_sram_len = sram_len;
  }
  
 +void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm)
 +{
 +      int i, reg_val;
 +      unsigned long flags;
 +
 +      if (!mvm->ucode_loaded || mvm->fw_error_rxf || mvm->fw_error_dump)
 +              return;
 +
 +      /* reading buffer size */
 +      reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR);
 +      mvm->fw_error_rxf_len =
 +              (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS;
 +
 +      /* the register holds the value divided by 128 */
 +      mvm->fw_error_rxf_len = mvm->fw_error_rxf_len << 7;
 +
 +      if (!mvm->fw_error_rxf_len)
 +              return;
 +
 +      mvm->fw_error_rxf =  kzalloc(mvm->fw_error_rxf_len, GFP_ATOMIC);
 +      if (!mvm->fw_error_rxf) {
 +              mvm->fw_error_rxf_len = 0;
 +              return;
 +      }
 +
 +      if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) {
 +              kfree(mvm->fw_error_rxf);
 +              mvm->fw_error_rxf = NULL;
 +              mvm->fw_error_rxf_len = 0;
 +              return;
 +      }
 +
 +      for (i = 0; i < (mvm->fw_error_rxf_len / sizeof(u32)); i++) {
 +              iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR,
 +                                   i * sizeof(u32));
 +              mvm->fw_error_rxf[i] =
 +                      iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_ADDR);
 +      }
 +      iwl_trans_release_nic_access(mvm->trans, &flags);
 +}
 +#endif
 +
  /**
   * iwl_mvm_send_lq_cmd() - Send link quality command
   * @init: This command is sent as part of station initialization right
@@@ -690,3 -644,22 +690,22 @@@ bool iwl_mvm_low_latency(struct iwl_mv
  
        return result;
  }
+ static void iwl_mvm_assoc_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)
+ {
+       bool *assoc = _data;
+       if (vif->bss_conf.assoc)
+               *assoc = true;
+ }
+ bool iwl_mvm_is_associated(struct iwl_mvm *mvm)
+ {
+       bool assoc = false;
+       ieee80211_iterate_active_interfaces_atomic(
+                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                       iwl_mvm_assoc_iter, &assoc);
+       return assoc;
+ }
index f8ebd477bbfccdf11f499fa16f9bc5ae70672fa5,2365553f1ef79d59c3e8598335e48eb43e5cfdcb..788085bc65d78e3382c7fa76ca74de30abd4cd84
@@@ -73,7 -73,6 +73,7 @@@
  #include "iwl-csr.h"
  #include "iwl-prph.h"
  #include "iwl-agn-hw.h"
 +#include "iwl-fw-error-dump.h"
  #include "internal.h"
  
  static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
@@@ -104,6 -103,7 +104,6 @@@ static void iwl_pcie_set_pwr(struct iwl
  
  /* PCI registers */
  #define PCI_CFG_RETRY_TIMEOUT 0x041
 -#define CPU1_CPU2_SEPARATOR_SECTION   0xFFFFCCCC
  
  static void iwl_pcie_apm_config(struct iwl_trans *trans)
  {
@@@ -454,7 -454,6 +454,7 @@@ static int iwl_pcie_prepare_card_hw(str
  {
        int ret;
        int t = 0;
 +      int iter;
  
        IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
  
        if (ret >= 0)
                return 0;
  
 -      /* If HW is not ready, prepare the conditions to check again */
 -      iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
 -                  CSR_HW_IF_CONFIG_REG_PREPARE);
 +      for (iter = 0; iter < 10; iter++) {
 +              /* If HW is not ready, prepare the conditions to check again */
 +              iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
 +                          CSR_HW_IF_CONFIG_REG_PREPARE);
 +
 +              do {
 +                      ret = iwl_pcie_set_hw_ready(trans);
 +                      if (ret >= 0)
 +                              return 0;
  
 -      do {
 -              ret = iwl_pcie_set_hw_ready(trans);
 -              if (ret >= 0)
 -                      return 0;
 +                      usleep_range(200, 1000);
 +                      t += 200;
 +              } while (t < 150000);
 +              msleep(25);
 +      }
  
 -              usleep_range(200, 1000);
 -              t += 200;
 -      } while (t < 150000);
 +      IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter);
  
        return ret;
  }
@@@ -1059,12 -1053,6 +1059,12 @@@ static void iwl_trans_pcie_write_prph(s
        iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
  }
  
 +static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
 +{
 +      WARN_ON(1);
 +      return 0;
 +}
 +
  static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                                     const struct iwl_trans_config *trans_cfg)
  {
  
        trans_pcie->command_names = trans_cfg->command_names;
        trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
 +
 +      /* Initialize NAPI here - it should be before registering to mac80211
 +       * in the opmode but after the HW struct is allocated.
 +       * As this function may be called again in some corner cases don't
 +       * do anything if NAPI was already initialized.
 +       */
 +      if (!trans_pcie->napi.poll && trans->op_mode->ops->napi_add) {
 +              init_dummy_netdev(&trans_pcie->napi_dev);
 +              iwl_op_mode_napi_add(trans->op_mode, &trans_pcie->napi,
 +                                   &trans_pcie->napi_dev,
 +                                   iwl_pcie_dummy_napi_poll, 64);
 +      }
  }
  
  void iwl_trans_pcie_free(struct iwl_trans *trans)
        pci_disable_device(trans_pcie->pci_dev);
        kmem_cache_destroy(trans->dev_cmd_pool);
  
 +      if (trans_pcie->napi.poll)
 +              netif_napi_del(&trans_pcie->napi);
 +
        kfree(trans);
  }
  
@@@ -1264,7 -1237,7 +1264,7 @@@ static int iwl_trans_pcie_write_mem(str
  
  #define IWL_FLUSH_WAIT_MS     2000
  
 -static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
 +static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_txq *txq;
  
        /* waiting for all the tx frames complete might take a while */
        for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
 +              u8 wr_ptr;
 +
                if (cnt == trans_pcie->cmd_queue)
                        continue;
 +              if (!test_bit(cnt, trans_pcie->queue_used))
 +                      continue;
 +              if (!(BIT(cnt) & txq_bm))
 +                      continue;
 +
 +              IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt);
                txq = &trans_pcie->txq[cnt];
                q = &txq->q;
 -              while (q->read_ptr != q->write_ptr && !time_after(jiffies,
 -                     now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
 +              wr_ptr = ACCESS_ONCE(q->write_ptr);
 +
 +              while (q->read_ptr != ACCESS_ONCE(q->write_ptr) &&
 +                     !time_after(jiffies,
 +                                 now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) {
 +                      u8 write_ptr = ACCESS_ONCE(q->write_ptr);
 +
 +                      if (WARN_ONCE(wr_ptr != write_ptr,
 +                                    "WR pointer moved while flushing %d -> %d\n",
 +                                    wr_ptr, write_ptr))
 +                              return -ETIMEDOUT;
                        msleep(1);
 +              }
  
                if (q->read_ptr != q->write_ptr) {
                        IWL_ERR(trans,
                        ret = -ETIMEDOUT;
                        break;
                }
 +              IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt);
        }
  
        if (!ret)
                IWL_ERR(trans,
                        "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
                        cnt, active ? "" : "in", fifo, tbl_dw,
 -                      iwl_read_prph(trans,
 -                                    SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1),
 +                      iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) &
 +                              (TFD_QUEUE_SIZE_MAX - 1),
                        iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
        }
  
        IWL_ERR(trans, "failed to create the trans debugfs entry\n");
        return -ENOMEM;
  }
 +
 +static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
 +{
 +      u32 cmdlen = 0;
 +      int i;
 +
 +      for (i = 0; i < IWL_NUM_OF_TBS; i++)
 +              cmdlen += iwl_pcie_tfd_tb_get_len(tfd, i);
 +
 +      return cmdlen;
 +}
 +
 +static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
 +                                  void *buf, u32 buflen)
 +{
 +      struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 +      struct iwl_fw_error_dump_data *data;
 +      struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
 +      struct iwl_fw_error_dump_txcmd *txcmd;
 +      u32 len;
 +      int i, ptr;
 +
 +      if (!buf)
 +              return sizeof(*data) +
 +                     cmdq->q.n_window * (sizeof(*txcmd) +
 +                                         TFD_MAX_PAYLOAD_SIZE);
 +
 +      len = 0;
 +      data = buf;
 +      data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
 +      txcmd = (void *)data->data;
 +      spin_lock_bh(&cmdq->lock);
 +      ptr = cmdq->q.write_ptr;
 +      for (i = 0; i < cmdq->q.n_window; i++) {
 +              u8 idx = get_cmd_index(&cmdq->q, ptr);
 +              u32 caplen, cmdlen;
 +
 +              cmdlen = iwl_trans_pcie_get_cmdlen(&cmdq->tfds[ptr]);
 +              caplen = min_t(u32, TFD_MAX_PAYLOAD_SIZE, cmdlen);
 +
 +              if (cmdlen) {
 +                      len += sizeof(*txcmd) + caplen;
 +                      txcmd->cmdlen = cpu_to_le32(cmdlen);
 +                      txcmd->caplen = cpu_to_le32(caplen);
 +                      memcpy(txcmd->data, cmdq->entries[idx].cmd, caplen);
 +                      txcmd = (void *)((u8 *)txcmd->data + caplen);
 +              }
 +
 +              ptr = iwl_queue_dec_wrap(ptr);
 +      }
 +      spin_unlock_bh(&cmdq->lock);
 +
 +      data->len = cpu_to_le32(len);
 +      return sizeof(*data) + len;
 +}
  #else
  static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
                                         struct dentry *dir)
@@@ -1773,10 -1672,6 +1773,10 @@@ static const struct iwl_trans_ops trans
        .grab_nic_access = iwl_trans_pcie_grab_nic_access,
        .release_nic_access = iwl_trans_pcie_release_nic_access,
        .set_bits_mask = iwl_trans_pcie_set_bits_mask,
 +
 +#ifdef CONFIG_IWLWIFI_DEBUGFS
 +      .dump_data = iwl_trans_pcie_dump_data,
 +#endif
  };
  
  struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
         * PCI Tx retries from interfering with C3 CPU state */
        pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
  
+       trans->dev = &pdev->dev;
+       trans_pcie->pci_dev = pdev;
+       iwl_disable_interrupts(trans);
        err = pci_enable_msi(pdev);
        if (err) {
                dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err);
                }
        }
  
-       trans->dev = &pdev->dev;
-       trans_pcie->pci_dev = pdev;
        trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
        trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
        snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
                goto out_pci_disable_msi;
        }
  
-       trans_pcie->inta_mask = CSR_INI_SET_MASK;
        if (iwl_pcie_alloc_ict(trans))
                goto out_free_cmd_pool;
  
                goto out_free_ict;
        }
  
+       trans_pcie->inta_mask = CSR_INI_SET_MASK;
        return trans;
  
  out_free_ict: