Add 'qcom/opensource/wlan/qca-wifi-host-cmn/' from commit 'fec800ab539956671af604bdd6e1ee3b84eef491'

git-subtree-dir: qcom/opensource/wlan/qca-wifi-host-cmn
git-subtree-mainline: 5add812a59
git-subtree-split: fec800ab53
Change-Id:
repo: https://git.codelinaro.org/clo/la/platform/vendor/qcom-opensource/wlan/qca-wifi-host-cmn
tag: LA.VENDOR.14.3.0.r1-17300-lanai.QSSI15.0
This commit is contained in:
David Wronek
2024-10-06 16:49:55 +02:00
1248 changed files with 924106 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef EPPING_INTERNAL_H
#define EPPING_INTERNAL_H
/**
* DOC: epping_internal.h
* Linux epping internal head file
*/
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>
#if defined(CONFIG_HAS_WAKELOCK)
#include <linux/wakelock.h>
#endif
#include "htc_api.h"
#include "htc_packet.h"
#include "epping_test.h"
#include <qdf_atomic.h>
#include <sir_mac_prot_def.h>
#include <sir_debug.h>
#define EPPING_LOG_MASK (1<<EPPING_CMD_CAPTURE_RECV_CNT)
#define EPPING_STATS_LOG_COUNT 50000
#define EPPING_KTID_KILL_WAIT_TIME_MS 50
#define EPPING_FRAG_PER_MSDU 1
#ifndef EPPING_TXBUF
#define EPPING_TXBUF (512/EPPING_FRAG_PER_MSDU)
#endif
/*---------------------------------------------------------------------------
Preprocessor definitions and constants
-------------------------------------------------------------------------*/
#define EPPING_MAX_ADAPTERS 1
#define EPPING_LOG(level, args ...) QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args)
#define EPPING_HEX_DUMP(level, data, len) qdf_trace_hex_dump( \
QDF_MODULE_ID_HDD, \
level, \
data, buf_len)
struct epping_cookie {
HTC_PACKET HtcPkt; /* HTC packet wrapper */
struct epping_cookie *next;
};
typedef enum {
EPPING_CTX_STATE_INITIAL = 0,
EPPING_CTX_STATE_HIF_INIT,
EPPING_CTX_STATE_STARTUP,
EPPING_CTX_STATE_STARTED,
EPPING_CTX_STATE_STOP
} epping_ctx_state_t;
#define EPPING_MAX_NUM_EPIDS 4
#define MAX_COOKIE_SLOTS_NUM 4
#define MAX_COOKIE_SLOT_SIZE 512
#define MAX_TX_PKT_DUP_NUM 4
#if defined(HIF_PCI) || defined(HIF_IPCI)
#define WLAN_EPPING_DELAY_TIMEOUT_US 10
#define EPPING_MAX_CE_NUMS 8
#define EPPING_MAX_WATER_MARK 8
typedef struct {
struct task_struct *pid;
void *arg;
bool done;
qdf_nbuf_t skb;
HTC_ENDPOINT_ID eid;
struct semaphore sem;
bool inited;
qdf_atomic_t atm;
} epping_poll_t;
#endif
typedef struct epping_context {
int32_t con_mode;
char *pwlan_module_name;
uint32_t target_type;
void *p_cds_context; /* CDS context */
struct device *parent_dev; /* Pointer to the parent device */
epping_ctx_state_t e_ctx_state;
bool wow_nack;
void *epping_adapter;
HTC_HANDLE HTCHandle;
HTC_ENDPOINT_ID EppingEndpoint[EPPING_MAX_NUM_EPIDS];
unsigned int kperf_num_rx_recv[EPPING_MAX_NUM_EPIDS];
unsigned int kperf_num_tx_acks[EPPING_MAX_NUM_EPIDS];
unsigned int total_rx_recv;
unsigned int total_tx_acks;
#if defined(HIF_PCI) || defined(HIF_IPCI)
epping_poll_t epping_poll[EPPING_MAX_NUM_EPIDS];
#endif
struct epping_cookie *cookie_list;
int cookie_count;
struct epping_cookie *s_cookie_mem[MAX_COOKIE_SLOTS_NUM];
qdf_spinlock_t cookie_lock;
} epping_context_t;
typedef enum {
EPPING_TX_TIMER_STOPPED,
EPPING_TX_TIMER_RUNNING
} epping_tx_timer_state_t;
typedef struct epping_adapter_s {
epping_context_t *pEpping_ctx;
enum QDF_OPMODE device_mode;
/** Handle to the network device */
struct net_device *dev;
struct qdf_mac_addr macAddressCurrent;
uint8_t sessionId;
/* for mboxping */
qdf_spinlock_t data_lock;
qdf_nbuf_queue_t nodrop_queue;
qdf_timer_t epping_timer;
epping_tx_timer_state_t epping_timer_state;
bool registered;
bool started;
struct net_device_stats stats;
} epping_adapter_t;
/* epping_helper signatures */
int epping_cookie_init(epping_context_t *pEpping_ctx);
void epping_cookie_cleanup(epping_context_t *pEpping_ctx);
void epping_free_cookie(epping_context_t *pEpping_ctx,
struct epping_cookie *cookie);
struct epping_cookie *epping_alloc_cookie(epping_context_t *pEpping_ctx);
void epping_get_dummy_mac_addr(tSirMacAddr macAddr);
void epping_hex_dump(void *data, int buf_len, const char *str);
void *epping_get_qdf_ctx(void);
void epping_log_packet(epping_adapter_t *adapter,
EPPING_HEADER *eppingHdr, int ret, const char *str);
void epping_log_stats(epping_adapter_t *adapter, const char *str);
void epping_set_kperf_flag(epping_adapter_t *adapter,
HTC_ENDPOINT_ID eid, uint8_t kperf_flag);
/* epping_tx signatures */
void epping_tx_timer_expire(epping_adapter_t *adapter);
void epping_tx_complete(void *ctx, HTC_PACKET *htc_pkt);
int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *adapter);
#ifdef HIF_SDIO
enum htc_send_full_action epping_tx_queue_full(void *Context,
struct _HTC_PACKET *pPacket);
#endif
void epping_tx_dup_pkt(epping_adapter_t *adapter,
HTC_ENDPOINT_ID eid, qdf_nbuf_t skb);
/* epping_rx signatures */
void epping_rx(void *Context, HTC_PACKET *pPacket);
#ifdef HIF_SDIO
void epping_refill(void *ctx, HTC_ENDPOINT_ID Endpoint);
#endif
/* epping_txrx signatures */
epping_adapter_t *epping_add_adapter(epping_context_t *pEpping_ctx,
tSirMacAddr macAddr,
enum QDF_OPMODE device_mode,
bool rtnl_held);
void epping_destroy_adapter(epping_adapter_t *adapter);
int epping_connect_service(epping_context_t *pEpping_ctx);
#if defined(HIF_PCI) || defined(HIF_IPCI)
void epping_register_tx_copier(HTC_ENDPOINT_ID eid,
epping_context_t *pEpping_ctx);
void epping_unregister_tx_copier(HTC_ENDPOINT_ID eid,
epping_context_t *pEpping_ctx);
void epping_tx_copier_schedule(epping_context_t *pEpping_ctx,
HTC_ENDPOINT_ID eid, qdf_nbuf_t skb);
#endif /* HIF_PCI || HIF_IPCI */
#endif /* end #ifndef EPPING_INTERNAL_H */

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef EPPING_MAIN_H
#define EPPING_MAIN_H
/**===========================================================================
\file epping_main.h
\brief Linux epping head file
==========================================================================*/
/*---------------------------------------------------------------------------
Include files
-------------------------------------------------------------------------*/
#include <qdf_lock.h>
#include <qdf_types.h>
/* epping_main signatures */
#ifdef WLAN_FEATURE_EPPING
int epping_open(void);
void epping_close(void);
void epping_disable(void);
int epping_enable(struct device *parent_dev, bool rtnl_held);
void epping_enable_adapter(void);
#else
static inline int epping_open(void)
{
return QDF_STATUS_E_INVAL;
}
static inline int epping_enable(struct device *parent_dev, bool rtnl_held)
{
return QDF_STATUS_E_INVAL;
}
static inline void epping_close(void) {}
static inline void epping_disable(void) {}
static inline void epping_enable_adapter(void) {}
#endif
#endif /* end #ifndef EPPING_MAIN_H */

View File

@@ -0,0 +1,184 @@
/*
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*========================================================================
\file epping_main.c
\brief WLAN End Point Ping test tool implementation
========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <cds_api.h>
#include <cds_sched.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <wni_api.h>
#include <wlan_ptt_sock_svc.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/rtnetlink.h>
#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include "epping_main.h"
#include "epping_internal.h"
int epping_cookie_init(epping_context_t *pEpping_ctx)
{
uint32_t i, j;
pEpping_ctx->cookie_list = NULL;
pEpping_ctx->cookie_count = 0;
for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) {
pEpping_ctx->s_cookie_mem[i] =
qdf_mem_malloc(sizeof(struct epping_cookie) *
MAX_COOKIE_SLOT_SIZE);
if (!pEpping_ctx->s_cookie_mem[i])
goto error;
}
qdf_spinlock_create(&pEpping_ctx->cookie_lock);
for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) {
struct epping_cookie *cookie_mem = pEpping_ctx->s_cookie_mem[i];
for (j = 0; j < MAX_COOKIE_SLOT_SIZE; j++) {
epping_free_cookie(pEpping_ctx, &cookie_mem[j]);
}
}
return 0;
error:
for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) {
if (pEpping_ctx->s_cookie_mem[i]) {
qdf_mem_free(pEpping_ctx->s_cookie_mem[i]);
pEpping_ctx->s_cookie_mem[i] = NULL;
}
}
return -ENOMEM;
}
/* cleanup cookie queue */
void epping_cookie_cleanup(epping_context_t *pEpping_ctx)
{
int i;
qdf_spin_lock_bh(&pEpping_ctx->cookie_lock);
pEpping_ctx->cookie_list = NULL;
pEpping_ctx->cookie_count = 0;
qdf_spin_unlock_bh(&pEpping_ctx->cookie_lock);
for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) {
if (pEpping_ctx->s_cookie_mem[i]) {
qdf_mem_free(pEpping_ctx->s_cookie_mem[i]);
pEpping_ctx->s_cookie_mem[i] = NULL;
}
}
}
void epping_free_cookie(epping_context_t *pEpping_ctx,
struct epping_cookie *cookie)
{
qdf_spin_lock_bh(&pEpping_ctx->cookie_lock);
cookie->next = pEpping_ctx->cookie_list;
pEpping_ctx->cookie_list = cookie;
pEpping_ctx->cookie_count++;
qdf_spin_unlock_bh(&pEpping_ctx->cookie_lock);
}
struct epping_cookie *epping_alloc_cookie(epping_context_t *pEpping_ctx)
{
struct epping_cookie *cookie;
qdf_spin_lock_bh(&pEpping_ctx->cookie_lock);
cookie = pEpping_ctx->cookie_list;
if (cookie) {
pEpping_ctx->cookie_list = cookie->next;
pEpping_ctx->cookie_count--;
}
qdf_spin_unlock_bh(&pEpping_ctx->cookie_lock);
return cookie;
}
void epping_get_dummy_mac_addr(tSirMacAddr macAddr)
{
macAddr[0] = 69; /* E */
macAddr[1] = 80; /* P */
macAddr[2] = 80; /* P */
macAddr[3] = 73; /* I */
macAddr[4] = 78; /* N */
macAddr[5] = 71; /* G */
}
void epping_hex_dump(void *data, int buf_len, const char *str)
{
EPPING_LOG(QDF_TRACE_LEVEL_FATAL, "%s: E, %s", __func__, str);
EPPING_HEX_DUMP(QDF_TRACE_LEVEL_INFO, data, buf_len);
EPPING_LOG(QDF_TRACE_LEVEL_FATAL, "%s: X %s", __func__, str);
}
void *epping_get_qdf_ctx(void)
{
qdf_device_t *qdf_ctx;
qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
return qdf_ctx;
}
void epping_log_packet(epping_adapter_t *adapter,
EPPING_HEADER *eppingHdr, int ret, const char *str)
{
if (eppingHdr->Cmd_h & EPPING_LOG_MASK) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: cmd = %d, seqNo = %u, flag = 0x%x, ret = %d, "
"txCount = %lu, txDrop = %lu, txBytes = %lu,"
"rxCount = %lu, rxDrop = %lu, rxBytes = %lu\n",
str, eppingHdr->Cmd_h, eppingHdr->SeqNo,
eppingHdr->CmdFlags_h, ret,
adapter->stats.tx_packets,
adapter->stats.tx_dropped,
adapter->stats.tx_bytes,
adapter->stats.rx_packets,
adapter->stats.rx_dropped,
adapter->stats.rx_bytes);
}
}
void epping_log_stats(epping_adapter_t *adapter, const char *str)
{
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: txCount = %lu, txDrop = %lu, tx_bytes = %lu, "
"rxCount = %lu, rxDrop = %lu, rx_bytes = %lu, tx_acks = %u\n",
str,
adapter->stats.tx_packets,
adapter->stats.tx_dropped,
adapter->stats.tx_bytes,
adapter->stats.rx_packets,
adapter->stats.rx_dropped,
adapter->stats.rx_bytes,
adapter->pEpping_ctx->total_tx_acks);
}
void epping_set_kperf_flag(epping_adapter_t *adapter,
HTC_ENDPOINT_ID eid, uint8_t kperf_flag)
{
adapter->pEpping_ctx->kperf_num_rx_recv[eid] = 0;
adapter->pEpping_ctx->kperf_num_tx_acks[eid] = 0;
}

View File

@@ -0,0 +1,371 @@
/*
* Copyright (c) 2014-2019,2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*========================================================================
\file epping_main.c
\brief WLAN End Point Ping test tool implementation
========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <cds_api.h>
#include <cds_sched.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <wni_api.h>
#include <wlan_ptt_sock_svc.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/rtnetlink.h>
#include <linux/semaphore.h>
#include <linux/ctype.h>
#include "bmi.h"
#include "ol_fw.h"
#include "ol_if_athvar.h"
#include "hif.h"
#include "epping_main.h"
#include "epping_internal.h"
#include "wlan_policy_mgr_api.h"
#ifdef TIMER_MANAGER
#define TIMER_MANAGER_STR " +TIMER_MANAGER"
#else
#define TIMER_MANAGER_STR ""
#endif
#ifdef MEMORY_DEBUG
#define MEMORY_DEBUG_STR " +MEMORY_DEBUG"
#else
#define MEMORY_DEBUG_STR ""
#endif
#ifdef HIF_SDIO
#define WLAN_WAIT_TIME_WLANSTART 10000
#else
#define WLAN_WAIT_TIME_WLANSTART 2000
#endif
#ifdef WLAN_FEATURE_EPPING
static struct epping_context *g_epping_ctx;
/**
* epping_open(): End point ping driver open Function
*
* This function is called by HDD to open epping module
*
*
* return - 0 for success, negative for failure
*/
int epping_open(void)
{
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__);
g_epping_ctx = qdf_mem_malloc(sizeof(*g_epping_ctx));
if (!g_epping_ctx)
return -ENOMEM;
g_epping_ctx->con_mode = cds_get_conparam();
return 0;
}
/**
* epping_disable(): End point ping driver disable Function
*
* This is the driver disable function - called by HDD to
* disable epping module
*
* return: none
*/
void epping_disable(void)
{
epping_context_t *epping_ctx;
struct hif_opaque_softc *hif_ctx;
HTC_HANDLE htc_handle;
epping_ctx = g_epping_ctx;
if (!epping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: error: epping_ctx = NULL", __func__);
return;
}
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
if (!hif_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: error: hif_ctx = NULL", __func__);
return;
}
hif_disable_isr(hif_ctx);
hif_reset_soc(hif_ctx);
htc_handle = cds_get_context(QDF_MODULE_ID_HTC);
if (!htc_handle) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: error: htc_handle = NULL", __func__);
return;
}
htc_stop(htc_handle);
epping_cookie_cleanup(epping_ctx);
htc_destroy(htc_handle);
if (epping_ctx->epping_adapter) {
epping_destroy_adapter(epping_ctx->epping_adapter);
epping_ctx->epping_adapter = NULL;
}
}
/**
* epping_close(): End point ping driver close Function
*
* This is the driver close function - called by HDD to close epping module
*
* return: none
*/
void epping_close(void)
{
epping_context_t *to_free;
if (!g_epping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: error: g_epping_ctx = NULL", __func__);
return;
}
to_free = g_epping_ctx;
g_epping_ctx = NULL;
qdf_mem_free(to_free);
}
/**
* epping_target_suspend_acknowledge() - process wow ack/nack from fw
* @context: htc_init_info->context
* @wow_nack: true when wow is rejected
* @reason_code : WoW status reason code
*/
static void epping_target_suspend_acknowledge(void *context, bool wow_nack,
uint16_t reson_code)
{
if (!g_epping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: epping_ctx is NULL", __func__);
return;
}
/* EPPING_TODO: do we need wow_nack? */
g_epping_ctx->wow_nack = wow_nack;
}
#ifdef WLAN_FEATURE_BMI
/**
* epping_update_ol_config - API to update ol configuration parameters
*
* Return: void
*/
static void epping_update_ol_config(void)
{
struct ol_config_info cfg;
struct ol_context *ol_ctx = cds_get_context(QDF_MODULE_ID_BMI);
if (!ol_ctx)
return;
cfg.enable_self_recovery = 0;
cfg.enable_uart_print = 0;
cfg.enable_fw_log = 0;
cfg.enable_ramdump_collection = 0;
cfg.enable_lpass_support = 0;
ol_init_ini_config(ol_ctx, &cfg);
}
static
QDF_STATUS epping_bmi_download_fw(struct ol_context *ol_ctx)
{
epping_update_ol_config();
/* Initialize BMI and Download firmware */
if (bmi_download_firmware(ol_ctx)) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
"%s: BMI failed to download target", __func__);
bmi_cleanup(ol_ctx);
return QDF_STATUS_E_INVAL;
}
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
"%s: bmi_download_firmware done", __func__);
return QDF_STATUS_SUCCESS;
}
#else
static
QDF_STATUS epping_bmi_download_fw(struct ol_context *ol_ctx)
{
return QDF_STATUS_SUCCESS;
}
#endif
/**
* epping_enable(): End point ping driver enable Function
*
* This is the driver enable function - called by HDD to enable
* epping module
*
* return - 0 : success, negative: error
*/
int epping_enable(struct device *parent_dev, bool rtnl_held)
{
int ret = 0;
epping_context_t *epping_ctx = NULL;
struct cds_context *p_cds_context = NULL;
qdf_device_t qdf_ctx;
struct htc_init_info htc_info;
struct hif_opaque_softc *scn;
tSirMacAddr adapter_macAddr;
struct ol_context *ol_ctx = NULL;
struct hif_target_info *tgt_info;
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__);
p_cds_context = cds_get_global_context();
if (!p_cds_context) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Failed cds_get_global_context", __func__);
ret = -1;
return ret;
}
epping_ctx = g_epping_ctx;
if (!epping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Failed to get epping_ctx", __func__);
ret = -1;
return ret;
}
epping_ctx->parent_dev = (void *)parent_dev;
epping_get_dummy_mac_addr(adapter_macAddr);
/* Initialize the timer module */
qdf_timer_module_init();
scn = cds_get_context(QDF_MODULE_ID_HIF);
if (!scn) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
"%s: scn is null!", __func__);
return A_ERROR;
}
tgt_info = hif_get_target_info_handle(scn);
ol_ctx = cds_get_context(QDF_MODULE_ID_BMI);
if (epping_bmi_download_fw(ol_ctx) != QDF_STATUS_SUCCESS)
return A_ERROR;
/* store target type and target version info in hdd ctx */
epping_ctx->target_type = tgt_info->target_type;
htc_info.pContext = NULL;
htc_info.TargetFailure = ol_target_failure;
htc_info.TargetSendSuspendComplete = epping_target_suspend_acknowledge;
qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
/* Create HTC */
p_cds_context->htc_ctx = htc_create(scn, &htc_info, qdf_ctx,
cds_get_conparam());
if (!p_cds_context->htc_ctx) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
"%s: Failed to Create HTC", __func__);
bmi_cleanup(ol_ctx);
return A_ERROR;
}
epping_ctx->HTCHandle =
cds_get_context(QDF_MODULE_ID_HTC);
if (!epping_ctx->HTCHandle) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: HTCHandle is NULL", __func__);
return A_ERROR;
}
if (bmi_done(ol_ctx)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Failed to complete BMI phase", __func__);
goto error_end;
}
/* start HIF */
if (htc_wait_target(epping_ctx->HTCHandle) != QDF_STATUS_SUCCESS) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_wait_target error", __func__);
goto error_end;
}
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC ready", __func__);
ret = epping_connect_service(epping_ctx);
if (ret != 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_wait_targetdone", __func__);
goto error_end;
}
if (htc_start(epping_ctx->HTCHandle) != QDF_STATUS_SUCCESS)
goto error_end;
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC started", __func__);
/* init the tx cookie resource */
ret = epping_cookie_init(epping_ctx);
if (ret < 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: cookie init failed", __func__);
htc_stop(epping_ctx->HTCHandle);
epping_cookie_cleanup(epping_ctx);
goto error_end;
}
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Exit", __func__);
return ret;
error_end:
htc_destroy(p_cds_context->htc_ctx);
p_cds_context->htc_ctx = NULL;
bmi_cleanup(ol_ctx);
return A_ERROR;
}
void epping_enable_adapter(void)
{
epping_context_t *epping_ctx = g_epping_ctx;
tSirMacAddr adapter_macaddr;
if (!epping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL, "epping context is NULL");
return;
}
epping_get_dummy_mac_addr(adapter_macaddr);
epping_ctx->epping_adapter = epping_add_adapter(epping_ctx,
adapter_macaddr,
QDF_STA_MODE, true);
if (!epping_ctx->epping_adapter)
EPPING_LOG(QDF_TRACE_LEVEL_FATAL, "epping add adapter failed");
}
#endif

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2014-2017, 2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*========================================================================
\file epping_rx.c
\brief WLAN End Point Ping test tool implementation
========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <cds_api.h>
#include <cds_sched.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <wni_api.h>
#include <wlan_ptt_sock_svc.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/rtnetlink.h>
#include <linux/semaphore.h>
#include <linux/ctype.h>
#include "epping_main.h"
#include "epping_internal.h"
#include "epping_test.h"
#include <wlan_hdd_napi.h>
#define AR6000_MAX_RX_BUFFERS 16
#define AR6000_BUFFER_SIZE 1664
#define AR6000_MIN_HEAD_ROOM 64
static bool enb_rx_dump;
#ifdef HIF_SDIO
void epping_refill(void *ctx, HTC_ENDPOINT_ID Endpoint)
{
epping_context_t *pEpping_ctx = (epping_context_t *) ctx;
void *osBuf;
int RxBuffers;
int buffersToRefill;
HTC_PACKET *pPacket;
HTC_PACKET_QUEUE queue;
buffersToRefill = (int)AR6000_MAX_RX_BUFFERS -
htc_get_num_recv_buffers(pEpping_ctx->HTCHandle, Endpoint);
if (buffersToRefill <= 0) {
/* fast return, nothing to fill */
return;
}
INIT_HTC_PACKET_QUEUE(&queue);
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s: providing htc with %d buffers at eid=%d\n",
__func__, buffersToRefill, Endpoint);
for (RxBuffers = 0; RxBuffers < buffersToRefill; RxBuffers++) {
osBuf = qdf_nbuf_alloc(NULL, AR6000_BUFFER_SIZE,
AR6000_MIN_HEAD_ROOM, 4, false);
if (!osBuf) {
break;
}
/* the HTC packet wrapper is at the head of the reserved area
* in the skb */
pPacket = (HTC_PACKET *) (A_NETBUF_HEAD(osBuf));
/* set re-fill info */
SET_HTC_PACKET_INFO_RX_REFILL(pPacket, osBuf,
qdf_nbuf_data(osBuf),
AR6000_BUFFER_SIZE, Endpoint);
SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, osBuf);
/* add to queue */
HTC_PACKET_ENQUEUE(&queue, pPacket);
}
if (!HTC_QUEUE_EMPTY(&queue)) {
/* add packets */
htc_add_receive_pkt_multiple(pEpping_ctx->HTCHandle, &queue);
}
}
#endif /* HIF_SDIO */
void epping_rx(void *ctx, HTC_PACKET *pPacket)
{
epping_context_t *pEpping_ctx = (epping_context_t *) ctx;
epping_adapter_t *adapter = pEpping_ctx->epping_adapter;
struct net_device *dev = adapter->dev;
QDF_STATUS status = pPacket->Status;
HTC_ENDPOINT_ID eid = pPacket->Endpoint;
struct sk_buff *pktSkb = (struct sk_buff *)pPacket->pPktContext;
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s: adapter = 0x%pK eid=%d, skb=0x%pK, data=0x%pK, len=0x%x status:%d",
__func__, adapter, eid, pktSkb, pPacket->pBuffer,
pPacket->ActualLength, status);
if (status != QDF_STATUS_SUCCESS) {
if (status != QDF_STATUS_E_CANCELED) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: RX ERR (%d)",
__func__, status);
}
qdf_nbuf_free(pktSkb);
return;
}
/* deliver to up layer */
if (pktSkb) {
if (EPPING_ALIGNMENT_PAD > 0) {
A_NETBUF_PULL(pktSkb, EPPING_ALIGNMENT_PAD);
}
if (enb_rx_dump)
epping_hex_dump((void *)qdf_nbuf_data(pktSkb),
pktSkb->len, __func__);
pktSkb->dev = dev;
if ((pktSkb->dev->flags & IFF_UP) == IFF_UP) {
pktSkb->protocol = eth_type_trans(pktSkb, pktSkb->dev);
++adapter->stats.rx_packets;
adapter->stats.rx_bytes += pktSkb->len;
qdf_net_buf_debug_release_skb(pktSkb);
if (hdd_napi_enabled(HDD_NAPI_ANY))
netif_receive_skb(pktSkb);
else
netif_rx_ni(pktSkb);
if ((adapter->stats.rx_packets %
EPPING_STATS_LOG_COUNT) == 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: total_rx_pkts = %lu",
__func__,
adapter->stats.rx_packets);
}
} else {
++adapter->stats.rx_dropped;
qdf_nbuf_free(pktSkb);
}
}
}

View File

