The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/iwlwifi/fw/acpi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2 /*
    3  * Copyright (C) 2017 Intel Deutschland GmbH
    4  * Copyright (C) 2019-2022 Intel Corporation
    5  */
    6 #include <linux/uuid.h>
    7 #include <linux/dmi.h>
    8 #include "iwl-drv.h"
    9 #include "iwl-debug.h"
   10 #include "acpi.h"
   11 #include "fw/runtime.h"
   12 
   13 const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
   14                                   0xA5, 0xB3, 0x1F, 0x73,
   15                                   0x8E, 0x28, 0x5A, 0xDE);
   16 IWL_EXPORT_SYMBOL(iwl_guid);
   17 
   18 const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29,
   19                                       0x81, 0x4F, 0x75, 0xE4,
   20                                       0xDD, 0x26, 0xB5, 0xFD);
   21 IWL_EXPORT_SYMBOL(iwl_rfi_guid);
   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 
   47 static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
   48                                acpi_handle *ret_handle)
   49 {
   50         acpi_handle root_handle;
   51         acpi_status status;
   52 
   53         root_handle = ACPI_HANDLE(dev);
   54         if (!root_handle) {
   55                 IWL_DEBUG_DEV_RADIO(dev,
   56                                     "ACPI: Could not retrieve root port handle\n");
   57                 return -ENOENT;
   58         }
   59 
   60         status = acpi_get_handle(root_handle, method, ret_handle);
   61         if (ACPI_FAILURE(status)) {
   62                 IWL_DEBUG_DEV_RADIO(dev,
   63                                     "ACPI: %s method not found\n", method);
   64                 return -ENOENT;
   65         }
   66         return 0;
   67 }
   68 
   69 void *iwl_acpi_get_object(struct device *dev, acpi_string method)
   70 {
   71         struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
   72         acpi_handle handle;
   73         acpi_status status;
   74         int ret;
   75 
   76         ret = iwl_acpi_get_handle(dev, method, &handle);
   77         if (ret)
   78                 return ERR_PTR(-ENOENT);
   79 
   80         /* Call the method with no arguments */
   81         status = acpi_evaluate_object(handle, NULL, NULL, &buf);
   82         if (ACPI_FAILURE(status)) {
   83                 IWL_DEBUG_DEV_RADIO(dev,
   84                                     "ACPI: %s method invocation failed (status: 0x%x)\n",
   85                                     method, status);
   86                 return ERR_PTR(-ENOENT);
   87         }
   88         return buf.pointer;
   89 }
   90 IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
   91 
   92 /*
   93  * Generic function for evaluating a method defined in the device specific
   94  * method (DSM) interface. The returned acpi object must be freed by calling
   95  * function.
   96  */
   97 static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
   98                                      union acpi_object *args,
   99                                      const guid_t *guid)
  100 {
  101         union acpi_object *obj;
  102 
  103         obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func,
  104                                 args);
  105         if (!obj) {
  106                 IWL_DEBUG_DEV_RADIO(dev,
  107                                     "ACPI: DSM method invocation failed (rev: %d, func:%d)\n",
  108                                     rev, func);
  109                 return ERR_PTR(-ENOENT);
  110         }
  111         return obj;
  112 }
  113 
  114 /*
  115  * Generic function to evaluate a DSM with no arguments
  116  * and an integer return value,
  117  * (as an integer object or inside a buffer object),
  118  * verify and assign the value in the "value" parameter.
  119  * return 0 in success and the appropriate errno otherwise.
  120  */
  121 static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
  122                                     const guid_t *guid, u64 *value,
  123                                     size_t expected_size)
  124 {
  125         union acpi_object *obj;
  126         int ret = 0;
  127 
  128         obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid);
  129         if (IS_ERR(obj)) {
  130                 IWL_DEBUG_DEV_RADIO(dev,
  131                                     "Failed to get  DSM object. func= %d\n",
  132                                     func);
  133                 return -ENOENT;
  134         }
  135 
  136         if (obj->type == ACPI_TYPE_INTEGER) {
  137                 *value = obj->integer.value;
  138         } else if (obj->type == ACPI_TYPE_BUFFER) {
  139                 __le64 le_value = 0;
  140 
  141                 if (WARN_ON_ONCE(expected_size > sizeof(le_value)))
  142                         return -EINVAL;
  143 
  144                 /* if the buffer size doesn't match the expected size */
  145                 if (obj->buffer.length != expected_size)
  146                         IWL_DEBUG_DEV_RADIO(dev,
  147                                             "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
  148                                             obj->buffer.length);
  149 
  150                  /* assuming LE from Intel BIOS spec */
  151                 memcpy(&le_value, obj->buffer.pointer,
  152                        min_t(size_t, expected_size, (size_t)obj->buffer.length));
  153                 *value = le64_to_cpu(le_value);
  154         } else {
  155                 IWL_DEBUG_DEV_RADIO(dev,
  156                                     "ACPI: DSM method did not return a valid object, type=%d\n",
  157                                     obj->type);
  158                 ret = -EINVAL;
  159                 goto out;
  160         }
  161 
  162         IWL_DEBUG_DEV_RADIO(dev,
  163                             "ACPI: DSM method evaluated: func=%d, ret=%d\n",
  164                             func, ret);
  165 out:
  166         ACPI_FREE(obj);
  167         return ret;
  168 }
  169 
  170 /*
  171  * Evaluate a DSM with no arguments and a u8 return value,
  172  */
  173 int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
  174                         const guid_t *guid, u8 *value)
  175 {
  176         int ret;
  177         u64 val;
  178 
  179         ret = iwl_acpi_get_dsm_integer(dev, rev, func,
  180                                        guid, &val, sizeof(u8));
  181 
  182         if (ret < 0)
  183                 return ret;
  184 
  185         /* cast val (u64) to be u8 */
  186         *value = (u8)val;
  187         return 0;
  188 }
  189 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
  190 
  191 /*
  192  * Evaluate a DSM with no arguments and a u32 return value,
  193  */
  194 int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
  195                          const guid_t *guid, u32 *value)
  196 {
  197         int ret;
  198         u64 val;
  199 
  200         ret = iwl_acpi_get_dsm_integer(dev, rev, func,
  201                                        guid, &val, sizeof(u32));
  202 
  203         if (ret < 0)
  204                 return ret;
  205 
  206         /* cast val (u64) to be u32 */
  207         *value = (u32)val;
  208         return 0;
  209 }
  210 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32);
  211 
  212 union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev,
  213                                                union acpi_object *data,
  214                                                int min_data_size,
  215                                                int max_data_size,
  216                                                int *tbl_rev)
  217 {
  218         int i;
  219         union acpi_object *wifi_pkg;
  220 
  221         /*
  222          * We need at least one entry in the wifi package that
  223          * describes the domain, and one more entry, otherwise there's
  224          * no point in reading it.
  225          */
  226         if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
  227                 return ERR_PTR(-EINVAL);
  228 
  229         /*
  230          * We need at least two packages, one for the revision and one
  231          * for the data itself.  Also check that the revision is valid
  232          * (i.e. it is an integer (each caller has to check by itself
  233          * if the returned revision is supported)).
  234          */
  235         if (data->type != ACPI_TYPE_PACKAGE ||
  236             data->package.count < 2 ||
  237             data->package.elements[0].type != ACPI_TYPE_INTEGER) {
  238                 IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
  239                 return ERR_PTR(-EINVAL);
  240         }
  241 
  242         *tbl_rev = data->package.elements[0].integer.value;
  243 
  244         /* loop through all the packages to find the one for WiFi */
  245         for (i = 1; i < data->package.count; i++) {
  246                 union acpi_object *domain;
  247 
  248                 wifi_pkg = &data->package.elements[i];
  249 
  250                 /* skip entries that are not a package with the right size */
  251                 if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
  252                     wifi_pkg->package.count < min_data_size ||
  253                     wifi_pkg->package.count > max_data_size)
  254                         continue;
  255 
  256                 domain = &wifi_pkg->package.elements[0];
  257                 if (domain->type == ACPI_TYPE_INTEGER &&
  258                     domain->integer.value == ACPI_WIFI_DOMAIN)
  259                         goto found;
  260         }
  261 
  262         return ERR_PTR(-ENOENT);
  263 
  264 found:
  265         return wifi_pkg;
  266 }
  267 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range);
  268 
  269 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt,
  270                      union iwl_tas_config_cmd *cmd, int fw_ver)
  271 {
  272         union acpi_object *wifi_pkg, *data;
  273         int ret, tbl_rev, i, block_list_size, enabled;
  274 
  275         data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD);
  276         if (IS_ERR(data))
  277                 return PTR_ERR(data);
  278 
  279         /* try to read wtas table revision 1 or revision 0*/
  280         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  281                                          ACPI_WTAS_WIFI_DATA_SIZE,
  282                                          &tbl_rev);
  283         if (IS_ERR(wifi_pkg)) {
  284                 ret = PTR_ERR(wifi_pkg);
  285                 goto out_free;
  286         }
  287 
  288         if (tbl_rev == 1 && wifi_pkg->package.elements[1].type ==
  289                 ACPI_TYPE_INTEGER) {
  290                 u32 tas_selection =
  291                         (u32)wifi_pkg->package.elements[1].integer.value;
  292                 u16 override_iec =
  293                         (tas_selection & ACPI_WTAS_OVERRIDE_IEC_MSK) >> ACPI_WTAS_OVERRIDE_IEC_POS;
  294                 u16 enabled_iec = (tas_selection & ACPI_WTAS_ENABLE_IEC_MSK) >>
  295                         ACPI_WTAS_ENABLE_IEC_POS;
  296                 u8 usa_tas_uhb = (tas_selection & ACPI_WTAS_USA_UHB_MSK) >> ACPI_WTAS_USA_UHB_POS;
  297 
  298 
  299                 enabled = tas_selection & ACPI_WTAS_ENABLED_MSK;
  300                 if (fw_ver <= 3) {
  301                         cmd->v3.override_tas_iec = cpu_to_le16(override_iec);
  302                         cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec);
  303                 } else {
  304                         cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb;
  305                         cmd->v4.override_tas_iec = (u8)override_iec;
  306                         cmd->v4.enable_tas_iec = (u8)enabled_iec;
  307                 }
  308 
  309         } else if (tbl_rev == 0 &&
  310                 wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) {
  311                 enabled = !!wifi_pkg->package.elements[1].integer.value;
  312         } else {
  313                 ret = -EINVAL;
  314                 goto out_free;
  315         }
  316 
  317         if (!enabled) {
  318                 IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n");
  319                 ret = 0;
  320                 goto out_free;
  321         }
  322 
  323         IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev);
  324         if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER ||
  325             wifi_pkg->package.elements[2].integer.value >
  326             APCI_WTAS_BLACK_LIST_MAX) {
  327                 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n",
  328                                 wifi_pkg->package.elements[2].integer.value);
  329                 ret = -EINVAL;
  330                 goto out_free;
  331         }
  332         block_list_size = wifi_pkg->package.elements[2].integer.value;
  333         cmd->v4.block_list_size = cpu_to_le32(block_list_size);
  334 
  335         IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size);
  336         if (block_list_size > APCI_WTAS_BLACK_LIST_MAX) {
  337                 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n",
  338                                 block_list_size);
  339                 ret = -EINVAL;
  340                 goto out_free;
  341         }
  342 
  343         for (i = 0; i < block_list_size; i++) {
  344                 u32 country;
  345 
  346                 if (wifi_pkg->package.elements[3 + i].type !=
  347                     ACPI_TYPE_INTEGER) {
  348                         IWL_DEBUG_RADIO(fwrt,
  349                                         "TAS invalid array elem %d\n", 3 + i);
  350                         ret = -EINVAL;
  351                         goto out_free;
  352                 }
  353 
  354                 country = wifi_pkg->package.elements[3 + i].integer.value;
  355                 cmd->v4.block_list_array[i] = cpu_to_le32(country);
  356                 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
  357         }
  358 
  359         ret = 1;
  360 out_free:
  361         kfree(data);
  362         return ret;
  363 }
  364 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas);
  365 
  366 int iwl_acpi_get_mcc(struct device *dev, char *mcc)
  367 {
  368         union acpi_object *wifi_pkg, *data;
  369         u32 mcc_val;
  370         int ret, tbl_rev;
  371 
  372         data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
  373         if (IS_ERR(data))
  374                 return PTR_ERR(data);
  375 
  376         wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
  377                                          &tbl_rev);
  378         if (IS_ERR(wifi_pkg)) {
  379                 ret = PTR_ERR(wifi_pkg);
  380                 goto out_free;
  381         }
  382 
  383         if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
  384             tbl_rev != 0) {
  385                 ret = -EINVAL;
  386                 goto out_free;
  387         }
  388 
  389         mcc_val = wifi_pkg->package.elements[1].integer.value;
  390 
  391         mcc[0] = (mcc_val >> 8) & 0xff;
  392         mcc[1] = mcc_val & 0xff;
  393         mcc[2] = '\0';
  394 
  395         ret = 0;
  396 out_free:
  397         kfree(data);
  398         return ret;
  399 }
  400 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc);
  401 
  402 u64 iwl_acpi_get_pwr_limit(struct device *dev)
  403 {
  404         union acpi_object *data, *wifi_pkg;
  405         u64 dflt_pwr_limit;
  406         int tbl_rev;
  407 
  408         data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
  409         if (IS_ERR(data)) {
  410                 dflt_pwr_limit = 0;
  411                 goto out;
  412         }
  413 
  414         wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
  415                                          ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
  416         if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
  417             wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
  418                 dflt_pwr_limit = 0;
  419                 goto out_free;
  420         }
  421 
  422         dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
  423 out_free:
  424         kfree(data);
  425 out:
  426         return dflt_pwr_limit;
  427 }
  428 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
  429 
  430 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
  431 {
  432         union acpi_object *wifi_pkg, *data;
  433         int ret, tbl_rev;
  434 
  435         data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
  436         if (IS_ERR(data))
  437                 return PTR_ERR(data);
  438 
  439         wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
  440                                          &tbl_rev);
  441         if (IS_ERR(wifi_pkg)) {
  442                 ret = PTR_ERR(wifi_pkg);
  443                 goto out_free;
  444         }
  445 
  446         if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
  447             tbl_rev != 0) {
  448                 ret = -EINVAL;
  449                 goto out_free;
  450         }
  451 
  452         *extl_clk = wifi_pkg->package.elements[1].integer.value;
  453 
  454         ret = 0;
  455 
  456 out_free:
  457         kfree(data);
  458         return ret;
  459 }
  460 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv);
  461 
  462 static int iwl_sar_set_profile(union acpi_object *table,
  463                                struct iwl_sar_profile *profile,
  464                                bool enabled, u8 num_chains, u8 num_sub_bands)
  465 {
  466         int i, j, idx = 0;
  467 
  468         /*
  469          * The table from ACPI is flat, but we store it in a
  470          * structured array.
  471          */
  472         for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) {
  473                 for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) {
  474                         /* if we don't have the values, use the default */
  475                         if (i >= num_chains || j >= num_sub_bands) {
  476                                 profile->chains[i].subbands[j] = 0;
  477                         } else {
  478                                 if (table[idx].type != ACPI_TYPE_INTEGER ||
  479                                     table[idx].integer.value > U8_MAX)
  480                                         return -EINVAL;
  481 
  482                                 profile->chains[i].subbands[j] =
  483                                         table[idx].integer.value;
  484 
  485                                 idx++;
  486                         }
  487                 }
  488         }
  489 
  490         /* Only if all values were valid can the profile be enabled */
  491         profile->enabled = enabled;
  492 
  493         return 0;
  494 }
  495 
  496 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
  497                               __le16 *per_chain, u32 n_subbands,
  498                               int prof_a, int prof_b)
  499 {
  500         int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b };
  501         int i, j;
  502 
  503         for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) {
  504                 struct iwl_sar_profile *prof;
  505 
  506                 /* don't allow SAR to be disabled (profile 0 means disable) */
  507                 if (profs[i] == 0)
  508                         return -EPERM;
  509 
  510                 /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */
  511                 if (profs[i] > ACPI_SAR_PROFILE_NUM)
  512                         return -EINVAL;
  513 
  514                 /* profiles go from 1 to 4, so decrement to access the array */
  515                 prof = &fwrt->sar_profiles[profs[i] - 1];
  516 
  517                 /* if the profile is disabled, do nothing */
  518                 if (!prof->enabled) {
  519                         IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",
  520                                         profs[i]);
  521                         /*
  522                          * if one of the profiles is disabled, we
  523                          * ignore all of them and return 1 to
  524                          * differentiate disabled from other failures.
  525                          */
  526                         return 1;
  527                 }
  528 
  529                 IWL_DEBUG_INFO(fwrt,
  530                                "SAR EWRD: chain %d profile index %d\n",
  531                                i, profs[i]);
  532                 IWL_DEBUG_RADIO(fwrt, "  Chain[%d]:\n", i);
  533                 for (j = 0; j < n_subbands; j++) {
  534                         per_chain[i * n_subbands + j] =
  535                                 cpu_to_le16(prof->chains[i].subbands[j]);
  536                         IWL_DEBUG_RADIO(fwrt, "    Band[%d] = %d * .125dBm\n",
  537                                         j, prof->chains[i].subbands[j]);
  538                 }
  539         }
  540 
  541         return 0;
  542 }
  543 
  544 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt,
  545                            __le16 *per_chain, u32 n_tables, u32 n_subbands,
  546                            int prof_a, int prof_b)
  547 {
  548         int i, ret = 0;
  549 
  550         for (i = 0; i < n_tables; i++) {
  551                 ret = iwl_sar_fill_table(fwrt,
  552                          &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0],
  553                          n_subbands, prof_a, prof_b);
  554                 if (ret)
  555                         break;
  556         }
  557 
  558         return ret;
  559 }
  560 IWL_EXPORT_SYMBOL(iwl_sar_select_profile);
  561 
  562 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
  563 {
  564         union acpi_object *wifi_pkg, *table, *data;
  565         int ret, tbl_rev;
  566         u32 flags;
  567         u8 num_chains, num_sub_bands;
  568 
  569         data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD);
  570         if (IS_ERR(data))
  571                 return PTR_ERR(data);
  572 
  573         /* start by trying to read revision 2 */
  574         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  575                                          ACPI_WRDS_WIFI_DATA_SIZE_REV2,
  576                                          &tbl_rev);
  577         if (!IS_ERR(wifi_pkg)) {
  578                 if (tbl_rev != 2) {
  579                         ret = PTR_ERR(wifi_pkg);
  580                         goto out_free;
  581                 }
  582 
  583                 num_chains = ACPI_SAR_NUM_CHAINS_REV2;
  584                 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
  585 
  586                 goto read_table;
  587         }
  588 
  589         /* then try revision 1 */
  590         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  591                                          ACPI_WRDS_WIFI_DATA_SIZE_REV1,
  592                                          &tbl_rev);
  593         if (!IS_ERR(wifi_pkg)) {
  594                 if (tbl_rev != 1) {
  595                         ret = PTR_ERR(wifi_pkg);
  596                         goto out_free;
  597                 }
  598 
  599                 num_chains = ACPI_SAR_NUM_CHAINS_REV1;
  600                 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
  601 
  602                 goto read_table;
  603         }
  604 
  605         /* then finally revision 0 */
  606         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  607                                          ACPI_WRDS_WIFI_DATA_SIZE_REV0,
  608                                          &tbl_rev);
  609         if (!IS_ERR(wifi_pkg)) {
  610                 if (tbl_rev != 0) {
  611                         ret = PTR_ERR(wifi_pkg);
  612                         goto out_free;
  613                 }
  614 
  615                 num_chains = ACPI_SAR_NUM_CHAINS_REV0;
  616                 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
  617 
  618                 goto read_table;
  619         }
  620 
  621         ret = PTR_ERR(wifi_pkg);
  622         goto out_free;
  623 
  624 read_table:
  625         if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
  626                 ret = -EINVAL;
  627                 goto out_free;
  628         }
  629 
  630         IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
  631 
  632         flags = wifi_pkg->package.elements[1].integer.value;
  633         fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS;
  634 
  635         /* position of the actual table */
  636         table = &wifi_pkg->package.elements[2];
  637 
  638         /* The profile from WRDS is officially profile 1, but goes
  639          * into sar_profiles[0] (because we don't have a profile 0).
  640          */
  641         ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0],
  642                                   flags & IWL_SAR_ENABLE_MSK,
  643                                   num_chains, num_sub_bands);
  644 out_free:
  645         kfree(data);
  646         return ret;
  647 }
  648 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table);
  649 
  650 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
  651 {
  652         union acpi_object *wifi_pkg, *data;
  653         bool enabled;
  654         int i, n_profiles, tbl_rev, pos;
  655         int ret = 0;
  656         u8 num_chains, num_sub_bands;
  657 
  658         data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
  659         if (IS_ERR(data))
  660                 return PTR_ERR(data);
  661 
  662         /* start by trying to read revision 2 */
  663         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  664                                          ACPI_EWRD_WIFI_DATA_SIZE_REV2,
  665                                          &tbl_rev);
  666         if (!IS_ERR(wifi_pkg)) {
  667                 if (tbl_rev != 2) {
  668                         ret = PTR_ERR(wifi_pkg);
  669                         goto out_free;
  670                 }
  671 
  672                 num_chains = ACPI_SAR_NUM_CHAINS_REV2;
  673                 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
  674 
  675                 goto read_table;
  676         }
  677 
  678         /* then try revision 1 */
  679         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  680                                          ACPI_EWRD_WIFI_DATA_SIZE_REV1,
  681                                          &tbl_rev);
  682         if (!IS_ERR(wifi_pkg)) {
  683                 if (tbl_rev != 1) {
  684                         ret = PTR_ERR(wifi_pkg);
  685                         goto out_free;
  686                 }
  687 
  688                 num_chains = ACPI_SAR_NUM_CHAINS_REV1;
  689                 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
  690 
  691                 goto read_table;
  692         }
  693 
  694         /* then finally revision 0 */
  695         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
  696                                          ACPI_EWRD_WIFI_DATA_SIZE_REV0,
  697                                          &tbl_rev);
  698         if (!IS_ERR(wifi_pkg)) {
  699                 if (tbl_rev != 0) {
  700                         ret = PTR_ERR(wifi_pkg);
  701                         goto out_free;
  702                 }
  703 
  704                 num_chains = ACPI_SAR_NUM_CHAINS_REV0;
  705                 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
  706 
  707                 goto read_table;
  708         }
  709 
  710         ret = PTR_ERR(wifi_pkg);
  711         goto out_free;
  712 
  713 read_table:
  714         if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
  715             wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
  716                 ret = -EINVAL;
  717                 goto out_free;
  718         }
  719 
  720         enabled = !!(wifi_pkg->package.elements[1].integer.value);
  721         n_profiles = wifi_pkg->package.elements[2].integer.value;
  722 
  723         /*
  724          * Check the validity of n_profiles.  The EWRD profiles start
  725          * from index 1, so the maximum value allowed here is
  726          * ACPI_SAR_PROFILES_NUM - 1.
  727          */
  728         if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) {
  729                 ret = -EINVAL;
  730                 goto out_free;
  731         }
  732 
  733         /* the tables start at element 3 */
  734         pos = 3;
  735 
  736         for (i = 0; i < n_profiles; i++) {
  737                 /* The EWRD profiles officially go from 2 to 4, but we
  738                  * save them in sar_profiles[1-3] (because we don't
  739                  * have profile 0).  So in the array we start from 1.
  740                  */
  741                 ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos],
  742                                           &fwrt->sar_profiles[i + 1], enabled,
  743                                           num_chains, num_sub_bands);
  744                 if (ret < 0)
  745                         break;
  746 
  747                 /* go to the next table */
  748                 pos += num_chains * num_sub_bands;
  749         }
  750 
  751 out_free:
  752         kfree(data);
  753         return ret;
  754 }
  755 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table);
  756 
  757 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt)
  758 {
  759         union acpi_object *wifi_pkg, *data;
  760         int i, j, k, ret, tbl_rev;
  761         u8 num_bands, num_profiles;
  762         static const struct {
  763                 u8 revisions;
  764                 u8 bands;
  765                 u8 profiles;
  766                 u8 min_profiles;
  767         } rev_data[] = {
  768                 {
  769                         .revisions = BIT(3),
  770                         .bands = ACPI_GEO_NUM_BANDS_REV2,
  771                         .profiles = ACPI_NUM_GEO_PROFILES_REV3,
  772                         .min_profiles = 3,
  773                 },
  774                 {
  775                         .revisions = BIT(2),
  776                         .bands = ACPI_GEO_NUM_BANDS_REV2,
  777                         .profiles = ACPI_NUM_GEO_PROFILES,
  778                 },
  779                 {
  780                         .revisions = BIT(0) | BIT(1),
  781                         .bands = ACPI_GEO_NUM_BANDS_REV0,
  782                         .profiles = ACPI_NUM_GEO_PROFILES,
  783                 },
  784         };
  785         int idx;
  786         /* start from one to skip the domain */
  787         int entry_idx = 1;
  788 
  789         BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
  790         BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
  791 
  792         data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
  793         if (IS_ERR(data))
  794                 return PTR_ERR(data);
  795 
  796         /* read the highest revision we understand first */
  797         for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
  798                 /* min_profiles != 0 requires num_profiles header */
  799                 u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
  800                 u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
  801                                    rev_data[idx].bands;
  802                 u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
  803                 u32 min_size;
  804 
  805                 if (!rev_data[idx].min_profiles)
  806                         min_size = max_size;
  807                 else
  808                         min_size = hdr_size +
  809                                    profile_size * rev_data[idx].min_profiles;
  810 
  811                 wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
  812                                                        min_size, max_size,
  813                                                        &tbl_rev);
  814                 if (!IS_ERR(wifi_pkg)) {
  815                         if (!(BIT(tbl_rev) & rev_data[idx].revisions))
  816                                 continue;
  817 
  818                         num_bands = rev_data[idx].bands;
  819                         num_profiles = rev_data[idx].profiles;
  820 
  821                         if (rev_data[idx].min_profiles) {
  822                                 /* read header that says # of profiles */
  823                                 union acpi_object *entry;
  824 
  825                                 entry = &wifi_pkg->package.elements[entry_idx];
  826                                 entry_idx++;
  827                                 if (entry->type != ACPI_TYPE_INTEGER ||
  828                                     entry->integer.value > num_profiles) {
  829                                         ret = -EINVAL;
  830                                         goto out_free;
  831                                 }
  832                                 num_profiles = entry->integer.value;
  833 
  834                                 /*
  835                                  * this also validates >= min_profiles since we
  836                                  * otherwise wouldn't have gotten the data when
  837                                  * looking up in ACPI
  838                                  */
  839                                 if (wifi_pkg->package.count !=
  840                                     hdr_size + profile_size * num_profiles) {
  841                                         ret = -EINVAL;
  842                                         goto out_free;
  843                                 }
  844                         }
  845                         goto read_table;
  846                 }
  847         }
  848 
  849         if (idx < ARRAY_SIZE(rev_data))
  850                 ret = PTR_ERR(wifi_pkg);
  851         else
  852                 ret = -ENOENT;
  853         goto out_free;
  854 
  855 read_table:
  856         fwrt->geo_rev = tbl_rev;
  857         for (i = 0; i < num_profiles; i++) {
  858                 for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) {
  859                         union acpi_object *entry;
  860 
  861                         /*
  862                          * num_bands is either 2 or 3, if it's only 2 then
  863                          * fill the third band (6 GHz) with the values from
  864                          * 5 GHz (second band)
  865                          */
  866                         if (j >= num_bands) {
  867                                 fwrt->geo_profiles[i].bands[j].max =
  868                                         fwrt->geo_profiles[i].bands[1].max;
  869                         } else {
  870                                 entry = &wifi_pkg->package.elements[entry_idx];
  871                                 entry_idx++;
  872                                 if (entry->type != ACPI_TYPE_INTEGER ||
  873                                     entry->integer.value > U8_MAX) {
  874                                         ret = -EINVAL;
  875                                         goto out_free;
  876                                 }
  877 
  878                                 fwrt->geo_profiles[i].bands[j].max =
  879                                         entry->integer.value;
  880                         }
  881 
  882                         for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) {
  883                                 /* same here as above */
  884                                 if (j >= num_bands) {
  885                                         fwrt->geo_profiles[i].bands[j].chains[k] =
  886                                                 fwrt->geo_profiles[i].bands[1].chains[k];
  887                                 } else {
  888                                         entry = &wifi_pkg->package.elements[entry_idx];
  889                                         entry_idx++;
  890                                         if (entry->type != ACPI_TYPE_INTEGER ||
  891                                             entry->integer.value > U8_MAX) {
  892                                                 ret = -EINVAL;
  893                                                 goto out_free;
  894                                         }
  895 
  896                                         fwrt->geo_profiles[i].bands[j].chains[k] =
  897                                                 entry->integer.value;
  898                                 }
  899                         }
  900                 }
  901         }
  902 
  903         fwrt->geo_num_profiles = num_profiles;
  904         fwrt->geo_enabled = true;
  905         ret = 0;
  906 out_free:
  907         kfree(data);
  908         return ret;
  909 }
  910 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table);
  911 
  912 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
  913 {
  914         /*
  915          * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on
  916          * earlier firmware versions.  Unfortunately, we don't have a
  917          * TLV API flag to rely on, so rely on the major version which
  918          * is in the first byte of ucode_ver.  This was implemented
  919          * initially on version 38 and then backported to 17.  It was
  920          * also backported to 29, but only for 7265D devices.  The
  921          * intention was to have it in 36 as well, but not all 8000
  922          * family got this feature enabled.  The 8000 family is the
  923          * only one using version 36, so skip this version entirely.
  924          */
  925         return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||
  926                 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&
  927                  fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) ||
  928                 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
  929                  ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) ==
  930                   CSR_HW_REV_TYPE_7265D));
  931 }
  932 IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
  933 
  934 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
  935                      struct iwl_per_chain_offset *table,
  936                      u32 n_bands, u32 n_profiles)
  937 {
  938         int i, j;
  939 
  940         if (!iwl_sar_geo_support(fwrt))
  941                 return -EOPNOTSUPP;
  942 
  943         for (i = 0; i < n_profiles; i++) {
  944                 for (j = 0; j < n_bands; j++) {
  945                         struct iwl_per_chain_offset *chain =
  946                                 &table[i * n_bands + j];
  947 
  948                         chain->max_tx_power =
  949                                 cpu_to_le16(fwrt->geo_profiles[i].bands[j].max);
  950                         chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0];
  951                         chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1];
  952                         IWL_DEBUG_RADIO(fwrt,
  953                                         "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n",
  954                                         i, j,
  955                                         fwrt->geo_profiles[i].bands[j].chains[0],
  956                                         fwrt->geo_profiles[i].bands[j].chains[1],
  957                                         fwrt->geo_profiles[i].bands[j].max);
  958                 }
  959         }
  960 
  961         return 0;
  962 }
  963 IWL_EXPORT_SYMBOL(iwl_sar_geo_init);
  964 
  965 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
  966 {
  967         int ret;
  968         u8 value;
  969         __le32 config_bitmap = 0;
  970 
  971         /*
  972          ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2'
  973          */
  974         ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
  975                                   DSM_FUNC_ENABLE_INDONESIA_5G2,
  976                                   &iwl_guid, &value);
  977 
  978         if (!ret && value == DSM_VALUE_INDONESIA_ENABLE)
  979                 config_bitmap |=
  980                         cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
  981 
  982         /*
  983          ** Evaluate func 'DSM_FUNC_DISABLE_SRD'
  984          */
  985         ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
  986                                   DSM_FUNC_DISABLE_SRD,
  987                                   &iwl_guid, &value);
  988         if (!ret) {
  989                 if (value == DSM_VALUE_SRD_PASSIVE)
  990                         config_bitmap |=
  991                                 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
  992                 else if (value == DSM_VALUE_SRD_DISABLE)
  993                         config_bitmap |=
  994                                 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
  995         }
  996 
  997         return config_bitmap;
  998 }
  999 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap);
 1000 
 1001 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
 1002 {
 1003         union acpi_object *wifi_pkg, *data, *flags;
 1004         int i, j, ret, tbl_rev, num_sub_bands = 0;
 1005         int idx = 2;
 1006 
 1007         fwrt->ppag_flags = 0;
 1008 
 1009         data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
 1010         if (IS_ERR(data))
 1011                 return PTR_ERR(data);
 1012 
 1013         /* try to read ppag table rev 2 or 1 (both have the same data size) */
 1014         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
 1015                                 ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
 1016 
 1017         if (!IS_ERR(wifi_pkg)) {
 1018                 if (tbl_rev == 1 || tbl_rev == 2) {
 1019                         num_sub_bands = IWL_NUM_SUB_BANDS_V2;
 1020                         IWL_DEBUG_RADIO(fwrt,
 1021                                         "Reading PPAG table v2 (tbl_rev=%d)\n",
 1022                                         tbl_rev);
 1023                         goto read_table;
 1024                 } else {
 1025                         ret = -EINVAL;
 1026                         goto out_free;
 1027                 }
 1028         }
 1029 
 1030         /* try to read ppag table revision 0 */
 1031         wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
 1032                         ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
 1033 
 1034         if (!IS_ERR(wifi_pkg)) {
 1035                 if (tbl_rev != 0) {
 1036                         ret = -EINVAL;
 1037                         goto out_free;
 1038                 }
 1039                 num_sub_bands = IWL_NUM_SUB_BANDS_V1;
 1040                 IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
 1041                 goto read_table;
 1042         }
 1043 
 1044 read_table:
 1045         fwrt->ppag_ver = tbl_rev;
 1046         flags = &wifi_pkg->package.elements[1];
 1047 
 1048         if (flags->type != ACPI_TYPE_INTEGER) {
 1049                 ret = -EINVAL;
 1050                 goto out_free;
 1051         }
 1052 
 1053         fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK;
 1054 
 1055         if (!fwrt->ppag_flags) {
 1056                 ret = 0;
 1057                 goto out_free;
 1058         }
 1059 
 1060         /*
 1061          * read, verify gain values and save them into the PPAG table.
 1062          * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
 1063          * following sub-bands to High-Band (5GHz).
 1064          */
 1065         for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
 1066                 for (j = 0; j < num_sub_bands; j++) {
 1067                         union acpi_object *ent;
 1068 
 1069                         ent = &wifi_pkg->package.elements[idx++];
 1070                         if (ent->type != ACPI_TYPE_INTEGER) {
 1071                                 ret = -EINVAL;
 1072                                 goto out_free;
 1073                         }
 1074 
 1075                         fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
 1076 
 1077                         if ((j == 0 &&
 1078                                 (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB ||
 1079                                  fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) ||
 1080                                 (j != 0 &&
 1081                                 (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB ||
 1082                                 fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) {
 1083                                         fwrt->ppag_flags = 0;
 1084                                         ret = -EINVAL;
 1085                                         goto out_free;
 1086                                 }
 1087                 }
 1088         }
 1089 
 1090 
 1091         ret = 0;
 1092 
 1093 out_free:
 1094         kfree(data);
 1095         return ret;
 1096 }
 1097 IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table);
 1098 
 1099 int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd,
 1100                         int *cmd_size)
 1101 {
 1102         u8 cmd_ver;
 1103         int i, j, num_sub_bands;
 1104         s8 *gain;
 1105 
 1106         if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
 1107                 IWL_DEBUG_RADIO(fwrt,
 1108                                 "PPAG capability not supported by FW, command not sent.\n");
 1109                 return -EINVAL;
 1110         }
 1111         if (!fwrt->ppag_flags) {
 1112                 IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
 1113                 return -EINVAL;
 1114         }
 1115 
 1116         /* The 'flags' field is the same in v1 and in v2 so we can just
 1117          * use v1 to access it.
 1118          */
 1119         cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
 1120         cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
 1121                                         WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD),
 1122                                         IWL_FW_CMD_VER_UNKNOWN);
 1123         if (cmd_ver == 1) {
 1124                 num_sub_bands = IWL_NUM_SUB_BANDS_V1;
 1125                 gain = cmd->v1.gain[0];
 1126                 *cmd_size = sizeof(cmd->v1);
 1127                 if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) {
 1128                         IWL_DEBUG_RADIO(fwrt,
 1129                                         "PPAG table rev is %d but FW supports v1, sending truncated table\n",
 1130                                         fwrt->ppag_ver);
 1131                         cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
 1132                 }
 1133         } else if (cmd_ver == 2 || cmd_ver == 3) {
 1134                 num_sub_bands = IWL_NUM_SUB_BANDS_V2;
 1135                 gain = cmd->v2.gain[0];
 1136                 *cmd_size = sizeof(cmd->v2);
 1137                 if (fwrt->ppag_ver == 0) {
 1138                         IWL_DEBUG_RADIO(fwrt,
 1139                                         "PPAG table is v1 but FW supports v2, sending padded table\n");
 1140                 } else if (cmd_ver == 2 && fwrt->ppag_ver == 2) {
 1141                         IWL_DEBUG_RADIO(fwrt,
 1142                                         "PPAG table is v3 but FW supports v2, sending partial bitmap.\n");
 1143                         cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
 1144                 }
 1145         } else {
 1146                 IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
 1147                 return -EINVAL;
 1148         }
 1149 
 1150         for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
 1151                 for (j = 0; j < num_sub_bands; j++) {
 1152                         gain[i * num_sub_bands + j] =
 1153                                 fwrt->ppag_chains[i].subbands[j];
 1154                         IWL_DEBUG_RADIO(fwrt,
 1155                                         "PPAG table: chain[%d] band[%d]: gain = %d\n",
 1156                                         i, j, gain[i * num_sub_bands + j]);
 1157                 }
 1158         }
 1159 
 1160         return 0;
 1161 }
 1162 IWL_EXPORT_SYMBOL(iwl_read_ppag_table);
 1163 
 1164 bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt)
 1165 {
 1166 
 1167         if (!dmi_check_system(dmi_ppag_approved_list)) {
 1168                 IWL_DEBUG_RADIO(fwrt,
 1169                         "System vendor '%s' is not in the approved list, disabling PPAG.\n",
 1170                         dmi_get_system_info(DMI_SYS_VENDOR));
 1171                         fwrt->ppag_flags = 0;
 1172                         return false;
 1173         }
 1174 
 1175         return true;
 1176 }
 1177 IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved);

Cache object: cac664042ac96aa54746d317c6959fda


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.