diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 334 |
1 files changed, 293 insertions, 41 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f23d61fda243..ce9ef3499ecb 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -92,7 +92,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); - INIT_COMPLETION(ar->install_key_done); + reinit_completion(&ar->install_key_done); ret = ath10k_send_key(arvif, key, cmd, macaddr); if (ret) @@ -322,12 +322,16 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) lockdep_assert_held(&ar->conf_mutex); ret = ath10k_wmi_peer_create(ar, vdev_id, addr); - if (ret) + if (ret) { + ath10k_warn("Failed to create wmi peer: %i\n", ret); return ret; + } ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); - if (ret) + if (ret) { + ath10k_warn("Failed to wait for created wmi peer: %i\n", ret); return ret; + } return 0; } @@ -438,7 +442,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) lockdep_assert_held(&ar->conf_mutex); - INIT_COMPLETION(ar->vdev_setup_done); + reinit_completion(&ar->vdev_setup_done); arg.vdev_id = arvif->vdev_id; arg.dtim_period = arvif->dtim_period; @@ -450,15 +454,19 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.channel.mode = chan_to_phymode(&conf->chandef); - arg.channel.min_power = channel->max_power * 3; - arg.channel.max_power = channel->max_power * 4; - arg.channel.max_reg_power = channel->max_reg_power * 4; - arg.channel.max_antenna_gain = channel->max_antenna_gain; + arg.channel.min_power = 0; + arg.channel.max_power = channel->max_power * 2; + arg.channel.max_reg_power = channel->max_reg_power * 2; + arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; arg.ssid_len = arvif->u.ap.ssid_len; arg.hidden_ssid = arvif->u.ap.hidden_ssid; + + /* For now allow DFS for AP mode */ + arg.channel.chan_radar = + !!(channel->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { arg.ssid = arvif->vif->bss_conf.ssid; arg.ssid_len = arvif->vif->bss_conf.ssid_len; @@ -491,7 +499,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) lockdep_assert_held(&ar->conf_mutex); - INIT_COMPLETION(ar->vdev_setup_done); + reinit_completion(&ar->vdev_setup_done); ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { @@ -516,6 +524,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) lockdep_assert_held(&ar->conf_mutex); + if (!ar->monitor_present) { + ath10k_warn("mac montor stop -- monitor is not present\n"); + return -EINVAL; + } + arg.vdev_id = vdev_id; arg.channel.freq = channel->center_freq; arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; @@ -523,11 +536,13 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) /* TODO setup this dynamically, what in case we don't have any vifs? */ arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); + arg.channel.chan_radar = + !!(channel->flags & IEEE80211_CHAN_RADAR); - arg.channel.min_power = channel->max_power * 3; - arg.channel.max_power = channel->max_power * 4; - arg.channel.max_reg_power = channel->max_reg_power * 4; - arg.channel.max_antenna_gain = channel->max_antenna_gain; + arg.channel.min_power = 0; + arg.channel.max_power = channel->max_power * 2; + arg.channel.max_reg_power = channel->max_reg_power * 2; + arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { @@ -566,6 +581,16 @@ static int ath10k_monitor_stop(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); + if (!ar->monitor_present) { + ath10k_warn("mac montor stop -- monitor is not present\n"); + return -EINVAL; + } + + if (!ar->monitor_enabled) { + ath10k_warn("mac montor stop -- monitor is not enabled\n"); + return -EINVAL; + } + ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); if (ret) ath10k_warn("Monitor vdev down failed: %d\n", ret); @@ -647,6 +672,107 @@ static int ath10k_monitor_destroy(struct ath10k *ar) return ret; } +static int ath10k_start_cac(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + + ret = ath10k_monitor_create(ar); + if (ret) { + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + return ret; + } + + ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); + if (ret) { + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ath10k_monitor_destroy(ar); + return ret; + } + + ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", + ar->monitor_vdev_id); + + return 0; +} + +static int ath10k_stop_cac(struct ath10k *ar) +{ + lockdep_assert_held(&ar->conf_mutex); + + /* CAC is not running - do nothing */ + if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) + return 0; + + ath10k_monitor_stop(ar); + ath10k_monitor_destroy(ar); + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + + ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); + + return 0; +} + +static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state) +{ + switch (dfs_state) { + case NL80211_DFS_USABLE: + return "USABLE"; + case NL80211_DFS_UNAVAILABLE: + return "UNAVAILABLE"; + case NL80211_DFS_AVAILABLE: + return "AVAILABLE"; + default: + WARN_ON(1); + return "bug"; + } +} + +static void ath10k_config_radar_detection(struct ath10k *ar) +{ + struct ieee80211_channel *chan = ar->hw->conf.chandef.chan; + bool radar = ar->hw->conf.radar_enabled; + bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR); + enum nl80211_dfs_state dfs_state = chan->dfs_state; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n", + chan->center_freq, radar, chan_radar, + ath10k_dfs_state(dfs_state)); + + /* + * It's safe to call it even if CAC is not started. + * This call here guarantees changing channel, etc. will stop CAC. + */ + ath10k_stop_cac(ar); + + if (!radar) + return; + + if (!chan_radar) + return; + + if (dfs_state != NL80211_DFS_USABLE) + return; + + ret = ath10k_start_cac(ar); + if (ret) { + /* + * Not possible to start CAC on current channel so starting + * radiation is not allowed, make this channel DFS_UNAVAILABLE + * by indicating that radar was detected. + */ + ath10k_warn("failed to start CAC (%d)\n", ret); + ieee80211_radar_detected(ar->hw); + } +} + static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -1356,14 +1482,17 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->ht40plus = !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS); + ch->chan_radar = + !!(channel->flags & IEEE80211_CHAN_RADAR); + passive = channel->flags & IEEE80211_CHAN_NO_IR; ch->passive = passive; ch->freq = channel->center_freq; - ch->min_power = channel->max_power * 3; - ch->max_power = channel->max_power * 4; - ch->max_reg_power = channel->max_reg_power * 4; - ch->max_antenna_gain = channel->max_antenna_gain; + ch->min_power = 0; + ch->max_power = channel->max_power * 2; + ch->max_reg_power = channel->max_reg_power * 2; + ch->max_antenna_gain = channel->max_antenna_gain * 2; ch->reg_class_id = 0; /* FIXME */ /* FIXME: why use only legacy modes, why not any @@ -1423,9 +1552,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath10k *ar = hw->priv; + bool result; ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { + ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", + request->dfs_region); + result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, + request->dfs_region); + if (!result) + ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n", + request->dfs_region); + } + mutex_lock(&ar->conf_mutex); if (ar->state == ATH10K_STATE_ON) ath10k_regd_update(ar); @@ -1666,7 +1806,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) } spin_lock_bh(&ar->data_lock); - INIT_COMPLETION(ar->offchan_tx_completed); + reinit_completion(&ar->offchan_tx_completed); ar->offchan_tx_skb = skb; spin_unlock_bh(&ar->data_lock); @@ -1714,8 +1854,10 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) break; ret = ath10k_wmi_mgmt_tx(ar, skb); - if (ret) + if (ret) { ath10k_warn("wmi mgmt_tx failed (%d)\n", ret); + ieee80211_free_txskb(ar->hw, skb); + } } } @@ -1889,6 +2031,7 @@ void ath10k_halt(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + ath10k_stop_cac(ar); del_timer_sync(&ar->scan.timeout); ath10k_offchan_tx_purge(ar); ath10k_mgmt_over_wmi_tx_purge(ar); @@ -1943,7 +2086,7 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", ret); - ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0); + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); if (ret) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); @@ -1998,15 +2141,40 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) struct ath10k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; int ret = 0; + u32 param; mutex_lock(&ar->conf_mutex); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ath10k_dbg(ATH10K_DBG_MAC, "mac config channel %d mhz\n", - conf->chandef.chan->center_freq); + ath10k_dbg(ATH10K_DBG_MAC, + "mac config channel %d mhz flags 0x%x\n", + conf->chandef.chan->center_freq, + conf->chandef.chan->flags); + spin_lock_bh(&ar->data_lock); ar->rx_channel = conf->chandef.chan; spin_unlock_bh(&ar->data_lock); + + ath10k_config_radar_detection(ar); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n", + hw->conf.power_level); + + param = ar->wmi.pdev_param->txpower_limit2g; + ret = ath10k_wmi_pdev_set_param(ar, param, + hw->conf.power_level * 2); + if (ret) + ath10k_warn("mac failed to set 2g txpower %d (%d)\n", + hw->conf.power_level, ret); + + param = ar->wmi.pdev_param->txpower_limit5g; + ret = ath10k_wmi_pdev_set_param(ar, param, + hw->conf.power_level * 2); + if (ret) + ath10k_warn("mac failed to set 5g txpower %d (%d)\n", + hw->conf.power_level, ret); } if (changed & IEEE80211_CONF_CHANGE_PS) @@ -2049,6 +2217,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->vif = vif; INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); + INIT_LIST_HEAD(&arvif->list); if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) { ath10k_warn("Only one monitor interface allowed\n"); @@ -2265,8 +2434,14 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; ar->filter_flags = *total_flags; + /* Monitor must not be started if it wasn't created first. + * Promiscuous mode may be started on a non-monitor interface - in + * such case the monitor vdev is not created so starting the + * monitor makes no sense. Since ath10k uses no special RX filters + * (only BSS filter in STA mode) there's no need for any special + * action here. */ if ((ar->filter_flags & FIF_PROMISC_IN_BSS) && - !ar->monitor_enabled) { + !ar->monitor_enabled && ar->monitor_present) { ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n", ar->monitor_vdev_id); @@ -2274,7 +2449,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, if (ret) ath10k_warn("Unable to start monitor mode\n"); } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && - ar->monitor_enabled) { + ar->monitor_enabled && ar->monitor_present) { ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n", ar->monitor_vdev_id); @@ -2360,8 +2535,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, info->bssid); if (ret) - ath10k_warn("Failed to add peer: %pM for VDEV: %d\n", - info->bssid, arvif->vdev_id); + ath10k_warn("Failed to add peer %pM for vdev %d when changin bssid: %i\n", + info->bssid, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) { /* @@ -2476,8 +2651,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, goto exit; } - INIT_COMPLETION(ar->scan.started); - INIT_COMPLETION(ar->scan.completed); + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); ar->scan.in_progress = true; ar->scan.aborting = false; ar->scan.is_roc = false; @@ -2542,6 +2717,44 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, + struct ath10k_vif *arvif, + enum set_key_cmd cmd, + struct ieee80211_key_conf *key) +{ + u32 vdev_param = arvif->ar->wmi.vdev_param->def_keyid; + int ret; + + /* 10.1 firmware branch requires default key index to be set to group + * key index after installing it. Otherwise FW/HW Txes corrupted + * frames with multi-vif APs. This is not required for main firmware + * branch (e.g. 636). + * + * FIXME: This has been tested only in AP. It remains unknown if this + * is required for multi-vif STA interfaces on 10.1 */ + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP40) + return; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP104) + return; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + return; + + if (cmd != SET_KEY) + return; + + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + key->keyidx); + if (ret) + ath10k_warn("failed to set group key as default key: %d\n", + ret); +} + static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) @@ -2603,6 +2816,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, goto exit; } + ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key); + spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr); if (peer && cmd == SET_KEY) @@ -2643,8 +2858,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to add peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); + ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", + sta->addr, arvif->vdev_id, ret); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { /* @@ -2832,9 +3047,9 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, goto exit; } - INIT_COMPLETION(ar->scan.started); - INIT_COMPLETION(ar->scan.completed); - INIT_COMPLETION(ar->scan.on_channel); + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + reinit_completion(&ar->scan.on_channel); ar->scan.in_progress = true; ar->scan.aborting = false; ar->scan.is_roc = true; @@ -3249,12 +3464,36 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = { }, }; -static const struct ieee80211_iface_combination ath10k_if_comb = { - .limits = ath10k_if_limits, - .n_limits = ARRAY_SIZE(ath10k_if_limits), - .max_interfaces = 8, - .num_different_channels = 1, - .beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED +static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = { + { + .max = 8, + .types = BIT(NL80211_IFTYPE_AP) + }, +}; +#endif + +static const struct ieee80211_iface_combination ath10k_if_comb[] = { + { + .limits = ath10k_if_limits, + .n_limits = ARRAY_SIZE(ath10k_if_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + }, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED + { + .limits = ath10k_if_dfs_limits, + .n_limits = ARRAY_SIZE(ath10k_if_dfs_limits), + .max_interfaces = 8, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), + } +#endif }; static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) @@ -3478,11 +3717,21 @@ int ath10k_mac_register(struct ath10k *ar) */ ar->hw->queues = 4; - ar->hw->wiphy->iface_combinations = &ath10k_if_comb; - ar->hw->wiphy->n_iface_combinations = 1; + ar->hw->wiphy->iface_combinations = ath10k_if_comb; + ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb); ar->hw->netdev_features = NETIF_F_HW_CSUM; + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { + /* Init ath dfs pattern detector */ + ar->ath_common.debug_mask = ATH_DBG_DFS; + ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common, + NL80211_DFS_UNSET); + + if (!ar->dfs_detector) + ath10k_warn("dfs pattern detector init failed\n"); + } + ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { @@ -3518,6 +3767,9 @@ void ath10k_mac_unregister(struct ath10k *ar) { ieee80211_unregister_hw(ar->hw); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) + ar->dfs_detector->exit(ar->dfs_detector); + kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); |