@@ -0,0 +1,395 @@
/*
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*========================================================================
\file epping_tx.c
\brief WLAN End Point Ping test tool implementation
========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <cds_api.h>
#include <cds_sched.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <wni_api.h>
#include <wlan_ptt_sock_svc.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/rtnetlink.h>
#include <linux/semaphore.h>
#include <linux/ctype.h>
#include "epping_main.h"
#include "epping_internal.h"
#include "epping_test.h"
#define TX_RETRY_TIMEOUT_IN_MS 1
static bool enb_tx_dump;
void epping_tx_dup_pkt(epping_adapter_t *adapter,
HTC_ENDPOINT_ID eid, qdf_nbuf_t skb)
{
struct epping_cookie *cookie = NULL;
int skb_len, ret;
qdf_nbuf_t new_skb;
cookie = epping_alloc_cookie(adapter->pEpping_ctx);
if (!cookie) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: epping_alloc_cookie returns no resource\n",
__func__);
return;
}
new_skb = qdf_nbuf_copy(skb);
if (!new_skb) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: qdf_nbuf_copy returns no resource\n", __func__);
epping_free_cookie(adapter->pEpping_ctx, cookie);
return;
}
SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
cookie, qdf_nbuf_data(skb),
qdf_nbuf_len(new_skb), eid, 0);
SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb);
skb_len = (int)qdf_nbuf_len(new_skb);
/* send the packet */
ret = htc_send_pkt(adapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt);
if (ret != QDF_STATUS_SUCCESS) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_send_pkt failed, ret = %d\n", __func__, ret);
epping_free_cookie(adapter->pEpping_ctx, cookie);
qdf_nbuf_free(new_skb);
return;
}
adapter->stats.tx_bytes += skb_len;
++adapter->stats.tx_packets;
if (((adapter->stats.tx_packets +
adapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 &&
(adapter->stats.tx_packets || adapter->stats.tx_dropped)) {
epping_log_stats(adapter, __func__);
}
}
static int epping_tx_send_int(qdf_nbuf_t skb, epping_adapter_t *adapter)
{
EPPING_HEADER *eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb);
HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED;
struct epping_cookie *cookie = NULL;
uint8_t ac = 0;
QDF_STATUS ret = QDF_STATUS_SUCCESS;
int skb_len;
EPPING_HEADER tmpHdr = *eppingHdr;
/* allocate resource for this packet */
cookie = epping_alloc_cookie(adapter->pEpping_ctx);
/* no resource */
if (!cookie) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: epping_alloc_cookie returns no resource\n",
__func__);
return A_ERROR;
}
if (enb_tx_dump)
epping_hex_dump((void *)eppingHdr, skb->len, __func__);
/*
* a quirk of linux, the payload of the frame is 32-bit aligned and thus
* the addition of the HTC header will mis-align the start of the HTC
* frame, so we add some padding which will be stripped off in the target
*/
if (EPPING_ALIGNMENT_PAD > 0) {
A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD);
}
/* prepare ep/HTC information */
ac = eppingHdr->StreamNo_h;
eid = adapter->pEpping_ctx->EppingEndpoint[ac];
if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: invalid eid = %d, ac = %d\n", __func__, eid,
ac);
return A_ERROR;
}
if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT ||
tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) {
epping_set_kperf_flag(adapter, eid, tmpHdr.CmdBuffer_t[0]);
}
SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
cookie, qdf_nbuf_data(skb), qdf_nbuf_len(skb),
eid, 0);
SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb);
skb_len = skb->len;
/* send the packet */
ret = htc_send_pkt(adapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt);
epping_log_packet(adapter, &tmpHdr, ret, __func__);
if (ret != QDF_STATUS_SUCCESS) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_send_pkt failed, status = %d\n", __func__,
ret);
epping_free_cookie(adapter->pEpping_ctx, cookie);
return A_ERROR;
}
adapter->stats.tx_bytes += skb_len;
++adapter->stats.tx_packets;
if (((adapter->stats.tx_packets +
adapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 &&
(adapter->stats.tx_packets || adapter->stats.tx_dropped)) {
epping_log_stats(adapter, __func__);
}
return 0;
}
void epping_tx_timer_expire(epping_adapter_t *adapter)
{
qdf_nbuf_t nodrop_skb;
EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__,
qdf_nbuf_queue_len(&adapter->nodrop_queue));
if (!qdf_nbuf_queue_len(&adapter->nodrop_queue)) {
/* nodrop queue is empty so no need to arm timer */
adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
return;
}
/* try to flush nodrop queue */
while ((nodrop_skb = qdf_nbuf_queue_remove(&adapter->nodrop_queue))) {
htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, true);
if (epping_tx_send_int(nodrop_skb, adapter)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: nodrop: %pK xmit fail in timer\n",
__func__, nodrop_skb);
/* fail to xmit so put the nodrop packet to the nodrop queue */
qdf_nbuf_queue_insert_head(&adapter->nodrop_queue,
nodrop_skb);
break;
} else {
htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, false);
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s: nodrop: %pK xmit ok in timer\n",
__func__, nodrop_skb);
}
}
/* if nodrop queue is not empty, continue to arm timer */
if (nodrop_skb) {
qdf_spin_lock_bh(&adapter->data_lock);
/* if nodrop queue is not empty, continue to arm timer */
if (adapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) {
adapter->epping_timer_state = EPPING_TX_TIMER_RUNNING;
qdf_timer_mod(&adapter->epping_timer,
TX_RETRY_TIMEOUT_IN_MS);
}
qdf_spin_unlock_bh(&adapter->data_lock);
} else {
adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
}
}
int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *adapter)
{
qdf_nbuf_t nodrop_skb;
EPPING_HEADER *eppingHdr;
uint8_t ac = 0;
eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb);
if (!IS_EPPING_PACKET(eppingHdr)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Received non endpoint ping packets\n", __func__);
/* no packet to send, cleanup */
qdf_nbuf_free(skb);
return -ENOMEM;
}
/* the stream ID is mapped to an access class */
ac = eppingHdr->StreamNo_h;
/* hard coded two ep ids */
if (ac != 0 && ac != 1) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: ac %d is not mapped to mboxping service\n",
__func__, ac);
qdf_nbuf_free(skb);
return -ENOMEM;
}
/*
* some EPPING packets cannot be dropped no matter what access class
* it was sent on. A special care has been taken:
* 1. when there is no TX resource, queue the control packets to
* a special queue
* 2. when there is TX resource, send the queued control packets first
* and then other packets
* 3. a timer launches to check if there is queued control packets and
* flush them
*/
/* check the nodrop queue first */
while ((nodrop_skb = qdf_nbuf_queue_remove(&adapter->nodrop_queue))) {
htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, true);
if (epping_tx_send_int(nodrop_skb, adapter)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: nodrop: %pK xmit fail\n", __func__,
nodrop_skb);
/* fail to xmit so put the nodrop packet to the nodrop queue */
qdf_nbuf_queue_insert_head(&adapter->nodrop_queue,
nodrop_skb);
/* no cookie so free the current skb */
goto tx_fail;
} else {
htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, false);
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s: nodrop: %pK xmit ok\n", __func__,
nodrop_skb);
}
}
/* send the original packet */
if (epping_tx_send_int(skb, adapter))
goto tx_fail;
return 0;
tx_fail:
if (!IS_EPING_PACKET_NO_DROP(eppingHdr)) {
/* allow to drop the skb so drop it */
qdf_nbuf_free(skb);
++adapter->stats.tx_dropped;
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Tx skb %pK dropped, stats.tx_dropped = %ld\n",
__func__, skb, adapter->stats.tx_dropped);
return -ENOMEM;
} else {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: nodrop: %pK queued\n", __func__, skb);
qdf_nbuf_queue_add(&adapter->nodrop_queue, skb);
qdf_spin_lock_bh(&adapter->data_lock);
if (adapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) {
adapter->epping_timer_state = EPPING_TX_TIMER_RUNNING;
qdf_timer_mod(&adapter->epping_timer,
TX_RETRY_TIMEOUT_IN_MS);
}
qdf_spin_unlock_bh(&adapter->data_lock);
}
return 0;
}
#ifdef HIF_SDIO
enum htc_send_full_action epping_tx_queue_full(void *Context,
HTC_PACKET *pPacket)
{
/*
* Call netif_stop_queue frequently will impact the mboxping tx t-put.
* Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid.
*/
return HTC_SEND_FULL_KEEP;
}
#endif /* HIF_SDIO */
void epping_tx_complete(void *ctx, HTC_PACKET *htc_pkt)
{
epping_context_t *pEpping_ctx = (epping_context_t *) ctx;
epping_adapter_t *adapter = pEpping_ctx->epping_adapter;
struct net_device *dev = adapter->dev;
QDF_STATUS status;
HTC_ENDPOINT_ID eid;
qdf_nbuf_t pktSkb;
struct epping_cookie *cookie;
A_BOOL flushing = false;
qdf_nbuf_queue_t skb_queue;
if (!htc_pkt)
return;
qdf_nbuf_queue_init(&skb_queue);
qdf_spin_lock_bh(&adapter->data_lock);
status = htc_pkt->Status;
eid = htc_pkt->Endpoint;
pktSkb = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt);
cookie = htc_pkt->pPktContext;
if (!pktSkb) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s: NULL skb from hc packet", __func__);
QDF_BUG(0);
} else {
if (htc_pkt->pBuffer != qdf_nbuf_data(pktSkb)) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s: htc_pkt buffer not equal to skb->data",
__func__);
QDF_BUG(0);
}
/* add this to the list, use faster non-lock API */
qdf_nbuf_queue_add(&skb_queue, pktSkb);
if (QDF_IS_STATUS_SUCCESS(status)) {
if (htc_pkt->ActualLength !=
qdf_nbuf_len(pktSkb)) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s: htc_pkt length not equal to skb->len",
__func__);
QDF_BUG(0);
}
}
}
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s skb=%pK data=%pK len=0x%x eid=%d ",
__func__, pktSkb, htc_pkt->pBuffer,
htc_pkt->ActualLength, eid);
if (QDF_IS_STATUS_ERROR(status)) {
if (status == QDF_STATUS_E_CANCELED) {
/* a packet was flushed */
flushing = true;
}
if (status != QDF_STATUS_E_RESOURCES) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s() -TX ERROR, status: 0x%x",
__func__, status);
}
} else {
EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: OK\n", __func__);
flushing = false;
}
epping_free_cookie(adapter->pEpping_ctx, cookie);
qdf_spin_unlock_bh(&adapter->data_lock);
/* free all skbs in our local list */
while (qdf_nbuf_queue_len(&skb_queue)) {
/* use non-lock version */
pktSkb = qdf_nbuf_queue_remove(&skb_queue);
if (!pktSkb)
break;
qdf_nbuf_tx_free(pktSkb, QDF_NBUF_PKT_ERROR);
pEpping_ctx->total_tx_acks++;
}
if (!flushing) {
netif_wake_queue(dev);
}
}

View File

@@ -0,0 +1,481 @@
/*
* Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*========================================================================
\file epping_txrx.c
\brief WLAN End Point Ping test tool implementation
========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <cds_api.h>
#include <cds_sched.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <wni_api.h>
#include <wlan_ptt_sock_svc.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <pld_common.h>
#include <linux/rtnetlink.h>
#include <linux/semaphore.h>
#include <linux/ctype.h>
#include "epping_main.h"
#include "epping_internal.h"
#include "qdf_net_if.h"
static int epping_start_adapter(epping_adapter_t *adapter);
static void epping_stop_adapter(epping_adapter_t *adapter);
static void epping_timer_expire(void *data)
{
struct net_device *dev = (struct net_device *)data;
epping_adapter_t *adapter;
if (!dev) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: netdev = NULL", __func__);
return;
}
adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: adapter = NULL", __func__);
return;
}
adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
epping_tx_timer_expire(adapter);
}
static int epping_ndev_open(struct net_device *dev)
{
epping_adapter_t *adapter;
int ret = 0;
adapter = netdev_priv(dev);
epping_start_adapter(adapter);
return ret;
}
static int epping_ndev_stop(struct net_device *dev)
{
epping_adapter_t *adapter;
int ret = 0;
adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
ret = -ENODEV;
goto end;
}
epping_stop_adapter(adapter);
end:
return ret;
}
static void epping_ndev_uninit(struct net_device *dev)
{
epping_adapter_t *adapter;
adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
goto end;
}
epping_stop_adapter(adapter);
end:
return;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
static void epping_tx_queue_timeout(struct net_device *dev,
unsigned int txqueue)
#else
static void epping_tx_queue_timeout(struct net_device *dev)
#endif
{
epping_adapter_t *adapter;
adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
goto end;
}
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s: Transmission timeout occurred, adapter->started= %d",
__func__, adapter->started);
/* Getting here implies we disabled the TX queues
* for too long. Since this is epping
* (not because of disassociation or low resource scenarios),
* try to restart the queue
*/
if (adapter->started)
netif_wake_queue(dev);
end:
return;
}
static netdev_tx_t epping_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
epping_adapter_t *adapter;
int ret = 0;
adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
kfree_skb(skb);
ret = -ENODEV;
goto end;
}
qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__);
ret = epping_tx_send(skb, adapter);
end:
return NETDEV_TX_OK;
}
static struct net_device_stats *epping_get_stats(struct net_device *dev)
{
epping_adapter_t *adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: adapter = NULL",
__func__);
return NULL;
}
return &adapter->stats;
}
static int epping_ndev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
epping_adapter_t *adapter;
int ret = 0;
adapter = netdev_priv(dev);
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
ret = -ENODEV;
goto end;
}
if (dev != adapter->dev) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: HDD adapter/dev inconsistency", __func__);
ret = -ENODEV;
goto end;
}
if ((!ifr) || (!ifr->ifr_data)) {
ret = -EINVAL;
goto end;
}
switch (cmd) {
case (SIOCDEVPRIVATE + 1):
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s: do not support ioctl %d (SIOCDEVPRIVATE + 1)",
__func__, cmd);
break;
default:
EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d",
__func__, cmd);
ret = -EINVAL;
break;
}
end:
return ret;
}
static int epping_set_mac_address(struct net_device *dev, void *addr)
{
epping_adapter_t *adapter = netdev_priv(dev);
struct sockaddr *psta_mac_addr = addr;
qdf_mem_copy(&adapter->macAddressCurrent,
psta_mac_addr->sa_data, ETH_ALEN);
qdf_net_update_net_device_dev_addr(dev, psta_mac_addr->sa_data,
ETH_ALEN);
return 0;
}
static void epping_stop_adapter(epping_adapter_t *adapter)
{
qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
if (!qdf_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: qdf_ctx is NULL\n", __func__);
return;
}
if (adapter && adapter->started) {
EPPING_LOG(LOG1, FL("Disabling queues"));
netif_tx_disable(adapter->dev);
netif_carrier_off(adapter->dev);
adapter->started = false;
pld_request_bus_bandwidth(qdf_ctx->dev,
PLD_BUS_WIDTH_LOW);
}
}
static int epping_start_adapter(epping_adapter_t *adapter)
{
qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
if (!qdf_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: qdf_ctx is NULL", __func__);
return -EINVAL;
}
if (!adapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: adapter= NULL\n", __func__);
return -EINVAL;
}
if (!adapter->started) {
pld_request_bus_bandwidth(qdf_ctx->dev,
PLD_BUS_WIDTH_HIGH);
netif_carrier_on(adapter->dev);
EPPING_LOG(LOG1, FL("Enabling queues"));
netif_tx_start_all_queues(adapter->dev);
adapter->started = true;
} else {
EPPING_LOG(QDF_TRACE_LEVEL_WARN,
"%s: adapter %pK already started\n", __func__,
adapter);
}
return 0;
}
static int epping_register_adapter(epping_adapter_t *adapter, bool rtnl_held)
{
int ret = 0;
if (!rtnl_held)
ret = register_netdev(adapter->dev);
else
ret = register_netdevice(adapter->dev);
if (ret != 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: unable to register device\n",
adapter->dev->name);
} else {
adapter->registered = true;
}
return ret;
}
static void epping_unregister_adapter(epping_adapter_t *adapter)
{
if (adapter) {
epping_stop_adapter(adapter);
if (adapter->registered) {
unregister_netdev(adapter->dev);
adapter->registered = false;
}
} else {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: adapter = NULL, unable to unregister device\n",
__func__);
}
}
void epping_destroy_adapter(epping_adapter_t *adapter)
{
struct net_device *dev = NULL;
epping_context_t *pEpping_ctx;
if (!adapter || !adapter->pEpping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: adapter = NULL\n", __func__);
return;
}
dev = adapter->dev;
pEpping_ctx = adapter->pEpping_ctx;
epping_unregister_adapter(adapter);
qdf_spinlock_destroy(&adapter->data_lock);
qdf_timer_free(&adapter->epping_timer);
adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
while (qdf_nbuf_queue_len(&adapter->nodrop_queue)) {
qdf_nbuf_t tmp_nbuf = NULL;
tmp_nbuf = qdf_nbuf_queue_remove(&adapter->nodrop_queue);
if (tmp_nbuf)
qdf_nbuf_free(tmp_nbuf);
}
free_netdev(dev);
if (!pEpping_ctx)
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: pEpping_ctx = NULL\n", __func__);
else
pEpping_ctx->epping_adapter = NULL;
}
static struct net_device_ops epping_drv_ops = {
.ndo_open = epping_ndev_open,
.ndo_stop = epping_ndev_stop,
.ndo_uninit = epping_ndev_uninit,
.ndo_start_xmit = epping_hard_start_xmit,
.ndo_tx_timeout = epping_tx_queue_timeout,
.ndo_get_stats = epping_get_stats,
.ndo_do_ioctl = epping_ndev_ioctl,
.ndo_set_mac_address = epping_set_mac_address,
.ndo_select_queue = NULL,
};
#define EPPING_TX_QUEUE_MAX_LEN 128 /* need to be power of 2 */
epping_adapter_t *epping_add_adapter(epping_context_t *pEpping_ctx,
tSirMacAddr macAddr,
enum QDF_OPMODE device_mode,
bool rtnl_held)
{
struct net_device *dev;
epping_adapter_t *adapter;
dev = alloc_netdev(sizeof(epping_adapter_t), "wifi%d",
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
NET_NAME_UNKNOWN,
#endif
ether_setup);
if (!dev) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Cannot allocate epping_adapter_t\n", __func__);
return NULL;
}
adapter = netdev_priv(dev);
qdf_mem_zero(adapter, sizeof(*adapter));
adapter->dev = dev;
adapter->pEpping_ctx = pEpping_ctx;
adapter->device_mode = device_mode; /* station, SAP, etc */
qdf_net_update_net_device_dev_addr(dev,
(void *)macAddr,
sizeof(tSirMacAddr));
qdf_mem_copy(adapter->macAddressCurrent.bytes,
macAddr, sizeof(tSirMacAddr));
qdf_spinlock_create(&adapter->data_lock);
qdf_nbuf_queue_init(&adapter->nodrop_queue);
adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
qdf_timer_init(epping_get_qdf_ctx(), &adapter->epping_timer,
epping_timer_expire, dev, QDF_TIMER_TYPE_SW);
dev->type = ARPHRD_IEEE80211;
dev->needed_headroom += 24;
dev->netdev_ops = &epping_drv_ops;
dev->watchdog_timeo = 5 * HZ; /* XXX */
dev->tx_queue_len = EPPING_TXBUF - 1; /* 1 for mgmt frame */
if (epping_register_adapter(adapter, rtnl_held) == 0) {
EPPING_LOG(LOG1, FL("Disabling queues"));
netif_tx_disable(dev);
netif_carrier_off(dev);
return adapter;
} else {
epping_destroy_adapter(adapter);
return NULL;
}
}
int epping_connect_service(epping_context_t *pEpping_ctx)
{
int status, i;
struct htc_service_connect_req connect;
struct htc_service_connect_resp response;
qdf_mem_zero(&connect, sizeof(connect));
qdf_mem_zero(&response, sizeof(response));
/* these fields are the same for all service endpoints */
connect.EpCallbacks.pContext = pEpping_ctx;
connect.EpCallbacks.EpTxCompleteMultiple = NULL;
connect.EpCallbacks.EpRecv = epping_rx;
/* epping_tx_complete use Multiple version */
connect.EpCallbacks.EpTxComplete = epping_tx_complete;
connect.MaxSendQueueDepth = 64;
#ifdef HIF_SDIO
connect.EpCallbacks.EpRecvRefill = epping_refill;
connect.EpCallbacks.EpSendFull =
epping_tx_queue_full /* ar6000_tx_queue_full */;
#elif defined(HIF_USB) || defined(HIF_PCI) || defined(HIF_SNOC) || \
defined(HIF_IPCI)
connect.EpCallbacks.EpRecvRefill = NULL /* provided by HIF */;
connect.EpCallbacks.EpSendFull = NULL /* provided by HIF */;
/* disable flow control for hw flow control */
connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
#endif
/* connect to service */
connect.service_id = WMI_DATA_BE_SVC;
status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response);
if (QDF_IS_STATUS_ERROR(status)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"Failed to connect to Endpoint Ping BE service status:%d\n",
status);
return status;
} else {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"eppingtest BE endpoint:%d\n", response.Endpoint);
}
pEpping_ctx->EppingEndpoint[0] = response.Endpoint;
#if defined(HIF_PCI) || defined(HIF_USB) || defined(HIF_SNOC) || \
defined(HIF_IPCI)
connect.service_id = WMI_DATA_BK_SVC;
status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response);
if (QDF_IS_STATUS_ERROR(status)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"Failed to connect to Endpoint Ping BK service status:%d\n",
status);
return status;
} else {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"eppingtest BK endpoint:%d\n", response.Endpoint);
}
pEpping_ctx->EppingEndpoint[1] = response.Endpoint;
/* Since we do not create other two SVC use BK endpoint
* for rest ACs (2, 3) */
for (i = 2; i < EPPING_MAX_NUM_EPIDS; i++) {
pEpping_ctx->EppingEndpoint[i] = response.Endpoint;
}
#else
/* we only use one endpoint for high latenance bus.
* Map all AC's EPIDs to the same endpoint ID returned by HTC */
for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) {
pEpping_ctx->EppingEndpoint[i] = response.Endpoint;
}
#endif
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
/*
* Copyright (c) 2011, 2014-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _DBGLOG_HOST_H_
#define _DBGLOG_HOST_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "dbglog_common.h"
#include "wmi_unified_param.h"
#define DIAG_FWID_OFFSET 24
#define DIAG_FWID_MASK 0xFF000000 /* Bit 24-31 */
#define DIAG_TIMESTAMP_OFFSET 0
#define DIAG_TIMESTAMP_MASK 0x00FFFFFF /* Bit 0-23 */
#define DIAG_ID_OFFSET 16
#define DIAG_ID_MASK 0xFFFF0000 /* Bit 16-31 */
#define DIAG_VDEVID_OFFSET 11
#define DIAG_VDEVID_MASK 0x0000F800 /* Bit 11-15 */
#define DIAG_VDEVID_NUM_MAX 16
#define DIAG_VDEVLEVEL_OFFSET 8
#define DIAG_VDEVLEVEL_MASK 0x00000700 /* Bit 8-10 */
#define DIAG_PAYLEN_OFFSET 0
#define DIAG_PAYLEN_MASK 0x000000FF /* Bit 0-7 */
#define DIAG_PAYLEN_OFFSET16 0
#define DIAG_PAYLEN_MASK16 0x0000FFFF /* Bit 0-16 */
#define DIAG_GET_TYPE(arg) \
((arg & DIAG_FWID_MASK) >> DIAG_FWID_OFFSET)
#define DIAG_GET_TIME_STAMP(arg) \
((arg & DIAG_TIMESTAMP_MASK) >> DIAG_TIMESTAMP_OFFSET)
#define DIAG_GET_ID(arg) \
((arg & DIAG_ID_MASK) >> DIAG_ID_OFFSET)
#define DIAG_GET_VDEVID(arg) \
((arg & DIAG_VDEVID_MASK) >> DIAG_VDEVID_OFFSET)
#define DIAG_GET_VDEVLEVEL(arg) \
((arg & DIAG_VDEVLEVEL_MASK) >> DIAG_VDEVLEVEL_OFFSET)
#define DIAG_GET_PAYLEN(arg) \
((arg & DIAG_PAYLEN_MASK) >> DIAG_PAYLEN_OFFSET)
#define DIAG_GET_PAYLEN16(arg) \
((arg & DIAG_PAYLEN_MASK16) >> DIAG_PAYLEN_OFFSET16)
#define diag_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_DIAG, params)
#define diag_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_DIAG, params)
#define diag_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_DIAG, params)
#define diag_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_DIAG, params)
#define diag_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_DIAG, params)
#define diag_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_DIAG, params)
#ifdef FEATURE_FW_LOG_PARSING
/*
* set the dbglog parser type
*/int
dbglog_parser_type_init(wmi_unified_t wmi_handle, int type);
/** dbglog_int - Registers a WMI event handle for WMI_DBGMSG_EVENT
* @brief wmi_handle - handle to wmi module
*/
int
dbglog_init(wmi_unified_t wmi_handle);
/** dbglog_deinit - UnRegisters a WMI event handle for WMI_DBGMSG_EVENT
* @brief wmi_handle - handle to wmi module
*/
int
dbglog_deinit(wmi_unified_t wmi_handle);
/** set the size of the report size
* @brief wmi_handle - handle to Wmi module
* @brief size - Report size
*/
int
dbglog_set_report_size(wmi_unified_t wmi_handle, uint16_t size);
/** Set the resolution for time stamp
* @brief wmi_handle - handle to Wmi module
* @ brief tsr - time stamp resolution
*/
int
dbglog_set_timestamp_resolution(wmi_unified_t wmi_handle,
uint16_t tsr);
/** Enable reporting. If it is set to false then Target won't deliver
* any debug information
*/
int
dbglog_report_enable(wmi_unified_t wmi_handle, A_BOOL isenable);
/** Set the log level
* @brief DBGLOG_INFO - Information lowest log level
* @brief DBGLOG_WARNING
* @brief DBGLOG_ERROR - default log level
*/
int
dbglog_set_log_lvl(wmi_unified_t wmi_handle, DBGLOG_LOG_LVL log_lvl);
/*
* set the debug log level for a given module
* mod_id_lvl : the format is more user friendly.
* module_id = mod_id_lvl/10;
* log_level = mod_id_lvl%10;
* example : mod_id_lvl is 153. then module id is 15 and log level is 3.
* this format allows user to pass a single value
* (which is the most convenient way for most of the OSs)
* to be passed from user to the driver.
*/
int
dbglog_set_mod_log_lvl(wmi_unified_t wmi_handle, uint32_t mod_id_lvl);
/*
* set the debug log level for wow module
* mod_id_lvl : the format is more user friendly.
* module_id = mod_id_lvl/10;
* log_level = mod_id_lvl%10;
* example : mod_id_lvl is 153. then module id is 15 and log level is 3.
* this format allows user to pass a single value
* (which is the most convenient way for most of the OSs)
* to be passed from user to the driver.
*/
int
dbglog_set_mod_wow_log_lvl(wmi_unified_t wmi_handle, uint32_t mod_id_lvl);
/** Enable/Disable the logging for VAP */
int
dbglog_vap_log_enable(wmi_unified_t wmi_handle, uint16_t vap_id,
A_BOOL isenable);
/** Enable/Disable logging for Module */
int
dbglog_module_log_enable(wmi_unified_t wmi_handle, uint32_t mod_id,
A_BOOL isenable);
/** set vap enablie bitmap */
void
dbglog_set_vap_enable_bitmap(wmi_unified_t wmi_handle,
uint32_t vap_enable_bitmap);
/** set log level for all the modules specified in the bitmap.
* for all other modules with 0 in the bitmap (or) outside the bitmap,
* the log level be reset to DBGLOG_ERR.
*/
void
dbglog_set_mod_enable_bitmap(wmi_unified_t wmi_handle,
uint32_t log_level,
uint32_t *mod_enable_bitmap,
uint32_t bitmap_len);
int
dbglog_parse_debug_logs(ol_scn_t scn, u_int8_t *datap,
u_int32_t len);
/**
* cnss_diag_activate_service() - API to register CNSS diag cmd handler
*
* API to register the handler for the NL message received from cnss_diag
* application.
*
* Return: 0
*/
int cnss_diag_activate_service(void);
/**
* cnss_diag_deactivate_service() - API to deregister CNSS diag cmd handler
*
* API to deregister the handler for the NL message received from cnss_diag
* application.
*
* Return: 0
*/
int cnss_diag_deactivate_service(void);
#else
static inline int
dbglog_parser_type_init(wmi_unified_t wmi_handle, int type)
{
return A_OK;
}
static inline int
dbglog_init(wmi_unified_t wmi_handle)
{
return A_OK;
}
static inline int
dbglog_deinit(wmi_unified_t wmi_handle)
{
return A_OK;
}
static inline int
dbglog_report_enable(wmi_unified_t wmi_handle, A_BOOL isenable)
{
return A_OK;
}
static inline int
dbglog_set_log_lvl(wmi_unified_t wmi_handle, DBGLOG_LOG_LVL log_lvl)
{
return A_OK;
}
static inline int cnss_diag_activate_service(void)
{
return A_OK;
}
static inline int cnss_diag_deactivate_service(void)
{
return A_OK;
}
static inline int
dbglog_module_log_enable(wmi_unified_t wmi_handle, uint32_t mod_id,
A_BOOL isenable)
{
return A_OK;
}
static inline int
dbglog_vap_log_enable(wmi_unified_t wmi_handle, uint16_t vap_id,
A_BOOL isenable)
{
return A_OK;
}
static inline int
dbglog_set_mod_log_lvl(wmi_unified_t wmi_handle, uint32_t mod_id_lvl)
{
return A_OK;
}
static inline int
dbglog_set_mod_wow_log_lvl(wmi_unified_t wmi_handle, uint32_t mod_id_lvl)
{
return A_OK;
}
#endif /* FEATURE_FW_LOG_PARSING */
#ifdef __cplusplus
}
#endif
#endif /* _DBGLOG_HOST_H_ */

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "fw_dbglog_api.h"
#include "fw_dbglog_priv.h"
static inline struct dbglog_info *handle2info(
struct common_dbglog_handle *dbg_handle)
{
return (struct dbglog_info *)dbg_handle;
}
void fwdbg_set_log_lvl(struct common_dbglog_handle *dbg_handle, ol_scn_t scn,
uint32_t log_lvl)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_set_log_lvl)
dbg_info->ops->dbglog_set_log_lvl(scn, log_lvl);
}
int fwdbg_fw_handler(struct common_dbglog_handle *dbg_handle, ol_scn_t soc,
uint8_t *data, uint32_t datalen)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_fw_handler)
return dbg_info->ops->dbglog_fw_handler(soc, data, datalen);
return 0;
}
int fwdbg_parse_debug_logs(struct common_dbglog_handle *dbg_handle,
ol_scn_t soc, uint8_t *datap,
uint16_t len, void *context)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_parse_debug_logs)
return dbg_info->ops->dbglog_parse_debug_logs(soc,
datap, len, context);
return 0;
}
qdf_export_symbol(fwdbg_parse_debug_logs);
void fwdbg_ratelimit_set(struct common_dbglog_handle *dbg_handle,
uint32_t burst_limit)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_ratelimit_set)
dbg_info->ops->dbglog_ratelimit_set(burst_limit);
}
void fwdbg_vap_log_enable(struct common_dbglog_handle *dbg_handle, ol_scn_t scn,
uint16_t vap_id, bool isenable)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_vap_log_enable)
dbg_info->ops->dbglog_vap_log_enable(scn, vap_id,
isenable);
}
void fwdbg_set_timestamp_resolution(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, uint16_t tsr)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_set_timestamp_resolution)
dbg_info->ops->dbglog_set_timestamp_resolution(scn, tsr);
}
void fwdbg_reporting_enable(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, bool isenable)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_reporting_enable)
dbg_info->ops->dbglog_reporting_enable(scn, isenable);
}
void fwdbg_module_log_enable(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, uint32_t mod_id, bool isenable)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_module_log_enable)
dbg_info->ops->dbglog_module_log_enable(scn, mod_id,
isenable);
}
void fwdbg_init(struct common_dbglog_handle *dbg_handle, void *soc)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_init)
dbg_info->ops->dbglog_init(soc);
}
void fwdbg_free(struct common_dbglog_handle *dbg_handle, void *soc)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_free)
dbg_info->ops->dbglog_free(soc);
}
void fwdbg_set_report_size(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, uint16_t size)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->dbglog_set_report_size)
dbg_info->ops->dbglog_set_report_size(scn, size);
}
int fwdbg_smartlog_init(struct common_dbglog_handle *dbg_handle, void *icp)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->smartlog_init)
return dbg_info->ops->smartlog_init(icp);
return 0;
}
void fwdbg_smartlog_deinit(struct common_dbglog_handle *dbg_handle, void *sc)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->smartlog_deinit)
dbg_info->ops->smartlog_deinit(sc);
}
ssize_t fwdbg_smartlog_dump(struct common_dbglog_handle *dbg_handle,
struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dbglog_info *dbg_info = handle2info(dbg_handle);
if (dbg_info->ops->smartlog_dump)
return dbg_info->ops->smartlog_dump(dev, attr, buf);
return 0;
}

