#include "iwl-phy-db.h"
 #include "iwl-modparams.h"
 #include "iwl-nvm-parse.h"
+#include "time-sync.h"
 
 #define MVM_UCODE_ALIVE_TIMEOUT        (HZ)
 #define MVM_UCODE_CALIB_TIMEOUT        (2 * HZ)
                        goto error;
        }
 
-       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
                iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB);
+               iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr,
+                                        IWL_TIME_SYNC_PROTOCOL_TM |
+                                        IWL_TIME_SYNC_PROTOCOL_FTM);
+       }
 
        if (!mvm->ptp_data.ptp_clock)
                iwl_mvm_ptp_init(mvm);
 
 #include "fw/error-dump.h"
 #include "iwl-prph.h"
 #include "iwl-nvm-parse.h"
+#include "time-sync.h"
 
 static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
        {
                wiphy_ext_feature_set(hw->wiphy,
                                      NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT);
 
+       if (fw_has_capa(&mvm->fw->ucode_capa,
+                       IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM))
+               hw->wiphy->hw_timestamp_max_peers = 1;
+
        ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
        hw->wiphy->features |=
                NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
        return iwl_mvm_can_hw_csum(skb) == iwl_mvm_can_hw_csum(head);
 }
 
+static int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct cfg80211_set_hw_timestamp *hwts)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       u32 protocols = 0;
+       int ret;
+
+       /* HW timestamping is only supported for a specific station */
+       if (!hwts->macaddr)
+               return -EOPNOTSUPP;
+
+       if (hwts->enable)
+               protocols =
+                       IWL_TIME_SYNC_PROTOCOL_TM | IWL_TIME_SYNC_PROTOCOL_FTM;
+
+       mutex_lock(&mvm->mutex);
+       ret = iwl_mvm_time_sync_config(mvm, hwts->macaddr, protocols);
+       mutex_unlock(&mvm->mutex);
+
+       return ret;
+}
+
 const struct ieee80211_ops iwl_mvm_hw_ops = {
        .tx = iwl_mvm_mac_tx,
        .wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        .sta_add_debugfs = iwl_mvm_sta_add_debugfs,
 #endif
+       .set_hw_timestamp = iwl_mvm_set_hw_timestamp,
 };
 
 #include "mvm.h"
 #include "sta.h"
 #include "rs.h"
-#include "time-sync.h"
 
 /*
  * New version of ADD_STA_sta command added new fields at the end of the
                }
        }
 
-       if (!sta->tdls)
-               iwl_mvm_time_sync_config(mvm, sta->addr,
-                                        IWL_TIME_SYNC_PROTOCOL_TM |
-                                        IWL_TIME_SYNC_PROTOCOL_FTM);
-
        rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
 
        return 0;
        spin_lock_bh(&mvm_sta->lock);
        spin_unlock_bh(&mvm_sta->lock);
 
-       iwl_mvm_time_sync_sta_rm(mvm, sta);
-
        return false;
 }
 
 
        ieee80211_tx_status_ext(mvm->hw, &status);
 }
 
-int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, u8 *addr, u32 protocols)
+int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, const u8 *addr, u32 protocols)
 {
        struct iwl_time_sync_cfg_cmd cmd = {};
        int err;
                IWL_DEBUG_INFO(mvm, "Time sync: set peer addr=%pM\n", addr);
        }
 
-       return err;
-}
+       if (!mvm->time_sync.active)
+               skb_queue_purge(&mvm->time_sync.frame_list);
 
-void iwl_mvm_time_sync_sta_rm(struct iwl_mvm *mvm, struct ieee80211_sta *sta)
-{
-       /* Disable time sync with this station */
-       iwl_mvm_time_sync_config(mvm, sta->addr, 0);
-
-       skb_queue_purge(&mvm->time_sync.frame_list);
+       return err;
 }
 
                                  struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_time_sync_msmt_confirm_event(struct iwl_mvm *mvm,
                                          struct iwl_rx_cmd_buffer *rxb);
-int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, u8 *addr, u32 protocols);
-void iwl_mvm_time_sync_sta_rm(struct iwl_mvm *mvm, struct ieee80211_sta *sta);
+int iwl_mvm_time_sync_config(struct iwl_mvm *mvm, const u8 *addr,
+                            u32 protocols);
 
 static inline
 bool iwl_mvm_time_sync_frame(struct iwl_mvm *mvm, struct sk_buff *skb, u8 *addr)
 
--- /dev/null
+@@
+struct ieee80211_hw *hw;
+expression val;
+@@
+-hw->wiphy->hw_timestamp_max_peers = val
++hw_timestamp_max_peers(hw)