regd = rcu_dereference_rtnl(ar->hw->wiphy->regd); /* This can happen during wiphy registration where the previous *userrequestisreceivedbeforeweupdatetheregdreceived *fromfirmware.
*/ if (!regd) returntrue;
ath11k_dbg(ar->ab, ATH11K_DBG_REG, "Regulatory Notification received for %s\n", wiphy_name(wiphy));
if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
ath11k_dbg(ar->ab, ATH11K_DBG_REG, "driver initiated regd update\n"); if (ar->state != ATH11K_STATE_ON) return;
ret = ath11k_reg_update_chan_list(ar, true); if (ret)
ath11k_warn(ar->ab, "failed to update channel list: %d\n", ret);
return;
}
/* Currently supporting only General User Hints. Cell base user *hintstobehandledlater. *HintsfromothersourceslikeCore,Beaconsarenotexpectedfor *selfmanagedwiphy's
*/ if (!(request->initiator == NL80211_REGDOM_SET_BY_USER &&
request->user_reg_hint_type == NL80211_USER_REG_HINT_USER)) {
ath11k_warn(ar->ab, "Unexpected Regulatory event for this wiphy\n"); return;
}
if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) {
ath11k_dbg(ar->ab, ATH11K_DBG_REG, "Country Setting is not allowed\n"); return;
}
if (!ath11k_regdom_changes(ar, request->alpha2)) {
ath11k_dbg(ar->ab, ATH11K_DBG_REG, "Country is already set\n"); return;
}
/* Set the country code to the firmware and will receive *theWMI_REG_CHAN_LIST_CCEVENTforupdatingthe *reginfo
*/ if (ar->ab->hw_params.current_cc_support) {
memcpy(&ar->alpha2, request->alpha2, 2);
ret = ath11k_reg_set_cc(ar); if (ret)
ath11k_warn(ar->ab, "failed set current country code: %d\n", ret);
} else {
init_country_param.flags = ALPHA_IS_SET;
memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2);
init_country_param.cc_info.alpha2[2] = 0;
ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); if (ret)
ath11k_warn(ar->ab, "INIT Country code set to fw failed : %d\n", ret);
}
/* The caller should have checked error conditions */
memcpy(regd_copy, regd_orig, sizeof(*regd_orig));
for (i = 0; i < regd_orig->n_reg_rules; i++)
memcpy(®d_copy->reg_rules[i], ®d_orig->reg_rules[i], sizeof(struct ieee80211_reg_rule));
}
int ath11k_regd_update(struct ath11k *ar)
{ struct ieee80211_regdomain *regd, *regd_copy = NULL; int ret, regd_len, pdev_id; struct ath11k_base *ab;
ab = ar->ab;
pdev_id = ar->pdev_idx;
spin_lock_bh(&ab->base_lock);
/* Prefer the latest regd update over default if it's available */ if (ab->new_regd[pdev_id]) {
regd = ab->new_regd[pdev_id];
} else { /* Apply the regd received during init through *WMI_REG_CHAN_LIST_CCevent.Incaseoffailureto *receivetheregd,initializewithadefaultworld *regulatory.
*/ if (ab->default_regd[pdev_id]) {
regd = ab->default_regd[pdev_id];
} else {
ath11k_warn(ab, "failed to receive default regd during init\n");
regd = (struct ieee80211_regdomain *)&ath11k_world_regd;
}
}
if (!regd) {
ret = -EINVAL;
spin_unlock_bh(&ab->base_lock); goto err;
}
/* Find the number of intersecting rules to allocate new regd memory */ for (i = 0; i < num_old_regd_rules; i++) {
old_rule = default_regd->reg_rules + i; for (j = 0; j < num_curr_regd_rules; j++) {
curr_rule = curr_regd->reg_rules + j;
if (ath11k_reg_can_intersect(old_rule, curr_rule))
num_new_regd_rules++;
}
}
/* We set the new country and dfs region directly and only trim *thefreq,power,antennagainbyintersectingwiththe *defaultregdomain.AlsoMAXofthedfscactimeoutisselected.
*/
new_regd->n_reg_rules = num_new_regd_rules;
memcpy(new_regd->alpha2, curr_regd->alpha2, sizeof(new_regd->alpha2));
new_regd->dfs_region = curr_regd->dfs_region;
new_rule = new_regd->reg_rules;
for (i = 0, k = 0; i < num_old_regd_rules; i++) {
old_rule = default_regd->reg_rules + i; for (j = 0; j < num_curr_regd_rules; j++) {
curr_rule = curr_regd->reg_rules + j;
if (intersect) {
default_regd = ab->default_regd[reg_info->phy_id];
/* Get a new regd by intersecting the received regd with *ourdefaultregd.
*/
new_regd = ath11k_regd_intersect(default_regd, tmp_regd);
kfree(tmp_regd); if (!new_regd) {
ath11k_warn(ab, "Unable to create intersected regdomain\n"); goto ret;
}
} else {
new_regd = tmp_regd;
}
/* Currently each struct ath11k maps to one struct ieee80211_hw/wiphy *andonestructieee80211_regdomain,soitcouldonlystoreonegroup *regrules.Itmeansmulti-interfaceconcurrencyinthesameath11kis *notsupportfortheregdomain.Sogetthevdevtypeofthefirstentry *now.Afterconcurrencysupportfortheregdomain,thisshouldchange.
*/
arvif = list_first_entry_or_null(&ar->arvifs, struct ath11k_vif, list); if (arvif) return arvif->vdev_type;
if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { /* In case of failure to set the requested ctry, *fwretainsthecurrentregd.Weprintafailureinfo *andreturnfromhere.
*/
ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); return -EINVAL;
}
pdev_idx = reg_info->phy_id;
/* Avoid default reg rule updates sent during FW recovery if *itisalreadyavailable
*/
spin_lock_bh(&ab->base_lock); if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) &&
ab->default_regd[pdev_idx]) {
spin_unlock_bh(&ab->base_lock); goto retfail;
}
spin_unlock_bh(&ab->base_lock);
if (pdev_idx >= ab->num_radios) { /* Process the event for phy0 only if single_pdev_only *istrue.Ifpdev_idxisvalidbutnot0,discardthe *event.Otherwise,itgoestofallback.Ineithercase *ath11k_reg_reset_info()needstobecalledtoavoid *memoryleakissue.
*/
ath11k_reg_reset_info(reg_info);
if (ab->hw_params.single_pdev_only &&
pdev_idx < ab->hw_params.num_rxdma_per_pdev) return0; goto fallback;
}
/* Avoid multiple overwrites to default regd, during core *stop-startaftermacregistration.
*/ if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
!memcmp((char *)ab->default_regd[pdev_idx]->alpha2,
(char *)reg_info->alpha2, 2)) goto retfail;
/* Intersect new rules with default regd if a new country setting was *requested,i.eadefaultregdwasalreadysetduringinitialization *andtheregdcomingfromthiseventhasavalidcountryinfo.
*/ if (ab->default_regd[pdev_idx] &&
!ath11k_reg_is_world_alpha((char *)
ab->default_regd[pdev_idx]->alpha2) &&
!ath11k_reg_is_world_alpha((char *)reg_info->alpha2))
intersect = true;
ar = ab->pdevs[pdev_idx].ar;
vdev_type = ath11k_reg_get_ar_vdev_type(ar);
ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi handle chan list power type %d vdev type %d intersect %d\n",
power_type, vdev_type, intersect);
regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type); if (!regd) {
ath11k_warn(ab, "failed to build regd from reg_info\n"); goto fallback;
}
if (power_type == IEEE80211_REG_UNSET_AP) {
ath11k_reg_reset_info(&ab->reg_info_store[pdev_idx]);
ab->reg_info_store[pdev_idx] = *reg_info;
}
spin_lock_bh(&ab->base_lock); if (ab->default_regd[pdev_idx]) { /* The initial rules from FW after WMI Init is to build *thedefaultregd.Fromthenon,anyrulesupdatedfor *thepdevcouldbeduetouserregchanges. *Freepreviouslybuiltregdbeforeassigningthenewly *generatedregdtoar.NULLpointerhandlingwillbe *takencarebykfreeitself.
*/
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 { /* This regd would be applied during mac registration and is *heldconstantthroughoutforregdintersectionpurpose
*/
ab->default_regd[pdev_idx] = regd;
}
ab->dfs_region = reg_info->dfs_region;
spin_unlock_bh(&ab->base_lock);
return0;
fallback: /* Fallback to older reg (by sending previous country setting *againiffwhassucceededandwefailedtoprocesshere. *TheRegdomainshouldbeuniformacrossdriverandfw.Sincethe *FWhasprocessedthecommandandsentasuccessstatus,weexpect *thisfunctiontosucceedaswell.Ifitdoesn't,CTRYneedstobe *revertedatthefwandtheoldSCAN_CHAN_LISTcmdneedstobesent.
*/ /* TODO: This is rare, but still should also be handled */
WARN_ON(1);
ret = ath11k_regd_update(ar); if (ret) { /* Firmware has already moved to the new regd. We need *tomaintainchannelconsistencyacrossFW,Hostdriver *anduserspace.Henceasafallbackmechanismwecanset *theprevordefaultcountrycodetothefirmware.
*/ /* TODO: Implement Fallback Mechanism */
}
}
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.