View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _FW_DBGLOG_API_H_
#define _FW_DBGLOG_API_H_
#include "target_if.h"
/**
* fwdbg_set_log_lvl() - API to set debug log level
* @dbg_handle: Debug module handle
* @scn: scn handle
* @log_lvl: value of log level
*
* Send wmi configuration command to set debug log level.
*
* Return: None
*/
void fwdbg_set_log_lvl(struct common_dbglog_handle *dbg_handle, ol_scn_t scn,
uint32_t log_lvl);
/**
* fwdbg_fw_handler() - Firmware handler interface
* @dbg_handle: Debug module handle
* @sc: soc handle
* @data: Reference to command data
* @datalen: length of data
*
* Return: 0 success
*/
int fwdbg_fw_handler(struct common_dbglog_handle *dbg_handle, ol_scn_t sc,
uint8_t *data, uint32_t datalen);
/**
* fwdbg_parse_debug_logs() - API to parse firmware debug logs
* @dbg_handle: Debug module handle
* @soc: soc handle
* @datap: Reference to log data
* @len: length of data
* @context: log context
*
* API parse firmware debug log messages and prints to console.
*
* Return: 0 success
*/
int fwdbg_parse_debug_logs(struct common_dbglog_handle *dbg_handle,
ol_scn_t soc, uint8_t *datap,
uint16_t len, void *context);
/**
* fwdbg_ratelimit_set() - API to set rate limit
* @dbg_handle: Debug module handle
* @burst_limit: burst limit
*
* Return: None
*/
void fwdbg_ratelimit_set(struct common_dbglog_handle *dbg_handle,
uint32_t burst_limit);
/**
* fwdbg_vap_log_enable() - API to Enable/Disable the logging for VAP
* @dbg_handle: Debug module handle
* @scn: scn handle
* @vap_id: VAP id
* @isenable: Enable/disable
*
* API allows to enable or disable debuglogs at VAP level. It encodes wmi
* config command based on VAP id and sends wmi command to firmware to
* enable/disable debuglog.
*
* Return: None
*/
void fwdbg_vap_log_enable(struct common_dbglog_handle *dbg_handle, ol_scn_t scn,
uint16_t vap_id, bool isenable);
/**
* fwdbg_set_timestamp_resolution - Set the resolution for time stamp
* @dbg_handle: Debug module handle
* @scn: scn handle
* @tsr: time stamp resolution
*
* Set the resolution for time stamp in debug logs. It encodes wmi
* config command to desired timestamp resolution and sends wmi command to
* firmware.
*
* Return: None
*/
void fwdbg_set_timestamp_resolution(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, uint16_t tsr);
/**
* fwdbg_reporting_enable() - Enable reporting.
* @dbg_handle: Debug module handle
* @scn: scn handle
* @isenable: Enable/disable
*
* API to enable debug information reporting. It encodes wmi config command
* to enable reporting. If set to false then Target won't deliver any debug
* information.
*
* Return: None
*/
void fwdbg_reporting_enable(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, bool isenable);
/**
* fwdbg_module_log_enable() - Enable/Disable logging for Module.
* @dbg_handle: Debug module handle
* @scn: scn handle
* @mod_id: Module id
* @isenable: Enable/disable
*
* API allows to enable or disable debuglogs per module. It encodes wmi
* config command based on module id and sends wmi command to firmware to
* enable/disable debuglog for that module.
*
* Return: None
*/
void fwdbg_module_log_enable(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, uint32_t mod_id, bool isenable);
/**
* fwdbg_init() - Initialize debuglog.
* @dbg_handle: Debug module handle
* @soc: soc handle
*
* It initializes debuglog print function for set of modules and
* initializes WMI event handler for debuglog message event.
*
* Return: None
*/
void fwdbg_init(struct common_dbglog_handle *dbg_handle, void *soc);
/**
* fwdbg_free() - Free debug handler.
* @dbg_handle: Debug module handle
* @soc: soc handle
*
* Return: None
*/
void fwdbg_free(struct common_dbglog_handle *dbg_handle, void *soc);
/**
* fwdbg_set_report_size() - set the size of the report size
* @dbg_handle: Debug module handle
* @scn: soc handler
* @size: Report size
*
* Set the debug log report size. It encodes wmi config command to
* desired report size and sends wmi command to firmware.
*
* Return: None
*/
void fwdbg_set_report_size(struct common_dbglog_handle *dbg_handle,
ol_scn_t scn, uint16_t size);
/**
* fwdbg_smartlog_init() - initialize smart logging feature
* @dbg_handle: Debug module handle
* @ic: ic handler
*
* Return: 0 Success
*/
int fwdbg_smartlog_init(struct common_dbglog_handle *dbg_handle, void *icp);
/**
* fwdbg_smartlog_deinit() - uninitializes smart logging feature
* @dbg_handle: Debug module handle
* @sc: sc handler
*
* Return: None
*/
void fwdbg_smartlog_deinit(struct common_dbglog_handle *dbg_handle, void *sc);
/**
* fwdbg_smartlog_dump() - dumps smart logs
* @dev: dev handler
* @dbg_handle: Debug module handle
* @attr: dev handler attributes
* @buf: destination buffer to dump smart logs
*
* Return: 0 success
*/
ssize_t fwdbg_smartlog_dump(struct common_dbglog_handle *dbg_handle,
struct device *dev,
struct device_attribute *attr, char *buf);
#endif /* _FW_DBGLOG_API_H_ */

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file contains the API definitions for the Unified Wireless
* Module Interface (WMI).
*/
#ifndef _FW_DBGLOG_PRIV_H_
#define _FW_DBGLOG_PRIV_H_
#include <wmi_unified_api.h>
struct dbglog_ops {
void (*dbglog_set_log_lvl)(ol_scn_t scn, uint32_t log_lvl);
int (*dbglog_fw_handler)(ol_scn_t soc, uint8_t *data, uint32_t datalen);
int (*dbglog_parse_debug_logs)(ol_scn_t scn,
u_int8_t *datap, uint16_t len, void *context);
void (*dbglog_ratelimit_set)(uint32_t burst_limit);
void (*dbglog_vap_log_enable)(ol_scn_t soc, uint16_t vap_id,
bool isenable);
void (*dbglog_set_timestamp_resolution)(ol_scn_t soc, uint16_t tsr);
void (*dbglog_reporting_enable)(ol_scn_t soc, bool isenable);
void (*dbglog_module_log_enable)(ol_scn_t scn,
uint32_t mod_id, bool isenable);
void (*dbglog_init)(void *scn);
void (*dbglog_set_report_size)(ol_scn_t scn, uint16_t size);
void (*dbglog_free)(void *soc);
int (*smartlog_init)(void *icp);
void (*smartlog_deinit)(void *sc);
ssize_t (*smartlog_dump)(struct device *dev,
struct device_attribute *attr, char *buf);
};
struct dbglog_info {
struct dbglog_ops *ops;
};
#endif /*_FW_DBGLOG_PRIV_H_ */

View File

@@ -0,0 +1,591 @@
/*
* Copyright (c) 2014-2017, 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(__HOST_DIAG_CORE_LOG_H)
#define __HOST_DIAG_CORE_LOG_H
/**=========================================================================
\file host_diag_core_log.h
\brief WLAN UTIL host DIAG logs
Definitions for WLAN UTIL host diag events
========================================================================*/
/* $Header$ */
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include "qdf_types.h"
#include "i_host_diag_core_log.h"
/*--------------------------------------------------------------------------
Preprocessor definitions and constants
------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*--------------------------------------------------------------------------
Preprocessor definitions and constants
------------------------------------------------------------------------*/
#define HOST_LOG_MAX_NUM_SSID (21)
#define HOST_LOG_MAX_NUM_BSSID (21)
#define HOST_LOG_MAX_SSID_SIZE (32)
#define HOST_LOG_MAX_BSSID_SIZE (6)
#define HOST_LOG_MAX_NUM_CHANNEL (64)
#define HOST_LOG_MAX_NUM_HO_CANDIDATE_APS (20)
#define HOST_LOG_MAX_WOW_PTRN_SIZE (128)
#define HOST_LOG_MAX_WOW_PTRN_MASK_SIZE (16)
#define VOS_LOG_PKT_LOG_SIZE (2048)
#define HOST_LOG_PKT_LOG_THRESHOLD 40960
#define HOST_LOG_MAX_COLD_BOOT_CAL_DATA_SIZE (2048)
/* Version to be updated whenever format of vos_log_pktlog_info changes */
#define VERSION_LOG_WLAN_PKT_LOG_INFO_C 1
/* Version to be updated whenever format of host_log_cold_boot_cal_data_type
* changes
*/
#define VERSION_LOG_WLAN_COLD_BOOT_CAL_DATA_C 1
/*---------------------------------------------------------------------------
This packet contains the scan results of the recent scan operation
LOG_WLAN_SCAN_C 0x1496
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint8_t eventId;
uint8_t numSsid;
uint8_t ssid[HOST_LOG_MAX_NUM_SSID][HOST_LOG_MAX_SSID_SIZE];
uint8_t bssid[HOST_LOG_MAX_NUM_BSSID][HOST_LOG_MAX_BSSID_SIZE];
uint8_t totalSsid;
uint8_t minChnTime;
uint8_t maxChnTime;
uint16_t timeBetweenBgScan;
uint8_t BSSMode;
uint8_t numChannel;
uint8_t channels[HOST_LOG_MAX_NUM_CHANNEL];
uint16_t status;
} host_log_scan_pkt_type;
/*---------------------------------------------------------------------------
This packet contains the information related to IBSS connection setup
LOG_WLAN_IBSS_C 0x1497
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint8_t eventId;
uint8_t channelSetting;
struct qdf_mac_addr bssid;
struct qdf_mac_addr peer_macaddr;
uint8_t ssid[HOST_LOG_MAX_SSID_SIZE];
uint8_t operatingChannel;
uint8_t beaconInterval;
uint8_t status;
uint32_t op_freq;
} host_log_ibss_pkt_type;
/*---------------------------------------------------------------------------
This packet contains the information related to 802.11D
LOG_WLAN_80211D_C 0x1498
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint8_t eventId;
uint8_t numChannel;
uint8_t Channels[HOST_LOG_MAX_NUM_CHANNEL];
uint8_t TxPwr[HOST_LOG_MAX_NUM_CHANNEL];
uint8_t countryCode[3];
uint8_t supportMultipleDomain;
} host_log_802_11d_pkt_type;
/*---------------------------------------------------------------------------
This is a log packet which contains below handoff information:
- Current AP + RSSI (if already associated)
- Candidate AP + RSSI (before association and when the list is updated)
- For each BSSID in candidate list, provide RSSI, QoS and security compatibility
LOG_WLAN_HANDOFF_C 0x1499
---------------------------------------------------------------------------*/
typedef struct {
uint8_t ssid[9];
uint8_t bssid[HOST_LOG_MAX_BSSID_SIZE];
uint8_t channel_id;
uint32_t qos_score;
uint32_t sec_score;
uint32_t rssi_score;
uint32_t overall_score;
uint32_t tx_per; /* represented as a % */
uint32_t rx_per; /* represented as a % */
} host_log_ho_ap_info;
typedef struct {
log_hdr_type hdr;
uint32_t num_aps;
host_log_ho_ap_info current_ap_info;
host_log_ho_ap_info
candidate_ap_info[HOST_LOG_MAX_NUM_HO_CANDIDATE_APS];
} host_log_ho_pkt_type;
/*---------------------------------------------------------------------------
This packet contains the information related to the EDCA parameters
advertised by the AP
LOG_WLAN_QOS_EDCA_C 0x149A
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint8_t aci_be;
uint8_t cw_be;
uint16_t txoplimit_be;
uint8_t aci_bk;
uint8_t cw_bk;
uint16_t txoplimit_bk;
uint8_t aci_vi;
uint8_t cw_vi;
uint16_t txoplimit_vi;
uint8_t aci_vo;
uint8_t cw_vo;
uint16_t txoplimit_vo;
} host_log_qos_edca_pkt_type;
/*---------------------------------------------------------------------------
This packet contains the total number of beacon received value
LOG_WLAN_BEACON_UPDATE_C 0x149B
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint32_t bcn_rx_cnt;
} host_log_beacon_update_pkt_type;
/*---------------------------------------------------------------------------
This packet contains the information related to a WoW pattern value when set
LOG_WLAN_POWERSAVE_WOW_ADD_PTRN_C 0x149C
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint8_t pattern_id;
uint8_t pattern_byte_offset;
uint8_t pattern_size;
uint8_t pattern[HOST_LOG_MAX_WOW_PTRN_SIZE];
uint8_t pattern_mask_size;
uint8_t pattern_mask[HOST_LOG_MAX_WOW_PTRN_MASK_SIZE];
} host_log_powersave_wow_add_ptrn_pkt_type;
/*---------------------------------------------------------------------------
This packet contains the Tspec info negotiated with the AP for the
specific AC
LOG_WLAN_QOS_TSPEC_C 0x14A2
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
uint8_t tsinfo[3];
uint16_t nominal_msdu_size;
uint16_t maximum_msdu_size;
uint32_t min_service_interval;
uint32_t max_service_interval;
uint32_t inactivity_interval;
uint32_t suspension_interval;
uint32_t svc_start_time;
uint32_t min_data_rate;
uint32_t mean_data_rate;
uint32_t peak_data_rate;
uint32_t max_burst_size;
uint32_t delay_bound;
uint32_t min_phy_rate;
uint16_t surplus_bw_allowance;
uint16_t medium_time;
} host_log_qos_tspec_pkt_type;
/*---------------------------------------------------------------------------
This packet contains data information when stall detected
LOG_TRSP_DATA_STALL_C 0x1801
---------------------------------------------------------------------------*/
typedef struct {
char channelName[4];
uint32_t numDesc;
uint32_t numFreeDesc;
uint32_t numRsvdDesc;
uint32_t headDescOrder;
uint32_t tailDescOrder;
uint32_t ctrlRegVal;
uint32_t statRegVal;
uint32_t numValDesc;
uint32_t numInvalDesc;
} host_log_data_stall_channel_type;
typedef struct {
log_hdr_type hdr;
uint32_t PowerState;
uint32_t numFreeBd;
host_log_data_stall_channel_type dxeChannelInfo[4];
} host_log_data_stall_type;
/*---------------------------------------------------------------------------
This packet contains the rssi value from BSS descriptor
LOG_WLAN_RSSI_UPDATE_C 0x1354
---------------------------------------------------------------------------*/
typedef struct {
log_hdr_type hdr;
int8_t rssi;
} host_log_rssi_pkt_type;
/**
* struct host_log_pktlog_info - Packet log info
* @log_hdr: Log header
* @version: Version
* @seq_no: Sequence number
* @buf_len: Length of the buffer that follows
* @buf: Buffer containing the packet log info
*
* Structure containing the packet log information
* LOG_WLAN_PKT_LOG_INFO_C 0x18E0
*/
struct host_log_pktlog_info {
log_hdr_type log_hdr;
uint32_t version;
uint32_t seq_no;
uint32_t buf_len;
uint8_t buf[];
};
/**
* struct host_log_cold_boot_cal_data_type - Cold boot cal log info
* @hdr: Log header
* @version: version
* @flags: Flag to indicate if more data follows
* @cb_cal_data_len: Length of the cal data
* @cb_cal_data: Cold boot cal data
*
* Structure containing the cold boot calibration data
* log information
* LOG_WLAN_COLD_BOOT_CAL_DATA_C 0x1A18
*/
struct host_log_cold_boot_cal_data_type {
log_hdr_type hdr;
uint32_t version;
uint32_t flags;
uint32_t cb_cal_data_len;
uint8_t cb_cal_data[HOST_LOG_MAX_COLD_BOOT_CAL_DATA_SIZE];
};
#define WLAN_MAX_ROAM_CANDIDATE_AP 9
#define WLAN_MAX_ROAM_SCAN_CHAN 38
#define WLAN_MAX_SSID_SIZE 32
/**
* struct host_log_wlan_mgmt_tx_rx_info - To capture TX/RX mgmt frames' payload
* @hdr: Log header
* @version: Version number of the payload
* @vdev_id: Vdev id
* @is_tx: 1 - TX frame, 0 - RX frame
* @mgmt_type: type of frames, value: enum wifi_frm_type
* @mgmt_subtype: subtype of mgmt frame, value: enum mgmt_frm_subtype
* @mgmt_frame_seq_num: Frame sequence number in 802.11 header
* @operating_freq: operating frequency of AP
* @ssid_len: length of SSID, max 32 bytes long as per standard
* @ssid: SSID of connected AP
* @self_mac_addr: mac address of self interface
* @bssid: BSSID for which frame is received
* @mac_failure_reason: Internal driver failure reason
* @mgmt_status_code: 802.11 management frame response status code from
* section 9.4.1.9 IEEE 802.11 - 2016
* @auth_algo: Authentication algorithm number
* @auth_transaction_num: Authentication transaction sequence number
* @is_retry: Is retry frame
* @rssi: RSSI for the received frame
* @origin: 1- Sent by host. 2- sent by firmware
*/
struct host_log_wlan_mgmt_tx_rx_info {
log_hdr_type hdr;
uint8_t version;
uint8_t vdev_id;
bool is_tx;
uint8_t mgmt_type;
uint8_t mgmt_subtype;
uint16_t mgmt_frame_seq_num;
uint8_t operating_freq;
uint8_t ssid_len;
char ssid[WLAN_MAX_SSID_SIZE];
uint8_t self_mac_addr[QDF_MAC_ADDR_SIZE];
uint8_t bssid[QDF_MAC_ADDR_SIZE];
uint16_t mac_failure_reason;
uint16_t mgmt_status_code;
uint8_t auth_algo;
uint8_t auth_transaction_num;
uint8_t is_retry;
uint32_t rssi;
uint8_t origin;
} qdf_packed;
/**
* struct wlan_roam_btm_trigger_data - BTM roam trigger related information
* @btm_request_mode: BTM request mode - solicited/unsolicited
* @disassoc_timer: Number of TBTT before AP disassociates the STA in ms
* @validity_interval: Preferred candidate list validity interval in ms
* @candidate_list_count: Number of candidates in BTM request.
* @btm_resp_status: Status code of the BTM response.
*/
struct wlan_roam_btm_trigger_data {
uint8_t btm_request_mode;
uint32_t disassoc_timer;
uint32_t validity_interval;
uint16_t candidate_list_count;
uint16_t btm_resp_status;
} qdf_packed;
/**
* struct wlan_roam_cu_trigger_data - BSS Load roam trigger parameters
* @cu_load: Connected AP CU load percentage
*/
struct wlan_roam_cu_trigger_data {
uint16_t cu_load;
} qdf_packed;
/**
* struct wlan_roam_rssi_trigger_data - RSSI roam trigger related
* parameters
* @threshold: RSSI threshold value in dBm for LOW rssi roam trigger
*/
struct wlan_roam_rssi_trigger_data {
uint32_t threshold;
} qdf_packed;
/**
* struct wlan_roam_deauth_trigger_data - Deauth roaming trigger related
* parameters
* @type: 1- Deauthentication 2- Disassociation
* @reason: Status code of the Deauth/Disassoc received
*/
struct wlan_roam_deauth_trigger_data {
uint8_t type;
uint32_t reason;
} qdf_packed;
/**
* struct host_log_wlan_roam_trigger_info - Roam trigger
* related info
* @hdr: Log header
* @version: Version number of the payload
* @vdev_id: Vdev id
* @trigger_reason: Roaming trigger reason
* @trigger_sub_reason: Roaming trigger sub reason
* @current_rssi: Current connected AP RSSI
* @timestamp: Host driver timestamp in msecs
* @btm_trig_data: BTM trigger related data
* @cu_load_data: CU load trigger related data
* @rssi_trig_data: RSSI roam trigger related data
* @deauth_trig_data: Deauth Roam trigger related data
*/
struct host_log_wlan_roam_trigger_info {
log_hdr_type hdr;
uint8_t version;
uint8_t vdev_id;
uint32_t trigger_reason;
uint32_t trigger_sub_reason;
uint32_t current_rssi;
uint32_t timestamp;
union {
struct wlan_roam_btm_trigger_data btm_trig_data;
struct wlan_roam_cu_trigger_data cu_load_data;
struct wlan_roam_rssi_trigger_data rssi_trig_data;
struct wlan_roam_deauth_trigger_data deauth_trig_data;
};
} qdf_packed;
/**
* struct host_log_wlan_roam_candidate_info - Roam scan candidate APs related
* info
* @version: Payload structure version
* @timestamp: Host timestamp in millisecs
* @type: 0 - Candidate AP; 1 - Current connected AP.
* @bssid: AP bssid.
* @freq: Channel frquency
* @cu_load: Channel utilization load of the AP.
* @cu_score: Channel Utilization score.
* @rssi: Candidate AP rssi
* @rssi_score: AP RSSI score
* @total_score: Total score of the candidate AP.
* @etp: Estimated throughput value of the AP in Mbps
*/
struct host_log_wlan_roam_candidate_info {
uint8_t version;
uint32_t timestamp;
uint8_t type;
uint8_t bssid[QDF_MAC_ADDR_SIZE];
uint16_t freq;
uint32_t cu_load;
uint32_t cu_score;
uint32_t rssi;
uint32_t rssi_score;
uint32_t total_score;
uint32_t etp;
} qdf_packed;
/**
* struct host_log_wlan_roam_scan_data - Roam scan event details
* @hdr: Log header
* @version: Version number of the diag log payload
* @vdev_id: Vdev ID
* @type: 0 - Partial roam scan; 1 - Full roam scan
* @num_ap: Number of candidate APs.
* @num_chan: Number of channels.
* @timestamp: Time of day in milliseconds at which scan was triggered
* @trigger_reason: Roam scan trigger reason
* @next_rssi_threshold: Next roam can trigger rssi threshold
* @chan_freq: List of frequencies scanned as part of roam scan
* @ap: List of candidate AP info
*/
struct host_log_wlan_roam_scan_data {
log_hdr_type hdr;
uint8_t version;
uint8_t vdev_id;
uint16_t type;
uint8_t num_ap;
uint8_t num_chan;
uint32_t timestamp;
uint32_t trigger_reason;
uint32_t next_rssi_threshold;
uint16_t chan_freq[WLAN_MAX_ROAM_SCAN_CHAN];
struct host_log_wlan_roam_candidate_info ap[WLAN_MAX_ROAM_CANDIDATE_AP];
} qdf_packed;
/**
* struct host_log_wlan_roam_result_info - Roam result related info.
* @hdr: Log header
* @version: Payload structure version
* @vdev_id: Vdev Id
* @status: 0 - Roaming is success ; 1 - Roaming failed
* @timestamp: Host timestamp in millisecs
* @fail_reason: One of WMI_ROAM_FAIL_REASON_ID
*/
struct host_log_wlan_roam_result_info {
log_hdr_type hdr;
uint8_t version;
uint8_t vdev_id;
bool status;
uint32_t timestamp;
uint32_t fail_reason;
} qdf_packed;
/**
* struct wlan_rrm_beacon_report - RRM beacon report related
* parameters
* @req_bssid: beacon report requestor BSSID
* @req_ssid: Requested SSID for beacon report
* @is_wildcard_bssid: Is the BSSID FF:FF:FF:FF:FF:FF
* @req_reg_class: Regulatory class mentioned in the request
* @req_measurement_mode: Measurement mode. Active/Passive/Beacon report Table
* @req_measurement_duration: Measurement duration requested.
* @num_reports_in_frame: Number of BSS scanned
* @is_last_frame_in_req: True if this frame is the last frame sent for the
* request
*/
struct wlan_rrm_beacon_report {
uint8_t req_bssid[QDF_MAC_ADDR_SIZE];
uint8_t req_ssid[WLAN_MAX_SSID_SIZE];
bool is_wildcard_bssid;
uint8_t req_reg_class;
uint16_t req_measurement_mode;
uint16_t req_measurement_duration;
uint8_t num_reports_in_frame;
bool is_last_frame_in_req;
} qdf_packed;
/**
* struct host_log_wlan_rrm_tx_rx_info - RRM frame related details
* @hdr: Log header
* @version: Version of the payload structure
* @vdev_id: Vdev id
* @origin: Sent by host or firmware
* @is_tx: Is Tx frame or RX frame
* @roam_result: Roaming result
* @timestamp: Time of the day in milliseconds
* @mgmt_frame_seq_num: Frame sequence number
* @received_chan_freq: Frame received channel frequency
* @action_category: Action frame category
* @rrm_action_code: Radio measurement/Noise measurement
* @radio_measurement_type: Neighbor report/Beacon report
* @bssid: BSSID field in frame
* @req_num_freq: Number of frequencies provided in request
* @req_freq: Frequencies requested
* @fail_reason_code: response TX failure status code
* @rssi: Rx frame rssi
* @bcn_rpt: Beacon report related parameters
*/
struct host_log_wlan_rrm_tx_rx_info {
log_hdr_type hdr;
uint8_t version;
uint8_t vdev_id;
uint8_t origin;
bool is_tx;
bool roam_result;
uint32_t timestamp;
uint16_t mgmt_frame_seq_num;
uint16_t received_chan_freq;
uint8_t action_category;
uint8_t rrm_action_code;
uint8_t radio_measurement_type;
uint8_t bssid[QDF_MAC_ADDR_SIZE];
uint8_t req_num_freq;
uint16_t req_freq[WLAN_MAX_ROAM_SCAN_CHAN];
uint8_t fail_reason_code;
uint32_t rssi;
struct wlan_rrm_beacon_report bcn_rpt;
} qdf_packed;
/**
* struct host_event_proto_pkt_info - DP protocol pkt info
* @hdr: Log header
* @version: version
* @type: data pkt type
* @subtype: data pkt subtype
* @dir: tx or rx
* @sa: source MAC address
* @da: destination MAC address
* @msdu_id: MSDU id
* @status: status
*
* Structure containing the protocol data pkt info
*
* LOG_WLAN_DP_PROTO_PKT_INFO_C 0x1A1E
*/
struct host_event_proto_pkt_info {
log_hdr_type hdr;
uint32_t version;
uint8_t type;
uint8_t subtype;
uint8_t dir;
uint8_t sa[QDF_MAC_ADDR_SIZE];
uint8_t da[QDF_MAC_ADDR_SIZE];
uint16_t msdu_id;
uint8_t status;
};
/*-------------------------------------------------------------------------
Function declarations and documentation
------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __HOST_DIAG_CORE_LOG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*============================================================================
FILE: host_diag_log.c
OVERVIEW: This source file contains definitions for WLAN UTIL diag APIs
DEPENDENCIES:
============================================================================*/
#include "qdf_types.h"
#include "i_host_diag_core_log.h"
#include "host_diag_core_event.h"
#include "wlan_nlink_common.h"
#include "cds_sched.h"
#include "wlan_ptt_sock_svc.h"
#include "wlan_nlink_srv.h"
#include "cds_api.h"
#include "wlan_ps_wow_diag.h"
#include "qdf_str.h"
#define PTT_MSG_DIAG_CMDS_TYPE (0x5050)
#define DIAG_TYPE_LOGS (1)
#define DIAG_TYPE_EVENTS (2)
#define DIAG_SWAP16(A) ((((uint16_t)(A) & 0xff00) >> 8) | (((uint16_t)(A) & 0x00ff) << 8))
typedef struct event_report_s {
uint32_t diag_type;
uint16_t event_id;
uint16_t length;
} event_report_t;
/**---------------------------------------------------------------------------
\brief host_diag_log_set_code() -
This function sets the logging code in the given log record.
\param - ptr - Pointer to the log header type.
- code - log code.
\return - None
--------------------------------------------------------------------------*/
void host_diag_log_set_code(void *ptr, uint16_t code)
{
if (ptr) {
/* All log packets are required to start with 'log_header_type' */
((log_hdr_type *) ptr)->code = code;
}
}
/**---------------------------------------------------------------------------
\brief host_diag_log_set_length() -
This function sets the length field in the given log record.
\param - ptr - Pointer to the log header type.
- length - log length.
\return - None
--------------------------------------------------------------------------*/
void host_diag_log_set_length(void *ptr, uint16_t length)
{
if (ptr) {
/* All log packets are required to start with 'log_header_type' */
((log_hdr_type *) ptr)->len = (uint16_t) length;
}
}
/**---------------------------------------------------------------------------
\brief host_diag_log_submit() -
This function sends the log data to the ptt socket app only if it is registered with the driver.
\param - ptr - Pointer to the log header type.
\return - None
--------------------------------------------------------------------------*/
void host_diag_log_submit(void *plog_hdr_ptr)
{
log_hdr_type *pHdr = (log_hdr_type *) plog_hdr_ptr;
tAniHdr *wmsg = NULL;
uint8_t *pBuf;
uint16_t data_len;
uint16_t total_len;
if (cds_is_load_or_unload_in_progress())
return;
if (nl_srv_is_initialized() != 0)
return;
if (cds_is_multicast_logging()) {
data_len = pHdr->len;
total_len = sizeof(tAniHdr) + sizeof(uint32_t) + data_len;
pBuf = (uint8_t *) qdf_mem_malloc(total_len);
if (!pBuf)
return;
wmsg = (tAniHdr *) pBuf;
wmsg->type = PTT_MSG_DIAG_CMDS_TYPE;
wmsg->length = total_len;
wmsg->length = DIAG_SWAP16(wmsg->length);
pBuf += sizeof(tAniHdr);
/* Diag Type events or log */
*(uint32_t *) pBuf = DIAG_TYPE_LOGS;
pBuf += sizeof(uint32_t);
memcpy(pBuf, pHdr, data_len);
ptt_sock_send_msg_to_app (wmsg, 0, ANI_NL_MSG_PUMAC,
INVALID_PID);
qdf_mem_free((void *)wmsg);
}
return;
}
/**
* host_diag_log_wlock() - This function is used to send wake lock diag events
* @reason: Reason why the wakelock was taken or released
* @wake_lock_name: Function in which the wakelock was taken or released
* @timeout: Timeout value in case of timed wakelocks
* @status: Status field indicating whether the wake lock was taken/released
*
* This function is used to send wake lock diag events to user space
*
* Return: None
*
*/
void host_diag_log_wlock(uint32_t reason, const char *wake_lock_name,
uint32_t timeout, uint32_t status)
{
WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
struct host_event_wlan_wake_lock);
if ((nl_srv_is_initialized() != 0) ||
(cds_is_wakelock_enabled() == false))
return;
wlan_diag_event.status = status;
wlan_diag_event.reason = reason;
wlan_diag_event.timeout = timeout;
wlan_diag_event.name_len = strlen(wake_lock_name);
strlcpy(&wlan_diag_event.name[0],
wake_lock_name,
wlan_diag_event.name_len+1);
WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_WAKE_LOCK);
}
/**---------------------------------------------------------------------------
\brief host_diag_event_report_payload() -
This function sends the event data to the ptt socket app only if it is
registered with the driver.
\param - ptr - Pointer to the log header type.
\return - None
--------------------------------------------------------------------------*/
void host_diag_event_report_payload(uint16_t event_Id, uint16_t length,
void *pPayload)
{
tAniHdr *wmsg = NULL;
uint8_t *pBuf;
event_report_t *pEvent_report;
uint16_t total_len;
int ret;
if (cds_is_load_or_unload_in_progress())
return;
if (nl_srv_is_initialized() != 0)
return;
if (cds_is_multicast_logging()) {
total_len = sizeof(tAniHdr) + sizeof(event_report_t) + length;
pBuf = (uint8_t *) qdf_mem_malloc(total_len);
if (!pBuf)
return;
wmsg = (tAniHdr *) pBuf;
wmsg->type = PTT_MSG_DIAG_CMDS_TYPE;
wmsg->length = total_len;
wmsg->length = DIAG_SWAP16(wmsg->length);
pBuf += sizeof(tAniHdr);
pEvent_report = (event_report_t *) pBuf;
pEvent_report->diag_type = DIAG_TYPE_EVENTS;
pEvent_report->event_id = event_Id;
pEvent_report->length = length;
pBuf += sizeof(event_report_t);
memcpy(pBuf, pPayload, length);
ret = ptt_sock_send_msg_to_app
(wmsg, 0, ANI_NL_MSG_PUMAC, INVALID_PID);
if ((ret < 0) && (ret != -ESRCH)) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"Ptt Socket error sending message to the app!!");
qdf_mem_free((void *)wmsg);
return;
}
qdf_mem_free((void *)wmsg);
}
return;
}
/**
* host_log_low_resource_failure() - This function is used to send low
* resource failure event
* @event_sub_type: Reason why the failure was observed
*
* This function is used to send low resource failure events to user space
*
* Return: None
*
*/
void host_log_low_resource_failure(uint8_t event_sub_type)
{
WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
struct host_event_wlan_low_resource_failure);
wlan_diag_event.event_sub_type = event_sub_type;
WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
EVENT_WLAN_LOW_RESOURCE_FAILURE);
}
void host_log_rsn_info(uint8_t *ucast_cipher, uint8_t *mcast_cipher,
uint8_t *akm_suite, uint8_t *group_mgmt)
{
WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
struct event_wlan_csr_rsn_info);
qdf_mem_copy(wlan_diag_event.ucast_cipher, ucast_cipher,
RSN_OUI_SIZE);
qdf_mem_copy(wlan_diag_event.mcast_cipher, mcast_cipher,
RSN_OUI_SIZE);
qdf_mem_copy(wlan_diag_event.akm_suite, akm_suite,
RSN_OUI_SIZE);
qdf_mem_copy(wlan_diag_event.group_mgmt, group_mgmt,
RSN_OUI_SIZE);
WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
EVENT_WLAN_RSN_INFO);
}
void
host_log_wlan_auth_info(uint16_t auth_algo_num, uint16_t auth_tx_seq_num,
uint16_t auth_status_code)
{
WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
struct event_wlan_lim_auth_info);
wlan_diag_event.auth_algo_num = auth_algo_num;
wlan_diag_event.auth_transaction_seq_num = auth_tx_seq_num;
wlan_diag_event.auth_status_code = auth_status_code;
WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event,
EVENT_WLAN_AUTH_INFO);
}
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* qdf_wow_wakeup_host_event()- send wow wakeup event
* @wow_wakeup_cause: WOW wakeup reason code
*
* This function sends wow wakeup reason code diag event
*
* Return: void.
*/
void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause)
{
WLAN_HOST_DIAG_EVENT_DEF(wowRequest,
host_event_wlan_powersave_wow_payload_type);
qdf_mem_zero(&wowRequest, sizeof(wowRequest));
wowRequest.event_subtype = WLAN_WOW_WAKEUP;
wowRequest.wow_wakeup_cause = wow_wakeup_cause;
WLAN_HOST_DIAG_EVENT_REPORT(&wowRequest,
EVENT_WLAN_POWERSAVE_WOW);
}
void host_log_acs_req_event(uint8_t *intf, const uint8_t *hw_mode, uint16_t bw,
uint8_t ht, uint8_t vht, uint16_t chan_start,
uint16_t chan_end)
{
WLAN_HOST_DIAG_EVENT_DEF(acs_req, struct host_event_wlan_acs_req);
qdf_str_lcopy(acs_req.intf, intf, HOST_EVENT_INTF_STR_LEN);
qdf_str_lcopy(acs_req.hw_mode, hw_mode, HOST_EVENT_HW_MODE_STR_LEN);
acs_req.bw = bw;
acs_req.ht = ht;
acs_req.vht = vht;
acs_req.chan_start = chan_start;
acs_req.chan_end = chan_end;
WLAN_HOST_DIAG_EVENT_REPORT(&acs_req, EVENT_WLAN_ACS_REQ);
}
void host_log_acs_scan_start(uint32_t scan_id, uint8_t vdev_id)
{
WLAN_HOST_DIAG_EVENT_DEF(acs_scan_start,
struct host_event_wlan_acs_scan_start);
acs_scan_start.scan_id = scan_id;
acs_scan_start.vdev_id = vdev_id;
WLAN_HOST_DIAG_EVENT_REPORT(&acs_scan_start,
EVENT_WLAN_ACS_SCAN_START);
}
void host_log_acs_scan_done(const uint8_t *status,
uint8_t vdev_id, uint32_t scan_id)
{
WLAN_HOST_DIAG_EVENT_DEF(acs_scan_done,
struct host_event_wlan_acs_scan_done);
qdf_str_lcopy(acs_scan_done.status, status, HOST_EVENT_STATUS_STR_LEN);
acs_scan_done.vdev_id = vdev_id;
acs_scan_done.scan_id = scan_id;
WLAN_HOST_DIAG_EVENT_REPORT(&acs_scan_done, EVENT_WLAN_ACS_SCAN_DONE);
}
void host_log_acs_chan_spect_weight(uint16_t chan, uint16_t weight,
int32_t rssi, uint16_t bss_count)
{
WLAN_HOST_DIAG_EVENT_DEF(
acs_chan_spect_weight,
struct host_event_wlan_acs_chan_spectral_weight);
acs_chan_spect_weight.chan = chan;
acs_chan_spect_weight.weight = weight;
acs_chan_spect_weight.rssi = rssi;
acs_chan_spect_weight.bss_count = bss_count;
WLAN_HOST_DIAG_EVENT_REPORT(&acs_chan_spect_weight,
EVENT_WLAN_ACS_CHANNEL_SPECTRAL_WEIGHT);
}
void host_log_acs_best_chan(uint16_t chan, uint16_t weight)
{
WLAN_HOST_DIAG_EVENT_DEF(acs_best_chan,
struct host_event_wlan_acs_best_chan);
acs_best_chan.chan = chan;
acs_best_chan.weight = weight;
WLAN_HOST_DIAG_EVENT_REPORT(&acs_best_chan,
EVENT_WLAN_ACS_BEST_CHANNEL);
}
void host_log_device_status(uint16_t status_code)
{
WLAN_HOST_DIAG_EVENT_DEF(driver_status,
host_event_wlan_bringup_status_payload_type);
driver_status.wlan_status = status_code;
/* driver version not used yet, fill properly if need later */
qdf_mem_zero(driver_status.driver_version,
sizeof(driver_status.driver_version));
WLAN_HOST_DIAG_EVENT_REPORT(&driver_status,
EVENT_WLAN_BRINGUP_STATUS);
}
#endif

View File

@@ -0,0 +1,379 @@
/*
* Copyright (c) 2014-2019, 2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(__I_HOST_DIAG_CORE_EVENT_H)
#define __I_HOST_DIAG_CORE_EVENT_H
/**=========================================================================
\file i_host_diag_core_event.h
\brief Android specific definitions for WLAN UTIL DIAG events
========================================================================*/
/* $Header$ */
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <qdf_types.h>
#ifdef FEATURE_WLAN_DIAG_SUPPORT
#include <host_diag_event_defs.h>
#endif
/*--------------------------------------------------------------------------
Preprocessor definitions and constants
------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
void host_diag_event_report_payload(uint16_t event_Id, uint16_t length,
void *pPayload);
/*---------------------------------------------------------------------------
Allocate an event payload holder
---------------------------------------------------------------------------*/
#define WLAN_HOST_DIAG_EVENT_DEF(payload_name, payload_type) \
payload_type(payload_name)
/*---------------------------------------------------------------------------
Report the event
---------------------------------------------------------------------------*/
#define WLAN_HOST_DIAG_EVENT_REPORT(payload_ptr, ev_id) \
do { \
host_diag_event_report_payload(ev_id, \
sizeof(*(payload_ptr)), \
(void *)(payload_ptr)); \
} while (0)
#else /* FEATURE_WLAN_DIAG_SUPPORT */
#define WLAN_HOST_DIAG_EVENT_DEF(payload_name, payload_type)
#define WLAN_HOST_DIAG_EVENT_REPORT(payload_ptr, ev_id)
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
/**
* enum auth_timeout_type - authentication timeout type
* @AUTH_FAILURE_TIMEOUT: auth failure timeout
* @AUTH_RESPONSE_TIMEOUT: auth response timeout
*/
enum auth_timeout_type {
AUTH_FAILURE_TIMEOUT,
AUTH_RESPONSE_TIMEOUT,
};
#ifdef CONNECTIVITY_DIAG_EVENT
/**
* enum diag_roam_reason - Represents the reason codes for roaming.
* @DIAG_ROAM_REASON_UNKNOWN: Any reason that do not classify under the below
* reasons.
* @DIAG_ROAM_REASON_PER: Roam triggered when packet error rates(PER) breached
* the configured threshold.
* @DIAG_ROAM_REASON_BEACON_MISS: Roam triggered due to the continuous
* configured beacon misses from the then connected AP.
* @DIAG_ROAM_REASON_POOR_RSSI: Roam triggered due to the poor RSSI reported
* by the connected AP.
* @DIAG_ROAM_REASON_BETTER_RSSI: Roam triggered for finding a BSSID with a
* better RSSI than the connected BSSID. Here the RSSI of the current BSSID is
* not poor.
* @DIAG_ROAM_REASON_CONGESTION: Roam triggered considering the connected
* channel or environment being very noisy / congested.
* @DIAG_ROAM_REASON_USER_TRIGGER: Roam triggered due to an explicit request
* from the user (user space).
* @DIAG_ROAM_REASON_BTM: Roam triggered due to BTM request frame received from
* connected AP.
* @DIAG_ROAM_REASON_BSS_LOAD: Roam triggered due to the channel utilization
* breaching out the configured threshold.
* @DIAG_ROAM_REASON_WTC: Roam triggered due to Wireless to Cellular BSS
* transition request.
* @DIAG_ROAM_REASON_IDLE: Roam triggered when device is suspended,
* there is no data activity with the AP and the current rssi falls below a
* certain threshold.
* @DIAG_ROAM_REASON_DISCONNECTION: Roam triggered due to
* deauthentication or disassociation frames received from the connected AP.
* @DIAG_ROAM_REASON_PERIODIC_TIMER: Roam triggered as part of the periodic
* scan that happens when there is no candidate AP found during the poor
* RSSI scan trigger.
* @DIAG_ROAM_REASON_BACKGROUND_SCAN: Roam triggered based on the scan
* results obtained from an external scan (not aimed at roaming).
* @DIAG_ROAM_REASON_BT_ACTIVITY: Roam triggered due to bluetooth
* connection is established when the station is connected in 2.4 Ghz band.
*/
enum diag_roam_reason {
DIAG_ROAM_REASON_UNKNOWN,
DIAG_ROAM_REASON_PER,
DIAG_ROAM_REASON_BEACON_MISS,
DIAG_ROAM_REASON_POOR_RSSI,
DIAG_ROAM_REASON_BETTER_RSSI,
DIAG_ROAM_REASON_CONGESTION,
DIAG_ROAM_REASON_USER_TRIGGER,
DIAG_ROAM_REASON_BTM,
DIAG_ROAM_REASON_BSS_LOAD,
DIAG_ROAM_REASON_WTC,
DIAG_ROAM_REASON_IDLE,
DIAG_ROAM_REASON_DISCONNECTION,
DIAG_ROAM_REASON_PERIODIC_TIMER,
DIAG_ROAM_REASON_BACKGROUND_SCAN,
DIAG_ROAM_REASON_BT_ACTIVITY
};
/**
* enum diag_roam_sub_reason - Used by attribute
* @DIAG_ROAM_SUB_REASON_UNKNOWN: Roam sub-reason unknown/unspecified
* @DIAG_ROAM_SUB_REASON_PERIODIC_TIMER: Roam scan triggered due to periodic
* timer expiry
* @DIAG_ROAM_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI: Roam scan trigger due
* to no candidate found during LOW RSSI trigger.
* @DIAG_ROAM_SUB_REASON_BTM_DI_TIMER: Roam scan triggered due to BTM Disassoc
* Imminent timeout
* @DIAG_ROAM_SUB_REASON_FULL_SCAN: Roam scan triggered due to partial scan
* failure
* @DIAG_ROAM_SUB_REASON_LOW_RSSI_PERIODIC: Roam trigger due to
* emergency like deauth/disassoc.
* @DIAG_ROAM_SUB_REASON_CU_PERIODIC: Roam trigger due to
* BSS transition management request.
* @DIAG_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_LOW_RSSI:
* Roam scan triggered due to Low RSSI periodic timer
* @DIAG_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU:
* Roam trigger due to periodic timer after no candidate found during CU
* inactivity timer scan.
* @DIAG_ROAM_SUB_REASON_INACTIVITY_TIMER_CU: Roam trigger due to no candidate
* found in high CU roam trigger.
*/
enum diag_roam_sub_reason {
DIAG_ROAM_SUB_REASON_UNKNOWN = 0,
DIAG_ROAM_SUB_REASON_PERIODIC_TIMER = 1,
DIAG_ROAM_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI = 2,
DIAG_ROAM_SUB_REASON_BTM_DI_TIMER = 3,
DIAG_ROAM_SUB_REASON_FULL_SCAN = 4,
DIAG_ROAM_SUB_REASON_LOW_RSSI_PERIODIC = 5,
DIAG_ROAM_SUB_REASON_CU_PERIODIC = 6,
DIAG_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_LOW_RSSI = 7,
DIAG_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU = 8,
DIAG_ROAM_SUB_REASON_INACTIVITY_TIMER_CU = 9,
};
#endif
/*-------------------------------------------------------------------------
Function declarations and documentation
------------------------------------------------------------------------*/
#ifdef FEATURE_WLAN_DIAG_SUPPORT
void host_diag_log_wlock(uint32_t reason, const char *wake_lock_name,
uint32_t timeout, uint32_t status);
#else
static inline void host_diag_log_wlock(uint32_t reason,
const char *wake_lock_name,
uint32_t timeout, uint32_t status)
{
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
void host_log_low_resource_failure(uint8_t event_sub_type);
#else
static inline void host_log_low_resource_failure(uint8_t event_sub_type)
{
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* host_log_rsn_info() - This function is used to send
* requested rsn info in assoc request
* @ucast_cipher: Unicast ciphers used in assoc request
* @mcast_cipher: Group ciphers used in assoc request
* @auth_suite: Gives information about akm suites used in assoc request
* @gp_mgmt_cipher: Requested group mgmt cipher suite
*
* This function is used to send RSN info used in assoc req to user space
*
* Return: None
*
*/
void host_log_rsn_info(uint8_t *ucast_cipher, uint8_t *mcast_cipher,
uint8_t *auth_suite, uint8_t *gp_mgmt_cipher);
#else
static inline void host_log_rsn_info(uint8_t *ucast_cipher,
uint8_t *mcast_cipher,
uint8_t *auth_suite,
uint8_t *gp_mgmt_cipher)
{
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* host_log_wlan_auth_info() - This function is used to send
* algo num, seq num and status code for auth request
* @auth_algo_num: Gives information about algo num used in auth request
* @auth_tx_seq_num: seq num of auth request
* @auth_status_code: status code of auth request
*
* This function is used to send send algo num, seq num and status code
* for auth request
*
* Return: None
*
*/
void
host_log_wlan_auth_info(uint16_t auth_algo_num, uint16_t auth_tx_seq_num,
uint16_t auth_status_code);
#else
static inline void
host_log_wlan_auth_info(uint16_t auth_algo_num, uint16_t auth_tx_seq_num,
uint16_t auth_status_code)
{
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause);
/**
* host_log_acs_req_event() - ACS request event indication
* @intf: network interface name for WLAN
* @hw_mode: hw mode configured by hostapd
* @bw: channel bandwidth (MHz)
* @ht: a flag indicating whether HT phy mode is enabled
* @vht: a flag indicating whether VHT phy mode is enabled
* @chan_start: starting channel number for ACS scan
* @chan_end: ending channel number for ACS scan
*
* Indicates the diag event for ACS request with payload related
* to parameters populated by hostapd
*
* Return: None
*/
void host_log_acs_req_event(uint8_t *intf, const uint8_t *hw_mode,
uint16_t bw, uint8_t ht, uint8_t vht,
uint16_t chan_start, uint16_t chan_end);
/**
* host_log_acs_scan_start() - ACS scan start event indication
* @scan_id: scan request ID
* @vdev_id: vdev/session ID
*
* Indicates the diag event for ACS scan start request
*
* Return: None
*/
void host_log_acs_scan_start(uint32_t scan_id, uint8_t vdev_id);
/**
* host_log_acs_scan_done() - ACS scan done event indication
* @status: indicating whether ACS scan is successful
* @vdev_id: vdev/session ID
* @scan_id: scan request ID
*
* Indicates the diag event for ACS scan done
*
* Return: None
*/
void host_log_acs_scan_done(const uint8_t *status, uint8_t vdev_id,
uint32_t scan_id);
/**
* host_log_acs_chan_spect_weight() - ACS channel spectral weight indication
* weight event indication
* @chan: channel number
* @weight: channel weight
* @rssi: RSSI value obtained after scanning
* @bss_count: number of BSS detected on this channel
*
* Indicates a diag event for ACS channel weight evaluation result
*
* Return: None
*/
void host_log_acs_chan_spect_weight(uint16_t chan, uint16_t weight,
int32_t rssi, uint16_t bss_count);
/**
* host_log_acs_best_chan() - ACS best channel event indication
* @chan: channel number
* @weight: channel weight
*
* Indicates the best channel has been selected after ACS
*
* Return: None
*/
void host_log_acs_best_chan(uint16_t chan, uint16_t weight);
/**
* host_log_device_status() - device status indication
* @status_code: status code from enum wlan_bringup_status
*
* Indicates device status
*
* Return: None
*/
void host_log_device_status(uint16_t status_code);
#else
static inline void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause)
{
return;
}
static inline void host_log_acs_req_event(uint8_t *intf, const uint8_t *hw_mode,
uint16_t bw, uint8_t ht, uint8_t vht,
uint16_t chan_start,
uint16_t chan_end)
{
}
static inline void host_log_acs_scan_start(uint32_t scan_id, uint8_t vdev_id)
{
}
static inline void host_log_acs_scan_done(const uint8_t *status,
uint8_t vdev_id, uint32_t scan_id)
{
}
static inline void host_log_acs_chan_spect_weight(uint16_t chan,
uint16_t weight, int32_t rssi,
uint16_t bss_count)
{
}
static inline void host_log_acs_best_chan(uint16_t chan, uint32_t weight)
{
}
static inline void host_log_device_status(uint16_t status_code)
{
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __I_HOST_DIAG_CORE_EVENT_H */

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(__I_HOST_DIAG_CORE_LOG_H)
#define __I_HOST_DIAG_CORE_LOG_H
#include <log_codes.h>
/**=========================================================================
\file i_host_diag_core_event.h
\brief android-specific definitions for WLAN UTIL DIAG logs
========================================================================*/
/* $Header$ */
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <qdf_types.h>
#include <qdf_mem.h>
/*--------------------------------------------------------------------------
Preprocessor definitions and constants
------------------------------------------------------------------------*/
/* FIXME To be removed when DIAG support is added. This definition should be */
/* picked from log.h file above. */
typedef struct {
/* Specifies the length, in bytes of the entry, including this header. */
uint16_t len;
/* Specifies the log code for the entry */
uint16_t code;
/*Time Stamp lo */
uint32_t ts_lo;
/*Time Stamp hi */
uint32_t ts_hi;
} __packed log_hdr_type;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
void host_diag_log_set_code(void *ptr, uint16_t code);
void host_diag_log_set_length(void *ptr, uint16_t length);
void host_diag_log_set_timestamp(void *plog_hdr_ptr);
void host_diag_log_submit(void *plog_hdr_ptr);
/*---------------------------------------------------------------------------
Allocate an event payload holder
---------------------------------------------------------------------------*/
#define WLAN_HOST_DIAG_LOG_ALLOC(payload_ptr, payload_type, log_code) \
do { \
payload_ptr = (payload_type *)qdf_mem_malloc(sizeof(payload_type)); \
if (payload_ptr) { \
host_diag_log_set_code(payload_ptr, log_code); \
host_diag_log_set_length(payload_ptr, sizeof(payload_type)); \
} \
} while (0)
/*---------------------------------------------------------------------------
Report the event
---------------------------------------------------------------------------*/
#define WLAN_HOST_DIAG_LOG_REPORT(payload_ptr) \
do { \
if (payload_ptr) { \
host_diag_log_submit(payload_ptr); \
qdf_mem_free(payload_ptr); \
} \
} while (0)
/*---------------------------------------------------------------------------
Free the payload
---------------------------------------------------------------------------*/
#define WLAN_HOST_DIAG_LOG_FREE(payload_ptr) \
do { \
if (payload_ptr) { \
qdf_mem_free(payload_ptr); \
} \
} while (0)
#else /* FEATURE_WLAN_DIAG_SUPPORT */
#define WLAN_HOST_DIAG_LOG_ALLOC(payload_ptr, payload_type, log_code)
#define WLAN_HOST_DIAG_LOG_REPORT(payload_ptr)
#define WLAN_HOST_DIAG_LOG_FREE(payload_ptr)
static inline void host_diag_log_set_code(void *ptr, uint16_t code)
{
}
static inline void host_diag_log_set_length(void *ptr, uint16_t length)
{
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
/*-------------------------------------------------------------------------
Function declarations and documentation
------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __I_HOST_DIAG_CORE_LOG_H */

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/******************************************************************************
* wlan_logging_sock_svc.h
*
******************************************************************************/
#ifndef WLAN_LOGGING_SOCK_SVC_H
#define WLAN_LOGGING_SOCK_SVC_H
#include <wlan_nlink_srv.h>
#include <qdf_status.h>
#include <qdf_trace.h>
#include <wlan_nlink_common.h>
int wlan_logging_sock_init_svc(void);
int wlan_logging_sock_deinit_svc(void);
int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length);
/**
* wlan_logging_set_flush_timer() - Sets the time period for log flush timer
* @milliseconds: Time period in milliseconds
*
* This function sets the time period interval during which the log buffers
* will be flushed out to user space. Setting this interval can set an
* approximate maximum delay after which any message logged through QDF_TRACE
* will appear at user-space
*
* Return: void
*/
int wlan_logging_set_flush_timer(uint32_t milliseconds);
/**
* wlan_logging_notifier_init() - registers to panic notifier chain
* @dump_at_kernel_enable: qdf logging at kernel level enabled
*
* This function registers an handler to panic notifier chain if
* qdf logging at kernel level is disabled.
*
* Return: 0 on success
*/
int wlan_logging_notifier_init(bool dump_at_kernel_enable);
/**
* wlan_logging_notifier_deinit() - unregisters to panic notifier chain
* @dump_at_kernel_enable: qdf logging at kernel level enabled
*
* This function unregisters an handler to panic notifier chain if
* qdf logging at kernel level is disabled.
*
* Return: 0 on success
*/
int wlan_logging_notifier_deinit(bool dump_at_kernel_enable);
#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
/**
* wlan_logging_wait_for_flush_log_completion() - Wait for flush log completion
*
* Return: QDF_STATUS
*/
QDF_STATUS wlan_logging_wait_for_flush_log_completion(void);
void wlan_logging_set_per_pkt_stats(void);
/**
* wlan_logging_set_connectivity_log() - INterrupt the gwlan_logging thread
* to send the connectivity logs
*
* Return: None
*/
void wlan_logging_set_connectivity_log(void);
void wlan_logging_set_fw_flush_complete(void);
void wlan_flush_host_logs_for_fatal(void);
void wlan_logging_set_active(bool active);
void wlan_set_console_log_levels(uint32_t console_log_levels);
#else
static inline QDF_STATUS wlan_logging_wait_for_flush_log_completion(void)
{
return QDF_STATUS_SUCCESS;
}
static inline void wlan_flush_host_logs_for_fatal(void) {}
static inline void wlan_logging_set_per_pkt_stats(void) {}
static inline void wlan_logging_set_fw_flush_complete(void) {}
static inline void wlan_logging_set_active(bool active) {}
static inline void wlan_set_console_log_levels(uint32_t console_log_levels) {}
#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */
#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) && \
defined(CONNECTIVITY_PKTLOG)
/**
* wlan_deregister_txrx_packetdump() - tx/rx packet dump
* deregistration
* @pdev_id: id of the datapath pdev handle
*
* This function is used to deregister tx/rx packet dump callbacks
* with ol, pe and htt layers
*
* Return: None
*
*/
void wlan_deregister_txrx_packetdump(uint8_t pdev_id);
/**
* wlan_register_txrx_packetdump() - tx/rx packet dump
* registration
* @pdev_id: id of the datapath pdev handle
*
* This function is used to register tx/rx packet dump callbacks
* with ol, pe and htt layers
*
* Return: None
*
*/
void wlan_register_txrx_packetdump(uint8_t pdev_id);
#else
static inline void wlan_deregister_txrx_packetdump(uint8_t pdev_id) {}
static inline void wlan_register_txrx_packetdump(uint8_t pdev_id) {}
#endif
#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) && defined(FEATURE_WLAN_DIAG_SUPPORT)
void wlan_report_log_completion(uint32_t is_fatal,
uint32_t indicator,
uint32_t reason_code,
uint8_t ring_id);
#else
static inline void wlan_report_log_completion(uint32_t is_fatal,
uint32_t indicator,
uint32_t reason_code,
uint8_t ring_id)
{
return;
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) && \
defined(CONNECTIVITY_PKTLOG)
void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data);
#else
static inline
void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
{
}
#endif
/**
* enum tx_status - tx status
* @tx_status_ok: successfully sent + acked
* @tx_status_discard: discard - not sent (congestion control)
* @tx_status_no_ack: no_ack - sent, but no ack
* @tx_status_download_fail: download_fail -
* the host could not deliver the tx frame to the target
* @tx_status_peer_del: peer_del - tx completion for
* already deleted peer used for HL case
*
* This enum has tx status types
*/
enum tx_status {
tx_status_ok,
tx_status_discard,
tx_status_no_ack,
tx_status_download_fail,
tx_status_peer_del,
};
#ifdef WLAN_CHIPSET_STATS
void wlan_set_chipset_stats_bit(void);
#else
static inline void wlan_set_chipset_stats_bit(void)
{
}
#endif /* WLAN_CHIPSET_STATS */
#endif /* WLAN_LOGGING_SOCK_SVC_H */

View File

@@ -0,0 +1,250 @@
/*
* Copyright (c) 2013-2019, 2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* DOC: Roaming debug log operations declarations
*/
#ifndef _WLAN_ROAM_DEBUG_H_
#define _WLAN_ROAM_DEBUG_H_
#define roam_debug(args ...) \
QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_ROAM_DEBUG, ## args)
#define roam_info(args ...) \
QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_ROAM_DEBUG, ## args)
#define wlan_rec_conn_info(vdev_id, op, mac_addr, arg1, arg2) \
wlan_rec_debug_log(REC_CONN, vdev_id, op, 0, mac_addr, 0, arg1,\
arg2)
#ifndef WLAN_ROAM_DEBUG_MAX_REC
#define WLAN_ROAM_DEBUG_MAX_REC 128
#endif
typedef enum {
REC_ROAM,
REC_CONN,
REC_MAX,
} wlan_rec_type;
/**
* @DEBUG_PEER_CREATE_SEND: sent peer_create command to firmware
* @DEBUG_PEER_CREATE_RESP: received peer create response
* @DEBUG_PEER_DELETE_SEND: sent peer delete command to firmware
* @DEBUG_PEER_DELETE_RESP: received peer delete response
* @DEBUG_PEER_MAP_EVENT: received peer map event
* @DEBUG_PEER_UNMAP_EVENT: received peer unmap event
* @DEBUG_PEER_UNREF_DELETE: peer reference is decremented
* @DEBUG_DELETING_PEER_OBJ: peer object is deleted
* @DEBUG_ROAM_SYNCH_IND: received roam offload sync indication
* @DEBUG_ROAM_SYNCH_CNF: sent roam offload sync confirmation
* @DEBUG_ROAM_SYNCH_FAIL: received roam sync failure indication
* @DEBUG_ROAM_EVENT: received roam event
* @DEBUG_BUS_SUSPEND: host going into suspend mode
* @DEBUG_BUS_RESUME: host operation resumed
* @DEBUG_CONN_CONNECTING: trace connecting to bssid
* @DEBUG_CONN_ASSOCIATION: trace association completion
* @DEBUG_CONN_CONNECT_RESULT: trace connect result to os
* @DEBUG_CONN_ROAMING: trace station roaming propagtion
* @DEBUG_CONN_ROAMED: trace roamed to bssid
* @DEBUG_CONN_ROAMED_IND: trace roam indication
* @DEBUG_CONN_DISCONNECT: trace station disconnect
* @DEBUG_CONN_DISCONNECT_HANDLER: trace disconnect handler
* @DEBUG_CONN_DISCONNECT_IND: trace disconnect indication
* @DEBUG_CONN_RSO: trace RSO state changing
*/
enum peer_debug_op {
DEBUG_PEER_CREATE_SEND = 0,
DEBUG_PEER_CREATE_RESP,
DEBUG_PEER_DELETE_SEND,
DEBUG_PEER_DELETE_RESP,
DEBUG_PEER_MAP_EVENT,
DEBUG_PEER_UNMAP_EVENT,
DEBUG_PEER_UNREF_DELETE,
DEBUG_DELETING_PEER_OBJ,
DEBUG_ROAM_SYNCH_IND,
DEBUG_ROAM_SYNCH_CNF,
DEBUG_ROAM_SYNCH_FAIL,
DEBUG_ROAM_EVENT,
DEBUG_WOW_ROAM_EVENT,
DEBUG_BUS_SUSPEND,
DEBUG_BUS_RESUME,
DEBUG_WOW_REASON,
DEBUG_CONN_CONNECTING,
DEBUG_CONN_ASSOCIATION,
DEBUG_CONN_CONNECT_RESULT,
DEBUG_CONN_ROAMING,
DEBUG_CONN_ROAMED,
DEBUG_CONN_ROAMED_IND,
DEBUG_CONN_DISCONNECT,
DEBUG_CONN_DISCONNECT_HANDLER,
DEBUG_CONN_DISCONNECT_IND,
DEBUG_CONN_RSO,
};
/**
* struct wlan_roam_debug_rec - roam debug information record definition
* @time: timestamp when record was added
* @operation: identifier for operation, command, event, etc.
* @vdev_id: vdev identifier
* @peer_id: peer_id. Range 0 - 255, 0xffff is invalid peer_id.
* @mac_addr: mac address of peer
* @peer_obj: pointer to peer object
* @arg1: Optional argument #1
* @arg2: Opttional argument #2
*/
struct wlan_roam_debug_rec {
uint64_t time;
enum peer_debug_op operation;
uint8_t vdev_id;
uint16_t peer_id;
struct qdf_mac_addr mac_addr;
void *peer_obj;
uint32_t arg1;
uint32_t arg2;
};
/**
* struct wlan_roam_debug_info - Buffer to store the wma debug records
* @index: index of the most recent entry in the circular buffer
* @num_max_rec: maximum records stored in the records array
* @rec: array to store wma debug records, used in circular fashion
*/
struct wlan_roam_debug_info {
qdf_atomic_t index;
uint32_t num_max_rec;
void (*rec_print)(struct wlan_roam_debug_rec *dbg_rec,
uint32_t idx, uint32_t delta,
bool to_kernel);
struct wlan_roam_debug_rec rec[WLAN_ROAM_DEBUG_MAX_REC];
};
#define DEBUG_INVALID_PEER_ID 0xffff
#define DEBUG_INVALID_VDEV_ID 0xff
#ifdef FEATURE_ROAM_DEBUG
/**
* wlan_roam_debug_log() - Add a debug log entry to wlan roam debug records
* @vdev_id: vdev identifier
* @op: operation identifier
* @peer_id: peer id
* @mac_addr: mac address of peer, can be NULL
* @peer_obj: peer object address, can be NULL
* @arg1: extra argument #1
* @arg2: extra argument #2
*
* Return: none
*/
void wlan_roam_debug_log(uint8_t vdev_id, uint8_t op,
uint16_t peer_id, void *mac_addr,
void *peer_obj, uint32_t arg1, uint32_t arg2);
/**
* wlan_rec_debug_log() - Add a debug log entry to wlan debug records
* @rec_type: record type
* @vdev_id: vdev identifier
* @op: operation identifier
* @peer_id: peer id
* @mac_addr: mac address of peer, can be NULL
* @peer_obj: peer object address, can be NULL
* @arg1: extra argument #1
* @arg2: extra argument #2
*
* Return: none
*/
void wlan_rec_debug_log(wlan_rec_type rec_type, uint8_t vdev_id, uint8_t op,
uint16_t peer_id, const void *mac_addr,
void *peer_obj, uint32_t arg1, uint32_t arg2);
/**
* wlan_roam_debug_dump_table() - Print the roam debug log records
* print all the valid debug records in the order of timestamp
*
* Return: none
*/
void wlan_roam_debug_dump_table(void);
/**
* wlan_rec_debug_dump_table() - Print the wlan roam debug log records
* @rec_type: recorad type
* @count: count of records to print
* @to_kernel: print to kernel or not
*
* print all the valid debug records in the order of timestamp
*
* Return: none
*/
void wlan_rec_debug_dump_table(wlan_rec_type rec_type, uint32_t count,
bool to_kernel);
#ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
/**
* wlan_roam_debug_init() - Allocate log buffer dynamically
*
* Return: none
*/
void wlan_roam_debug_init(void);
/**
* wlan_roam_debug_deinit() - Free log buffer allocated dynamically
*
* Return: none
*/
void wlan_roam_debug_deinit(void);
#else /* WLAN_LOGGING_BUFFERS_DYNAMICALLY */
static inline void wlan_roam_debug_init(void)
{
}
static inline void wlan_roam_debug_deinit(void)
{
}
#endif /* WLAN_LOGGING_BUFFERS_DYNAMICALLY */
#else /* FEATURE_ROAM_DEBUG */
static inline void
wlan_roam_debug_log(uint8_t vdev_id, uint8_t op,
uint16_t peer_id, void *mac_addr,
void *peer_obj, uint32_t arg1, uint32_t arg2)
{
}
static inline void wlan_rec_debug_log(
wlan_rec_type rec_type, uint8_t vdev_id, uint8_t op,
uint16_t peer_id, const void *mac_addr,
void *peer_obj, uint32_t arg1, uint32_t arg2)
{
}
static inline void wlan_roam_debug_dump_table(void)
{
}
static inline void wlan_rec_debug_dump_table(wlan_rec_type rec_type,
uint32_t count,
bool to_kernel)
{
}
static inline void wlan_roam_debug_init(void)
{
}
static inline void wlan_roam_debug_deinit(void)
{
}
#endif /* FEATURE_ROAM_DEBUG */
#endif /* _WLAN_ROAM_DEBUG_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,368 @@
/*
* Copyright (c) 2013-2018, 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* DOC: Roaming debug log operations routines and global data
*/
#include <qdf_types.h>
#include <qdf_atomic.h>
#include <qdf_mem.h>
#include <qdf_time.h>
#include <qdf_trace.h>
#include <qdf_module.h>
#include <wlan_cmn.h>
#include "wlan_roam_debug.h"
#ifdef FEATURE_ROAM_DEBUG
static void wlan_roam_rec_print(struct wlan_roam_debug_rec *dbg_rec,
uint32_t idx, uint32_t delta,
bool to_kernel);
static void wlan_conn_rec_print(struct wlan_roam_debug_rec *dbg_rec,
uint32_t idx, uint32_t delta,
bool to_kernel);
#ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
static struct wlan_roam_debug_info *global_wlan_roam_debug_table;
/**
* wlan_roam_debug_init() - Allocate log buffer dynamically
*
* Return: none
*/
void wlan_roam_debug_init(void)
{
uint8_t i;
global_wlan_roam_debug_table = qdf_mem_valloc(
sizeof(struct wlan_roam_debug_info) * REC_MAX);
QDF_BUG(global_wlan_roam_debug_table);
if (global_wlan_roam_debug_table) {
for (i = 0; i < REC_MAX; i++) {
qdf_atomic_init(&global_wlan_roam_debug_table[i].index);
global_wlan_roam_debug_table[i].num_max_rec =
WLAN_ROAM_DEBUG_MAX_REC;
if (i == REC_ROAM)
global_wlan_roam_debug_table[i].rec_print =
wlan_roam_rec_print;
else
global_wlan_roam_debug_table[i].rec_print =
wlan_conn_rec_print;
}
}
}
qdf_export_symbol(wlan_roam_debug_init);
static inline struct wlan_roam_debug_info *wlan_roam_debug_get_table(
wlan_rec_type type)
{
if (type >= REC_MAX)
return NULL;
return &global_wlan_roam_debug_table[type];
}
/**
* wlan_roam_debug_deinit() - Free log buffer allocated dynamically
*
* Return: none
*/
void wlan_roam_debug_deinit(void)
{
qdf_mem_vfree(global_wlan_roam_debug_table);
global_wlan_roam_debug_table = NULL;
}
qdf_export_symbol(wlan_roam_debug_deinit);
#else /* WLAN_LOGGING_BUFFERS_DYNAMICALLY */
/*
* wlan roam debug log is stored in this global structure. It can be accessed
* without requiring any psoc or vdev context. It will be accessible in
* the crash dump without having to dereference complex stack traces.
*/
static struct wlan_roam_debug_info global_wlan_roam_debug_table[REC_MAX] = {
[REC_ROAM] = {{ 0 },
.num_max_rec = WLAN_ROAM_DEBUG_MAX_REC,
.rec_print = wlan_roam_rec_print},
[REC_CONN] = {{ 0 },
.num_max_rec = WLAN_ROAM_DEBUG_MAX_REC,
.rec_print = wlan_conn_rec_print},
};
static inline struct wlan_roam_debug_info *wlan_roam_debug_get_table(
wlan_rec_type type)
{
if (type >= REC_MAX)
return NULL;
return &global_wlan_roam_debug_table[type];
}
#endif /* WLAN_LOGGING_BUFFERS_DYNAMICALLY */
/**
* wlan_roam_next_debug_log_index() - atomically increment and wrap around index
* @index: address of index to increment
* @size: wrap around this value
*
* Return: new value of index
*/
static int wlan_roam_next_debug_log_index(qdf_atomic_t *index, int size)
{
int i = qdf_atomic_inc_return(index);
if (i == WLAN_ROAM_DEBUG_MAX_REC)
qdf_atomic_sub(WLAN_ROAM_DEBUG_MAX_REC, index);
while (i >= size)
i -= WLAN_ROAM_DEBUG_MAX_REC;
return i;
}
/**
* wlan_roam_debug_log() - Add a debug log entry to wlan roam debug records
* @vdev_id: vdev identifier
* @op: operation identifier
* @peer_id: peer id
* @mac_addr: mac address of peer, can be NULL
* @peer_obj: peer object address, can be NULL
* @arg1: extra argument #1
* @arg2: extra argument #2
*
* Return: none
*/
void wlan_roam_debug_log(uint8_t vdev_id, uint8_t op,
uint16_t peer_id, void *mac_addr,
void *peer_obj, uint32_t arg1, uint32_t arg2)
{
wlan_rec_debug_log(REC_ROAM, vdev_id, op, peer_id, mac_addr,
peer_obj, arg1, arg2);
}
qdf_export_symbol(wlan_roam_debug_log);
void wlan_rec_debug_log(wlan_rec_type rec_type, uint8_t vdev_id, uint8_t op,
uint16_t peer_id, const void *mac_addr,
void *peer_obj, uint32_t arg1, uint32_t arg2)
{
uint32_t i;
struct wlan_roam_debug_info *dbg_tbl;
struct wlan_roam_debug_rec *rec;
dbg_tbl = wlan_roam_debug_get_table(rec_type);
if (!dbg_tbl)
return;
i = wlan_roam_next_debug_log_index(
&dbg_tbl->index,
WLAN_ROAM_DEBUG_MAX_REC);
rec = &dbg_tbl->rec[i];
rec->time = qdf_get_log_timestamp();
rec->operation = op;
rec->vdev_id = vdev_id;
rec->peer_id = peer_id;
if (mac_addr)
qdf_mem_copy(rec->mac_addr.bytes, mac_addr,
QDF_MAC_ADDR_SIZE);
else
qdf_mem_zero(rec->mac_addr.bytes,
QDF_MAC_ADDR_SIZE);
rec->peer_obj = peer_obj;
rec->arg1 = arg1;
rec->arg2 = arg2;
}
qdf_export_symbol(wlan_rec_debug_log);
/**
* wlan_roam_debug_string() - convert operation value to printable string
* @op: operation identifier
*
* Return: printable string for the operation
*/
static char *wlan_roam_debug_string(uint32_t op)
{
switch (op) {
case DEBUG_PEER_CREATE_SEND:
return "peer create send";
case DEBUG_PEER_CREATE_RESP:
return "peer create resp_event";
case DEBUG_PEER_DELETE_SEND:
return "peer delete send";
case DEBUG_PEER_DELETE_RESP:
return "peer delete resp_event";
case DEBUG_PEER_MAP_EVENT:
return "peer map event";
case DEBUG_PEER_UNMAP_EVENT:
return "peer unmap event";
case DEBUG_PEER_UNREF_DELETE:
return "peer unref delete";
case DEBUG_DELETING_PEER_OBJ:
return "peer obj deleted";
case DEBUG_ROAM_SYNCH_IND:
return "roam synch ind event";
case DEBUG_ROAM_SYNCH_CNF:
return "roam sync conf sent";
case DEBUG_ROAM_SYNCH_FAIL:
return "roam sync fail event";
case DEBUG_ROAM_EVENT:
return "roam event";
case DEBUG_WOW_ROAM_EVENT:
return "wow wakeup roam event";
case DEBUG_BUS_SUSPEND:
return "host suspend";
case DEBUG_BUS_RESUME:
return "host wakeup";
case DEBUG_WOW_REASON:
return "wow wakeup reason";
case DEBUG_CONN_CONNECTING:
return "conn";
case DEBUG_CONN_ASSOCIATION:
return "assoc";
case DEBUG_CONN_CONNECT_RESULT:
return "cnrlt";
case DEBUG_CONN_ROAMING:
return "roaming";
case DEBUG_CONN_ROAMED:
return "roamed";
case DEBUG_CONN_ROAMED_IND:
return "rmind";
case DEBUG_CONN_DISCONNECT:
return "disc";
case DEBUG_CONN_DISCONNECT_HANDLER:
return "dishdr";
case DEBUG_CONN_DISCONNECT_IND:
return "disind";
case DEBUG_CONN_RSO:
return "rso";
default:
return "unknown";
}
}
void wlan_roam_rec_print(struct wlan_roam_debug_rec *dbg_rec,
uint32_t idx, uint32_t delta,
bool to_kernel)
{
roam_debug("index = %5d timestamp = 0x%016llx delta ms = %-12u",
idx, dbg_rec->time, delta);
roam_debug("info = %-24s vdev_id = %-3d mac addr = "QDF_MAC_ADDR_FMT,
wlan_roam_debug_string(dbg_rec->operation),
(int8_t)dbg_rec->vdev_id,
QDF_MAC_ADDR_REF(dbg_rec->mac_addr.bytes));
roam_debug("peer obj = 0x%pK peer_id = %-4d", dbg_rec->peer_obj,
(int8_t)dbg_rec->peer_id);
roam_debug("arg1 = 0x%-8x arg2 = 0x%-8x", dbg_rec->arg1,
dbg_rec->arg2);
}
void wlan_conn_rec_print(struct wlan_roam_debug_rec *dbg_rec,
uint32_t idx, uint32_t delta,
bool to_kernel)
{
if (to_kernel) {
roam_info("i %d ti 0x%08llx ms %u vdv %d %s a1 0x%x a2 0x%x "QDF_MAC_ADDR_FMT,
idx, dbg_rec->time, delta, (int8_t)dbg_rec->vdev_id,
wlan_roam_debug_string(dbg_rec->operation),
dbg_rec->arg1, dbg_rec->arg2,
QDF_MAC_ADDR_REF(dbg_rec->mac_addr.bytes));
} else {
roam_debug("i %d ti 0x%08llx ms %u vdv %d %s a1 0x%x a2 0x%x "QDF_MAC_ADDR_FMT,
idx, dbg_rec->time, delta, (int8_t)dbg_rec->vdev_id,
wlan_roam_debug_string(dbg_rec->operation),
dbg_rec->arg1, dbg_rec->arg2,
QDF_MAC_ADDR_REF(dbg_rec->mac_addr.bytes));
}
}
/**
* wlan_rec_debug_dump_table() - Print the wlan roam debug log records
* print all the valid debug records in the order of timestamp
*
* Return: none
*/
void wlan_rec_debug_dump_table(wlan_rec_type rec_type, uint32_t count,
bool to_kernel)
{
uint32_t i;
int32_t current_index;
struct wlan_roam_debug_info *dbg_tbl;
struct wlan_roam_debug_rec *dbg_rec;
uint64_t startt = 0;
uint32_t delta;
#define DEBUG_CLOCK_TICKS_PER_MSEC 19200
if (count > WLAN_ROAM_DEBUG_MAX_REC)
count = WLAN_ROAM_DEBUG_MAX_REC;
dbg_tbl = wlan_roam_debug_get_table(rec_type);
if (!dbg_tbl)
return;
current_index = qdf_atomic_read(&dbg_tbl->index);
if (current_index < 0) {
roam_debug("No records to dump");
return;
}
roam_debug("dump %d rec type %d idx %d", count, rec_type,
current_index);
i = (current_index + WLAN_ROAM_DEBUG_MAX_REC - count) %
WLAN_ROAM_DEBUG_MAX_REC;
do {
/* wrap around */
i = (i + 1) % WLAN_ROAM_DEBUG_MAX_REC;
dbg_rec = &dbg_tbl->rec[i];
/* skip unused entry */
if (dbg_rec->time == 0)
continue;
if (count == 0)
break;
count--;
if (startt == 0)
startt = dbg_rec->time;
/*
* Divide by 19200 == right shift 8 bits, then divide by 75
* 32 bit computation keeps both 32 and 64 bit compilers happy.
* The value will roll over after approx. 33554 seconds.
*/
delta = (uint32_t) (((dbg_rec->time - startt) >> 8) &
0xffffffff);
delta = delta / (DEBUG_CLOCK_TICKS_PER_MSEC >> 8);
if (dbg_tbl->rec_print)
dbg_tbl->rec_print(dbg_rec, i, delta, to_kernel);
} while (i != current_index);
}
qdf_export_symbol(wlan_rec_debug_dump_table);
/**
* wlan_roam_debug_dump_table() - Print the wlan roam debug log records
* print all the valid debug records in the order of timestamp
*
* Return: none
*/
void wlan_roam_debug_dump_table(void)
{
wlan_rec_debug_dump_table(REC_ROAM, WLAN_ROAM_DEBUG_MAX_REC, false);
}
qdf_export_symbol(wlan_roam_debug_dump_table);
#endif /* FEATURE_ROAM_DEBUG */

View File

@@ -0,0 +1,287 @@
/*
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*===========================================================================
\file wlan_nlink_common.h
Exports and types for the Netlink Service interface. This header file contains
message types and definitions that is shared between the user space service
(e.g. logging service) and WLAN kernel module.
===========================================================================*/
#ifndef WLAN_NLINK_COMMON_H__
#define WLAN_NLINK_COMMON_H__
#include <linux/netlink.h>
#ifdef __KERNEL__
#include <linux/if.h>
#else
#include <net/if.h>
#endif
/*---------------------------------------------------------------------------
* External Functions
*-------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
* Preprocessor Definitions and Constants
*-------------------------------------------------------------------------*/
#define WLAN_NL_MAX_PAYLOAD 5120 /* maximum size for netlink message */
#define WLAN_NLINK_PROTO_FAMILY NETLINK_USERSOCK
#define WLAN_NLINK_MCAST_GRP_ID 0x01
/*---------------------------------------------------------------------------
* Type Declarations
*-------------------------------------------------------------------------*/
/*
* The following enum defines the target service within WLAN driver for which the
* message is intended for. Each service along with its counterpart
* in the user space, define a set of messages they recognize.
* Each of this message will have an header of type tAniMsgHdr defined below.
* Each Netlink message to/from a kernel module will contain only one
* message which is preceded by a tAniMsgHdr. The maximum size (in bytes) of
* a netlink message is assumed to be MAX_PAYLOAD bytes.
*
* +------------+-------+----------+----------+
* |Netlink hdr | Align |tAniMsgHdr| msg body |
* +------------+-------+----------|----------+
*/
/* Message Types */
#define WLAN_SVC_FW_CRASHED_IND 0x100
#define WLAN_SVC_LTE_COEX_IND 0x101
#define WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND 0x102
#define WLAN_SVC_DFS_CAC_START_IND 0x103
#define WLAN_SVC_DFS_CAC_END_IND 0x104
#define WLAN_SVC_DFS_RADAR_DETECT_IND 0x105
#define WLAN_SVC_WLAN_STATUS_IND 0x106
#define WLAN_SVC_WLAN_VERSION_IND 0x107
#define WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND 0x108
#define WLAN_SVC_WLAN_TP_IND 0x109
#define WLAN_SVC_RPS_ENABLE_IND 0x10A
#define WLAN_SVC_WLAN_TP_TX_IND 0x10B
#define WLAN_SVC_WLAN_AUTO_SHUTDOWN_CANCEL_IND 0x10C
#define WLAN_SVC_WLAN_RADIO_INDEX 0x10D
#define WLAN_SVC_FW_SHUTDOWN_IND 0x10E
#define WLAN_SVC_CORE_MINFREQ 0x10F
#define WLAN_SVC_MAX_SSID_LEN 32
#define WLAN_SVC_MAX_BSSID_LEN 6
#define WLAN_SVC_MAX_STR_LEN 16
#define WLAN_SVC_MAX_NUM_CHAN 128
#define WLAN_SVC_COUNTRY_CODE_LEN 3
#define ANI_NL_MSG_BASE 0x10 /* Some arbitrary base */
typedef enum eAniNlModuleTypes {
ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01, /* PTT Socket App */
ANI_NL_MSG_PTT = ANI_NL_MSG_BASE + 0x07, /* Quarky GUI */
WLAN_NL_MSG_OEM = ANI_NL_MSG_BASE + 0x09,
WLAN_NL_MSG_SVC = ANI_NL_MSG_BASE + 0x0a,
WLAN_NL_MSG_CNSS_DIAG = ANI_NL_MSG_BASE + 0x0B, /* Value needs to be 27 */
ANI_NL_MSG_LOG,
WLAN_NL_MSG_SPECTRAL_SCAN,
ANI_NL_MSG_MAX
} tAniNlModTypes, tWlanNlModTypes;
#define WLAN_NL_MSG_BASE ANI_NL_MSG_BASE
#define WLAN_NL_MSG_MAX ANI_NL_MSG_MAX
/* All Netlink messages must contain this header */
typedef struct sAniHdr {
unsigned short type;
unsigned short length;
} tAniHdr, tAniMsgHdr;
typedef struct sAniNlMsg {
struct nlmsghdr nlh; /* Netlink Header */
int radio; /* unit number of the radio */
tAniHdr wmsg; /* Airgo Message Header */
} tAniNlHdr;
struct radio_index_tlv {
unsigned short type;
unsigned short length;
int radio;
};
/**
* struct svc_channel_info - Channel information
* @chan_id: Channel ID
* @reserved0: Reserved for padding and future use
* @mhz: Primary 20 MHz channel frequency in MHz
* @band_center_freq1: Center frequency 1 in MHz
* @band_center_freq2: Center frequency 2 in MHz
* @info: Channel info
* @reg_info_1: Regulatory information field 1 which contains
* MIN power, MAX power, reg power and reg class ID
* @reg_info_2: Regulatory information field 2 which contains antennamax
*/
struct svc_channel_info {
uint32_t chan_id;
uint32_t reserved0;
uint32_t mhz;
uint32_t band_center_freq1;
uint32_t band_center_freq2;
uint32_t info;
uint32_t reg_info_1;
uint32_t reg_info_2;
};
struct wlan_status_data {
uint8_t lpss_support;
uint8_t is_on;
uint8_t vdev_id;
uint8_t is_connected;
int8_t rssi;
uint8_t ssid_len;
uint8_t country_code[WLAN_SVC_COUNTRY_CODE_LEN];
uint32_t vdev_mode;
uint32_t freq;
uint32_t numChannels;
uint8_t channel_list[WLAN_SVC_MAX_NUM_CHAN];
uint8_t ssid[WLAN_SVC_MAX_SSID_LEN];
uint8_t bssid[WLAN_SVC_MAX_BSSID_LEN];
struct svc_channel_info channel_info[WLAN_SVC_MAX_NUM_CHAN];
};
struct wlan_version_data {
uint32_t chip_id;
char chip_name[WLAN_SVC_MAX_STR_LEN];
char chip_from[WLAN_SVC_MAX_STR_LEN];
char host_version[WLAN_SVC_MAX_STR_LEN];
char fw_version[WLAN_SVC_MAX_STR_LEN];
};
struct wlan_dfs_info {
uint16_t channel;
uint8_t country_code[WLAN_SVC_COUNTRY_CODE_LEN];
};
/*
* Maximum number of queues supported by WLAN driver. Setting an upper
* limit. Actual number of queues may be smaller than this value.
*/
#define WLAN_SVC_IFACE_NUM_QUEUES 6
/**
* struct wlan_rps_data - structure to send RPS info to cnss-daemon
* @ifname: interface name for which the RPS data belongs to
* @num_queues: number of rx queues for which RPS data is being sent
* @cpu_map_list: array of cpu maps for different rx queues supported by
* the wlan driver
*
* The structure specifies the format of data exchanged between wlan
* driver and cnss-daemon. On receipt of the data, cnss-daemon is expected
* to apply the 'cpu_map' for each rx queue belonging to the interface 'ifname'
*/
struct wlan_rps_data {
char ifname[IFNAMSIZ];
uint16_t num_queues;
uint16_t cpu_map_list[WLAN_SVC_IFACE_NUM_QUEUES];
};
/**
* enum wlan_tp_level - indicates wlan throughput level
* @WLAN_SVC_TP_NONE: used for initialization
* @WLAN_SVC_TP_LOW: used to identify low throughput level
* @WLAN_SVC_TP_MEDIUM: used to identify medium throughput level
* @WLAN_SVC_TP_HIGH: used to identify high throughput level
*
* The different throughput levels are determined on the basis of # of tx and
* rx packets and other threshold values. For example, if the # of total
* packets sent or received by the driver is greater than 500 in the last 100ms
* , the driver has a high throughput requirement. The driver may tweak certain
* system parameters based on the throughput level.
*/
enum wlan_tp_level {
WLAN_SVC_TP_NONE,
WLAN_SVC_TP_LOW,
WLAN_SVC_TP_MEDIUM,
WLAN_SVC_TP_HIGH,
};
/**
* struct wlan_core_minfreq - msg to [re]set the min freq of a set of cores
* @magic: signature token: 0xBABA
* @reserved: unused for now
* @coremask: bitmap of cores (16 bits) bit0=CORE0, bit1=CORE1, ...
* coremask is ONLY valid for set command
* valid values: 0xf0, or 0x0f
* @freq: frequency in KH
* > 0: "set to the given frequency"
* == 0: "free; remove the lock"
*
* Msg structure passed by the driver to cnss-daemon.
*
* Semantical Alert:
* There can be only one outstanding lock, even for different masks.
*/
#define WLAN_CORE_MINFREQ_MAGIC 0xBABA
struct wlan_core_minfreq {
uint16_t magic;
uint16_t reserved;
uint16_t coremask;
uint16_t freq;
};
/* Indication to enable TCP delayed ack in TPUT indication */
#define TCP_DEL_ACK_IND (1 << 0)
#define TCP_DEL_ACK_IND_MASK 0x1
/* Indication to enable TCP advance window scaling in TPUT indication */
#define TCP_ADV_WIN_SCL (1 << 1)
#define TCP_ADV_WIN_SCL_MASK 0x2
/* TCP limit output bytes for low and high TPUT */
#define TCP_LIMIT_OUTPUT_BYTES_LOW 506072
#define TCP_LIMIT_OUTPUT_BYTES_HI 4048579
/* TCP window scale for low and high TPUT */
#define WIN_SCALE_LOW 2
#define WIN_SCALE_HI 1
/* TCP DEL ACK value for low and high TPUT */
#define TCP_DEL_ACK_LOW 0
#define TCP_DEL_ACK_HI 20
/**
* struct wlan_rx_tp_data - msg to TCP delayed ack and advance window scaling
* @level: Throughput level.
* @rx_tp_flags: Bit map of flags, for which this indcation will take
* effect, bit map for TCP_ADV_WIN_SCL and TCP_DEL_ACK_IND.
*/
struct wlan_rx_tp_data {
enum wlan_tp_level level;
uint16_t rx_tp_flags;
};
/**
* struct wlan_tx_tp_data - msg to TCP for Tx Dir
* @level: Throughput level.
* @tcp_limit_output: Tcp limit output flag.
*
*/
struct wlan_tx_tp_data {
enum wlan_tp_level level;
bool tcp_limit_output;
};
#endif /* WLAN_NLINK_COMMON_H__ */

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2012-2017, 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/******************************************************************************
* wlan_nlink_srv.h
*
* wlan_nlink_srv is used to RX/TX Netlink messages from user space to kernel
* modules and vice versa. Kernel modules must register a message handler for a
* message type so that the wlan_nlink_srv can invoke the corresponding msg handler
* whenever a Netlink message of a particular type has been received from an
* application. In the opposite direction, wlan_nlink_srv provides a mechanism
* which kernel modules can use to send Netlink messages to applications.
*
******************************************************************************/
#ifndef WLAN_NLINK_SRV_H
#define WLAN_NLINK_SRV_H
#include <linux/skbuff.h>
#include <net/netlink.h>
#include <wlan_nlink_common.h>
#define INVALID_PID -1
#define NLINK_MAX_CALLBACKS (WLAN_NL_MSG_MAX - WLAN_NL_MSG_BASE)
typedef int (*nl_srv_msg_callback)(struct sk_buff *skb);
/**
* cld80211_oem_send_reply() - API to send cld80211 msg
* @skb: Sk buffer
* @hdr: nl80211hdr pointer
* @nest: pointer of vendor nested attribute
* @flags: Flags
*
* API to send cld80211 msg to applications
*
* Return: None
*/
void cld80211_oem_send_reply(struct sk_buff *msg, void *hdr,
struct nlattr *nest, int flags);
/**
* nl80211hdr_put() - API to allocate skb for cld80211 msg
* @hdr: nl80211hdr pointer
* @portid: Port ID
* @nest: pointer of vendor nested attribute
* @flags: Flags
*
* API to allocate skb for cld80211 msg
*
* Return: Pointer to skbuff
*/
struct sk_buff *
cld80211_oem_rsp_alloc_skb(uint32_t portid, void **hdr, struct nlattr **nest,
int *flags);
int nl_srv_init(void *wiphy, int proto);
void nl_srv_exit(void);
int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler);
int nl_srv_unregister(tWlanNlModTypes msg_type,
nl_srv_msg_callback msg_handler);
#ifdef CNSS_GENL
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag,
int app_id, int mcgroup_id);
int nl_srv_bcast(struct sk_buff *skb, int mcgroup_id, int app_id);
/**
* nl80211hdr_put() - API to fill genlmsg header
* @skb: Sk buffer
* @portid: Port ID
* @seq: Sequence number
* @flags: Flags
* @cmd: Command id
*
* API to fill genl message header for broadcast events to user space
*
* Return: Pointer to user specific header/payload
*/
void *nl80211hdr_put(struct sk_buff *skb, uint32_t portid,
uint32_t seq, int flags, uint8_t cmd);
#else
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag);
int nl_srv_bcast(struct sk_buff *skb);
#endif
int nl_srv_is_initialized(void);
void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag);
#endif

