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:
parent
fcac70029c
commit
9db93491f2
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue