Commit aefbe5c4 authored by Matt Chen's avatar Matt Chen Committed by Kalle Valo
Browse files

iwlwifi: mvm: fix the return type for DSM functions 1 and 2



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: default avatarMatt Chen <matt.chen@intel.com>
Fixes: 9db93491 ("iwlwifi: acpi: support device specific method (DSM)")
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/iwlwifi.20210122144849.5757092adcd6.Ic24524627b899c9a01af38107a62a626bdf5ae3a@changeid
parent 3d372c4e
Loading
Loading
Loading
Loading
+50 −15
Original line number Diff line number Diff line
@@ -80,35 +80,52 @@ 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))
		return -ENOENT;

	if (obj->type != ACPI_TYPE_BUFFER) {
	if (IS_ERR(obj)) {
		IWL_DEBUG_DEV_RADIO(dev,
				    "ACPI: DSM method did not return a valid object, type=%d\n",
				    obj->type);
		ret = -EINVAL;
		goto out;
				    "Failed to get  DSM object. func= %d\n",
				    func);
		return -ENOENT;
	}

	if (obj->buffer.length != sizeof(u8)) {
	if (obj->type == ACPI_TYPE_INTEGER) {
		*value = obj->integer.value;
	} else if (obj->type == ACPI_TYPE_BUFFER) {
		__le64 le_value = 0;

		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 method returned invalid buffer, length=%d\n",
					    "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);
		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 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func)
	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,
+4 −3
Original line number Diff line number Diff line
/* 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;
}
+14 −11
Original line number Diff line number Diff line
@@ -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;