View File

@@ -0,0 +1,846 @@
/*
* Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/******************************************************************************
* wlan_nlink_srv.c
*
* This file contains the definitions specific to the wlan_nlink_srv
*
******************************************************************************/
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <wlan_nlink_srv.h>
#include <qdf_trace.h>
#include <qdf_module.h>
#define WLAN_CLD80211_MAX_SIZE (SKB_WITH_OVERHEAD(8192UL) - NLMSG_HDRLEN)
#if defined(CONFIG_CNSS_LOGGER)
#include <net/cnss_logger.h>
static int radio_idx = -EINVAL;
static void *wiphy_ptr;
static bool logger_initialized;
/**
* nl_srv_init() - wrapper function to register to cnss_logger
* @wiphy: the pointer to the wiphy structure
* @proto: the host log netlink protocol
*
* The netlink socket is no longer initialized in the driver itself, instead
* will be initialized in the cnss_logger module, the driver should register
* itself to cnss_logger module to get the radio_index for all the netlink
* operation. (cfg80211 vendor command is using different netlink socket).
*
* The cnss_logger_device_register() use to register the driver with the
* wiphy structure and the module name (debug purpose) and then return the
* radio_index depending on the availability.
*
* Return: radio index for success and -EINVAL for failure
*/
int nl_srv_init(void *wiphy, int proto)
{
if (logger_initialized)
goto initialized;
wiphy_ptr = wiphy;
radio_idx = cnss_logger_device_register(wiphy, THIS_MODULE->name);
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"%s: radio_index: %d, wiphy_ptr: %pK",
__func__, radio_idx, wiphy_ptr);
if (radio_idx >= 0)
logger_initialized = true;
initialized:
return radio_idx;
}
/**
* nl_srv_exit() - wrapper function to unregister from cnss_logger
*
* The cnss_logger_device_unregister() use to unregister the driver with
* the radio_index assigned and wiphy structure from cnss_logger.
*
* Return: None
*/
void nl_srv_exit(void)
{
if (logger_initialized) {
cnss_logger_device_unregister(radio_idx, wiphy_ptr);
radio_idx = -EINVAL;
wiphy_ptr = NULL;
logger_initialized = false;
}
}
/**
* nl_srv_ucast() - wrapper function to do unicast tx through cnss_logger
* @skb: the socket buffer to send
* @dst_pid: the port id
* @flag: the blocking or nonblocking flag
*
* The nl_srv_is_initialized() is used to do sanity check if the netlink
* service is ready, e.g if the radio_index is assigned properly, if not
* the driver should take the responsibility to free the skb.
*
* The cnss_logger_nl_ucast() use the same parameters to send the socket
* buffers.
*
* Return: the error of the transmission status
*/
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
{
int err = -EINVAL;
/* sender's pid */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
NETLINK_CB(skb).pid = 0;
#else
NETLINK_CB(skb).portid = 0;
#endif
/* not multicast */
NETLINK_CB(skb).dst_group = 0;
if (nl_srv_is_initialized() == 0) {
err = cnss_logger_nl_ucast(skb, dst_pid, flag);
if (err < 0)
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: netlink_unicast to pid[%d] failed, ret[%d]",
dst_pid, err);
} else {
dev_kfree_skb(skb);
}
return err;
}
/**
* nl_srv_bcast() - wrapper function to do broadcast tx through cnss_logger
* @skb: the socket buffer to send
*
* The cnss_logger_nl_bcast() is used to transmit the socket buffer.
*
* Return: status of transmission
*/
int nl_srv_bcast(struct sk_buff *skb)
{
int err = -EINVAL;
int flags = GFP_KERNEL;
if (in_interrupt() || irqs_disabled() || in_atomic())
flags = GFP_ATOMIC;
/* sender's pid */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
NETLINK_CB(skb).pid = 0;
#else
NETLINK_CB(skb).portid = 0;
#endif
/* destination group */
NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID;
if (nl_srv_is_initialized() == 0) {
err = cnss_logger_nl_bcast(skb, WLAN_NLINK_MCAST_GRP_ID, flags);
if ((err < 0) && (err != -ESRCH)) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: netlink_broadcast failed err = %d",
err);
dev_kfree_skb(skb);
}
}
else
dev_kfree_skb(skb);
return err;
}
qdf_export_symbol(nl_srv_bcast);
/**
* nl_srv_unregister() - wrapper function to unregister event to cnss_logger
* @msg_type: the message to unregister
* @msg_handler: the message handler
*
* The cnss_logger_event_unregister() is used to unregister the message and
* message handler.
*
* Return: 0 if successfully unregister, otherwise proper error code
*/
int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
int ret = -EINVAL;
if (nl_srv_is_initialized() != 0)
return ret;
if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
msg_handler) {
ret = cnss_logger_event_unregister(radio_idx, msg_type,
msg_handler);
} else {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"NLINK: nl_srv_unregister failed for msg_type %d",
msg_type);
ret = -EINVAL;
}
return ret;
}
/**
* nl_srv_register() - wrapper function to register event to cnss_logger
* @msg_type: the message to register
* @msg_handler: the message handler
*
* The cnss_logger_event_register() is used to register the message and
* message handler.
*
* Return: 0 if successfully register, otherwise proper error code
*/
int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
int ret = -EINVAL;
if (nl_srv_is_initialized() != 0)
return ret;
if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
msg_handler) {
ret = cnss_logger_event_register(radio_idx, msg_type,
msg_handler);
} else {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"NLINK: nl_srv_register failed for msg_type %d",
msg_type);
ret = -EINVAL;
}
return ret;
}
/**
* nl_srv_is_initialized() - check if netlink service is initialized
*
* Return: 0 if it is initialized, otherwise error code
*/
inline int nl_srv_is_initialized(void)
{
if (logger_initialized)
return 0;
else
return -EPERM;
}
qdf_export_symbol(nl_srv_is_initialized);
/*
* If MULTI_IF_NAME is not defined, then this is the primary instance of the
* driver and the diagnostics netlink socket will be available. If
* MULTI_IF_NAME is defined then this is not the primary instance of the driver
* and the diagnostics netlink socket will not be available since this
* diagnostics netlink socket can only be exposed by one instance of the driver.
*/
#elif defined(CNSS_GENL)
#include <qdf_mem.h>
#include <wlan_nlink_common.h>
#include <net/genetlink.h>
#ifdef CONFIG_CNSS_OUT_OF_TREE
#include "cnss_nl.h"
#else
#include <net/cnss_nl.h>
#endif
void cld80211_oem_send_reply(struct sk_buff *msg, void *hdr,
struct nlattr *nest, int flags)
{
struct genl_family *cld80211_fam = cld80211_get_genl_family();
nla_nest_end(msg, nest);
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0,
CLD80211_MCGRP_OEM_MSGS, flags);
}
struct sk_buff *
cld80211_oem_rsp_alloc_skb(uint32_t portid, void **hdr, struct nlattr **nest,
int *flags)
{
struct sk_buff *msg;
if (in_interrupt() || irqs_disabled() || in_atomic())
*flags = GFP_ATOMIC;
msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, *flags);
if (!msg) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nlmsg malloc fails");
return NULL;
}
*hdr = nl80211hdr_put(msg, portid, 0, *flags, WLAN_NL_MSG_OEM);
if (*hdr == NULL) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nl80211 hdr put failed");
goto nla_put_failure;
}
*nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA);
if (*nest == NULL) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nla_nest_start failed");
goto nla_put_failure;
}
return msg;
nla_put_failure:
genlmsg_cancel(msg, *hdr);
nlmsg_free(msg);
return NULL;
}
/* For CNSS_GENL netlink sockets will be initialized by CNSS Kernel Module */
int nl_srv_init(void *wiphy, int proto)
{
return 0;
}
void nl_srv_exit(void)
{
}
int nl_srv_is_initialized(void)
{
return 0;
}
/* Not implemented by CNSS kernel module */
int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
return 0;
}
int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
return 0;
}
void *nl80211hdr_put(struct sk_buff *skb, uint32_t portid,
uint32_t seq, int flags, uint8_t cmd)
{
struct genl_family *cld80211_fam = cld80211_get_genl_family();
return genlmsg_put(skb, portid, seq, cld80211_fam, flags, cmd);
}
/**
* cld80211_fill_data() - API to fill payload to nl message
* @msg: Sk buffer
* @portid: Port ID
* @seq: Sequence number
* @flags: Flags
* @cmd: Command ID
* @buf: data buffer/payload to be filled
* @len: length of the payload ie. @buf
*
* API to fill the payload/data of the nl message to be sent
*
* Return: zero on success
*/
static int cld80211_fill_data(struct sk_buff *msg, uint32_t portid,
uint32_t seq, int flags, uint8_t cmd,
uint8_t *buf, int len)
{
void *hdr;
struct nlattr *nest;
hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
if (!hdr) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nl80211 hdr put failed");
return -EPERM;
}
nest = nla_nest_start(msg, CLD80211_ATTR_VENDOR_DATA);
if (!nest) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nla_nest_start failed");
goto nla_put_failure;
}
if (nla_put(msg, CLD80211_ATTR_DATA, len, buf)) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nla_put failed");
goto nla_put_failure;
}
nla_nest_end(msg, nest);
genlmsg_end(msg, hdr);
return 0;
nla_put_failure:
genlmsg_cancel(msg, hdr);
return -EPERM;
}
/**
* send_msg_to_cld80211() - API to send message to user space Application
* @mcgroup_id: Multicast group ID
* @pid: Port ID
* @app_id: Application ID
* @buf: Data/payload buffer to be sent
* @len: Length of the data ie. @buf
*
* API to send the nl message to user space application.
*
* Return: zero on success
*/
static int send_msg_to_cld80211(int mcgroup_id, int pid, int app_id,
uint8_t *buf, int len)
{
struct sk_buff *msg;
struct genl_family *cld80211_fam = cld80211_get_genl_family();
int status;
int flags = GFP_KERNEL;
if (in_interrupt() || irqs_disabled() || in_atomic())
flags = GFP_ATOMIC;
if (len > NLMSG_DEFAULT_SIZE) {
if (len > WLAN_CLD80211_MAX_SIZE) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"buf size:%d if more than max size: %d",
len, (int) WLAN_CLD80211_MAX_SIZE);
return -ENOMEM;
}
msg = nlmsg_new(WLAN_CLD80211_MAX_SIZE, flags);
} else {
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, flags);
}
if (!msg) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"nlmsg malloc fails");
return -EPERM;
}
status = cld80211_fill_data(msg, pid, 0, 0, app_id, buf, len);
if (status) {
nlmsg_free(msg);
return -EPERM;
}
genlmsg_multicast_netns(cld80211_fam, &init_net, msg, 0,
mcgroup_id, flags);
return 0;
}
/**
* nl_srv_bcast() - wrapper function to do broadcast events to user space apps
* @skb: the socket buffer to send
* @mcgroup_id: multicast group id
* @app_id: application id
*
* This function is common wrapper to send broadcast events to different
* user space applications.
*
* return: none
*/
int nl_srv_bcast(struct sk_buff *skb, int mcgroup_id, int app_id)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
void *msg = NLMSG_DATA(nlh);
uint32_t msg_len = nlmsg_len(nlh);
int status;
status = send_msg_to_cld80211(mcgroup_id, 0, app_id, msg, msg_len);
if (status) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"send msg to cld80211 fails for app id %d", app_id);
dev_kfree_skb(skb);
return -EPERM;
}
dev_kfree_skb(skb);
return 0;
}
qdf_export_symbol(nl_srv_bcast);
/**
* nl_srv_ucast() - wrapper function to do unicast events to user space apps
* @skb: the socket buffer to send
* @dst_pid: destination process IF
* @flag: flags
* @app_id: application id
* @mcgroup_id: Multicast group ID
*
* This function is common wrapper to send unicast events to different
* user space applications. This internally used broadcast API with multicast
* group mcgrp_id. This wrapper serves as a common API in both
* new generic netlink infra and legacy implementation.
*
* return: zero on success, error code otherwise
*/
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag,
int app_id, int mcgroup_id)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
void *msg = NLMSG_DATA(nlh);
uint32_t msg_len = nlmsg_len(nlh);
int status;
status = send_msg_to_cld80211(mcgroup_id, dst_pid, app_id,
msg, msg_len);
if (status) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"send msg to cld80211 fails for app id %d", app_id);
dev_kfree_skb(skb);
return -EPERM;
}
dev_kfree_skb(skb);
return 0;
}
#elif !defined(MULTI_IF_NAME) || defined(MULTI_IF_LOG)
/* Global variables */
static DEFINE_MUTEX(nl_srv_sem);
static struct sock *nl_srv_sock;
static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS];
/* Forward declaration */
static void nl_srv_rcv(struct sk_buff *sk);
static void nl_srv_rcv_skb(struct sk_buff *skb);
static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh);
/*
* Initialize the netlink service.
* Netlink service is usable after this.
*/
int nl_srv_init(void *wiphy, int proto)
{
int retcode = 0;
struct netlink_kernel_cfg cfg = {
.groups = WLAN_NLINK_MCAST_GRP_ID,
.input = nl_srv_rcv
};
nl_srv_sock = netlink_kernel_create(&init_net, proto,
&cfg);
if (nl_srv_sock) {
memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler));
} else {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"NLINK: netlink_kernel_create failed");
retcode = -ECONNREFUSED;
}
return retcode;
}
/*
* Deinit the netlink service.
* Netlink service is unusable after this.
*/
void nl_srv_exit(void)
{
if (nl_srv_is_initialized() == 0)
netlink_kernel_release(nl_srv_sock);
nl_srv_sock = NULL;
}
/*
* Register a message handler for a specified module.
* Each module (e.g. WLAN_NL_MSG_BTC )will register a
* handler to handle messages addressed to it.
*/
int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
int retcode = 0;
if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
msg_handler) {
nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler;
} else {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: nl_srv_register failed for msg_type %d",
msg_type);
retcode = -EINVAL;
}
return retcode;
}
qdf_export_symbol(nl_srv_register);
/*
* Unregister the message handler for a specified module.
*/
int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
int retcode = 0;
if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) &&
(nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) {
nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL;
} else {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: nl_srv_unregister failed for msg_type %d",
msg_type);
retcode = -EINVAL;
}
return retcode;
}
/*
* Unicast the message to the process in user space identfied
* by the dst-pid
*/
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
{
int err = -EINVAL;
NETLINK_CB(skb).portid = 0; /* sender's pid */
NETLINK_CB(skb).dst_group = 0; /* not multicast */
if (nl_srv_sock) {
err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag);
if (err < 0)
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: netlink_unicast to pid[%d] failed, ret[%d]",
dst_pid, err);
} else {
dev_kfree_skb(skb);
}
return err;
}
/*
* Broadcast the message. Broadcast will return an error if
* there are no listeners
*/
int nl_srv_bcast(struct sk_buff *skb)
{
int err = -EINVAL;
int flags = GFP_KERNEL;
if (in_interrupt() || irqs_disabled() || in_atomic())
flags = GFP_ATOMIC;
NETLINK_CB(skb).portid = 0; /* sender's pid */
NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; /* destination group */
if (nl_srv_sock) {
err = netlink_broadcast(nl_srv_sock, skb, 0,
WLAN_NLINK_MCAST_GRP_ID, flags);
if ((err < 0) && (err != -ESRCH)) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: netlink_broadcast failed err = %d",
err);
dev_kfree_skb(skb);
}
} else
dev_kfree_skb(skb);
return err;
}
qdf_export_symbol(nl_srv_bcast);
/*
* Processes the Netlink socket input queue.
* Dequeue skb's from the socket input queue and process
* all the netlink messages in that skb, before moving
* to the next skb.
*/
static void nl_srv_rcv(struct sk_buff *sk)
{
mutex_lock(&nl_srv_sem);
nl_srv_rcv_skb(sk);
mutex_unlock(&nl_srv_sem);
}
/*
* Each skb could contain multiple Netlink messages. Process all the
* messages in one skb and discard malformed skb's silently.
*/
static void nl_srv_rcv_skb(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
while (skb->len >= NLMSG_SPACE(0)) {
u32 rlen;
nlh = (struct nlmsghdr *)skb->data;
if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: Invalid "
"Netlink message: skb[%pK], len[%d], nlhdr[%pK], nlmsg_len[%d]",
skb, skb->len, nlh, nlh->nlmsg_len);
return;
}
rlen = NLMSG_ALIGN(nlh->nlmsg_len);
if (rlen > skb->len)
rlen = skb->len;
nl_srv_rcv_msg(skb, nlh);
skb_pull(skb, rlen);
}
}
/*
* Process a netlink message.
* Each netlink message will have a message of type tAniMsgHdr inside.
*/
static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
int type;
/* Only requests are handled by kernel now */
if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD,
"NLINK: Received Invalid NL Req type [%x]",
nlh->nlmsg_flags);
return;
}
type = nlh->nlmsg_type;
/* Unknown message */
if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) {
QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD,
"NLINK: Received Invalid NL Msg type [%x]",
type);
return;
}
/*
* All the messages must at least carry the tAniMsgHdr
* Drop any message with invalid length
*/
if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) {
QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD,
"NLINK: Received NL Msg with invalid len[%x]",
nlh->nlmsg_len);
return;
}
/* turn type into dispatch table offset */
type -= WLAN_NL_MSG_BASE;
/* dispatch to handler */
if (nl_srv_msg_handler[type]) {
(nl_srv_msg_handler[type])(skb);
} else {
QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD,
"NLINK: No handler for msg [0x%X]", type);
}
}
/**
* nl_srv_is_initialized() - This function is used check if the netlink
* service is initialized
*
* This function is used check if the netlink service is initialized
*
* Return: Return -EPERM if the service is not initialized
*
*/
int nl_srv_is_initialized(void)
{
if (nl_srv_sock)
return 0;
return -EPERM;
}
qdf_export_symbol(nl_srv_is_initialized);
#else
int nl_srv_init(void *wiphy, int proto)
{
return 0;
}
void nl_srv_exit(void)
{
}
int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
return 0;
}
int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler)
{
return 0;
}
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag)
{
dev_kfree_skb(skb);
return 0;
}
int nl_srv_bcast(struct sk_buff *skb)
{
dev_kfree_skb(skb);
return 0;
}
qdf_export_symbol(nl_srv_bcast);
int nl_srv_is_initialized(void)
{
return -EPERM;
}
qdf_export_symbol(nl_srv_is_initialized);
#endif
/**
* nl_srv_ucast_oem() - Wrapper function to send ucast msgs to OEM
* @skb: sk buffer pointer
* @dst_pid: Destination PID
* @flag: flags
*
* Sends the ucast message to OEM with generic nl socket if CNSS_GENL
* is enabled. Else, use the legacy netlink socket to send.
*
* Return: None
*/
#ifdef CNSS_GENL
void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag)
{
nl_srv_ucast(skb, dst_pid, flag, WLAN_NL_MSG_OEM,
CLD80211_MCGRP_OEM_MSGS);
}
#else
void nl_srv_ucast_oem(struct sk_buff *skb, int dst_pid, int flag)
{
nl_srv_ucast(skb, dst_pid, flag);
}
qdf_export_symbol(nl_srv_ucast_oem);
#endif

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _PKTLOG_
#define _PKTLOG_
#ifndef REMOVE_PKT_LOG
/**
* @typedef ol_pktlog_dev_handle
* @brief opaque handle for pktlog device object
*/
struct ol_pktlog_dev_t;
typedef struct ol_pktlog_dev_t *ol_pktlog_dev_handle;
#endif /* #ifndef REMOVE_PKT_LOG */
#endif /* _PKTLOG_ */

