]> git.baikalelectronics.ru Git - kernel.git/commitdiff
iwlwifi: acpi: support device specific method (DSM)
authorGil Adam <gil.adam@intel.com>
Fri, 29 May 2020 06:39:24 +0000 (09:39 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 29 May 2020 07:32:14 +0000 (10:32 +0300)
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
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.h

index e2184ba4d8b56d00f598116dd971729065f86977..dc769b58043197ceb5000eb68dbffbbaee1e220a 100644 (file)
  *
  *****************************************************************************/
 
+#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)
index 6a646dc524e1f056d4758dac1c1f28392ab98b6a..0ada9eddb8b1709a95d88d2af25fc71fce45f71c 100644 (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,