iwlwifi: mvm: fix the return type for DSM functions 1 and 2
authorMatt Chen <matt.chen@intel.com>
Fri, 22 Jan 2021 12:52:36 +0000 (14:52 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 25 Jan 2021 13:59:12 +0000 (15:59 +0200)
The return type value of functions 1 and 2 were considered to be an
integer inside a buffer, but they can also be only an integer, without
the buffer.  Fix the code in iwl_acpi_get_dsm_u8() to handle it as a
single integer value, as well as packed inside a buffer.

Signed-off-by: Matt Chen <matt.chen@intel.com>
Fixes: 9db93491f29e ("iwlwifi: acpi: support device specific method (DSM)")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/iwlwifi.20210122144849.5757092adcd6.Ic24524627b899c9a01af38107a62a626bdf5ae3a@changeid
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c

index 15248b0..d8b7776 100644 (file)
@@ -80,19 +80,45 @@ static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
 }
 
 /*
- * Evaluate a DSM with no arguments and a single u8 return value (inside a
- * buffer object), verify and return that value.
+ * 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.
  */
-int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
+static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
+                                   u64 *value, size_t expected_size)
 {
        union acpi_object *obj;
-       int ret;
+       int ret = 0;
 
        obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL);
-       if (IS_ERR(obj))
+       if (IS_ERR(obj)) {
+               IWL_DEBUG_DEV_RADIO(dev,
+                                   "Failed to get  DSM object. func= %d\n",
+                                   func);
                return -ENOENT;
+       }
+
+       if (obj->type == ACPI_TYPE_INTEGER) {
+               *value = obj->integer.value;
+       } else if (obj->type == ACPI_TYPE_BUFFER) {
+               __le64 le_value = 0;
 
-       if (obj->type != ACPI_TYPE_BUFFER) {
+               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 {
                IWL_DEBUG_DEV_RADIO(dev,
                                    "ACPI: DSM method did not return a valid object, type=%d\n",
                                    obj->type);
@@ -100,15 +126,6 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
                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);
@@ -116,6 +133,24 @@ out:
        ACPI_FREE(obj);
        return ret;
 }
+
+/*
+ * Evaluate a DSM with no arguments and a u8 return value,
+ */
+int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, u8 *value)
+{
+       int ret;
+       u64 val;
+
+       ret = iwl_acpi_get_dsm_integer(dev, rev, func, &val, sizeof(u8));
+
+       if (ret < 0)
+               return ret;
+
+       /* cast val (u64) to be u8 */
+       *value = (u8)val;
+       return 0;
+}
 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
 
 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
index 042dd24..1cce30d 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
  * Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
  */
 #ifndef __iwl_fw_acpi__
 #define __iwl_fw_acpi__
@@ -99,7 +99,7 @@ struct iwl_fw_runtime;
 
 void *iwl_acpi_get_object(struct device *dev, acpi_string method);
 
-int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func);
+int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, u8 *value);
 
 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
                                         union acpi_object *data,
@@ -159,7 +159,8 @@ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev,
        return ERR_PTR(-ENOENT);
 }
 
-static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
+static inline
+int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, u8 *value)
 {
        return -ENOENT;
 }
index 0637eb1..313e9f1 100644 (file)
@@ -1090,20 +1090,22 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
 
 static u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm)
 {
+       u8 value;
+
        int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0,
-                                     DSM_FUNC_ENABLE_INDONESIA_5G2);
+                                     DSM_FUNC_ENABLE_INDONESIA_5G2, &value);
 
        if (ret < 0)
                IWL_DEBUG_RADIO(mvm,
                                "Failed to evaluate DSM function ENABLE_INDONESIA_5G2, ret=%d\n",
                                ret);
 
-       else if (ret >= DSM_VALUE_INDONESIA_MAX)
+       else if (value >= DSM_VALUE_INDONESIA_MAX)
                IWL_DEBUG_RADIO(mvm,
-                               "DSM function ENABLE_INDONESIA_5G2 return invalid value, ret=%d\n",
-                               ret);
+                               "DSM function ENABLE_INDONESIA_5G2 return invalid value, value=%d\n",
+                               value);
 
-       else if (ret == DSM_VALUE_INDONESIA_ENABLE) {
+       else if (value == DSM_VALUE_INDONESIA_ENABLE) {
                IWL_DEBUG_RADIO(mvm,
                                "Evaluated DSM function ENABLE_INDONESIA_5G2: Enabling 5g2\n");
                return DSM_VALUE_INDONESIA_ENABLE;
@@ -1114,25 +1116,26 @@ static u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm)
 
 static u8 iwl_mvm_eval_dsm_disable_srd(struct iwl_mvm *mvm)
 {
+       u8 value;
        int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0,
-                                     DSM_FUNC_DISABLE_SRD);
+                                     DSM_FUNC_DISABLE_SRD, &value);
 
        if (ret < 0)
                IWL_DEBUG_RADIO(mvm,
                                "Failed to evaluate DSM function DISABLE_SRD, ret=%d\n",
                                ret);
 
-       else if (ret >= DSM_VALUE_SRD_MAX)
+       else if (value >= DSM_VALUE_SRD_MAX)
                IWL_DEBUG_RADIO(mvm,
-                               "DSM function DISABLE_SRD return invalid value, ret=%d\n",
-                               ret);
+                               "DSM function DISABLE_SRD return invalid value, value=%d\n",
+                               value);
 
-       else if (ret == DSM_VALUE_SRD_PASSIVE) {
+       else if (value == DSM_VALUE_SRD_PASSIVE) {
                IWL_DEBUG_RADIO(mvm,
                                "Evaluated DSM function DISABLE_SRD: setting SRD to passive\n");
                return DSM_VALUE_SRD_PASSIVE;
 
-       } else if (ret == DSM_VALUE_SRD_DISABLE) {
+       } else if (value == DSM_VALUE_SRD_DISABLE) {
                IWL_DEBUG_RADIO(mvm,
                                "Evaluated DSM function DISABLE_SRD: disabling SRD\n");
                return DSM_VALUE_SRD_DISABLE;