View File

@@ -0,0 +1,234 @@
/*
* Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _PKTLOG_AC_H_
#define _PKTLOG_AC_H_
#include "hif.h"
#if defined(CONNECTIVITY_PKTLOG) || !defined(REMOVE_PKT_LOG)
#include "ol_if_athvar.h"
#include "osdep.h"
#include <wmi_unified.h>
#include <wmi_unified_api.h>
#include <wdi_event_api.h>
#include <ol_defines.h>
#include <pktlog_ac_api.h>
#include <pktlog_ac_fmt.h>
#define NO_REG_FUNCS 4
/* Locking interface for pktlog */
#define PKTLOG_LOCK_INIT(_pl_info) qdf_spinlock_create(&(_pl_info)->log_lock)
#define PKTLOG_LOCK_DESTROY(_pl_info) \
qdf_spinlock_destroy(&(_pl_info)->log_lock)
#define PKTLOG_LOCK(_pl_info) qdf_spin_lock_bh(&(_pl_info)->log_lock)
#define PKTLOG_UNLOCK(_pl_info) qdf_spin_unlock_bh(&(_pl_info)->log_lock)
#define PKTLOG_MODE_SYSTEM 1
#define PKTLOG_MODE_ADAPTER 2
/*
* The proc entry starts with magic number and version field which will be
* used by post processing scripts. These fields are not needed by applications
* that do not use these scripts. This is skipped using the offset value.
*/
#define PKTLOG_READ_OFFSET 8
/* forward declaration for cdp_pdev */
struct cdp_pdev;
/* Opaque softc */
struct ol_ath_generic_softc_t;
typedef struct ol_ath_generic_softc_t *ol_ath_generic_softc_handle;
extern void pktlog_disable_adapter_logging(struct hif_opaque_softc *scn);
extern int pktlog_alloc_buf(struct hif_opaque_softc *scn);
extern void pktlog_release_buf(struct hif_opaque_softc *scn);
ssize_t pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos,
struct ath_pktlog_info *pl_info, bool *read_complete);
/**
* wdi_pktlog_unsubscribe() - Unsubscribe pktlog callbacks
* @pdev_id: pdev id
* @log_state: Pktlog registration
*
* Return: zero on success, non-zero on failure
*/
A_STATUS wdi_pktlog_unsubscribe(uint8_t pdev_id, uint32_t log_state);
struct ol_pl_arch_dep_funcs {
void (*pktlog_init)(struct hif_opaque_softc *scn);
int (*pktlog_enable)(struct hif_opaque_softc *scn, int32_t log_state,
bool ini, uint8_t user,
uint32_t is_iwpriv_command);
int (*pktlog_setsize)(struct hif_opaque_softc *scn, int32_t log_state);
int (*pktlog_disable)(struct hif_opaque_softc *scn);
};
struct ol_pl_os_dep_funcs {
int (*pktlog_attach)(struct hif_opaque_softc *scn);
void (*pktlog_detach)(struct hif_opaque_softc *scn);
};
struct ath_pktlog_wmi_params {
WMI_PKTLOG_EVENT pktlog_event;
WMI_CMD_ID cmd_id;
bool ini_triggered;
uint8_t user_triggered;
};
extern struct ol_pl_arch_dep_funcs ol_pl_funcs;
extern struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs;
/* Pktlog handler to save the state of the pktlogs */
struct pktlog_dev_t {
struct ol_pl_arch_dep_funcs *pl_funcs;
struct ath_pktlog_info *pl_info;
ol_ath_generic_softc_handle scn;
uint8_t pdev_id;
char *name;
bool tgt_pktlog_alloced;
bool is_pktlog_cb_subscribed;
bool mt_pktlog_enabled;
uint32_t htc_err_cnt;
uint8_t htc_endpoint;
void *htc_pdev;
bool vendor_cmd_send;
uint8_t callback_type;
uint32_t invalid_packets;
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0))
#define PKTLOG_SYSCTL_SIZE 10
#else
#define PKTLOG_SYSCTL_SIZE 14
#endif
#define PKTLOG_MAX_SEND_QUEUE_DEPTH 64
/*
* Linux specific pktlog state information
*/
struct ath_pktlog_info_lnx {
struct ath_pktlog_info info;
struct ctl_table sysctls[PKTLOG_SYSCTL_SIZE];
struct proc_dir_entry *proc_entry;
struct ctl_table_header *sysctl_header;
};
#define PL_INFO_LNX(_pl_info) ((struct ath_pktlog_info_lnx *)(_pl_info))
/*
* WDI related data and functions
* Callback function to the WDI events
*/
void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data,
u_int16_t peer_id, uint32_t status);
void pktlog_init(struct hif_opaque_softc *scn);
int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool, uint8_t, uint32_t);
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini_triggered, uint8_t user_triggered,
uint32_t is_iwpriv_command);
int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state);
int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff);
int pktlog_disable(struct hif_opaque_softc *scn);
int pktlogmod_init(void *context);
void pktlogmod_exit(void *context);
int pktlog_htc_attach(void);
/**
* pktlog_process_fw_msg() - process packetlog message
* @pdev_id: physical device instance id
* @msg_word: message buffer
* @msg_len: message length
*
* Return: None
*/
void pktlog_process_fw_msg(uint8_t pdev_id, uint32_t *msg_word,
uint32_t msg_len);
void lit_pktlog_callback(void *context, enum WDI_EVENT event, void *log_data,
u_int16_t peer_id, uint32_t status);
#define ol_pktlog_attach(_scn) \
do { \
if (g_ol_pl_os_dep_funcs) { \
g_ol_pl_os_dep_funcs->pktlog_attach(_scn); \
} \
} while (0)
#define ol_pktlog_detach(_scn) \
do { \
if (g_ol_pl_os_dep_funcs) { \
g_ol_pl_os_dep_funcs->pktlog_detach(_scn); \
} \
} while (0)
#else /* REMOVE_PKT_LOG */
#define ol_pktlog_attach(_scn) ({ (void)_scn; })
#define ol_pktlog_detach(_scn) ({ (void)_scn; })
static inline void pktlog_init(struct hif_opaque_softc *scn)
{
return;
}
static inline int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini, uint8_t user,
uint32_t is_iwpriv_command)
{
return 0;
}
static inline
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini_triggered, uint8_t user_triggered,
uint32_t is_iwpriv_command)
{
return 0;
}
static inline int pktlog_setsize(struct hif_opaque_softc *scn,
int32_t log_state)
{
return 0;
}
static inline int pktlog_clearbuff(struct hif_opaque_softc *scn,
bool clear_buff)
{
return 0;
}
static inline int pktlog_disable(struct hif_opaque_softc *scn)
{
return 0;
}
static inline int pktlog_htc_attach(void)
{
return 0;
}
static inline void pktlog_process_fw_msg(uint8_t pdev_id, uint32_t *msg_word,
uint32_t msg_len)
{ }
#endif /* REMOVE_PKT_LOG */
#endif /* _PKTLOG_AC_H_ */

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2012-2014, 2016-2018, 2020 The Linux Foundation.
* All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* The file is used to define structures that are shared between
* kernel space and user space pktlog application.
*/
#ifndef _PKTLOG_AC_API_
#define _PKTLOG_AC_API_
#if defined(CONNECTIVITY_PKTLOG) || !defined(REMOVE_PKT_LOG)
struct hif_opaque_softc;
/**
* typedef hif_opaque_softc_handle - opaque handle for hif_opaque_softc
*/
typedef struct hif_opaque_softc * hif_opaque_softc_handle;
enum pktlog_callback_regtype {
PKTLOG_DEFAULT_CALLBACK_REGISTRATION,
PKTLOG_LITE_CALLBACK_REGISTRATION
};
struct net_device;
/**
* typedef net_device_handle - opaque handle to linux net device object
*/
typedef struct net_device * net_device_handle;
struct pktlog_dev_t;
void pktlog_sethandle(struct pktlog_dev_t **pl_handle,
hif_opaque_softc_handle scn);
void pktlog_set_pdev_id(struct pktlog_dev_t *pl_dev, uint8_t pdev_id);
void *get_txrx_context(void);
struct pktlog_dev_t *get_pktlog_handle(void);
void pktlog_set_callback_regtype(enum pktlog_callback_regtype callback_type);
/* Packet log state information */
#ifndef _PKTLOG_INFO
#define _PKTLOG_INFO
/**
* enum ath_pktlog_state - pktlog status
* @PKTLOG_OPR_IN_PROGRESS : pktlog command in progress
* @PKTLOG_OPR_IN_PROGRESS_READ_START: pktlog read is issued
* @PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED:
* as part of pktlog read, pktlog is disabled
* @PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE:
* as part of read, till pktlog read is complete
* @PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE:
* as part of read, pktlog clear buffer is done
* @PKTLOG_OPR_NOT_IN_PROGRESS: no pktlog command in progress
*/
enum ath_pktlog_state {
PKTLOG_OPR_IN_PROGRESS = 0,
PKTLOG_OPR_IN_PROGRESS_READ_START,
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED,
PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE,
PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE,
PKTLOG_OPR_NOT_IN_PROGRESS
};
struct ath_pktlog_info {
struct ath_pktlog_buf *buf;
uint32_t log_state;
uint32_t saved_state;
uint32_t options;
/* Initial saved state: It will save the log state in pktlog
* open and used in pktlog release after
* pktlog read is complete.
*/
uint32_t init_saved_state;
enum ath_pktlog_state curr_pkt_state;
/* Size of buffer in bytes */
int32_t buf_size;
qdf_spinlock_t log_lock;
struct mutex pktlog_mutex;
/* Threshold of TCP SACK packets for triggered stop */
int sack_thr;
/* # of tail packets to log after triggered stop */
int tail_length;
/* throuput threshold in bytes for triggered stop */
uint32_t thruput_thresh;
/* (aggregated or single) packet size in bytes */
uint32_t pktlen;
/* a temporary variable for counting TX throughput only */
/* PER threshold for triggered stop, 10 for 10%, range [1, 99] */
uint32_t per_thresh;
/* Phyerr threshold for triggered stop */
uint32_t phyerr_thresh;
/* time period for counting trigger parameters, in millisecond */
uint32_t trigger_interval;
uint32_t start_time_thruput;
uint32_t start_time_per;
};
#endif /* _PKTLOG_INFO */
#else /* REMOVE_PKT_LOG */
typedef void *pktlog_dev_handle;
#define pktlog_set_pdev_id(pl_dev, pdev_id) \
do { \
(void)pl_dev; \
(void)pdev_id; \
} while (0)
#define pktlog_sethandle(pl_handle, scn) \
do { \
(void)pl_handle; \
(void)scn; \
} while (0)
#define ol_pl_set_name(dev) \
do { \
(void)scn; \
(void)dev; \
} while (0)
#endif /* REMOVE_PKT_LOG */
#endif /* _PKTLOG_AC_API_ */

