Skip to content

Commit 77e30e1

Browse files
haimdreyfussKalle Valo
authored andcommitted
iwlwifi: mvm: query regdb for wmm rule if needed
Since our device is regulatory self managed it maintains its regulatory rules by its own. However the wmm_rules values can't be set by the device itself but only the indication about the need to set it. In case the device set wmm indication, proactively query the regulatory data base to get these values Signed-off-by: Haim Dreyfuss <[email protected]> Signed-off-by: Luca Coelho <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 0b5c030 commit 77e30e1

File tree

3 files changed

+101
-19
lines changed

3 files changed

+101
-19
lines changed

drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#include "iwl-io.h"
7777
#include "iwl-csr.h"
7878
#include "fw/acpi.h"
79+
#include "fw/api/nvm-reg.h"
7980

8081
/* NVM offsets (in words) definitions */
8182
enum nvm_offsets {
@@ -146,8 +147,8 @@ static const u8 iwl_ext_nvm_channels[] = {
146147
149, 153, 157, 161, 165, 169, 173, 177, 181
147148
};
148149

149-
#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
150-
#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
150+
#define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
151+
#define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
151152
#define NUM_2GHZ_CHANNELS 14
152153
#define NUM_2GHZ_CHANNELS_EXT 14
153154
#define FIRST_2GHZ_HT_MINUS 5
@@ -301,11 +302,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
301302
const u8 *nvm_chan;
302303

303304
if (cfg->nvm_type != IWL_NVM_EXT) {
304-
num_of_ch = IWL_NUM_CHANNELS;
305+
num_of_ch = IWL_NVM_NUM_CHANNELS;
305306
nvm_chan = &iwl_nvm_channels[0];
306307
num_2ghz_channels = NUM_2GHZ_CHANNELS;
307308
} else {
308-
num_of_ch = IWL_NUM_CHANNELS_EXT;
309+
num_of_ch = IWL_NVM_NUM_CHANNELS_EXT;
309310
nvm_chan = &iwl_ext_nvm_channels[0];
310311
num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT;
311312
}
@@ -720,12 +721,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
720721
if (cfg->nvm_type != IWL_NVM_EXT)
721722
data = kzalloc(sizeof(*data) +
722723
sizeof(struct ieee80211_channel) *
723-
IWL_NUM_CHANNELS,
724+
IWL_NVM_NUM_CHANNELS,
724725
GFP_KERNEL);
725726
else
726727
data = kzalloc(sizeof(*data) +
727728
sizeof(struct ieee80211_channel) *
728-
IWL_NUM_CHANNELS_EXT,
729+
IWL_NVM_NUM_CHANNELS_EXT,
729730
GFP_KERNEL);
730731
if (!data)
731732
return NULL;
@@ -842,24 +843,34 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
842843
return flags;
843844
}
844845

846+
struct regdb_ptrs {
847+
struct ieee80211_wmm_rule *rule;
848+
u32 token;
849+
};
850+
845851
struct ieee80211_regdomain *
846852
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
847-
int num_of_ch, __le32 *channels, u16 fw_mcc)
853+
int num_of_ch, __le32 *channels, u16 fw_mcc,
854+
u16 geo_info)
848855
{
849856
int ch_idx;
850857
u16 ch_flags;
851858
u32 reg_rule_flags, prev_reg_rule_flags = 0;
852859
const u8 *nvm_chan = cfg->nvm_type == IWL_NVM_EXT ?
853860
iwl_ext_nvm_channels : iwl_nvm_channels;
854-
struct ieee80211_regdomain *regd;
855-
int size_of_regd;
861+
struct ieee80211_regdomain *regd, *copy_rd;
862+
int size_of_regd, regd_to_copy, wmms_to_copy;
863+
int size_of_wmms = 0;
856864
struct ieee80211_reg_rule *rule;
865+
struct ieee80211_wmm_rule *wmm_rule, *d_wmm, *s_wmm;
866+
struct regdb_ptrs *regdb_ptrs;
857867
enum nl80211_band band;
858868
int center_freq, prev_center_freq = 0;
859-
int valid_rules = 0;
869+
int valid_rules = 0, n_wmms = 0;
870+
int i;
860871
bool new_rule;
861872
int max_num_ch = cfg->nvm_type == IWL_NVM_EXT ?
862-
IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS;
873+
IWL_NVM_NUM_CHANNELS_EXT : IWL_NVM_NUM_CHANNELS;
863874

864875
if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
865876
return ERR_PTR(-EINVAL);
@@ -875,10 +886,26 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
875886
sizeof(struct ieee80211_regdomain) +
876887
num_of_ch * sizeof(struct ieee80211_reg_rule);
877888

878-
regd = kzalloc(size_of_regd, GFP_KERNEL);
889+
if (geo_info & GEO_WMM_ETSI_5GHZ_INFO)
890+
size_of_wmms =
891+
num_of_ch * sizeof(struct ieee80211_wmm_rule);
892+
893+
regd = kzalloc(size_of_regd + size_of_wmms, GFP_KERNEL);
879894
if (!regd)
880895
return ERR_PTR(-ENOMEM);
881896

897+
regdb_ptrs = kcalloc(num_of_ch, sizeof(*regdb_ptrs), GFP_KERNEL);
898+
if (!regdb_ptrs) {
899+
copy_rd = ERR_PTR(-ENOMEM);
900+
goto out;
901+
}
902+
903+
/* set alpha2 from FW. */
904+
regd->alpha2[0] = fw_mcc >> 8;
905+
regd->alpha2[1] = fw_mcc & 0xff;
906+
907+
wmm_rule = (struct ieee80211_wmm_rule *)((u8 *)regd + size_of_regd);
908+
882909
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
883910
ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
884911
band = (ch_idx < NUM_2GHZ_CHANNELS) ?
@@ -927,14 +954,66 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
927954

928955
iwl_nvm_print_channel_flags(dev, IWL_DL_LAR,
929956
nvm_chan[ch_idx], ch_flags);
957+
958+
if (!(geo_info & GEO_WMM_ETSI_5GHZ_INFO) ||
959+
band == NL80211_BAND_2GHZ)
960+
continue;
961+
962+
if (!reg_query_regdb_wmm(regd->alpha2, center_freq,
963+
&regdb_ptrs[n_wmms].token, wmm_rule)) {
964+
/* Add only new rules */
965+
for (i = 0; i < n_wmms; i++) {
966+
if (regdb_ptrs[i].token ==
967+
regdb_ptrs[n_wmms].token) {
968+
rule->wmm_rule = regdb_ptrs[i].rule;
969+
break;
970+
}
971+
}
972+
if (i == n_wmms) {
973+
rule->wmm_rule = wmm_rule;
974+
regdb_ptrs[n_wmms++].rule = wmm_rule;
975+
wmm_rule++;
976+
}
977+
}
930978
}
931979

