4
4
* Copyright (C) 2019-2021 Intel Corporation
5
5
*/
6
6
#include <linux/uuid.h>
7
+ #include <linux/dmi.h>
7
8
#include "iwl-drv.h"
8
9
#include "iwl-debug.h"
9
10
#include "acpi.h"
@@ -19,6 +20,30 @@ const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29,
19
20
0xDD , 0x26 , 0xB5 , 0xFD );
20
21
IWL_EXPORT_SYMBOL (iwl_rfi_guid );
21
22
23
+ static const struct dmi_system_id dmi_ppag_approved_list [] = {
24
+ { .ident = "HP" ,
25
+ .matches = {
26
+ DMI_MATCH (DMI_SYS_VENDOR , "HP" ),
27
+ },
28
+ },
29
+ { .ident = "SAMSUNG" ,
30
+ .matches = {
31
+ DMI_MATCH (DMI_SYS_VENDOR , "SAMSUNG ELECTRONICS CO., LTD" ),
32
+ },
33
+ },
34
+ { .ident = "MSFT" ,
35
+ .matches = {
36
+ DMI_MATCH (DMI_SYS_VENDOR , "Microsoft Corporation" ),
37
+ },
38
+ },
39
+ { .ident = "ASUS" ,
40
+ .matches = {
41
+ DMI_MATCH (DMI_SYS_VENDOR , "ASUSTek COMPUTER INC." ),
42
+ },
43
+ },
44
+ {}
45
+ };
46
+
22
47
static int iwl_acpi_get_handle (struct device * dev , acpi_string method ,
23
48
acpi_handle * ret_handle )
24
49
{
@@ -971,3 +996,181 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
971
996
return config_bitmap ;
972
997
}
973
998
IWL_EXPORT_SYMBOL (iwl_acpi_get_lari_config_bitmap );
999
+
1000
+ int iwl_acpi_get_ppag_table (struct iwl_fw_runtime * fwrt )
1001
+ {
1002
+ union acpi_object * wifi_pkg , * data , * flags ;
1003
+ int i , j , ret , tbl_rev , num_sub_bands = 0 ;
1004
+ int idx = 2 ;
1005
+
1006
+ fwrt -> ppag_flags = 0 ;
1007
+
1008
+ data = iwl_acpi_get_object (fwrt -> dev , ACPI_PPAG_METHOD );
1009
+ if (IS_ERR (data ))
1010
+ return PTR_ERR (data );
1011
+
1012
+ /* try to read ppag table rev 2 or 1 (both have the same data size) */
1013
+ wifi_pkg = iwl_acpi_get_wifi_pkg (fwrt -> dev , data ,
1014
+ ACPI_PPAG_WIFI_DATA_SIZE_V2 , & tbl_rev );
1015
+
1016
+ if (!IS_ERR (wifi_pkg )) {
1017
+ if (tbl_rev == 1 || tbl_rev == 2 ) {
1018
+ num_sub_bands = IWL_NUM_SUB_BANDS_V2 ;
1019
+ IWL_DEBUG_RADIO (fwrt ,
1020
+ "Reading PPAG table v2 (tbl_rev=%d)\n" ,
1021
+ tbl_rev );
1022
+ goto read_table ;
1023
+ } else {
1024
+ ret = - EINVAL ;
1025
+ goto out_free ;
1026
+ }
1027
+ }
1028
+
1029
+ /* try to read ppag table revision 0 */
1030
+ wifi_pkg = iwl_acpi_get_wifi_pkg (fwrt -> dev , data ,
1031
+ ACPI_PPAG_WIFI_DATA_SIZE_V1 , & tbl_rev );
1032
+
1033
+ if (!IS_ERR (wifi_pkg )) {
1034
+ if (tbl_rev != 0 ) {
1035
+ ret = - EINVAL ;
1036
+ goto out_free ;
1037
+ }
1038
+ num_sub_bands = IWL_NUM_SUB_BANDS_V1 ;
1039
+ IWL_DEBUG_RADIO (fwrt , "Reading PPAG table v1 (tbl_rev=0)\n" );
1040
+ goto read_table ;
1041
+ }
1042
+
1043
+ read_table :
1044
+ fwrt -> ppag_ver = tbl_rev ;
1045
+ flags = & wifi_pkg -> package .elements [1 ];
1046
+
1047
+ if (flags -> type != ACPI_TYPE_INTEGER ) {
1048
+ ret = - EINVAL ;
1049
+ goto out_free ;
1050
+ }
1051
+
1052
+ fwrt -> ppag_flags = flags -> integer .value & ACPI_PPAG_MASK ;
1053
+
1054
+ if (!fwrt -> ppag_flags ) {
1055
+ ret = 0 ;
1056
+ goto out_free ;
1057
+ }
1058
+
1059
+ /*
1060
+ * read, verify gain values and save them into the PPAG table.
1061
+ * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
1062
+ * following sub-bands to High-Band (5GHz).
1063
+ */
1064
+ for (i = 0 ; i < IWL_NUM_CHAIN_LIMITS ; i ++ ) {
1065
+ for (j = 0 ; j < num_sub_bands ; j ++ ) {
1066
+ union acpi_object * ent ;
1067
+
1068
+ ent = & wifi_pkg -> package .elements [idx ++ ];
1069
+ if (ent -> type != ACPI_TYPE_INTEGER ) {
1070
+ ret = - EINVAL ;
1071
+ goto out_free ;
1072
+ }
1073
+
1074
+ fwrt -> ppag_chains [i ].subbands [j ] = ent -> integer .value ;
1075
+
1076
+ if ((j == 0 &&
1077
+ (fwrt -> ppag_chains [i ].subbands [j ] > ACPI_PPAG_MAX_LB ||
1078
+ fwrt -> ppag_chains [i ].subbands [j ] < ACPI_PPAG_MIN_LB )) ||
1079
+ (j != 0 &&
1080
+ (fwrt -> ppag_chains [i ].subbands [j ] > ACPI_PPAG_MAX_HB ||
1081
+ fwrt -> ppag_chains [i ].subbands [j ] < ACPI_PPAG_MIN_HB ))) {
1082
+ fwrt -> ppag_flags = 0 ;
1083
+ ret = - EINVAL ;
1084
+ goto out_free ;
1085
+ }
1086
+ }
1087
+ }
1088
+
1089
+
1090
+ ret = 0 ;
1091
+
1092
+ out_free :
1093
+ kfree (data );
1094
+ return ret ;
1095
+ }
1096
+ IWL_EXPORT_SYMBOL (iwl_acpi_get_ppag_table );
1097
+
1098
+ int iwl_read_ppag_table (struct iwl_fw_runtime * fwrt , union iwl_ppag_table_cmd * cmd ,
1099
+ int * cmd_size )
1100
+ {
1101
+ u8 cmd_ver ;
1102
+ int i , j , num_sub_bands ;
1103
+ s8 * gain ;
1104
+
1105
+ if (!fw_has_capa (& fwrt -> fw -> ucode_capa , IWL_UCODE_TLV_CAPA_SET_PPAG )) {
1106
+ IWL_DEBUG_RADIO (fwrt ,
1107
+ "PPAG capability not supported by FW, command not sent.\n" );
1108
+ return - EINVAL ;
1109
+ }
1110
+ if (!fwrt -> ppag_flags ) {
1111
+ IWL_DEBUG_RADIO (fwrt , "PPAG not enabled, command not sent.\n" );
1112
+ return - EINVAL ;
1113
+ }
1114
+
1115
+ /* The 'flags' field is the same in v1 and in v2 so we can just
1116
+ * use v1 to access it.
1117
+ */
1118
+ cmd -> v1 .flags = cpu_to_le32 (fwrt -> ppag_flags );
1119
+ cmd_ver = iwl_fw_lookup_cmd_ver (fwrt -> fw ,
1120
+ WIDE_ID (PHY_OPS_GROUP , PER_PLATFORM_ANT_GAIN_CMD ),
1121
+ IWL_FW_CMD_VER_UNKNOWN );
1122
+ if (cmd_ver == 1 ) {
1123
+ num_sub_bands = IWL_NUM_SUB_BANDS_V1 ;
1124
+ gain = cmd -> v1 .gain [0 ];
1125
+ * cmd_size = sizeof (cmd -> v1 );
1126
+ if (fwrt -> ppag_ver == 1 || fwrt -> ppag_ver == 2 ) {
1127
+ IWL_DEBUG_RADIO (fwrt ,
1128
+ "PPAG table rev is %d but FW supports v1, sending truncated table\n" ,
1129
+ fwrt -> ppag_ver );
1130
+ cmd -> v1 .flags &= cpu_to_le32 (IWL_PPAG_ETSI_MASK );
1131
+ }
1132
+ } else if (cmd_ver == 2 || cmd_ver == 3 ) {
1133
+ num_sub_bands = IWL_NUM_SUB_BANDS_V2 ;
1134
+ gain = cmd -> v2 .gain [0 ];
1135
+ * cmd_size = sizeof (cmd -> v2 );
1136
+ if (fwrt -> ppag_ver == 0 ) {
1137
+ IWL_DEBUG_RADIO (fwrt ,
1138
+ "PPAG table is v1 but FW supports v2, sending padded table\n" );
1139
+ } else if (cmd_ver == 2 && fwrt -> ppag_ver == 2 ) {
1140
+ IWL_DEBUG_RADIO (fwrt ,
1141
+ "PPAG table is v3 but FW supports v2, sending partial bitmap.\n" );
1142
+ cmd -> v1 .flags &= cpu_to_le32 (IWL_PPAG_ETSI_MASK );
1143
+ }
1144
+ } else {
1145
+ IWL_DEBUG_RADIO (fwrt , "Unsupported PPAG command version\n" );
1146
+ return - EINVAL ;
1147
+ }
1148
+
1149
+ for (i = 0 ; i < IWL_NUM_CHAIN_LIMITS ; i ++ ) {
1150
+ for (j = 0 ; j < num_sub_bands ; j ++ ) {
1151
+ gain [i * num_sub_bands + j ] =
1152
+ fwrt -> ppag_chains [i ].subbands [j ];
1153
+ IWL_DEBUG_RADIO (fwrt ,
1154
+ "PPAG table: chain[%d] band[%d]: gain = %d\n" ,
1155
+ i , j , gain [i * num_sub_bands + j ]);
1156
+ }
1157
+ }
1158
+
1159
+ return 0 ;
1160
+ }
1161
+ IWL_EXPORT_SYMBOL (iwl_read_ppag_table );
1162
+
1163
+ bool iwl_acpi_is_ppag_approved (struct iwl_fw_runtime * fwrt )
1164
+ {
1165
+
1166
+ if (!dmi_check_system (dmi_ppag_approved_list )) {
1167
+ IWL_DEBUG_RADIO (fwrt ,
1168
+ "System vendor '%s' is not in the approved list, disabling PPAG.\n" ,
1169
+ dmi_get_system_info (DMI_SYS_VENDOR ));
1170
+ fwrt -> ppag_flags = 0 ;
1171
+ return false;
1172
+ }
1173
+
1174
+ return true;
1175
+ }
1176
+ IWL_EXPORT_SYMBOL (iwl_acpi_is_ppag_approved );
0 commit comments