root/drivers/net/wireless/intel/iwlwifi/fw/acpi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. iwl_acpi_get_object
  2. iwl_acpi_get_wifi_pkg
  3. iwl_acpi_get_mcc
  4. iwl_acpi_get_pwr_limit
  5. iwl_acpi_get_eckv

   1 /******************************************************************************
   2  *
   3  * This file is provided under a dual BSD/GPLv2 license.  When using or
   4  * redistributing this file, you may do so under either license.
   5  *
   6  * GPL LICENSE SUMMARY
   7  *
   8  * Copyright(c) 2017        Intel Deutschland GmbH
   9  * Copyright (C) 2019 Intel Corporation
  10  *
  11  * This program is free software; you can redistribute it and/or modify
  12  * it under the terms of version 2 of the GNU General Public License as
  13  * published by the Free Software Foundation.
  14  *
  15  * This program is distributed in the hope that it will be useful, but
  16  * WITHOUT ANY WARRANTY; without even the implied warranty of
  17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18  * General Public License for more details.
  19  *
  20  * The full GNU General Public License is included in this distribution
  21  * in the file called COPYING.
  22  *
  23  * Contact Information:
  24  *  Intel Linux Wireless <linuxwifi@intel.com>
  25  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  26  *
  27  * BSD LICENSE
  28  *
  29  * Copyright(c) 2017        Intel Deutschland GmbH
  30  * Copyright (C) 2019 Intel Corporation
  31  * All rights reserved.
  32  *
  33  * Redistribution and use in source and binary forms, with or without
  34  * modification, are permitted provided that the following conditions
  35  * are met:
  36  *
  37  *  * Redistributions of source code must retain the above copyright
  38  *    notice, this list of conditions and the following disclaimer.
  39  *  * Redistributions in binary form must reproduce the above copyright
  40  *    notice, this list of conditions and the following disclaimer in
  41  *    the documentation and/or other materials provided with the
  42  *    distribution.
  43  *  * Neither the name Intel Corporation nor the names of its
  44  *    contributors may be used to endorse or promote products derived
  45  *    from this software without specific prior written permission.
  46  *
  47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  48  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  49  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  50  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  51  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  53  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  54  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  55  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  56  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  57  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  58  *
  59  *****************************************************************************/
  60 
  61 #include "iwl-drv.h"
  62 #include "iwl-debug.h"
  63 #include "acpi.h"
  64 
  65 void *iwl_acpi_get_object(struct device *dev, acpi_string method)
  66 {
  67         acpi_handle root_handle;
  68         acpi_handle handle;
  69         struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
  70         acpi_status status;
  71 
  72         root_handle = ACPI_HANDLE(dev);
  73         if (!root_handle) {
  74                 IWL_DEBUG_DEV_RADIO(dev,
  75                                     "Could not retrieve root port ACPI handle\n");
  76                 return ERR_PTR(-ENOENT);
  77         }
  78 
  79         /* Get the method's handle */
  80         status = acpi_get_handle(root_handle, method, &handle);
  81         if (ACPI_FAILURE(status)) {
  82                 IWL_DEBUG_DEV_RADIO(dev, "%s method not found\n", method);
  83                 return ERR_PTR(-ENOENT);
  84         }
  85 
  86         /* Call the method with no arguments */
  87         status = acpi_evaluate_object(handle, NULL, NULL, &buf);
  88         if (ACPI_FAILURE(status)) {
  89                 IWL_DEBUG_DEV_RADIO(dev, "%s invocation failed (0x%x)\n",
  90                                     method, status);
  91                 return ERR_PTR(-ENOENT);
  92         }
  93 
  94         return buf.pointer;
  95 }
  96 IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
  97 
  98 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
  99                                          union acpi_object *data,
 100                                          int data_size, int *tbl_rev)
 101 {
 102         int i;
 103         union acpi_object *wifi_pkg;
 104 
 105         /*
 106          * We need at least one entry in the wifi package that
 107          * describes the domain, and one more entry, otherwise there's
 108          * no point in reading it.
 109          */
 110         if (WARN_ON_ONCE(data_size < 2))
 111                 return ERR_PTR(-EINVAL);
 112 
 113         /*
 114          * We need at least two packages, one for the revision and one
 115          * for the data itself.  Also check that the revision is valid
 116          * (i.e. it is an integer smaller than 2, as we currently support only
 117          * 2 revisions).
 118          */
 119         if (data->type != ACPI_TYPE_PACKAGE ||
 120             data->package.count < 2 ||
 121             data->package.elements[0].type != ACPI_TYPE_INTEGER ||
 122             data->package.elements[0].integer.value > 1) {
 123                 IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
 124                 return ERR_PTR(-EINVAL);
 125         }
 126 
 127         *tbl_rev = data->package.elements[0].integer.value;
 128 
 129         /* loop through all the packages to find the one for WiFi */
 130         for (i = 1; i < data->package.count; i++) {
 131                 union acpi_object *domain;
 132 
 133                 wifi_pkg = &data->package.elements[i];
 134 
 135                 /* skip entries that are not a package with the right size */
 136                 if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
 137                     wifi_pkg->package.count != data_size)
 138                         continue;
 139 
 140                 domain = &wifi_pkg->package.elements[0];
 141                 if (domain->type == ACPI_TYPE_INTEGER &&
 142                     domain->integer.value == ACPI_WIFI_DOMAIN)
 143                         goto found;
 144         }
 145 
 146         return ERR_PTR(-ENOENT);
 147 
 148 found:
 149         return wifi_pkg;
 150 }
 151 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg);
 152 
 153 int iwl_acpi_get_mcc(struct device *dev, char *mcc)
 154 {
 155         union acpi_object *wifi_pkg, *data;
 156         u32 mcc_val;
 157         int ret, tbl_rev;
 158 
 159         data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
 160         if (IS_ERR(data))
 161                 return PTR_ERR(data);
 162 
 163         wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
 164                                          &tbl_rev);
 165         if (IS_ERR(wifi_pkg)) {
 166                 ret = PTR_ERR(wifi_pkg);
 167                 goto out_free;
 168         }
 169 
 170         if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
 171             tbl_rev != 0) {
 172                 ret = -EINVAL;
 173                 goto out_free;
 174         }
 175 
 176         mcc_val = wifi_pkg->package.elements[1].integer.value;
 177 
 178         mcc[0] = (mcc_val >> 8) & 0xff;
 179         mcc[1] = mcc_val & 0xff;
 180         mcc[2] = '\0';
 181 
 182         ret = 0;
 183 out_free:
 184         kfree(data);
 185         return ret;
 186 }
 187 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc);
 188 
 189 u64 iwl_acpi_get_pwr_limit(struct device *dev)
 190 {
 191         union acpi_object *data, *wifi_pkg;
 192         u64 dflt_pwr_limit;
 193         int tbl_rev;
 194 
 195         data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
 196         if (IS_ERR(data)) {
 197                 dflt_pwr_limit = 0;
 198                 goto out;
 199         }
 200 
 201         wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
 202                                          ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
 203         if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
 204             wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
 205                 dflt_pwr_limit = 0;
 206                 goto out_free;
 207         }
 208 
 209         dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
 210 out_free:
 211         kfree(data);
 212 out:
 213         return dflt_pwr_limit;
 214 }
 215 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
 216 
 217 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
 218 {
 219         union acpi_object *wifi_pkg, *data;
 220         int ret, tbl_rev;
 221 
 222         data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
 223         if (IS_ERR(data))
 224                 return PTR_ERR(data);
 225 
 226         wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
 227                                          &tbl_rev);
 228         if (IS_ERR(wifi_pkg)) {
 229                 ret = PTR_ERR(wifi_pkg);
 230                 goto out_free;
 231         }
 232 
 233         if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
 234             tbl_rev != 0) {
 235                 ret = -EINVAL;
 236                 goto out_free;
 237         }
 238 
 239         *extl_clk = wifi_pkg->package.elements[1].integer.value;
 240 
 241         ret = 0;
 242 
 243 out_free:
 244         kfree(data);
 245         return ret;
 246 }
 247 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv);

/* [<][>][^][v][top][bottom][index][help] */