932980
regd->n_reg_rules = valid_rules;
981+
regd->n_wmm_rules = n_wmms;
933982

934-
/* set alpha2 from FW. */
935-
regd->alpha2[0] = fw_mcc >> 8;
936-
regd->alpha2[1] = fw_mcc & 0xff;
983+
/*
984+
* Narrow down regdom for unused regulatory rules to prevent hole
985+
* between reg rules to wmm rules.
986+
*/
987+
regd_to_copy = sizeof(struct ieee80211_regdomain) +
988+
valid_rules * sizeof(struct ieee80211_reg_rule);
989+
990+
wmms_to_copy = sizeof(struct ieee80211_wmm_rule) * n_wmms;
991+
992+
copy_rd = kzalloc(regd_to_copy + wmms_to_copy, GFP_KERNEL);
993+
if (!copy_rd) {
994+
copy_rd = ERR_PTR(-ENOMEM);
995+
goto out;
996+
}
997+
998+
memcpy(copy_rd, regd, regd_to_copy);
999+
memcpy((u8 *)copy_rd + regd_to_copy, (u8 *)regd + size_of_regd,
1000+
wmms_to_copy);
1001+
1002+
d_wmm = (struct ieee80211_wmm_rule *)((u8 *)copy_rd + regd_to_copy);
1003+
s_wmm = (struct ieee80211_wmm_rule *)((u8 *)regd + size_of_regd);
1004+
1005+
for (i = 0; i < regd->n_reg_rules; i++) {
1006+
if (!regd->reg_rules[i].wmm_rule)
1007+
continue;
1008+
1009+
copy_rd->reg_rules[i].wmm_rule = d_wmm +
1010+
(regd->reg_rules[i].wmm_rule - s_wmm) /
1011+
sizeof(struct ieee80211_wmm_rule);
1012+
}
9371013

938-
return regd;
1014+
out:
1015+
kfree(regdb_ptrs);
1016+
kfree(regd);
1017+
return copy_rd;
9391018
}
9401019
IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);

drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,14 @@ void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
101101
*
102102
* This function parses the regulatory channel data received as a
103103
* MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain,
104-
* to be fed into the regulatory core. An ERR_PTR is returned on error.
104+
* to be fed into the regulatory core. In case the geo_info is set handle
105+
* accordingly. An ERR_PTR is returned on error.
105106
* If not given to the regulatory core, the user is responsible for freeing
106107
* the regdomain returned here with kfree.
107108
*/
108109
struct ieee80211_regdomain *
109110
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
110-
int num_of_ch, __le32 *channels, u16 fw_mcc);
111+
int num_of_ch, __le32 *channels, u16 fw_mcc,
112+
u16 geo_info);
111113

112114
#endif /* __iwl_nvm_parse_h__ */

drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,8 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
311311
regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
312312
__le32_to_cpu(resp->n_channels),
313313
resp->channels,
314-
__le16_to_cpu(resp->mcc));
314+
__le16_to_cpu(resp->mcc),
315+
__le16_to_cpu(resp->geo_info));
315316
/* Store the return source id */
316317
src_id = resp->source_id;
317318
kfree(resp);

0 commit comments

Comments
 (0)