76
76
#include "iwl-io.h"
77
77
#include "iwl-csr.h"
78
78
#include "fw/acpi.h"
79
+ #include "fw/api/nvm-reg.h"
79
80
80
81
/* NVM offsets (in words) definitions */
81
82
enum nvm_offsets {
@@ -146,8 +147,8 @@ static const u8 iwl_ext_nvm_channels[] = {
146
147
149 , 153 , 157 , 161 , 165 , 169 , 173 , 177 , 181
147
148
};
148
149
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)
151
152
#define NUM_2GHZ_CHANNELS 14
152
153
#define NUM_2GHZ_CHANNELS_EXT 14
153
154
#define FIRST_2GHZ_HT_MINUS 5
@@ -301,11 +302,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
301
302
const u8 * nvm_chan ;
302
303
303
304
if (cfg -> nvm_type != IWL_NVM_EXT ) {
304
- num_of_ch = IWL_NUM_CHANNELS ;
305
+ num_of_ch = IWL_NVM_NUM_CHANNELS ;
305
306
nvm_chan = & iwl_nvm_channels [0 ];
306
307
num_2ghz_channels = NUM_2GHZ_CHANNELS ;
307
308
} else {
308
- num_of_ch = IWL_NUM_CHANNELS_EXT ;
309
+ num_of_ch = IWL_NVM_NUM_CHANNELS_EXT ;
309
310
nvm_chan = & iwl_ext_nvm_channels [0 ];
310
311
num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT ;
311
312
}
@@ -720,12 +721,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
720
721
if (cfg -> nvm_type != IWL_NVM_EXT )
721
722
data = kzalloc (sizeof (* data ) +
722
723
sizeof (struct ieee80211_channel ) *
723
- IWL_NUM_CHANNELS ,
724
+ IWL_NVM_NUM_CHANNELS ,
724
725
GFP_KERNEL );
725
726
else
726
727
data = kzalloc (sizeof (* data ) +
727
728
sizeof (struct ieee80211_channel ) *
728
- IWL_NUM_CHANNELS_EXT ,
729
+ IWL_NVM_NUM_CHANNELS_EXT ,
729
730
GFP_KERNEL );
730
731
if (!data )
731
732
return NULL ;
@@ -842,24 +843,34 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
842
843
return flags ;
843
844
}
844
845
846
+ struct regdb_ptrs {
847
+ struct ieee80211_wmm_rule * rule ;
848
+ u32 token ;
849
+ };
850
+
845
851
struct ieee80211_regdomain *
846
852
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 )
848
855
{
849
856
int ch_idx ;
850
857
u16 ch_flags ;
851
858
u32 reg_rule_flags , prev_reg_rule_flags = 0 ;
852
859
const u8 * nvm_chan = cfg -> nvm_type == IWL_NVM_EXT ?
853
860
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 ;
856
864
struct ieee80211_reg_rule * rule ;
865
+ struct ieee80211_wmm_rule * wmm_rule , * d_wmm , * s_wmm ;
866
+ struct regdb_ptrs * regdb_ptrs ;
857
867
enum nl80211_band band ;
858
868
int center_freq , prev_center_freq = 0 ;
859
- int valid_rules = 0 ;
869
+ int valid_rules = 0 , n_wmms = 0 ;
870
+ int i ;
860
871
bool new_rule ;
861
872
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 ;
863
874
864
875
if (WARN_ON_ONCE (num_of_ch > NL80211_MAX_SUPP_REG_RULES ))
865
876
return ERR_PTR (- EINVAL );
@@ -875,10 +886,26 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
875
886
sizeof (struct ieee80211_regdomain ) +
876
887
num_of_ch * sizeof (struct ieee80211_reg_rule );
877
888
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 );
879
894
if (!regd )
880
895
return ERR_PTR (- ENOMEM );
881
896
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
+
882
909
for (ch_idx = 0 ; ch_idx < num_of_ch ; ch_idx ++ ) {
883
910
ch_flags = (u16 )__le32_to_cpup (channels + ch_idx );
884
911
band = (ch_idx < NUM_2GHZ_CHANNELS ) ?
@@ -927,14 +954,66 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
927
954
928
955
iwl_nvm_print_channel_flags (dev , IWL_DL_LAR ,
929
956
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
+ }
930
978
}
931
979
932
980
regd -> n_reg_rules = valid_rules ;
981
+ regd -> n_wmm_rules = n_wmms ;
933
982
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
+ }
937
1013
938
- return regd ;
1014
+ out :
1015
+ kfree (regdb_ptrs );
1016
+ kfree (regd );
1017
+ return copy_rd ;
939
1018
}
940
1019
IWL_EXPORT_SYMBOL (iwl_parse_nvm_mcc_info );
0 commit comments