View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _PKTLOG_AC_I_
#define _PKTLOG_AC_I_
#ifndef REMOVE_PKT_LOG
#include <ol_txrx_internal.h>
#include <pktlog_ac.h>
#define PKTLOG_TAG "ATH_PKTLOG"
#define PKTLOG_DEFAULT_BUFSIZE (10 * 1024 * 1024) /* 10MB */
#define PKTLOG_DEFAULT_SACK_THR 3
#define PKTLOG_DEFAULT_TAIL_LENGTH 100
#define PKTLOG_DEFAULT_THRUPUT_THRESH (64 * 1024)
#define PKTLOG_DEFAULT_PER_THRESH 30
#define PKTLOG_DEFAULT_PHYERR_THRESH 300
#define PKTLOG_DEFAULT_TRIGGER_INTERVAL 500
/* Max Pktlog buffer size received from fw/hw */
#define MAX_PKTLOG_RECV_BUF_SIZE 2048
struct ath_pktlog_arg {
struct ath_pktlog_info *pl_info;
uint32_t flags;
uint16_t missed_cnt;
#ifdef HELIUMPLUS
uint8_t log_type;
uint8_t macId;
#else
uint16_t log_type;
#endif
size_t log_size;
uint16_t timestamp;
#ifdef PKTLOG_HAS_SPECIFIC_DATA
uint32_t type_specific_data;
#endif
char *buf;
};
void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg);
char *pktlog_getbuf(struct pktlog_dev_t *pl_dev,
struct ath_pktlog_info *pl_info,
size_t log_size, struct ath_pktlog_hdr *pl_hdr);
#ifdef PKTLOG_HAS_SPECIFIC_DATA
/**
* pktlog_hdr_set_specific_data() - set type specific data
* @log_hdr: pktlog header
* @type_specific_data: type specific data
*
* Return: None
*/
void
pktlog_hdr_set_specific_data(struct ath_pktlog_hdr *log_hdr,
uint32_t type_specific_data);
/**
* pktlog_hdr_get_specific_data() - get type specific data
* @log_hdr: pktlog header
* @type_specific_data: type specific data
*
* Return: pktlog subtype
*/
uint32_t
pktlog_hdr_get_specific_data(struct ath_pktlog_hdr *log_hdr);
/**
* pktlog_arg_set_specific_data() - set type specific data
* @log_hdr: pktlog arg
* @type_specific_data: type specific data
*
* Return: None
*/
void
pktlog_arg_set_specific_data(struct ath_pktlog_arg *plarg,
uint32_t type_specific_data);
/**
* pktlog_arg_get_specific_data() - set type specific data
* @log_hdr: pktlog arg
* @type_specific_data: type specific data
*
* Return: pktlog subtype
*/
uint32_t
pktlog_arg_get_specific_data(struct ath_pktlog_arg *plarg);
#else
static inline void
pktlog_hdr_set_specific_data(struct ath_pktlog_hdr *log_hdr,
uint32_t type_specific_data)
{
}
static inline uint32_t
pktlog_hdr_get_specific_data(struct ath_pktlog_hdr *log_hdr)
{
return 0;
}
static inline void
pktlog_arg_set_specific_data(struct ath_pktlog_arg *plarg,
uint32_t type_specific_data)
{
}
static inline uint32_t
pktlog_arg_get_specific_data(struct ath_pktlog_arg *plarg)
{
return 0;
}
#endif /* PKTLOG_HAS_SPECIFIC_DATA */
#endif /* REMOVE_PKT_LOG */
#endif

View File

@@ -0,0 +1,164 @@
/**
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "ol_txrx_types.h"
#include "ol_htt_tx_api.h"
#include "ol_tx_desc.h"
#include "qdf_mem.h"
#include "htt.h"
#include "htt_internal.h"
#include "pktlog_ac_i.h"
#include "wma_api.h"
#include "wlan_logging_sock_svc.h"
#define TX_DESC_ID_LOW_MASK 0xffff
#define TX_DESC_ID_LOW_SHIFT 0
#define TX_DESC_ID_HIGH_MASK 0xffff0000
#define TX_DESC_ID_HIGH_SHIFT 16
#ifndef REMOVE_PKT_LOG
/**
* process_tx_info() - process tx pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
A_STATUS process_tx_info(struct cdp_pdev *txrx_pdev, void *data);
/**
* process_rx_info_remote() - process rx pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
A_STATUS process_rx_info_remote(void *pdev, void *data);
/**
* process_rx_info() - process rx pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
A_STATUS process_rx_info(void *pdev, void *data);
/**
* process_rate_find() - process rate event pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
A_STATUS process_rate_find(void *pdev, void *data);
/**
* process_rate_update() - process rate event pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
A_STATUS process_rate_update(void *pdev, void *data);
/**
* process_sw_event() - process sw event pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
A_STATUS process_sw_event(void *pdev, void *data);
#else
static inline
A_STATUS process_tx_info(struct cdp_pdev *txrx_pdev, void *data)
{
return 0;
}
static inline
A_STATUS process_rx_info_remote(void *pdev, void *data)
{
return 0;
}
static inline
A_STATUS process_rx_info(void *pdev, void *data)
{
return 0;
}
static inline
A_STATUS process_rate_find(void *pdev, void *data)
{
return 0;
}
static inline
A_STATUS process_rate_update(void *pdev, void *data)
{
return 0;
}
static inline
A_STATUS process_sw_event(void *pdev, void *data)
{
return 0;
}
#endif /* REMOVE_PKT_LOG */
/**
* process_offload_pktlog_wifi3() - Process full pktlog events
* pdev: abstract pdev handle
* data: pktlog buffer
*
* Return: zero on success, non-zero on failure
*/
static inline A_STATUS
process_offload_pktlog_wifi3(struct cdp_pdev *pdev, void *data)
{
return 0;
}
/**
* process_rx_desc_remote_wifi3() - Process pktlog buffers received
* from monitor status ring
* @pdev: pdev handle
* @data: pktlog buffer pointer
*
* Return: 0 - success/non-zero - failure
*/
static inline int
process_rx_desc_remote_wifi3(void *pdev, void *data)
{
return 0;
}
/**
* process_pktlog_lite_wifi3() - Process pktlog buffers received
* from monitor status ring
* @pdev: pdev handle
* @data: pktlog buffer pointer
*
* Return: 0 - success/non-zero - failure
*/
static inline int
process_pktlog_lite_wifi3(void *context, void *log_data,
uint16_t log_type)
{
return 0;
}

View File

