First batch of iwlwifi patches for 4.15 (v2)
* Cleanups: - remove an unused value that we read from the NVM; - remove link quality measurement code that was never used; * One FW command API update; * A fix and an addition for PCI devices for the A000 family; * Tiny refactor of ref/unref code used by runtime-PM; * Some debugging improvements; * Implementation of a more flexible way to define command queue sizes; * ACPI code refactoring; * Some coding-style fixes; * Avoid redundant command to the firmware; * Add a struct with the format of one FW command; * Change an error log to a warning when the FW API is not aligned with the driver (important during development); * Change a WARN_ON to WARN_ONCE to make it more descriptive and less noisy (i.e. no repeated warnings on a firmware triggered error); * Dump PCI registers when an error occurs, to make it easier to debug; -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEF3LNfgb2BPWm68smoUecoho8xfoFAlnXdt0ACgkQoUecoho8 xfq1QQ//c4mVNNi0eqgMtamkQ2VJdy233dlxKwzRyaA8ZymMmrWlbHxpCFWS6Iw8 246iWR7EHeC749DIotalCb83ixi02GTGqA65/0eB+LxHTf4TzWx0CmAMBvEdWJQA X+GfUPQSmOTqASoHNV7dmtGH6P3LHL82OAV5OumVTTdSimwt3gdqTv9R53HitXQn br0/IDmx6UEnv7vaymZvVQKarliEdV2IEY59MQLQ/ny7GyTALvu99f/HUlIIvMhk TgGQNcN+ozLhYcJ97DhpWLkkXfaM3e+o6rVmx6xeDT3q4DSveDHYLyXDluXnkXl1 D20bAekeaS46zNmwin8sWtNjpajEElbEWj7pxkJVH+uGRDB9zkqNI9rq35+3BR+u uki7E1mPAVxSthxBT58XbTxM5QghaJLMiYwmDTeRFFkgL5HUEC6hYbB4YKroVn26 56qrIGMyVoWbrlvKUcC5y8ImrbdIzetlhZAWVVqP0Lz2s2KW73xJ4yq+FW1isWTN iRuO3GoLqgR8g4WFVT+90C2O8A5NlgAySG3ScayjOPAFG0+OMjuTszEG/mF7xInU F9Yetd/Ob6MK2p8fb55daZidu+aqDRFNk4lgDlguSLq5vy+a5DvXNQ7rp898uRuQ 8lpCK9qOUpMlkApK3JihUi7C2FORn7Q4bncYcv3HZVI3mxRQQnE= =wHeE -----END PGP SIGNATURE----- Merge tag 'iwlwifi-next-for-kalle-2017-10-06-2' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next First batch of iwlwifi patches for 4.15 (v2) * Cleanups: - remove an unused value that we read from the NVM; - remove link quality measurement code that was never used; * One FW command API update; * A fix and an addition for PCI devices for the A000 family; * Tiny refactor of ref/unref code used by runtime-PM; * Some debugging improvements; * Implementation of a more flexible way to define command queue sizes; * ACPI code refactoring; * Some coding-style fixes; * Avoid redundant command to the firmware; * Add a struct with the format of one FW command; * Change an error log to a warning when the FW API is not aligned with the driver (important during development); * Change a WARN_ON to WARN_ONCE to make it more descriptive and less noisy (i.e. no repeated warnings on a firmware triggered error); * Dump PCI registers when an error occurs, to make it easier to debug;
This commit is contained in:
Коммит
20d879e7f0
|
@ -13,6 +13,7 @@ iwlwifi-objs += iwl-trans.o
|
|||
iwlwifi-objs += fw/notif-wait.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += fw/common_rx.o fw/nvm.o
|
||||
iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
|
||||
|
||||
iwlwifi-objs += $(iwlwifi-m)
|
||||
|
||||
|
|
|
@ -134,7 +134,8 @@ static const struct iwl_ht_params iwl_a000_ht_params = {
|
|||
.rf_id = true, \
|
||||
.gen2 = true, \
|
||||
.ext_nvm = true, \
|
||||
.dbgc_supported = true
|
||||
.dbgc_supported = true, \
|
||||
.tx_cmd_queue_size = 32
|
||||
|
||||
const struct iwl_cfg iwla000_2ac_cfg_hr = {
|
||||
.name = "Intel(R) Dual Band Wireless AC a000",
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program;
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called COPYING.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <linuxwifi@intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "acpi.h"
|
||||
|
||||
void *iwl_acpi_get_object(struct device *dev, acpi_string method)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, method, &handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_DEV_RADIO(dev, "%s method not found\n", method);
|
||||
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",
|
||||
method, status);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
return buf.pointer;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
|
||||
|
||||
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
||||
union acpi_object *data,
|
||||
int data_size)
|
||||
{
|
||||
int i;
|
||||
union acpi_object *wifi_pkg;
|
||||
|
||||
/*
|
||||
* We need at least one entry in the wifi package that
|
||||
* describes the domain, and one more entry, otherwise there's
|
||||
* no point in reading it.
|
||||
*/
|
||||
if (WARN_ON_ONCE(data_size < 2))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/*
|
||||
* We need at least two packages, one for the revision and one
|
||||
* for the data itself. Also check that the revision is valid
|
||||
* (i.e. it is an integer set to 0).
|
||||
*/
|
||||
if (data->type != ACPI_TYPE_PACKAGE ||
|
||||
data->package.count < 2 ||
|
||||
data->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
data->package.elements[0].integer.value != 0) {
|
||||
IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* loop through all the packages to find the one for WiFi */
|
||||
for (i = 1; i < data->package.count; i++) {
|
||||
union acpi_object *domain;
|
||||
|
||||
wifi_pkg = &data->package.elements[i];
|
||||
|
||||
/* skip entries that are not a package with the right size */
|
||||
if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
|
||||
wifi_pkg->package.count != data_size)
|
||||
continue;
|
||||
|
||||
domain = &wifi_pkg->package.elements[0];
|
||||
if (domain->type == ACPI_TYPE_INTEGER &&
|
||||
domain->integer.value == ACPI_WIFI_DOMAIN)
|
||||
goto found;
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
found:
|
||||
return wifi_pkg;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg);
|
||||
|
||||
int iwl_acpi_get_mcc(struct device *dev, char *mcc)
|
||||
{
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
u32 mcc_val;
|
||||
int ret;
|
||||
|
||||
data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mcc_val = wifi_pkg->package.elements[1].integer.value;
|
||||
|
||||
mcc[0] = (mcc_val >> 8) & 0xff;
|
||||
mcc[1] = mcc_val & 0xff;
|
||||
mcc[2] = '\0';
|
||||
|
||||
ret = 0;
|
||||
out_free:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc);
|
||||
|
||||
u64 iwl_acpi_get_pwr_limit(struct device *dev)
|
||||
{
|
||||
union acpi_object *data, *wifi_pkg;
|
||||
u64 dflt_pwr_limit;
|
||||
|
||||
data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
|
||||
if (IS_ERR(data)) {
|
||||
dflt_pwr_limit = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
|
||||
ACPI_SPLC_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg) ||
|
||||
wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
|
||||
dflt_pwr_limit = 0;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
|
||||
out_free:
|
||||
kfree(data);
|
||||
out:
|
||||
return dflt_pwr_limit;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
|
|
@ -0,0 +1,138 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program;
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called COPYING.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <linuxwifi@intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef __iwl_fw_acpi__
|
||||
#define __iwl_fw_acpi__
|
||||
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define ACPI_WRDS_METHOD "WRDS"
|
||||
#define ACPI_EWRD_METHOD "EWRD"
|
||||
#define ACPI_WGDS_METHOD "WGDS"
|
||||
#define ACPI_WRDD_METHOD "WRDD"
|
||||
#define ACPI_SPLC_METHOD "SPLC"
|
||||
|
||||
#define ACPI_WIFI_DOMAIN (0x07)
|
||||
|
||||
#define ACPI_SAR_TABLE_SIZE 10
|
||||
#define ACPI_SAR_PROFILE_NUM 4
|
||||
|
||||
#define ACPI_GEO_TABLE_SIZE 6
|
||||
#define ACPI_NUM_GEO_PROFILES 3
|
||||
#define ACPI_GEO_PER_CHAIN_SIZE 3
|
||||
|
||||
#define ACPI_SAR_NUM_CHAIN_LIMITS 2
|
||||
#define ACPI_SAR_NUM_SUB_BANDS 5
|
||||
|
||||
#define ACPI_WRDS_WIFI_DATA_SIZE (ACPI_SAR_TABLE_SIZE + 2)
|
||||
#define ACPI_EWRD_WIFI_DATA_SIZE ((ACPI_SAR_PROFILE_NUM - 1) * \
|
||||
ACPI_SAR_TABLE_SIZE + 3)
|
||||
#define ACPI_WGDS_WIFI_DATA_SIZE 18
|
||||
#define ACPI_WRDD_WIFI_DATA_SIZE 2
|
||||
#define ACPI_SPLC_WIFI_DATA_SIZE 2
|
||||
|
||||
#define ACPI_WGDS_NUM_BANDS 2
|
||||
#define ACPI_WGDS_TABLE_SIZE 3
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
void *iwl_acpi_get_object(struct device *dev, acpi_string method);
|
||||
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
||||
union acpi_object *data,
|
||||
int data_size);
|
||||
|
||||
/**
|
||||
* iwl_acpi_get_mcc - read MCC from ACPI, if available
|
||||
*
|
||||
* @dev: the struct device
|
||||
* @mcc: output buffer (3 bytes) that will get the MCC
|
||||
*
|
||||
* This function tries to read the current MCC from ACPI if available.
|
||||
*/
|
||||
int iwl_acpi_get_mcc(struct device *dev, char *mcc);
|
||||
|
||||
u64 iwl_acpi_get_pwr_limit(struct device *dev);
|
||||
|
||||
#else /* CONFIG_ACPI */
|
||||
|
||||
static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
|
||||
union acpi_object *data,
|
||||
int data_size)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static inline int iwl_acpi_get_mcc(struct device *dev, char *mcc)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static inline u64 iwl_acpi_get_pwr_limit(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
#endif /* __iwl_fw_acpi__ */
|
|
@ -116,14 +116,14 @@ struct iwl_binding_cmd {
|
|||
#define IWL_MVM_MAX_QUOTA 128
|
||||
|
||||
/**
|
||||
* struct iwl_time_quota_data - configuration of time quota per binding
|
||||
* struct iwl_time_quota_data_v1 - configuration of time quota per binding
|
||||
* @id_and_color: ID and color of the relevant Binding,
|
||||
* &enum iwl_ctxt_id_and_color
|
||||
* @quota: absolute time quota in TU. The scheduler will try to divide the
|
||||
* remainig quota (after Time Events) according to this quota.
|
||||
* @max_duration: max uninterrupted context duration in TU
|
||||
*/
|
||||
struct iwl_time_quota_data {
|
||||
struct iwl_time_quota_data_v1 {
|
||||
__le32 id_and_color;
|
||||
__le32 quota;
|
||||
__le32 max_duration;
|
||||
|
@ -137,8 +137,43 @@ struct iwl_time_quota_data {
|
|||
* essentially zero.
|
||||
* On CDB the fourth one is a regular binding.
|
||||
*/
|
||||
struct iwl_time_quota_cmd {
|
||||
struct iwl_time_quota_data quotas[MAX_BINDINGS];
|
||||
struct iwl_time_quota_cmd_v1 {
|
||||
struct iwl_time_quota_data_v1 quotas[MAX_BINDINGS];
|
||||
} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */
|
||||
|
||||
enum iwl_quota_low_latency {
|
||||
IWL_QUOTA_LOW_LATENCY_NONE = 0,
|
||||
IWL_QUOTA_LOW_LATENCY_TX = BIT(0),
|
||||
IWL_QUOTA_LOW_LATENCY_RX = BIT(1),
|
||||
IWL_QUOTA_LOW_LATENCY_TX_RX =
|
||||
IWL_QUOTA_LOW_LATENCY_TX | IWL_QUOTA_LOW_LATENCY_RX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_time_quota_data - configuration of time quota per binding
|
||||
* @id_and_color: ID and color of the relevant Binding.
|
||||
* @quota: absolute time quota in TU. The scheduler will try to divide the
|
||||
* remainig quota (after Time Events) according to this quota.
|
||||
* @max_duration: max uninterrupted context duration in TU
|
||||
* @low_latency: low latency status, &enum iwl_quota_low_latency
|
||||
*/
|
||||
struct iwl_time_quota_data {
|
||||
__le32 id_and_color;
|
||||
__le32 quota;
|
||||
__le32 max_duration;
|
||||
__le32 low_latency;
|
||||
} __packed; /* TIME_QUOTA_DATA_API_S_VER_2 */
|
||||
|
||||
/**
|
||||
* struct iwl_time_quota_cmd - configuration of time quota between bindings
|
||||
* ( TIME_QUOTA_CMD = 0x2c )
|
||||
* Note: on non-CDB the fourth one is the auxilary mac and is essentially zero.
|
||||
* On CDB the fourth one is a regular binding.
|
||||
*
|
||||
* @quotas: allocations per binding
|
||||
*/
|
||||
struct iwl_time_quota_cmd {
|
||||
struct iwl_time_quota_data quotas[MAX_BINDINGS];
|
||||
} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_2 */
|
||||
|
||||
#endif /* __iwl_fw_api_binding_h__ */
|
||||
|
|
|
@ -504,6 +504,7 @@ enum iwl_legacy_cmds {
|
|||
|
||||
/**
|
||||
* @MARKER_CMD: trace marker command, uses &struct iwl_mvm_marker
|
||||
* with &struct iwl_mvm_marker_rsp
|
||||
*/
|
||||
MARKER_CMD = 0xcb,
|
||||
|
||||
|
|
|
@ -278,6 +278,15 @@ struct iwl_mvm_marker {
|
|||
__le32 metadata[0];
|
||||
} __packed; /* MARKER_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_marker_rsp - Response to marker cmd
|
||||
*
|
||||
* @gp2: The gp2 clock value in the FW
|
||||
*/
|
||||
struct iwl_mvm_marker_rsp {
|
||||
__le32 gp2;
|
||||
} __packed;
|
||||
|
||||
/* Operation types for the debug mem access */
|
||||
enum {
|
||||
DEBUG_MEM_OP_READ = 0,
|
||||
|
|
|
@ -67,79 +67,12 @@
|
|||
* enum iwl_mac_conf_subcmd_ids - mac configuration command IDs
|
||||
*/
|
||||
enum iwl_mac_conf_subcmd_ids {
|
||||
/**
|
||||
* @LINK_QUALITY_MEASUREMENT_CMD: &struct iwl_link_qual_msrmnt_cmd
|
||||
*/
|
||||
LINK_QUALITY_MEASUREMENT_CMD = 0x1,
|
||||
|
||||
/**
|
||||
* @LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF:
|
||||
* &struct iwl_link_qual_msrmnt_notif
|
||||
*/
|
||||
LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE,
|
||||
|
||||
/**
|
||||
* @CHANNEL_SWITCH_NOA_NOTIF: &struct iwl_channel_switch_noa_notif
|
||||
*/
|
||||
CHANNEL_SWITCH_NOA_NOTIF = 0xFF,
|
||||
};
|
||||
|
||||
#define LQM_NUMBER_OF_STATIONS_IN_REPORT 16
|
||||
|
||||
enum iwl_lqm_cmd_operatrions {
|
||||
LQM_CMD_OPERATION_START_MEASUREMENT = 0x01,
|
||||
LQM_CMD_OPERATION_STOP_MEASUREMENT = 0x02,
|
||||
};
|
||||
|
||||
enum iwl_lqm_status {
|
||||
LQM_STATUS_SUCCESS = 0,
|
||||
LQM_STATUS_TIMEOUT = 1,
|
||||
LQM_STATUS_ABORT = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_link_qual_msrmnt_cmd - Link Quality Measurement command
|
||||
* @cmd_operation: command operation to be performed (start or stop)
|
||||
* as defined above.
|
||||
* @mac_id: MAC ID the measurement applies to.
|
||||
* @measurement_time: time of the total measurement to be performed, in uSec.
|
||||
* @timeout: maximum time allowed until a response is sent, in uSec.
|
||||
*/
|
||||
struct iwl_link_qual_msrmnt_cmd {
|
||||
__le32 cmd_operation;
|
||||
__le32 mac_id;
|
||||
__le32 measurement_time;
|
||||
__le32 timeout;
|
||||
} __packed /* LQM_CMD_API_S_VER_1 */;
|
||||
|
||||
/**
|
||||
* struct iwl_link_qual_msrmnt_notif - Link Quality Measurement notification
|
||||
*
|
||||
* @frequent_stations_air_time: an array containing the total air time
|
||||
* (in uSec) used by the most frequently transmitting stations.
|
||||
* @number_of_stations: the number of uniqe stations included in the array
|
||||
* (a number between 0 to 16)
|
||||
* @total_air_time_other_stations: the total air time (uSec) used by all the
|
||||
* stations which are not included in the above report.
|
||||
* @time_in_measurement_window: the total time in uSec in which a measurement
|
||||
* took place.
|
||||
* @tx_frame_dropped: the number of TX frames dropped due to retry limit during
|
||||
* measurement
|
||||
* @mac_id: MAC ID the measurement applies to.
|
||||
* @status: return status. may be one of the LQM_STATUS_* defined above.
|
||||
* @reserved: reserved.
|
||||
*/
|
||||
struct iwl_link_qual_msrmnt_notif {
|
||||
__le32 frequent_stations_air_time[LQM_NUMBER_OF_STATIONS_IN_REPORT];
|
||||
__le32 number_of_stations;
|
||||
__le32 total_air_time_other_stations;
|
||||
__le32 time_in_measurement_window;
|
||||
__le32 tx_frame_dropped;
|
||||
__le32 mac_id;
|
||||
__le32 status;
|
||||
u8 reserved[12];
|
||||
} __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */
|
||||
|
||||
/**
|
||||
* struct iwl_channel_switch_noa_notif - Channel switch NOA notification
|
||||
*
|
||||
|
|
|
@ -358,7 +358,6 @@ struct iwl_dev_tx_power_cmd {
|
|||
} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */
|
||||
|
||||
#define IWL_NUM_GEO_PROFILES 3
|
||||
#define IWL_GEO_PER_CHAIN_SIZE 3
|
||||
|
||||
/**
|
||||
* enum iwl_geo_per_chain_offset_operation - type of operation
|
||||
|
|
|
@ -68,9 +68,6 @@
|
|||
* @STA_FLG_REDUCED_TX_PWR_DATA: reduced TX power (data frames)
|
||||
* @STA_FLG_DISABLE_TX: set if TX should be disabled
|
||||
* @STA_FLG_PS: set if STA is in Power Save
|
||||
* @STA_FLG_INVALID: set if STA is invalid
|
||||
* @STA_FLG_DLP_EN: Direct Link Protocol is enabled
|
||||
* @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs
|
||||
* @STA_FLG_DRAIN_FLOW: drain flow
|
||||
* @STA_FLG_PAN: STA is for PAN interface
|
||||
* @STA_FLG_CLASS_AUTH: station is authenticated
|
||||
|
@ -100,7 +97,6 @@
|
|||
* @STA_FLG_MIMO_EN_SISO: no support for MIMO
|
||||
* @STA_FLG_MIMO_EN_MIMO2: 2 streams supported
|
||||
* @STA_FLG_MIMO_EN_MIMO3: 3 streams supported
|
||||
* @STA_FLG_MFP_EN: Management Frame Protection
|
||||
* @STA_FLG_AGG_MPDU_DENS_MSK: A-MPDU density (mask)
|
||||
* @STA_FLG_AGG_MPDU_DENS_SHIFT: A-MPDU density (bit shift)
|
||||
* @STA_FLG_AGG_MPDU_DENS_2US: A-MPDU density (2 usec gap)
|
||||
|
|
|
@ -93,6 +93,8 @@ static void iwl_read_radio_regs(struct iwl_fw_runtime *fwrt,
|
|||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT radio registers dump\n");
|
||||
|
||||
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
|
||||
return;
|
||||
|
||||
|
@ -233,6 +235,8 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
|
|||
unsigned long flags;
|
||||
int i, j;
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT FIFO dump\n");
|
||||
|
||||
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
|
||||
return;
|
||||
|
||||
|
@ -476,6 +480,8 @@ static void iwl_dump_prph(struct iwl_trans *trans,
|
|||
unsigned long flags;
|
||||
u32 i;
|
||||
|
||||
IWL_DEBUG_INFO(trans, "WRT PRPH dump\n");
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, &flags))
|
||||
return;
|
||||
|
||||
|
@ -559,6 +565,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
bool monitor_dump_only = false;
|
||||
int i;
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT dump start\n");
|
||||
|
||||
/* there's no point in fw dump if the bus is dead */
|
||||
if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
|
||||
IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
|
||||
|
@ -816,6 +824,9 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
dump_mem->type = fw_dbg_mem[i].data_type;
|
||||
dump_mem->offset = cpu_to_le32(ofs);
|
||||
|
||||
IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n",
|
||||
dump_mem->type);
|
||||
|
||||
switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) {
|
||||
case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR):
|
||||
iwl_trans_read_mem_bytes(fwrt->trans, ofs,
|
||||
|
@ -841,6 +852,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
}
|
||||
|
||||
if (smem_len) {
|
||||
IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n");
|
||||
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)dump_data->data;
|
||||
|
@ -853,6 +865,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
}
|
||||
|
||||
if (sram2_len) {
|
||||
IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n");
|
||||
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
|
||||
dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
|
||||
dump_mem = (void *)dump_data->data;
|
||||
|
@ -868,6 +881,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
|
|||
if (!fwrt->trans->cfg->gen2 &&
|
||||
fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
|
||||
fwrt->fw_paging_db[0].fw_paging_block) {
|
||||
IWL_DEBUG_INFO(fwrt, "WRT paging dump\n");
|
||||
for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) {
|
||||
struct iwl_fw_error_dump_paging *paging;
|
||||
struct page *pages =
|
||||
|
@ -930,6 +944,7 @@ out:
|
|||
iwl_fw_free_dump_desc(fwrt);
|
||||
fwrt->dump.trig = NULL;
|
||||
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
|
||||
IWL_DEBUG_INFO(fwrt, "WRT dump done\n");
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_error_dump);
|
||||
|
||||
|
|
|
@ -248,6 +248,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
|
|||
* @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used
|
||||
* @IWL_UCODE_TLV_API_ATS_COEX_EXTERNAL: the coex notification is enlared to
|
||||
* include information about ACL time sharing.
|
||||
* @IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field
|
||||
* indicating low latency direction.
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_API: number of bits used
|
||||
*/
|
||||
|
@ -265,6 +267,7 @@ enum iwl_ucode_tlv_api {
|
|||
IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34,
|
||||
IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35,
|
||||
IWL_UCODE_TLV_API_COEX_ATS_EXTERNAL = (__force iwl_ucode_tlv_api_t)37,
|
||||
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38,
|
||||
|
||||
NUM_IWL_UCODE_TLV_API
|
||||
#ifdef __CHECKER__
|
||||
|
|
|
@ -321,6 +321,8 @@ struct iwl_pwr_tx_backoff {
|
|||
* @gen2: a000 and on transport operation
|
||||
* @cdb: CDB support
|
||||
* @ext_nvm: extended NVM format
|
||||
* @tx_cmd_queue_size: size of the cmd queue. If zero, use the same value as
|
||||
* the regular queues
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt. hardware features.
|
||||
* API differences in uCode shouldn't be handled here but through TLVs
|
||||
|
@ -371,6 +373,7 @@ struct iwl_cfg {
|
|||
cdb:1,
|
||||
ext_nvm:1,
|
||||
dbgc_supported:1;
|
||||
u16 tx_cmd_queue_size;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u8 non_shared_ant;
|
||||
|
|
|
@ -216,6 +216,7 @@ do { \
|
|||
#define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a)
|
||||
#define IWL_DEBUG_TX_QUEUES(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a)
|
||||
#define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
|
||||
#define IWL_DEBUG_DEV_RADIO(p, f, a...) IWL_DEBUG_DEV(p, IWL_DL_RADIO, f, ## a)
|
||||
#define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
|
||||
#define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a)
|
||||
#define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a)
|
||||
|
|
|
@ -1335,7 +1335,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
|||
|
||||
/* Runtime instructions and 2 copies of data:
|
||||
* 1) unmodified from disk
|
||||
* 2) backup cache for save/restore during power-downs */
|
||||
* 2) backup cache for save/restore during power-downs
|
||||
*/
|
||||
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
|
||||
if (iwl_alloc_ucode(drv, pieces, i))
|
||||
goto out_free_fw;
|
||||
|
|
|
@ -68,13 +68,14 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-modparams.h"
|
||||
#include "iwl-nvm-parse.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-csr.h"
|
||||
#include "fw/acpi.h"
|
||||
|
||||
/* NVM offsets (in words) definitions */
|
||||
enum wkp_nvm_offsets {
|
||||
|
@ -89,10 +90,6 @@ enum wkp_nvm_offsets {
|
|||
SKU = 2,
|
||||
N_HW_ADDRS = 3,
|
||||
NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
|
||||
|
||||
/* NVM calibration section offset (in words) definitions */
|
||||
NVM_CALIB_SECTION = 0x2B8,
|
||||
XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
|
||||
};
|
||||
|
||||
enum ext_nvm_offsets {
|
||||
|
@ -748,9 +745,6 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
kfree(data);
|
||||
return NULL;
|
||||
}
|
||||
/* in family 8000 Xtal calibration values moved to OTP */
|
||||
data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
|
||||
data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
|
||||
lar_enabled = true;
|
||||
ch_section = &nvm_sw[NVM_CHANNELS];
|
||||
} else {
|
||||
|
@ -950,91 +944,3 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
|
|||
return regd;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#define WRDD_METHOD "WRDD"
|
||||
#define WRDD_WIFI (0x07)
|
||||
#define WRDD_WIGIG (0x10)
|
||||
|
||||
static u32 iwl_wrdd_get_mcc(struct device *dev, union acpi_object *wrdd)
|
||||
{
|
||||
union acpi_object *mcc_pkg, *domain_type, *mcc_value;
|
||||
u32 i;
|
||||
|
||||
if (wrdd->type != ACPI_TYPE_PACKAGE ||
|
||||
wrdd->package.count < 2 ||
|
||||
wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
wrdd->package.elements[0].integer.value != 0) {
|
||||
IWL_DEBUG_EEPROM(dev, "Unsupported wrdd structure\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1 ; i < wrdd->package.count ; ++i) {
|
||||
mcc_pkg = &wrdd->package.elements[i];
|
||||
|
||||
if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
|
||||
mcc_pkg->package.count < 2 ||
|
||||
mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
|
||||
mcc_pkg = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
domain_type = &mcc_pkg->package.elements[0];
|
||||
if (domain_type->integer.value == WRDD_WIFI)
|
||||
break;
|
||||
|
||||
mcc_pkg = NULL;
|
||||
}
|
||||
|
||||
if (mcc_pkg) {
|
||||
mcc_value = &mcc_pkg->package.elements[1];
|
||||
return mcc_value->integer.value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_get_bios_mcc(struct device *dev, char *mcc)
|
||||
{
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
u32 mcc_val;
|
||||
|
||||
root_handle = ACPI_HANDLE(dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, (acpi_string)WRDD_METHOD,
|
||||
&handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_EEPROM(dev, "WRD method not found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Call WRDD with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_EEPROM(dev, "WRDC invocation failed (0x%x)\n",
|
||||
status);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mcc_val = iwl_wrdd_get_mcc(dev, wrdd.pointer);
|
||||
kfree(wrdd.pointer);
|
||||
if (!mcc_val)
|
||||
return -ENOENT;
|
||||
|
||||
mcc[0] = (mcc_val >> 8) & 0xff;
|
||||
mcc[1] = mcc_val & 0xff;
|
||||
mcc[2] = '\0';
|
||||
return 0;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_get_bios_mcc);
|
||||
#endif
|
||||
|
|
|
@ -109,21 +109,4 @@ struct ieee80211_regdomain *
|
|||
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
|
||||
int num_of_ch, __le32 *channels, u16 fw_mcc);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/**
|
||||
* iwl_get_bios_mcc - read MCC from BIOS, if available
|
||||
*
|
||||
* @dev: the struct device
|
||||
* @mcc: output buffer (3 bytes) that will get the MCC
|
||||
*
|
||||
* This function tries to read the current MCC from ACPI if available.
|
||||
*/
|
||||
int iwl_get_bios_mcc(struct device *dev, char *mcc);
|
||||
#else
|
||||
static inline int iwl_get_bios_mcc(struct device *dev, char *mcc)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __iwl_nvm_parse_h__ */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -31,6 +32,7 @@
|
|||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -205,3 +207,17 @@ int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans)
|
|||
return 0;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_cmd_groups_verify_sorted);
|
||||
|
||||
void iwl_trans_ref(struct iwl_trans *trans)
|
||||
{
|
||||
if (trans->ops->ref)
|
||||
trans->ops->ref(trans);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_trans_ref);
|
||||
|
||||
void iwl_trans_unref(struct iwl_trans *trans)
|
||||
{
|
||||
if (trans->ops->unref)
|
||||
trans->ops->unref(trans);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_trans_unref);
|
||||
|
|
|
@ -749,8 +749,6 @@ struct iwl_trans {
|
|||
struct lockdep_map sync_cmd_lockdep_map;
|
||||
#endif
|
||||
|
||||
u64 dflt_pwr_limit;
|
||||
|
||||
const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
|
||||
const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
|
||||
struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
|
||||
|
@ -875,18 +873,6 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
|
|||
return trans->ops->d3_resume(trans, status, test, reset);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_ref(struct iwl_trans *trans)
|
||||
{
|
||||
if (trans->ops->ref)
|
||||
trans->ops->ref(trans);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_unref(struct iwl_trans *trans)
|
||||
{
|
||||
if (trans->ops->unref)
|
||||
trans->ops->unref(trans);
|
||||
}
|
||||
|
||||
static inline int iwl_trans_suspend(struct iwl_trans *trans)
|
||||
{
|
||||
if (!trans->ops->suspend)
|
||||
|
@ -1191,6 +1177,8 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
|
|||
const struct iwl_cfg *cfg,
|
||||
const struct iwl_trans_ops *ops);
|
||||
void iwl_trans_free(struct iwl_trans *trans);
|
||||
void iwl_trans_ref(struct iwl_trans *trans);
|
||||
void iwl_trans_unref(struct iwl_trans *trans);
|
||||
|
||||
/*****************************************************
|
||||
* driver (transport) register/unregister functions
|
||||
|
|
|
@ -664,6 +664,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
int ret, i;
|
||||
struct iwl_binding_cmd binding_cmd = {};
|
||||
struct iwl_time_quota_cmd quota_cmd = {};
|
||||
struct iwl_time_quota_data *quota;
|
||||
u32 status;
|
||||
int size;
|
||||
|
||||
|
@ -745,17 +746,20 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
return ret;
|
||||
|
||||
/* and some quota */
|
||||
quota_cmd.quotas[0].id_and_color =
|
||||
quota = iwl_mvm_quota_cmd_get_quota(mvm, "a_cmd, 0);
|
||||
quota->id_and_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
|
||||
mvmvif->phy_ctxt->color));
|
||||
quota_cmd.quotas[0].quota = cpu_to_le32(IWL_MVM_MAX_QUOTA);
|
||||
quota_cmd.quotas[0].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
|
||||
quota->quota = cpu_to_le32(IWL_MVM_MAX_QUOTA);
|
||||
quota->max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
|
||||
|
||||
for (i = 1; i < MAX_BINDINGS; i++)
|
||||
quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
|
||||
for (i = 1; i < MAX_BINDINGS; i++) {
|
||||
quota = iwl_mvm_quota_cmd_get_quota(mvm, "a_cmd, i);
|
||||
quota->id_and_color = cpu_to_le32(FW_CTXT_INVALID);
|
||||
}
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
|
||||
sizeof(quota_cmd), "a_cmd);
|
||||
iwl_mvm_quota_cmd_size(mvm), "a_cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
|
||||
|
||||
|
|
|
@ -1455,80 +1455,6 @@ static const char * const chanwidths[] = {
|
|||
[NL80211_CHAN_WIDTH_160] = "vht160",
|
||||
};
|
||||
|
||||
static bool iwl_mvm_lqm_notif_wait(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_rx_packet *pkt, void *data)
|
||||
{
|
||||
struct ieee80211_vif *vif = data;
|
||||
struct iwl_mvm *mvm =
|
||||
container_of(notif_wait, struct iwl_mvm, notif_wait);
|
||||
struct iwl_link_qual_msrmnt_notif *report = (void *)pkt->data;
|
||||
u32 num_of_stations = le32_to_cpu(report->number_of_stations);
|
||||
int i;
|
||||
|
||||
IWL_INFO(mvm, "LQM report:\n");
|
||||
IWL_INFO(mvm, "\tstatus: %d\n", report->status);
|
||||
IWL_INFO(mvm, "\tmacID: %d\n", le32_to_cpu(report->mac_id));
|
||||
IWL_INFO(mvm, "\ttx_frame_dropped: %d\n",
|
||||
le32_to_cpu(report->tx_frame_dropped));
|
||||
IWL_INFO(mvm, "\ttime_in_measurement_window: %d us\n",
|
||||
le32_to_cpu(report->time_in_measurement_window));
|
||||
IWL_INFO(mvm, "\ttotal_air_time_other_stations: %d\n",
|
||||
le32_to_cpu(report->total_air_time_other_stations));
|
||||
IWL_INFO(mvm, "\tchannel_freq: %d\n",
|
||||
vif->bss_conf.chandef.center_freq1);
|
||||
IWL_INFO(mvm, "\tchannel_width: %s\n",
|
||||
chanwidths[vif->bss_conf.chandef.width]);
|
||||
IWL_INFO(mvm, "\tnumber_of_stations: %d\n", num_of_stations);
|
||||
for (i = 0; i < num_of_stations; i++)
|
||||
IWL_INFO(mvm, "\t\tsta[%d]: %d\n", i,
|
||||
report->frequent_stations_air_time[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_lqm_send_cmd_write(struct ieee80211_vif *vif,
|
||||
char *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm *mvm = mvmvif->mvm;
|
||||
struct iwl_notification_wait wait_lqm_notif;
|
||||
static u16 lqm_notif[] = {
|
||||
WIDE_ID(MAC_CONF_GROUP,
|
||||
LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF)
|
||||
};
|
||||
int err;
|
||||
u32 duration;
|
||||
u32 timeout;
|
||||
|
||||
if (sscanf(buf, "%d,%d", &duration, &timeout) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait, &wait_lqm_notif,
|
||||
lqm_notif, ARRAY_SIZE(lqm_notif),
|
||||
iwl_mvm_lqm_notif_wait, vif);
|
||||
mutex_lock(&mvm->mutex);
|
||||
err = iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_START_MEASUREMENT,
|
||||
duration, timeout);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
if (err) {
|
||||
IWL_ERR(mvm, "Failed to send lqm cmdf(err=%d)\n", err);
|
||||
iwl_remove_notification(&mvm->notif_wait, &wait_lqm_notif);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* wait for 2 * timeout (safety guard) and convert to jiffies*/
|
||||
timeout = msecs_to_jiffies((timeout * 2) / 1000);
|
||||
|
||||
err = iwl_wait_notification(&mvm->notif_wait, &wait_lqm_notif,
|
||||
timeout);
|
||||
if (err)
|
||||
IWL_ERR(mvm, "Getting lqm notif timed out\n");
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
|
||||
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
|
||||
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
|
||||
|
@ -1553,7 +1479,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
|
|||
MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
|
||||
|
||||
|
||||
|
@ -1594,7 +1519,6 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
|
||||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff,
|
||||
mvmvif->dbgfs_dir, S_IRUSR);
|
||||
|
||||
|
|
|
@ -660,6 +660,36 @@ out:
|
|||
return ret ?: count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
char *buff, *pos, *endpos;
|
||||
static const size_t bufsz = 1024;
|
||||
int ret;
|
||||
|
||||
buff = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!buff)
|
||||
return -ENOMEM;
|
||||
|
||||
pos = buff;
|
||||
endpos = pos + bufsz;
|
||||
|
||||
pos += scnprintf(pos, endpos - pos, "FW prefix: %s\n",
|
||||
mvm->trans->cfg->fw_name_pre);
|
||||
pos += scnprintf(pos, endpos - pos, "FW: %s\n",
|
||||
mvm->fwrt.fw->human_readable);
|
||||
pos += scnprintf(pos, endpos - pos, "Device: %s\n",
|
||||
mvm->fwrt.trans->cfg->name);
|
||||
pos += scnprintf(pos, endpos - pos, "Bus: %s\n",
|
||||
mvm->fwrt.dev->bus->name);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
|
||||
kfree(buff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PRINT_STATS_LE32(_struct, _memb) \
|
||||
pos += scnprintf(buf + pos, bufsz - pos, \
|
||||
fmt_table, #_memb, \
|
||||
|
@ -1662,6 +1692,7 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
|
|||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(fw_ver);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
|
||||
|
@ -1843,6 +1874,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
|
||||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
*****************************************************************************/
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-op-mode.h"
|
||||
|
@ -75,7 +74,7 @@
|
|||
#include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
|
||||
#include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-eeprom-parse.h"
|
||||
#include "fw/acpi.h"
|
||||
|
||||
#include "mvm.h"
|
||||
#include "fw/dbg.h"
|
||||
|
@ -579,17 +578,6 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#define ACPI_WRDS_METHOD "WRDS"
|
||||
#define ACPI_EWRD_METHOD "EWRD"
|
||||
#define ACPI_WGDS_METHOD "WGDS"
|
||||
#define ACPI_WIFI_DOMAIN (0x07)
|
||||
#define ACPI_WRDS_WIFI_DATA_SIZE (IWL_MVM_SAR_TABLE_SIZE + 2)
|
||||
#define ACPI_EWRD_WIFI_DATA_SIZE ((IWL_MVM_SAR_PROFILE_NUM - 1) * \
|
||||
IWL_MVM_SAR_TABLE_SIZE + 3)
|
||||
#define ACPI_WGDS_WIFI_DATA_SIZE 18
|
||||
#define ACPI_WGDS_NUM_BANDS 2
|
||||
#define ACPI_WGDS_TABLE_SIZE 3
|
||||
|
||||
static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm,
|
||||
union acpi_object *table,
|
||||
struct iwl_mvm_sar_profile *profile,
|
||||
|
@ -599,7 +587,7 @@ static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm,
|
|||
|
||||
profile->enabled = enabled;
|
||||
|
||||
for (i = 0; i < IWL_MVM_SAR_TABLE_SIZE; i++) {
|
||||
for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) {
|
||||
if ((table[i].type != ACPI_TYPE_INTEGER) ||
|
||||
(table[i].integer.value > U8_MAX))
|
||||
return -EINVAL;
|
||||
|
@ -610,87 +598,17 @@ static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static union acpi_object *iwl_mvm_sar_find_wifi_pkg(struct iwl_mvm *mvm,
|
||||
union acpi_object *data,
|
||||
int data_size)
|
||||
{
|
||||
union acpi_object *wifi_pkg = NULL;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* We need at least two packages, one for the revision and one
|
||||
* for the data itself. Also check that the revision is valid
|
||||
* (i.e. it is an integer set to 0).
|
||||
*/
|
||||
if (data->type != ACPI_TYPE_PACKAGE ||
|
||||
data->package.count < 2 ||
|
||||
data->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
data->package.elements[0].integer.value != 0) {
|
||||
IWL_DEBUG_RADIO(mvm, "Unsupported packages structure\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* loop through all the packages to find the one for WiFi */
|
||||
for (i = 1; i < data->package.count; i++) {
|
||||
union acpi_object *domain;
|
||||
|
||||
wifi_pkg = &data->package.elements[i];
|
||||
|
||||
/* Skip anything that is not a package with the right
|
||||
* amount of elements (i.e. domain_type,
|
||||
* enabled/disabled plus the actual data size.
|
||||
*/
|
||||
if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
|
||||
wifi_pkg->package.count != data_size)
|
||||
continue;
|
||||
|
||||
domain = &wifi_pkg->package.elements[0];
|
||||
if (domain->type == ACPI_TYPE_INTEGER &&
|
||||
domain->integer.value == ACPI_WIFI_DOMAIN)
|
||||
break;
|
||||
|
||||
wifi_pkg = NULL;
|
||||
}
|
||||
|
||||
if (!wifi_pkg)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return wifi_pkg;
|
||||
}
|
||||
|
||||
static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm)
|
||||
{
|
||||
union acpi_object *wifi_pkg, *table;
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer wrds = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
union acpi_object *wifi_pkg, *table, *data;
|
||||
bool enabled;
|
||||
int ret;
|
||||
|
||||
root_handle = ACPI_HANDLE(mvm->dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, (acpi_string)ACPI_WRDS_METHOD,
|
||||
&handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "WRDS method not found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Call WRDS with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &wrds);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "WRDS invocation failed (0x%x)\n", status);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, wrds.pointer,
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
|
||||
ACPI_WRDS_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
|
@ -712,45 +630,22 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm)
|
|||
*/
|
||||
ret = iwl_mvm_sar_set_profile(mvm, table, &mvm->sar_profiles[0],
|
||||
enabled);
|
||||
|
||||
out_free:
|
||||
kfree(wrds.pointer);
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
|
||||
{
|
||||
union acpi_object *wifi_pkg;
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer ewrd = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
bool enabled;
|
||||
int i, n_profiles, ret;
|
||||
|
||||
root_handle = ACPI_HANDLE(mvm->dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, (acpi_string)ACPI_EWRD_METHOD,
|
||||
&handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "EWRD method not found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Call EWRD with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &ewrd);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "EWRD invocation failed (0x%x)\n", status);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, ewrd.pointer,
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
|
||||
ACPI_EWRD_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
|
@ -788,55 +683,33 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
|
|||
break;
|
||||
|
||||
/* go to the next table */
|
||||
pos += IWL_MVM_SAR_TABLE_SIZE;
|
||||
pos += ACPI_SAR_TABLE_SIZE;
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(ewrd.pointer);
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
|
||||
{
|
||||
union acpi_object *wifi_pkg;
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer wgds = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
union acpi_object *wifi_pkg, *data;
|
||||
int i, j, ret;
|
||||
int idx = 1;
|
||||
|
||||
root_handle = ACPI_HANDLE(mvm->dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, (acpi_string)ACPI_WGDS_METHOD,
|
||||
&handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "WGDS method not found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Call WGDS with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &wgds);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "WGDS invocation failed (0x%x)\n", status);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, wgds.pointer,
|
||||
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
|
||||
ACPI_WGDS_WIFI_DATA_SIZE);
|
||||
if (IS_ERR(wifi_pkg)) {
|
||||
ret = PTR_ERR(wifi_pkg);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
for (i = 0; i < IWL_NUM_GEO_PROFILES; i++) {
|
||||
for (j = 0; j < IWL_MVM_GEO_TABLE_SIZE; j++) {
|
||||
for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
|
||||
for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) {
|
||||
union acpi_object *entry;
|
||||
|
||||
entry = &wifi_pkg->package.elements[idx++];
|
||||
|
@ -851,7 +724,7 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm)
|
|||
}
|
||||
ret = 0;
|
||||
out_free:
|
||||
kfree(wgds.pointer);
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -861,25 +734,25 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
|
|||
.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS),
|
||||
};
|
||||
int i, j, idx;
|
||||
int profs[IWL_NUM_CHAIN_LIMITS] = { prof_a, prof_b };
|
||||
int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b };
|
||||
int len = sizeof(cmd);
|
||||
|
||||
BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS < 2);
|
||||
BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS !=
|
||||
IWL_MVM_SAR_TABLE_SIZE);
|
||||
BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS < 2);
|
||||
BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS * ACPI_SAR_NUM_SUB_BANDS !=
|
||||
ACPI_SAR_TABLE_SIZE);
|
||||
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
|
||||
len = sizeof(cmd.v3);
|
||||
|
||||
for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
|
||||
for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) {
|
||||
struct iwl_mvm_sar_profile *prof;
|
||||
|
||||
/* don't allow SAR to be disabled (profile 0 means disable) */
|
||||
if (profs[i] == 0)
|
||||
return -EPERM;
|
||||
|
||||
/* we are off by one, so allow up to IWL_MVM_SAR_PROFILE_NUM */
|
||||
if (profs[i] > IWL_MVM_SAR_PROFILE_NUM)
|
||||
/* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */
|
||||
if (profs[i] > ACPI_SAR_PROFILE_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
/* profiles go from 1 to 4, so decrement to access the array */
|
||||
|
@ -894,8 +767,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
|
|||
}
|
||||
|
||||
IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i);
|
||||
for (j = 0; j < IWL_NUM_SUB_BANDS; j++) {
|
||||
idx = (i * IWL_NUM_SUB_BANDS) + j;
|
||||
for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) {
|
||||
idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j;
|
||||
cmd.v3.per_chain_restriction[i][j] =
|
||||
cpu_to_le16(prof->table[idx]);
|
||||
IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n",
|
||||
|
@ -931,7 +804,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
|
|||
|
||||
resp = (void *)cmd.resp_pkt->data;
|
||||
ret = le32_to_cpu(resp->profile_idx);
|
||||
if (WARN_ON(ret > IWL_NUM_GEO_PROFILES)) {
|
||||
if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES)) {
|
||||
ret = -EIO;
|
||||
IWL_WARN(mvm, "Invalid geographic profile idx (%d)\n", ret);
|
||||
}
|
||||
|
@ -959,10 +832,12 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
|
|||
|
||||
IWL_DEBUG_RADIO(mvm, "Sending GEO_TX_POWER_LIMIT\n");
|
||||
|
||||
BUILD_BUG_ON(IWL_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS *
|
||||
BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS *
|
||||
ACPI_WGDS_TABLE_SIZE != ACPI_WGDS_WIFI_DATA_SIZE);
|
||||
|
||||
for (i = 0; i < IWL_NUM_GEO_PROFILES; i++) {
|
||||
BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES > IWL_NUM_GEO_PROFILES);
|
||||
|
||||
for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) {
|
||||
struct iwl_per_chain_offset *chain =
|
||||
(struct iwl_per_chain_offset *)&cmd.table[i];
|
||||
|
||||
|
@ -970,7 +845,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
|
|||
u8 *value;
|
||||
|
||||
value = &mvm->geo_profiles[i].values[j *
|
||||
IWL_GEO_PER_CHAIN_SIZE];
|
||||
ACPI_GEO_PER_CHAIN_SIZE];
|
||||
chain[j].max_tx_power = cpu_to_le16(value[0]);
|
||||
chain[j].chain_a = value[1];
|
||||
chain[j].chain_b = value[2];
|
||||
|
|
|
@ -1878,11 +1878,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|||
if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
|
||||
iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
|
||||
|
||||
if (changes & BSS_CHANGED_ASSOC && !bss_conf->assoc &&
|
||||
mvmvif->lqm_active)
|
||||
iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_STOP_MEASUREMENT,
|
||||
0, 0);
|
||||
|
||||
/*
|
||||
* If we're not associated yet, take the (new) BSSID before associating
|
||||
* so the firmware knows. If we're already associated, then use the old
|
||||
|
@ -3411,10 +3406,24 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
|
|||
return;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
/* we are only changing the min_width, may be a noop */
|
||||
if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) {
|
||||
if (phy_ctxt->width == ctx->min_def.width)
|
||||
goto out_unlock;
|
||||
|
||||
/* we are just toggling between 20_NOHT and 20 */
|
||||
if (phy_ctxt->width <= NL80211_CHAN_WIDTH_20 &&
|
||||
ctx->min_def.width <= NL80211_CHAN_WIDTH_20)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
|
||||
ctx->rx_chains_static,
|
||||
ctx->rx_chains_dynamic);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
|
@ -3879,11 +3888,6 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
|||
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (mvmvif->lqm_active)
|
||||
iwl_mvm_send_lqm_cmd(vif,
|
||||
LQM_CMD_OPERATION_STOP_MEASUREMENT,
|
||||
0, 0);
|
||||
|
||||
/* Schedule the time event to a bit before beacon 1,
|
||||
* to make sure we're in the new channel when the
|
||||
* GO/AP arrives. In case count <= 1 immediately schedule the
|
||||
|
@ -4196,31 +4200,6 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,
|
|||
event->u.ba.ssn);
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct ieee80211_event *event)
|
||||
{
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_ba *ba_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
|
||||
ba_trig = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(event->u.ba.tid)))
|
||||
return;
|
||||
|
||||
iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
|
||||
"Frame from %pM timed out, tid %d",
|
||||
event->u.ba.sta->addr, event->u.ba.tid);
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct ieee80211_event *event)
|
||||
|
@ -4235,7 +4214,8 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
|
|||
iwl_mvm_event_bar_rx_callback(mvm, vif, event);
|
||||
break;
|
||||
case BA_FRAME_TIMEOUT:
|
||||
iwl_mvm_event_frame_timeout_callback(mvm, vif, event);
|
||||
iwl_mvm_event_frame_timeout_callback(mvm, vif, event->u.ba.sta,
|
||||
event->u.ba.tid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
#include "tof.h"
|
||||
#include "fw/runtime.h"
|
||||
#include "fw/dbg.h"
|
||||
#include "fw/acpi.h"
|
||||
|
||||
#define IWL_MVM_MAX_ADDRESSES 5
|
||||
/* RSSI offset for WkP */
|
||||
|
@ -147,6 +148,8 @@ struct iwl_mvm_phy_ctxt {
|
|||
u16 color;
|
||||
u32 ref;
|
||||
|
||||
enum nl80211_chan_width width;
|
||||
|
||||
/*
|
||||
* TODO: This should probably be removed. Currently here only for rate
|
||||
* scaling algorithm
|
||||
|
@ -436,12 +439,6 @@ struct iwl_mvm_vif {
|
|||
|
||||
/* TCP Checksum Offload */
|
||||
netdev_features_t features;
|
||||
|
||||
/*
|
||||
* link quality measurement - used to check whether this interface
|
||||
* is in the middle of a link quality measurement
|
||||
*/
|
||||
bool lqm_active;
|
||||
};
|
||||
|
||||
static inline struct iwl_mvm_vif *
|
||||
|
@ -592,6 +589,7 @@ enum iwl_mvm_tdls_cs_state {
|
|||
* @queue: queue of this reorder buffer
|
||||
* @last_amsdu: track last ASMDU SN for duplication detection
|
||||
* @last_sub_index: track ASMDU sub frame index for duplication detection
|
||||
* @tid: the tid
|
||||
* @entries: list of skbs stored
|
||||
* @reorder_time: time the packet was stored in the reorder buffer
|
||||
* @reorder_timer: timer for frames are in the reorder buffer. For AMSDU
|
||||
|
@ -609,6 +607,7 @@ struct iwl_mvm_reorder_buffer {
|
|||
int queue;
|
||||
u16 last_amsdu;
|
||||
u8 last_sub_index;
|
||||
u8 tid;
|
||||
struct sk_buff_head entries[IEEE80211_MAX_AMPDU_BUF];
|
||||
unsigned long reorder_time[IEEE80211_MAX_AMPDU_BUF];
|
||||
struct timer_list reorder_timer;
|
||||
|
@ -685,20 +684,14 @@ enum iwl_mvm_queue_status {
|
|||
|
||||
#define IWL_MVM_NUM_CIPHERS 10
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#define IWL_MVM_SAR_TABLE_SIZE 10
|
||||
#define IWL_MVM_SAR_PROFILE_NUM 4
|
||||
#define IWL_MVM_GEO_TABLE_SIZE 6
|
||||
|
||||
struct iwl_mvm_sar_profile {
|
||||
bool enabled;
|
||||
u8 table[IWL_MVM_SAR_TABLE_SIZE];
|
||||
u8 table[ACPI_SAR_TABLE_SIZE];
|
||||
};
|
||||
|
||||
struct iwl_mvm_geo_profile {
|
||||
u8 values[IWL_MVM_GEO_TABLE_SIZE];
|
||||
u8 values[ACPI_GEO_TABLE_SIZE];
|
||||
};
|
||||
#endif
|
||||
|
||||
struct iwl_mvm {
|
||||
/* for logger access */
|
||||
|
@ -1016,8 +1009,8 @@ struct iwl_mvm {
|
|||
|
||||
struct delayed_work cs_tx_unblock_dwork;
|
||||
#ifdef CONFIG_ACPI
|
||||
struct iwl_mvm_sar_profile sar_profiles[IWL_MVM_SAR_PROFILE_NUM];
|
||||
struct iwl_mvm_geo_profile geo_profiles[IWL_NUM_GEO_PROFILES];
|
||||
struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM];
|
||||
struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1248,6 +1241,12 @@ static inline bool iwl_mvm_has_new_ats_coex_api(struct iwl_mvm *mvm)
|
|||
IWL_UCODE_TLV_API_COEX_ATS_EXTERNAL);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_has_quota_low_latency(struct iwl_mvm *mvm)
|
||||
{
|
||||
return fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY);
|
||||
}
|
||||
|
||||
static inline struct agg_tx_status *
|
||||
iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp)
|
||||
{
|
||||
|
@ -1486,6 +1485,27 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
|||
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
|
||||
/* Quota management */
|
||||
static inline size_t iwl_mvm_quota_cmd_size(struct iwl_mvm *mvm)
|
||||
{
|
||||
return iwl_mvm_has_quota_low_latency(mvm) ?
|
||||
sizeof(struct iwl_time_quota_cmd) :
|
||||
sizeof(struct iwl_time_quota_cmd_v1);
|
||||
}
|
||||
|
||||
static inline struct iwl_time_quota_data
|
||||
*iwl_mvm_quota_cmd_get_quota(struct iwl_mvm *mvm,
|
||||
struct iwl_time_quota_cmd *cmd,
|
||||
int i)
|
||||
{
|
||||
struct iwl_time_quota_data_v1 *quotas;
|
||||
|
||||
if (iwl_mvm_has_quota_low_latency(mvm))
|
||||
return &cmd->quotas[i];
|
||||
|
||||
quotas = (struct iwl_time_quota_data_v1 *)cmd->quotas;
|
||||
return (struct iwl_time_quota_data *)"as[i];
|
||||
}
|
||||
|
||||
int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload,
|
||||
struct ieee80211_vif *disabled_vif);
|
||||
|
||||
|
@ -1818,12 +1838,10 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm,
|
|||
bool tdls, bool cmd_q);
|
||||
void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
const char *errmsg);
|
||||
|
||||
/* Link Quality Measurement */
|
||||
int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
|
||||
enum iwl_lqm_cmd_operatrions operation,
|
||||
u32 duration, u32 timeout);
|
||||
bool iwl_mvm_lqm_active(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct ieee80211_sta *sta,
|
||||
u16 tid);
|
||||
|
||||
int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b);
|
||||
int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm);
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include "iwl-eeprom-read.h"
|
||||
#include "iwl-nvm-parse.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "fw/acpi.h"
|
||||
|
||||
/* Default NVM size to read */
|
||||
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
|
||||
|
@ -775,7 +776,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
|
|||
return -EIO;
|
||||
|
||||
if (iwl_mvm_is_wifi_mcc_supported(mvm) &&
|
||||
!iwl_get_bios_mcc(mvm->dev, mcc)) {
|
||||
!iwl_acpi_get_mcc(mvm->dev, mcc)) {
|
||||
kfree(regd);
|
||||
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc,
|
||||
MCC_SOURCE_BIOS, NULL);
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
#include "time-event.h"
|
||||
#include "fw-api.h"
|
||||
#include "fw/api/scan.h"
|
||||
#include "fw/acpi.h"
|
||||
|
||||
#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
|
||||
MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
||||
|
@ -423,8 +424,6 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
|
|||
* Access is done through binary search
|
||||
*/
|
||||
static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
|
||||
HCMD_NAME(LINK_QUALITY_MEASUREMENT_CMD),
|
||||
HCMD_NAME(LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF),
|
||||
HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
|
||||
};
|
||||
|
||||
|
@ -490,18 +489,21 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
|
|||
static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
|
||||
static void iwl_mvm_d0i3_exit_work(struct work_struct *wk);
|
||||
|
||||
static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
|
||||
static u32 iwl_mvm_min_backoff(struct iwl_mvm *mvm)
|
||||
{
|
||||
const struct iwl_pwr_tx_backoff *pwr_tx_backoff = cfg->pwr_tx_backoffs;
|
||||
const struct iwl_pwr_tx_backoff *backoff = mvm->cfg->pwr_tx_backoffs;
|
||||
u64 dflt_pwr_limit;
|
||||
|
||||
if (!pwr_tx_backoff)
|
||||
if (!backoff)
|
||||
return 0;
|
||||
|
||||
while (pwr_tx_backoff->pwr) {
|
||||
if (trans->dflt_pwr_limit >= pwr_tx_backoff->pwr)
|
||||
return pwr_tx_backoff->backoff;
|
||||
dflt_pwr_limit = iwl_acpi_get_pwr_limit(mvm->dev);
|
||||
|
||||
pwr_tx_backoff++;
|
||||
while (backoff->pwr) {
|
||||
if (dflt_pwr_limit >= backoff->pwr)
|
||||
return backoff->backoff;
|
||||
|
||||
backoff++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -771,7 +773,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
goto out_free;
|
||||
mvm->hw_registered = true;
|
||||
|
||||
min_backoff = calc_min_backoff(trans, cfg);
|
||||
min_backoff = iwl_mvm_min_backoff(mvm);
|
||||
iwl_mvm_thermal_initialize(mvm, min_backoff);
|
||||
|
||||
err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir);
|
||||
|
|
|
@ -272,6 +272,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
|
|||
}
|
||||
|
||||
ctxt->channel = chandef->chan;
|
||||
ctxt->width = chandef->width;
|
||||
return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
|
||||
chains_static, chains_dynamic,
|
||||
action, 0);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -34,7 +34,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -164,9 +164,12 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
|
|||
beacon_int = mvm->noa_vif->bss_conf.beacon_int;
|
||||
|
||||
for (i = 0; i < MAX_BINDINGS; i++) {
|
||||
u32 id_n_c = le32_to_cpu(cmd->quotas[i].id_and_color);
|
||||
struct iwl_time_quota_data *data =
|
||||
iwl_mvm_quota_cmd_get_quota(mvm, cmd,
|
||||
i);
|
||||
u32 id_n_c = le32_to_cpu(data->id_and_color);
|
||||
u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS;
|
||||
u32 quota = le32_to_cpu(cmd->quotas[i].quota);
|
||||
u32 quota = le32_to_cpu(data->quota);
|
||||
|
||||
if (id != phy_id)
|
||||
continue;
|
||||
|
@ -175,9 +178,9 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
|
|||
quota /= beacon_int;
|
||||
|
||||
IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
|
||||
le32_to_cpu(cmd->quotas[i].quota), quota);
|
||||
le32_to_cpu(data->quota), quota);
|
||||
|
||||
cmd->quotas[i].quota = cpu_to_le32(quota);
|
||||
data->quota = cpu_to_le32(quota);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -194,6 +197,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
|||
.disabled_vif = disabled_vif,
|
||||
};
|
||||
struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
|
||||
struct iwl_time_quota_data *qdata, *last_data;
|
||||
bool send = false;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
@ -216,7 +220,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
|||
*/
|
||||
num_active_macs = 0;
|
||||
for (i = 0; i < MAX_BINDINGS; i++) {
|
||||
cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
|
||||
qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
|
||||
qdata->id_and_color = cpu_to_le32(FW_CTXT_INVALID);
|
||||
num_active_macs += data.n_interfaces[i];
|
||||
}
|
||||
|
||||
|
@ -265,14 +270,16 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
|||
if (data.colors[i] < 0)
|
||||
continue;
|
||||
|
||||
cmd.quotas[idx].id_and_color =
|
||||
qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, idx);
|
||||
|
||||
qdata->id_and_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
|
||||
|
||||
if (data.n_interfaces[i] <= 0)
|
||||
cmd.quotas[idx].quota = cpu_to_le32(0);
|
||||
qdata->quota = cpu_to_le32(0);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
else if (data.dbgfs_min[i])
|
||||
cmd.quotas[idx].quota =
|
||||
qdata->quota =
|
||||
cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100);
|
||||
#endif
|
||||
else if (data.n_low_latency_bindings == 1 && n_non_lowlat &&
|
||||
|
@ -283,24 +290,25 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
|||
* the minimal required quota for the low latency
|
||||
* binding.
|
||||
*/
|
||||
cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN);
|
||||
qdata->quota = cpu_to_le32(QUOTA_LOWLAT_MIN);
|
||||
else
|
||||
cmd.quotas[idx].quota =
|
||||
qdata->quota =
|
||||
cpu_to_le32(quota * data.n_interfaces[i]);
|
||||
|
||||
WARN_ONCE(le32_to_cpu(cmd.quotas[idx].quota) > QUOTA_100,
|
||||
WARN_ONCE(le32_to_cpu(qdata->quota) > QUOTA_100,
|
||||
"Binding=%d, quota=%u > max=%u\n",
|
||||
idx, le32_to_cpu(cmd.quotas[idx].quota), QUOTA_100);
|
||||
idx, le32_to_cpu(qdata->quota), QUOTA_100);
|
||||
|
||||
cmd.quotas[idx].max_duration = cpu_to_le32(0);
|
||||
qdata->max_duration = cpu_to_le32(0);
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* Give the remainder of the session to the first data binding */
|
||||
for (i = 0; i < MAX_BINDINGS; i++) {
|
||||
if (le32_to_cpu(cmd.quotas[i].quota) != 0) {
|
||||
le32_add_cpu(&cmd.quotas[i].quota, quota_rem);
|
||||
qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
|
||||
if (le32_to_cpu(qdata->quota) != 0) {
|
||||
le32_add_cpu(&qdata->quota, quota_rem);
|
||||
IWL_DEBUG_QUOTA(mvm,
|
||||
"quota: giving remainder of %d to binding %d\n",
|
||||
quota_rem, i);
|
||||
|
@ -312,17 +320,19 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
|||
|
||||
/* check that we have non-zero quota for all valid bindings */
|
||||
for (i = 0; i < MAX_BINDINGS; i++) {
|
||||
if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color)
|
||||
qdata = iwl_mvm_quota_cmd_get_quota(mvm, &cmd, i);
|
||||
last_data = iwl_mvm_quota_cmd_get_quota(mvm, last, i);
|
||||
if (qdata->id_and_color != last_data->id_and_color)
|
||||
send = true;
|
||||
if (cmd.quotas[i].max_duration != last->quotas[i].max_duration)
|
||||
if (qdata->max_duration != last_data->max_duration)
|
||||
send = true;
|
||||
if (abs((int)le32_to_cpu(cmd.quotas[i].quota) -
|
||||
(int)le32_to_cpu(last->quotas[i].quota))
|
||||
if (abs((int)le32_to_cpu(qdata->quota) -
|
||||
(int)le32_to_cpu(last_data->quota))
|
||||
> IWL_MVM_QUOTA_THRESHOLD)
|
||||
send = true;
|
||||
if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID))
|
||||
if (qdata->id_and_color == cpu_to_le32(FW_CTXT_INVALID))
|
||||
continue;
|
||||
WARN_ONCE(cmd.quotas[i].quota == 0,
|
||||
WARN_ONCE(qdata->quota == 0,
|
||||
"zero quota on binding %d\n", i);
|
||||
}
|
||||
|
||||
|
@ -334,7 +344,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
|
||||
err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
|
||||
iwl_mvm_quota_cmd_size(mvm), &cmd);
|
||||
|
||||
if (err)
|
||||
IWL_ERR(mvm, "Failed to send quota: %d\n", err);
|
||||
|
|
|
@ -661,11 +661,10 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
|
|||
expected_size = sizeof(struct iwl_notif_statistics_cdb);
|
||||
}
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) != expected_size) {
|
||||
IWL_ERR(mvm, "received invalid statistics size (%d)!\n",
|
||||
iwl_rx_packet_payload_len(pkt));
|
||||
if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) != expected_size,
|
||||
"received invalid statistics size (%d)!\n",
|
||||
iwl_rx_packet_payload_len(pkt)))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
|
||||
struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data;
|
||||
|
|
|
@ -492,13 +492,18 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
|
|||
|
||||
if (expired) {
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[buf->sta_id]);
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
/* SN is set to the last expired frame + 1 */
|
||||
IWL_DEBUG_HT(buf->mvm,
|
||||
"Releasing expired frames for sta %u, sn %d\n",
|
||||
buf->sta_id, sn);
|
||||
iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif,
|
||||
sta, buf->tid);
|
||||
iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn);
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
|
@ -619,7 +624,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|||
return false;
|
||||
|
||||
/* no sta yet */
|
||||
if (WARN_ON(IS_ERR_OR_NULL(sta)))
|
||||
if (WARN_ONCE(IS_ERR_OR_NULL(sta),
|
||||
"Got valid BAID without a valid station assigned\n"))
|
||||
return false;
|
||||
|
||||
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
|
|
@ -2158,6 +2158,7 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm,
|
|||
reorder_buf->mvm = mvm;
|
||||
reorder_buf->queue = i;
|
||||
reorder_buf->sta_id = sta_id;
|
||||
reorder_buf->tid = data->tid;
|
||||
reorder_buf->valid = false;
|
||||
for (j = 0; j < reorder_buf->buf_size; j++)
|
||||
__skb_queue_head_init(&reorder_buf->entries[j]);
|
||||
|
|
|
@ -1368,6 +1368,31 @@ void iwl_mvm_inactivity_check(struct iwl_mvm *mvm)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct ieee80211_sta *sta,
|
||||
u16 tid)
|
||||
{
|
||||
struct iwl_fw_dbg_trigger_tlv *trig;
|
||||
struct iwl_fw_dbg_trigger_ba *ba_trig;
|
||||
|
||||
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
|
||||
return;
|
||||
|
||||
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
|
||||
ba_trig = (void *)trig->data;
|
||||
if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
|
||||
ieee80211_vif_to_wdev(vif), trig))
|
||||
return;
|
||||
|
||||
if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(tid)))
|
||||
return;
|
||||
|
||||
iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
|
||||
"Frame from %pM timed out, tid %d",
|
||||
sta->addr, tid);
|
||||
}
|
||||
|
||||
void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
|
||||
{
|
||||
bool ps_disabled;
|
||||
|
@ -1389,74 +1414,3 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
|
|||
iwl_mvm_power_update_device(mvm);
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
|
||||
enum iwl_lqm_cmd_operatrions operation,
|
||||
u32 duration, u32 timeout)
|
||||
{
|
||||
struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_link_qual_msrmnt_cmd cmd = {
|
||||
.cmd_operation = cpu_to_le32(operation),
|
||||
.mac_id = cpu_to_le32(mvm_vif->id),
|
||||
.measurement_time = cpu_to_le32(duration),
|
||||
.timeout = cpu_to_le32(timeout),
|
||||
};
|
||||
u32 cmdid =
|
||||
iwl_cmd_id(LINK_QUALITY_MEASUREMENT_CMD, MAC_CONF_GROUP, 0);
|
||||
int ret;
|
||||
|
||||
if (!fw_has_capa(&mvm_vif->mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_LQM_SUPPORT))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
|
||||
return -EINVAL;
|
||||
|
||||
switch (operation) {
|
||||
case LQM_CMD_OPERATION_START_MEASUREMENT:
|
||||
if (iwl_mvm_lqm_active(mvm_vif->mvm))
|
||||
return -EBUSY;
|
||||
if (!vif->bss_conf.assoc)
|
||||
return -EINVAL;
|
||||
mvm_vif->lqm_active = true;
|
||||
break;
|
||||
case LQM_CMD_OPERATION_STOP_MEASUREMENT:
|
||||
if (!iwl_mvm_lqm_active(mvm_vif->mvm))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm_vif->mvm, cmdid, 0, sizeof(cmd),
|
||||
&cmd);
|
||||
|
||||
/* command failed - roll back lqm_active state */
|
||||
if (ret) {
|
||||
mvm_vif->lqm_active =
|
||||
operation == LQM_CMD_OPERATION_STOP_MEASUREMENT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_lqm_active_iterator(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
|
||||
bool *lqm_active = _data;
|
||||
|
||||
*lqm_active = *lqm_active || mvm_vif->lqm_active;
|
||||
}
|
||||
|
||||
bool iwl_mvm_lqm_active(struct iwl_mvm *mvm)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_lqm_active_iterator, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -244,7 +244,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
|
|||
ctxt_info->hcmd_cfg.cmd_queue_addr =
|
||||
cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue]->dma_addr);
|
||||
ctxt_info->hcmd_cfg.cmd_queue_size =
|
||||
TFD_QUEUE_CB_SIZE(TFD_CMD_SLOTS);
|
||||
TFD_QUEUE_CB_SIZE(trans_pcie->tx_cmd_queue_size);
|
||||
|
||||
/* allocate ucode sections in dram and set addresses */
|
||||
ret = iwl_pcie_ctxt_info_init_fw_sec(trans, fw, ctxt_info);
|
||||
|
|
|
@ -73,6 +73,8 @@
|
|||
#include <linux/pci-aspm.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "fw/acpi.h"
|
||||
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-drv.h"
|
||||
#include "internal.h"
|
||||
|
@ -576,7 +578,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x2720, 0x0000, iwla000_2ax_cfg_hr)},
|
||||
{IWL_PCI_DEVICE(0x34F0, 0x0070, iwla000_2ax_cfg_hr)},
|
||||
{IWL_PCI_DEVICE(0x2720, 0x0078, iwla000_2ax_cfg_hr)},
|
||||
{IWL_PCI_DEVICE(0x2720, 0x0070, iwla000_2ax_cfg_hr)},
|
||||
{IWL_PCI_DEVICE(0x2720, 0x0070, iwla000_2ac_cfg_hr_cdb)},
|
||||
{IWL_PCI_DEVICE(0x2720, 0x0030, iwla000_2ac_cfg_hr_cdb)},
|
||||
{IWL_PCI_DEVICE(0x2720, 0x1080, iwla000_2ax_cfg_hr)},
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
|
@ -584,99 +587,6 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#define ACPI_SPLC_METHOD "SPLC"
|
||||
#define ACPI_SPLC_DOMAIN_WIFI (0x07)
|
||||
|
||||
static u64 splc_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splc)
|
||||
{
|
||||
union acpi_object *data_pkg, *dflt_pwr_limit;
|
||||
int i;
|
||||
|
||||
/* We need at least two elements, one for the revision and one
|
||||
* for the data itself. Also check that the revision is
|
||||
* supported (currently only revision 0).
|
||||
*/
|
||||
if (splc->type != ACPI_TYPE_PACKAGE ||
|
||||
splc->package.count < 2 ||
|
||||
splc->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
splc->package.elements[0].integer.value != 0) {
|
||||
IWL_DEBUG_INFO(trans,
|
||||
"Unsupported structure returned by the SPLC method. Ignoring.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* loop through all the packages to find the one for WiFi */
|
||||
for (i = 1; i < splc->package.count; i++) {
|
||||
union acpi_object *domain;
|
||||
|
||||
data_pkg = &splc->package.elements[i];
|
||||
|
||||
/* Skip anything that is not a package with the right
|
||||
* amount of elements (i.e. at least 2 integers).
|
||||
*/
|
||||
if (data_pkg->type != ACPI_TYPE_PACKAGE ||
|
||||
data_pkg->package.count < 2 ||
|
||||
data_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
|
||||
continue;
|
||||
|
||||
domain = &data_pkg->package.elements[0];
|
||||
if (domain->integer.value == ACPI_SPLC_DOMAIN_WIFI)
|
||||
break;
|
||||
|
||||
data_pkg = NULL;
|
||||
}
|
||||
|
||||
if (!data_pkg) {
|
||||
IWL_DEBUG_INFO(trans,
|
||||
"No element for the WiFi domain returned by the SPLC method.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dflt_pwr_limit = &data_pkg->package.elements[1];
|
||||
return dflt_pwr_limit->integer.value;
|
||||
}
|
||||
|
||||
static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
|
||||
{
|
||||
acpi_handle pxsx_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer splc = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
|
||||
pxsx_handle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!pxsx_handle) {
|
||||
IWL_DEBUG_INFO(trans,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(pxsx_handle, (acpi_string)ACPI_SPLC_METHOD,
|
||||
&handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_INFO(trans, "SPLC method not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call SPLC with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &splc);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
trans->dflt_pwr_limit = splc_get_pwr_limit(trans, splc.pointer);
|
||||
IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n",
|
||||
trans->dflt_pwr_limit);
|
||||
kfree(splc.pointer);
|
||||
}
|
||||
|
||||
#else /* CONFIG_ACPI */
|
||||
static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {}
|
||||
#endif
|
||||
|
||||
/* PCI registers */
|
||||
#define PCI_CFG_RETRY_TIMEOUT 0x041
|
||||
|
||||
|
@ -740,8 +650,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
goto out_free_trans;
|
||||
}
|
||||
|
||||
set_dflt_pwr_limit(iwl_trans, pdev);
|
||||
|
||||
/* register transport layer debugfs here */
|
||||
ret = iwl_trans_pcie_dbgfs_register(iwl_trans);
|
||||
if (ret)
|
||||
|
|
|
@ -383,6 +383,7 @@ struct iwl_self_init_dram {
|
|||
* @hw_init_mask: initial unmasked hw causes
|
||||
* @fh_mask: current unmasked fh causes
|
||||
* @hw_mask: current unmasked hw causes
|
||||
* @tx_cmd_queue_size: the size of the tx command queue
|
||||
*/
|
||||
struct iwl_trans_pcie {
|
||||
struct iwl_rxq *rxq;
|
||||
|
@ -442,6 +443,7 @@ struct iwl_trans_pcie {
|
|||
bool bc_table_dword;
|
||||
bool scd_set_active;
|
||||
bool sw_csum_tx;
|
||||
bool pcie_dbg_dumped_once;
|
||||
u32 rx_page_order;
|
||||
|
||||
/*protect hw register */
|
||||
|
@ -463,6 +465,7 @@ struct iwl_trans_pcie {
|
|||
u32 fh_mask;
|
||||
u32 hw_mask;
|
||||
cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES];
|
||||
u16 tx_cmd_queue_size;
|
||||
};
|
||||
|
||||
static inline struct iwl_trans_pcie *
|
||||
|
@ -534,6 +537,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
|
|||
void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
|
||||
struct sk_buff_head *skbs);
|
||||
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
|
||||
void iwl_pcie_set_tx_cmd_queue_size(struct iwl_trans *trans);
|
||||
|
||||
static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_trans *trans, void *_tfd,
|
||||
u8 idx)
|
||||
|
|
|
@ -88,6 +88,93 @@
|
|||
#define IWL_FW_MEM_EXTENDED_START 0x40000
|
||||
#define IWL_FW_MEM_EXTENDED_END 0x57FFF
|
||||
|
||||
static void iwl_trans_pcie_err_dump(struct iwl_trans *trans)
|
||||
{
|
||||
#define PCI_DUMP_SIZE 64
|
||||
#define PREFIX_LEN 32
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct pci_dev *pdev = trans_pcie->pci_dev;
|
||||
u32 i, pos, alloc_size, *ptr, *buf;
|
||||
char *prefix;
|
||||
|
||||
if (trans_pcie->pcie_dbg_dumped_once)
|
||||
return;
|
||||
|
||||
/* Should be a multiple of 4 */
|
||||
BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
|
||||
/* Alloc a max size buffer */
|
||||
if (PCI_ERR_ROOT_ERR_SRC + 4 > PCI_DUMP_SIZE)
|
||||
alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
|
||||
else
|
||||
alloc_size = PCI_DUMP_SIZE + PREFIX_LEN;
|
||||
buf = kmalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return;
|
||||
prefix = (char *)buf + alloc_size - PREFIX_LEN;
|
||||
|
||||
IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n");
|
||||
|
||||
/* Print wifi device registers */
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
IWL_ERR(trans, "iwlwifi device config registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
*ptr = iwl_read32(trans, i);
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
IWL_ERR(trans, "iwlwifi device AER capability structure:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, pos + i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
|
||||
32, 4, buf, i, 0);
|
||||
}
|
||||
|
||||
/* Print parent device registers next */
|
||||
if (!pdev->bus->self)
|
||||
goto out;
|
||||
|
||||
pdev = pdev->bus->self;
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
|
||||
IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
|
||||
pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
/* Print root port AER registers */
|
||||
pos = 0;
|
||||
pdev = pcie_find_root_port(pdev);
|
||||
if (pdev)
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n",
|
||||
pci_name(pdev));
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, pos + i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32,
|
||||
4, buf, i, 0);
|
||||
}
|
||||
|
||||
err_read:
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
IWL_ERR(trans, "Read failed at 0x%X\n", i);
|
||||
out:
|
||||
trans_pcie->pcie_dbg_dumped_once = 1;
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
@ -649,6 +736,7 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans,
|
|||
trans_pcie->ucode_write_complete, 5 * HZ);
|
||||
if (!ret) {
|
||||
IWL_ERR(trans, "Failed to load firmware chunk!\n");
|
||||
iwl_trans_pcie_err_dump(trans);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -1868,6 +1956,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
|
|||
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
||||
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
|
||||
if (unlikely(ret < 0)) {
|
||||
iwl_trans_pcie_err_dump(trans);
|
||||
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
|
||||
WARN_ONCE(1,
|
||||
"Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
|
||||
|
|
|
@ -1160,6 +1160,8 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans)
|
|||
struct iwl_txq *cmd_queue;
|
||||
int txq_id = trans_pcie->cmd_queue, ret;
|
||||
|
||||
iwl_pcie_set_tx_cmd_queue_size(trans);
|
||||
|
||||
/* alloc and init the command queue */
|
||||
if (!trans_pcie->txq[txq_id]) {
|
||||
cmd_queue = kzalloc(sizeof(*cmd_queue), GFP_KERNEL);
|
||||
|
@ -1168,7 +1170,8 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans)
|
|||
return -ENOMEM;
|
||||
}
|
||||
trans_pcie->txq[txq_id] = cmd_queue;
|
||||
ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, true);
|
||||
ret = iwl_pcie_txq_alloc(trans, cmd_queue,
|
||||
trans_pcie->tx_cmd_queue_size, true);
|
||||
if (ret) {
|
||||
IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
|
||||
goto error;
|
||||
|
@ -1177,7 +1180,8 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans)
|
|||
cmd_queue = trans_pcie->txq[txq_id];
|
||||
}
|
||||
|
||||
ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, true);
|
||||
ret = iwl_pcie_txq_init(trans, cmd_queue,
|
||||
trans_pcie->tx_cmd_queue_size, true);
|
||||
if (ret) {
|
||||
IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
|
||||
goto error;
|
||||
|
|
|
@ -951,7 +951,8 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans)
|
|||
txq_id++) {
|
||||
bool cmd_queue = (txq_id == trans_pcie->cmd_queue);
|
||||
|
||||
slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
|
||||
slots_num = cmd_queue ? trans_pcie->tx_cmd_queue_size :
|
||||
TFD_TX_CMD_SLOTS;
|
||||
trans_pcie->txq[txq_id] = &trans_pcie->txq_memory[txq_id];
|
||||
ret = iwl_pcie_txq_alloc(trans, trans_pcie->txq[txq_id],
|
||||
slots_num, cmd_queue);
|
||||
|
@ -970,6 +971,21 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void iwl_pcie_set_tx_cmd_queue_size(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int queue_size = TFD_CMD_SLOTS;
|
||||
|
||||
if (trans->cfg->tx_cmd_queue_size)
|
||||
queue_size = trans->cfg->tx_cmd_queue_size;
|
||||
|
||||
if (WARN_ON(!(is_power_of_2(queue_size) &&
|
||||
TFD_QUEUE_CB_SIZE(queue_size) > 0)))
|
||||
trans_pcie->tx_cmd_queue_size = TFD_CMD_SLOTS;
|
||||
else
|
||||
trans_pcie->tx_cmd_queue_size = queue_size;
|
||||
}
|
||||
|
||||
int iwl_pcie_tx_init(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
@ -977,6 +993,8 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
|
|||
int txq_id, slots_num;
|
||||
bool alloc = false;
|
||||
|
||||
iwl_pcie_set_tx_cmd_queue_size(trans);
|
||||
|
||||
if (!trans_pcie->txq_memory) {
|
||||
ret = iwl_pcie_tx_alloc(trans);
|
||||
if (ret)
|
||||
|
@ -1000,7 +1018,8 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
|
|||
txq_id++) {
|
||||
bool cmd_queue = (txq_id == trans_pcie->cmd_queue);
|
||||
|
||||
slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
|
||||
slots_num = cmd_queue ? trans_pcie->tx_cmd_queue_size :
|
||||
TFD_TX_CMD_SLOTS;
|
||||
ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id],
|
||||
slots_num, cmd_queue);
|
||||
if (ret) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче