mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
ath.git patches for v7.3 (PR #1)
There has been quite a bit of activity across the ath drivers. Significant changes in ath12k include: Align with new Qualcomm generic Peripheral Authentication Service (PAS). Ongoing infrastructure changes to support the QCC2072 platform. Ongoing infrastructure changes to support the IPQ5332 platform. Enhance datapath statistics. Tuning of datapath parameters. In addition, an assortment of cleanups and minor bug fixes across ath6kl, ath10k, ath11k, ath12k, and carl9170. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQ/mtSHzPUi16IfDEksFbugiYzLewUCamDp7AAKCRAsFbugiYzL ezyJAQC6D29OEEnel7C3H4gPsLdF8oI3pszt9MHFAhKpqCh/7AEAzzuvfNVfewXU WeP+bkfi+fLPSChX4UxWsw8xx4vVHgM= =A8cC -----END PGP SIGNATURE----- Merge tag 'ath-next-20260722' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath Jeff Johnson says: ================== ath.git patches for v7.3 (PR #1) There has been quite a bit of activity across the ath drivers. Significant changes in ath12k include: Align with new Qualcomm generic Peripheral Authentication Service (PAS). Ongoing infrastructure changes to support the QCC2072 platform. Ongoing infrastructure changes to support the IPQ5332 platform. Enhance datapath statistics. Tuning of datapath parameters. In addition, an assortment of cleanups and minor bug fixes across ath6kl, ath10k, ath11k, ath12k, and carl9170. ================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
commit
90883c513c
|
|
@ -22325,6 +22325,15 @@ F: Documentation/devicetree/bindings/media/*qcom*
|
|||
F: drivers/media/platform/qcom
|
||||
F: include/dt-bindings/media/*qcom*
|
||||
|
||||
QUALCOMM PAS TZ SERVICE
|
||||
M: Sumit Garg <sumit.garg@oss.qualcomm.com>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/firmware/qcom/qcom_pas.c
|
||||
F: drivers/firmware/qcom/qcom_pas.h
|
||||
F: drivers/firmware/qcom/qcom_pas_tee.c
|
||||
F: include/linux/firmware/qcom/qcom_pas.h
|
||||
|
||||
QUALCOMM SMB CHARGER DRIVER
|
||||
M: Casey Connolly <casey.connolly@linaro.org>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -6,9 +6,29 @@
|
|||
|
||||
menu "Qualcomm firmware drivers"
|
||||
|
||||
config QCOM_PAS
|
||||
tristate "Qualcomm generic PAS interface driver"
|
||||
help
|
||||
Enable the generic Peripheral Authentication Service (PAS) provided
|
||||
by the firmware. It acts as the common layer with different TZ
|
||||
backends plugged in whether it's an SCM implementation or a proper
|
||||
TEE bus based PAS service implementation.
|
||||
|
||||
config QCOM_PAS_TEE
|
||||
tristate "Qualcomm PAS TEE interface driver"
|
||||
select QCOM_PAS
|
||||
depends on TEE
|
||||
depends on !CPU_BIG_ENDIAN
|
||||
default m if ARCH_QCOM
|
||||
help
|
||||
Enable the generic Peripheral Authentication Service (PAS) provided
|
||||
by the firmware TEE implementation as the backend.
|
||||
|
||||
config QCOM_SCM
|
||||
tristate "Qualcomm PAS SCM interface driver"
|
||||
select QCOM_PAS
|
||||
select QCOM_TZMEM
|
||||
tristate
|
||||
default y if ARCH_QCOM
|
||||
|
||||
config QCOM_TZMEM
|
||||
tristate
|
||||
|
|
|
|||
|
|
@ -8,3 +8,5 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
|
|||
obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
|
||||
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
|
||||
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
|
||||
obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
|
||||
obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o
|
||||
|
|
|
|||
298
drivers/firmware/qcom/qcom_pas.c
Normal file
298
drivers/firmware/qcom/qcom_pas.c
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2015 Linaro Ltd.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "qcom_pas.h"
|
||||
|
||||
static struct qcom_pas_ops *ops_ptr;
|
||||
|
||||
/**
|
||||
* devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
|
||||
* context for a given peripheral
|
||||
*
|
||||
* PAS context is device-resource managed, so the caller does not need
|
||||
* to worry about freeing the context memory.
|
||||
*
|
||||
* @dev: PAS firmware device
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @mem_phys: Subsystem reserve memory start address
|
||||
* @mem_size: Subsystem reserve memory size
|
||||
*
|
||||
* Return: The new PAS context, or ERR_PTR() on failure.
|
||||
*/
|
||||
struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
|
||||
u32 pas_id,
|
||||
phys_addr_t mem_phys,
|
||||
size_t mem_size)
|
||||
{
|
||||
struct qcom_pas_context *ctx;
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ctx->dev = dev;
|
||||
ctx->pas_id = pas_id;
|
||||
ctx->mem_phys = mem_phys;
|
||||
ctx->mem_size = mem_size;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
|
||||
|
||||
/**
|
||||
* qcom_pas_init_image() - Initialize peripheral authentication service state
|
||||
* machine for a given peripheral, using the metadata
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @metadata: pointer to memory containing ELF header, program header table
|
||||
* and optional blob of data used for authenticating the metadata
|
||||
* and the rest of the firmware
|
||||
* @size: size of the metadata
|
||||
* @ctx: optional pas context
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*
|
||||
* Upon successful return, the PAS metadata context (@ctx) will be used to
|
||||
* track the metadata allocation, this needs to be released by invoking
|
||||
* qcom_pas_metadata_release() by the caller.
|
||||
*/
|
||||
int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_init_image);
|
||||
|
||||
/**
|
||||
* qcom_pas_metadata_release() - release metadata context
|
||||
* @ctx: pas context
|
||||
*/
|
||||
void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
|
||||
{
|
||||
if (!ops_ptr || !ctx || !ctx->ptr)
|
||||
return;
|
||||
|
||||
ops_ptr->metadata_release(ops_ptr->dev, ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
|
||||
|
||||
/**
|
||||
* qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
|
||||
* for firmware loading
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @addr: start address of memory area to prepare
|
||||
* @size: size of the memory area to prepare
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
|
||||
|
||||
/**
|
||||
* qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
|
||||
* for a given peripheral.
|
||||
*
|
||||
* Qualcomm remote processor may rely on both static and dynamic resources for
|
||||
* its functionality. Static resources typically refer to memory-mapped
|
||||
* addresses required by the subsystem and are often embedded within the
|
||||
* firmware binary and dynamic resources, such as shared memory in DDR etc.,
|
||||
* are determined at runtime during the boot process.
|
||||
*
|
||||
* On Qualcomm Technologies devices, it's possible that static resources are
|
||||
* not embedded in the firmware binary and instead are provided by TrustZone.
|
||||
* However, dynamic resources are always expected to come from TrustZone. This
|
||||
* indicates that for Qualcomm devices, all resources (static and dynamic) will
|
||||
* be provided by TrustZone PAS service.
|
||||
*
|
||||
* If the remote processor firmware binary does contain static resources, they
|
||||
* should be passed in input_rt. These will be forwarded to TrustZone for
|
||||
* authentication. TrustZone will then append the dynamic resources and return
|
||||
* the complete resource table in output_rt_tzm.
|
||||
*
|
||||
* If the remote processor firmware binary does not include a resource table,
|
||||
* the caller of this function should set input_rt as NULL and input_rt_size
|
||||
* as zero respectively.
|
||||
*
|
||||
* More about documentation on resource table data structures can be found in
|
||||
* include/linux/remoteproc.h
|
||||
*
|
||||
* @ctx: PAS context
|
||||
* @input_rt: resource table buffer which is present in firmware binary
|
||||
* @input_rt_size: size of the resource table present in firmware binary
|
||||
* @output_rt_size: TrustZone expects caller should pass worst case size for
|
||||
* the output_rt_tzm.
|
||||
*
|
||||
* Return:
|
||||
* On success, returns a pointer to the allocated buffer containing the final
|
||||
* resource table and output_rt_size will have actual resource table size from
|
||||
* TrustZone. The caller is responsible for freeing the buffer. On failure,
|
||||
* returns ERR_PTR(-errno).
|
||||
*/
|
||||
struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
|
||||
void *input_rt,
|
||||
size_t input_rt_size,
|
||||
size_t *output_rt_size)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return ERR_PTR(-ENODEV);
|
||||
if (!ctx)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
|
||||
input_rt_size, output_rt_size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
|
||||
|
||||
/**
|
||||
* qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
|
||||
* and reset the remote processor
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_auth_and_reset(u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
|
||||
|
||||
/**
|
||||
* qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
|
||||
* remote processor
|
||||
*
|
||||
* @ctx: Context saved during call to devm_qcom_pas_context_alloc()
|
||||
*
|
||||
* This function performs the necessary steps to prepare a PAS subsystem,
|
||||
* authenticate it using the provided metadata, and initiate a reset sequence.
|
||||
*
|
||||
* It should be used when Linux is in control setting up the IOMMU hardware
|
||||
* for remote subsystem during secure firmware loading processes. The
|
||||
* preparation step sets up a shmbridge over the firmware memory before
|
||||
* TrustZone accesses the firmware memory region for authentication. The
|
||||
* authentication step verifies the integrity and authenticity of the firmware
|
||||
* or configuration using secure metadata. Finally, the reset step ensures the
|
||||
* subsystem starts in a clean and sane state.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure.
|
||||
*/
|
||||
int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
|
||||
|
||||
/**
|
||||
* qcom_pas_set_remote_state() - Set the remote processor state
|
||||
* @state: peripheral state
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_set_remote_state(u32 state, u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
|
||||
|
||||
/**
|
||||
* qcom_pas_shutdown() - Shut down the remote processor
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int qcom_pas_shutdown(u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
return ops_ptr->shutdown(ops_ptr->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
|
||||
|
||||
/**
|
||||
* qcom_pas_supported() - Check if the peripheral authentication service is
|
||||
* supported for the given peripheral
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return: true if PAS is supported for this peripheral, otherwise false.
|
||||
*/
|
||||
bool qcom_pas_supported(u32 pas_id)
|
||||
{
|
||||
if (!ops_ptr)
|
||||
return false;
|
||||
|
||||
return ops_ptr->supported(ops_ptr->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_supported);
|
||||
|
||||
/**
|
||||
* qcom_pas_is_available() - Check if the peripheral authentication service is
|
||||
* available. Note that it is mandatory for any PAS
|
||||
* client to invoke this API. If it returns true then
|
||||
* only any other PAS API can be invoked.
|
||||
*
|
||||
* Return: true if PAS is available, otherwise false.
|
||||
*/
|
||||
bool qcom_pas_is_available(void)
|
||||
{
|
||||
/*
|
||||
* The barrier for ops_ptr is intended to synchronize the data stores
|
||||
* for the ops data structure when client drivers are in parallel
|
||||
* checking for PAS service availability.
|
||||
*
|
||||
* Once the PAS backend becomes available, it is allowed for multiple
|
||||
* threads to enter TZ for parallel bringup of co-processors during
|
||||
* boot.
|
||||
*/
|
||||
return !!smp_load_acquire(&ops_ptr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_is_available);
|
||||
|
||||
void qcom_pas_ops_register(struct qcom_pas_ops *ops)
|
||||
{
|
||||
if (!qcom_pas_is_available())
|
||||
/* Paired with smp_load_acquire() in qcom_pas_is_available() */
|
||||
smp_store_release(&ops_ptr, ops);
|
||||
else
|
||||
pr_err("qcom_pas: ops already registered by %s\n",
|
||||
ops_ptr->drv_name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
|
||||
|
||||
void qcom_pas_ops_unregister(void)
|
||||
{
|
||||
/* Paired with smp_load_acquire() in qcom_pas_is_available() */
|
||||
smp_store_release(&ops_ptr, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver");
|
||||
50
drivers/firmware/qcom/qcom_pas.h
Normal file
50
drivers/firmware/qcom/qcom_pas.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef __QCOM_PAS_INT_H
|
||||
#define __QCOM_PAS_INT_H
|
||||
|
||||
struct device;
|
||||
|
||||
/**
|
||||
* struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
|
||||
* @drv_name: PAS driver name.
|
||||
* @dev: PAS device pointer.
|
||||
* @supported: Peripheral supported callback.
|
||||
* @init_image: Peripheral image initialization callback.
|
||||
* @mem_setup: Peripheral memory setup callback.
|
||||
* @get_rsc_table: Peripheral get resource table callback.
|
||||
* @prepare_and_auth_reset: Peripheral prepare firmware authentication and
|
||||
* reset callback.
|
||||
* @auth_and_reset: Peripheral firmware authentication and reset
|
||||
* callback.
|
||||
* @set_remote_state: Peripheral set remote state callback.
|
||||
* @shutdown: Peripheral shutdown callback.
|
||||
* @metadata_release: Image metadata release callback.
|
||||
*/
|
||||
struct qcom_pas_ops {
|
||||
const char *drv_name;
|
||||
struct device *dev;
|
||||
bool (*supported)(struct device *dev, u32 pas_id);
|
||||
int (*init_image)(struct device *dev, u32 pas_id, const void *metadata,
|
||||
size_t size, struct qcom_pas_context *ctx);
|
||||
int (*mem_setup)(struct device *dev, u32 pas_id, phys_addr_t addr,
|
||||
phys_addr_t size);
|
||||
void *(*get_rsc_table)(struct device *dev, struct qcom_pas_context *ctx,
|
||||
void *input_rt, size_t input_rt_size,
|
||||
size_t *output_rt_size);
|
||||
int (*prepare_and_auth_reset)(struct device *dev,
|
||||
struct qcom_pas_context *ctx);
|
||||
int (*auth_and_reset)(struct device *dev, u32 pas_id);
|
||||
int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id);
|
||||
int (*shutdown)(struct device *dev, u32 pas_id);
|
||||
void (*metadata_release)(struct device *dev,
|
||||
struct qcom_pas_context *ctx);
|
||||
};
|
||||
|
||||
void qcom_pas_ops_register(struct qcom_pas_ops *ops);
|
||||
void qcom_pas_ops_unregister(void);
|
||||
|
||||
#endif /* __QCOM_PAS_INT_H */
|
||||
479
drivers/firmware/qcom/qcom_pas_tee.c
Normal file
479
drivers/firmware/qcom/qcom_pas_tee.c
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#include "qcom_pas.h"
|
||||
|
||||
/*
|
||||
* Peripheral Authentication Service (PAS) supported.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
*/
|
||||
#define TA_QCOM_PAS_IS_SUPPORTED 1
|
||||
|
||||
/*
|
||||
* PAS capabilities.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
* [out] params[1].value.a: PAS capability flags
|
||||
*/
|
||||
#define TA_QCOM_PAS_CAPABILITIES 2
|
||||
|
||||
/*
|
||||
* PAS image initialization.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
* [in] params[1].memref: Loadable firmware metadata
|
||||
*/
|
||||
#define TA_QCOM_PAS_INIT_IMAGE 3
|
||||
|
||||
/*
|
||||
* PAS memory setup.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
* [in] params[0].value.b: Relocatable firmware size
|
||||
* [in] params[1].value.a: 32bit LSB relocatable firmware memory address
|
||||
* [in] params[1].value.b: 32bit MSB relocatable firmware memory address
|
||||
*/
|
||||
#define TA_QCOM_PAS_MEM_SETUP 4
|
||||
|
||||
/*
|
||||
* PAS get resource table.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
* [inout] params[1].memref: Resource table config
|
||||
*/
|
||||
#define TA_QCOM_PAS_GET_RESOURCE_TABLE 5
|
||||
|
||||
/*
|
||||
* PAS image authentication and co-processor reset.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
* [in] params[0].value.b: Firmware size
|
||||
* [in] params[1].value.a: 32bit LSB firmware memory address
|
||||
* [in] params[1].value.b: 32bit MSB firmware memory address
|
||||
* [in] params[2].memref: Optional fw memory space shared/lent
|
||||
*/
|
||||
#define TA_QCOM_PAS_AUTH_AND_RESET 6
|
||||
|
||||
/*
|
||||
* PAS co-processor set suspend/resume state.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
* [in] params[0].value.b: Co-processor state identifier
|
||||
*/
|
||||
#define TA_QCOM_PAS_SET_REMOTE_STATE 7
|
||||
|
||||
/*
|
||||
* PAS co-processor shutdown.
|
||||
*
|
||||
* [in] params[0].value.a: Unique 32bit remote processor identifier
|
||||
*/
|
||||
#define TA_QCOM_PAS_SHUTDOWN 8
|
||||
|
||||
#define TEE_NUM_PARAMS 4
|
||||
|
||||
/**
|
||||
* struct qcom_pas_tee_private - PAS service private data
|
||||
* @dev: PAS service device.
|
||||
* @ctx: TEE context handler.
|
||||
* @session_id: PAS TA session identifier.
|
||||
*/
|
||||
struct qcom_pas_tee_private {
|
||||
struct device *dev;
|
||||
struct tee_context *ctx;
|
||||
u32 session_id;
|
||||
};
|
||||
|
||||
static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_IS_SUPPORTED,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = pas_id
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id,
|
||||
const void *metadata, size_t size,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_INIT_IMAGE,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = pas_id
|
||||
},
|
||||
[1] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
|
||||
}
|
||||
};
|
||||
struct tee_shm *mdata_shm;
|
||||
u8 *mdata_buf = NULL;
|
||||
int ret;
|
||||
|
||||
mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size);
|
||||
if (IS_ERR(mdata_shm)) {
|
||||
dev_err(dev, "mdata_shm allocation failed\n");
|
||||
return PTR_ERR(mdata_shm);
|
||||
}
|
||||
|
||||
mdata_buf = tee_shm_get_va(mdata_shm, 0);
|
||||
if (IS_ERR(mdata_buf)) {
|
||||
dev_err(dev, "mdata_buf get VA failed\n");
|
||||
tee_shm_free(mdata_shm);
|
||||
return PTR_ERR(mdata_buf);
|
||||
}
|
||||
memcpy(mdata_buf, metadata, size);
|
||||
|
||||
param[1].u.memref.shm = mdata_shm;
|
||||
param[1].u.memref.size = size;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
tee_shm_free(mdata_shm);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
if (ctx)
|
||||
ctx->ptr = (void *)mdata_shm;
|
||||
else
|
||||
tee_shm_free(mdata_shm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id,
|
||||
phys_addr_t addr, phys_addr_t size)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_MEM_SETUP,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = pas_id,
|
||||
.u.value.b = size,
|
||||
},
|
||||
[1] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = lower_32_bits(addr),
|
||||
.u.value.b = upper_32_bits(addr),
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T))
|
||||
|
||||
static void *qcom_pas_tee_get_rsc_table(struct device *dev,
|
||||
struct qcom_pas_context *ctx,
|
||||
void *input_rt, size_t input_rt_size,
|
||||
size_t *output_rt_size)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_GET_RESOURCE_TABLE,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = ctx->pas_id,
|
||||
},
|
||||
[1] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
|
||||
.u.memref.size = input_rt_size,
|
||||
}
|
||||
};
|
||||
void *rt_buf = NULL;
|
||||
int ret;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
ctx->pas_id, ret, inv_arg.ret);
|
||||
return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (param[1].u.memref.size >= input_rt_size) {
|
||||
struct tee_shm *rt_shm __free(shm_free) =
|
||||
tee_shm_alloc_kernel_buf(data->ctx,
|
||||
param[1].u.memref.size);
|
||||
void *rt_shm_va;
|
||||
|
||||
if (IS_ERR_OR_NULL(rt_shm)) {
|
||||
dev_err(dev, "rt_shm allocation failed\n");
|
||||
rt_shm = NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
rt_shm_va = tee_shm_get_va(rt_shm, 0);
|
||||
if (IS_ERR(rt_shm_va)) {
|
||||
dev_err(dev, "rt_shm get VA failed\n");
|
||||
return ERR_CAST(rt_shm_va);
|
||||
}
|
||||
memcpy(rt_shm_va, input_rt, input_rt_size);
|
||||
|
||||
param[1].u.memref.shm = rt_shm;
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
ctx->pas_id, ret, inv_arg.ret);
|
||||
return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (param[1].u.memref.size) {
|
||||
*output_rt_size = param[1].u.memref.size;
|
||||
rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
|
||||
if (!rt_buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
} else {
|
||||
*output_rt_size = 0;
|
||||
}
|
||||
|
||||
return rt_buf;
|
||||
}
|
||||
|
||||
static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id,
|
||||
phys_addr_t mem_phys, size_t mem_size)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_AUTH_AND_RESET,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = pas_id,
|
||||
.u.value.b = mem_size,
|
||||
},
|
||||
[1] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = lower_32_bits(mem_phys),
|
||||
.u.value.b = upper_32_bits(mem_phys),
|
||||
},
|
||||
/* Reserved for fw memory space to be shared or lent */
|
||||
[2] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id)
|
||||
{
|
||||
return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0);
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys,
|
||||
ctx->mem_size);
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state,
|
||||
u32 pas_id)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_SET_REMOTE_STATE,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = pas_id,
|
||||
.u.value.b = state,
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS set remote state failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id)
|
||||
{
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
struct tee_ioctl_invoke_arg inv_arg = {
|
||||
.func = TA_QCOM_PAS_SHUTDOWN,
|
||||
.session = data->session_id,
|
||||
.num_params = TEE_NUM_PARAMS
|
||||
};
|
||||
struct tee_param param[4] = {
|
||||
[0] = {
|
||||
.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
.u.value.a = pas_id
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
|
||||
if (ret < 0 || inv_arg.ret != 0) {
|
||||
dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
|
||||
pas_id, ret, inv_arg.ret);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_pas_tee_metadata_release(struct device *dev,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
struct tee_shm *mdata_shm = ctx->ptr;
|
||||
|
||||
tee_shm_free(mdata_shm);
|
||||
ctx->ptr = NULL;
|
||||
}
|
||||
|
||||
static struct qcom_pas_ops qcom_pas_ops_tee = {
|
||||
.drv_name = "qcom-pas-tee",
|
||||
.supported = qcom_pas_tee_supported,
|
||||
.init_image = qcom_pas_tee_init_image,
|
||||
.mem_setup = qcom_pas_tee_mem_setup,
|
||||
.get_rsc_table = qcom_pas_tee_get_rsc_table,
|
||||
.auth_and_reset = qcom_pas_tee_auth_and_reset,
|
||||
.prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset,
|
||||
.set_remote_state = qcom_pas_tee_set_remote_state,
|
||||
.shutdown = qcom_pas_tee_shutdown,
|
||||
.metadata_release = qcom_pas_tee_metadata_release,
|
||||
};
|
||||
|
||||
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
|
||||
{
|
||||
return ver->impl_id == TEE_IMPL_ID_OPTEE;
|
||||
}
|
||||
|
||||
static int qcom_pas_tee_probe(struct tee_client_device *pas_dev)
|
||||
{
|
||||
struct device *dev = &pas_dev->dev;
|
||||
struct qcom_pas_tee_private *data;
|
||||
struct tee_ioctl_open_session_arg sess_arg = {
|
||||
.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL
|
||||
};
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
|
||||
if (IS_ERR(data->ctx))
|
||||
return -ENODEV;
|
||||
|
||||
export_uuid(sess_arg.uuid, &pas_dev->id.uuid);
|
||||
ret = tee_client_open_session(data->ctx, &sess_arg, NULL);
|
||||
if (ret < 0 || sess_arg.ret != 0) {
|
||||
dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n",
|
||||
ret, sess_arg.ret);
|
||||
tee_client_close_context(data->ctx);
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
data->session_id = sess_arg.session;
|
||||
dev_set_drvdata(dev, data);
|
||||
qcom_pas_ops_tee.dev = dev;
|
||||
qcom_pas_ops_register(&qcom_pas_ops_tee);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_pas_tee_remove(struct tee_client_device *pas_dev)
|
||||
{
|
||||
struct device *dev = &pas_dev->dev;
|
||||
struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
|
||||
|
||||
qcom_pas_ops_unregister();
|
||||
tee_client_close_session(data->ctx, data->session_id);
|
||||
tee_client_close_context(data->ctx);
|
||||
}
|
||||
|
||||
static const struct tee_client_device_id qcom_pas_tee_id_table[] = {
|
||||
{UUID_INIT(0xcff7d191, 0x7ca0, 0x4784,
|
||||
0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table);
|
||||
|
||||
static struct tee_client_driver optee_pas_tee_driver = {
|
||||
.probe = qcom_pas_tee_probe,
|
||||
.remove = qcom_pas_tee_remove,
|
||||
.id_table = qcom_pas_tee_id_table,
|
||||
.driver = {
|
||||
.name = "qcom-pas-tee",
|
||||
},
|
||||
};
|
||||
|
||||
module_tee_client_driver(optee_pas_tee_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Qualcomm PAS TEE driver");
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/firmware/qcom/qcom_tzmem.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
#include "qcom_pas.h"
|
||||
#include "qcom_scm.h"
|
||||
#include "qcom_tzmem.h"
|
||||
|
||||
|
|
@ -479,25 +481,6 @@ void qcom_scm_cpu_power_down(u32 flags)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
|
||||
|
||||
int qcom_scm_set_remote_state(u32 state, u32 id)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_BOOT,
|
||||
.cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
|
||||
.arginfo = QCOM_SCM_ARGS(2),
|
||||
.args[0] = state,
|
||||
.args[1] = id,
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
struct qcom_scm_res res;
|
||||
int ret;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
|
||||
|
||||
static int qcom_scm_disable_sdi(void)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -570,26 +553,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
|
|||
dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
|
||||
* context for a given peripheral
|
||||
*
|
||||
* PAS context is device-resource managed, so the caller does not need
|
||||
* to worry about freeing the context memory.
|
||||
*
|
||||
* @dev: PAS firmware device
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @mem_phys: Subsystem reserve memory start address
|
||||
* @mem_size: Subsystem reserve memory size
|
||||
*
|
||||
* Returns: The new PAS context, or ERR_PTR() on failure.
|
||||
*/
|
||||
struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
|
||||
u32 pas_id,
|
||||
phys_addr_t mem_phys,
|
||||
size_t mem_size)
|
||||
{
|
||||
struct qcom_scm_pas_context *ctx;
|
||||
struct qcom_pas_context *ctx;
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
|
|
@ -600,11 +569,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
|
|||
ctx->mem_phys = mem_phys;
|
||||
ctx->mem_size = mem_size;
|
||||
|
||||
return ctx;
|
||||
return (struct qcom_scm_pas_context *)ctx;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
|
||||
|
||||
static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
|
||||
static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id,
|
||||
dma_addr_t mdata_phys,
|
||||
struct qcom_scm_res *res)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
@ -626,7 +596,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
|
|||
|
||||
desc.args[1] = mdata_phys;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, res);
|
||||
ret = qcom_scm_call(dev, &desc, res);
|
||||
qcom_scm_bw_disable();
|
||||
|
||||
disable_clk:
|
||||
|
|
@ -635,7 +605,8 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
|
||||
static int qcom_scm_pas_prep_and_init_image(struct device *dev,
|
||||
struct qcom_pas_context *ctx,
|
||||
const void *metadata, size_t size)
|
||||
{
|
||||
struct qcom_scm_res res;
|
||||
|
|
@ -650,7 +621,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
|
|||
memcpy(mdata_buf, metadata, size);
|
||||
mdata_phys = qcom_tzmem_to_phys(mdata_buf);
|
||||
|
||||
ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res);
|
||||
ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res);
|
||||
if (ret < 0)
|
||||
qcom_tzmem_free(mdata_buf);
|
||||
else
|
||||
|
|
@ -659,25 +630,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
|
|||
return ret ? : res.result[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_init_image() - Initialize peripheral authentication service
|
||||
* state machine for a given peripheral, using the
|
||||
* metadata
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @metadata: pointer to memory containing ELF header, program header table
|
||||
* and optional blob of data used for authenticating the metadata
|
||||
* and the rest of the firmware
|
||||
* @size: size of the metadata
|
||||
* @ctx: optional pas context
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*
|
||||
* Upon successful return, the PAS metadata context (@ctx) will be used to
|
||||
* track the metadata allocation, this needs to be released by invoking
|
||||
* qcom_scm_pas_metadata_release() by the caller.
|
||||
*/
|
||||
int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
||||
struct qcom_scm_pas_context *ctx)
|
||||
static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
|
||||
const void *metadata, size_t size,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
struct qcom_scm_res res;
|
||||
dma_addr_t mdata_phys;
|
||||
|
|
@ -685,7 +640,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
|||
int ret;
|
||||
|
||||
if (ctx && ctx->use_tzmem)
|
||||
return qcom_scm_pas_prep_and_init_image(ctx, metadata, size);
|
||||
return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, size);
|
||||
|
||||
/*
|
||||
* During the scm call memory protection will be enabled for the meta
|
||||
|
|
@ -699,16 +654,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
|||
* If we pass a buffer that is already part of an SHM Bridge to this
|
||||
* call, it will fail.
|
||||
*/
|
||||
mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
|
||||
GFP_KERNEL);
|
||||
mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
|
||||
if (!mdata_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(mdata_buf, metadata, size);
|
||||
|
||||
ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res);
|
||||
ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res);
|
||||
if (ret < 0 || !ctx) {
|
||||
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
|
||||
dma_free_coherent(dev, size, mdata_buf, mdata_phys);
|
||||
} else if (ctx) {
|
||||
ctx->ptr = mdata_buf;
|
||||
ctx->phys = mdata_phys;
|
||||
|
|
@ -717,36 +671,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
|||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
|
||||
int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
||||
struct qcom_scm_pas_context *ctx)
|
||||
{
|
||||
return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size,
|
||||
(struct qcom_pas_context *)ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_metadata_release() - release metadata context
|
||||
* @ctx: pas context
|
||||
*/
|
||||
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
|
||||
static void __qcom_scm_pas_metadata_release(struct device *dev,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
if (!ctx->ptr)
|
||||
return;
|
||||
|
||||
if (ctx->use_tzmem)
|
||||
qcom_tzmem_free(ctx->ptr);
|
||||
else
|
||||
dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
|
||||
dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys);
|
||||
|
||||
ctx->ptr = NULL;
|
||||
}
|
||||
|
||||
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
|
||||
{
|
||||
__qcom_scm_pas_metadata_release(__scm->dev,
|
||||
(struct qcom_pas_context *)ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
|
||||
* for firmware loading
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @addr: start address of memory area to prepare
|
||||
* @size: size of the memory area to prepare
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
|
||||
static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id,
|
||||
phys_addr_t addr, phys_addr_t size)
|
||||
{
|
||||
int ret;
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
@ -768,7 +721,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
|
|||
if (ret)
|
||||
goto disable_clk;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
qcom_scm_bw_disable();
|
||||
|
||||
disable_clk:
|
||||
|
|
@ -776,9 +729,15 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
|
|||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
|
||||
int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
|
||||
{
|
||||
return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
|
||||
|
||||
static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
|
||||
static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id,
|
||||
void *input_rt_tzm,
|
||||
size_t input_rt_size,
|
||||
size_t *output_rt_size)
|
||||
{
|
||||
|
|
@ -813,7 +772,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
|
|||
* with output_rt_tzm buffer with res.result[2] size however, It should not
|
||||
* be of unresonable size.
|
||||
*/
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
if (!ret && res.result[2] > SZ_1G) {
|
||||
ret = -E2BIG;
|
||||
goto free_output_rt;
|
||||
|
|
@ -830,51 +789,11 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
|
|||
return ret ? ERR_PTR(ret) : output_rt_tzm;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
|
||||
* for a given peripheral.
|
||||
*
|
||||
* Qualcomm remote processor may rely on both static and dynamic resources for
|
||||
* its functionality. Static resources typically refer to memory-mapped addresses
|
||||
* required by the subsystem and are often embedded within the firmware binary
|
||||
* and dynamic resources, such as shared memory in DDR etc., are determined at
|
||||
* runtime during the boot process.
|
||||
*
|
||||
* On Qualcomm Technologies devices, it's possible that static resources are not
|
||||
* embedded in the firmware binary and instead are provided by TrustZone However,
|
||||
* dynamic resources are always expected to come from TrustZone. This indicates
|
||||
* that for Qualcomm devices, all resources (static and dynamic) will be provided
|
||||
* by TrustZone via the SMC call.
|
||||
*
|
||||
* If the remote processor firmware binary does contain static resources, they
|
||||
* should be passed in input_rt. These will be forwarded to TrustZone for
|
||||
* authentication. TrustZone will then append the dynamic resources and return
|
||||
* the complete resource table in output_rt_tzm.
|
||||
*
|
||||
* If the remote processor firmware binary does not include a resource table,
|
||||
* the caller of this function should set input_rt as NULL and input_rt_size
|
||||
* as zero respectively.
|
||||
*
|
||||
* More about documentation on resource table data structures can be found in
|
||||
* include/linux/remoteproc.h
|
||||
*
|
||||
* @ctx: PAS context
|
||||
* @pas_id: peripheral authentication service id
|
||||
* @input_rt: resource table buffer which is present in firmware binary
|
||||
* @input_rt_size: size of the resource table present in firmware binary
|
||||
* @output_rt_size: TrustZone expects caller should pass worst case size for
|
||||
* the output_rt_tzm.
|
||||
*
|
||||
* Return:
|
||||
* On success, returns a pointer to the allocated buffer containing the final
|
||||
* resource table and output_rt_size will have actual resource table size from
|
||||
* TrustZone. The caller is responsible for freeing the buffer. On failure,
|
||||
* returns ERR_PTR(-errno).
|
||||
*/
|
||||
struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
|
||||
void *input_rt,
|
||||
size_t input_rt_size,
|
||||
size_t *output_rt_size)
|
||||
static void *__qcom_scm_pas_get_rsc_table2(struct device *dev,
|
||||
struct qcom_pas_context *ctx,
|
||||
void *input_rt,
|
||||
size_t input_rt_size,
|
||||
size_t *output_rt_size)
|
||||
{
|
||||
struct resource_table empty_rsc = {};
|
||||
size_t size = SZ_16K;
|
||||
|
|
@ -909,11 +828,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
|
|||
|
||||
memcpy(input_rt_tzm, input_rt, input_rt_size);
|
||||
|
||||
output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm,
|
||||
output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
|
||||
input_rt_tzm,
|
||||
input_rt_size, &size);
|
||||
if (PTR_ERR(output_rt_tzm) == -EOVERFLOW)
|
||||
/* Try again with the size requested by the TZ */
|
||||
output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id,
|
||||
output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
|
||||
input_rt_tzm,
|
||||
input_rt_size,
|
||||
&size);
|
||||
|
|
@ -943,16 +863,20 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
|
|||
|
||||
return ret ? ERR_PTR(ret) : tbl_ptr;
|
||||
}
|
||||
|
||||
struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
|
||||
void *input_rt,
|
||||
size_t input_rt_size,
|
||||
size_t *output_rt_size)
|
||||
{
|
||||
return __qcom_scm_pas_get_rsc_table2(__scm->dev,
|
||||
(struct qcom_pas_context *)ctx,
|
||||
input_rt, input_rt_size,
|
||||
output_rt_size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
|
||||
* and reset the remote processor
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Return 0 on success.
|
||||
*/
|
||||
int qcom_scm_pas_auth_and_reset(u32 pas_id)
|
||||
static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
|
||||
{
|
||||
int ret;
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
@ -972,7 +896,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
|
|||
if (ret)
|
||||
goto disable_clk;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
qcom_scm_bw_disable();
|
||||
|
||||
disable_clk:
|
||||
|
|
@ -980,28 +904,15 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
|
|||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
|
||||
int qcom_scm_pas_auth_and_reset(u32 pas_id)
|
||||
{
|
||||
return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
|
||||
* remote processor
|
||||
*
|
||||
* @ctx: Context saved during call to qcom_scm_pas_context_init()
|
||||
*
|
||||
* This function performs the necessary steps to prepare a PAS subsystem,
|
||||
* authenticate it using the provided metadata, and initiate a reset sequence.
|
||||
*
|
||||
* It should be used when Linux is in control setting up the IOMMU hardware
|
||||
* for remote subsystem during secure firmware loading processes. The preparation
|
||||
* step sets up a shmbridge over the firmware memory before TrustZone accesses the
|
||||
* firmware memory region for authentication. The authentication step verifies
|
||||
* the integrity and authenticity of the firmware or configuration using secure
|
||||
* metadata. Finally, the reset step ensures the subsystem starts in a clean and
|
||||
* sane state.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure.
|
||||
*/
|
||||
int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
|
||||
static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
u64 handle;
|
||||
int ret;
|
||||
|
|
@ -1012,7 +923,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
|
|||
* memory region and then invokes a call to TrustZone to authenticate.
|
||||
*/
|
||||
if (!ctx->use_tzmem)
|
||||
return qcom_scm_pas_auth_and_reset(ctx->pas_id);
|
||||
return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
|
||||
|
||||
/*
|
||||
* When Linux runs @ EL2 Linux must create the shmbridge itself and then
|
||||
|
|
@ -1022,20 +933,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = qcom_scm_pas_auth_and_reset(ctx->pas_id);
|
||||
ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
|
||||
qcom_tzmem_shm_bridge_delete(handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
|
||||
{
|
||||
return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev,
|
||||
(struct qcom_pas_context *)ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_shutdown() - Shut down the remote processor
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int qcom_scm_pas_shutdown(u32 pas_id)
|
||||
static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
|
||||
u32 pas_id)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_BOOT,
|
||||
.cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
|
||||
.arginfo = QCOM_SCM_ARGS(2),
|
||||
.args[0] = state,
|
||||
.args[1] = pas_id,
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
struct qcom_scm_res res;
|
||||
int ret;
|
||||
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
|
||||
int qcom_scm_set_remote_state(u32 state, u32 id)
|
||||
{
|
||||
return __qcom_scm_pas_set_remote_state(__scm->dev, state, id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
|
||||
|
||||
static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id)
|
||||
{
|
||||
int ret;
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
@ -1055,7 +991,7 @@ int qcom_scm_pas_shutdown(u32 pas_id)
|
|||
if (ret)
|
||||
goto disable_clk;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
qcom_scm_bw_disable();
|
||||
|
||||
disable_clk:
|
||||
|
|
@ -1063,16 +999,14 @@ int qcom_scm_pas_shutdown(u32 pas_id)
|
|||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
|
||||
int qcom_scm_pas_shutdown(u32 pas_id)
|
||||
{
|
||||
return __qcom_scm_pas_shutdown(__scm->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_supported() - Check if the peripheral authentication service is
|
||||
* available for the given peripherial
|
||||
* @pas_id: peripheral authentication service id
|
||||
*
|
||||
* Returns true if PAS is supported for this peripheral, otherwise false.
|
||||
*/
|
||||
bool qcom_scm_pas_supported(u32 pas_id)
|
||||
static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id)
|
||||
{
|
||||
int ret;
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
@ -1084,16 +1018,49 @@ bool qcom_scm_pas_supported(u32 pas_id)
|
|||
};
|
||||
struct qcom_scm_res res;
|
||||
|
||||
if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
|
||||
if (!__qcom_scm_is_call_available(dev, QCOM_SCM_SVC_PIL,
|
||||
QCOM_SCM_PIL_PAS_IS_SUPPORTED))
|
||||
return false;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
|
||||
return ret ? false : !!res.result[0];
|
||||
}
|
||||
|
||||
bool qcom_scm_pas_supported(u32 pas_id)
|
||||
{
|
||||
return __qcom_scm_pas_supported(__scm->dev, pas_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
|
||||
|
||||
static struct qcom_pas_ops qcom_pas_ops_scm = {
|
||||
.drv_name = "qcom_scm",
|
||||
.supported = __qcom_scm_pas_supported,
|
||||
.init_image = __qcom_scm_pas_init_image2,
|
||||
.mem_setup = __qcom_scm_pas_mem_setup,
|
||||
.get_rsc_table = __qcom_scm_pas_get_rsc_table2,
|
||||
.auth_and_reset = __qcom_scm_pas_auth_and_reset,
|
||||
.prepare_and_auth_reset = __qcom_scm_pas_prepare_and_auth_reset,
|
||||
.set_remote_state = __qcom_scm_pas_set_remote_state,
|
||||
.shutdown = __qcom_scm_pas_shutdown,
|
||||
.metadata_release = __qcom_scm_pas_metadata_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* qcom_scm_is_pas_available() - Check if the peripheral authentication service
|
||||
* is available via SCM or not
|
||||
*
|
||||
* Returns true if PAS is available, otherwise false.
|
||||
*/
|
||||
static bool qcom_scm_is_pas_available(void)
|
||||
{
|
||||
if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
|
||||
QCOM_SCM_PIL_PAS_AUTH_AND_RESET))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
@ -2837,6 +2804,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||
|
||||
__get_convention();
|
||||
|
||||
if (qcom_scm_is_pas_available()) {
|
||||
qcom_pas_ops_scm.dev = scm->dev;
|
||||
qcom_pas_ops_register(&qcom_pas_ops_scm);
|
||||
}
|
||||
|
||||
/*
|
||||
* If "download mode" is requested, from this point on warmboot
|
||||
* will cause the boot stages to enter download mode, unless
|
||||
|
|
@ -2876,6 +2848,7 @@ static void qcom_scm_shutdown(struct platform_device *pdev)
|
|||
{
|
||||
/* Clean shutdown, disable download mode to allow normal restart */
|
||||
qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
|
||||
qcom_pas_ops_unregister();
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_scm_dt_match[] = {
|
||||
|
|
|
|||
|
|
@ -87,24 +87,24 @@ static int ath10k_ahb_clock_init(struct ath10k *ar)
|
|||
dev = &ar_ahb->pdev->dev;
|
||||
|
||||
ar_ahb->cmd_clk = devm_clk_get(dev, "wifi_wcss_cmd");
|
||||
if (IS_ERR_OR_NULL(ar_ahb->cmd_clk)) {
|
||||
if (IS_ERR(ar_ahb->cmd_clk)) {
|
||||
ath10k_err(ar, "failed to get cmd clk: %ld\n",
|
||||
PTR_ERR(ar_ahb->cmd_clk));
|
||||
return ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV;
|
||||
return PTR_ERR(ar_ahb->cmd_clk);
|
||||
}
|
||||
|
||||
ar_ahb->ref_clk = devm_clk_get(dev, "wifi_wcss_ref");
|
||||
if (IS_ERR_OR_NULL(ar_ahb->ref_clk)) {
|
||||
if (IS_ERR(ar_ahb->ref_clk)) {
|
||||
ath10k_err(ar, "failed to get ref clk: %ld\n",
|
||||
PTR_ERR(ar_ahb->ref_clk));
|
||||
return ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV;
|
||||
return PTR_ERR(ar_ahb->ref_clk);
|
||||
}
|
||||
|
||||
ar_ahb->rtc_clk = devm_clk_get(dev, "wifi_wcss_rtc");
|
||||
if (IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {
|
||||
if (IS_ERR(ar_ahb->rtc_clk)) {
|
||||
ath10k_err(ar, "failed to get rtc clk: %ld\n",
|
||||
PTR_ERR(ar_ahb->rtc_clk));
|
||||
return ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV;
|
||||
return PTR_ERR(ar_ahb->rtc_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -2343,10 +2343,8 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|||
if (ret < 0) {
|
||||
ath10k_warn(ar, "rx ring became corrupted: %d\n", ret);
|
||||
__skb_queue_purge(&amsdu);
|
||||
/* FIXME: It's probably a good idea to reboot the
|
||||
* device instead of leaving it inoperable.
|
||||
*/
|
||||
htt->rx_confused = true;
|
||||
ath10k_core_start_recovery(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3311,6 +3309,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
if (ret < 0) {
|
||||
ath10k_warn(ar, "failed to pop paddr list: %d\n", ret);
|
||||
htt->rx_confused = true;
|
||||
ath10k_core_start_recovery(ar);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -3344,6 +3343,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
ath10k_warn(ar, "failed to extract amsdu: %d\n", ret);
|
||||
htt->rx_confused = true;
|
||||
__skb_queue_purge(&list);
|
||||
ath10k_core_start_recovery(ar);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1049,9 +1049,11 @@ static const struct __ath11k_core_usecase_firmware_table {
|
|||
const char *compatible;
|
||||
const char *firmware_name;
|
||||
} ath11k_core_usecase_firmware_table[] = {
|
||||
{ ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"},
|
||||
{ ATH11K_HW_WCN6855_HW21, "qcom,lemans-evk", "nfa765"},
|
||||
{ ATH11K_HW_WCN6855_HW21, "qcom,monaco-evk", "nfa765"},
|
||||
{ ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"},
|
||||
{ ATH11K_HW_WCN6855_HW21, "qcom,purwa-iot-evk", "nfa765"},
|
||||
{ ATH11K_HW_WCN6855_HW21, "qcom,qcs6490-rb3gen2", "nfa765"},
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2334,10 +2334,10 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
|
|||
case RX_MSDU_START_PKT_TYPE_11N:
|
||||
rx_status->encoding = RX_ENC_HT;
|
||||
if (rate_mcs > ATH11K_HT_MCS_MAX) {
|
||||
ath11k_warn(ar->ab,
|
||||
"Received with invalid mcs in HT mode %d\n",
|
||||
rate_mcs);
|
||||
break;
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_DP_RX,
|
||||
"Received HT frame with out-of-range mcs %d, capping to %d\n",
|
||||
rate_mcs, ATH11K_HT_MCS_MAX);
|
||||
rate_mcs = ATH11K_HT_MCS_MAX;
|
||||
}
|
||||
rx_status->rate_idx = rate_mcs + (8 * (nss - 1));
|
||||
if (sgi)
|
||||
|
|
@ -2346,13 +2346,13 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
|
|||
break;
|
||||
case RX_MSDU_START_PKT_TYPE_11AC:
|
||||
rx_status->encoding = RX_ENC_VHT;
|
||||
rx_status->rate_idx = rate_mcs;
|
||||
if (rate_mcs > ATH11K_VHT_MCS_MAX) {
|
||||
ath11k_warn(ar->ab,
|
||||
"Received with invalid mcs in VHT mode %d\n",
|
||||
rate_mcs);
|
||||
break;
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_DP_RX,
|
||||
"Received VHT frame with out-of-range mcs %d, capping to %d\n",
|
||||
rate_mcs, ATH11K_VHT_MCS_MAX);
|
||||
rate_mcs = ATH11K_VHT_MCS_MAX;
|
||||
}
|
||||
rx_status->rate_idx = rate_mcs;
|
||||
rx_status->nss = nss;
|
||||
if (sgi)
|
||||
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
|
||||
|
|
@ -2362,14 +2362,14 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
|
|||
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
|
||||
break;
|
||||
case RX_MSDU_START_PKT_TYPE_11AX:
|
||||
rx_status->rate_idx = rate_mcs;
|
||||
if (rate_mcs > ATH11K_HE_MCS_MAX) {
|
||||
ath11k_warn(ar->ab,
|
||||
"Received with invalid mcs in HE mode %d\n",
|
||||
rate_mcs);
|
||||
break;
|
||||
}
|
||||
rx_status->encoding = RX_ENC_HE;
|
||||
if (rate_mcs > ATH11K_HE_MCS_MAX) {
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_DP_RX,
|
||||
"Received HE frame with out-of-range mcs %d, capping to %d\n",
|
||||
rate_mcs, ATH11K_HE_MCS_MAX);
|
||||
rate_mcs = ATH11K_HE_MCS_MAX;
|
||||
}
|
||||
rx_status->rate_idx = rate_mcs;
|
||||
rx_status->nss = nss;
|
||||
rx_status->he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi);
|
||||
rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw);
|
||||
|
|
|
|||
|
|
@ -2423,8 +2423,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|
|||
for (i = 0; i < params->num_hint_bssid; ++i) {
|
||||
hint_bssid->freq_flags =
|
||||
params->hint_bssid[i].freq_flags;
|
||||
ether_addr_copy(¶ms->hint_bssid[i].bssid.addr[0],
|
||||
&hint_bssid->bssid.addr[0]);
|
||||
ether_addr_copy(&hint_bssid->bssid.addr[0],
|
||||
¶ms->hint_bssid[i].bssid.addr[0]);
|
||||
hint_bssid++;
|
||||
}
|
||||
}
|
||||
|
|
@ -4858,6 +4858,12 @@ static int ath11k_wmi_tlv_ext_hal_reg_caps(struct ath11k_base *soc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (reg_cap.phy_id >= ARRAY_SIZE(soc->hal_reg_cap)) {
|
||||
ath11k_warn(soc, "invalid reg cap phy_id %u\n",
|
||||
reg_cap.phy_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&soc->hal_reg_cap[reg_cap.phy_id],
|
||||
®_cap, sizeof(reg_cap));
|
||||
}
|
||||
|
|
@ -8895,13 +8901,15 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
|
|||
struct wmi_cmd_hdr *cmd_hdr;
|
||||
enum wmi_tlv_event_id id;
|
||||
|
||||
if (skb->len < sizeof(*cmd_hdr))
|
||||
goto out;
|
||||
|
||||
cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
|
||||
id = FIELD_GET(WMI_CMD_HDR_CMD_ID, (cmd_hdr->cmd_id));
|
||||
|
||||
trace_ath11k_wmi_event(ab, id, skb->data, skb->len);
|
||||
|
||||
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
|
||||
goto out;
|
||||
skb_pull(skb, sizeof(*cmd_hdr));
|
||||
|
||||
switch (id) {
|
||||
/* Process all the WMI events here */
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ config ATH12K_AHB
|
|||
bool "Qualcomm ath12k AHB support"
|
||||
depends on ATH12K && REMOTEPROC
|
||||
select QCOM_MDT_LOADER
|
||||
select QCOM_SCM
|
||||
select QCOM_PAS
|
||||
help
|
||||
Enable support for Ath12k AHB bus chipsets, example IPQ5332.
|
||||
|
||||
|
|
|
|||
|
|
@ -5,19 +5,19 @@
|
|||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/firmware/qcom/qcom_pas.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/soc/qcom/mdt_loader.h>
|
||||
#include <linux/soc/qcom/smem_state.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include "ahb.h"
|
||||
#include "debug.h"
|
||||
#include "hif.h"
|
||||
|
||||
#define ATH12K_IRQ_CE0_OFFSET 4
|
||||
#define ATH12K_MAX_UPDS 1
|
||||
#define ATH12K_UPD_IRQ_WRD_LEN 18
|
||||
|
||||
static struct ath12k_ahb_driver *ath12k_ahb_family_drivers[ATH12K_DEVICE_FAMILY_MAX];
|
||||
|
|
@ -338,24 +338,25 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
|
|||
char fw2_name[ATH12K_USERPD_FW_NAME_LEN];
|
||||
struct device *dev = ab->dev;
|
||||
const struct firmware *fw, *fw2;
|
||||
struct reserved_mem *rmem = NULL;
|
||||
unsigned long time_left;
|
||||
phys_addr_t mem_phys;
|
||||
struct resource res;
|
||||
void *mem_region;
|
||||
size_t mem_size;
|
||||
u32 pasid;
|
||||
int ret;
|
||||
|
||||
rmem = ath12k_core_get_reserved_mem(ab, 0);
|
||||
if (!rmem)
|
||||
return -ENODEV;
|
||||
ret = of_reserved_mem_region_to_resource_byname(dev->of_node, "q6-region",
|
||||
&res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mem_phys = rmem->base;
|
||||
mem_size = rmem->size;
|
||||
mem_phys = res.start;
|
||||
mem_size = resource_size(&res);
|
||||
mem_region = devm_memremap(dev, mem_phys, mem_size, MEMREMAP_WC);
|
||||
if (IS_ERR(mem_region)) {
|
||||
ath12k_err(ab, "unable to map memory region: %pa+%pa\n",
|
||||
&rmem->base, &rmem->size);
|
||||
ath12k_err(ab, "unable to map memory region: %pa+%zx\n",
|
||||
&res.start, mem_size);
|
||||
return PTR_ERR(mem_region);
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +421,7 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
|
|||
|
||||
if (ab_ahb->scm_auth_enabled) {
|
||||
/* Authenticate FW image using peripheral ID */
|
||||
ret = qcom_scm_pas_auth_and_reset(pasid);
|
||||
ret = qcom_pas_auth_and_reset(pasid);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to boot the remote processor %d\n", ret);
|
||||
goto err_fw2;
|
||||
|
|
@ -485,10 +486,10 @@ static void ath12k_ahb_power_down(struct ath12k_base *ab, bool is_suspend)
|
|||
pasid = (u32_encode_bits(ab_ahb->userpd_id, ATH12K_USERPD_ID_MASK)) |
|
||||
ATH12K_AHB_UPD_SWID;
|
||||
/* Release the firmware */
|
||||
ret = qcom_scm_pas_shutdown(pasid);
|
||||
ret = qcom_pas_shutdown(pasid);
|
||||
if (ret)
|
||||
ath12k_err(ab, "scm pas shutdown failed for userPD%d\n",
|
||||
ab_ahb->userpd_id);
|
||||
ath12k_err(ab, "PAS shutdown failed for userPD%d: %d\n",
|
||||
ab_ahb->userpd_id, ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#define ATH12K_USERPD_SPAWN_TIMEOUT (5 * HZ)
|
||||
#define ATH12K_USERPD_READY_TIMEOUT (10 * HZ)
|
||||
#define ATH12K_USERPD_STOP_TIMEOUT (5 * HZ)
|
||||
#define ATH12K_USERPD_ID_MASK GENMASK(9, 8)
|
||||
#define ATH12K_USERPD_ID_MASK GENMASK(10, 8)
|
||||
#define ATH12K_USERPD_FW_NAME_LEN 35
|
||||
|
||||
enum ath12k_ahb_smp2p_msg_id {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = {
|
|||
.dp_params = {
|
||||
.tx_comp_ring_size = 32768,
|
||||
.rxdma_monitor_buf_ring_size = 4096,
|
||||
.rxdma_monitor_dst_ring_size = 8092,
|
||||
.rxdma_monitor_dst_ring_size = 8192,
|
||||
.num_pool_tx_desc = 32768,
|
||||
.rx_desc_count = 12288,
|
||||
},
|
||||
|
|
@ -637,31 +637,6 @@ u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab)
|
|||
}
|
||||
EXPORT_SYMBOL(ath12k_core_get_max_peers_per_radio);
|
||||
|
||||
struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab,
|
||||
int index)
|
||||
{
|
||||
struct device *dev = ab->dev;
|
||||
struct reserved_mem *rmem;
|
||||
struct device_node *node;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", index);
|
||||
if (!node) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT,
|
||||
"failed to parse memory-region for index %d\n", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rmem = of_reserved_mem_lookup(node);
|
||||
of_node_put(node);
|
||||
if (!rmem) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT,
|
||||
"unable to get memory-region for index %d\n", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rmem;
|
||||
}
|
||||
|
||||
static inline
|
||||
void ath12k_core_to_group_ref_get(struct ath12k_base *ab)
|
||||
{
|
||||
|
|
@ -708,8 +683,10 @@ static void ath12k_core_stop(struct ath12k_base *ab)
|
|||
|
||||
ath12k_core_to_group_ref_put(ab);
|
||||
|
||||
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
|
||||
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) {
|
||||
ath12k_dp_reoq_lut_addr_reset(ath12k_ab_to_dp(ab));
|
||||
ath12k_qmi_firmware_stop(ab);
|
||||
}
|
||||
|
||||
ath12k_acpi_stop(ab);
|
||||
|
||||
|
|
@ -1371,6 +1348,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
|
|||
goto exit;
|
||||
|
||||
err_deinit:
|
||||
ath12k_dp_reoq_lut_addr_reset(ath12k_ab_to_dp(ab));
|
||||
ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
|
||||
mutex_unlock(&ab->core_lock);
|
||||
mutex_unlock(&ag->mutex);
|
||||
|
|
@ -1524,7 +1502,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
|
|||
complete_all(&ar->scan.completed);
|
||||
complete(&ar->scan.on_channel);
|
||||
complete(&ar->peer_assoc_done);
|
||||
complete(&ar->peer_delete_done);
|
||||
ath12k_peer_delete_wait_flush(ar);
|
||||
complete(&ar->install_key_done);
|
||||
complete(&ar->vdev_setup_done);
|
||||
complete(&ar->vdev_delete_done);
|
||||
|
|
|
|||
|
|
@ -665,7 +665,8 @@ struct ath12k {
|
|||
|
||||
/* protects the radio specific data like debug stats, ppdu_stats_info stats,
|
||||
* vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info,
|
||||
* channel context data, survey info, test mode data, regd_channel_update_queue.
|
||||
* channel context data, test mode data, regd_channel_update_queue,
|
||||
* peer_delete_waits.
|
||||
*/
|
||||
spinlock_t data_lock;
|
||||
|
||||
|
|
@ -687,7 +688,7 @@ struct ath12k {
|
|||
u8 radio_idx;
|
||||
|
||||
struct completion peer_assoc_done;
|
||||
struct completion peer_delete_done;
|
||||
struct list_head peer_delete_waits;
|
||||
|
||||
int install_key_status;
|
||||
struct completion install_key_done;
|
||||
|
|
@ -721,7 +722,6 @@ struct ath12k {
|
|||
* avoid reporting garbage data.
|
||||
*/
|
||||
bool ch_info_can_report_survey;
|
||||
struct survey_info survey[ATH12K_NUM_CHANS];
|
||||
struct completion bss_survey_done;
|
||||
|
||||
struct work_struct regd_update_work;
|
||||
|
|
@ -791,6 +791,11 @@ struct ath12k_hw {
|
|||
*/
|
||||
struct mutex hw_mutex;
|
||||
enum ath12k_hw_state state;
|
||||
|
||||
/* protects survey[] shared across radios of this hw. */
|
||||
spinlock_t survey_lock;
|
||||
struct survey_info survey[ATH12K_NUM_CHANS];
|
||||
|
||||
bool regd_updated;
|
||||
bool use_6ghz_regd;
|
||||
|
||||
|
|
@ -1294,8 +1299,6 @@ void ath12k_fw_stats_init(struct ath12k *ar);
|
|||
void ath12k_fw_stats_bcn_free(struct list_head *head);
|
||||
void ath12k_fw_stats_free(struct ath12k_fw_stats *stats);
|
||||
void ath12k_fw_stats_reset(struct ath12k *ar);
|
||||
struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab,
|
||||
int index);
|
||||
enum ath12k_qmi_mem_mode ath12k_core_get_memory_mode(struct ath12k_base *ab);
|
||||
|
||||
static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state)
|
||||
|
|
|
|||
|
|
@ -1031,6 +1031,7 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
|
|||
struct ath12k_device_dp_stats *device_stats = &dp->device_stats;
|
||||
int len = 0, i, j, ret;
|
||||
struct ath12k *ar;
|
||||
u32 center_freq;
|
||||
const int size = 4096;
|
||||
static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
|
||||
[HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR] = "Overflow",
|
||||
|
|
@ -1082,6 +1083,9 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"DEVICE DP STATS (timestamp: %lldms):\n\n",
|
||||
ktime_to_ms(ktime_get()));
|
||||
len += scnprintf(buf + len, size - len, "DEVICE RX STATS:\n\n");
|
||||
len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
|
||||
device_stats->err_ring_pkts);
|
||||
|
|
@ -1161,6 +1165,12 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
|
|||
for (i = 0; i < ab->num_radios; i++) {
|
||||
ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i));
|
||||
if (ar) {
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
center_freq = ar->rx_channel ? ar->rx_channel->center_freq : 0;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\nradio%d center_freq: %u\n",
|
||||
i, center_freq);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\nradio%d tx_pending: %u\n", i,
|
||||
atomic_read(&ar->dp.num_tx_pending));
|
||||
|
|
@ -1173,7 +1183,7 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
|
|||
for (i = 0; i < DP_REO_DST_RING_MAX; i++) {
|
||||
len += scnprintf(buf + len, size - len, "Ring%d:", i + 1);
|
||||
|
||||
for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
|
||||
for (j = 0; j < ab->ag->num_devices; j++) {
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\t%d:%u", j,
|
||||
device_stats->reo_rx[i][j]);
|
||||
|
|
@ -1190,7 +1200,7 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
|
|||
for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++) {
|
||||
len += scnprintf(buf + len, size - len, "%s:", wbm_rel_src[i]);
|
||||
|
||||
for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
|
||||
for (j = 0; j < ab->ag->num_devices; j++) {
|
||||
len += scnprintf(buf + len,
|
||||
size - len,
|
||||
"\t%d:%u", j,
|
||||
|
|
|
|||
|
|
@ -1097,7 +1097,6 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
|
|||
return;
|
||||
|
||||
if (dp->reoq_lut.vaddr_unaligned) {
|
||||
ath12k_hal_write_reoq_lut_addr(ab, 0);
|
||||
dma_free_coherent(ab->dev, dp->reoq_lut.size,
|
||||
dp->reoq_lut.vaddr_unaligned,
|
||||
dp->reoq_lut.paddr_unaligned);
|
||||
|
|
@ -1105,7 +1104,6 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (dp->ml_reoq_lut.vaddr_unaligned) {
|
||||
ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
|
||||
dma_free_coherent(ab->dev, dp->ml_reoq_lut.size,
|
||||
dp->ml_reoq_lut.vaddr_unaligned,
|
||||
dp->ml_reoq_lut.paddr_unaligned);
|
||||
|
|
@ -1568,6 +1566,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab)
|
|||
ath12k_dp_rx_free(ab);
|
||||
|
||||
fail_cmn_reoq_cleanup:
|
||||
ath12k_dp_reoq_lut_addr_reset(dp);
|
||||
ath12k_dp_reoq_lut_cleanup(ab);
|
||||
|
||||
fail_cmn_srng_cleanup:
|
||||
|
|
@ -1627,3 +1626,14 @@ void ath12k_dp_cmn_hw_group_assign(struct ath12k_dp *dp,
|
|||
dp->device_id = ab->device_id;
|
||||
dp_hw_grp->dp[dp->device_id] = dp;
|
||||
}
|
||||
|
||||
void ath12k_dp_reoq_lut_addr_reset(struct ath12k_dp *dp)
|
||||
{
|
||||
struct ath12k_base *ab = dp->ab;
|
||||
|
||||
if (dp->reoq_lut.vaddr_unaligned)
|
||||
ath12k_hal_write_reoq_lut_addr(ab, 0);
|
||||
|
||||
if (dp->ml_reoq_lut.vaddr_unaligned)
|
||||
ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ struct ath12k_pdev_dp {
|
|||
#define DP_REO_CMD_RING_SIZE 256
|
||||
#define DP_REO_STATUS_RING_SIZE 2048
|
||||
#define DP_RXDMA_BUF_RING_SIZE 4096
|
||||
#define DP_RX_MAC_BUF_RING_SIZE 2048
|
||||
#define DP_RX_MAC_BUF_RING_SIZE 4096
|
||||
#define DP_RXDMA_REFILL_RING_SIZE 2048
|
||||
#define DP_RXDMA_ERR_DST_RING_SIZE 1024
|
||||
#define DP_RXDMA_MON_STATUS_RING_SIZE 1024
|
||||
|
|
@ -538,7 +538,7 @@ struct ath12k_dp {
|
|||
/* Lock for protection of peers and rhead_peer_addr */
|
||||
spinlock_t dp_lock;
|
||||
|
||||
struct ath12k_dp_arch_ops *ops;
|
||||
const struct ath12k_dp_arch_ops *ops;
|
||||
|
||||
/* Linked list of struct ath12k_dp_link_peer */
|
||||
struct list_head peers;
|
||||
|
|
@ -701,4 +701,5 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_dp *dp,
|
|||
u32 cookie);
|
||||
struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_dp *dp,
|
||||
u32 desc_id);
|
||||
void ath12k_dp_reoq_lut_addr_reset(struct ath12k_dp *dp);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -493,12 +493,8 @@ EXPORT_SYMBOL(ath12k_dp_mon_update_radiotap);
|
|||
void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
|
||||
struct napi_struct *napi,
|
||||
struct sk_buff *msdu,
|
||||
const struct hal_rx_mon_ppdu_info *ppduinfo,
|
||||
struct ieee80211_rx_status *status,
|
||||
u8 decap)
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
struct ath12k_dp *dp = dp_pdev->dp;
|
||||
struct ath12k_base *ab = dp->ab;
|
||||
static const struct ieee80211_radiotap_he known = {
|
||||
.data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
|
||||
IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN),
|
||||
|
|
@ -506,14 +502,6 @@ void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
|
|||
};
|
||||
struct ieee80211_rx_status *rx_status;
|
||||
struct ieee80211_radiotap_he *he = NULL;
|
||||
struct ieee80211_sta *pubsta = NULL;
|
||||
struct ath12k_dp_link_peer *peer;
|
||||
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
|
||||
struct hal_rx_desc_data rx_info;
|
||||
bool is_mcbc = rxcb->is_mcbc;
|
||||
bool is_eapol_tkip = rxcb->is_eapol;
|
||||
struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data;
|
||||
u8 addr[ETH_ALEN] = {};
|
||||
|
||||
status->link_valid = 0;
|
||||
|
||||
|
|
@ -524,64 +512,10 @@ void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
|
|||
status->flag |= RX_FLAG_RADIOTAP_HE;
|
||||
}
|
||||
|
||||
ath12k_dp_extract_rx_desc_data(dp->hal, &rx_info, rx_desc, rx_desc);
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_bh(&dp->dp_lock);
|
||||
peer = ath12k_dp_rx_h_find_link_peer(dp_pdev, msdu, &rx_info);
|
||||
if (peer && peer->sta) {
|
||||
pubsta = peer->sta;
|
||||
memcpy(addr, peer->addr, ETH_ALEN);
|
||||
if (pubsta->valid_links) {
|
||||
status->link_valid = 1;
|
||||
status->link_id = peer->link_id;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dp->dp_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_DATA,
|
||||
"rx skb %p len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
msdu,
|
||||
msdu->len,
|
||||
addr,
|
||||
rxcb->tid,
|
||||
(is_mcbc) ? "mcast" : "ucast",
|
||||
(status->encoding == RX_ENC_LEGACY) ? "legacy" : "",
|
||||
(status->encoding == RX_ENC_HT) ? "ht" : "",
|
||||
(status->encoding == RX_ENC_VHT) ? "vht" : "",
|
||||
(status->encoding == RX_ENC_HE) ? "he" : "",
|
||||
(status->bw == RATE_INFO_BW_40) ? "40" : "",
|
||||
(status->bw == RATE_INFO_BW_80) ? "80" : "",
|
||||
(status->bw == RATE_INFO_BW_160) ? "160" : "",
|
||||
(status->bw == RATE_INFO_BW_320) ? "320" : "",
|
||||
status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "",
|
||||
status->rate_idx,
|
||||
status->nss,
|
||||
status->freq,
|
||||
status->band, status->flag,
|
||||
!!(status->flag & RX_FLAG_FAILED_FCS_CRC),
|
||||
!!(status->flag & RX_FLAG_MMIC_ERROR),
|
||||
!!(status->flag & RX_FLAG_AMSDU_MORE));
|
||||
|
||||
ath12k_dbg_dump(ab, ATH12K_DBG_DP_RX, NULL, "dp rx msdu: ",
|
||||
msdu->data, msdu->len);
|
||||
rx_status = IEEE80211_SKB_RXCB(msdu);
|
||||
*rx_status = *status;
|
||||
|
||||
/* TODO: trace rx packet */
|
||||
|
||||
/* PN for multicast packets are not validate in HW,
|
||||
* so skip 802.3 rx path
|
||||
* Also, fast_rx expects the STA to be authorized, hence
|
||||
* eapol packets are sent in slow path.
|
||||
*/
|
||||
if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol_tkip &&
|
||||
!(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED))
|
||||
rx_status->flag |= RX_FLAG_8023;
|
||||
|
||||
ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), pubsta, msdu, napi);
|
||||
ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), NULL, msdu, napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_dp_mon_rx_deliver_msdu);
|
||||
|
||||
|
|
|
|||
|
|
@ -112,9 +112,7 @@ void ath12k_dp_mon_update_radiotap(struct ath12k_pdev_dp *dp_pdev,
|
|||
void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
|
||||
struct napi_struct *napi,
|
||||
struct sk_buff *msdu,
|
||||
const struct hal_rx_mon_ppdu_info *ppduinfo,
|
||||
struct ieee80211_rx_status *status,
|
||||
u8 decap);
|
||||
struct ieee80211_rx_status *status);
|
||||
struct sk_buff *
|
||||
ath12k_dp_mon_rx_merg_msdus(struct ath12k_pdev_dp *dp_pdev,
|
||||
struct dp_mon_mpdu *mon_mpdu,
|
||||
|
|
|
|||
|
|
@ -828,8 +828,8 @@ void *ath12k_hal_encode_tlv64_hdr(void *tlv, u64 tag, u64 len)
|
|||
{
|
||||
struct hal_tlv_64_hdr *tlv64 = tlv;
|
||||
|
||||
tlv64->tl = le64_encode_bits(tag, HAL_TLV_HDR_TAG) |
|
||||
le64_encode_bits(len, HAL_TLV_HDR_LEN);
|
||||
tlv64->tl = le64_encode_bits(tag, HAL_TLV_64_HDR_TAG) |
|
||||
le64_encode_bits(len, HAL_TLV_64_HDR_LEN);
|
||||
|
||||
return tlv64->value;
|
||||
}
|
||||
|
|
@ -846,26 +846,44 @@ void *ath12k_hal_encode_tlv32_hdr(void *tlv, u64 tag, u64 len)
|
|||
}
|
||||
EXPORT_SYMBOL(ath12k_hal_encode_tlv32_hdr);
|
||||
|
||||
u16 ath12k_hal_decode_tlv64_hdr(void *tlv, void **desc)
|
||||
void *ath12k_hal_decode_tlv64_hdr(void *tlv, u16 *tag, u16 *len, u16 *usrid)
|
||||
{
|
||||
struct hal_tlv_64_hdr *tlv64 = tlv;
|
||||
u16 tag;
|
||||
|
||||
tag = le64_get_bits(tlv64->tl, HAL_SRNG_TLV_HDR_TAG);
|
||||
*desc = tlv64->value;
|
||||
if (tag)
|
||||
*tag = le64_get_bits(tlv64->tl, HAL_TLV_64_HDR_TAG);
|
||||
if (len)
|
||||
*len = le64_get_bits(tlv64->tl, HAL_TLV_64_HDR_LEN);
|
||||
if (usrid)
|
||||
*usrid = le64_get_bits(tlv64->tl, HAL_TLV_64_USR_ID);
|
||||
|
||||
return tag;
|
||||
return tlv64->value;
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_hal_decode_tlv64_hdr);
|
||||
|
||||
u16 ath12k_hal_decode_tlv32_hdr(void *tlv, void **desc)
|
||||
void *ath12k_hal_decode_tlv32_hdr(void *tlv, u16 *tag, u16 *len, u16 *usrid)
|
||||
{
|
||||
struct hal_tlv_hdr *tlv32 = tlv;
|
||||
u16 tag;
|
||||
|
||||
tag = le32_get_bits(tlv32->tl, HAL_SRNG_TLV_HDR_TAG);
|
||||
*desc = tlv32->value;
|
||||
if (tag)
|
||||
*tag = le32_get_bits(tlv32->tl, HAL_TLV_HDR_TAG);
|
||||
if (len)
|
||||
*len = le32_get_bits(tlv32->tl, HAL_TLV_HDR_LEN);
|
||||
if (usrid)
|
||||
*usrid = le32_get_bits(tlv32->tl, HAL_TLV_USR_ID);
|
||||
|
||||
return tag;
|
||||
return tlv32->value;
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_hal_decode_tlv32_hdr);
|
||||
|
||||
u32 ath12k_hal_get_tlv64_hdr_align(void)
|
||||
{
|
||||
return HAL_TLV_64_ALIGN;
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_hal_get_tlv64_hdr_align);
|
||||
|
||||
u32 ath12k_hal_get_tlv32_hdr_align(void)
|
||||
{
|
||||
return HAL_TLV_ALIGN;
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_hal_get_tlv32_hdr_align);
|
||||
|
|
|
|||
|
|
@ -1024,7 +1024,7 @@ enum hal_wbm_rel_desc_type {
|
|||
|
||||
/* Interrupt mitigation - timer threshold in us */
|
||||
#define HAL_SRNG_INT_TIMER_THRESHOLD_TX 1000
|
||||
#define HAL_SRNG_INT_TIMER_THRESHOLD_RX 500
|
||||
#define HAL_SRNG_INT_TIMER_THRESHOLD_RX 200
|
||||
#define HAL_SRNG_INT_TIMER_THRESHOLD_OTHER 256
|
||||
|
||||
enum hal_srng_mac_type {
|
||||
|
|
@ -1441,10 +1441,12 @@ struct hal_ops {
|
|||
u8 *rbm, u32 *msdu_cnt);
|
||||
void *(*reo_cmd_enc_tlv_hdr)(void *tlv, u64 tag, u64 len);
|
||||
u16 (*reo_status_dec_tlv_hdr)(void *tlv, void **desc);
|
||||
void *(*mon_rx_status_dec_tlv_hdr)(void *tlv, u16 *tag, u16 *len, u16 *usrid);
|
||||
u32 (*get_tlv_hdr_align)(void);
|
||||
};
|
||||
|
||||
#define HAL_TLV_HDR_TAG GENMASK(9, 1)
|
||||
#define HAL_TLV_HDR_LEN GENMASK(25, 10)
|
||||
#define HAL_TLV_HDR_LEN GENMASK(21, 10)
|
||||
#define HAL_TLV_USR_ID GENMASK(31, 26)
|
||||
|
||||
#define HAL_TLV_ALIGN 4
|
||||
|
|
@ -1464,9 +1466,6 @@ struct hal_tlv_64_hdr {
|
|||
u8 value[];
|
||||
} __packed;
|
||||
|
||||
#define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1)
|
||||
#define HAL_SRNG_TLV_HDR_LEN GENMASK(25, 10)
|
||||
|
||||
dma_addr_t ath12k_hal_srng_get_tp_addr(struct ath12k_base *ab,
|
||||
struct hal_srng *srng);
|
||||
dma_addr_t ath12k_hal_srng_get_hp_addr(struct ath12k_base *ab,
|
||||
|
|
@ -1556,6 +1555,8 @@ void ath12k_hal_rx_reo_ent_buf_paddr_get(struct ath12k_hal *hal, void *rx_desc,
|
|||
u8 *rbm, u32 *msdu_cnt);
|
||||
void *ath12k_hal_encode_tlv64_hdr(void *tlv, u64 tag, u64 len);
|
||||
void *ath12k_hal_encode_tlv32_hdr(void *tlv, u64 tag, u64 len);
|
||||
u16 ath12k_hal_decode_tlv64_hdr(void *tlv, void **desc);
|
||||
u16 ath12k_hal_decode_tlv32_hdr(void *tlv, void **desc);
|
||||
void *ath12k_hal_decode_tlv64_hdr(void *tlv, u16 *tag, u16 *len, u16 *usrid);
|
||||
void *ath12k_hal_decode_tlv32_hdr(void *tlv, u16 *tag, u16 *len, u16 *usrid);
|
||||
u32 ath12k_hal_get_tlv64_hdr_align(void);
|
||||
u32 ath12k_hal_get_tlv32_hdr_align(void);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ struct ath12k_hw_params {
|
|||
bool supports_shadow_regs:1;
|
||||
bool supports_aspm:1;
|
||||
bool current_cc_support:1;
|
||||
bool supports_cong_ctrl_max_msdus:1;
|
||||
|
||||
u32 num_tcl_banks;
|
||||
u32 max_tx_ring;
|
||||
|
|
|
|||
|
|
@ -3985,6 +3985,17 @@ static void ath12k_bss_assoc(struct ath12k *ar,
|
|||
ath12k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
|
||||
if (ar->ab->hw_params->supports_sta_ps &&
|
||||
ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
|
||||
ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
|
||||
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_DTIM_POLICY,
|
||||
WMI_DTIM_POLICY_STICK);
|
||||
if (ret)
|
||||
ath12k_warn(ar->ab, "failed to set vdev %d stick DTIM policy: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
}
|
||||
|
||||
if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map) &&
|
||||
ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
|
||||
ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
|
||||
|
|
@ -9722,6 +9733,19 @@ static int ath12k_mac_start(struct ath12k *ar)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (ab->hw_params->supports_cong_ctrl_max_msdus) {
|
||||
ret = ath12k_wmi_pdev_set_param(ar,
|
||||
WMI_PDEV_PARAM_SET_CONG_CTRL_MAX_MSDUS,
|
||||
ATH12K_NUM_POOL_TX_DESC(ab),
|
||||
pdev->pdev_id);
|
||||
if (ret) {
|
||||
ath12k_err(ab,
|
||||
"failed to set congestion control MAX MSDUS: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
__ath12k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
|
||||
|
||||
/* TODO: Do we need to enable ANI? */
|
||||
|
|
@ -10117,16 +10141,16 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
|
|||
if (vif->type != NL80211_IFTYPE_STATION &&
|
||||
vif->type != NL80211_IFTYPE_AP)
|
||||
vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED |
|
||||
IEEE80211_OFFLOAD_DECAP_ENABLED);
|
||||
IEEE80211_OFFLOAD_DECAP_ENABLED |
|
||||
IEEE80211_OFFLOAD_ENCAP_MCAST |
|
||||
IEEE80211_OFFLOAD_ENCAP_4ADDR);
|
||||
|
||||
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
|
||||
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
|
||||
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
|
||||
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
|
||||
} else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
|
||||
else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
|
||||
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_RAW;
|
||||
} else {
|
||||
else
|
||||
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
|
||||
}
|
||||
|
||||
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
|
||||
param_id, ahvif->dp_vif.tx_encap_type);
|
||||
|
|
@ -10136,6 +10160,10 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
|
|||
vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
|
||||
}
|
||||
|
||||
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
|
||||
vif->offload_flags |= (IEEE80211_OFFLOAD_ENCAP_MCAST |
|
||||
IEEE80211_OFFLOAD_ENCAP_4ADDR);
|
||||
|
||||
param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE;
|
||||
if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED)
|
||||
param_value = ATH12K_HW_TXRX_ETHERNET;
|
||||
|
|
@ -10564,22 +10592,8 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
|
|||
|
||||
err_peer_del:
|
||||
if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
reinit_completion(&ar->peer_delete_done);
|
||||
|
||||
ret = ath12k_wmi_send_peer_delete_cmd(ar, arvif->bssid,
|
||||
arvif->vdev_id);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
|
||||
arvif->vdev_id, arvif->bssid);
|
||||
goto err_dp_peer_del;
|
||||
}
|
||||
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id,
|
||||
arvif->bssid);
|
||||
if (ret)
|
||||
goto err_dp_peer_del;
|
||||
|
||||
ar->num_peers--;
|
||||
/* ignore return value: propagate the original error */
|
||||
ath12k_peer_delete(ar, arvif->vdev_id, arvif->bssid);
|
||||
}
|
||||
|
||||
err_dp_peer_del:
|
||||
|
|
@ -11253,6 +11267,8 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
|
|||
|
||||
ml_arg->assoc_link = arvif->is_sta_assoc_link;
|
||||
|
||||
ml_arg->ieee_link_id = arvif->link_id;
|
||||
|
||||
partner_info = ml_arg->partner_info;
|
||||
|
||||
links = ahvif->links_map;
|
||||
|
|
@ -11276,6 +11292,7 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
|
|||
|
||||
partner_info->vdev_id = arvif_p->vdev_id;
|
||||
partner_info->hw_link_id = arvif_p->ar->pdev->hw_link_id;
|
||||
partner_info->ieee_link_id = arvif_p->link_id;
|
||||
ether_addr_copy(partner_info->addr, link_conf->addr);
|
||||
ml_arg->num_partner_links++;
|
||||
partner_info++;
|
||||
|
|
@ -13581,52 +13598,54 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar,
|
|||
int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
struct ath12k_hw *ah = hw->priv;
|
||||
struct ath12k *ar;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct survey_info *ar_survey;
|
||||
struct survey_info *ah_survey;
|
||||
int sband_idx = idx;
|
||||
|
||||
lockdep_assert_wiphy(hw->wiphy);
|
||||
|
||||
if (idx >= ATH12K_NUM_CHANS)
|
||||
if (sband_idx >= ATH12K_NUM_CHANS)
|
||||
return -ENOENT;
|
||||
|
||||
sband = hw->wiphy->bands[NL80211_BAND_2GHZ];
|
||||
if (sband && idx >= sband->n_channels) {
|
||||
idx -= sband->n_channels;
|
||||
if (sband && sband_idx >= sband->n_channels) {
|
||||
sband_idx -= sband->n_channels;
|
||||
sband = NULL;
|
||||
}
|
||||
|
||||
if (!sband)
|
||||
sband = hw->wiphy->bands[NL80211_BAND_5GHZ];
|
||||
if (sband && idx >= sband->n_channels) {
|
||||
idx -= sband->n_channels;
|
||||
if (sband && sband_idx >= sband->n_channels) {
|
||||
sband_idx -= sband->n_channels;
|
||||
sband = NULL;
|
||||
}
|
||||
|
||||
if (!sband)
|
||||
sband = hw->wiphy->bands[NL80211_BAND_6GHZ];
|
||||
|
||||
if (!sband || idx >= sband->n_channels)
|
||||
if (!sband || sband_idx >= sband->n_channels)
|
||||
return -ENOENT;
|
||||
|
||||
ar = ath12k_mac_get_ar_by_chan(hw, &sband->channels[idx]);
|
||||
ar = ath12k_mac_get_ar_by_chan(hw, &sband->channels[sband_idx]);
|
||||
if (!ar) {
|
||||
if (sband->channels[idx].flags & IEEE80211_CHAN_DISABLED) {
|
||||
if (sband->channels[sband_idx].flags & IEEE80211_CHAN_DISABLED) {
|
||||
memset(survey, 0, sizeof(*survey));
|
||||
return 0;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ar_survey = &ar->survey[idx];
|
||||
ah_survey = &ah->survey[idx];
|
||||
|
||||
ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]);
|
||||
ath12k_mac_update_bss_chan_survey(ar, &sband->channels[sband_idx]);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
memcpy(survey, ar_survey, sizeof(*survey));
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
scoped_guard(spinlock_bh, &ah->survey_lock) {
|
||||
memcpy(survey, ah_survey, sizeof(*survey));
|
||||
}
|
||||
|
||||
survey->channel = &sband->channels[idx];
|
||||
survey->channel = &sband->channels[sband_idx];
|
||||
|
||||
if (ar->rx_channel == survey->channel)
|
||||
survey->filled |= SURVEY_INFO_IN_USE;
|
||||
|
|
@ -15048,11 +15067,11 @@ static void ath12k_mac_setup(struct ath12k *ar)
|
|||
spin_lock_init(&ar->dp.ppdu_list_lock);
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
INIT_LIST_HEAD(&ar->dp.ppdu_stats_info);
|
||||
INIT_LIST_HEAD(&ar->peer_delete_waits);
|
||||
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
init_completion(&ar->vdev_delete_done);
|
||||
init_completion(&ar->peer_assoc_done);
|
||||
init_completion(&ar->peer_delete_done);
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->bss_survey_done);
|
||||
init_completion(&ar->scan.started);
|
||||
|
|
@ -15301,6 +15320,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
|
|||
|
||||
mutex_init(&ah->hw_mutex);
|
||||
|
||||
spin_lock_init(&ah->survey_lock);
|
||||
spin_lock_init(&ah->dp_hw.peer_lock);
|
||||
INIT_LIST_HEAD(&ah->dp_hw.dp_peers_list);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/time.h>
|
||||
|
|
@ -537,6 +538,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
|
|||
int i, j, n, ret, num_vectors = 0;
|
||||
u32 user_base_data = 0, base_vector = 0, base_idx;
|
||||
struct ath12k_ext_irq_grp *irq_grp;
|
||||
bool threaded_napi = false;
|
||||
int irq;
|
||||
|
||||
base_idx = ATH12K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
|
||||
ret = ath12k_pci_get_user_msi_assignment(ab, "DP",
|
||||
|
|
@ -546,6 +549,10 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
irq = ath12k_pci_get_msi_irq(ab->dev, base_vector);
|
||||
if (irq >= 0)
|
||||
threaded_napi = !irq_can_set_affinity(irq);
|
||||
|
||||
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
||||
irq_grp = &ab->ext_irq_grp[i];
|
||||
u32 num_irq = 0;
|
||||
|
|
@ -560,6 +567,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
|
|||
|
||||
netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,
|
||||
ath12k_pci_ext_grp_napi_poll);
|
||||
if (threaded_napi)
|
||||
netif_threaded_enable(irq_grp->napi_ndev);
|
||||
|
||||
if (ab->hw_params->ring_mask->tx[i] ||
|
||||
ab->hw_params->ring_mask->rx[i] ||
|
||||
|
|
@ -578,7 +587,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
|
|||
for (j = 0; j < irq_grp->num_irq; j++) {
|
||||
int irq_idx = irq_grp->irqs[j];
|
||||
int vector = (i % num_vectors) + base_vector;
|
||||
int irq = ath12k_pci_get_msi_irq(ab->dev, vector);
|
||||
|
||||
irq = ath12k_pci_get_msi_irq(ab->dev, vector);
|
||||
|
||||
ab->irq_num[irq_idx] = irq;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,55 @@
|
|||
#include "debug.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
static void ath12k_peer_delete_wait_register(struct ath12k *ar,
|
||||
struct ath12k_peer_delete_wait *wait,
|
||||
u32 vdev_id, const u8 *addr)
|
||||
{
|
||||
wait->vdev_id = vdev_id;
|
||||
ether_addr_copy(wait->addr, addr);
|
||||
init_completion(&wait->done);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
list_add(&wait->list, &ar->peer_delete_waits);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static void ath12k_peer_delete_wait_unregister(struct ath12k *ar,
|
||||
struct ath12k_peer_delete_wait *wait)
|
||||
{
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
list_del(&wait->list);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void ath12k_peer_delete_resp_signal(struct ath12k *ar, u32 vdev_id, const u8 *addr)
|
||||
{
|
||||
struct ath12k_peer_delete_wait *wait;
|
||||
|
||||
guard(spinlock_bh)(&ar->data_lock);
|
||||
|
||||
list_for_each_entry(wait, &ar->peer_delete_waits, list) {
|
||||
if (wait->vdev_id == vdev_id &&
|
||||
ether_addr_equal(wait->addr, addr)) {
|
||||
complete(&wait->done);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ath12k_warn(ar->ab, "failed to find link peer with vdev id %u addr %pM\n",
|
||||
vdev_id, addr);
|
||||
}
|
||||
|
||||
void ath12k_peer_delete_wait_flush(struct ath12k *ar)
|
||||
{
|
||||
struct ath12k_peer_delete_wait *wait;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
list_for_each_entry(wait, &ar->peer_delete_waits, list)
|
||||
complete(&wait->done);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static int ath12k_wait_for_dp_link_peer_common(struct ath12k_base *ab, int vdev_id,
|
||||
const u8 *addr, bool expect_mapped)
|
||||
{
|
||||
|
|
@ -62,20 +111,19 @@ static int ath12k_wait_for_peer_deleted(struct ath12k *ar, int vdev_id, const u8
|
|||
return ath12k_wait_for_dp_link_peer_common(ar->ab, vdev_id, addr, false);
|
||||
}
|
||||
|
||||
int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,
|
||||
const u8 *addr)
|
||||
int ath12k_wait_for_peer_delete_done(struct ath12k *ar,
|
||||
struct ath12k_peer_delete_wait *wait)
|
||||
{
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
ret = ath12k_wait_for_peer_deleted(ar, vdev_id, addr);
|
||||
ret = ath12k_wait_for_peer_deleted(ar, wait->vdev_id, wait->addr);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab, "failed wait for peer deleted");
|
||||
ath12k_warn(ar->ab, "failed wait for peer deleted\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->peer_delete_done,
|
||||
3 * HZ);
|
||||
time_left = wait_for_completion_timeout(&wait->done, 3 * HZ);
|
||||
if (time_left == 0) {
|
||||
ath12k_warn(ar->ab, "Timeout in receiving peer delete response\n");
|
||||
return -ETIMEDOUT;
|
||||
|
|
@ -91,8 +139,6 @@ static int ath12k_peer_delete_send(struct ath12k *ar, u32 vdev_id, const u8 *add
|
|||
|
||||
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
|
||||
|
||||
reinit_completion(&ar->peer_delete_done);
|
||||
|
||||
ret = ath12k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
|
|
@ -106,6 +152,7 @@ static int ath12k_peer_delete_send(struct ath12k *ar, u32 vdev_id, const u8 *add
|
|||
|
||||
int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr)
|
||||
{
|
||||
struct ath12k_peer_delete_wait wait;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
|
||||
|
|
@ -114,17 +161,25 @@ int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr)
|
|||
&(ath12k_ar_to_ah(ar)->dp_hw), vdev_id,
|
||||
addr, ar->hw_link_id);
|
||||
|
||||
/*
|
||||
* Register the stack waiter before sending so the resp_event for
|
||||
* this peer cannot arrive while no waiter is queued.
|
||||
*/
|
||||
ath12k_peer_delete_wait_register(ar, &wait, vdev_id, addr);
|
||||
|
||||
ret = ath12k_peer_delete_send(ar, vdev_id, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, vdev_id, addr);
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, &wait);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ar->num_peers--;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
ath12k_peer_delete_wait_unregister(ar, &wait);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8 *addr)
|
||||
|
|
@ -184,22 +239,26 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
|||
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arg->vdev_id,
|
||||
arg->peer_addr);
|
||||
if (!peer) {
|
||||
struct ath12k_peer_delete_wait wait;
|
||||
|
||||
spin_unlock_bh(&dp->dp_lock);
|
||||
ath12k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
|
||||
arg->peer_addr, arg->vdev_id);
|
||||
|
||||
reinit_completion(&ar->peer_delete_done);
|
||||
ath12k_peer_delete_wait_register(ar, &wait, arg->vdev_id,
|
||||
arg->peer_addr);
|
||||
|
||||
ret = ath12k_wmi_send_peer_delete_cmd(ar, arg->peer_addr,
|
||||
arg->vdev_id);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
|
||||
arg->vdev_id, arg->peer_addr);
|
||||
ath12k_peer_delete_wait_unregister(ar, &wait);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, arg->vdev_id,
|
||||
arg->peer_addr);
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, &wait);
|
||||
ath12k_peer_delete_wait_unregister(ar, &wait);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -283,13 +342,14 @@ u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
|
|||
|
||||
int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta)
|
||||
{
|
||||
DECLARE_BITMAP(registered, IEEE80211_MLD_MAX_NUM_LINKS);
|
||||
struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta);
|
||||
struct ath12k_hw *ah = ahvif->ah;
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ath12k_link_sta *arsta;
|
||||
int ret, err_ret = 0;
|
||||
unsigned long links;
|
||||
struct ath12k *ar;
|
||||
int ret, err_ret = 0;
|
||||
u8 link_id;
|
||||
|
||||
lockdep_assert_wiphy(ah->hw->wiphy);
|
||||
|
|
@ -297,8 +357,19 @@ int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_st
|
|||
if (!sta->mlo)
|
||||
return -EINVAL;
|
||||
|
||||
/* FW expects delete of all link peers at once before waiting for reception
|
||||
* of peer unmap or delete responses
|
||||
struct ath12k_peer_delete_wait *waits __free(kfree) =
|
||||
kzalloc_objs(*waits, IEEE80211_MLD_MAX_NUM_LINKS);
|
||||
if (!waits)
|
||||
return -ENOMEM;
|
||||
|
||||
bitmap_zero(registered, IEEE80211_MLD_MAX_NUM_LINKS);
|
||||
|
||||
/*
|
||||
* Firmware expects delete of all link peers at once before waiting
|
||||
* for reception of peer unmap or delete responses. Phase 1 registers
|
||||
* a per-link stack waiter and sends WMI peer delete for every
|
||||
* link; the resp_event handler matches each response to its
|
||||
* (vdev_id, addr) waiter on ar->peer_delete_waits.
|
||||
*/
|
||||
links = ahsta->links_map;
|
||||
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
|
|
@ -318,29 +389,36 @@ int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_st
|
|||
arvif->vdev_id, arsta->addr,
|
||||
ar->hw_link_id);
|
||||
|
||||
ath12k_peer_delete_wait_register(ar, &waits[link_id],
|
||||
arvif->vdev_id, arsta->addr);
|
||||
|
||||
ret = ath12k_peer_delete_send(ar, arvif->vdev_id, arsta->addr);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to delete peer vdev_id %d addr %pM ret %d\n",
|
||||
arvif->vdev_id, arsta->addr, ret);
|
||||
err_ret = ret;
|
||||
ath12k_peer_delete_wait_unregister(ar, &waits[link_id]);
|
||||
continue;
|
||||
}
|
||||
|
||||
set_bit(link_id, registered);
|
||||
}
|
||||
|
||||
/* Ensure all link peers are deleted and unmapped */
|
||||
/*
|
||||
* Phase 2: wait for unmap + delete_resp on each registered link
|
||||
* and tear down the waiter.
|
||||
*/
|
||||
links = ahsta->links_map;
|
||||
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
if (!test_bit(link_id, registered))
|
||||
continue;
|
||||
|
||||
arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]);
|
||||
arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
|
||||
if (!arvif || !arsta)
|
||||
continue;
|
||||
|
||||
ar = arvif->ar;
|
||||
if (!ar)
|
||||
continue;
|
||||
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id, arsta->addr);
|
||||
ret = ath12k_wait_for_peer_delete_done(ar, &waits[link_id]);
|
||||
ath12k_peer_delete_wait_unregister(ar, &waits[link_id]);
|
||||
if (ret) {
|
||||
err_ret = ret;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -9,13 +9,23 @@
|
|||
|
||||
#include "dp_peer.h"
|
||||
|
||||
struct ath12k_peer_delete_wait {
|
||||
struct list_head list;
|
||||
u32 vdev_id;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
void ath12k_peer_delete_resp_signal(struct ath12k *ar, u32 vdev_id, const u8 *addr);
|
||||
void ath12k_peer_delete_wait_flush(struct ath12k *ar);
|
||||
|
||||
void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id);
|
||||
int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr);
|
||||
int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ath12k_wmi_peer_create_arg *arg);
|
||||
int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,
|
||||
const u8 *addr);
|
||||
int ath12k_wait_for_peer_delete_done(struct ath12k *ar,
|
||||
struct ath12k_peer_delete_wait *wait);
|
||||
int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta);
|
||||
struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah,
|
||||
const u8 *addr);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
|
||||
#define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02
|
||||
#define HOST_CSTATE_BIT 0x04
|
||||
|
|
@ -21,45 +22,45 @@
|
|||
|
||||
static const struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
chip_id),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
num_local_links),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = STATIC_ARRAY,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = STATIC_ARRAY,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
hw_link_id),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = STATIC_ARRAY,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = STATIC_ARRAY,
|
||||
.tlv_type = 0,
|
||||
.offset = offsetof(struct wlfw_host_mlo_chip_info_s_v01,
|
||||
valid_mlo_link_id),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -506,6 +507,24 @@ static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
|
|||
.offset = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
|
||||
feature_list),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_OPT_FLAG,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x33,
|
||||
.offset = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
|
||||
dynamic_mem_support_valid),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x33,
|
||||
.offset = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
|
||||
dynamic_mem_support),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
|
|
@ -585,23 +604,41 @@ static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = {
|
|||
board_id),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_OPT_FLAG,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
|
||||
.data_type = QMI_OPT_FLAG,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
|
||||
single_chip_mlo_support_valid),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
|
||||
single_chip_mlo_support),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_OPT_FLAG,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x17,
|
||||
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
|
||||
dynamic_ddr_support_valid),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_1_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x17,
|
||||
.offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
|
||||
dynamic_ddr_support),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
|
|
@ -1625,42 +1662,45 @@ static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = {
|
|||
|
||||
static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_req_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_8_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u64),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x01,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, addr),
|
||||
.data_type = QMI_UNSIGNED_8_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u64),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x01,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01,
|
||||
addr),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_UNSIGNED_4_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u32),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x02,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, size),
|
||||
.data_type = QMI_UNSIGNED_4_BYTE,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u32),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x02,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01,
|
||||
size),
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_resp_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_STRUCT,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(struct qmi_response_type_v01),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x02,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_resp_msg_v01, resp),
|
||||
.ei_array = qmi_response_type_v01_ei,
|
||||
.data_type = QMI_STRUCT,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(struct qmi_response_type_v01),
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x02,
|
||||
.offset = offsetof(struct qmi_wlanfw_aux_uc_info_resp_msg_v01,
|
||||
resp),
|
||||
.ei_array = qmi_response_type_v01_ei,
|
||||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1772,7 +1812,8 @@ static const struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = {
|
|||
},
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = QMI_COMMON_TLV_TYPE,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1925,7 +1966,7 @@ static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = {
|
|||
.data_type = QMI_OPT_FLAG,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
|
||||
shadow_reg_valid),
|
||||
|
|
@ -1934,7 +1975,7 @@ static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = {
|
|||
.data_type = QMI_DATA_LEN,
|
||||
.elem_len = 1,
|
||||
.elem_size = sizeof(u8),
|
||||
.array_type = NO_ARRAY,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
|
||||
shadow_reg_len),
|
||||
|
|
@ -1943,7 +1984,7 @@ static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = {
|
|||
.data_type = QMI_STRUCT,
|
||||
.elem_len = QMI_WLANFW_MAX_NUM_SHADOW_REG_V01,
|
||||
.elem_size = sizeof(struct qmi_wlanfw_shadow_reg_cfg_s_v01),
|
||||
.array_type = VAR_LEN_ARRAY,
|
||||
.array_type = VAR_LEN_ARRAY,
|
||||
.tlv_type = 0x13,
|
||||
.offset = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
|
||||
shadow_reg),
|
||||
|
|
@ -2003,15 +2044,17 @@ static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = {
|
|||
|
||||
static const struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = {
|
||||
{
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.data_type = QMI_EOTI,
|
||||
.array_type = NO_ARRAY,
|
||||
.tlv_type = QMI_COMMON_TLV_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -2094,14 +2137,14 @@ static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
|
|||
|
||||
if (!ag->mlo_capable) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"MLO is disabled hence skip QMI MLO cap");
|
||||
"MLO is disabled hence skip QMI MLO cap\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) {
|
||||
ag->mlo_capable = false;
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"skip QMI MLO cap due to invalid num_radio %d\n",
|
||||
"skip QMI MLO cap due to invalid num_radio %u\n",
|
||||
ab->qmi.num_radios);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2125,7 +2168,7 @@ static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
|
|||
req->mlo_num_chips_valid = 1;
|
||||
req->mlo_num_chips = ag->num_devices;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo capability advertisement device_id %d group_id %d num_devices %d",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo capability advertisement device_id %u group_id %u num_devices %u\n",
|
||||
req->mlo_chip_id, req->mlo_group_id, req->mlo_num_chips);
|
||||
|
||||
mutex_lock(&ag->mutex);
|
||||
|
|
@ -2146,14 +2189,14 @@ static int ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
|
|||
info->chip_id = partner_ab->device_id;
|
||||
info->num_local_links = partner_ab->qmi.num_radios;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo device id %d num_link %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo device id %u num_link %u\n",
|
||||
info->chip_id, info->num_local_links);
|
||||
|
||||
for (j = 0; j < info->num_local_links; j++) {
|
||||
info->hw_link_id[j] = partner_ab->wsi_info.hw_link_id_base + j;
|
||||
info->valid_mlo_link_id[j] = 1;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo hw_link_id %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "mlo hw_link_id %u\n",
|
||||
info->hw_link_id[j]);
|
||||
|
||||
hw_link_id++;
|
||||
|
|
@ -2248,6 +2291,11 @@ int ath12k_qmi_host_cap_send(struct ath12k_base *ab)
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (ab->qmi.dynamic_ddr_support) {
|
||||
req.dynamic_mem_support_valid = 1;
|
||||
req.dynamic_mem_support = 1;
|
||||
}
|
||||
|
||||
ret = qmi_txn_init(&ab->qmi.handle, &txn,
|
||||
qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp);
|
||||
if (ret < 0)
|
||||
|
|
@ -2268,7 +2316,7 @@ int ath12k_qmi_host_cap_send(struct ath12k_base *ab)
|
|||
goto out;
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "Host capability request failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "Host capability request failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -2319,11 +2367,15 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
|
|||
|
||||
ab->qmi.num_radios = resp.num_phy;
|
||||
|
||||
if (resp.dynamic_ddr_support_valid)
|
||||
ab->qmi.dynamic_ddr_support = resp.dynamic_ddr_support;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"phy capability resp valid %d single_chip_mlo_support %d valid %d num_phy %d valid %d board_id %d\n",
|
||||
"phy capability resp valid %u single_chip_mlo_support %u valid %u num_phy %u valid %u board_id %u dynamic_ddr_valid %u dynamic_ddr_support %u\n",
|
||||
resp.single_chip_mlo_support_valid, resp.single_chip_mlo_support,
|
||||
resp.num_phy_valid, resp.num_phy,
|
||||
resp.board_id_valid, resp.board_id);
|
||||
resp.board_id_valid, resp.board_id, resp.dynamic_ddr_support_valid,
|
||||
resp.dynamic_ddr_support);
|
||||
|
||||
return;
|
||||
|
||||
|
|
@ -2332,7 +2384,7 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
|
|||
ab->qmi.num_radios = ab->hw_params->def_num_link;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"no valid response from PHY capability, choose default num_phy %d\n",
|
||||
"no valid response from PHY capability, choose default num_phy %u\n",
|
||||
ab->qmi.num_radios);
|
||||
}
|
||||
|
||||
|
|
@ -2393,7 +2445,7 @@ static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "FW Ind register request failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "FW Ind register request failed, result: %u, err: %u\n",
|
||||
resp->resp.result, resp->resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -2428,7 +2480,7 @@ int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab)
|
|||
if (!test_bit(ATH12K_FLAG_FIXED_MEM_REGION, &ab->dev_flags) &&
|
||||
ab->qmi.target_mem_delayed) {
|
||||
delayed = true;
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi delays mem_request %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi delays mem_request %u\n",
|
||||
ab->qmi.mem_seg_count);
|
||||
} else {
|
||||
delayed = false;
|
||||
|
|
@ -2474,7 +2526,7 @@ int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab)
|
|||
if (delayed && resp.resp.error == 0)
|
||||
goto out;
|
||||
|
||||
ath12k_warn(ab, "Respond mem req failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "Respond mem req failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -2606,13 +2658,13 @@ static int ath12k_qmi_alloc_chunk(struct ath12k_base *ab,
|
|||
if (chunk->size > ATH12K_QMI_MAX_CHUNK_SIZE) {
|
||||
ab->qmi.target_mem_delayed = true;
|
||||
ath12k_warn(ab,
|
||||
"qmi dma allocation failed (%d B type %u), will try later with small size\n",
|
||||
"qmi dma allocation failed (%u B type %u), will try later with small size\n",
|
||||
chunk->size,
|
||||
chunk->type);
|
||||
ath12k_qmi_free_target_mem_chunk(ab);
|
||||
return -EAGAIN;
|
||||
}
|
||||
ath12k_warn(ab, "memory allocation failure for %u size: %d\n",
|
||||
ath12k_warn(ab, "memory allocation failure for %u size: %u\n",
|
||||
chunk->type, chunk->size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -2659,7 +2711,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
|
|||
mlo_size += chunk->size;
|
||||
if (ag->mlo_mem.mlo_mem_size &&
|
||||
mlo_size > ag->mlo_mem.mlo_mem_size) {
|
||||
ath12k_err(ab, "QMI MLO memory allocation failure, requested size %d is more than allocated size %d",
|
||||
ath12k_err(ab, "QMI MLO memory allocation failure, requested size %d is more than allocated size %d\n",
|
||||
mlo_size, ag->mlo_mem.mlo_mem_size);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
|
|
@ -2668,7 +2720,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
|
|||
mlo_chunk = &ag->mlo_mem.chunk[mlo_idx];
|
||||
if (mlo_chunk->paddr) {
|
||||
if (chunk->size != mlo_chunk->size) {
|
||||
ath12k_err(ab, "QMI MLO chunk memory allocation failure for index %d, requested size %d is more than allocated size %d",
|
||||
ath12k_err(ab, "QMI MLO chunk memory allocation failure for index %d, requested size %u is more than allocated size %u\n",
|
||||
mlo_idx, chunk->size, mlo_chunk->size);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
|
|
@ -2699,7 +2751,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
|
|||
if (!ag->mlo_mem.mlo_mem_size) {
|
||||
ag->mlo_mem.mlo_mem_size = mlo_size;
|
||||
} else if (ag->mlo_mem.mlo_mem_size != mlo_size) {
|
||||
ath12k_err(ab, "QMI MLO memory size error, expected size is %d but requested size is %d",
|
||||
ath12k_err(ab, "QMI MLO memory size error, expected size is %d but requested size is %d\n",
|
||||
ag->mlo_mem.mlo_mem_size, mlo_size);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
|
|
@ -2725,121 +2777,96 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char *ath12k_qmi_get_mem_reg_name(int mem_type)
|
||||
{
|
||||
switch (mem_type) {
|
||||
case HOST_DDR_REGION_TYPE:
|
||||
case BDF_MEM_REGION_TYPE:
|
||||
return "q6-region";
|
||||
case M3_DUMP_REGION_TYPE:
|
||||
return "m3-dump";
|
||||
case CALDB_MEM_REGION_TYPE:
|
||||
return "q6-caldb";
|
||||
case MLO_GLOBAL_MEM_REGION_TYPE:
|
||||
return "mlo-global-mem";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath12k_qmi_assign_target_mem_chunk(struct ath12k_base *ab)
|
||||
{
|
||||
struct reserved_mem *rmem;
|
||||
size_t avail_rmem_size;
|
||||
struct device_node *np = ab->dev->of_node;
|
||||
size_t avail_rmem_size, offset = 0;
|
||||
struct target_mem_chunk *chunk;
|
||||
struct resource res;
|
||||
const char *rname;
|
||||
int i, idx, ret;
|
||||
|
||||
for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) {
|
||||
switch (ab->qmi.target_mem[i].type) {
|
||||
case HOST_DDR_REGION_TYPE:
|
||||
rmem = ath12k_core_get_reserved_mem(ab, 0);
|
||||
if (!rmem) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
avail_rmem_size = rmem->size;
|
||||
if (avail_rmem_size < ab->qmi.target_mem[i].size) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"failed to assign mem type %u req size %u avail size %zu\n",
|
||||
ab->qmi.target_mem[i].type,
|
||||
ab->qmi.target_mem[i].size,
|
||||
avail_rmem_size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ab->qmi.target_mem[idx].paddr = rmem->base;
|
||||
ab->qmi.target_mem[idx].v.ioaddr =
|
||||
ioremap(ab->qmi.target_mem[idx].paddr,
|
||||
ab->qmi.target_mem[i].size);
|
||||
if (!ab->qmi.target_mem[idx].v.ioaddr) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||
idx++;
|
||||
break;
|
||||
case BDF_MEM_REGION_TYPE:
|
||||
rmem = ath12k_core_get_reserved_mem(ab, 0);
|
||||
if (!rmem) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
avail_rmem_size = rmem->size - ab->hw_params->bdf_addr_offset;
|
||||
if (avail_rmem_size < ab->qmi.target_mem[i].size) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"failed to assign mem type %u req size %u avail size %zu\n",
|
||||
ab->qmi.target_mem[i].type,
|
||||
ab->qmi.target_mem[i].size,
|
||||
avail_rmem_size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ab->qmi.target_mem[idx].paddr =
|
||||
rmem->base + ab->hw_params->bdf_addr_offset;
|
||||
ab->qmi.target_mem[idx].v.ioaddr =
|
||||
ioremap(ab->qmi.target_mem[idx].paddr,
|
||||
ab->qmi.target_mem[i].size);
|
||||
if (!ab->qmi.target_mem[idx].v.ioaddr) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||
idx++;
|
||||
break;
|
||||
case CALDB_MEM_REGION_TYPE:
|
||||
/* Cold boot calibration is not enabled in Ath12k. Hence,
|
||||
chunk = &ab->qmi.target_mem[i];
|
||||
if (chunk->type == CALDB_MEM_REGION_TYPE) {
|
||||
/*
|
||||
* Cold boot calibration is not enabled in Ath12k. Hence,
|
||||
* assign paddr = 0.
|
||||
* Once cold boot calibration is enabled add support to
|
||||
* assign reserved memory from DT.
|
||||
*/
|
||||
ab->qmi.target_mem[idx].paddr = 0;
|
||||
ab->qmi.target_mem[idx].v.ioaddr = NULL;
|
||||
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||
ab->qmi.target_mem[idx].size = chunk->size;
|
||||
ab->qmi.target_mem[idx].type = chunk->type;
|
||||
idx++;
|
||||
break;
|
||||
case M3_DUMP_REGION_TYPE:
|
||||
rmem = ath12k_core_get_reserved_mem(ab, 1);
|
||||
if (!rmem) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
avail_rmem_size = rmem->size;
|
||||
if (avail_rmem_size < ab->qmi.target_mem[i].size) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"failed to assign mem type %u req size %u avail size %zu\n",
|
||||
ab->qmi.target_mem[i].type,
|
||||
ab->qmi.target_mem[i].size,
|
||||
rname = ath12k_qmi_get_mem_reg_name(chunk->type);
|
||||
if (!rname) {
|
||||
ath12k_warn(ab, "qmi ignore invalid mem req type %u\n",
|
||||
chunk->type);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = of_reserved_mem_region_to_resource_byname(np, rname, &res);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
avail_rmem_size = resource_size(&res);
|
||||
if (chunk->type == BDF_MEM_REGION_TYPE ||
|
||||
chunk->type == HOST_DDR_REGION_TYPE) {
|
||||
if (ab->hw_params->bdf_addr_offset > avail_rmem_size ||
|
||||
offset > avail_rmem_size - ab->hw_params->bdf_addr_offset) {
|
||||
ath12k_err(ab, "qmi mem offset overflow: bdf_offset=%u offset=%zu size=%zu\n",
|
||||
ab->hw_params->bdf_addr_offset, offset,
|
||||
avail_rmem_size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ab->qmi.target_mem[idx].paddr = rmem->base;
|
||||
ab->qmi.target_mem[idx].v.ioaddr =
|
||||
ioremap(ab->qmi.target_mem[idx].paddr,
|
||||
ab->qmi.target_mem[i].size);
|
||||
if (!ab->qmi.target_mem[idx].v.ioaddr) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
|
||||
ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
|
||||
idx++;
|
||||
break;
|
||||
default:
|
||||
ath12k_warn(ab, "qmi ignore invalid mem req type %u\n",
|
||||
ab->qmi.target_mem[i].type);
|
||||
break;
|
||||
avail_rmem_size -= ab->hw_params->bdf_addr_offset + offset;
|
||||
res.start += ab->hw_params->bdf_addr_offset + offset;
|
||||
offset += chunk->size;
|
||||
}
|
||||
|
||||
if (avail_rmem_size < chunk->size) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"failed to assign mem type %u req size %u avail size %zu\n",
|
||||
chunk->type, chunk->size, avail_rmem_size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ab->qmi.target_mem[idx].paddr = res.start;
|
||||
ab->qmi.target_mem[idx].v.ioaddr = ioremap(ab->qmi.target_mem[idx].paddr,
|
||||
chunk->size);
|
||||
if (!ab->qmi.target_mem[idx].v.ioaddr) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ab->qmi.target_mem[idx].size = chunk->size;
|
||||
ab->qmi.target_mem[idx].type = chunk->type;
|
||||
idx++;
|
||||
}
|
||||
ab->qmi.mem_seg_count = idx;
|
||||
|
||||
|
|
@ -2884,7 +2911,7 @@ int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "qmi targetcap req failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "qmi targetcap req failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -2936,7 +2963,7 @@ int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
|
|||
ab->qmi.target.chip_id, ab->qmi.target.chip_family,
|
||||
ab->qmi.target.board_id, ab->qmi.target.soc_id);
|
||||
|
||||
ath12k_info(ab, "fw_version 0x%x fw_build_timestamp %s fw_build_id %s",
|
||||
ath12k_info(ab, "fw_version 0x%x fw_build_timestamp %s fw_build_id %s\n",
|
||||
ab->qmi.target.fw_version,
|
||||
ab->qmi.target.fw_build_timestamp,
|
||||
ab->qmi.target.fw_build_id);
|
||||
|
|
@ -3006,7 +3033,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi bdf download req fixed addr type %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi bdf download req fixed addr type %u\n",
|
||||
type);
|
||||
|
||||
ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
|
||||
|
|
@ -3023,7 +3050,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab,
|
|||
goto out;
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "qmi BDF download failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "qmi BDF download failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -3036,7 +3063,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab,
|
|||
temp += req->data_len;
|
||||
req->seg_id++;
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI,
|
||||
"qmi bdf download request remaining %i\n",
|
||||
"qmi bdf download request remaining %u\n",
|
||||
remaining);
|
||||
}
|
||||
}
|
||||
|
|
@ -3127,7 +3154,7 @@ int ath12k_qmi_load_bdf_qmi(struct ath12k_base *ab,
|
|||
release_firmware(fw_entry);
|
||||
return ret;
|
||||
default:
|
||||
ath12k_warn(ab, "unknown file type for load %d", type);
|
||||
ath12k_warn(ab, "unknown file type for load %d\n", type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -3239,7 +3266,7 @@ int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab)
|
|||
if (ab->hw_params->fw.m3_loader == ath12k_m3_fw_loader_driver) {
|
||||
ret = ath12k_qmi_m3_load(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to load m3 firmware: %d", ret);
|
||||
ath12k_err(ab, "failed to load m3 firmware: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
req.addr = m3_mem->paddr;
|
||||
|
|
@ -3269,7 +3296,7 @@ int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "qmi M3 info request failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "qmi M3 info request failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -3364,7 +3391,7 @@ int ath12k_qmi_wlanfw_aux_uc_info_send(struct ath12k_base *ab)
|
|||
|
||||
ret = ath12k_qmi_aux_uc_load(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to load aux_uc firmware: %d", ret);
|
||||
ath12k_err(ab, "failed to load aux_uc firmware: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3394,7 +3421,7 @@ int ath12k_qmi_wlanfw_aux_uc_info_send(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "qmi AUX_UC info request failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "qmi AUX_UC info request failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -3426,7 +3453,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
|
|||
qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req);
|
||||
if (ret < 0) {
|
||||
qmi_txn_cancel(&txn);
|
||||
ath12k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n",
|
||||
ath12k_warn(ab, "qmi failed to send mode request, mode: %u, err = %d\n",
|
||||
mode, ret);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -3437,13 +3464,13 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
|
|||
ath12k_warn(ab, "WLFW service is dis-connected\n");
|
||||
return 0;
|
||||
}
|
||||
ath12k_warn(ab, "qmi failed set mode request, mode: %d, err = %d\n",
|
||||
ath12k_warn(ab, "qmi failed set mode request, mode: %u, err = %d\n",
|
||||
mode, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "Mode request failed, mode: %d, result: %d err: %d\n",
|
||||
ath12k_warn(ab, "Mode request failed, mode: %u, result: %u err: %u\n",
|
||||
mode, resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -3536,7 +3563,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "qmi wlan config request failed, result: %d, err: %d\n",
|
||||
ath12k_warn(ab, "qmi wlan config request failed, result: %u, err: %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -3580,7 +3607,7 @@ static int ath12k_qmi_wlanfw_wlan_ini_send(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
ath12k_warn(ab, "QMI wlan ini response failure: %d %d\n",
|
||||
ath12k_warn(ab, "QMI wlan ini response failure: %u %u\n",
|
||||
resp.resp.result, resp.resp.error);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
|
@ -3663,7 +3690,7 @@ void ath12k_qmi_trigger_host_cap(struct ath12k_base *ab)
|
|||
|
||||
spin_unlock(&qmi->event_lock);
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "trigger host cap for device id %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "trigger host cap for device id %u\n",
|
||||
ab->device_id);
|
||||
|
||||
ath12k_qmi_driver_event_post(qmi, ATH12K_QMI_EVENT_HOST_CAP, NULL);
|
||||
|
|
@ -3833,7 +3860,7 @@ static void ath12k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
|
|||
for (i = 0; i < qmi->mem_seg_count ; i++) {
|
||||
ab->qmi.target_mem[i].type = msg->mem_seg[i].type;
|
||||
ab->qmi.target_mem[i].size = msg->mem_seg[i].size;
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi mem seg type %d size %d\n",
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi mem seg type %d size %u\n",
|
||||
msg->mem_seg[i].type, msg->mem_seg[i].size);
|
||||
}
|
||||
|
||||
|
|
@ -3954,7 +3981,7 @@ static int ath12k_qmi_event_host_cap(struct ath12k_qmi *qmi)
|
|||
|
||||
ret = ath12k_qmi_host_cap_send(ab);
|
||||
if (ret < 0) {
|
||||
ath12k_warn(ab, "failed to send qmi host cap for device id %d: %d\n",
|
||||
ath12k_warn(ab, "failed to send qmi host cap for device id %u: %d\n",
|
||||
ab->device_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -4024,7 +4051,7 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work)
|
|||
set_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags);
|
||||
break;
|
||||
default:
|
||||
ath12k_warn(ab, "invalid event type: %d", event->type);
|
||||
ath12k_warn(ab, "invalid event type: %d\n", event->type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#define ATH12K_HOST_VERSION_STRING "WIN"
|
||||
#define ATH12K_QMI_WLANFW_TIMEOUT_MS 10000
|
||||
#define ATH12K_QMI_MAX_BDF_FILE_NAME_SIZE 64
|
||||
#define ATH12K_QMI_CALDB_ADDRESS 0x4BA00000
|
||||
#define ATH12K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128
|
||||
#define ATH12K_QMI_WLFW_SERVICE_VERS_V01 0x01
|
||||
#define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01 0x02
|
||||
|
|
@ -24,9 +23,7 @@
|
|||
#define ATH12K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 32
|
||||
#define ATH12K_QMI_RESP_LEN_MAX 8192
|
||||
#define ATH12K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01 52
|
||||
#define ATH12K_QMI_CALDB_SIZE 0x480000
|
||||
#define ATH12K_QMI_BDF_EXT_STR_LENGTH 0x20
|
||||
#define ATH12K_QMI_FW_MEM_REQ_SEGMENT_CNT 3
|
||||
#define ATH12K_QMI_WLFW_MAX_DEV_MEM_NUM_V01 4
|
||||
#define ATH12K_QMI_DEVMEM_CMEM_INDEX 0
|
||||
|
||||
|
|
@ -156,12 +153,11 @@ struct ath12k_qmi {
|
|||
struct m3_mem_region aux_uc_mem;
|
||||
unsigned int service_ins_id;
|
||||
struct dev_mem_info dev_mem[ATH12K_QMI_WLFW_MAX_DEV_MEM_NUM_V01];
|
||||
u8 dynamic_ddr_support;
|
||||
};
|
||||
|
||||
#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 261
|
||||
#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 265
|
||||
#define QMI_WLANFW_HOST_CAP_REQ_V01 0x0034
|
||||
#define QMI_WLANFW_HOST_CAP_RESP_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
|
||||
#define QMI_WLFW_MAX_NUM_GPIO_V01 32
|
||||
#define QMI_WLANFW_MAX_PLATFORM_NAME_LEN_V01 64
|
||||
#define QMI_WLANFW_MAX_HOST_DDR_RANGE_SIZE_V01 3
|
||||
|
|
@ -258,7 +254,8 @@ struct qmi_wlanfw_host_cap_req_msg_v01 {
|
|||
struct wlfw_host_mlo_chip_info_s_v01 mlo_chip_info[QMI_WLFW_MAX_NUM_MLO_CHIPS_V01];
|
||||
u8 feature_list_valid;
|
||||
u64 feature_list;
|
||||
|
||||
u8 dynamic_mem_support_valid;
|
||||
u8 dynamic_mem_support;
|
||||
};
|
||||
|
||||
struct qmi_wlanfw_host_cap_resp_msg_v01 {
|
||||
|
|
@ -267,8 +264,6 @@ struct qmi_wlanfw_host_cap_resp_msg_v01 {
|
|||
|
||||
#define QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN 0
|
||||
#define QMI_WLANFW_PHY_CAP_REQ_V01 0x0057
|
||||
#define QMI_WLANFW_PHY_CAP_RESP_MSG_V01_MAX_LEN 18
|
||||
#define QMI_WLANFW_PHY_CAP_RESP_V01 0x0057
|
||||
|
||||
struct qmi_wlanfw_phy_cap_req_msg_v01 {
|
||||
};
|
||||
|
|
@ -281,12 +276,12 @@ struct qmi_wlanfw_phy_cap_resp_msg_v01 {
|
|||
u32 board_id;
|
||||
u8 single_chip_mlo_support_valid;
|
||||
u8 single_chip_mlo_support;
|
||||
u8 dynamic_ddr_support_valid;
|
||||
u8 dynamic_ddr_support;
|
||||
};
|
||||
|
||||
#define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN 54
|
||||
#define QMI_WLANFW_IND_REGISTER_REQ_V01 0x0020
|
||||
#define QMI_WLANFW_IND_REGISTER_RESP_MSG_V01_MAX_LEN 18
|
||||
#define QMI_WLANFW_IND_REGISTER_RESP_V01 0x0020
|
||||
#define QMI_WLANFW_CLIENT_ID 0x4b4e454c
|
||||
|
||||
struct qmi_wlanfw_ind_register_req_msg_v01 {
|
||||
|
|
@ -322,12 +317,8 @@ struct qmi_wlanfw_ind_register_resp_msg_v01 {
|
|||
u64 fw_status;
|
||||
};
|
||||
|
||||
#define QMI_WLANFW_REQUEST_MEM_IND_MSG_V01_MAX_LEN 1824
|
||||
#define QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN 888
|
||||
#define QMI_WLANFW_RESPOND_MEM_RESP_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLANFW_REQUEST_MEM_IND_V01 0x0035
|
||||
#define QMI_WLANFW_RESPOND_MEM_REQ_V01 0x0036
|
||||
#define QMI_WLANFW_RESPOND_MEM_RESP_V01 0x0036
|
||||
#define QMI_WLANFW_MAX_NUM_MEM_CFG_V01 2
|
||||
#define QMI_WLANFW_MAX_STR_LEN_V01 16
|
||||
|
||||
|
|
@ -385,9 +376,7 @@ struct qmi_wlanfw_fw_ready_ind_msg_v01 {
|
|||
};
|
||||
|
||||
#define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0
|
||||
#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 207
|
||||
#define QMI_WLANFW_CAP_REQ_V01 0x0024
|
||||
#define QMI_WLANFW_CAP_RESP_V01 0x0024
|
||||
|
||||
enum qmi_wlanfw_pipedir_enum_v01 {
|
||||
QMI_WLFW_PIPEDIR_NONE_V01 = 0,
|
||||
|
|
@ -500,8 +489,6 @@ struct qmi_wlanfw_cap_req_msg_v01 {
|
|||
};
|
||||
|
||||
#define QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN 6182
|
||||
#define QMI_WLANFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLANFW_BDF_DOWNLOAD_RESP_V01 0x0025
|
||||
#define QMI_WLANFW_BDF_DOWNLOAD_REQ_V01 0x0025
|
||||
/* TODO: Need to check with MCL and FW team that data can be pointer and
|
||||
* can be last element in structure
|
||||
|
|
@ -529,8 +516,6 @@ struct qmi_wlanfw_bdf_download_resp_msg_v01 {
|
|||
};
|
||||
|
||||
#define QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
|
||||
#define QMI_WLANFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
#define QMI_WLANFW_M3_INFO_RESP_V01 0x003C
|
||||
#define QMI_WLANFW_M3_INFO_REQ_V01 0x003C
|
||||
|
||||
struct qmi_wlanfw_m3_info_req_msg_v01 {
|
||||
|
|
@ -543,7 +528,6 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 {
|
|||
};
|
||||
|
||||
#define QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
|
||||
#define QMI_WLANFW_AUX_UC_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
#define QMI_WLANFW_AUX_UC_INFO_REQ_V01 0x005A
|
||||
|
||||
struct qmi_wlanfw_aux_uc_info_req_msg_v01 {
|
||||
|
|
@ -556,13 +540,9 @@ struct qmi_wlanfw_aux_uc_info_resp_msg_v01 {
|
|||
};
|
||||
|
||||
#define QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN 11
|
||||
#define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN 803
|
||||
#define QMI_WLANFW_WLAN_CFG_RESP_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLANFW_WLAN_MODE_REQ_V01 0x0022
|
||||
#define QMI_WLANFW_WLAN_MODE_RESP_V01 0x0022
|
||||
#define QMI_WLANFW_WLAN_CFG_REQ_V01 0x0023
|
||||
#define QMI_WLANFW_WLAN_CFG_RESP_V01 0x0023
|
||||
#define QMI_WLANFW_MAX_STR_LEN_V01 16
|
||||
#define QMI_WLANFW_MAX_NUM_CE_V01 12
|
||||
#define QMI_WLANFW_MAX_NUM_SVC_V01 24
|
||||
|
|
@ -605,9 +585,7 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 {
|
|||
};
|
||||
|
||||
#define ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01 0x002F
|
||||
#define ATH12K_QMI_WLANFW_WLAN_INI_RESP_V01 0x002F
|
||||
#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN 7
|
||||
#define QMI_WLANFW_WLAN_INI_RESP_MSG_V01_MAX_LEN 7
|
||||
|
||||
struct qmi_wlanfw_wlan_ini_req_msg_v01 {
|
||||
/* Must be set to true if enable_fwlog is being passed */
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ static int ath12k_wifi7_dp_service_srng(struct ath12k_dp *dp,
|
|||
return tot_work_done;
|
||||
}
|
||||
|
||||
static struct ath12k_dp_arch_ops ath12k_wifi7_dp_arch_ops = {
|
||||
static const struct ath12k_dp_arch_ops ath12k_wifi7_dp_arch_ops = {
|
||||
.service_srng = ath12k_wifi7_dp_service_srng,
|
||||
.tx_get_vdev_bank_config = ath12k_wifi7_dp_tx_get_vdev_bank_config,
|
||||
.reo_cmd_send = ath12k_wifi7_dp_reo_cmd_send,
|
||||
|
|
|
|||
|
|
@ -1565,16 +1565,17 @@ ath12k_wifi7_dp_mon_parse_status_msdu_end(struct ath12k_mon_data *pmon,
|
|||
static enum hal_rx_mon_status
|
||||
ath12k_wifi7_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev,
|
||||
struct ath12k_mon_data *pmon,
|
||||
const struct hal_tlv_64_hdr *tlv)
|
||||
const void *tlv)
|
||||
{
|
||||
struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
|
||||
const void *tlv_data = tlv->value;
|
||||
u32 info[7], userid;
|
||||
u16 tlv_tag, tlv_len;
|
||||
struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
|
||||
struct ath12k_hal *hal = &ar->ab->hal;
|
||||
u16 tlv_tag, tlv_len, userid;
|
||||
void *tlv_data;
|
||||
u32 info[7];
|
||||
|
||||
tlv_tag = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_TAG);
|
||||
tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN);
|
||||
userid = le64_get_bits(tlv->tl, HAL_TLV_64_USR_ID);
|
||||
tlv_data = hal->ops->mon_rx_status_dec_tlv_hdr((void *)tlv, &tlv_tag,
|
||||
&tlv_len, &userid);
|
||||
|
||||
if (ppdu_info->tlv_aggr.in_progress && ppdu_info->tlv_aggr.tlv_tag != tlv_tag) {
|
||||
ath12k_wifi7_dp_mon_parse_eht_sig_hdr(ppdu_info,
|
||||
|
|
@ -2480,7 +2481,6 @@ ath12k_wifi7_dp_mon_rx_deliver(struct ath12k_pdev_dp *dp_pdev,
|
|||
{
|
||||
struct sk_buff *mon_skb, *skb_next, *header;
|
||||
struct ieee80211_rx_status *rxs = &dp_pdev->rx_status;
|
||||
u8 decap = DP_RX_DECAP_TYPE_RAW;
|
||||
|
||||
mon_skb = ath12k_dp_mon_rx_merg_msdus(dp_pdev, mon_mpdu, ppduinfo, rxs);
|
||||
if (!mon_skb)
|
||||
|
|
@ -2507,12 +2507,8 @@ ath12k_wifi7_dp_mon_rx_deliver(struct ath12k_pdev_dp *dp_pdev,
|
|||
}
|
||||
rxs->flag |= RX_FLAG_ONLY_MONITOR;
|
||||
|
||||
if (!(rxs->flag & RX_FLAG_ONLY_MONITOR))
|
||||
decap = mon_mpdu->decap_format;
|
||||
|
||||
ath12k_dp_mon_update_radiotap(dp_pdev, ppduinfo, mon_skb, rxs);
|
||||
ath12k_dp_mon_rx_deliver_msdu(dp_pdev, napi, mon_skb, ppduinfo,
|
||||
rxs, decap);
|
||||
ath12k_dp_mon_rx_deliver_msdu(dp_pdev, napi, mon_skb, rxs);
|
||||
mon_skb = skb_next;
|
||||
} while (mon_skb);
|
||||
rxs->flag = 0;
|
||||
|
|
@ -2930,11 +2926,12 @@ static enum dp_mon_status_buf_state
|
|||
ath12k_wifi7_dp_rx_mon_buf_done(struct ath12k_base *ab, struct hal_srng *srng,
|
||||
struct dp_rxdma_mon_ring *rx_ring)
|
||||
{
|
||||
struct ath12k_hal *hal = &ab->hal;
|
||||
struct ath12k_skb_rxcb *rxcb;
|
||||
struct hal_tlv_64_hdr *tlv;
|
||||
struct sk_buff *skb;
|
||||
void *status_desc;
|
||||
dma_addr_t paddr;
|
||||
u16 tlv_tag;
|
||||
u32 cookie;
|
||||
int buf_id;
|
||||
u8 rbm;
|
||||
|
|
@ -2959,8 +2956,8 @@ ath12k_wifi7_dp_rx_mon_buf_done(struct ath12k_base *ab, struct hal_srng *srng,
|
|||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
tlv = (struct hal_tlv_64_hdr *)skb->data;
|
||||
if (le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG) != HAL_RX_STATUS_BUFFER_DONE)
|
||||
hal->ops->mon_rx_status_dec_tlv_hdr(skb->data, &tlv_tag, NULL, NULL);
|
||||
if (tlv_tag != HAL_RX_STATUS_BUFFER_DONE)
|
||||
return DP_MON_STATUS_NO_DMA;
|
||||
|
||||
return DP_MON_STATUS_REPLINISH;
|
||||
|
|
@ -2972,41 +2969,40 @@ ath12k_wifi7_dp_mon_parse_rx_dest(struct ath12k_pdev_dp *dp_pdev,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
|
||||
struct hal_tlv_64_hdr *tlv;
|
||||
struct ath12k_hal *hal = &ar->ab->hal;
|
||||
u8 *tlv_value, *tlv = skb->data;
|
||||
struct ath12k_skb_rxcb *rxcb;
|
||||
enum hal_rx_mon_status hal_status;
|
||||
u16 tlv_tag, tlv_len;
|
||||
u8 *ptr = skb->data;
|
||||
u32 tlv_hdr_len;
|
||||
|
||||
tlv_hdr_len = hal->ops->get_tlv_hdr_align();
|
||||
|
||||
do {
|
||||
tlv = (struct hal_tlv_64_hdr *)ptr;
|
||||
tlv_tag = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_TAG);
|
||||
tlv_value = hal->ops->mon_rx_status_dec_tlv_hdr(tlv, &tlv_tag,
|
||||
&tlv_len, NULL);
|
||||
|
||||
/* The actual length of PPDU_END is the combined length of many PHY
|
||||
* TLVs that follow. Skip the TLV header and
|
||||
* rx_rxpcu_classification_overview that follows the header to get to
|
||||
* next TLV.
|
||||
*/
|
||||
|
||||
if (tlv_tag == HAL_RX_PPDU_END)
|
||||
tlv_len = sizeof(struct hal_rx_rxpcu_classification_overview);
|
||||
else
|
||||
tlv_len = le64_get_bits(tlv->tl, HAL_TLV_64_HDR_LEN);
|
||||
|
||||
hal_status = ath12k_wifi7_dp_mon_rx_parse_status_tlv(dp_pdev, pmon,
|
||||
tlv);
|
||||
|
||||
if (ar->monitor_started && ar->ab->hw_params->rxdma1_enable &&
|
||||
ath12k_wifi7_dp_mon_parse_rx_dest_tlv(dp_pdev, pmon, hal_status,
|
||||
tlv->value))
|
||||
tlv_value))
|
||||
return HAL_RX_MON_STATUS_PPDU_DONE;
|
||||
|
||||
ptr += sizeof(*tlv) + tlv_len;
|
||||
ptr = PTR_ALIGN(ptr, HAL_TLV_64_ALIGN);
|
||||
tlv = PTR_ALIGN(tlv + tlv_len + tlv_hdr_len, tlv_hdr_len);
|
||||
|
||||
if ((ptr - skb->data) > skb->len)
|
||||
if (unlikely(tlv - skb->data > skb->len ||
|
||||
skb->len - (tlv - skb->data) < tlv_hdr_len))
|
||||
break;
|
||||
|
||||
} while ((hal_status == HAL_RX_MON_STATUS_PPDU_NOT_DONE) ||
|
||||
(hal_status == HAL_RX_MON_STATUS_BUF_ADDR) ||
|
||||
(hal_status == HAL_RX_MON_STATUS_MPDU_START) ||
|
||||
|
|
@ -3056,15 +3052,16 @@ ath12k_wifi7_dp_rx_reap_mon_status_ring(struct ath12k_base *ab, int mac_id,
|
|||
int buf_id, srng_id, num_buffs_reaped = 0;
|
||||
enum dp_mon_status_buf_state reap_status;
|
||||
struct dp_rxdma_mon_ring *rx_ring;
|
||||
struct ath12k_hal *hal = &ab->hal;
|
||||
struct ath12k_mon_data *pmon;
|
||||
struct ath12k_skb_rxcb *rxcb;
|
||||
struct hal_tlv_64_hdr *tlv;
|
||||
void *rx_mon_status_desc;
|
||||
struct hal_srng *srng;
|
||||
struct ath12k_dp *dp;
|
||||
struct sk_buff *skb;
|
||||
struct ath12k *ar;
|
||||
dma_addr_t paddr;
|
||||
u16 tlv_tag;
|
||||
u32 cookie;
|
||||
u8 rbm;
|
||||
|
||||
|
|
@ -3109,14 +3106,13 @@ ath12k_wifi7_dp_rx_reap_mon_status_ring(struct ath12k_base *ab, int mac_id,
|
|||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
tlv = (struct hal_tlv_64_hdr *)skb->data;
|
||||
if (le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG) !=
|
||||
HAL_RX_STATUS_BUFFER_DONE) {
|
||||
hal->ops->mon_rx_status_dec_tlv_hdr(skb->data, &tlv_tag,
|
||||
NULL, NULL);
|
||||
if (tlv_tag != HAL_RX_STATUS_BUFFER_DONE) {
|
||||
pmon->buf_state = DP_MON_STATUS_NO_DMA;
|
||||
ath12k_warn(ab,
|
||||
"mon status DONE not set %llx, buf_id %d\n",
|
||||
le64_get_bits(tlv->tl, HAL_TLV_HDR_TAG),
|
||||
buf_id);
|
||||
"mon status DONE not set %x, buf_id %d\n",
|
||||
tlv_tag, buf_id);
|
||||
/* RxDMA status done bit might not be set even
|
||||
* though tp is moved by HW.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ static u16 ath12k_hal_reo_status_dec_tlv_hdr_qcc2072(void *tlv, void **desc)
|
|||
struct hal_reo_get_queue_stats_status_qcc2072 *status_tlv;
|
||||
u16 tag;
|
||||
|
||||
tag = ath12k_hal_decode_tlv32_hdr(tlv, (void **)&status_tlv);
|
||||
status_tlv = ath12k_hal_decode_tlv32_hdr(tlv, &tag, NULL, NULL);
|
||||
/*
|
||||
* actual desc of REO status entry starts after tlv32_padding,
|
||||
* see hal_reo_get_queue_stats_status_qcc2072
|
||||
|
|
@ -506,6 +506,8 @@ const struct hal_ops hal_qcc2072_ops = {
|
|||
.rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get,
|
||||
.reo_cmd_enc_tlv_hdr = ath12k_hal_encode_tlv32_hdr,
|
||||
.reo_status_dec_tlv_hdr = ath12k_hal_reo_status_dec_tlv_hdr_qcc2072,
|
||||
.mon_rx_status_dec_tlv_hdr = ath12k_hal_decode_tlv32_hdr,
|
||||
.get_tlv_hdr_align = ath12k_hal_get_tlv32_hdr_align,
|
||||
};
|
||||
|
||||
u32 ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(void)
|
||||
|
|
|
|||
|
|
@ -950,6 +950,15 @@ void ath12k_hal_extract_rx_desc_data_qcn9274(struct hal_rx_desc_data *rx_desc_da
|
|||
rx_desc_data->err_bitmap = ath12k_hal_rx_h_mpdu_err_qcn9274(rx_desc);
|
||||
}
|
||||
|
||||
static u16 ath12k_hal_reo_status_dec_tlv_hdr_qcn9274(void *tlv, void **desc)
|
||||
{
|
||||
u16 tag;
|
||||
|
||||
*desc = ath12k_hal_decode_tlv64_hdr(tlv, &tag, NULL, NULL);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
const struct ath12k_hw_hal_params ath12k_hw_hal_params_qcn9274 = {
|
||||
.rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM,
|
||||
.wbm2sw_cc_enable = HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW0_EN |
|
||||
|
|
@ -1138,5 +1147,7 @@ const struct hal_ops hal_qcn9274_ops = {
|
|||
.rx_msdu_list_get = ath12k_wifi7_hal_rx_msdu_list_get,
|
||||
.rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get,
|
||||
.reo_cmd_enc_tlv_hdr = ath12k_hal_encode_tlv64_hdr,
|
||||
.reo_status_dec_tlv_hdr = ath12k_hal_decode_tlv64_hdr,
|
||||
.reo_status_dec_tlv_hdr = ath12k_hal_reo_status_dec_tlv_hdr_qcn9274,
|
||||
.mon_rx_status_dec_tlv_hdr = ath12k_hal_decode_tlv64_hdr,
|
||||
.get_tlv_hdr_align = ath12k_hal_get_tlv64_hdr_align,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -140,6 +140,38 @@ struct rx_mpdu_start_qcn9274 {
|
|||
__le32 res1;
|
||||
} __packed;
|
||||
|
||||
struct rx_mpdu_start_qcc2072 {
|
||||
__le32 info0;
|
||||
__le32 info2;
|
||||
__le32 reo_queue_desc_lo;
|
||||
__le32 info1;
|
||||
__le32 pn[4];
|
||||
__le32 info4;
|
||||
__le32 peer_meta_data;
|
||||
__le16 ast_index;
|
||||
__le16 sw_peer_id;
|
||||
__le16 info3;
|
||||
__le16 phy_ppdu_id;
|
||||
__le32 info5;
|
||||
__le32 info6;
|
||||
__le16 frame_ctrl;
|
||||
__le16 duration;
|
||||
u8 addr1[ETH_ALEN];
|
||||
u8 addr2[ETH_ALEN];
|
||||
u8 addr3[ETH_ALEN];
|
||||
__le16 seq_ctrl;
|
||||
u8 addr4[ETH_ALEN];
|
||||
__le16 qos_ctrl;
|
||||
__le32 ht_ctrl;
|
||||
__le32 info7;
|
||||
__le32 res0;
|
||||
__le32 res1;
|
||||
__le32 res2;
|
||||
__le32 info8;
|
||||
__le32 res3;
|
||||
__le32 res4;
|
||||
} __packed;
|
||||
|
||||
#define QCN9274_MPDU_START_SELECT_MPDU_START_TAG BIT(0)
|
||||
#define QCN9274_MPDU_START_SELECT_INFO0_REO_QUEUE_DESC_LO BIT(1)
|
||||
#define QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 BIT(2)
|
||||
|
|
@ -1492,7 +1524,7 @@ struct hal_rx_desc_qcc2072 {
|
|||
struct rx_msdu_end_qcn9274 msdu_end;
|
||||
u8 rx_padding0[RX_BE_PADDING0_BYTES];
|
||||
__le32 mpdu_start_tag;
|
||||
struct rx_mpdu_start_qcn9274 mpdu_start;
|
||||
struct rx_mpdu_start_qcc2072 mpdu_start;
|
||||
struct rx_pkt_hdr_tlv_qcc2072 pkt_hdr_tlv;
|
||||
u8 msdu_payload[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -756,6 +756,15 @@ int ath12k_hal_srng_create_config_wcn7850(struct ath12k_hal *hal)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u16 ath12k_hal_reo_status_dec_tlv_hdr_wcn7850(void *tlv, void **desc)
|
||||
{
|
||||
u16 tag;
|
||||
|
||||
*desc = ath12k_hal_decode_tlv64_hdr(tlv, &tag, NULL, NULL);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
const struct ath12k_hal_tcl_to_wbm_rbm_map
|
||||
ath12k_hal_tcl_to_wbm_rbm_map_wcn7850[DP_TCL_NUM_RING_MAX] = {
|
||||
{
|
||||
|
|
@ -821,5 +830,7 @@ const struct hal_ops hal_wcn7850_ops = {
|
|||
.rx_msdu_list_get = ath12k_wifi7_hal_rx_msdu_list_get,
|
||||
.rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get,
|
||||
.reo_cmd_enc_tlv_hdr = ath12k_hal_encode_tlv64_hdr,
|
||||
.reo_status_dec_tlv_hdr = ath12k_hal_decode_tlv64_hdr,
|
||||
.reo_status_dec_tlv_hdr = ath12k_hal_reo_status_dec_tlv_hdr_wcn7850,
|
||||
.mon_rx_status_dec_tlv_hdr = ath12k_hal_decode_tlv64_hdr,
|
||||
.get_tlv_hdr_align = ath12k_hal_get_tlv64_hdr_align,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_AP_VLAN),
|
||||
.supports_monitor = false,
|
||||
.supports_cong_ctrl_max_msdus = true,
|
||||
|
||||
.idle_ps = false,
|
||||
.download_calib = true,
|
||||
|
|
@ -480,6 +481,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO),
|
||||
.supports_monitor = true,
|
||||
.supports_cong_ctrl_max_msdus = false,
|
||||
|
||||
.idle_ps = true,
|
||||
.download_calib = false,
|
||||
|
|
@ -568,6 +570,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_AP_VLAN),
|
||||
.supports_monitor = true,
|
||||
.supports_cong_ctrl_max_msdus = true,
|
||||
|
||||
.idle_ps = false,
|
||||
.download_calib = true,
|
||||
|
|
@ -654,6 +657,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT),
|
||||
.supports_monitor = true,
|
||||
.supports_cong_ctrl_max_msdus = true,
|
||||
|
||||
.idle_ps = false,
|
||||
.download_calib = true,
|
||||
|
|
@ -689,7 +693,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
|
||||
.ce_ie_addr = &ath12k_wifi7_ce_ie_addr_ipq5332,
|
||||
.ce_remap = &ath12k_wifi7_ce_remap_ipq5332,
|
||||
.bdf_addr_offset = 0xC00000,
|
||||
.bdf_addr_offset = 0x1A00000,
|
||||
|
||||
.dp_primary_link_only = true,
|
||||
.client = {
|
||||
|
|
@ -738,6 +742,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO),
|
||||
.supports_monitor = true,
|
||||
.supports_cong_ctrl_max_msdus = false,
|
||||
|
||||
.idle_ps = true,
|
||||
.download_calib = false,
|
||||
|
|
@ -826,6 +831,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT),
|
||||
.supports_monitor = true,
|
||||
.supports_cong_ctrl_max_msdus = true,
|
||||
|
||||
.idle_ps = false,
|
||||
.download_calib = true,
|
||||
|
|
@ -903,6 +909,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
|
|||
struct ethhdr *eth;
|
||||
bool is_prb_rsp;
|
||||
u16 mcbc_gsn;
|
||||
u8 cb_flags;
|
||||
u8 link_id;
|
||||
int ret;
|
||||
struct ath12k_dp *tmp_dp;
|
||||
|
|
@ -996,8 +1003,13 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
|
|||
ieee80211_has_protected(hdr->frame_control))
|
||||
is_dvlan = true;
|
||||
|
||||
/*
|
||||
* Add a sta pointer check to differentiate multicast encapsulation
|
||||
* offload packets, as the ATH12K_SKB_HW_80211_ENCAP flag is also set
|
||||
* for such packets.
|
||||
*/
|
||||
if (!vif->valid_links || !is_mcast || is_dvlan ||
|
||||
(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
|
||||
((skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && sta) ||
|
||||
test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
|
||||
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast);
|
||||
if (unlikely(ret)) {
|
||||
|
|
@ -1009,6 +1021,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
|
|||
mcbc_gsn = atomic_inc_return(&ahvif->dp_vif.mcbc_gsn) & 0xfff;
|
||||
|
||||
links_map = ahvif->links_map;
|
||||
cb_flags = skb_cb->flags;
|
||||
for_each_set_bit(link_id, &links_map,
|
||||
IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
tmp_arvif = rcu_dereference(ahvif->link[link_id]);
|
||||
|
|
@ -1016,21 +1029,49 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
|
|||
continue;
|
||||
|
||||
tmp_ar = tmp_arvif->ar;
|
||||
tmp_dp_pdev = ath12k_dp_to_pdev_dp(tmp_ar->ab->dp,
|
||||
tmp_dp = ath12k_ab_to_dp(tmp_ar->ab);
|
||||
tmp_dp_pdev = ath12k_dp_to_pdev_dp(tmp_dp,
|
||||
tmp_ar->pdev_idx);
|
||||
if (!tmp_dp_pdev)
|
||||
continue;
|
||||
msdu_copied = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!msdu_copied) {
|
||||
ath12k_err(ar->ab,
|
||||
"skb copy failure link_id 0x%X vdevid 0x%X\n",
|
||||
link_id, tmp_arvif->vdev_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
ath12k_mlo_mcast_update_tx_link_address(vif, link_id,
|
||||
msdu_copied,
|
||||
info_flags);
|
||||
if (cb_flags & ATH12K_SKB_HW_80211_ENCAP) {
|
||||
/*
|
||||
* skb->data may be modified for the
|
||||
* iova_mask devices. It is better to
|
||||
* use skb_copy() for such devices to
|
||||
* avoid any potential skb corruption
|
||||
* related issues.
|
||||
*/
|
||||
if (tmp_dp->hw_params->iova_mask) {
|
||||
msdu_copied = skb_copy(skb, GFP_ATOMIC);
|
||||
} else {
|
||||
/*
|
||||
* ath12k_wifi7_dp_tx() should
|
||||
* treat cloned HW-encap Ethernet
|
||||
* multicast frames as read-only.
|
||||
*/
|
||||
msdu_copied = skb_clone(skb, GFP_ATOMIC);
|
||||
}
|
||||
if (!msdu_copied) {
|
||||
ath12k_err(ar->ab,
|
||||
"skb copy/clone failure link_id 0x%X vdevid 0x%X\n",
|
||||
link_id, tmp_arvif->vdev_id);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
msdu_copied = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!msdu_copied) {
|
||||
ath12k_err(ar->ab,
|
||||
"skb copy failure link_id 0x%X vdevid 0x%X\n",
|
||||
link_id, tmp_arvif->vdev_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
ath12k_mlo_mcast_update_tx_link_address(vif, link_id,
|
||||
msdu_copied,
|
||||
info_flags);
|
||||
}
|
||||
|
||||
skb_cb = ATH12K_SKB_CB(msdu_copied);
|
||||
skb_cb->link_id = link_id;
|
||||
|
|
@ -1046,7 +1087,6 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
|
|||
if (unlikely(!ahvif->dp_vif.key_cipher))
|
||||
goto skip_peer_find;
|
||||
|
||||
tmp_dp = ath12k_ab_to_dp(tmp_ar->ab);
|
||||
spin_lock_bh(&tmp_dp->dp_lock);
|
||||
peer = ath12k_dp_link_peer_find_by_addr(tmp_dp,
|
||||
tmp_arvif->bssid);
|
||||
|
|
@ -1065,11 +1105,16 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
|
|||
skb_cb->cipher = key->cipher;
|
||||
skb_cb->flags |= ATH12K_SKB_CIPHER_SET;
|
||||
|
||||
if (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP)
|
||||
goto skip_fctl_protected_check;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)msdu_copied->data;
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
hdr->frame_control |=
|
||||
cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
skip_fctl_protected_check:
|
||||
spin_unlock_bh(&tmp_dp->dp_lock);
|
||||
|
||||
skip_peer_find:
|
||||
|
|
|
|||
|
|
@ -1228,10 +1228,16 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
|
|||
le32_encode_bits(arg->ml.mcast_link,
|
||||
ATH12K_WMI_FLAG_MLO_MCAST_VDEV) |
|
||||
le32_encode_bits(arg->ml.link_add,
|
||||
ATH12K_WMI_FLAG_MLO_LINK_ADD);
|
||||
ATH12K_WMI_FLAG_MLO_LINK_ADD) |
|
||||
le32_encode_bits(arg->ml.assoc_link,
|
||||
ATH12K_WMI_FLAG_MLO_START_AS_ACTIVE) |
|
||||
cpu_to_le32(ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID);
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %d start ml flags 0x%x\n",
|
||||
arg->vdev_id, ml_params->flags);
|
||||
ml_params->ieee_link_id = cpu_to_le32(arg->ml.ieee_link_id);
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %u start link_id %u ml flags 0x%x\n",
|
||||
arg->vdev_id, arg->ml.ieee_link_id,
|
||||
le32_to_cpu(ml_params->flags));
|
||||
|
||||
ptr += sizeof(*ml_params);
|
||||
|
||||
|
|
@ -1244,19 +1250,23 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
|
|||
partner_info = ptr;
|
||||
|
||||
for (i = 0; i < arg->ml.num_partner_links; i++) {
|
||||
struct wmi_ml_partner_info *pinfo = &arg->ml.partner_info[i];
|
||||
|
||||
partner_info->tlv_header =
|
||||
ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PARTNER_LINK_PARAMS,
|
||||
sizeof(*partner_info));
|
||||
partner_info->vdev_id =
|
||||
cpu_to_le32(arg->ml.partner_info[i].vdev_id);
|
||||
partner_info->hw_link_id =
|
||||
cpu_to_le32(arg->ml.partner_info[i].hw_link_id);
|
||||
partner_info->vdev_id = cpu_to_le32(pinfo->vdev_id);
|
||||
partner_info->hw_link_id = cpu_to_le32(pinfo->hw_link_id);
|
||||
ether_addr_copy(partner_info->vdev_addr.addr,
|
||||
arg->ml.partner_info[i].addr);
|
||||
pinfo->addr);
|
||||
partner_info->flags =
|
||||
cpu_to_le32(ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID_PARTNER);
|
||||
partner_info->ieee_link_id = cpu_to_le32(pinfo->ieee_link_id);
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "partner vdev %d hw_link_id %d macaddr%pM\n",
|
||||
partner_info->vdev_id, partner_info->hw_link_id,
|
||||
partner_info->vdev_addr.addr);
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "partner vdev %u hw_link_id %u macaddr %pM link_id %u ml flags 0x%x\n",
|
||||
pinfo->vdev_id, pinfo->hw_link_id,
|
||||
pinfo->addr, pinfo->ieee_link_id,
|
||||
le32_to_cpu(partner_info->flags));
|
||||
|
||||
partner_info++;
|
||||
}
|
||||
|
|
@ -2629,9 +2639,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
|
|||
struct wmi_tlv *tlv;
|
||||
void *ptr;
|
||||
int i, ret, len;
|
||||
u32 *tmp_ptr, extraie_len_with_pad = 0;
|
||||
struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
|
||||
struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
|
||||
__le32 *tmp_ptr;
|
||||
u32 extraie_len_with_pad = 0;
|
||||
struct ath12k_wmi_hint_short_ssid_params *s_ssid = NULL;
|
||||
struct ath12k_wmi_hint_bssid_params *hint_bssid = NULL;
|
||||
|
||||
len = sizeof(*cmd);
|
||||
|
||||
|
|
@ -2714,9 +2725,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
|
|||
tlv = ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
|
||||
ptr += TLV_HDR_SIZE;
|
||||
tmp_ptr = (u32 *)ptr;
|
||||
tmp_ptr = (__le32 *)ptr;
|
||||
|
||||
memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
|
||||
for (i = 0; i < arg->num_chan; i++)
|
||||
tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
|
||||
|
||||
ptr += len;
|
||||
|
||||
|
|
@ -2772,8 +2784,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
|
|||
ptr += TLV_HDR_SIZE;
|
||||
s_ssid = ptr;
|
||||
for (i = 0; i < arg->num_hint_s_ssid; ++i) {
|
||||
s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;
|
||||
s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;
|
||||
s_ssid->freq_flags =
|
||||
cpu_to_le32(arg->hint_s_ssid[i].freq_flags);
|
||||
s_ssid->short_ssid =
|
||||
cpu_to_le32(arg->hint_s_ssid[i].short_ssid);
|
||||
s_ssid++;
|
||||
}
|
||||
ptr += len;
|
||||
|
|
@ -2787,9 +2801,9 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
|
|||
hint_bssid = ptr;
|
||||
for (i = 0; i < arg->num_hint_bssid; ++i) {
|
||||
hint_bssid->freq_flags =
|
||||
arg->hint_bssid[i].freq_flags;
|
||||
ether_addr_copy(&arg->hint_bssid[i].bssid.addr[0],
|
||||
&hint_bssid->bssid.addr[0]);
|
||||
cpu_to_le32(arg->hint_bssid[i].freq_flags);
|
||||
ether_addr_copy(&hint_bssid->bssid.addr[0],
|
||||
&arg->hint_bssid[i].bssid.addr[0]);
|
||||
hint_bssid++;
|
||||
}
|
||||
}
|
||||
|
|
@ -5154,6 +5168,7 @@ static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
|
|||
__le32 cap_info_internal)
|
||||
{
|
||||
struct ath12k_band_cap *cap_band = &pdev->cap.band[band];
|
||||
u8 *phy_cap = (u8 *)&cap_band->eht_cap_phy_info[0];
|
||||
u32 support_320mhz;
|
||||
u8 i;
|
||||
|
||||
|
|
@ -5167,8 +5182,22 @@ static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
|
|||
for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++)
|
||||
cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]);
|
||||
|
||||
if (band == NL80211_BAND_6GHZ)
|
||||
if (band == NL80211_BAND_6GHZ) {
|
||||
cap_band->eht_cap_phy_info[0] |= support_320mhz;
|
||||
} else {
|
||||
/*
|
||||
* Firmware may report 6 GHz/320 MHz specific capabilities for
|
||||
* non-6 GHz bands, so explicitly clear them.
|
||||
*/
|
||||
phy_cap[0] &= ~IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
|
||||
phy_cap[1] &= ~IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK;
|
||||
phy_cap[2] &= ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK;
|
||||
phy_cap[3] &= ~IEEE80211_EHT_PHY_CAP3_SOUNDING_DIM_320MHZ_MASK;
|
||||
phy_cap[6] &= ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ;
|
||||
phy_cap[6] &= ~IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP;
|
||||
phy_cap[7] &= ~IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ;
|
||||
phy_cap[7] &= ~IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
|
||||
}
|
||||
|
||||
cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]);
|
||||
cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]);
|
||||
|
|
@ -6713,16 +6742,12 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int freq_to_idx(struct ath12k *ar, int freq)
|
||||
static int freq_to_idx(struct ieee80211_hw *hw, int freq)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
|
||||
int band, ch, idx = 0;
|
||||
|
||||
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
|
||||
if (!ar->mac.sbands[band].channels)
|
||||
continue;
|
||||
|
||||
sband = hw->wiphy->bands[band];
|
||||
if (!sband)
|
||||
continue;
|
||||
|
|
@ -7072,25 +7097,29 @@ static void ath12k_peer_delete_resp_event(struct ath12k_base *ab, struct sk_buff
|
|||
{
|
||||
struct wmi_peer_delete_resp_event peer_del_resp;
|
||||
struct ath12k *ar;
|
||||
u32 vdev_id;
|
||||
|
||||
if (ath12k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) {
|
||||
ath12k_warn(ab, "failed to extract peer delete resp");
|
||||
ath12k_warn(ab, "failed to extract peer delete resp\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vdev_id = le32_to_cpu(peer_del_resp.vdev_id);
|
||||
|
||||
rcu_read_lock();
|
||||
ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(peer_del_resp.vdev_id));
|
||||
ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
|
||||
if (!ar) {
|
||||
ath12k_warn(ab, "invalid vdev id in peer delete resp ev %d",
|
||||
peer_del_resp.vdev_id);
|
||||
ath12k_warn(ab, "invalid vdev id in peer delete resp ev %d\n",
|
||||
vdev_id);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
complete(&ar->peer_delete_done);
|
||||
ath12k_peer_delete_resp_signal(ar, vdev_id,
|
||||
peer_del_resp.peer_macaddr.addr);
|
||||
rcu_read_unlock();
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n",
|
||||
peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr);
|
||||
vdev_id, peer_del_resp.peer_macaddr.addr);
|
||||
}
|
||||
|
||||
static void ath12k_vdev_delete_resp_event(struct ath12k_base *ab,
|
||||
|
|
@ -7629,6 +7658,7 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
{
|
||||
struct wmi_chan_info_event ch_info_ev = {};
|
||||
struct ath12k *ar;
|
||||
struct ath12k_hw *ah;
|
||||
struct survey_info *survey;
|
||||
int idx;
|
||||
/* HW channel counters frequency value in hertz */
|
||||
|
|
@ -7660,6 +7690,7 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ah = ath12k_ar_to_ah(ar);
|
||||
|
||||
switch (ar->scan.state) {
|
||||
case ATH12K_SCAN_IDLE:
|
||||
|
|
@ -7671,8 +7702,8 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
break;
|
||||
}
|
||||
|
||||
idx = freq_to_idx(ar, le32_to_cpu(ch_info_ev.freq));
|
||||
if (idx >= ARRAY_SIZE(ar->survey)) {
|
||||
idx = freq_to_idx(ath12k_ar_to_hw(ar), le32_to_cpu(ch_info_ev.freq));
|
||||
if (idx >= ARRAY_SIZE(ah->survey)) {
|
||||
ath12k_warn(ab, "chan info: invalid frequency %d (idx %d out of bounds)\n",
|
||||
ch_info_ev.freq, idx);
|
||||
goto exit;
|
||||
|
|
@ -7685,14 +7716,20 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
cc_freq_hz = (le32_to_cpu(ch_info_ev.mac_clk_mhz) * 1000);
|
||||
|
||||
if (ch_info_ev.cmd_flags == WMI_CHAN_INFO_START_RESP) {
|
||||
survey = &ar->survey[idx];
|
||||
memset(survey, 0, sizeof(*survey));
|
||||
survey->noise = le32_to_cpu(ch_info_ev.noise_floor);
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY;
|
||||
survey->time = div_u64(le32_to_cpu(ch_info_ev.cycle_count), cc_freq_hz);
|
||||
survey->time_busy = div_u64(le32_to_cpu(ch_info_ev.rx_clear_count),
|
||||
cc_freq_hz);
|
||||
scoped_guard(spinlock_bh, &ah->survey_lock) {
|
||||
survey = &ah->survey[idx];
|
||||
memset(survey, 0, sizeof(*survey));
|
||||
survey->noise = le32_to_cpu(ch_info_ev.noise_floor);
|
||||
survey->time =
|
||||
div_u64(le32_to_cpu(ch_info_ev.cycle_count),
|
||||
cc_freq_hz);
|
||||
survey->time_busy =
|
||||
div_u64(le32_to_cpu(ch_info_ev.rx_clear_count),
|
||||
cc_freq_hz);
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM |
|
||||
SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
|
@ -7705,6 +7742,7 @@ ath12k_pdev_bss_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
struct wmi_pdev_bss_chan_info_event bss_ch_info_ev = {};
|
||||
struct survey_info *survey;
|
||||
struct ath12k *ar;
|
||||
struct ath12k_hw *ah;
|
||||
u32 cc_freq_hz = ab->cc_freq_hz;
|
||||
u64 busy, total, tx, rx, rx_bss;
|
||||
int idx;
|
||||
|
|
@ -7745,28 +7783,31 @@ ath12k_pdev_bss_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
idx = freq_to_idx(ar, le32_to_cpu(bss_ch_info_ev.freq));
|
||||
if (idx >= ARRAY_SIZE(ar->survey)) {
|
||||
ah = ath12k_ar_to_ah(ar);
|
||||
|
||||
idx = freq_to_idx(ath12k_ar_to_hw(ar), le32_to_cpu(bss_ch_info_ev.freq));
|
||||
if (idx >= ARRAY_SIZE(ah->survey)) {
|
||||
ath12k_warn(ab, "bss chan info: invalid frequency %d (idx %d out of bounds)\n",
|
||||
bss_ch_info_ev.freq, idx);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
survey = &ar->survey[idx];
|
||||
scoped_guard(spinlock_bh, &ah->survey_lock) {
|
||||
survey = &ah->survey[idx];
|
||||
|
||||
survey->noise = le32_to_cpu(bss_ch_info_ev.noise_floor);
|
||||
survey->time = div_u64(total, cc_freq_hz);
|
||||
survey->time_busy = div_u64(busy, cc_freq_hz);
|
||||
survey->time_rx = div_u64(rx_bss, cc_freq_hz);
|
||||
survey->time_tx = div_u64(tx, cc_freq_hz);
|
||||
survey->filled |= (SURVEY_INFO_NOISE_DBM |
|
||||
SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_TX);
|
||||
}
|
||||
|
||||
survey->noise = le32_to_cpu(bss_ch_info_ev.noise_floor);
|
||||
survey->time = div_u64(total, cc_freq_hz);
|
||||
survey->time_busy = div_u64(busy, cc_freq_hz);
|
||||
survey->time_rx = div_u64(rx_bss, cc_freq_hz);
|
||||
survey->time_tx = div_u64(tx, cc_freq_hz);
|
||||
survey->filled |= (SURVEY_INFO_NOISE_DBM |
|
||||
SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_TX);
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
complete(&ar->bss_survey_done);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
|
@ -10257,12 +10298,12 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
struct wmi_cmd_hdr *cmd_hdr;
|
||||
enum wmi_tlv_event_id id;
|
||||
|
||||
cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
|
||||
id = le32_get_bits(cmd_hdr->cmd_id, WMI_CMD_HDR_CMD_ID);
|
||||
|
||||
if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr)))
|
||||
cmd_hdr = skb_pull_data(skb, sizeof(*cmd_hdr));
|
||||
if (!cmd_hdr)
|
||||
goto out;
|
||||
|
||||
id = le32_get_bits(cmd_hdr->cmd_id, WMI_CMD_HDR_CMD_ID);
|
||||
|
||||
switch (id) {
|
||||
/* Process all the WMI events here */
|
||||
case WMI_SERVICE_READY_EVENTID:
|
||||
|
|
|
|||
|
|
@ -1083,6 +1083,7 @@ enum wmi_tlv_pdev_param {
|
|||
WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE,
|
||||
WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE,
|
||||
WMI_PDEV_PARAM_MESH_MCAST_ENABLE,
|
||||
WMI_PDEV_PARAM_SET_CONG_CTRL_MAX_MSDUS = 0xa6,
|
||||
WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD = 0xbc,
|
||||
WMI_PDEV_PARAM_SET_CMD_OBSS_PD_PER_AC = 0xbe,
|
||||
WMI_PDEV_PARAM_ENABLE_SR_PROHIBIT = 0xc6,
|
||||
|
|
@ -2330,6 +2331,13 @@ enum wmi_slot_time {
|
|||
WMI_VDEV_SLOT_TIME_SHORT = 2,
|
||||
};
|
||||
|
||||
enum wmi_dtim_policy {
|
||||
WMI_DTIM_POLICY_IGNORE = 1,
|
||||
WMI_DTIM_POLICY_NORMAL = 2,
|
||||
WMI_DTIM_POLICY_STICK = 3,
|
||||
WMI_DTIM_POLICY_AUTO = 4,
|
||||
};
|
||||
|
||||
enum wmi_preamble {
|
||||
WMI_VDEV_PREAMBLE_LONG = 1,
|
||||
WMI_VDEV_PREAMBLE_SHORT = 2,
|
||||
|
|
@ -2954,10 +2962,14 @@ struct wmi_vdev_create_mlo_params {
|
|||
#define ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT BIT(6)
|
||||
#define ATH12K_WMI_FLAG_MLO_FORCED_INACTIVE BIT(7)
|
||||
#define ATH12K_WMI_FLAG_MLO_LINK_ADD BIT(8)
|
||||
#define ATH12K_WMI_FLAG_MLO_START_AS_ACTIVE BIT(17)
|
||||
#define ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID BIT(18)
|
||||
#define ATH12K_WMI_FLAG_MLO_IEEE_LINK_IDX_VALID_PARTNER BIT(19)
|
||||
|
||||
struct wmi_vdev_start_mlo_params {
|
||||
__le32 tlv_header;
|
||||
__le32 flags;
|
||||
__le32 ieee_link_id;
|
||||
} __packed;
|
||||
|
||||
struct wmi_partner_link_info {
|
||||
|
|
@ -2965,6 +2977,8 @@ struct wmi_partner_link_info {
|
|||
__le32 vdev_id;
|
||||
__le32 hw_link_id;
|
||||
struct ath12k_wmi_mac_addr_params vdev_addr;
|
||||
__le32 flags;
|
||||
__le32 ieee_link_id;
|
||||
} __packed;
|
||||
|
||||
struct wmi_vdev_delete_cmd {
|
||||
|
|
@ -3120,6 +3134,7 @@ struct wmi_ml_partner_info {
|
|||
bool primary_umac;
|
||||
bool logical_link_idx_valid;
|
||||
u32 logical_link_idx;
|
||||
u32 ieee_link_id;
|
||||
};
|
||||
|
||||
struct wmi_ml_arg {
|
||||
|
|
@ -3127,6 +3142,7 @@ struct wmi_ml_arg {
|
|||
bool assoc_link;
|
||||
bool mcast_link;
|
||||
bool link_add;
|
||||
u32 ieee_link_id;
|
||||
u8 num_partner_links;
|
||||
struct wmi_ml_partner_info partner_info[ATH12K_WMI_MLO_MAX_LINKS];
|
||||
};
|
||||
|
|
@ -3549,6 +3565,16 @@ struct ath12k_wmi_hint_bssid_arg {
|
|||
struct ath12k_wmi_mac_addr_params bssid;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_hint_short_ssid_params {
|
||||
__le32 freq_flags;
|
||||
__le32 short_ssid;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_hint_bssid_params {
|
||||
__le32 freq_flags;
|
||||
struct ath12k_wmi_mac_addr_params bssid;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_scan_req_arg {
|
||||
u32 scan_id;
|
||||
u32 scan_req_id;
|
||||
|
|
|
|||
|
|
@ -3437,7 +3437,7 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct cfg80211_ops ath6kl_cfg80211_ops = {
|
||||
static const struct cfg80211_ops ath6kl_cfg80211_ops = {
|
||||
.add_virtual_intf = ath6kl_cfg80211_add_iface,
|
||||
.del_virtual_intf = ath6kl_cfg80211_del_iface,
|
||||
.change_virtual_intf = ath6kl_cfg80211_change_iface,
|
||||
|
|
|
|||
|
|
@ -1276,6 +1276,9 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len,
|
|||
{
|
||||
struct wmi_scan_complete_event *ev;
|
||||
|
||||
if (len < sizeof(*ev))
|
||||
return -EINVAL;
|
||||
|
||||
ev = (struct wmi_scan_complete_event *) datap;
|
||||
|
||||
ath6kl_scan_complete_evt(vif, a_sle32_to_cpu(ev->status));
|
||||
|
|
@ -3352,7 +3355,12 @@ static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
|
|||
static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
struct ath6kl_vif *vif)
|
||||
{
|
||||
struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;
|
||||
struct wmi_addba_req_event *cmd;
|
||||
|
||||
if (len < sizeof(*cmd))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = (struct wmi_addba_req_event *)datap;
|
||||
|
||||
aggr_recv_addba_req_evt(vif, cmd->tid,
|
||||
le16_to_cpu(cmd->st_seq_no), cmd->win_sz);
|
||||
|
|
@ -3363,7 +3371,12 @@ static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
|
|||
static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
struct ath6kl_vif *vif)
|
||||
{
|
||||
struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;
|
||||
struct wmi_delba_event *cmd;
|
||||
|
||||
if (len < sizeof(*cmd))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = (struct wmi_delba_event *)datap;
|
||||
|
||||
aggr_recv_delba_req_evt(vif, cmd->tid);
|
||||
|
||||
|
|
|
|||
|
|
@ -381,6 +381,7 @@ struct ar9170 {
|
|||
unsigned int tx_ack_failures;
|
||||
unsigned int tx_fcs_errors;
|
||||
unsigned int rx_dropped;
|
||||
unsigned int rx_phy_errors;
|
||||
|
||||
/* EEPROM */
|
||||
struct ar9170_eeprom eeprom;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
|
|||
(u8 *) buf, 0, NULL);
|
||||
if (err) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "writing reg %#x "
|
||||
wiphy_dbg(ar->hw->wiphy, "writing reg %#x "
|
||||
"(val %#x) failed (%d)\n", reg, val, err);
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
|
|||
4 * nregs, (u8 *)res);
|
||||
if (err) {
|
||||
if (net_ratelimit()) {
|
||||
wiphy_err(ar->hw->wiphy, "reading regs failed (%d)\n",
|
||||
wiphy_dbg(ar->hw->wiphy, "reading regs failed (%d)\n",
|
||||
err);
|
||||
}
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -794,6 +794,7 @@ DEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago",
|
|||
DEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped);
|
||||
|
||||
DEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped);
|
||||
DEBUGFS_READONLY_FILE(rx_phy_errors, 20, "%d", ar->rx_phy_errors);
|
||||
|
||||
DEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled);
|
||||
DEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d",
|
||||
|
|
@ -830,6 +831,7 @@ void carl9170_debugfs_register(struct ar9170 *ar)
|
|||
DEBUGFS_ADD(tx_ampdu_list_len);
|
||||
|
||||
DEBUGFS_ADD(rx_dropped);
|
||||
DEBUGFS_ADD(rx_phy_errors);
|
||||
DEBUGFS_ADD(sniffer_enabled);
|
||||
DEBUGFS_ADD(rx_software_decryption);
|
||||
|
||||
|
|
|
|||
|
|
@ -908,7 +908,13 @@ static int carl9170_op_config(struct ieee80211_hw *hw, int radio_idx, u32 change
|
|||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_SMPS) {
|
||||
/* TODO */
|
||||
/*
|
||||
* We advertise SM_PS disabled (all chains active).
|
||||
* mac80211 may still request mode changes, which we
|
||||
* accept but only support OFF (both chains active).
|
||||
* Static/dynamic SMPS would require firmware support
|
||||
* for chain control that the AR9170 does not provide.
|
||||
*/
|
||||
err = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -455,7 +455,9 @@ static void carl9170_rx_phy_status(struct ar9170 *ar,
|
|||
if (phy->rssi[i] & 0x80)
|
||||
phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
|
||||
|
||||
/* TODO: we could do something with phy_errors */
|
||||
if (phy->phy_err)
|
||||
ar->rx_phy_errors++;
|
||||
|
||||
status->signal = ar->noise[0] + phy->rssi_combined;
|
||||
}
|
||||
|
||||
|
|
|
|||
43
include/linux/firmware/qcom/qcom_pas.h
Normal file
43
include/linux/firmware/qcom/qcom_pas.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2015 Linaro Ltd.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef __QCOM_PAS_H
|
||||
#define __QCOM_PAS_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct qcom_pas_context {
|
||||
struct device *dev;
|
||||
u32 pas_id;
|
||||
phys_addr_t mem_phys;
|
||||
size_t mem_size;
|
||||
void *ptr;
|
||||
dma_addr_t phys;
|
||||
ssize_t size;
|
||||
bool use_tzmem;
|
||||
};
|
||||
|
||||
bool qcom_pas_is_available(void);
|
||||
struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
|
||||
u32 pas_id,
|
||||
phys_addr_t mem_phys,
|
||||
size_t mem_size);
|
||||
int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
||||
struct qcom_pas_context *ctx);
|
||||
struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
|
||||
void *input_rt, size_t input_rt_size,
|
||||
size_t *output_rt_size);
|
||||
int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size);
|
||||
int qcom_pas_auth_and_reset(u32 pas_id);
|
||||
int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx);
|
||||
int qcom_pas_set_remote_state(u32 state, u32 pas_id);
|
||||
int qcom_pas_shutdown(u32 pas_id);
|
||||
bool qcom_pas_supported(u32 pas_id);
|
||||
void qcom_pas_metadata_release(struct qcom_pas_context *ctx);
|
||||
|
||||
#endif /* __QCOM_PAS_H */
|
||||
|
|
@ -171,6 +171,7 @@ int irq_can_set_affinity(unsigned int irq)
|
|||
{
|
||||
return __irq_can_set_affinity(irq_to_desc(irq));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_can_set_affinity);
|
||||
|
||||
/**
|
||||
* irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user