mac80211: add offset_tsf driver op and use it for mesh
authorPedersen, Thomas <twp@qca.qualcomm.com>
Wed, 28 Sep 2016 23:56:28 +0000 (16:56 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 30 Sep 2016 11:45:44 +0000 (13:45 +0200)
This allows the mesh sync (and debugfs) code to make incremental
TSF adjustments, avoiding any uncertainty introduced by delay in
programming absolute TSF.

Signed-off-by: Thomas Pedersen <twp@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.c
net/mac80211/driver-ops.h
net/mac80211/mesh_sync.c
net/mac80211/trace.h

index fc589ba90a4862267c331dc2bf649d356c2fa80e..c9f39538ac17b4f13cd8e1b5ac3af72f27f88df3 100644 (file)
@@ -3169,6 +3169,12 @@ enum ieee80211_reconfig_type {
  *     required function.
  *     The callback can sleep.
  *
+ * @offset_tsf: Offset the TSF timer by the specified value in the
+ *     firmware/hardware.  Preferred to set_tsf as it avoids delay between
+ *     calling set_tsf() and hardware getting programmed, which will show up
+ *     as TSF delay. Is not a required function.
+ *     The callback can sleep.
+ *
  * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
  *     with other STAs in the IBSS. This is only used in IBSS mode. This
  *     function is optional if the firmware/hardware takes full care of
@@ -3549,6 +3555,8 @@ struct ieee80211_ops {
        u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        u64 tsf);
+       void (*offset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          s64 offset);
        void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
index 5d35c0f37bb7a86b9d964fd3095ded9db60fa980..bcec1240f41d90bec8b97a3bf52f8a8fcf918384 100644 (file)
@@ -556,9 +556,15 @@ static ssize_t ieee80211_if_parse_tsf(
                ret = kstrtoull(buf, 10, &tsf);
                if (ret < 0)
                        return ret;
-               if (tsf_is_delta)
-                       tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
-               if (local->ops->set_tsf) {
+               if (tsf_is_delta && local->ops->offset_tsf) {
+                       drv_offset_tsf(local, sdata, tsf_is_delta * tsf);
+                       wiphy_info(local->hw.wiphy,
+                                  "debugfs offset TSF by %018lld\n",
+                                  tsf_is_delta * tsf);
+               } else if (local->ops->set_tsf) {
+                       if (tsf_is_delta)
+                               tsf = drv_get_tsf(local, sdata) +
+                                     tsf_is_delta * tsf;
                        drv_set_tsf(local, sdata, tsf);
                        wiphy_info(local->hw.wiphy,
                                   "debugfs set TSF to %#018llx\n", tsf);
index c701b6438bd9e262b30e4ac941b1339f0e210835..bb886e7db47f1dcf409a4746d7ee47be8c679462 100644 (file)
@@ -215,6 +215,21 @@ void drv_set_tsf(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
+void drv_offset_tsf(struct ieee80211_local *local,
+                   struct ieee80211_sub_if_data *sdata,
+                   s64 offset)
+{
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return;
+
+       trace_drv_offset_tsf(local, sdata, offset);
+       if (local->ops->offset_tsf)
+               local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
+       trace_drv_return_void(local);
+}
+
 void drv_reset_tsf(struct ieee80211_local *local,
                   struct ieee80211_sub_if_data *sdata)
 {
index dea92c33b2caee3083e60667ceefd961d472f382..09f77e4a8a79d78f5722a85470bfa0862671e43e 100644 (file)
@@ -569,6 +569,9 @@ u64 drv_get_tsf(struct ieee80211_local *local,
 void drv_set_tsf(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
                 u64 tsf);
+void drv_offset_tsf(struct ieee80211_local *local,
+                   struct ieee80211_sub_if_data *sdata,
+                   s64 offset);
 void drv_reset_tsf(struct ieee80211_local *local,
                   struct ieee80211_sub_if_data *sdata);
 
index 64bc22ad94965c4615eaaa94aae02b45891204e7..22ca43c500e48d7d83ba431675a489b619256f7f 100644 (file)
@@ -70,9 +70,13 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
        }
        spin_unlock_bh(&ifmsh->sync_offset_lock);
 
-       tsf = drv_get_tsf(local, sdata);
-       if (tsf != -1ULL)
-               drv_set_tsf(local, sdata, tsf + tsfdelta);
+       if (local->ops->offset_tsf) {
+               drv_offset_tsf(local, sdata, tsfdelta);
+       } else {
+               tsf = drv_get_tsf(local, sdata);
+               if (tsf != -1ULL)
+                       drv_set_tsf(local, sdata, tsf + tsfdelta);
+       }
 }
 
 static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
index 37891fa67e9a5af36acdfb54a0553eaa2c5c82e4..92a47afaa989e6b63b494eacc23c56409f767642 100644 (file)
@@ -984,6 +984,32 @@ TRACE_EVENT(drv_set_tsf,
        )
 );
 
+TRACE_EVENT(drv_offset_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                s64 offset),
+
+       TP_ARGS(local, sdata, offset),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(s64, tsf_offset)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->tsf_offset = offset;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  " tsf offset:%lld",
+               LOCAL_PR_ARG, VIF_PR_ARG,
+               (unsigned long long)__entry->tsf_offset
+       )
+);
+
 DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata),