acpi.c 6.3 KB

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