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: Gil Adam <gil.adam@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20200529092401.c3242ff3ba5c.Icb48c8d61bede5dda7ef267bff10e4798e9dc77b@changeid
This commit is contained in:
Gil Adam 2020-05-29 09:39:24 +03:00 committed by Luca Coelho
parent fcac70029c
commit 9db93491f2
2 changed files with 110 additions and 11 deletions

View File

@ -58,44 +58,121 @@
*
*****************************************************************************/
#include <linux/uuid.h>
#include "iwl-drv.h"
#include "iwl-debug.h"
#include "acpi.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 handle;
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status;
root_handle = ACPI_HANDLE(dev);
if (!root_handle) {
IWL_DEBUG_DEV_RADIO(dev,
"Could not retrieve root port ACPI handle\n");
return ERR_PTR(-ENOENT);
"ACPI: Could not retrieve root port handle\n");
return -ENOENT;
}
/* Get the method's handle */
status = acpi_get_handle(root_handle, method, &handle);
status = acpi_get_handle(root_handle, method, ret_handle);
if (ACPI_FAILURE(status)) {
IWL_DEBUG_DEV_RADIO(dev, "%s method not found\n", method);
return ERR_PTR(-ENOENT);
IWL_DEBUG_DEV_RADIO(dev,
"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 */
status = acpi_evaluate_object(handle, NULL, NULL, &buf);
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);
return ERR_PTR(-ENOENT);
}
return buf.pointer;
}
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 *data,
int data_size, int *tbl_rev)

View File

@ -127,12 +127,23 @@ struct iwl_geo_profile {
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
struct iwl_fw_runtime;
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 *data,
int data_size, int *tbl_rev);
@ -192,6 +203,17 @@ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
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,
union acpi_object *data,
int data_size,