Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2017 Intel Deutschland GmbH
0004  * Copyright (C) 2019-2022 Intel Corporation
0005  */
0006 #include <linux/uuid.h>
0007 #include <linux/dmi.h>
0008 #include "iwl-drv.h"
0009 #include "iwl-debug.h"
0010 #include "acpi.h"
0011 #include "fw/runtime.h"
0012 
0013 const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
0014                   0xA5, 0xB3, 0x1F, 0x73,
0015                   0x8E, 0x28, 0x5A, 0xDE);
0016 IWL_EXPORT_SYMBOL(iwl_guid);
0017 
0018 const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29,
0019                       0x81, 0x4F, 0x75, 0xE4,
0020                       0xDD, 0x26, 0xB5, 0xFD);
0021 IWL_EXPORT_SYMBOL(iwl_rfi_guid);
0022 
0023 static const struct dmi_system_id dmi_ppag_approved_list[] = {
0024     { .ident = "HP",
0025       .matches = {
0026             DMI_MATCH(DMI_SYS_VENDOR, "HP"),
0027         },
0028     },
0029     { .ident = "SAMSUNG",
0030       .matches = {
0031             DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
0032         },
0033     },
0034     { .ident = "MSFT",
0035       .matches = {
0036             DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
0037         },
0038     },
0039     { .ident = "ASUS",
0040       .matches = {
0041             DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek COMPUTER INC."),
0042         },
0043     },
0044     {}
0045 };
0046 
0047 static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
0048                    acpi_handle *ret_handle)
0049 {
0050     acpi_handle root_handle;
0051     acpi_status status;
0052 
0053     root_handle = ACPI_HANDLE(dev);
0054     if (!root_handle) {
0055         IWL_DEBUG_DEV_RADIO(dev,
0056                     "ACPI: Could not retrieve root port handle\n");
0057         return -ENOENT;
0058     }
0059 
0060     status = acpi_get_handle(root_handle, method, ret_handle);
0061     if (ACPI_FAILURE(status)) {
0062         IWL_DEBUG_DEV_RADIO(dev,
0063                     "ACPI: %s method not found\n", method);
0064         return -ENOENT;
0065     }
0066     return 0;
0067 }
0068 
0069 void *iwl_acpi_get_object(struct device *dev, acpi_string method)
0070 {
0071     struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
0072     acpi_handle handle;
0073     acpi_status status;
0074     int ret;
0075 
0076     ret = iwl_acpi_get_handle(dev, method, &handle);
0077     if (ret)
0078         return ERR_PTR(-ENOENT);
0079 
0080     /* Call the method with no arguments */
0081     status = acpi_evaluate_object(handle, NULL, NULL, &buf);
0082     if (ACPI_FAILURE(status)) {
0083         IWL_DEBUG_DEV_RADIO(dev,
0084                     "ACPI: %s method invocation failed (status: 0x%x)\n",
0085                     method, status);
0086         return ERR_PTR(-ENOENT);
0087     }
0088     return buf.pointer;
0089 }
0090 IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
0091 
0092 /*
0093  * Generic function for evaluating a method defined in the device specific
0094  * method (DSM) interface. The returned acpi object must be freed by calling
0095  * function.
0096  */
0097 static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
0098                      union acpi_object *args,
0099                      const guid_t *guid)
0100 {
0101     union acpi_object *obj;
0102 
0103     obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func,
0104                 args);
0105     if (!obj) {
0106         IWL_DEBUG_DEV_RADIO(dev,
0107                     "ACPI: DSM method invocation failed (rev: %d, func:%d)\n",
0108                     rev, func);
0109         return ERR_PTR(-ENOENT);
0110     }
0111     return obj;
0112 }
0113 
0114 /*
0115  * Generic function to evaluate a DSM with no arguments
0116  * and an integer return value,
0117  * (as an integer object or inside a buffer object),
0118  * verify and assign the value in the "value" parameter.
0119  * return 0 in success and the appropriate errno otherwise.
0120  */
0121 static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
0122                     const guid_t *guid, u64 *value,
0123                     size_t expected_size)
0124 {
0125     union acpi_object *obj;
0126     int ret = 0;
0127 
0128     obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid);
0129     if (IS_ERR(obj)) {
0130         IWL_DEBUG_DEV_RADIO(dev,
0131                     "Failed to get  DSM object. func= %d\n",
0132                     func);
0133         return -ENOENT;
0134     }
0135 
0136     if (obj->type == ACPI_TYPE_INTEGER) {
0137         *value = obj->integer.value;
0138     } else if (obj->type == ACPI_TYPE_BUFFER) {
0139         __le64 le_value = 0;
0140 
0141         if (WARN_ON_ONCE(expected_size > sizeof(le_value)))
0142             return -EINVAL;
0143 
0144         /* if the buffer size doesn't match the expected size */
0145         if (obj->buffer.length != expected_size)
0146             IWL_DEBUG_DEV_RADIO(dev,
0147                         "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
0148                         obj->buffer.length);
0149 
0150          /* assuming LE from Intel BIOS spec */
0151         memcpy(&le_value, obj->buffer.pointer,
0152                min_t(size_t, expected_size, (size_t)obj->buffer.length));
0153         *value = le64_to_cpu(le_value);
0154     } else {
0155         IWL_DEBUG_DEV_RADIO(dev,
0156                     "ACPI: DSM method did not return a valid object, type=%d\n",
0157                     obj->type);
0158         ret = -EINVAL;
0159         goto out;
0160     }
0161 
0162     IWL_DEBUG_DEV_RADIO(dev,
0163                 "ACPI: DSM method evaluated: func=%d, ret=%d\n",
0164                 func, ret);
0165 out:
0166     ACPI_FREE(obj);
0167     return ret;
0168 }
0169 
0170 /*
0171  * Evaluate a DSM with no arguments and a u8 return value,
0172  */
0173 int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
0174             const guid_t *guid, u8 *value)
0175 {
0176     int ret;
0177     u64 val;
0178 
0179     ret = iwl_acpi_get_dsm_integer(dev, rev, func,
0180                        guid, &val, sizeof(u8));
0181 
0182     if (ret < 0)
0183         return ret;
0184 
0185     /* cast val (u64) to be u8 */
0186     *value = (u8)val;
0187     return 0;
0188 }
0189 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
0190 
0191 /*
0192  * Evaluate a DSM with no arguments and a u32 return value,
0193  */
0194 int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
0195              const guid_t *guid, u32 *value)
0196 {
0197     int ret;
0198     u64 val;
0199 
0200     ret = iwl_acpi_get_dsm_integer(dev, rev, func,
0201                        guid, &val, sizeof(u32));
0202 
0203     if (ret < 0)
0204         return ret;
0205 
0206     /* cast val (u64) to be u32 */
0207     *value = (u32)val;
0208     return 0;
0209 }
0210 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32);
0211 
0212 union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev,
0213                            union acpi_object *data,
0214                            int min_data_size,
0215                            int max_data_size,
0216                            int *tbl_rev)
0217 {
0218     int i;
0219     union acpi_object *wifi_pkg;
0220 
0221     /*
0222      * We need at least one entry in the wifi package that
0223      * describes the domain, and one more entry, otherwise there's
0224      * no point in reading it.
0225      */
0226     if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
0227         return ERR_PTR(-EINVAL);
0228 
0229     /*
0230      * We need at least two packages, one for the revision and one
0231      * for the data itself.  Also check that the revision is valid
0232      * (i.e. it is an integer (each caller has to check by itself
0233      * if the returned revision is supported)).
0234      */
0235     if (data->type != ACPI_TYPE_PACKAGE ||
0236         data->package.count < 2 ||
0237         data->package.elements[0].type != ACPI_TYPE_INTEGER) {
0238         IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
0239         return ERR_PTR(-EINVAL);
0240     }
0241 
0242     *tbl_rev = data->package.elements[0].integer.value;
0243 
0244     /* loop through all the packages to find the one for WiFi */
0245     for (i = 1; i < data->package.count; i++) {
0246         union acpi_object *domain;
0247 
0248         wifi_pkg = &data->package.elements[i];
0249 
0250         /* skip entries that are not a package with the right size */
0251         if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
0252             wifi_pkg->package.count < min_data_size ||
0253             wifi_pkg->package.count > max_data_size)
0254             continue;
0255 
0256         domain = &wifi_pkg->package.elements[0];
0257         if (domain->type == ACPI_TYPE_INTEGER &&
0258             domain->integer.value == ACPI_WIFI_DOMAIN)
0259             goto found;
0260     }
0261 
0262     return ERR_PTR(-ENOENT);
0263 
0264 found:
0265     return wifi_pkg;
0266 }
0267 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range);
0268 
0269 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt,
0270              union iwl_tas_config_cmd *cmd, int fw_ver)
0271 {
0272     union acpi_object *wifi_pkg, *data;
0273     int ret, tbl_rev, i, block_list_size, enabled;
0274 
0275     data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD);
0276     if (IS_ERR(data))
0277         return PTR_ERR(data);
0278 
0279     /* try to read wtas table revision 1 or revision 0*/
0280     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0281                      ACPI_WTAS_WIFI_DATA_SIZE,
0282                      &tbl_rev);
0283     if (IS_ERR(wifi_pkg)) {
0284         ret = PTR_ERR(wifi_pkg);
0285         goto out_free;
0286     }
0287 
0288     if (tbl_rev == 1 && wifi_pkg->package.elements[1].type ==
0289         ACPI_TYPE_INTEGER) {
0290         u32 tas_selection =
0291             (u32)wifi_pkg->package.elements[1].integer.value;
0292         u16 override_iec =
0293             (tas_selection & ACPI_WTAS_OVERRIDE_IEC_MSK) >> ACPI_WTAS_OVERRIDE_IEC_POS;
0294         u16 enabled_iec = (tas_selection & ACPI_WTAS_ENABLE_IEC_MSK) >>
0295             ACPI_WTAS_ENABLE_IEC_POS;
0296         u8 usa_tas_uhb = (tas_selection & ACPI_WTAS_USA_UHB_MSK) >> ACPI_WTAS_USA_UHB_POS;
0297 
0298 
0299         enabled = tas_selection & ACPI_WTAS_ENABLED_MSK;
0300         if (fw_ver <= 3) {
0301             cmd->v3.override_tas_iec = cpu_to_le16(override_iec);
0302             cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec);
0303         } else {
0304             cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb;
0305             cmd->v4.override_tas_iec = (u8)override_iec;
0306             cmd->v4.enable_tas_iec = (u8)enabled_iec;
0307         }
0308 
0309     } else if (tbl_rev == 0 &&
0310         wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) {
0311         enabled = !!wifi_pkg->package.elements[1].integer.value;
0312     } else {
0313         ret = -EINVAL;
0314         goto out_free;
0315     }
0316 
0317     if (!enabled) {
0318         IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n");
0319         ret = 0;
0320         goto out_free;
0321     }
0322 
0323     IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev);
0324     if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER ||
0325         wifi_pkg->package.elements[2].integer.value >
0326         APCI_WTAS_BLACK_LIST_MAX) {
0327         IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n",
0328                 wifi_pkg->package.elements[2].integer.value);
0329         ret = -EINVAL;
0330         goto out_free;
0331     }
0332     block_list_size = wifi_pkg->package.elements[2].integer.value;
0333     cmd->v4.block_list_size = cpu_to_le32(block_list_size);
0334 
0335     IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size);
0336     if (block_list_size > APCI_WTAS_BLACK_LIST_MAX) {
0337         IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n",
0338                 block_list_size);
0339         ret = -EINVAL;
0340         goto out_free;
0341     }
0342 
0343     for (i = 0; i < block_list_size; i++) {
0344         u32 country;
0345 
0346         if (wifi_pkg->package.elements[3 + i].type !=
0347             ACPI_TYPE_INTEGER) {
0348             IWL_DEBUG_RADIO(fwrt,
0349                     "TAS invalid array elem %d\n", 3 + i);
0350             ret = -EINVAL;
0351             goto out_free;
0352         }
0353 
0354         country = wifi_pkg->package.elements[3 + i].integer.value;
0355         cmd->v4.block_list_array[i] = cpu_to_le32(country);
0356         IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
0357     }
0358 
0359     ret = 1;
0360 out_free:
0361     kfree(data);
0362     return ret;
0363 }
0364 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas);
0365 
0366 int iwl_acpi_get_mcc(struct device *dev, char *mcc)
0367 {
0368     union acpi_object *wifi_pkg, *data;
0369     u32 mcc_val;
0370     int ret, tbl_rev;
0371 
0372     data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
0373     if (IS_ERR(data))
0374         return PTR_ERR(data);
0375 
0376     wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
0377                      &tbl_rev);
0378     if (IS_ERR(wifi_pkg)) {
0379         ret = PTR_ERR(wifi_pkg);
0380         goto out_free;
0381     }
0382 
0383     if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
0384         tbl_rev != 0) {
0385         ret = -EINVAL;
0386         goto out_free;
0387     }
0388 
0389     mcc_val = wifi_pkg->package.elements[1].integer.value;
0390 
0391     mcc[0] = (mcc_val >> 8) & 0xff;
0392     mcc[1] = mcc_val & 0xff;
0393     mcc[2] = '\0';
0394 
0395     ret = 0;
0396 out_free:
0397     kfree(data);
0398     return ret;
0399 }
0400 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc);
0401 
0402 u64 iwl_acpi_get_pwr_limit(struct device *dev)
0403 {
0404     union acpi_object *data, *wifi_pkg;
0405     u64 dflt_pwr_limit;
0406     int tbl_rev;
0407 
0408     data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
0409     if (IS_ERR(data)) {
0410         dflt_pwr_limit = 0;
0411         goto out;
0412     }
0413 
0414     wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
0415                      ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
0416     if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
0417         wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
0418         dflt_pwr_limit = 0;
0419         goto out_free;
0420     }
0421 
0422     dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
0423 out_free:
0424     kfree(data);
0425 out:
0426     return dflt_pwr_limit;
0427 }
0428 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
0429 
0430 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
0431 {
0432     union acpi_object *wifi_pkg, *data;
0433     int ret, tbl_rev;
0434 
0435     data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
0436     if (IS_ERR(data))
0437         return PTR_ERR(data);
0438 
0439     wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
0440                      &tbl_rev);
0441     if (IS_ERR(wifi_pkg)) {
0442         ret = PTR_ERR(wifi_pkg);
0443         goto out_free;
0444     }
0445 
0446     if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
0447         tbl_rev != 0) {
0448         ret = -EINVAL;
0449         goto out_free;
0450     }
0451 
0452     *extl_clk = wifi_pkg->package.elements[1].integer.value;
0453 
0454     ret = 0;
0455 
0456 out_free:
0457     kfree(data);
0458     return ret;
0459 }
0460 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv);
0461 
0462 static int iwl_sar_set_profile(union acpi_object *table,
0463                    struct iwl_sar_profile *profile,
0464                    bool enabled, u8 num_chains, u8 num_sub_bands)
0465 {
0466     int i, j, idx = 0;
0467 
0468     /*
0469      * The table from ACPI is flat, but we store it in a
0470      * structured array.
0471      */
0472     for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) {
0473         for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) {
0474             /* if we don't have the values, use the default */
0475             if (i >= num_chains || j >= num_sub_bands) {
0476                 profile->chains[i].subbands[j] = 0;
0477             } else {
0478                 if (table[idx].type != ACPI_TYPE_INTEGER ||
0479                     table[idx].integer.value > U8_MAX)
0480                     return -EINVAL;
0481 
0482                 profile->chains[i].subbands[j] =
0483                     table[idx].integer.value;
0484 
0485                 idx++;
0486             }
0487         }
0488     }
0489 
0490     /* Only if all values were valid can the profile be enabled */
0491     profile->enabled = enabled;
0492 
0493     return 0;
0494 }
0495 
0496 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
0497                   __le16 *per_chain, u32 n_subbands,
0498                   int prof_a, int prof_b)
0499 {
0500     int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b };
0501     int i, j;
0502 
0503     for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) {
0504         struct iwl_sar_profile *prof;
0505 
0506         /* don't allow SAR to be disabled (profile 0 means disable) */
0507         if (profs[i] == 0)
0508             return -EPERM;
0509 
0510         /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */
0511         if (profs[i] > ACPI_SAR_PROFILE_NUM)
0512             return -EINVAL;
0513 
0514         /* profiles go from 1 to 4, so decrement to access the array */
0515         prof = &fwrt->sar_profiles[profs[i] - 1];
0516 
0517         /* if the profile is disabled, do nothing */
0518         if (!prof->enabled) {
0519             IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",
0520                     profs[i]);
0521             /*
0522              * if one of the profiles is disabled, we
0523              * ignore all of them and return 1 to
0524              * differentiate disabled from other failures.
0525              */
0526             return 1;
0527         }
0528 
0529         IWL_DEBUG_INFO(fwrt,
0530                    "SAR EWRD: chain %d profile index %d\n",
0531                    i, profs[i]);
0532         IWL_DEBUG_RADIO(fwrt, "  Chain[%d]:\n", i);
0533         for (j = 0; j < n_subbands; j++) {
0534             per_chain[i * n_subbands + j] =
0535                 cpu_to_le16(prof->chains[i].subbands[j]);
0536             IWL_DEBUG_RADIO(fwrt, "    Band[%d] = %d * .125dBm\n",
0537                     j, prof->chains[i].subbands[j]);
0538         }
0539     }
0540 
0541     return 0;
0542 }
0543 
0544 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt,
0545                __le16 *per_chain, u32 n_tables, u32 n_subbands,
0546                int prof_a, int prof_b)
0547 {
0548     int i, ret = 0;
0549 
0550     for (i = 0; i < n_tables; i++) {
0551         ret = iwl_sar_fill_table(fwrt,
0552              &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0],
0553              n_subbands, prof_a, prof_b);
0554         if (ret)
0555             break;
0556     }
0557 
0558     return ret;
0559 }
0560 IWL_EXPORT_SYMBOL(iwl_sar_select_profile);
0561 
0562 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
0563 {
0564     union acpi_object *wifi_pkg, *table, *data;
0565     int ret, tbl_rev;
0566     u32 flags;
0567     u8 num_chains, num_sub_bands;
0568 
0569     data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD);
0570     if (IS_ERR(data))
0571         return PTR_ERR(data);
0572 
0573     /* start by trying to read revision 2 */
0574     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0575                      ACPI_WRDS_WIFI_DATA_SIZE_REV2,
0576                      &tbl_rev);
0577     if (!IS_ERR(wifi_pkg)) {
0578         if (tbl_rev != 2) {
0579             ret = PTR_ERR(wifi_pkg);
0580             goto out_free;
0581         }
0582 
0583         num_chains = ACPI_SAR_NUM_CHAINS_REV2;
0584         num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
0585 
0586         goto read_table;
0587     }
0588 
0589     /* then try revision 1 */
0590     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0591                      ACPI_WRDS_WIFI_DATA_SIZE_REV1,
0592                      &tbl_rev);
0593     if (!IS_ERR(wifi_pkg)) {
0594         if (tbl_rev != 1) {
0595             ret = PTR_ERR(wifi_pkg);
0596             goto out_free;
0597         }
0598 
0599         num_chains = ACPI_SAR_NUM_CHAINS_REV1;
0600         num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
0601 
0602         goto read_table;
0603     }
0604 
0605     /* then finally revision 0 */
0606     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0607                      ACPI_WRDS_WIFI_DATA_SIZE_REV0,
0608                      &tbl_rev);
0609     if (!IS_ERR(wifi_pkg)) {
0610         if (tbl_rev != 0) {
0611             ret = PTR_ERR(wifi_pkg);
0612             goto out_free;
0613         }
0614 
0615         num_chains = ACPI_SAR_NUM_CHAINS_REV0;
0616         num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
0617 
0618         goto read_table;
0619     }
0620 
0621     ret = PTR_ERR(wifi_pkg);
0622     goto out_free;
0623 
0624 read_table:
0625     if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
0626         ret = -EINVAL;
0627         goto out_free;
0628     }
0629 
0630     IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
0631 
0632     flags = wifi_pkg->package.elements[1].integer.value;
0633     fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS;
0634 
0635     /* position of the actual table */
0636     table = &wifi_pkg->package.elements[2];
0637 
0638     /* The profile from WRDS is officially profile 1, but goes
0639      * into sar_profiles[0] (because we don't have a profile 0).
0640      */
0641     ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0],
0642                   flags & IWL_SAR_ENABLE_MSK,
0643                   num_chains, num_sub_bands);
0644 out_free:
0645     kfree(data);
0646     return ret;
0647 }
0648 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table);
0649 
0650 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
0651 {
0652     union acpi_object *wifi_pkg, *data;
0653     bool enabled;
0654     int i, n_profiles, tbl_rev, pos;
0655     int ret = 0;
0656     u8 num_chains, num_sub_bands;
0657 
0658     data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
0659     if (IS_ERR(data))
0660         return PTR_ERR(data);
0661 
0662     /* start by trying to read revision 2 */
0663     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0664                      ACPI_EWRD_WIFI_DATA_SIZE_REV2,
0665                      &tbl_rev);
0666     if (!IS_ERR(wifi_pkg)) {
0667         if (tbl_rev != 2) {
0668             ret = PTR_ERR(wifi_pkg);
0669             goto out_free;
0670         }
0671 
0672         num_chains = ACPI_SAR_NUM_CHAINS_REV2;
0673         num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
0674 
0675         goto read_table;
0676     }
0677 
0678     /* then try revision 1 */
0679     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0680                      ACPI_EWRD_WIFI_DATA_SIZE_REV1,
0681                      &tbl_rev);
0682     if (!IS_ERR(wifi_pkg)) {
0683         if (tbl_rev != 1) {
0684             ret = PTR_ERR(wifi_pkg);
0685             goto out_free;
0686         }
0687 
0688         num_chains = ACPI_SAR_NUM_CHAINS_REV1;
0689         num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
0690 
0691         goto read_table;
0692     }
0693 
0694     /* then finally revision 0 */
0695     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
0696                      ACPI_EWRD_WIFI_DATA_SIZE_REV0,
0697                      &tbl_rev);
0698     if (!IS_ERR(wifi_pkg)) {
0699         if (tbl_rev != 0) {
0700             ret = PTR_ERR(wifi_pkg);
0701             goto out_free;
0702         }
0703 
0704         num_chains = ACPI_SAR_NUM_CHAINS_REV0;
0705         num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
0706 
0707         goto read_table;
0708     }
0709 
0710     ret = PTR_ERR(wifi_pkg);
0711     goto out_free;
0712 
0713 read_table:
0714     if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
0715         wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
0716         ret = -EINVAL;
0717         goto out_free;
0718     }
0719 
0720     enabled = !!(wifi_pkg->package.elements[1].integer.value);
0721     n_profiles = wifi_pkg->package.elements[2].integer.value;
0722 
0723     /*
0724      * Check the validity of n_profiles.  The EWRD profiles start
0725      * from index 1, so the maximum value allowed here is
0726      * ACPI_SAR_PROFILES_NUM - 1.
0727      */
0728     if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) {
0729         ret = -EINVAL;
0730         goto out_free;
0731     }
0732 
0733     /* the tables start at element 3 */
0734     pos = 3;
0735 
0736     for (i = 0; i < n_profiles; i++) {
0737         /* The EWRD profiles officially go from 2 to 4, but we
0738          * save them in sar_profiles[1-3] (because we don't
0739          * have profile 0).  So in the array we start from 1.
0740          */
0741         ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos],
0742                       &fwrt->sar_profiles[i + 1], enabled,
0743                       num_chains, num_sub_bands);
0744         if (ret < 0)
0745             break;
0746 
0747         /* go to the next table */
0748         pos += num_chains * num_sub_bands;
0749     }
0750 
0751 out_free:
0752     kfree(data);
0753     return ret;
0754 }
0755 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table);
0756 
0757 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt)
0758 {
0759     union acpi_object *wifi_pkg, *data;
0760     int i, j, k, ret, tbl_rev;
0761     u8 num_bands, num_profiles;
0762     static const struct {
0763         u8 revisions;
0764         u8 bands;
0765         u8 profiles;
0766         u8 min_profiles;
0767     } rev_data[] = {
0768         {
0769             .revisions = BIT(3),
0770             .bands = ACPI_GEO_NUM_BANDS_REV2,
0771             .profiles = ACPI_NUM_GEO_PROFILES_REV3,
0772             .min_profiles = 3,
0773         },
0774         {
0775             .revisions = BIT(2),
0776             .bands = ACPI_GEO_NUM_BANDS_REV2,
0777             .profiles = ACPI_NUM_GEO_PROFILES,
0778         },
0779         {
0780             .revisions = BIT(0) | BIT(1),
0781             .bands = ACPI_GEO_NUM_BANDS_REV0,
0782             .profiles = ACPI_NUM_GEO_PROFILES,
0783         },
0784     };
0785     int idx;
0786     /* start from one to skip the domain */
0787     int entry_idx = 1;
0788 
0789     BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
0790     BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
0791 
0792     data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
0793     if (IS_ERR(data))
0794         return PTR_ERR(data);
0795 
0796     /* read the highest revision we understand first */
0797     for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
0798         /* min_profiles != 0 requires num_profiles header */
0799         u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
0800         u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
0801                    rev_data[idx].bands;
0802         u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
0803         u32 min_size;
0804 
0805         if (!rev_data[idx].min_profiles)
0806             min_size = max_size;
0807         else
0808             min_size = hdr_size +
0809                    profile_size * rev_data[idx].min_profiles;
0810 
0811         wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
0812                                min_size, max_size,
0813                                &tbl_rev);
0814         if (!IS_ERR(wifi_pkg)) {
0815             if (!(BIT(tbl_rev) & rev_data[idx].revisions))
0816                 continue;
0817 
0818             num_bands = rev_data[idx].bands;
0819             num_profiles = rev_data[idx].profiles;
0820 
0821             if (rev_data[idx].min_profiles) {
0822                 /* read header that says # of profiles */
0823                 union acpi_object *entry;
0824 
0825                 entry = &wifi_pkg->package.elements[entry_idx];
0826                 entry_idx++;
0827                 if (entry->type != ACPI_TYPE_INTEGER ||
0828                     entry->integer.value > num_profiles) {
0829                     ret = -EINVAL;
0830                     goto out_free;
0831                 }
0832                 num_profiles = entry->integer.value;
0833 
0834                 /*
0835                  * this also validates >= min_profiles since we
0836                  * otherwise wouldn't have gotten the data when
0837                  * looking up in ACPI
0838                  */
0839                 if (wifi_pkg->package.count !=
0840                     hdr_size + profile_size * num_profiles) {
0841                     ret = -EINVAL;
0842                     goto out_free;
0843                 }
0844             }
0845             goto read_table;
0846         }
0847     }
0848 
0849     if (idx < ARRAY_SIZE(rev_data))
0850         ret = PTR_ERR(wifi_pkg);
0851     else
0852         ret = -ENOENT;
0853     goto out_free;
0854 
0855 read_table:
0856     fwrt->geo_rev = tbl_rev;
0857     for (i = 0; i < num_profiles; i++) {
0858         for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) {
0859             union acpi_object *entry;
0860 
0861             /*
0862              * num_bands is either 2 or 3, if it's only 2 then
0863              * fill the third band (6 GHz) with the values from
0864              * 5 GHz (second band)
0865              */
0866             if (j >= num_bands) {
0867                 fwrt->geo_profiles[i].bands[j].max =
0868                     fwrt->geo_profiles[i].bands[1].max;
0869             } else {
0870                 entry = &wifi_pkg->package.elements[entry_idx];
0871                 entry_idx++;
0872                 if (entry->type != ACPI_TYPE_INTEGER ||
0873                     entry->integer.value > U8_MAX) {
0874                     ret = -EINVAL;
0875                     goto out_free;
0876                 }
0877 
0878                 fwrt->geo_profiles[i].bands[j].max =
0879                     entry->integer.value;
0880             }
0881 
0882             for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) {
0883                 /* same here as above */
0884                 if (j >= num_bands) {
0885                     fwrt->geo_profiles[i].bands[j].chains[k] =
0886                         fwrt->geo_profiles[i].bands[1].chains[k];
0887                 } else {
0888                     entry = &wifi_pkg->package.elements[entry_idx];
0889                     entry_idx++;
0890                     if (entry->type != ACPI_TYPE_INTEGER ||
0891                         entry->integer.value > U8_MAX) {
0892                         ret = -EINVAL;
0893                         goto out_free;
0894                     }
0895 
0896                     fwrt->geo_profiles[i].bands[j].chains[k] =
0897                         entry->integer.value;
0898                 }
0899             }
0900         }
0901     }
0902 
0903     fwrt->geo_num_profiles = num_profiles;
0904     fwrt->geo_enabled = true;
0905     ret = 0;
0906 out_free:
0907     kfree(data);
0908     return ret;
0909 }
0910 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table);
0911 
0912 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
0913 {
0914     /*
0915      * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on
0916      * earlier firmware versions.  Unfortunately, we don't have a
0917      * TLV API flag to rely on, so rely on the major version which
0918      * is in the first byte of ucode_ver.  This was implemented
0919      * initially on version 38 and then backported to 17.  It was
0920      * also backported to 29, but only for 7265D devices.  The
0921      * intention was to have it in 36 as well, but not all 8000
0922      * family got this feature enabled.  The 8000 family is the
0923      * only one using version 36, so skip this version entirely.
0924      */
0925     return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||
0926         (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&
0927          fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) ||
0928         (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
0929          ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) ==
0930           CSR_HW_REV_TYPE_7265D));
0931 }
0932 IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
0933 
0934 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
0935              struct iwl_per_chain_offset *table,
0936              u32 n_bands, u32 n_profiles)
0937 {
0938     int i, j;
0939 
0940     if (!fwrt->geo_enabled)
0941         return -ENODATA;
0942 
0943     if (!iwl_sar_geo_support(fwrt))
0944         return -EOPNOTSUPP;
0945 
0946     for (i = 0; i < n_profiles; i++) {
0947         for (j = 0; j < n_bands; j++) {
0948             struct iwl_per_chain_offset *chain =
0949                 &table[i * n_bands + j];
0950 
0951             chain->max_tx_power =
0952                 cpu_to_le16(fwrt->geo_profiles[i].bands[j].max);
0953             chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0];
0954             chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1];
0955             IWL_DEBUG_RADIO(fwrt,
0956                     "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n",
0957                     i, j,
0958                     fwrt->geo_profiles[i].bands[j].chains[0],
0959                     fwrt->geo_profiles[i].bands[j].chains[1],
0960                     fwrt->geo_profiles[i].bands[j].max);
0961         }
0962     }
0963 
0964     return 0;
0965 }
0966 IWL_EXPORT_SYMBOL(iwl_sar_geo_init);
0967 
0968 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
0969 {
0970     int ret;
0971     u8 value;
0972     __le32 config_bitmap = 0;
0973 
0974     /*
0975      ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2'
0976      */
0977     ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
0978                   DSM_FUNC_ENABLE_INDONESIA_5G2,
0979                   &iwl_guid, &value);
0980 
0981     if (!ret && value == DSM_VALUE_INDONESIA_ENABLE)
0982         config_bitmap |=
0983             cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
0984 
0985     /*
0986      ** Evaluate func 'DSM_FUNC_DISABLE_SRD'
0987      */
0988     ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
0989                   DSM_FUNC_DISABLE_SRD,
0990                   &iwl_guid, &value);
0991     if (!ret) {
0992         if (value == DSM_VALUE_SRD_PASSIVE)
0993             config_bitmap |=
0994                 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
0995         else if (value == DSM_VALUE_SRD_DISABLE)
0996             config_bitmap |=
0997                 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
0998     }
0999 
1000     return config_bitmap;
1001 }
1002 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap);
1003 
1004 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
1005 {
1006     union acpi_object *wifi_pkg, *data, *flags;
1007     int i, j, ret, tbl_rev, num_sub_bands = 0;
1008     int idx = 2;
1009 
1010     fwrt->ppag_flags = 0;
1011 
1012     data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
1013     if (IS_ERR(data))
1014         return PTR_ERR(data);
1015 
1016     /* try to read ppag table rev 2 or 1 (both have the same data size) */
1017     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1018                 ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
1019 
1020     if (!IS_ERR(wifi_pkg)) {
1021         if (tbl_rev == 1 || tbl_rev == 2) {
1022             num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1023             IWL_DEBUG_RADIO(fwrt,
1024                     "Reading PPAG table v2 (tbl_rev=%d)\n",
1025                     tbl_rev);
1026             goto read_table;
1027         } else {
1028             ret = -EINVAL;
1029             goto out_free;
1030         }
1031     }
1032 
1033     /* try to read ppag table revision 0 */
1034     wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1035             ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
1036 
1037     if (!IS_ERR(wifi_pkg)) {
1038         if (tbl_rev != 0) {
1039             ret = -EINVAL;
1040             goto out_free;
1041         }
1042         num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1043         IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
1044         goto read_table;
1045     }
1046 
1047 read_table:
1048     fwrt->ppag_ver = tbl_rev;
1049     flags = &wifi_pkg->package.elements[1];
1050 
1051     if (flags->type != ACPI_TYPE_INTEGER) {
1052         ret = -EINVAL;
1053         goto out_free;
1054     }
1055 
1056     fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK;
1057 
1058     if (!fwrt->ppag_flags) {
1059         ret = 0;
1060         goto out_free;
1061     }
1062 
1063     /*
1064      * read, verify gain values and save them into the PPAG table.
1065      * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
1066      * following sub-bands to High-Band (5GHz).
1067      */
1068     for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
1069         for (j = 0; j < num_sub_bands; j++) {
1070             union acpi_object *ent;
1071 
1072             ent = &wifi_pkg->package.elements[idx++];
1073             if (ent->type != ACPI_TYPE_INTEGER) {
1074                 ret = -EINVAL;
1075                 goto out_free;
1076             }
1077 
1078             fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
1079 
1080             if ((j == 0 &&
1081                 (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB ||
1082                  fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) ||
1083                 (j != 0 &&
1084                 (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB ||
1085                 fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) {
1086                     fwrt->ppag_flags = 0;
1087                     ret = -EINVAL;
1088                     goto out_free;
1089                 }
1090         }
1091     }
1092 
1093 
1094     ret = 0;
1095 
1096 out_free:
1097     kfree(data);
1098     return ret;
1099 }
1100 IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table);
1101 
1102 int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd,
1103             int *cmd_size)
1104 {
1105         u8 cmd_ver;
1106         int i, j, num_sub_bands;
1107         s8 *gain;
1108 
1109         if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
1110                 IWL_DEBUG_RADIO(fwrt,
1111                                 "PPAG capability not supported by FW, command not sent.\n");
1112                 return -EINVAL;
1113         }
1114         if (!fwrt->ppag_flags) {
1115                 IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
1116                 return -EINVAL;
1117         }
1118 
1119         /* The 'flags' field is the same in v1 and in v2 so we can just
1120          * use v1 to access it.
1121          */
1122         cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
1123         cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
1124                                         WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD),
1125                                         IWL_FW_CMD_VER_UNKNOWN);
1126     if (cmd_ver == 1) {
1127                 num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1128                 gain = cmd->v1.gain[0];
1129                 *cmd_size = sizeof(cmd->v1);
1130                 if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) {
1131                         IWL_DEBUG_RADIO(fwrt,
1132                                         "PPAG table rev is %d but FW supports v1, sending truncated table\n",
1133                                         fwrt->ppag_ver);
1134                         cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
1135         }
1136     } else if (cmd_ver == 2 || cmd_ver == 3) {
1137                 num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1138                 gain = cmd->v2.gain[0];
1139                 *cmd_size = sizeof(cmd->v2);
1140                 if (fwrt->ppag_ver == 0) {
1141                         IWL_DEBUG_RADIO(fwrt,
1142                                         "PPAG table is v1 but FW supports v2, sending padded table\n");
1143                 } else if (cmd_ver == 2 && fwrt->ppag_ver == 2) {
1144                         IWL_DEBUG_RADIO(fwrt,
1145                                         "PPAG table is v3 but FW supports v2, sending partial bitmap.\n");
1146                         cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
1147                 }
1148         } else {
1149                 IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
1150                 return -EINVAL;
1151         }
1152 
1153     for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
1154                 for (j = 0; j < num_sub_bands; j++) {
1155                         gain[i * num_sub_bands + j] =
1156                                 fwrt->ppag_chains[i].subbands[j];
1157                         IWL_DEBUG_RADIO(fwrt,
1158                                         "PPAG table: chain[%d] band[%d]: gain = %d\n",
1159                                         i, j, gain[i * num_sub_bands + j]);
1160                 }
1161         }
1162 
1163     return 0;
1164 }
1165 IWL_EXPORT_SYMBOL(iwl_read_ppag_table);
1166 
1167 bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt)
1168 {
1169 
1170     if (!dmi_check_system(dmi_ppag_approved_list)) {
1171         IWL_DEBUG_RADIO(fwrt,
1172             "System vendor '%s' is not in the approved list, disabling PPAG.\n",
1173             dmi_get_system_info(DMI_SYS_VENDOR));
1174             fwrt->ppag_flags = 0;
1175             return false;
1176     }
1177 
1178     return true;
1179 }
1180 IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved);