// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/ #include <linux/rtnetlink.h> #include"core.h" #include"debug.h" #include"mac.h"
/* World regdom to be used in case default regd from fw is unavailable */ #define ATH12K_2GHZ_CH01_11 REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0) #define ATH12K_5GHZ_5150_5350 REG_RULE(5150 - 10, 5350 + 10, 80, 0, 30,\
NL80211_RRF_NO_IR) #define ATH12K_5GHZ_5725_5850 REG_RULE(5725 - 10, 5850 + 10, 80, 0, 30,\
NL80211_RRF_NO_IR)
regd = rcu_dereference_rtnl(hw->wiphy->regd); /* This can happen during wiphy registration where the previous * user request is received before we update the regd received * from firmware.
*/ if (!regd) returntrue;
ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Regulatory Notification received for %s\n", wiphy_name(wiphy));
if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG, "driver initiated regd update\n"); if (ah->state != ATH12K_HW_STATE_ON) return;
for_each_ar(ah, ar, i) {
ret = ath12k_reg_update_chan_list(ar, true); if (ret && ret != -EINVAL) {
ath12k_warn(ar->ab, "failed to update chan list for pdev %u, ret %d\n",
i, ret); break;
}
} return;
}
/* Currently supporting only General User Hints. Cell base user * hints to be handled later. * Hints from other sources like Core, Beacons are not expected for * self managed wiphy's
*/ if (!(request->initiator == NL80211_REGDOM_SET_BY_USER &&
request->user_reg_hint_type == NL80211_USER_REG_HINT_USER)) {
ath12k_warn(ar->ab, "Unexpected Regulatory event for this wiphy\n"); return;
}
if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Country Setting is not allowed\n"); return;
}
if (!ath12k_regdom_changes(hw, request->alpha2)) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Country is already set\n"); return;
}
int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
{ struct ieee80211_supported_band **bands; struct ath12k_wmi_scan_chan_list_arg *arg; struct ieee80211_channel *channel; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ath12k_wmi_channel_arg *ch; enum nl80211_band band; int num_channels = 0; int i, ret = 0;
if (ar->ah->state == ATH12K_HW_STATE_RESTARTING) return 0;
bands = hw->wiphy->bands; for (band = 0; band < NUM_NL80211_BANDS; band++) { if (!(ar->mac.sbands[band].channels && bands[band])) continue;
for (i = 0; i < bands[band]->n_channels; i++) { if (bands[band]->channels[i].flags &
IEEE80211_CHAN_DISABLED) continue; /* Skip Channels that are not in current radio's range */ if (bands[band]->channels[i].center_freq <
KHZ_TO_MHZ(ar->freq_range.start_freq) ||
bands[band]->channels[i].center_freq >
KHZ_TO_MHZ(ar->freq_range.end_freq)) continue;
num_channels++;
}
}
if (!num_channels) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG, "pdev is not supported for this country\n"); return -EINVAL;
}
for (band = 0; band < NUM_NL80211_BANDS; band++) { if (!(ar->mac.sbands[band].channels && bands[band])) continue;
for (i = 0; i < bands[band]->n_channels; i++) {
channel = &bands[band]->channels[i];
if (channel->flags & IEEE80211_CHAN_DISABLED) continue;
/* Skip Channels that are not in current radio's range */ if (bands[band]->channels[i].center_freq <
KHZ_TO_MHZ(ar->freq_range.start_freq) ||
bands[band]->channels[i].center_freq >
KHZ_TO_MHZ(ar->freq_range.end_freq)) continue;
/* TODO: Set to true/false based on some condition? */
ch->allow_ht = true;
ch->allow_vht = true;
ch->allow_he = true;
time_left = wait_for_completion_timeout(&ar->regd_update_completed,
ATH12K_REG_UPDATE_TIMEOUT_HZ); if (time_left == 0) {
ath12k_warn(ab, "Timeout while waiting for regulatory update"); /* Even though timeout has occurred, still continue since at least boot * time data would be there to process
*/
}
/* Possible that due to reg change, current limits for supported * frequency changed. Update it. As a first step, reset the * previous values and then compute and set the new values.
*/
ar->freq_range.start_freq = 0;
ar->freq_range.end_freq = 0;
if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) { if (ab->hw_params->single_pdev_only) {
phy_id = ar->pdev->cap.band[WMI_HOST_WLAN_2GHZ_CAP].phy_id;
reg_cap = &ab->hal_reg_cap[phy_id];
}
/* If one of the radios within ah has already updated the regd for * the wiphy, then avoid setting regd again
*/ if (ah->regd_updated) return 0;
/* firmware provides reg rules which are similar for 2 GHz and 5 GHz * pdev but 6 GHz pdev has superset of all rules including rules for * all bands, we prefer 6 GHz pdev's rules to be used for setup of * the wiphy regd. * If 6 GHz pdev was part of the ath12k_hw, wait for the 6 GHz pdev, * else pick the first pdev which calls this function and use its * regd to update global hw regd. * The regd_updated flag set at the end will not allow any further * updates.
*/ if (ah->use_6ghz_regd && !ar->supports_6ghz) return 0;
pdev_id = ar->pdev_idx;
spin_lock_bh(&ab->base_lock);
if (init) { /* Apply the regd received during init through * WMI_REG_CHAN_LIST_CC event. In case of failure to * receive the regd, initialize with a default world * regulatory.
*/ if (ab->default_regd[pdev_id]) {
regd = ab->default_regd[pdev_id];
} else {
ath12k_warn(ab, "failed to receive default regd during init\n");
regd = (struct ieee80211_regdomain *)&ath12k_world_regd;
}
} else {
regd = ab->new_regd[pdev_id];
}
if (!regd) {
ret = -EINVAL;
spin_unlock_bh(&ab->base_lock); goto err;
}
/* Reset start and end frequency for each band
*/
ab->reg_freq_5ghz.start_freq = INT_MAX;
ab->reg_freq_5ghz.end_freq = 0;
ab->reg_freq_2ghz.start_freq = INT_MAX;
ab->reg_freq_2ghz.end_freq = 0;
ab->reg_freq_6ghz.start_freq = INT_MAX;
ab->reg_freq_6ghz.end_freq = 0;
/* Update reg_rules[] below. Firmware is expected to * send these rules in order(2G rules first and then 5G)
*/ for (; i < num_rules; i++) { if (reg_info->num_2g_reg_rules &&
(i < reg_info->num_2g_reg_rules)) {
reg_rule = reg_info->reg_rules_2g_ptr + i;
max_bw = min_t(u16, reg_rule->max_bw,
reg_info->max_bw_2g);
flags = ath12k_get_bw_reg_flags(reg_info->max_bw_2g);
ath12k_reg_update_freq_range(&ab->reg_freq_2ghz, reg_rule);
} elseif (reg_info->num_5g_reg_rules &&
(j < reg_info->num_5g_reg_rules)) {
reg_rule = reg_info->reg_rules_5g_ptr + j++;
max_bw = min_t(u16, reg_rule->max_bw,
reg_info->max_bw_5g);
/* FW doesn't pass NL80211_RRF_AUTO_BW flag for * BW Auto correction, we can enable this by default * for all 5G rules here. The regulatory core performs * BW correction if required and applies flags as * per other BW rule flags we pass from here
*/
flags = NL80211_RRF_AUTO_BW |
ath12k_get_bw_reg_flags(reg_info->max_bw_5g);
ath12k_reg_update_freq_range(&ab->reg_freq_5ghz, reg_rule);
} elseif (reg_info->is_ext_reg_event && reg_6ghz_number &&
(k < reg_6ghz_number)) {
reg_rule = reg_rule_6ghz + k++;
max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
flags = NL80211_RRF_AUTO_BW |
ath12k_get_bw_reg_flags(max_bw_6ghz); if (reg_rule->psd_flag)
flags |= NL80211_RRF_PSD;
ath12k_reg_update_freq_range(&ab->reg_freq_6ghz, reg_rule);
} else { break;
}
ath12k_reg_update_rule(new_regd->reg_rules + i,
reg_rule->start_freq,
reg_rule->end_freq, max_bw,
reg_rule->ant_gain, reg_rule->reg_power,
reg_rule->psd_eirp, flags);
/* Update dfs cac timeout if the dfs domain is ETSI and the * new rule covers weather radar band. * Default value of '0' corresponds to 60s timeout, so no * need to update that for other rules.
*/ if (flags & NL80211_RRF_DFS &&
reg_info->dfs_region == ATH12K_DFS_REG_ETSI &&
(reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_LOW &&
reg_rule->start_freq < ETSI_WEATHER_RADAR_BAND_HIGH)){
ath12k_reg_update_weather_radar_band(ab, new_regd,
reg_rule, &i,
flags, max_bw); continue;
}
ret = ath12k_regd_update(ar, false); if (ret) { /* Firmware has already moved to the new regd. We need * to maintain channel consistency across FW, Host driver * and userspace. Hence as a fallback mechanism we can set * the prev or default country code to the firmware.
*/ /* TODO: Implement Fallback Mechanism */
}
}
void ath12k_reg_reset_reg_info(struct ath12k_reg_info *reg_info)
{
u8 i, j;
if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { /* In case of failure to set the requested country, * firmware retains the current regd. We print a failure info * and return from here.
*/
ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n"); return ATH12K_REG_STATUS_DROP;
}
if (pdev_idx >= ab->num_radios) { /* Process the event for phy0 only if single_pdev_only * is true. If pdev_idx is valid but not 0, discard the * event. Otherwise, it goes to fallback.
*/ if (ab->hw_params->single_pdev_only &&
pdev_idx < ab->hw_params->num_rxdma_per_pdev) return ATH12K_REG_STATUS_DROP; else return ATH12K_REG_STATUS_FALLBACK;
}
/* Avoid multiple overwrites to default regd, during core * stop-start after mac registration.
*/ if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
!memcmp(ab->default_regd[pdev_idx]->alpha2,
reg_info->alpha2, 2)) return ATH12K_REG_STATUS_DROP;
regd = ath12k_reg_build_regd(ab, reg_info, vdev_type, power_type); if (!regd) return -EINVAL;
spin_lock_bh(&ab->base_lock); if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) { /* Once mac is registered, ar is valid and all CC events from * firmware is considered to be received due to user requests * currently. * Free previously built regd before assigning the newly * generated regd to ar. NULL pointer handling will be * taken care by kfree itself.
*/
ar = ab->pdevs[pdev_idx].ar;
kfree(ab->new_regd[pdev_idx]);
ab->new_regd[pdev_idx] = regd;
queue_work(ab->workqueue, &ar->regd_update_work);
} else { /* Multiple events for the same *ar is not expected. But we * can still clear any previously stored default_regd if we * are receiving this event for the same radio by mistake. * NULL pointer handling will be taken care by kfree itself.
*/
kfree(ab->default_regd[pdev_idx]); /* This regd would be applied during mac registration */
ab->default_regd[pdev_idx] = regd;
}
ab->dfs_region = reg_info->dfs_region;
spin_unlock_bh(&ab->base_lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.