Merge tag 'for-linville-20131203' of git://github.com/kvalo/ath
Conflicts: drivers/net/wireless/ath/ath10k/htc.c drivers/net/wireless/ath/ath10k/mac.c
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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) {
|
||||
/*
|
||||
@@ -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)) {
|
||||
/*
|
||||
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user