diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_i.h b/drivers/net/wireless/virtual/mac80211_hwsim_i.h index d345595ca588..6b2a5dccb106 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_i.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim_i.h @@ -128,6 +128,11 @@ struct mac80211_hwsim_data { extern spinlock_t hwsim_radio_lock; extern struct list_head hwsim_radios; +ktime_t mac80211_hwsim_tsf_to_boottime(struct mac80211_hwsim_data *data, + u64 tsf); +u64 mac80211_hwsim_boottime_to_tsf(struct mac80211_hwsim_data *data, + ktime_t ts); + u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c index ba2aa09b37cb..c6d1f841c04d 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c @@ -1216,12 +1216,18 @@ static inline u64 mac80211_hwsim_get_sim_tsf(void) return ktime_to_us(ktime_get_boottime()); } -static ktime_t mac80211_hwsim_tsf_to_boottime(struct mac80211_hwsim_data *data, - u64 tsf) +ktime_t mac80211_hwsim_tsf_to_boottime(struct mac80211_hwsim_data *data, + u64 tsf) { return us_to_ktime(tsf - data->tsf_offset); } +u64 mac80211_hwsim_boottime_to_tsf(struct mac80211_hwsim_data *data, + ktime_t ts) +{ + return ktime_to_us(ts + data->tsf_offset); +} + u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -2045,12 +2051,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, * on channel 6 or channel 149, unless a ROC is in progress (for * USD use cases). */ - if (data->nan.curr_dw_band == NL80211_BAND_2GHZ) - channel = ieee80211_get_channel(hw->wiphy, 2437); - else if (data->nan.curr_dw_band == NL80211_BAND_5GHZ) - channel = ieee80211_get_channel(hw->wiphy, 5745); - else - channel = NULL; + channel = data->nan.channel; if (WARN_ON(!channel)) { ieee80211_free_txskb(hw, skb); @@ -5451,8 +5452,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED | NAN_DEV_CAPA_NDPE_SUPPORTED; - hrtimer_setup(&data->nan.timer, mac80211_hwsim_nan_dw_start, - CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT); + hrtimer_setup(&data->nan.slot_timer, + mac80211_hwsim_nan_slot_timer, + CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT); } data->if_combination.radar_detect_widths = diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c index 393ea70ee087..aa4aef0920f4 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c @@ -6,63 +6,132 @@ #include "mac80211_hwsim_i.h" +/* Defined as the lower 23 bits being zero */ +#define DW0_TSF_MASK GENMASK(22, 0) + +/* DWs are repeated every 512 TUs */ +#define DWST_TU 512 +#define DWST_TSF_MASK (ieee80211_tu_to_usec(DWST_TU) - 1) + +#define SLOT_TU 16 +#define SLOT_TSF_MASK (ieee80211_tu_to_usec(DWST_TU) - 1) + +/* The 2.4 GHz DW is at the start, the 5 GHz is in slot 8 (after 128 TUs) */ +#define DW_5G_OFFSET_TU 128 + +#define SLOT_24GHZ_DW 0 +#define SLOT_5GHZ_DW (DW_5G_OFFSET_TU / SLOT_TU) + +/* The special DW0 happens every 16 DWSTs (8192 TUs) */ +static_assert(16 * DWST_TU * 1024 == 8192 * 1024); +static_assert(DW0_TSF_MASK + 1 == 8192 * 1024); + static u8 hwsim_nan_cluster_id[ETH_ALEN]; +static u64 hwsim_nan_get_timer_tsf(struct mac80211_hwsim_data *data) +{ + ktime_t expires = hrtimer_get_expires(&data->nan.slot_timer); + + return mac80211_hwsim_boottime_to_tsf(data, expires); +} + +static u8 hwsim_nan_slot_from_tsf(u64 tsf) +{ + return (tsf & DWST_TSF_MASK) / ieee80211_tu_to_usec(SLOT_TU); +} + +static void +mac80211_hwsim_nan_schedule_slot(struct mac80211_hwsim_data *data, u8 slot) +{ + u64 tsf = hwsim_nan_get_timer_tsf(data); + + /* Only called by mac80211_hwsim_nan_dw_timer from softirq context */ + lockdep_assert_in_softirq(); + + tsf &= ~DWST_TSF_MASK; + tsf += ieee80211_tu_to_usec(slot * SLOT_TU); + + hrtimer_set_expires(&data->nan.slot_timer, + mac80211_hwsim_tsf_to_boottime(data, tsf)); +} + +static void +mac80211_hwsim_nan_exec_state_transitions(struct mac80211_hwsim_data *data) +{ + /* + * Handle NAN role and state transitions at the end of the DW period + * in accordance to Wi-Fi Aware version 4.0 section 3.3.7 point 2, i.e. + * end of 5 GHz DW if enabled else at the end of the 2.4 GHz DW. + * + * TODO: Implement + */ +} + enum hrtimer_restart -mac80211_hwsim_nan_dw_start(struct hrtimer *timer) +mac80211_hwsim_nan_slot_timer(struct hrtimer *timer) { struct mac80211_hwsim_data *data = container_of(timer, struct mac80211_hwsim_data, - nan.timer); + nan.slot_timer); struct ieee80211_hw *hw = data->hw; - u64 orig_tsf = mac80211_hwsim_get_tsf(hw, NULL), tsf = orig_tsf; - u32 dw_int = 512 * 1024; - u64 until_dw; + struct ieee80211_channel *notify_dw_chan = NULL; + u64 tsf = hwsim_nan_get_timer_tsf(data); + u8 slot = hwsim_nan_slot_from_tsf(tsf); + bool dwst_of_dw0 = false; + bool dw_end = false; if (!data->nan.device_vif) return HRTIMER_NORESTART; - if (data->nan.bands & BIT(NL80211_BAND_5GHZ)) { - if (data->nan.curr_dw_band == NL80211_BAND_2GHZ) { - dw_int = 128 * 1024; - data->nan.curr_dw_band = NL80211_BAND_5GHZ; - } else if (data->nan.curr_dw_band == NL80211_BAND_5GHZ) { - data->nan.curr_dw_band = NL80211_BAND_2GHZ; + if ((tsf & DW0_TSF_MASK & ~DWST_TSF_MASK) == 0) + dwst_of_dw0 = true; + + + switch (slot) { + case SLOT_24GHZ_DW: + wiphy_dbg(data->hw->wiphy, "Start of 2.4 GHz DW, is DW0=%d\n", + dwst_of_dw0); + data->nan.channel = ieee80211_get_channel(hw->wiphy, 2437); + break; + + case SLOT_24GHZ_DW + 1: + if (!(data->nan.bands & BIT(NL80211_BAND_5GHZ))) { + notify_dw_chan = ieee80211_get_channel(hw->wiphy, 2437); + dw_end = true; + } else { + notify_dw_chan = ieee80211_get_channel(hw->wiphy, 5745); } + break; + + case SLOT_5GHZ_DW: + if (data->nan.bands & BIT(NL80211_BAND_5GHZ)) { + wiphy_dbg(data->hw->wiphy, "Start of 5 GHz DW\n"); + data->nan.channel = + ieee80211_get_channel(hw->wiphy, 5745); + } + break; + + case SLOT_5GHZ_DW + 1: + if (data->nan.bands & BIT(NL80211_BAND_5GHZ)) { + notify_dw_chan = + ieee80211_get_channel(hw->wiphy, 2437); + dw_end = true; + } + break; } - until_dw = dw_int - do_div(tsf, dw_int); + if (dw_end) + mac80211_hwsim_nan_exec_state_transitions(data); - /* The timer might fire just before the actual DW, in which case - * update the timeout to the actual next DW - */ - if (until_dw < dw_int / 2) - until_dw += dw_int; - - /* The above do_div() call directly modifies the 'tsf' variable, thus, - * use a copy so that the print below would show the original TSF. - */ - wiphy_debug(hw->wiphy, - "%s: tsf=%llx, curr_dw_band=%u, next_dw=%llu\n", - __func__, orig_tsf, data->nan.curr_dw_band, - until_dw); - - hrtimer_forward_now(&data->nan.timer, - ns_to_ktime(until_dw * NSEC_PER_USEC)); - - if (data->nan.notify_dw) { - struct ieee80211_channel *ch; + if (data->nan.notify_dw && notify_dw_chan) { struct wireless_dev *wdev = ieee80211_vif_to_wdev(data->nan.device_vif); - if (data->nan.curr_dw_band == NL80211_BAND_5GHZ) - ch = ieee80211_get_channel(hw->wiphy, 5745); - else - ch = ieee80211_get_channel(hw->wiphy, 2437); - - cfg80211_next_nan_dw_notif(wdev, ch, GFP_ATOMIC); + cfg80211_next_nan_dw_notif(wdev, notify_dw_chan, GFP_ATOMIC); } + mac80211_hwsim_nan_schedule_slot(data, slot + 1); + return HRTIMER_RESTART; } @@ -71,9 +140,6 @@ int mac80211_hwsim_nan_start(struct ieee80211_hw *hw, struct cfg80211_nan_conf *conf) { struct mac80211_hwsim_data *data = hw->priv; - u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); - u32 dw_int = 512 * 1000; - u64 until_dw = dw_int - do_div(tsf, dw_int); struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); if (vif->type != NL80211_IFTYPE_NAN) @@ -85,13 +151,11 @@ int mac80211_hwsim_nan_start(struct ieee80211_hw *hw, /* set this before starting the timer, as preemption might occur */ data->nan.device_vif = vif; data->nan.bands = conf->bands; - data->nan.curr_dw_band = NL80211_BAND_2GHZ; + data->nan.channel = ieee80211_get_channel(hw->wiphy, 2437); - wiphy_debug(hw->wiphy, "nan_started, next_dw=%llu\n", - until_dw); - - hrtimer_start(&data->nan.timer, - ns_to_ktime(until_dw * NSEC_PER_USEC), + /* Just run this "soon" and start in a random schedule position */ + hrtimer_start(&data->nan.slot_timer, + ns_to_ktime(10 * NSEC_PER_USEC), HRTIMER_MODE_REL_SOFT); if (!is_zero_ether_addr(conf->cluster_id) && @@ -125,7 +189,7 @@ int mac80211_hwsim_nan_stop(struct ieee80211_hw *hw, data->nan.device_vif != vif) return -EINVAL; - hrtimer_cancel(&data->nan.timer); + hrtimer_cancel(&data->nan.slot_timer); data->nan.device_vif = NULL; spin_lock_bh(&hwsim_radio_lock); @@ -159,10 +223,8 @@ int mac80211_hwsim_nan_change_config(struct ieee80211_hw *hw, wiphy_debug(hw->wiphy, "nan_config_changed: changes=0x%x\n", changes); /* Handle only the changes we care about for simulation purposes */ - if (changes & CFG80211_NAN_CONF_CHANGED_BANDS) { + if (changes & CFG80211_NAN_CONF_CHANGED_BANDS) data->nan.bands = conf->bands; - data->nan.curr_dw_band = NL80211_BAND_2GHZ; - } if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG) data->nan.notify_dw = conf->enable_dw_notification; diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h index eac64ac37589..e86e7f9e9a3c 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h @@ -11,13 +11,15 @@ struct mac80211_hwsim_nan_data { struct ieee80211_vif *device_vif; u8 bands; - enum nl80211_band curr_dw_band; - struct hrtimer timer; + /* Current channel of the NAN device */ + struct ieee80211_channel *channel; + + struct hrtimer slot_timer; bool notify_dw; }; enum hrtimer_restart -mac80211_hwsim_nan_dw_start(struct hrtimer *timer); +mac80211_hwsim_nan_slot_timer(struct hrtimer *timer); int mac80211_hwsim_nan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,