@@ -0,0 +1,148 @@
/**
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "pktlog_ac_i.h"
#include "wlan_logging_sock_svc.h"
#ifndef REMOVE_PKT_LOG
/**
* process_offload_pktlog_wifi3() - Process full pktlog events
* pdev: abstract pdev handle
* data: pktlog buffer
*
* Return: zero on success, non-zero on failure
*/
A_STATUS
process_offload_pktlog_wifi3(struct cdp_pdev *pdev, void *data);
/**
* process_rx_desc_remote_wifi3() - Process pktlog buffers received
* from monitor status ring
* @pdev: pdev handle
* @data: pktlog buffer pointer
*
* Return: 0 - success/non-zero - failure
*/
int process_rx_desc_remote_wifi3(void *pdev, void *data);
/**
* process_pktlog_lite_wifi3() - Process pktlog buffers received
* from monitor status ring
* @pdev: pdev handle
* @data: pktlog buffer pointer
*
* Return: 0 - success/non-zero - failure
*/
int process_pktlog_lite_wifi3(void *context, void *log_data,
uint16_t log_type);
#else
static inline A_STATUS
process_offload_pktlog_wifi3(struct cdp_pdev *pdev, void *data)
{
return 0;
}
static inline
int process_rx_desc_remote_wifi3(void *pdev, void *data)
{
return 0;
}
static inline int
process_pktlog_lite_wifi3(void *context, void *log_data,
uint16_t log_type)
{
return 0;
}
#endif /* REMOVE_PKT_LOG */
/**
* process_tx_info() - process tx pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
static inline
A_STATUS process_tx_info(struct cdp_pdev *txrx_pdev, void *data)
{
return 0;
}
/**
* process_rx_info_remote() - process rx pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
static inline
A_STATUS process_rx_info_remote(void *pdev, void *data)
{
return 0;
}
/**
* process_rx_remote() - process rx pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
static inline
A_STATUS process_rx_info(void *pdev, void *data)
{
return 0;
}
/**
* process_rate_find() - process rate event pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
static inline
A_STATUS process_rate_find(void *pdev, void *data)
{
return 0;
}
/**
* process_rate_update() - process rate event pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
static inline
A_STATUS process_rate_update(void *pdev, void *data)
{
return 0;
}
/**
* process_sw_event() - process sw event pktlog buffers
* @txrx_pdev: ol pdev handle
* @data: pktlog buffer
*
* Return: 0 - success/non-zero - failure
*/
static inline
A_STATUS process_sw_event(void *pdev, void *data)
{
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef REMOVE_PKT_LOG
#include "ol_txrx_types.h"
#include "ol_htt_tx_api.h"
#include "ol_tx_desc.h"
#include "qdf_mem.h"
#include "htt.h"
#include "htt_internal.h"
#include "pktlog_ac_i.h"
#include "wma_api.h"
#include "wlan_logging_sock_svc.h"
#ifdef PKTLOG_HAS_SPECIFIC_DATA
void
pktlog_hdr_set_specific_data(struct ath_pktlog_hdr *log_hdr,
uint32_t type_specific_data)
{
log_hdr->type_specific_data = type_specific_data;
}
uint32_t
pktlog_hdr_get_specific_data(struct ath_pktlog_hdr *log_hdr)
{
return log_hdr->type_specific_data;
}
void
pktlog_arg_set_specific_data(struct ath_pktlog_arg *plarg,
uint32_t type_specific_data)
{
plarg->type_specific_data = type_specific_data;
}
uint32_t
pktlog_arg_get_specific_data(struct ath_pktlog_arg *plarg)
{
return plarg->type_specific_data;
}
#endif /* PKTLOG_HAS_SPECIFIC_DATA */
void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg)
{
struct ath_pktlog_buf *log_buf;
int32_t buf_size;
struct ath_pktlog_hdr *log_hdr;
int32_t cur_wr_offset;
char *log_ptr;
struct ath_pktlog_info *pl_info;
uint16_t log_type;
size_t log_size;
uint32_t flags;
#ifdef HELIUMPLUS
uint8_t mac_id;
#endif
if (!plarg) {
qdf_info("Invalid parg");
return;
}
pl_info = plarg->pl_info;
#ifdef HELIUMPLUS
mac_id = plarg->macId;
log_type = plarg->log_type;
#else
log_type = plarg->log_type;
#endif
log_size = plarg->log_size;
log_buf = pl_info->buf;
flags = plarg->flags;
if (!log_buf) {
qdf_info("Invalid log_buf");
return;
}
buf_size = pl_info->buf_size;
cur_wr_offset = log_buf->wr_offset;
/* Move read offset to the next entry if there is a buffer overlap */
if (log_buf->rd_offset >= 0) {
if ((cur_wr_offset <= log_buf->rd_offset)
&& (cur_wr_offset + sizeof(struct ath_pktlog_hdr)) >
log_buf->rd_offset) {
PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf,
buf_size);
}
} else {
log_buf->rd_offset = cur_wr_offset;
}
log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + cur_wr_offset);
log_hdr->flags = flags;
#ifdef HELIUMPLUS
log_hdr->macId = mac_id;
log_hdr->log_type = log_type;
#else
log_hdr->log_type = log_type;
#endif
log_hdr->size = (uint16_t) log_size;
log_hdr->missed_cnt = plarg->missed_cnt;
log_hdr->timestamp = plarg->timestamp;
pktlog_hdr_set_specific_data(log_hdr,
pktlog_arg_get_specific_data(plarg));
cur_wr_offset += sizeof(*log_hdr);
if ((buf_size - cur_wr_offset) < log_size) {
while ((cur_wr_offset <= log_buf->rd_offset)
&& (log_buf->rd_offset < buf_size)) {
PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf,
buf_size);
}
cur_wr_offset = 0;
}
while ((cur_wr_offset <= log_buf->rd_offset)
&& (cur_wr_offset + log_size) > log_buf->rd_offset) {
PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, buf_size);
}
log_ptr = &(log_buf->log_data[cur_wr_offset]);
cur_wr_offset += log_hdr->size;
log_buf->wr_offset = ((buf_size - cur_wr_offset) >=
sizeof(struct ath_pktlog_hdr)) ? cur_wr_offset :
0;
plarg->buf = log_ptr;
}
char *pktlog_getbuf(struct pktlog_dev_t *pl_dev,
struct ath_pktlog_info *pl_info,
size_t log_size, struct ath_pktlog_hdr *pl_hdr)
{
struct ath_pktlog_arg plarg = { 0, };
uint8_t flags = 0;
plarg.pl_info = pl_info;
#ifdef HELIUMPLUS
plarg.macId = pl_hdr->macId;
plarg.log_type = pl_hdr->log_type;
#else
plarg.log_type = pl_hdr->log_type;
#endif
plarg.log_size = log_size;
plarg.flags = pl_hdr->flags;
plarg.missed_cnt = pl_hdr->missed_cnt;
plarg.timestamp = pl_hdr->timestamp;
pktlog_arg_set_specific_data(&plarg,
pktlog_hdr_get_specific_data(pl_hdr));
if (flags & PHFLAGS_INTERRUPT_CONTEXT) {
/*
* We are already in interrupt context, no need to make it
* intsafe. call the function directly.
*/
pktlog_getbuf_intsafe(&plarg);
} else {
PKTLOG_LOCK(pl_info);
pktlog_getbuf_intsafe(&plarg);
PKTLOG_UNLOCK(pl_info);
}
return plarg.buf;
}
#endif /*REMOVE_PKT_LOG */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/**
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* WIFI3 - Refers to platforms - 6290/6390/6490 */
#include "pktlog_wifi3.h"
#ifndef REMOVE_PKT_LOG
A_STATUS
process_offload_pktlog_wifi3(struct cdp_pdev *pdev, void *data)
{
struct pktlog_dev_t *pl_dev = get_pktlog_handle();
struct ath_pktlog_info *pl_info;
struct ath_pktlog_hdr pl_hdr;
uint32_t *pl_tgt_hdr;
void *txdesc_hdr_ctl = NULL;
size_t log_size = 0;
if (!pl_dev) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
"Invalid context in %s\n", __func__);
return A_ERROR;
}
if (!data) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
"Invalid data in %s\n", __func__);
return A_ERROR;
}
pl_tgt_hdr = (uint32_t *)data;
pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
ATH_PKTLOG_HDR_FLAGS_MASK) >>
ATH_PKTLOG_HDR_FLAGS_SHIFT;
pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
pktlog_hdr_set_specific_data(&pl_hdr,
*(pl_tgt_hdr +
ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET));
if (pl_hdr.size > MAX_PKTLOG_RECV_BUF_SIZE) {
pl_dev->invalid_packets++;
return A_ERROR;
}
/*
* Must include to process different types
* TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR
*/
pl_info = pl_dev->pl_info;
log_size = pl_hdr.size;
txdesc_hdr_ctl =
(void *)pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr);
if (!txdesc_hdr_ctl) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
"Failed to allocate pktlog descriptor");
return A_NO_MEMORY;
}
qdf_assert(txdesc_hdr_ctl);
qdf_assert(pl_hdr->size < PKTLOG_MAX_TX_WORDS * sizeof(u_int32_t));
qdf_mem_copy(txdesc_hdr_ctl,
((void *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, txdesc_hdr_ctl);
return A_OK;
}
int process_rx_desc_remote_wifi3(void *pdev, void *data)
{
struct pktlog_dev_t *pl_dev = get_pktlog_handle();
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_rx_info rxstat_log;
size_t log_size;
struct ath_pktlog_info *pl_info;
qdf_nbuf_t log_nbuf = (qdf_nbuf_t)data;
if (!pl_dev) {
qdf_err("Pktlog handle is NULL");
return -EINVAL;
}
pl_info = pl_dev->pl_info;
qdf_mem_zero(&pl_hdr, sizeof(pl_hdr));
pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
pl_hdr.missed_cnt = 0;
pl_hdr.log_type = PKTLOG_TYPE_RX_STATBUF;
pl_hdr.size = qdf_nbuf_len(log_nbuf);
pl_hdr.timestamp = 0;
log_size = pl_hdr.size;
rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
if (!rxstat_log.rx_desc) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
"%s: Rx descriptor is NULL", __func__);
return -EINVAL;
}
qdf_mem_copy(rxstat_log.rx_desc, qdf_nbuf_data(log_nbuf), pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
rxstat_log.rx_desc);
return 0;
}
int
process_pktlog_lite_wifi3(void *context, void *log_data,
uint16_t log_type)
{
struct pktlog_dev_t *pl_dev = get_pktlog_handle();
struct ath_pktlog_info *pl_info;
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_rx_info rxstat_log;
size_t log_size;
qdf_nbuf_t log_nbuf = (qdf_nbuf_t)log_data;
if (!pl_dev) {
qdf_err("Pktlog handle is NULL");
return -EINVAL;
}
pl_info = pl_dev->pl_info;
qdf_mem_zero(&pl_hdr, sizeof(pl_hdr));
pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
pl_hdr.missed_cnt = 0;
pl_hdr.log_type = log_type;
pl_hdr.size = qdf_nbuf_len(log_nbuf);
pl_hdr.timestamp = 0;
log_size = pl_hdr.size;
rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
if (!rxstat_log.rx_desc) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
"%s: Rx descriptor is NULL", __func__);
return -EINVAL;
}
qdf_mem_copy(rxstat_log.rx_desc, qdf_nbuf_data(log_nbuf), pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc);
return 0;
}
#endif /* REMOVE_PKT_LOG */

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/******************************************************************************
* wlan_ptt_sock_svc.c
*
******************************************************************************/
#ifndef PTT_SOCK_SVC_H
#define PTT_SOCK_SVC_H
#include <wlan_nlink_srv.h>
#include <qdf_types.h>
#include <qdf_status.h>
#include <qdf_trace.h>
/*
* Quarky Message Format:
* The following is the messaging protocol between Quarky and PTT Socket App.
* The totalMsgLen is the length from Radio till msgBody. The value of Radio
* is always defaulted to 0. The MsgLen is the length from msgId till msgBody.
* The length of the msgBody varies with respect to the MsgId. Buffer space
* for MsgBody is already allocated in the received buffer. So in case of READ
* we just need to populate the values in the received message and send it
* back
* +------------+-------+-------+--------+-------+---------+
* |TotalMsgLen | Radio | MsgId | MsgLen |Status |MsgBody |
* +------------+-------+-------|--------+-------+---------+
* <------4----><--4---><---2--><---2---><---4--><--------->
*/
/* PTT Socket App Message Ids */
#define PTT_MSG_READ_REGISTER 0x3040
#define PTT_MSG_WRITE_REGISTER 0x3041
#define PTT_MSG_READ_MEMORY 0x3044
#define PTT_MSG_WRITE_MEMORY 0x3045
#define PTT_MSG_LOG_DUMP_DBG 0x32A1
#define PTT_MSG_FTM_CMDS_TYPE 0x4040
#define ANI_DRIVER_MSG_START 0x0001
#define ANI_MSG_APP_REG_REQ (ANI_DRIVER_MSG_START + 0)
#define ANI_MSG_APP_REG_RSP (ANI_DRIVER_MSG_START + 1)
#define ANI_MSG_OEM_DATA_REQ (ANI_DRIVER_MSG_START + 2)
#define ANI_MSG_OEM_DATA_RSP (ANI_DRIVER_MSG_START + 3)
#define ANI_MSG_CHANNEL_INFO_REQ (ANI_DRIVER_MSG_START + 4)
#define ANI_MSG_CHANNEL_INFO_RSP (ANI_DRIVER_MSG_START + 5)
#define ANI_MSG_OEM_ERROR (ANI_DRIVER_MSG_START + 6)
#define ANI_MSG_PEER_STATUS_IND (ANI_DRIVER_MSG_START + 7)
#define ANI_MSG_SET_OEM_CAP_REQ (ANI_DRIVER_MSG_START + 8)
#define ANI_MSG_SET_OEM_CAP_RSP (ANI_DRIVER_MSG_START + 9)
#define ANI_MSG_GET_OEM_CAP_REQ (ANI_DRIVER_MSG_START + 10)
#define ANI_MSG_GET_OEM_CAP_RSP (ANI_DRIVER_MSG_START + 11)
#define ANI_MAX_RADIOS 3
#define ANI_NL_MSG_OK 0
#define ANI_NL_MSG_ERROR -1
#define ANI_NL_MSG_OVERHEAD (NLMSG_SPACE(tAniHdr + 4))
/*
* Packet Format for READ_REGISTER & WRITE_REGISTER:
* TotalMsgLen : 4 bytes [value=20 bytes]
* Radio : 4 bytes
* MsgId : 2 bytes
* MsgLen : 2 bytes
* Status : 4 bytes
* Address : 4 bytes
* Payload : 4 bytes
*/
/*
* Packet Format for READ_MEMORY & WRITE_MEMORY :
* TotalMsgLen : 4 bytes [value= 20+LEN_PAYLOAD bytes]
* Radio : 4 bytes
* MsgId : 2 bytes
* MsgLen : 2 bytes
* Status : 4 bytes
* Address : 4 bytes
* Length : 4 bytes [LEN_PAYLOAD]
* Payload : LEN_PAYLOAD bytes
*/
#if defined(PTT_SOCK_SVC_ENABLE) && defined(CNSS_GENL)
/**
* ptt_sock_activate_svc() - API to register PTT/PUMAC command handlers
*
* API to register the handler for PTT/PUMAC NL messages.
*
* Return: None
*/
void ptt_sock_activate_svc(void);
/**
* ptt_sock_deactivate_svc() - API to deregister PTT/PUMAC command handlers
*
* API to deregister the handler for PTT/PUMAC NL messages.
*
* Return: None
*/
void ptt_sock_deactivate_svc(void);
#else
static inline void ptt_sock_activate_svc(void)
{
}
static inline void ptt_sock_deactivate_svc(void)
{
}
#endif
int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid);
/*
* Format of message exchanged between the PTT Socket App in userspace and the
* WLAN Driver, in either direction. Each msg will begin with this header and
* will followed by the Quarky message
*/
struct sAniAppRegReq {
tAniNlModTypes type; /* module id */
int pid; /* process id */
};
/**
* struct sptt_app_reg_req - PTT register request structure
* @radio: Radio ID
* @wmsg: ANI header
*
* payload structure received as nl data from PTT app/user space
*/
struct sptt_app_reg_req {
int radio;
tAniHdr wmsg;
};
struct sAniNlAppRegRsp {
tAniHdr wniHdr; /* Generic WNI msg header */
struct sAniAppRegReq regReq; /* The original request msg */
int ret; /* Return code */
};
#endif

View File

@@ -0,0 +1,256 @@
/*
* Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/******************************************************************************
* wlan_ptt_sock_svc.c
*
******************************************************************************/
#ifdef PTT_SOCK_SVC_ENABLE
#include <wlan_nlink_srv.h>
#include <qdf_types.h>
#include <qdf_status.h>
#include <qdf_trace.h>
#include <wlan_nlink_common.h>
#include <wlan_ptt_sock_svc.h>
#include <qdf_types.h>
#include <qdf_trace.h>
#ifdef CNSS_GENL
#ifdef CONFIG_CNSS_OUT_OF_TREE
#include "cnss_nl.h"
#else
#include <net/cnss_nl.h>
#endif
#include <wlan_cfg80211.h>
#endif
#define PTT_SOCK_DEBUG
#ifdef PTT_SOCK_DEBUG
#define PTT_TRACE(level, args ...) QDF_TRACE(QDF_MODULE_ID_QDF, level, ## args)
#else
#define PTT_TRACE(level, args ...)
#endif
#ifdef PTT_SOCK_DEBUG_VERBOSE
/* Utility function to perform a hex dump */
static void ptt_sock_dump_buf(const unsigned char *pbuf, int cnt)
{
int i;
for (i = 0; i < cnt; i++) {
if ((i % 16) == 0)
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
"\n%pK:", pbuf);
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, " %02X",
*pbuf);
pbuf++;
}
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "\n");
}
#endif
/**
* nl_srv_ucast_ptt() - Wrapper function to send ucast msgs to PTT
* @skb: sk buffer pointer
* @dst_pid: Destination PID
* @flag: flags
*
* Sends the ucast message to PTT with generic nl socket if CNSS_GENL
* is enabled. Else, use the legacy netlink socket to send.
*
* Return: zero on success, error code otherwise
*/
static int nl_srv_ucast_ptt(struct sk_buff *skb, int dst_pid, int flag)
{
#ifdef CNSS_GENL
return nl_srv_ucast(skb, dst_pid, flag, ANI_NL_MSG_PUMAC,
CLD80211_MCGRP_DIAG_EVENTS);
#else
return nl_srv_ucast(skb, dst_pid, flag);
#endif
}
/**
* nl_srv_bcast_ptt() - Wrapper function to send bcast msgs to DIAG mcast group
* @skb: sk buffer pointer
*
* Sends the bcast message to DIAG multicast group with generic nl socket
* if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
*
* Return: zero on success, error code otherwise
*/
static int nl_srv_bcast_ptt(struct sk_buff *skb)
{
#ifdef CNSS_GENL
return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
#else
return nl_srv_bcast(skb);
#endif
}
/**
* ptt_sock_send_msg_to_app() - Send nl message to user space
* wmsg: Message header
* radio: Unit number of the radio
* src_mod: Message type
* pid: Process ID to which message will be unicast. Message
* will be broadcast when PID is INVALID_PID
*
* Utility function to send a netlink message to an application in user space
*
* Return: 0 on success and negative value on failure
*/
int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid)
{
int err = -1;
int payload_len;
int tot_msg_len;
tAniNlHdr *wnl;
struct sk_buff *skb;
struct nlmsghdr *nlh;
int wmsg_length = be16_to_cpu(wmsg->length);
static int nlmsg_seq;
if (radio < 0 || radio > ANI_MAX_RADIOS) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n",
__func__, radio);
return -EINVAL;
}
payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(*wmsg);
tot_msg_len = NLMSG_SPACE(payload_len);
skb = dev_alloc_skb(tot_msg_len);
if (!skb) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
"%s: dev_alloc_skb() failed for msg size[%d]\n",
__func__, tot_msg_len);
return -ENOMEM;
}
nlh =
nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len,
NLM_F_REQUEST);
if (!nlh) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
"%s: nlmsg_put() failed for msg size[%d]\n", __func__,
tot_msg_len);
kfree_skb(skb);
return -ENOMEM;
}
wnl = (tAniNlHdr *) nlh;
wnl->radio = radio;
/* Offset of data buffer from nlmsg_hdr + sizeof(int) radio */
memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), wmsg, wmsg_length);
#ifdef PTT_SOCK_DEBUG_VERBOSE
ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len);
#endif
if (pid != INVALID_PID)
err = nl_srv_ucast_ptt(skb, pid, MSG_DONTWAIT);
else
err = nl_srv_bcast_ptt(skb);
if ((err < 0) && (err != -ESRCH))
PTT_TRACE(QDF_TRACE_LEVEL_INFO,
"%s:Failed sending Msg Type [0x%X] to pid[%d]\n",
__func__, be16_to_cpu(wmsg->type), pid);
return err;
}
#ifdef CNSS_GENL
/**
* ptt_cmd_handler() - Handler function for PTT commands
* @data: Data to be parsed
* @data_len: Length of the data received
* @ctx: Registered context reference
* @pid: Process id of the user space application
*
* This function handles the command from PTT user space application
*
* Return: None
*/
static void ptt_cmd_handler(const void *data, int data_len, void *ctx, int pid)
{
uint16_t length;
struct sptt_app_reg_req *payload;
struct nlattr *tb[CLD80211_ATTR_MAX + 1];
/*
* audit note: it is ok to pass a NULL policy here since a
* length check on the data is added later already
*/
if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX,
data, data_len, NULL)) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Invalid ATTR");
return;
}
if (!tb[CLD80211_ATTR_DATA]) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "attr ATTR_DATA failed");
return;
}
if (nla_len(tb[CLD80211_ATTR_DATA]) < sizeof(struct sptt_app_reg_req)) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s:attr length check fails\n",
__func__);
return;
}
payload = (struct sptt_app_reg_req *)(nla_data(tb[CLD80211_ATTR_DATA]));
length = be16_to_cpu(payload->wmsg.length);
if ((USHRT_MAX - length) < (sizeof(payload->radio) + sizeof(tAniHdr))) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
"u16 overflow length %d %zu %zu",
length,
sizeof(payload->radio),
sizeof(tAniHdr));
return;
}
if (nla_len(tb[CLD80211_ATTR_DATA]) < (length +
sizeof(payload->radio) +
sizeof(tAniHdr))) {
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "ATTR_DATA len check failed");
return;
}
switch (payload->wmsg.type) {
case ANI_MSG_APP_REG_REQ:
ptt_sock_send_msg_to_app(&payload->wmsg, payload->radio,
ANI_NL_MSG_PUMAC, pid);
break;
default:
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Unknown msg type %d",
payload->wmsg.type);
break;
}
}
void ptt_sock_activate_svc(void)
{
register_cld_cmd_cb(ANI_NL_MSG_PUMAC, ptt_cmd_handler, NULL);
register_cld_cmd_cb(ANI_NL_MSG_PTT, ptt_cmd_handler, NULL);
}
void ptt_sock_deactivate_svc(void)
{
deregister_cld_cmd_cb(ANI_NL_MSG_PTT);
deregister_cld_cmd_cb(ANI_NL_MSG_PUMAC);
}
#endif
#endif /* PTT_SOCK_SVC_ENABLE */

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: qld_api.h
* QLD: This file provides public exposed functions
*/
#ifndef _QLD_API_H_
#define _QLD_API_H_
#define QLD_MAX_NAME 48
/**
* struct qld_entry - Individual entry in qld_event
* @addr: Start address of object to dump
* @size: Size of memory dump
* @name: Name of memory dump
*/
struct qld_entry {
uint64_t addr;
size_t size;
char name[QLD_MAX_NAME];
};
/**
* typedef qld_iter_func - qld callback function
* @req: opaque pointer
* @qld_entry: qld_entry
*
* Return: 0 - OK -EINVAL - On failure
*/
typedef int (*qld_iter_func)(void *req, struct qld_entry *entry);
/**
* qld_iterate_list() - qld list iteration routine
* @gen_table: callback function to generate table
* @req: opaque request
*
* Return: 0 - OK -EINVAL - On failure
*/
int qld_iterate_list(qld_iter_func gen_table, void *req);
/**
* qld_register() - Register qld for the given address
* @addr: starting address the dump
* @size: size of memory to dump
* @name: name identifier of dump
*
* Return: 0 - OK -EINVAL -ENOMEM - On failure
*/
int qld_register(void *addr, size_t size, char *name);
/**
* qld_unregister() - Un-register qld for the given address
* @addr: starting address the dump
*
* Return: 0 - OK -EINVAL - On failure
*/
int qld_unregister(void *addr);
/**
* qld_list_init() - Initialize qld list
* @max_list: maximum size list supports
*
* Return: 0 - OK -EINVAL -ENOMEM - On failure
*/
int qld_list_init(uint32_t max_list);
/**
* qld_list_delete() - empty qld list
*
* Return: 0 - OK -EINVAL - On failure
*/
int qld_list_delete(void);
/**
* qld_list_deinit() - De-initialize qld list
*
* Return: 0 - OK -EINVAL - On failure
*/
int qld_list_deinit(void);
/**
* qld_get_list_count () - get size of qld list
* @list_count: list_count to set
*
* Return: 0 - OK -EINVAL - On failure
*/
int qld_get_list_count(uint32_t *list_count);
/**
* is_qld_enable() - check if qld feature is set
*
* Return: true on success, false on failure
*/
bool is_qld_enable(void);
#endif /* _QLD_API_H_ */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: qld_priv.h
* QLD: This file provides Private functions for qld
*/
#ifndef _QLD_PRIV_H_
#define _QLD_PRIV_H_
#include <qdf_lock.h>
#include <qdf_list.h>
#include <qld_api.h>
#define qld_alert(format, args...) \
QDF_TRACE_FATAL(QDF_MODULE_ID_QLD, format, ## args)
#define qld_err(format, args...) \
QDF_TRACE_ERROR(QDF_MODULE_ID_QLD, format, ## args)
#define qld_warn(format, args...) \
QDF_TRACE_WARN(QDF_MODULE_ID_QLD, format, ## args)
#define qld_info(format, args...) \
QDF_TRACE_INFO(QDF_MODULE_ID_QLD, format, ## args)
#define qld_debug(format, args...) \
QDF_TRACE_DEBUG(QDF_MODULE_ID_QLD, format, ## args)
/**
* struct qld_list_handle - Top level qld structure
* @qld_lock: Spinlock for structure
* @qld_list: linked list for linking
* @qld_max_list: maximum list size
*/
struct qld_list_handle {
qdf_spinlock_t qld_lock;
qdf_list_t qld_list;
uint32_t qld_max_list;
};
/**
* struct qld_node - qld node
* @node: single node of linked list
* @entry: single qld_entry in list
*/
struct qld_node {
qdf_list_node_t node;
struct qld_entry entry;
};
#endif /*_QLD_PRIV_H_*/

View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: qld
* QLD: main file of QCA Live Dump (QLD)
*/
#include "qld_priv.h"
#include "qld_api.h"
#include "qdf_module.h"
/* Handle for qld structure */
static struct qld_list_handle *qld_handle;
bool is_qld_enable(void)
{
if (!qld_handle)
return false;
return true;
}
qdf_export_symbol(is_qld_enable);
int qld_list_init(uint32_t max_list)
{
if (!max_list)
return -EINVAL;
qld_handle = qdf_mem_malloc(sizeof(*qld_handle));
if (!qld_handle)
return -ENOMEM;
qdf_spinlock_create(&qld_handle->qld_lock);
qld_handle->qld_max_list = max_list;
qdf_list_create(&qld_handle->qld_list, qld_handle->qld_max_list);
qld_debug("LIST init with max size of %u", qld_handle->qld_max_list);
return 0;
}
qdf_export_symbol(qld_list_init);
int qld_list_deinit(void)
{
if (!qld_handle) {
qld_err("Handle NULL");
return -EINVAL;
}
/* Delete the list */
qld_list_delete();
qdf_list_destroy(&qld_handle->qld_list);
qdf_spinlock_destroy(&qld_handle->qld_lock);
qdf_mem_free(qld_handle);
qld_handle = NULL;
qld_debug("LIST De-initialized");
return 0;
}
qdf_export_symbol(qld_list_deinit);
int qld_list_delete(void)
{
struct qld_node *qld;
qdf_list_node_t *node = NULL;
qdf_list_t *list;
if (!qld_handle) {
qld_err("Handle NULL");
return -EINVAL;
}
list = &qld_handle->qld_list;
qdf_spinlock_acquire(&qld_handle->qld_lock);
/* Check and remove the elements of list */
while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) {
qld = qdf_container_of(node, struct qld_node, node);
qdf_mem_free(qld);
}
qdf_spinlock_release(&qld_handle->qld_lock);
qld_debug("LIST Emptied");
return 0;
}
qdf_export_symbol(qld_list_delete);
int qld_register(void *addr, size_t size, char *name)
{
struct qld_node *qld;
uint32_t list_count = 0;
if (!qld_handle || !addr) {
qld_debug("Handle or address is NULL");
return -EINVAL;
}
if ((qld_get_list_count(&list_count) != 0)) {
qdf_err("QLD: Invalid list count");
return -EINVAL;
}
if (list_count >= qld_handle->qld_max_list) {
qld_err("List full,reg failed.Increase list size");
return -EINVAL;
}
/* Check if data is already registered */
qdf_spinlock_acquire(&qld_handle->qld_lock);
qdf_list_for_each(&qld_handle->qld_list, qld, node) {
if (qld->entry.addr == (uintptr_t)addr) {
qld_err("%s already registered", qld->entry.name);
qdf_spinlock_release(&qld_handle->qld_lock);
return -EINVAL;
}
}
qdf_spinlock_release(&qld_handle->qld_lock);
qld = qdf_mem_malloc(sizeof(*qld));
if (!qld)
return -ENOMEM;
qld_debug("Insert addr=%pK size=%zu name=%s", (void *)addr, size, name);
qdf_spinlock_acquire(&qld_handle->qld_lock);
qld->entry.addr = (uintptr_t)addr;
qld->entry.size = size;
qdf_snprintf(qld->entry.name, sizeof(qld->entry.name), "%s", name);
qdf_list_insert_front(&qld_handle->qld_list, &qld->node);
qdf_spinlock_release(&qld_handle->qld_lock);
return 0;
}
qdf_export_symbol(qld_register);
int qld_unregister(void *addr)
{
struct qld_node *qld = NULL;
struct qld_node *cur_entry;
if (!qld_handle || !addr) {
qld_err("Handle or address is NULL");
return -EINVAL;
}
qdf_spinlock_acquire(&qld_handle->qld_lock);
qdf_list_for_each(&qld_handle->qld_list, cur_entry, node) {
if (cur_entry->entry.addr == (uintptr_t)addr) {
qld = cur_entry;
break;
}
}
if (qld) {
qdf_list_remove_node(&qld_handle->qld_list, &qld->node);
qld_debug("Delete name=%s, size=%zu", qld->entry.name,
qld->entry.size);
qdf_mem_free(qld);
}
qdf_spinlock_release(&qld_handle->qld_lock);
return 0;
}
qdf_export_symbol(qld_unregister);
int qld_iterate_list(qld_iter_func gen_table, void *qld_req)
{
struct qld_node *qld = NULL;
if (!qld_handle)
return -EINVAL;
if (!qld_req || !gen_table) {
qld_err("req buffer or func is NULL %s", __func__);
return -EINVAL;
}
qdf_spinlock_acquire(&qld_handle->qld_lock);
qdf_list_for_each(&qld_handle->qld_list, qld, node) {
(gen_table)(qld_req, &qld->entry);
}
qdf_spinlock_release(&qld_handle->qld_lock);
return 0;
}
qdf_export_symbol(qld_iterate_list);
int qld_get_list_count(uint32_t *list_count)
{
if (!qld_handle) {
qld_err("Handle NULL");
return -EINVAL;
}
*list_count = qld_handle->qld_list.count;
return 0;
}
qdf_export_symbol(qld_get_list_count);

View File

@@ -0,0 +1,592 @@
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $
*/
#ifndef _QUEUE_H_
#define _QUEUE_H_
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - - - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
*
*/
#define QUEUE_MACRO_DEBUG 0
#if QUEUE_MACRO_DEBUG
/*
* Store the last 2 places the queue element or head was altered
*/
struct qm_trace {
char *lastfile;
int lastline;
char *prevfile;
int prevline;
};
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)NULL; } while (0)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define TRACEBUF
#define TRASHIT(x) do {(x) = (void *)0; } while (0)
#endif /* QUEUE_MACRO_DEBUG */
#ifdef ATHR_RNWF
/*
* NDIS contains a defn for SLIST_ENTRY and SINGLE_LIST_ENTRY
*/
#endif
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SING_LIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_NEXT(curelm, field) = \
SLIST_NEXT(SLIST_NEXT(curelm, field), field);\
} \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), \
field); \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; \
struct type **stqh_last; \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), \
field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == \
NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? \
NULL : \
((struct type *) \
((char *)((head)->stqh_last) - __offsetof(struct type, field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
if ((STAILQ_NEXT(curelm, field) = \
STAILQ_NEXT(STAILQ_NEXT(curelm, field), \
field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((curelm),\
field); \
} \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if (STAILQ_NEXT(elm, field)) { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), \
field)) == NULL) \
(head)->stqh_last = \
&STAILQ_NEXT((elm), field); \
} \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == \
NULL)\
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT((elm), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
/*
* List declarations.
*/
#define ATH_LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; \
}
#ifndef LIST_HEAD
#define LIST_HEAD ATH_LIST_HEAD
#endif
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; \
struct type **le_prev; \
}
/*
* List functions.
*/
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if ((LIST_NEXT((elm), field) = \
LIST_NEXT((listelm), field)) != NULL) \
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
} while (0)
/*
* Tail queue declarations.
*/
#ifndef TRACE_TX_LEAK
#define TRACE_TX_LEAK 0
#endif
#if TRACE_TX_LEAK
#define HEADNAME char headname[64];
#define COPY_HEADNAME(head) OS_MEMCPY((head)->headname, #head, sizeof(#head))
#else
#define HEADNAME
#define COPY_HEADNAME(head)
#endif
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; \
struct type **tqh_last; \
HEADNAME \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; \
struct type **tqe_prev; \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
COPY_HEADNAME(head); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), \
field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)\
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT((elm)->field.tqe_next); \
TRASHIT((elm)->field.tqe_prev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;\
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
#ifdef _KERNEL
/*
* XXX insque() and remque() are an old way of handling certain queues.
* They bogusly assumes that all queue heads look alike.
*/
struct quehead {
struct quehead *qh_link;
struct quehead *qh_rlink;
};
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
static inline void insque(void *a, void *b)
{
struct quehead *element = (struct quehead *)a,
*head = (struct quehead *)b;
element->qh_link = head->qh_link;
element->qh_rlink = head;
head->qh_link = element;
element->qh_link->qh_rlink = element;
}
static inline void remque(void *a)
{
struct quehead *element = (struct quehead *)a;
element->qh_link->qh_rlink = element->qh_rlink;
element->qh_rlink->qh_link = element->qh_link;
element->qh_rlink = 0;
}
#else /* !(__GNUC__ || __INTEL_COMPILER) */
void insque(void *a, void *b);
void remque(void *a);
#endif /* __GNUC__ || __INTEL_COMPILER */
#endif /* _KERNEL */
#endif /* _QUEUE_H_ */