2020-12-10 00:06:03 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2017 Intel Deutschland GmbH
|
2024-04-15 11:54:42 +03:00
|
|
|
* Copyright (C) 2019-2024 Intel Corporation
|
2020-12-10 00:06:03 +02:00
|
|
|
*/
|
2020-05-29 09:39:24 +03:00
|
|
|
#include <linux/uuid.h>
|
2017-09-19 12:35:18 +03:00
|
|
|
#include "iwl-drv.h"
|
|
|
|
#include "iwl-debug.h"
|
|
|
|
#include "acpi.h"
|
2019-11-15 09:28:11 +02:00
|
|
|
#include "fw/runtime.h"
|
2017-09-19 12:35:18 +03:00
|
|
|
|
2021-02-10 17:15:04 +02:00
|
|
|
const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
|
|
|
|
0xA5, 0xB3, 0x1F, 0x73,
|
|
|
|
0x8E, 0x28, 0x5A, 0xDE);
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
|
|
|
|
static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = {
|
|
|
|
[DSM_FUNC_QUERY] = sizeof(u32),
|
|
|
|
[DSM_FUNC_DISABLE_SRD] = sizeof(u8),
|
|
|
|
[DSM_FUNC_ENABLE_INDONESIA_5G2] = sizeof(u8),
|
|
|
|
[DSM_FUNC_ENABLE_6E] = sizeof(u32),
|
|
|
|
[DSM_FUNC_REGULATORY_CONFIG] = sizeof(u32),
|
|
|
|
/* Not supported in driver */
|
|
|
|
[5] = (size_t)0,
|
|
|
|
[DSM_FUNC_11AX_ENABLEMENT] = sizeof(u32),
|
|
|
|
[DSM_FUNC_ENABLE_UNII4_CHAN] = sizeof(u32),
|
|
|
|
[DSM_FUNC_ACTIVATE_CHANNEL] = sizeof(u32),
|
|
|
|
[DSM_FUNC_FORCE_DISABLE_CHANNELS] = sizeof(u32),
|
|
|
|
[DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32),
|
|
|
|
[DSM_FUNC_RFI_CONFIG] = sizeof(u32),
|
|
|
|
};
|
2021-02-10 17:15:04 +02:00
|
|
|
|
2020-05-29 09:39:24 +03:00
|
|
|
static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
|
|
|
|
acpi_handle *ret_handle)
|
2017-09-19 12:35:18 +03:00
|
|
|
{
|
|
|
|
acpi_handle root_handle;
|
|
|
|
acpi_status status;
|
|
|
|
|
|
|
|
root_handle = ACPI_HANDLE(dev);
|
|
|
|
if (!root_handle) {
|
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
2020-05-29 09:39:24 +03:00
|
|
|
"ACPI: Could not retrieve root port handle\n");
|
|
|
|
return -ENOENT;
|
2017-09-19 12:35:18 +03:00
|
|
|
}
|
|
|
|
|
2020-05-29 09:39:24 +03:00
|
|
|
status = acpi_get_handle(root_handle, method, ret_handle);
|
2017-09-19 12:35:18 +03:00
|
|
|
if (ACPI_FAILURE(status)) {
|
2020-05-29 09:39:24 +03:00
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"ACPI: %s method not found\n", method);
|
|
|
|
return -ENOENT;
|
2017-09-19 12:35:18 +03:00
|
|
|
}
|
2020-05-29 09:39:24 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-14 12:41:20 +03:00
|
|
|
static void *iwl_acpi_get_object(struct device *dev, acpi_string method)
|
2020-05-29 09:39:24 +03:00
|
|
|
{
|
|
|
|
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
|
|
|
|
acpi_handle handle;
|
|
|
|
acpi_status status;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = iwl_acpi_get_handle(dev, method, &handle);
|
|
|
|
if (ret)
|
|
|
|
return ERR_PTR(-ENOENT);
|
2017-09-19 12:35:18 +03:00
|
|
|
|
|
|
|
/* Call the method with no arguments */
|
|
|
|
status = acpi_evaluate_object(handle, NULL, NULL, &buf);
|
|
|
|
if (ACPI_FAILURE(status)) {
|
2020-05-29 09:39:24 +03:00
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"ACPI: %s method invocation failed (status: 0x%x)\n",
|
2017-09-19 12:35:18 +03:00
|
|
|
method, status);
|
|
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
}
|
|
|
|
return buf.pointer;
|
|
|
|
}
|
2017-09-21 14:30:53 +03:00
|
|
|
|
2020-11-26 13:31:51 +00:00
|
|
|
/*
|
|
|
|
* Generic function for evaluating a method defined in the device specific
|
|
|
|
* method (DSM) interface. The returned acpi object must be freed by calling
|
|
|
|
* function.
|
|
|
|
*/
|
2020-09-26 00:30:47 +03:00
|
|
|
static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
|
2021-02-10 17:15:04 +02:00
|
|
|
union acpi_object *args,
|
|
|
|
const guid_t *guid)
|
2020-05-29 09:39:24 +03:00
|
|
|
{
|
|
|
|
union acpi_object *obj;
|
|
|
|
|
2021-02-10 17:15:04 +02:00
|
|
|
obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func,
|
2020-05-29 09:39:24 +03:00
|
|
|
args);
|
|
|
|
if (!obj) {
|
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"ACPI: DSM method invocation failed (rev: %d, func:%d)\n",
|
|
|
|
rev, func);
|
|
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2020-11-26 13:31:51 +00:00
|
|
|
/*
|
2021-01-22 14:52:36 +02:00
|
|
|
* Generic function to evaluate a DSM with no arguments
|
|
|
|
* and an integer return value,
|
|
|
|
* (as an integer object or inside a buffer object),
|
|
|
|
* verify and assign the value in the "value" parameter.
|
|
|
|
* return 0 in success and the appropriate errno otherwise.
|
2020-05-29 09:39:24 +03:00
|
|
|
*/
|
2021-01-22 14:52:36 +02:00
|
|
|
static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
|
2021-02-10 17:15:04 +02:00
|
|
|
const guid_t *guid, u64 *value,
|
|
|
|
size_t expected_size)
|
2020-05-29 09:39:24 +03:00
|
|
|
{
|
|
|
|
union acpi_object *obj;
|
2021-01-22 14:52:36 +02:00
|
|
|
int ret = 0;
|
2020-05-29 09:39:24 +03:00
|
|
|
|
2021-02-10 17:15:04 +02:00
|
|
|
obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid);
|
2021-01-22 14:52:36 +02:00
|
|
|
if (IS_ERR(obj)) {
|
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"Failed to get DSM object. func= %d\n",
|
|
|
|
func);
|
2020-05-29 09:39:24 +03:00
|
|
|
return -ENOENT;
|
2021-01-22 14:52:36 +02:00
|
|
|
}
|
2020-05-29 09:39:24 +03:00
|
|
|
|
2021-01-22 14:52:36 +02:00
|
|
|
if (obj->type == ACPI_TYPE_INTEGER) {
|
|
|
|
*value = obj->integer.value;
|
|
|
|
} else if (obj->type == ACPI_TYPE_BUFFER) {
|
|
|
|
__le64 le_value = 0;
|
|
|
|
|
|
|
|
if (WARN_ON_ONCE(expected_size > sizeof(le_value)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* if the buffer size doesn't match the expected size */
|
|
|
|
if (obj->buffer.length != expected_size)
|
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
|
|
|
|
obj->buffer.length);
|
|
|
|
|
|
|
|
/* assuming LE from Intel BIOS spec */
|
|
|
|
memcpy(&le_value, obj->buffer.pointer,
|
|
|
|
min_t(size_t, expected_size, (size_t)obj->buffer.length));
|
|
|
|
*value = le64_to_cpu(le_value);
|
|
|
|
} else {
|
2020-05-29 09:39:24 +03:00
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"ACPI: DSM method did not return a valid object, type=%d\n",
|
|
|
|
obj->type);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
IWL_DEBUG_DEV_RADIO(dev,
|
|
|
|
"ACPI: DSM method evaluated: func=%d, ret=%d\n",
|
|
|
|
func, ret);
|
|
|
|
out:
|
|
|
|
ACPI_FREE(obj);
|
|
|
|
return ret;
|
|
|
|
}
|
2021-01-22 14:52:36 +02:00
|
|
|
|
|
|
|
/*
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
* This function receives a DSM function number, calculates its expected size
|
|
|
|
* according to Intel BIOS spec, and fills in the value in a 32-bit field.
|
|
|
|
* In case the expected size is smaller than 32-bit, padding will be added.
|
2021-01-22 14:52:36 +02:00
|
|
|
*/
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
|
2024-02-01 16:17:36 +02:00
|
|
|
enum iwl_dsm_funcs func, u32 *value)
|
2021-01-22 14:52:36 +02:00
|
|
|
{
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
size_t expected_size;
|
|
|
|
u64 tmp;
|
2021-01-22 14:52:36 +02:00
|
|
|
int ret;
|
|
|
|
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS);
|
2021-01-22 14:52:36 +02:00
|
|
|
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size)))
|
|
|
|
return -EINVAL;
|
2021-01-22 14:52:36 +02:00
|
|
|
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
expected_size = acpi_dsm_size[func];
|
2020-05-29 09:39:24 +03:00
|
|
|
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
/* Currently all ACPI DSMs are either 8-bit or 32-bit */
|
|
|
|
if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
|
|
|
|
return -EOPNOTSUPP;
|
2021-06-12 14:32:34 +03:00
|
|
|
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
|
|
|
|
&iwl_guid, &tmp, expected_size);
|
|
|
|
if (ret)
|
2021-06-12 14:32:34 +03:00
|
|
|
return ret;
|
|
|
|
|
wifi: iwlwifi: simplify getting DSM from ACPI
As DSMs are going to be read from UEFI too, we need a unified API
to get DSMs for both ACPI and UEFI.
The difference in getting DSM in each one of these methods (ACPI, UEFI)
is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM
values (8 or 32 for ACPI, 32 for UEFI).
Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which
determines the GUID, revision (these two are the same for all WiFi DSMs),
and size (based on a func-to-size mapping) internally.
While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value
(as defined in Intel BIOS spec) and not a 8-bit one.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-02-01 16:17:35 +02:00
|
|
|
if ((expected_size == sizeof(u8) && tmp != (u8)tmp) ||
|
|
|
|
(expected_size == sizeof(u32) && tmp != (u32)tmp))
|
|
|
|
IWL_DEBUG_RADIO(fwrt,
|
|
|
|
"DSM value overflows the expected size, truncating\n");
|
|
|
|
*value = (u32)tmp;
|
|
|
|
|
2021-06-12 14:32:34 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-14 12:41:20 +03:00
|
|
|
static union acpi_object *
|
|
|
|
iwl_acpi_get_wifi_pkg_range(struct device *dev,
|
|
|
|
union acpi_object *data,
|
|
|
|
int min_data_size,
|
|
|
|
int max_data_size,
|
|
|
|
int *tbl_rev)
|
2017-09-21 14:30:53 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
union acpi_object *wifi_pkg;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need at least one entry in the wifi package that
|
|
|
|
* describes the domain, and one more entry, otherwise there's
|
|
|
|
* no point in reading it.
|
|
|
|
*/
|
2021-10-24 16:55:04 +03:00
|
|
|
if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
|
2017-09-21 14:30:53 +03:00
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need at least two packages, one for the revision and one
|
|
|
|
* for the data itself. Also check that the revision is valid
|
2021-03-31 12:14:47 +03:00
|
|
|
* (i.e. it is an integer (each caller has to check by itself
|
|
|
|
* if the returned revision is supported)).
|
2017-09-21 14:30:53 +03:00
|
|
|
*/
|
|
|
|
if (data->type != ACPI_TYPE_PACKAGE ||
|
|
|
|
data->package.count < 2 ||
|
2021-03-31 12:14:47 +03:00
|
|
|
data->package.elements[0].type != ACPI_TYPE_INTEGER) {
|
|
|
|
IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
|
2017-09-21 14:30:53 +03:00
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
2019-02-27 16:43:45 +02:00
|
|
|
*tbl_rev = data->package.elements[0].integer.value;
|
|
|
|
|
2017-09-21 14:30:53 +03:00
|
|
|
/* loop through all the packages to find the one for WiFi */
|
|
|
|
for (i = 1; i < data->package.count; i++) {
|
|
|
|
union acpi_object *domain;
|
|
|
|
|
|
|
|
wifi_pkg = &data->package.elements[i];
|
|
|
|
|
|
|
|
/* skip entries that are not a package with the right size */
|
|
|
|
if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
|
2021-10-24 16:55:04 +03:00
|
|
|
wifi_pkg->package.count < min_data_size ||
|
|
|
|
wifi_pkg->package.count > max_data_size)
|
2017-09-21 14:30:53 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
domain = &wifi_pkg->package.elements[0];
|
|
|
|
if (domain->type == ACPI_TYPE_INTEGER &&
|
|
|
|
domain->integer.value == ACPI_WIFI_DOMAIN)
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
|
|
|
|
found:
|
|
|
|
return wifi_pkg;
|
|
|
|
}
|
2023-06-14 12:41:20 +03:00
|
|
|
|
|
|
|
static union acpi_object *
|
|
|
|
iwl_acpi_get_wifi_pkg(struct device *dev,
|
|
|
|
union acpi_object *data,
|
|
|
|
int data_size, int *tbl_rev)
|
|
|
|
{
|
|
|
|
return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size,
|
|
|
|
tbl_rev);
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:24:47 +02:00
|
|
|
int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt,
|
|
|
|
struct iwl_tas_data *tas_data)
|
2020-04-18 11:08:50 +03:00
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
2021-12-10 09:06:15 +02:00
|
|
|
int ret, tbl_rev, i, block_list_size, enabled;
|
2020-04-18 11:08:50 +03:00
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2021-12-10 09:06:15 +02:00
|
|
|
/* try to read wtas table revision 1 or revision 0*/
|
2020-04-18 11:08:50 +03:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_WTAS_WIFI_DATA_SIZE,
|
|
|
|
&tbl_rev);
|
|
|
|
if (IS_ERR(wifi_pkg)) {
|
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2021-12-10 09:06:15 +02:00
|
|
|
if (tbl_rev == 1 && wifi_pkg->package.elements[1].type ==
|
|
|
|
ACPI_TYPE_INTEGER) {
|
|
|
|
u32 tas_selection =
|
|
|
|
(u32)wifi_pkg->package.elements[1].integer.value;
|
2024-01-31 10:24:45 +02:00
|
|
|
|
2024-01-31 10:24:46 +02:00
|
|
|
enabled = iwl_parse_tas_selection(fwrt, tas_data,
|
2024-01-31 10:24:45 +02:00
|
|
|
tas_selection);
|
2021-12-10 09:06:15 +02:00
|
|
|
|
|
|
|
} else if (tbl_rev == 0 &&
|
|
|
|
wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) {
|
|
|
|
enabled = !!wifi_pkg->package.elements[1].integer.value;
|
|
|
|
} else {
|
2020-04-18 11:08:50 +03:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n");
|
|
|
|
ret = 0;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2021-12-10 09:06:15 +02:00
|
|
|
IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev);
|
2021-08-05 14:21:53 +03:00
|
|
|
if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER ||
|
|
|
|
wifi_pkg->package.elements[2].integer.value >
|
2024-01-31 10:24:45 +02:00
|
|
|
IWL_WTAS_BLACK_LIST_MAX) {
|
2020-04-18 11:08:50 +03:00
|
|
|
IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n",
|
2021-12-10 09:06:15 +02:00
|
|
|
wifi_pkg->package.elements[2].integer.value);
|
2020-04-18 11:08:50 +03:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
2021-12-10 09:06:15 +02:00
|
|
|
block_list_size = wifi_pkg->package.elements[2].integer.value;
|
2024-01-31 10:24:46 +02:00
|
|
|
tas_data->block_list_size = cpu_to_le32(block_list_size);
|
2020-04-18 11:08:50 +03:00
|
|
|
|
2021-12-10 09:06:15 +02:00
|
|
|
IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size);
|
2020-04-18 11:08:50 +03:00
|
|
|
|
2021-12-10 09:06:15 +02:00
|
|
|
for (i = 0; i < block_list_size; i++) {
|
2020-04-18 11:08:50 +03:00
|
|
|
u32 country;
|
|
|
|
|
2021-08-05 14:21:53 +03:00
|
|
|
if (wifi_pkg->package.elements[3 + i].type !=
|
2020-04-18 11:08:50 +03:00
|
|
|
ACPI_TYPE_INTEGER) {
|
|
|
|
IWL_DEBUG_RADIO(fwrt,
|
2021-08-05 14:21:53 +03:00
|
|
|
"TAS invalid array elem %d\n", 3 + i);
|
2020-04-18 11:08:50 +03:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:53 +03:00
|
|
|
country = wifi_pkg->package.elements[3 + i].integer.value;
|
2024-01-31 10:24:46 +02:00
|
|
|
tas_data->block_list_array[i] = cpu_to_le32(country);
|
2020-12-09 23:16:20 +02:00
|
|
|
IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
|
2020-04-18 11:08:50 +03:00
|
|
|
}
|
|
|
|
|
2021-12-10 09:06:15 +02:00
|
|
|
ret = 1;
|
2020-04-18 11:08:50 +03:00
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-02-01 16:17:31 +02:00
|
|
|
int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
|
2017-09-26 16:31:10 +03:00
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
|
|
|
u32 mcc_val;
|
2019-02-27 16:43:45 +02:00
|
|
|
int ret, tbl_rev;
|
2017-09-26 16:31:10 +03:00
|
|
|
|
2024-02-01 16:17:31 +02:00
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD);
|
2017-09-26 16:31:10 +03:00
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2024-02-01 16:17:31 +02:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_WRDD_WIFI_DATA_SIZE,
|
2019-02-27 16:43:45 +02:00
|
|
|
&tbl_rev);
|
2019-08-23 11:59:09 +03:00
|
|
|
if (IS_ERR(wifi_pkg)) {
|
2017-09-26 16:31:10 +03:00
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:59:09 +03:00
|
|
|
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
|
|
|
|
tbl_rev != 0) {
|
2017-09-26 16:31:10 +03:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
mcc_val = wifi_pkg->package.elements[1].integer.value;
|
|
|
|
|
|
|
|
mcc[0] = (mcc_val >> 8) & 0xff;
|
|
|
|
mcc[1] = mcc_val & 0xff;
|
|
|
|
mcc[2] = '\0';
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
2017-09-28 15:18:33 +03:00
|
|
|
|
2024-02-01 16:17:25 +02:00
|
|
|
int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit)
|
2017-09-28 15:18:33 +03:00
|
|
|
{
|
|
|
|
union acpi_object *data, *wifi_pkg;
|
2024-02-01 16:17:25 +02:00
|
|
|
int tbl_rev, ret = -EINVAL;
|
2017-09-28 15:18:33 +03:00
|
|
|
|
2024-02-01 16:17:25 +02:00
|
|
|
*dflt_pwr_limit = 0;
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_SPLC_METHOD);
|
|
|
|
if (IS_ERR(data))
|
2017-09-28 15:18:33 +03:00
|
|
|
goto out;
|
|
|
|
|
2024-02-01 16:17:25 +02:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
2019-02-27 16:43:45 +02:00
|
|
|
ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
|
|
|
|
if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
|
2024-02-01 16:17:25 +02:00
|
|
|
wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER)
|
2017-09-28 15:18:33 +03:00
|
|
|
goto out_free;
|
|
|
|
|
2024-02-01 16:17:25 +02:00
|
|
|
*dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
|
|
|
|
ret = 0;
|
2017-09-28 15:18:33 +03:00
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
out:
|
2024-02-01 16:17:25 +02:00
|
|
|
return ret;
|
2017-09-28 15:18:33 +03:00
|
|
|
}
|
2019-01-02 12:52:20 +02:00
|
|
|
|
2024-02-01 16:17:32 +02:00
|
|
|
int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
|
2019-01-02 12:52:20 +02:00
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
2019-02-27 16:43:45 +02:00
|
|
|
int ret, tbl_rev;
|
2019-01-02 12:52:20 +02:00
|
|
|
|
2024-02-01 16:17:32 +02:00
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_ECKV_METHOD);
|
2019-01-02 12:52:20 +02:00
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2024-02-01 16:17:32 +02:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_ECKV_WIFI_DATA_SIZE,
|
2019-02-27 16:43:45 +02:00
|
|
|
&tbl_rev);
|
2019-08-23 11:59:09 +03:00
|
|
|
if (IS_ERR(wifi_pkg)) {
|
2019-01-02 12:52:20 +02:00
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:59:09 +03:00
|
|
|
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
|
|
|
|
tbl_rev != 0) {
|
2019-01-02 12:52:20 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
*extl_clk = wifi_pkg->package.elements[1].integer.value;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
2019-11-15 09:28:11 +02:00
|
|
|
|
2024-01-31 10:24:37 +02:00
|
|
|
static int iwl_acpi_sar_set_profile(union acpi_object *table,
|
|
|
|
struct iwl_sar_profile *profile,
|
|
|
|
bool enabled, u8 num_chains,
|
|
|
|
u8 num_sub_bands)
|
2019-11-15 09:28:11 +02:00
|
|
|
{
|
2021-08-05 13:19:33 +03:00
|
|
|
int i, j, idx = 0;
|
2019-11-15 09:28:11 +02:00
|
|
|
|
2021-08-05 13:19:33 +03:00
|
|
|
/*
|
|
|
|
* The table from ACPI is flat, but we store it in a
|
|
|
|
* structured array.
|
|
|
|
*/
|
2024-01-31 10:24:37 +02:00
|
|
|
for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) {
|
|
|
|
for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) {
|
2021-08-19 18:40:27 +03:00
|
|
|
/* if we don't have the values, use the default */
|
|
|
|
if (i >= num_chains || j >= num_sub_bands) {
|
|
|
|
profile->chains[i].subbands[j] = 0;
|
|
|
|
} else {
|
|
|
|
if (table[idx].type != ACPI_TYPE_INTEGER ||
|
|
|
|
table[idx].integer.value > U8_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
profile->chains[i].subbands[j] =
|
|
|
|
table[idx].integer.value;
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
}
|
2021-08-05 13:19:33 +03:00
|
|
|
}
|
2019-11-15 09:28:11 +02:00
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:56 +03:00
|
|
|
/* Only if all values were valid can the profile be enabled */
|
|
|
|
profile->enabled = enabled;
|
|
|
|
|
2019-11-15 09:28:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:24:37 +02:00
|
|
|
int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
|
2019-11-15 09:28:11 +02:00
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *table, *data;
|
|
|
|
int ret, tbl_rev;
|
2022-03-04 13:21:18 +02:00
|
|
|
u32 flags;
|
2021-08-05 14:21:48 +03:00
|
|
|
u8 num_chains, num_sub_bands;
|
2019-11-15 09:28:11 +02:00
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2021-08-05 14:21:48 +03:00
|
|
|
/* start by trying to read revision 2 */
|
2019-11-15 09:28:11 +02:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
2021-08-05 14:21:48 +03:00
|
|
|
ACPI_WRDS_WIFI_DATA_SIZE_REV2,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 2) {
|
2024-02-08 13:17:06 +03:00
|
|
|
ret = -EINVAL;
|
2021-08-05 14:21:48 +03:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chains = ACPI_SAR_NUM_CHAINS_REV2;
|
|
|
|
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
|
|
|
|
|
|
|
|
goto read_table;
|
2019-11-15 09:28:11 +02:00
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:48 +03:00
|
|
|
/* then try revision 1 */
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_WRDS_WIFI_DATA_SIZE_REV1,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 1) {
|
2024-02-08 13:17:06 +03:00
|
|
|
ret = -EINVAL;
|
2021-08-05 14:21:48 +03:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chains = ACPI_SAR_NUM_CHAINS_REV1;
|
|
|
|
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
|
|
|
|
|
|
|
|
goto read_table;
|
2021-02-10 14:29:22 +02:00
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:48 +03:00
|
|
|
/* then finally revision 0 */
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_WRDS_WIFI_DATA_SIZE_REV0,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 0) {
|
2024-02-08 13:17:06 +03:00
|
|
|
ret = -EINVAL;
|
2021-08-05 14:21:48 +03:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chains = ACPI_SAR_NUM_CHAINS_REV0;
|
|
|
|
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
|
|
|
|
|
|
|
|
goto read_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
read_table:
|
2019-11-15 09:28:11 +02:00
|
|
|
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:48 +03:00
|
|
|
IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
|
|
|
|
|
2022-03-04 13:21:18 +02:00
|
|
|
flags = wifi_pkg->package.elements[1].integer.value;
|
|
|
|
fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS;
|
2019-11-15 09:28:11 +02:00
|
|
|
|
|
|
|
/* position of the actual table */
|
|
|
|
table = &wifi_pkg->package.elements[2];
|
|
|
|
|
|
|
|
/* The profile from WRDS is officially profile 1, but goes
|
|
|
|
* into sar_profiles[0] (because we don't have a profile 0).
|
|
|
|
*/
|
2024-01-31 10:24:37 +02:00
|
|
|
ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0],
|
|
|
|
flags & IWL_SAR_ENABLE_MSK,
|
|
|
|
num_chains, num_sub_bands);
|
2019-11-15 09:28:11 +02:00
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:24:37 +02:00
|
|
|
int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
|
2019-11-15 09:28:11 +02:00
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
|
|
|
bool enabled;
|
2019-12-23 13:00:59 +02:00
|
|
|
int i, n_profiles, tbl_rev, pos;
|
|
|
|
int ret = 0;
|
2021-08-05 14:21:49 +03:00
|
|
|
u8 num_chains, num_sub_bands;
|
2019-11-15 09:28:11 +02:00
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2021-08-05 14:21:49 +03:00
|
|
|
/* start by trying to read revision 2 */
|
2019-11-15 09:28:11 +02:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
2021-08-05 14:21:49 +03:00
|
|
|
ACPI_EWRD_WIFI_DATA_SIZE_REV2,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 2) {
|
2024-02-08 13:17:06 +03:00
|
|
|
ret = -EINVAL;
|
2021-08-05 14:21:49 +03:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chains = ACPI_SAR_NUM_CHAINS_REV2;
|
|
|
|
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
|
|
|
|
|
|
|
|
goto read_table;
|
2019-11-15 09:28:11 +02:00
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:49 +03:00
|
|
|
/* then try revision 1 */
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_EWRD_WIFI_DATA_SIZE_REV1,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 1) {
|
2024-02-08 13:17:06 +03:00
|
|
|
ret = -EINVAL;
|
2021-08-05 14:21:49 +03:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chains = ACPI_SAR_NUM_CHAINS_REV1;
|
|
|
|
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
|
|
|
|
|
|
|
|
goto read_table;
|
2021-02-10 14:29:22 +02:00
|
|
|
}
|
|
|
|
|
2021-08-05 14:21:49 +03:00
|
|
|
/* then finally revision 0 */
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_EWRD_WIFI_DATA_SIZE_REV0,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 0) {
|
2024-02-08 13:17:06 +03:00
|
|
|
ret = -EINVAL;
|
2021-08-05 14:21:49 +03:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chains = ACPI_SAR_NUM_CHAINS_REV0;
|
|
|
|
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
|
|
|
|
|
|
|
|
goto read_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
read_table:
|
2019-11-15 09:28:11 +02:00
|
|
|
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
|
|
|
|
wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
enabled = !!(wifi_pkg->package.elements[1].integer.value);
|
|
|
|
n_profiles = wifi_pkg->package.elements[2].integer.value;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the validity of n_profiles. The EWRD profiles start
|
|
|
|
* from index 1, so the maximum value allowed here is
|
|
|
|
* ACPI_SAR_PROFILES_NUM - 1.
|
|
|
|
*/
|
2024-01-31 10:24:37 +02:00
|
|
|
if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
|
2019-11-15 09:28:11 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2019-12-23 13:00:59 +02:00
|
|
|
/* the tables start at element 3 */
|
|
|
|
pos = 3;
|
2019-11-15 09:28:11 +02:00
|
|
|
|
2019-12-23 13:00:59 +02:00
|
|
|
for (i = 0; i < n_profiles; i++) {
|
2024-01-31 10:24:37 +02:00
|
|
|
union acpi_object *table = &wifi_pkg->package.elements[pos];
|
2019-11-15 09:28:11 +02:00
|
|
|
/* The EWRD profiles officially go from 2 to 4, but we
|
|
|
|
* save them in sar_profiles[1-3] (because we don't
|
|
|
|
* have profile 0). So in the array we start from 1.
|
|
|
|
*/
|
2024-01-31 10:24:37 +02:00
|
|
|
ret = iwl_acpi_sar_set_profile(table,
|
|
|
|
&fwrt->sar_profiles[i + 1],
|
|
|
|
enabled, num_chains,
|
|
|
|
num_sub_bands);
|
2019-11-15 09:28:11 +02:00
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* go to the next table */
|
2021-08-05 14:21:49 +03:00
|
|
|
pos += num_chains * num_sub_bands;
|
2019-11-15 09:28:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:24:37 +02:00
|
|
|
int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
|
2019-11-15 09:28:11 +02:00
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
2021-08-05 14:21:51 +03:00
|
|
|
int i, j, k, ret, tbl_rev;
|
2021-10-24 16:55:04 +03:00
|
|
|
u8 num_bands, num_profiles;
|
|
|
|
static const struct {
|
|
|
|
u8 revisions;
|
|
|
|
u8 bands;
|
|
|
|
u8 profiles;
|
|
|
|
u8 min_profiles;
|
|
|
|
} rev_data[] = {
|
|
|
|
{
|
|
|
|
.revisions = BIT(3),
|
|
|
|
.bands = ACPI_GEO_NUM_BANDS_REV2,
|
|
|
|
.profiles = ACPI_NUM_GEO_PROFILES_REV3,
|
2024-01-31 10:24:39 +02:00
|
|
|
.min_profiles = BIOS_GEO_MIN_PROFILE_NUM,
|
2021-10-24 16:55:04 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.revisions = BIT(2),
|
|
|
|
.bands = ACPI_GEO_NUM_BANDS_REV2,
|
|
|
|
.profiles = ACPI_NUM_GEO_PROFILES,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.revisions = BIT(0) | BIT(1),
|
|
|
|
.bands = ACPI_GEO_NUM_BANDS_REV0,
|
|
|
|
.profiles = ACPI_NUM_GEO_PROFILES,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
int idx;
|
|
|
|
/* start from one to skip the domain */
|
|
|
|
int entry_idx = 1;
|
|
|
|
|
|
|
|
BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
|
|
|
|
BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
|
2019-11-15 09:28:11 +02:00
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2021-10-24 16:55:04 +03:00
|
|
|
/* read the highest revision we understand first */
|
|
|
|
for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
|
|
|
|
/* min_profiles != 0 requires num_profiles header */
|
|
|
|
u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
|
|
|
|
u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
|
|
|
|
rev_data[idx].bands;
|
|
|
|
u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
|
|
|
|
u32 min_size;
|
|
|
|
|
|
|
|
if (!rev_data[idx].min_profiles)
|
|
|
|
min_size = max_size;
|
|
|
|
else
|
|
|
|
min_size = hdr_size +
|
|
|
|
profile_size * rev_data[idx].min_profiles;
|
|
|
|
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
|
|
|
|
min_size, max_size,
|
|
|
|
&tbl_rev);
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (!(BIT(tbl_rev) & rev_data[idx].revisions))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
num_bands = rev_data[idx].bands;
|
|
|
|
num_profiles = rev_data[idx].profiles;
|
|
|
|
|
|
|
|
if (rev_data[idx].min_profiles) {
|
|
|
|
/* read header that says # of profiles */
|
|
|
|
union acpi_object *entry;
|
|
|
|
|
|
|
|
entry = &wifi_pkg->package.elements[entry_idx];
|
|
|
|
entry_idx++;
|
|
|
|
if (entry->type != ACPI_TYPE_INTEGER ||
|
|
|
|
entry->integer.value > num_profiles) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
num_profiles = entry->integer.value;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this also validates >= min_profiles since we
|
|
|
|
* otherwise wouldn't have gotten the data when
|
|
|
|
* looking up in ACPI
|
|
|
|
*/
|
|
|
|
if (wifi_pkg->package.count !=
|
2021-12-04 13:10:50 +02:00
|
|
|
hdr_size + profile_size * num_profiles) {
|
2021-10-24 16:55:04 +03:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto read_table;
|
2021-08-05 14:21:58 +03:00
|
|
|
}
|
2021-02-10 14:29:22 +02:00
|
|
|
}
|
|
|
|
|
2021-10-24 16:55:04 +03:00
|
|
|
if (idx < ARRAY_SIZE(rev_data))
|
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
else
|
|
|
|
ret = -ENOENT;
|
2021-08-05 14:21:58 +03:00
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
read_table:
|
2019-11-15 09:28:11 +02:00
|
|
|
fwrt->geo_rev = tbl_rev;
|
2021-10-24 16:55:04 +03:00
|
|
|
for (i = 0; i < num_profiles; i++) {
|
2024-01-31 10:24:37 +02:00
|
|
|
for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) {
|
2019-11-15 09:28:11 +02:00
|
|
|
union acpi_object *entry;
|
|
|
|
|
2021-08-19 18:40:26 +03:00
|
|
|
/*
|
|
|
|
* num_bands is either 2 or 3, if it's only 2 then
|
|
|
|
* fill the third band (6 GHz) with the values from
|
|
|
|
* 5 GHz (second band)
|
|
|
|
*/
|
|
|
|
if (j >= num_bands) {
|
|
|
|
fwrt->geo_profiles[i].bands[j].max =
|
|
|
|
fwrt->geo_profiles[i].bands[1].max;
|
|
|
|
} else {
|
2021-10-24 16:55:04 +03:00
|
|
|
entry = &wifi_pkg->package.elements[entry_idx];
|
|
|
|
entry_idx++;
|
2021-08-05 14:21:51 +03:00
|
|
|
if (entry->type != ACPI_TYPE_INTEGER ||
|
|
|
|
entry->integer.value > U8_MAX) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2021-08-19 18:40:26 +03:00
|
|
|
fwrt->geo_profiles[i].bands[j].max =
|
2021-08-05 14:21:51 +03:00
|
|
|
entry->integer.value;
|
|
|
|
}
|
2021-08-19 18:40:26 +03:00
|
|
|
|
2024-01-31 10:24:37 +02:00
|
|
|
for (k = 0; k < BIOS_GEO_NUM_CHAINS; k++) {
|
2021-08-19 18:40:26 +03:00
|
|
|
/* same here as above */
|
|
|
|
if (j >= num_bands) {
|
|
|
|
fwrt->geo_profiles[i].bands[j].chains[k] =
|
|
|
|
fwrt->geo_profiles[i].bands[1].chains[k];
|
|
|
|
} else {
|
2021-10-24 16:55:04 +03:00
|
|
|
entry = &wifi_pkg->package.elements[entry_idx];
|
|
|
|
entry_idx++;
|
2021-08-19 18:40:26 +03:00
|
|
|
if (entry->type != ACPI_TYPE_INTEGER ||
|
|
|
|
entry->integer.value > U8_MAX) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrt->geo_profiles[i].bands[j].chains[k] =
|
|
|
|
entry->integer.value;
|
|
|
|
}
|
|
|
|
}
|
2019-11-15 09:28:11 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-05 14:21:51 +03:00
|
|
|
|
2021-12-04 17:49:37 +02:00
|
|
|
fwrt->geo_num_profiles = num_profiles;
|
|
|
|
fwrt->geo_enabled = true;
|
2019-11-15 09:28:11 +02:00
|
|
|
ret = 0;
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
2021-03-31 12:14:50 +03:00
|
|
|
|
2022-03-04 13:21:28 +02:00
|
|
|
int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
|
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data, *flags;
|
|
|
|
int i, j, ret, tbl_rev, num_sub_bands = 0;
|
|
|
|
int idx = 2;
|
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2024-02-05 00:06:06 +02:00
|
|
|
/* try to read ppag table rev 3, 2 or 1 (all have the same data size) */
|
2022-03-04 13:21:28 +02:00
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
|
|
|
|
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
2024-02-05 00:06:06 +02:00
|
|
|
if (tbl_rev >= 1 && tbl_rev <= 3) {
|
2022-03-04 13:21:28 +02:00
|
|
|
num_sub_bands = IWL_NUM_SUB_BANDS_V2;
|
|
|
|
IWL_DEBUG_RADIO(fwrt,
|
2024-02-05 00:06:06 +02:00
|
|
|
"Reading PPAG table (tbl_rev=%d)\n",
|
2022-03-04 13:21:28 +02:00
|
|
|
tbl_rev);
|
|
|
|
goto read_table;
|
|
|
|
} else {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to read ppag table revision 0 */
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
|
|
|
|
|
|
|
|
if (!IS_ERR(wifi_pkg)) {
|
|
|
|
if (tbl_rev != 0) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
num_sub_bands = IWL_NUM_SUB_BANDS_V1;
|
|
|
|
IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
|
|
|
|
goto read_table;
|
|
|
|
}
|
|
|
|
|
2024-02-08 13:17:31 +03:00
|
|
|
ret = PTR_ERR(wifi_pkg);
|
|
|
|
goto out_free;
|
|
|
|
|
2022-03-04 13:21:28 +02:00
|
|
|
read_table:
|
|
|
|
fwrt->ppag_ver = tbl_rev;
|
|
|
|
flags = &wifi_pkg->package.elements[1];
|
|
|
|
|
|
|
|
if (flags->type != ACPI_TYPE_INTEGER) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2024-02-05 00:06:06 +02:00
|
|
|
fwrt->ppag_flags = iwl_bios_get_ppag_flags(flags->integer.value,
|
|
|
|
fwrt->ppag_ver);
|
2022-03-04 13:21:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* read, verify gain values and save them into the PPAG table.
|
|
|
|
* first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
|
|
|
|
* following sub-bands to High-Band (5GHz).
|
|
|
|
*/
|
|
|
|
for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
|
|
|
|
for (j = 0; j < num_sub_bands; j++) {
|
|
|
|
union acpi_object *ent;
|
|
|
|
|
|
|
|
ent = &wifi_pkg->package.elements[idx++];
|
|
|
|
if (ent->type != ACPI_TYPE_INTEGER) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-06-14 12:41:33 +03:00
|
|
|
void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt,
|
|
|
|
struct iwl_phy_specific_cfg *filters)
|
|
|
|
{
|
|
|
|
struct iwl_phy_specific_cfg tmp = {};
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
|
|
|
int tbl_rev, i;
|
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_WPFC_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return;
|
|
|
|
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_WPFC_WIFI_DATA_SIZE,
|
|
|
|
&tbl_rev);
|
|
|
|
if (IS_ERR(wifi_pkg))
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
if (tbl_rev != 0)
|
|
|
|
goto out_free;
|
|
|
|
|
2024-01-28 08:53:55 +02:00
|
|
|
BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) !=
|
|
|
|
ACPI_WPFC_WIFI_DATA_SIZE - 1);
|
2023-06-14 12:41:33 +03:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) {
|
2024-01-28 08:53:55 +02:00
|
|
|
if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER)
|
|
|
|
goto out_free;
|
2023-06-14 12:41:33 +03:00
|
|
|
tmp.filter_cfg_chains[i] =
|
2024-01-28 08:53:55 +02:00
|
|
|
cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value);
|
2023-06-14 12:41:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n");
|
|
|
|
*filters = tmp;
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
}
|
|
|
|
IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters);
|
2024-01-28 08:53:59 +02:00
|
|
|
|
|
|
|
void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt)
|
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
|
|
|
int tbl_rev;
|
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_GLAI_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return;
|
|
|
|
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_GLAI_WIFI_DATA_SIZE,
|
|
|
|
&tbl_rev);
|
|
|
|
if (IS_ERR(wifi_pkg))
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
if (tbl_rev != 0) {
|
|
|
|
IWL_DEBUG_RADIO(fwrt, "Invalid GLAI revision: %d\n", tbl_rev);
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
|
|
|
|
wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
fwrt->uefi_tables_lock_status =
|
|
|
|
wifi_pkg->package.elements[1].integer.value;
|
|
|
|
|
|
|
|
IWL_DEBUG_RADIO(fwrt,
|
|
|
|
"Loaded UEFI WIFI GUID lock status: %d from ACPI\n",
|
|
|
|
fwrt->uefi_tables_lock_status);
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
}
|
|
|
|
IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status);
|
2024-04-15 11:54:42 +03:00
|
|
|
|
|
|
|
int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
|
|
|
|
{
|
|
|
|
union acpi_object *wifi_pkg, *data;
|
|
|
|
int ret = -ENOENT;
|
|
|
|
int tbl_rev;
|
|
|
|
|
|
|
|
data = iwl_acpi_get_object(fwrt->dev, ACPI_WBEM_METHOD);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
|
|
|
|
ACPI_WBEM_WIFI_DATA_SIZE,
|
|
|
|
&tbl_rev);
|
|
|
|
if (IS_ERR(wifi_pkg))
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
if (tbl_rev != IWL_ACPI_WBEM_REVISION) {
|
|
|
|
IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI WBEM revision:%d\n",
|
|
|
|
tbl_rev);
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
*value = wifi_pkg->package.elements[1].integer.value &
|
|
|
|
IWL_ACPI_WBEM_REV0_MASK;
|
|
|
|
IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n");
|
|
|
|
ret = 0;
|
|
|
|
out_free:
|
|
|
|
kfree(data);
|
|
|
|
return ret;
|
|
|
|
}
|