diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 6fcae5ce1b77..f735ebf1c0d1 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -14,6 +14,7 @@ #include "fw.h" #define WIL_MAX_ROC_DURATION_MS 5000 +#define CTRY_CHINA "CN" #define WIL_EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1)) #define WIL_EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2)) @@ -41,6 +42,10 @@ static struct wiphy_wowlan_support wil_wowlan_support = { }; #endif +static bool country_specific_board_file; +module_param(country_specific_board_file, bool, 0444); +MODULE_PARM_DESC(country_specific_board_file, " switch board file upon regulatory domain change (Default: false)"); + static bool ignore_reg_hints = true; module_param(ignore_reg_hints, bool, 0444); MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)"); @@ -2604,6 +2609,65 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int wil_switch_board_file(struct wil6210_priv *wil, + const u8 *new_regdomain) +{ + int rc = 0; + + if (!country_specific_board_file) + return 0; + + if (memcmp(wil->regdomain, CTRY_CHINA, 2) == 0) { + wil_info(wil, "moving out of China reg domain, use default board file\n"); + wil->board_file_country[0] = '\0'; + } else if (memcmp(new_regdomain, CTRY_CHINA, 2) == 0) { + wil_info(wil, "moving into China reg domain, use country specific board file\n"); + strlcpy(wil->board_file_country, CTRY_CHINA, + sizeof(wil->board_file_country)); + } else { + return 0; + } + + /* need to switch board file - reset the device */ + + mutex_lock(&wil->mutex); + + if (!wil_has_active_ifaces(wil, true, false) || + wil_is_recovery_blocked(wil)) + /* new board file will be used in next FW load */ + goto out; + + __wil_down(wil); + rc = __wil_up(wil); + +out: + mutex_unlock(&wil->mutex); + return rc; +} + +static void wil_cfg80211_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + wil_info(wil, "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n", + request->alpha2[0], request->alpha2[1], + request->intersect ? " intersect" : "", + request->processed ? " processed" : "", + request->initiator, request->user_reg_hint_type); + + if (memcmp(wil->regdomain, request->alpha2, 2) == 0) + /* reg domain did not change */ + return; + + rc = wil_switch_board_file(wil, request->alpha2); + if (rc) + wil_err(wil, "switch board file failed %d\n", rc); + + memcpy(wil->regdomain, request->alpha2, 2); +} + static int wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_update_ft_ies_params *ftie) @@ -2724,6 +2788,8 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->mgmt_stypes = wil_mgmt_stypes; wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; + wiphy->reg_notifier = wil_cfg80211_reg_notify; + wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands); wiphy->vendor_commands = wil_nl80211_vendor_commands; wiphy->vendor_events = wil_nl80211_vendor_events; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 89238bd046e9..a2243027cd24 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1291,6 +1291,8 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len) { const char *board_file; + const char *ext; + int prefix_len; const char *wil_talyn_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN : WIL_FW_NAME_TALYN; @@ -1306,7 +1308,21 @@ void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len) board_file = WIL_BOARD_FILE_NAME; } - strlcpy(buf, board_file, len); + if (wil->board_file_country[0] == '\0') { + strlcpy(buf, board_file, len); + return; + } + + /* use country specific board file */ + if (len < strlen(board_file) + 4 /* for _XX and terminating null */) + return; + + ext = strrchr(board_file, '.'); + prefix_len = (ext ? ext - board_file : strlen(board_file)); + snprintf(buf, len, "%.*s_%.2s", + prefix_len, board_file, wil->board_file_country); + if (ext) + strlcat(buf, ext, len); } static int wil_get_bl_info(struct wil6210_priv *wil) @@ -1707,16 +1723,16 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (load_fw) { char board_file[WIL_BOARD_FILE_MAX_NAMELEN]; - if (wil->secured_boot) { - wil_err(wil, "secured boot is not supported\n"); - return -ENOTSUPP; - } - board_file[0] = '\0'; wil_get_board_file(wil, board_file, sizeof(board_file)); wil_info(wil, "Use firmware <%s> + board <%s>\n", wil->wil_fw_name, board_file); + if (wil->secured_boot) { + wil_err(wil, "secured boot is not supported\n"); + return -ENOTSUPP; + } + if (!no_flash) wil_bl_prepare_halt(wil); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fddc8bccc524..aef6e90b0fef 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -934,6 +934,7 @@ struct wil6210_priv { const char *hw_name; const char *wil_fw_name; char *board_file; + char board_file_country[3]; /* alpha2 */ u32 num_of_brd_entries; struct wil_brd_info *brd_info; DECLARE_BITMAP(hw_capa, hw_capa_last); @@ -1045,6 +1046,9 @@ struct wil6210_priv { short direct; } snr_thresh; + /* current reg domain configured in kernel */ + char regdomain[3]; /* alpha2 */ + struct notifier_block pm_notify; bool suspend_resp_rcvd;