Commit 9db93491 authored by Gil Adam's avatar Gil Adam Committed by Luca Coelho

iwlwifi: acpi: support device specific method (DSM)

ACPI Device Specific Method (DSM) allows standardized feature
configuration through the ACPI interface without the namespace
pollution of the usual mechanism (ACPI method for each feature).
Add generic function for evaluating DSM objects and function for
evaluating a DSM with no arguments and a single int return value.
also implement the required backport for UUID.
Signed-off-by: default avatarGil Adam <gil.adam@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20200529092401.c3242ff3ba5c.Icb48c8d61bede5dda7ef267bff10e4798e9dc77b@changeid
parent fcac7002
...@@ -58,44 +58,121 @@ ...@@ -58,44 +58,121 @@
* *
*****************************************************************************/ *****************************************************************************/
#include <linux/uuid.h>
#include "iwl-drv.h" #include "iwl-drv.h"
#include "iwl-debug.h" #include "iwl-debug.h"
#include "acpi.h" #include "acpi.h"
#include "fw/runtime.h" #include "fw/runtime.h"
void *iwl_acpi_get_object(struct device *dev, acpi_string method) static const guid_t intel_wifi_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
0xA5, 0xB3, 0x1F, 0x73,
0x8E, 0x28, 0x5A, 0xDE);
static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
acpi_handle *ret_handle)
{ {
acpi_handle root_handle; acpi_handle root_handle;
acpi_handle handle;
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status; acpi_status status;
root_handle = ACPI_HANDLE(dev); root_handle = ACPI_HANDLE(dev);
if (!root_handle) { if (!root_handle) {
IWL_DEBUG_DEV_RADIO(dev, IWL_DEBUG_DEV_RADIO(dev,
"Could not retrieve root port ACPI handle\n"); "ACPI: Could not retrieve root port handle\n");
return ERR_PTR(-ENOENT); return -ENOENT;
} }
/* Get the method's handle */ status = acpi_get_handle(root_handle, method, ret_handle);
status = acpi_get_handle(root_handle, method, &handle);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
IWL_DEBUG_DEV_RADIO(dev, "%s method not found\n", method); IWL_DEBUG_DEV_RADIO(dev,
return ERR_PTR(-ENOENT); "ACPI: %s method not found\n", method);
return -ENOENT;
} }
return 0;
}
void *iwl_acpi_get_object(struct device *dev, acpi_string method)
{
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);
/* Call the method with no arguments */ /* Call the method with no arguments */
status = acpi_evaluate_object(handle, NULL, NULL, &buf); status = acpi_evaluate_object(handle, NULL, NULL, &buf);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
IWL_DEBUG_DEV_RADIO(dev, "%s invocation failed (0x%x)\n", IWL_DEBUG_DEV_RADIO(dev,
"ACPI: %s method invocation failed (status: 0x%x)\n",
method, status); method, status);
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
return buf.pointer; return buf.pointer;
} }
IWL_EXPORT_SYMBOL(iwl_acpi_get_object); IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
/**
* Generic function for evaluating a method defined in the device specific
* method (DSM) interface. The returned acpi object must be freed by calling
* function.
*/
void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
union acpi_object *args)
{
union acpi_object *obj;
obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_wifi_guid, rev, func,
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;
}
/**
* Evaluate a DSM with no arguments and a single u8 return value (inside a
* buffer object), verify and return that value.
*/
int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
{
union acpi_object *obj;
int ret;
obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL);
if (IS_ERR(obj))
return -ENOENT;
if (obj->type != ACPI_TYPE_BUFFER) {
IWL_DEBUG_DEV_RADIO(dev,
"ACPI: DSM method did not return a valid object, type=%d\n",
obj->type);
ret = -EINVAL;
goto out;
}
if (obj->buffer.length != sizeof(u8)) {
IWL_DEBUG_DEV_RADIO(dev,
"ACPI: DSM method returned invalid buffer, length=%d\n",
obj->buffer.length);
ret = -EINVAL;
goto out;
}
ret = obj->buffer.pointer[0];
IWL_DEBUG_DEV_RADIO(dev,
"ACPI: DSM method evaluated: func=%d, ret=%d\n",
func, ret);
out:
ACPI_FREE(obj);
return ret;
}
IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data, union acpi_object *data,
int data_size, int *tbl_rev) int data_size, int *tbl_rev)
......
...@@ -127,12 +127,23 @@ struct iwl_geo_profile { ...@@ -127,12 +127,23 @@ struct iwl_geo_profile {
u8 values[ACPI_GEO_TABLE_SIZE]; u8 values[ACPI_GEO_TABLE_SIZE];
}; };
enum iwl_dsm_funcs_rev_0 {
DSM_FUNC_QUERY = 0,
DSM_FUNC_DISABLE_SRD = 1,
DSM_FUNC_ENABLE_INDONESIA_5G2 = 2,
};
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
struct iwl_fw_runtime; struct iwl_fw_runtime;
void *iwl_acpi_get_object(struct device *dev, acpi_string method); void *iwl_acpi_get_object(struct device *dev, acpi_string method);
void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
union acpi_object *args);
int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func);
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data, union acpi_object *data,
int data_size, int *tbl_rev); int data_size, int *tbl_rev);
...@@ -192,6 +203,17 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method) ...@@ -192,6 +203,17 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev,
int func, union acpi_object *args)
{
return ERR_PTR(-ENOENT);
}
static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
{
return -ENOENT;
}
static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data, union acpi_object *data,
int data_size, int data_size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment