qcacmn: Add core\utils directory and files to qcacmn

As a part of UMAC convergence, move the core\utils logging to qcacmn.

CRs-Fixed: 1109855
Change-Id: I499a392f74f3e52e99df4d03e4a27bce6cf5be7c
This commit is contained in:
Srinivas Girigowda
2017-02-16 16:04:29 -08:00
committed by qcabuildsw
parent 6195152790
commit 60644c29e6
30 changed files with 15592 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef EPPING_INTERNAL_H
#define EPPING_INTERNAL_H
/**===========================================================================
\file epping_internal.h
\brief Linux epping internal head file
==========================================================================*/
/*---------------------------------------------------------------------------
Include files
-------------------------------------------------------------------------*/
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>
#if defined(WLAN_OPEN_SOURCE) && 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)
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
#ifdef HIF_PCI
#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;
#ifdef HIF_PCI
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 tQDF_ADAPTER_MODE 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 *pAdapter,
EPPING_HEADER *eppingHdr, int ret, const char *str);
void epping_log_stats(epping_adapter_t *pAdapter, const char *str);
void epping_set_kperf_flag(epping_adapter_t *pAdapter,
HTC_ENDPOINT_ID eid, A_UINT8 kperf_flag);
/* epping_tx signatures */
void epping_tx_timer_expire(epping_adapter_t *pAdapter);
void epping_tx_complete_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue);
int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *pAdapter);
#ifdef HIF_SDIO
HTC_SEND_FULL_ACTION epping_tx_queue_full(void *Context, HTC_PACKET *pPacket);
#endif
void epping_tx_dup_pkt(epping_adapter_t *pAdapter,
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 tQDF_ADAPTER_MODE device_mode);
void epping_destroy_adapter(epping_adapter_t *pAdapter);
int epping_connect_service(epping_context_t *pEpping_ctx);
#ifdef HIF_PCI
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 */
#endif /* end #ifndef EPPING_INTERNAL_H */

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#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 */
int epping_open(void);
void epping_close(void);
void epping_disable(void);
int epping_enable(struct device *parent_dev);
#endif /* end #ifndef EPPING_MAIN_H */

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*========================================================================
\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)
{
A_UINT32 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] == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: no mem for cookie (idx = %d)", __func__,
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 != NULL) {
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)
{
char *buf = (char *)data;
int i;
printk("%s: E, %s\n", __func__, str);
for (i = 0; (i + 7) < buf_len; i += 8) {
printk("%02x %02x %02x %02x %02x %02x %02x %02x\n",
buf[i],
buf[i + 1],
buf[i + 2],
buf[i + 3],
buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]);
}
/* Dump the bytes in the last line */
for (; i < buf_len; i++) {
printk("%02x ", buf[i]);
}
printk("\n%s: X %s\n", __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 *pAdapter,
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,
pAdapter->stats.tx_packets,
pAdapter->stats.tx_dropped,
pAdapter->stats.tx_bytes,
pAdapter->stats.rx_packets,
pAdapter->stats.rx_dropped,
pAdapter->stats.rx_bytes);
}
}
void epping_log_stats(epping_adapter_t *pAdapter, 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,
pAdapter->stats.tx_packets,
pAdapter->stats.tx_dropped,
pAdapter->stats.tx_bytes,
pAdapter->stats.rx_packets,
pAdapter->stats.rx_dropped,
pAdapter->stats.rx_bytes,
pAdapter->pEpping_ctx->total_tx_acks);
}
void epping_set_kperf_flag(epping_adapter_t *pAdapter,
HTC_ENDPOINT_ID eid, A_UINT8 kperf_flag)
{
pAdapter->pEpping_ctx->kperf_num_rx_recv[eid] = 0;
pAdapter->pEpping_ctx->kperf_num_tx_acks[eid] = 0;
}

View File

@@ -0,0 +1,354 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*========================================================================
\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 "cds_concurrency.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
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 == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
"%s: cannot alloc epping context", __func__);
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 *pEpping_ctx;
struct hif_opaque_softc *hif_ctx;
HTC_HANDLE htc_handle;
pEpping_ctx = g_epping_ctx;
if (pEpping_ctx == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: error: pEpping_ctx = NULL", __func__);
return;
}
if (pEpping_ctx->epping_adapter) {
epping_destroy_adapter(pEpping_ctx->epping_adapter);
pEpping_ctx->epping_adapter = NULL;
}
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
if (hif_ctx == NULL) {
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 == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: error: htc_handle = NULL", __func__);
return;
}
htc_stop(htc_handle);
epping_cookie_cleanup(pEpping_ctx);
htc_destroy(htc_handle);
}
/**
* 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 == NULL) {
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
*/
static void epping_target_suspend_acknowledge(void *context, bool wow_nack)
{
if (NULL == 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;
}
/**
* 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);
}
/**
* 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)
{
int ret = 0;
epping_context_t *pEpping_ctx = NULL;
cds_context_type *p_cds_context = NULL;
qdf_device_t qdf_ctx;
HTC_INIT_INFO htcInfo;
struct hif_opaque_softc *scn;
tSirMacAddr adapter_macAddr;
struct hif_target_info *tgt_info;
struct ol_context *ol_ctx;
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__);
p_cds_context = cds_get_global_context();
if (p_cds_context == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Failed cds_get_global_context", __func__);
ret = -1;
return ret;
}
pEpping_ctx = g_epping_ctx;
if (pEpping_ctx == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Failed to get pEpping_ctx", __func__);
ret = -1;
return ret;
}
pEpping_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);
/* store target type and target version info in hdd ctx */
pEpping_ctx->target_type = tgt_info->target_type;
ol_ctx = cds_get_context(QDF_MODULE_ID_BMI);
if (!ol_ctx) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
"%s: ol_ctx is NULL", __func__);
return A_ERROR;
}
epping_update_ol_config();
#ifndef FEATURE_BMI_2
/* 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 A_ERROR;
}
#endif
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH,
"%s: bmi_download_firmware done", __func__);
htcInfo.pContext = ol_ctx;
htcInfo.TargetFailure = ol_target_failure;
htcInfo.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, &htcInfo, 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;
}
pEpping_ctx->HTCHandle =
cds_get_context(QDF_MODULE_ID_HTC);
if (pEpping_ctx->HTCHandle == NULL) {
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(pEpping_ctx->HTCHandle) != A_OK) {
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(pEpping_ctx);
if (ret != 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_wait_targetdone", __func__);
goto error_end;
}
if (htc_start(pEpping_ctx->HTCHandle) != A_OK) {
goto error_end;
}
EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC started", __func__);
/* init the tx cookie resource */
ret = epping_cookie_init(pEpping_ctx);
if (ret == 0) {
pEpping_ctx->epping_adapter = epping_add_adapter(pEpping_ctx,
adapter_macAddr,
QDF_STA_MODE);
}
if (ret < 0 || pEpping_ctx->epping_adapter == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: epping_add_adaptererror error", __func__);
htc_stop(pEpping_ctx->HTCHandle);
epping_cookie_cleanup(pEpping_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;
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*========================================================================
\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 (NULL == 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 *pAdapter = pEpping_ctx->epping_adapter;
struct net_device *dev = pAdapter->dev;
A_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: pAdapter = 0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d",
__func__, pAdapter, eid, pktSkb, pPacket->pBuffer,
pPacket->ActualLength, status);
if (status != A_OK) {
if (status != A_ECANCELED) {
printk("%s: RX ERR (%d)\n", __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);
++pAdapter->stats.rx_packets;
pAdapter->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 ((pAdapter->stats.rx_packets %
EPPING_STATS_LOG_COUNT) == 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: total_rx_pkts = %lu",
__func__,
pAdapter->stats.rx_packets);
}
} else {
++pAdapter->stats.rx_dropped;
qdf_nbuf_free(pktSkb);
}
}
}

View File

@@ -0,0 +1,405 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*========================================================================
\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 *pAdapter,
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(pAdapter->pEpping_ctx);
if (cookie == NULL) {
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(pAdapter->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(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt);
if (ret != A_OK) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_send_pkt failed, ret = %d\n", __func__, ret);
epping_free_cookie(pAdapter->pEpping_ctx, cookie);
qdf_nbuf_free(new_skb);
return;
}
pAdapter->stats.tx_bytes += skb_len;
++pAdapter->stats.tx_packets;
if (((pAdapter->stats.tx_packets +
pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 &&
(pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) {
epping_log_stats(pAdapter, __func__);
}
}
static int epping_tx_send_int(qdf_nbuf_t skb, epping_adapter_t *pAdapter)
{
EPPING_HEADER *eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb);
HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED;
struct epping_cookie *cookie = NULL;
A_UINT8 ac = 0;
A_STATUS ret = A_OK;
int skb_len;
EPPING_HEADER tmpHdr = *eppingHdr;
/* allocate resource for this packet */
cookie = epping_alloc_cookie(pAdapter->pEpping_ctx);
/* no resource */
if (cookie == NULL) {
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 = pAdapter->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(pAdapter, 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(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt);
epping_log_packet(pAdapter, &tmpHdr, ret, __func__);
if (ret != A_OK) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: htc_send_pkt failed, status = %d\n", __func__,
ret);
epping_free_cookie(pAdapter->pEpping_ctx, cookie);
return A_ERROR;
}
pAdapter->stats.tx_bytes += skb_len;
++pAdapter->stats.tx_packets;
if (((pAdapter->stats.tx_packets +
pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 &&
(pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) {
epping_log_stats(pAdapter, __func__);
}
return 0;
}
void epping_tx_timer_expire(epping_adapter_t *pAdapter)
{
qdf_nbuf_t nodrop_skb;
EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__,
qdf_nbuf_queue_len(&pAdapter->nodrop_queue));
if (!qdf_nbuf_queue_len(&pAdapter->nodrop_queue)) {
/* nodrop queue is empty so no need to arm timer */
pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
return;
}
/* try to flush nodrop queue */
while ((nodrop_skb = qdf_nbuf_queue_remove(&pAdapter->nodrop_queue))) {
htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, true);
if (epping_tx_send_int(nodrop_skb, pAdapter)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: nodrop: %p 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(&pAdapter->nodrop_queue,
nodrop_skb);
break;
} else {
htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, false);
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s: nodrop: %p 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(&pAdapter->data_lock);
/* if nodrop queue is not empty, continue to arm timer */
if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) {
pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING;
qdf_timer_mod(&pAdapter->epping_timer,
TX_RETRY_TIMEOUT_IN_MS);
}
qdf_spin_unlock_bh(&pAdapter->data_lock);
} else {
pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
}
}
int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *pAdapter)
{
qdf_nbuf_t nodrop_skb;
EPPING_HEADER *eppingHdr;
A_UINT8 ac = 0;
eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb);
if (!IS_EPPING_PACKET(eppingHdr)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Recived 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(&pAdapter->nodrop_queue))) {
htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, true);
if (epping_tx_send_int(nodrop_skb, pAdapter)) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: nodrop: %p xmit fail\n", __func__,
nodrop_skb);
/* fail to xmit so put the nodrop packet to the nodrop queue */
qdf_nbuf_queue_insert_head(&pAdapter->nodrop_queue,
nodrop_skb);
/* no cookie so free the current skb */
goto tx_fail;
} else {
htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, false);
EPPING_LOG(QDF_TRACE_LEVEL_INFO,
"%s: nodrop: %p xmit ok\n", __func__,
nodrop_skb);
}
}
/* send the original packet */
if (epping_tx_send_int(skb, pAdapter))
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);
++pAdapter->stats.tx_dropped;
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Tx skb %p dropped, stats.tx_dropped = %ld\n",
__func__, skb, pAdapter->stats.tx_dropped);
return -ENOMEM;
} else {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: nodrop: %p queued\n", __func__, skb);
qdf_nbuf_queue_add(&pAdapter->nodrop_queue, skb);
qdf_spin_lock_bh(&pAdapter->data_lock);
if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) {
pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING;
qdf_timer_mod(&pAdapter->epping_timer,
TX_RETRY_TIMEOUT_IN_MS);
}
qdf_spin_unlock_bh(&pAdapter->data_lock);
}
return 0;
}
#ifdef HIF_SDIO
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_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue)
{
epping_context_t *pEpping_ctx = (epping_context_t *) ctx;
epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter;
struct net_device *dev = pAdapter->dev;
A_STATUS status;
HTC_ENDPOINT_ID eid;
qdf_nbuf_t pktSkb;
struct epping_cookie *cookie;
A_BOOL flushing = false;
qdf_nbuf_queue_t skb_queue;
HTC_PACKET *htc_pkt;
qdf_nbuf_queue_init(&skb_queue);
qdf_spin_lock_bh(&pAdapter->data_lock);
while (!HTC_QUEUE_EMPTY(pPacketQueue)) {
htc_pkt = htc_packet_dequeue(pPacketQueue);
if (htc_pkt == NULL)
break;
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 (A_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=%p data=%p len=0x%x eid=%d ",
__func__, pktSkb, htc_pkt->pBuffer,
htc_pkt->ActualLength, eid);
if (A_FAILED(status)) {
if (status == A_ECANCELED) {
/* a packet was flushed */
flushing = true;
}
if (status != A_NO_RESOURCE) {
printk("%s() -TX ERROR, status: 0x%x\n",
__func__, status);
}
} else {
EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: OK\n", __func__);
flushing = false;
}
epping_free_cookie(pAdapter->pEpping_ctx, cookie);
}
qdf_spin_unlock_bh(&pAdapter->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 == NULL)
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,470 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*========================================================================
\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"
static int epping_start_adapter(epping_adapter_t *pAdapter);
static void epping_stop_adapter(epping_adapter_t *pAdapter);
static void epping_timer_expire(void *data)
{
struct net_device *dev = (struct net_device *)data;
epping_adapter_t *pAdapter;
if (dev == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: netdev = NULL", __func__);
return;
}
pAdapter = netdev_priv(dev);
if (pAdapter == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: adapter = NULL", __func__);
return;
}
pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
epping_tx_timer_expire(pAdapter);
}
static int epping_ndev_open(struct net_device *dev)
{
epping_adapter_t *pAdapter;
int ret = 0;
pAdapter = netdev_priv(dev);
epping_start_adapter(pAdapter);
return ret;
}
static int epping_ndev_stop(struct net_device *dev)
{
epping_adapter_t *pAdapter;
int ret = 0;
pAdapter = netdev_priv(dev);
if (NULL == pAdapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
ret = -ENODEV;
goto end;
}
epping_stop_adapter(pAdapter);
end:
return ret;
}
static void epping_ndev_uninit(struct net_device *dev)
{
epping_adapter_t *pAdapter;
pAdapter = netdev_priv(dev);
if (NULL == pAdapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
goto end;
}
epping_stop_adapter(pAdapter);
end:
return;
}
static void epping_tx_queue_timeout(struct net_device *dev)
{
epping_adapter_t *pAdapter;
pAdapter = netdev_priv(dev);
if (NULL == pAdapter) {
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, pAdapter->started= %d",
__func__, pAdapter->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 (pAdapter->started)
netif_wake_queue(dev);
end:
return;
}
static int epping_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
epping_adapter_t *pAdapter;
int ret = 0;
pAdapter = netdev_priv(dev);
if (NULL == pAdapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
ret = -ENODEV;
goto end;
}
ret = epping_tx_send(skb, pAdapter);
end:
return ret;
}
static struct net_device_stats *epping_get_stats(struct net_device *dev)
{
epping_adapter_t *pAdapter = netdev_priv(dev);
if (NULL == pAdapter) {
EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: pAdapter = NULL",
__func__);
return NULL;
}
return &pAdapter->stats;
}
static int epping_ndev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
epping_adapter_t *pAdapter;
int ret = 0;
pAdapter = netdev_priv(dev);
if (NULL == pAdapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: EPPING adapter context is Null", __func__);
ret = -ENODEV;
goto end;
}
if (dev != pAdapter->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 *pAdapter = netdev_priv(dev);
struct sockaddr *psta_mac_addr = addr;
qdf_mem_copy(&pAdapter->macAddressCurrent,
psta_mac_addr->sa_data, ETH_ALEN);
qdf_mem_copy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
return 0;
}
static void epping_stop_adapter(epping_adapter_t *pAdapter)
{
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 (pAdapter && pAdapter->started) {
EPPING_LOG(LOG1, FL("Disabling queues"));
netif_tx_disable(pAdapter->dev);
netif_carrier_off(pAdapter->dev);
pAdapter->started = false;
pld_request_bus_bandwidth(qdf_ctx->dev,
PLD_BUS_WIDTH_LOW);
}
}
static int epping_start_adapter(epping_adapter_t *pAdapter)
{
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 (!pAdapter) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: pAdapter= NULL\n", __func__);
return -EINVAL;
}
if (!pAdapter->started) {
pld_request_bus_bandwidth(qdf_ctx->dev,
PLD_BUS_WIDTH_HIGH);
netif_carrier_on(pAdapter->dev);
EPPING_LOG(LOG1, FL("Enabling queues"));
netif_tx_start_all_queues(pAdapter->dev);
pAdapter->started = true;
} else {
EPPING_LOG(QDF_TRACE_LEVEL_WARN,
"%s: pAdapter %p already started\n", __func__,
pAdapter);
}
return 0;
}
static int epping_register_adapter(epping_adapter_t *pAdapter)
{
int ret = 0;
ret = register_netdev(pAdapter->dev);
if (ret != 0) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: unable to register device\n",
pAdapter->dev->name);
} else {
pAdapter->registered = true;
}
return ret;
}
static void epping_unregister_adapter(epping_adapter_t *pAdapter)
{
if (pAdapter) {
epping_stop_adapter(pAdapter);
if (pAdapter->registered) {
unregister_netdev(pAdapter->dev);
pAdapter->registered = false;
}
} else {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: pAdapter = NULL, unable to unregister device\n",
__func__);
}
}
void epping_destroy_adapter(epping_adapter_t *pAdapter)
{
struct net_device *dev = NULL;
epping_context_t *pEpping_ctx;
if (!pAdapter || !pAdapter->pEpping_ctx) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: pAdapter = NULL\n", __func__);
return;
}
dev = pAdapter->dev;
pEpping_ctx = pAdapter->pEpping_ctx;
epping_unregister_adapter(pAdapter);
qdf_spinlock_destroy(&pAdapter->data_lock);
qdf_timer_free(&pAdapter->epping_timer);
pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
while (qdf_nbuf_queue_len(&pAdapter->nodrop_queue)) {
qdf_nbuf_t tmp_nbuf = NULL;
tmp_nbuf = qdf_nbuf_queue_remove(&pAdapter->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 tQDF_ADAPTER_MODE device_mode)
{
struct net_device *dev;
epping_adapter_t *pAdapter;
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 == NULL) {
EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
"%s: Cannot allocate epping_adapter_t\n", __func__);
return NULL;
}
pAdapter = netdev_priv(dev);
qdf_mem_zero(pAdapter, sizeof(*pAdapter));
pAdapter->dev = dev;
pAdapter->pEpping_ctx = pEpping_ctx;
pAdapter->device_mode = device_mode; /* station, SAP, etc */
qdf_mem_copy(dev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr));
qdf_mem_copy(pAdapter->macAddressCurrent.bytes,
macAddr, sizeof(tSirMacAddr));
qdf_spinlock_create(&pAdapter->data_lock);
qdf_nbuf_queue_init(&pAdapter->nodrop_queue);
pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
qdf_timer_init(epping_get_qdf_ctx(), &pAdapter->epping_timer,
epping_timer_expire, dev, QDF_TIMER_TYPE_SW);
dev->type = ARPHRD_IEEE80211;
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(pAdapter) == 0) {
EPPING_LOG(LOG1, FL("Disabling queues"));
netif_tx_disable(dev);
netif_carrier_off(dev);
return pAdapter;
} else {
epping_destroy_adapter(pAdapter);
return NULL;
}
}
int epping_connect_service(epping_context_t *pEpping_ctx)
{
int status, i;
HTC_SERVICE_CONNECT_REQ connect;
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 = epping_tx_complete_multiple;
connect.EpCallbacks.EpRecv = epping_rx;
/* epping_tx_complete use Multiple version */
connect.EpCallbacks.EpTxComplete = NULL;
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)
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 (status != EOK) {
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)
connect.service_id = WMI_DATA_BK_SVC;
status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response);
if (status != EOK) {
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;
}

4394
utils/fwlog/dbglog_host.c Normal file

File diff suppressed because it is too large Load Diff

174
utils/fwlog/dbglog_host.h Normal file
View File

@@ -0,0 +1,174 @@
/*
* Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef _DBGLOG_HOST_H_
#define _DBGLOG_HOST_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "dbglog_common.h"
#include "ol_defines.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)
/*
* 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, A_UINT16 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,
A_UINT16 tsr);
/** Enable reporting. If it is set to false then Traget wont 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, enum 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 sinlge 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, A_UINT32 mod_id_lvl);
/** Enable/Disable the logging for VAP */
int
dbglog_vap_log_enable(wmi_unified_t wmi_handle, A_UINT16 vap_id,
A_BOOL isenable);
/** Enable/Disable logging for Module */
int
dbglog_module_log_enable(wmi_unified_t wmi_handle, A_UINT32 mod_id,
A_BOOL isenable);
/** set vap enablie bitmap */
void
dbglog_set_vap_enable_bitmap(wmi_unified_t wmi_handle,
A_UINT32 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,
A_UINT32 log_level,
A_UINT32 *mod_enable_bitmap,
A_UINT32 bitmap_len);
int
dbglog_parse_debug_logs(ol_scn_t scn, u_int8_t *datap,
u_int32_t len);
/** Register the cnss_diag activate with the wlan driver */
int cnss_diag_activate_service(void);
#ifdef __cplusplus
}
#endif
#endif /* _DBGLOG_HOST_H_ */

View File

@@ -0,0 +1,453 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#if !defined(__HOST_DIAG_CORE_EVENT_H)
#define __HOST_DIAG_CORE_EVENT_H
/**=========================================================================
\file host_diag_core_event.h
\brief WLAN UTIL host DIAG Events
Definitions for DIAG Events
========================================================================*/
/* $Header$ */
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include "qdf_types.h"
#include "i_host_diag_core_event.h"
/*--------------------------------------------------------------------------
Preprocessor definitions and constants
------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define WAKE_LOCK_NAME_LEN 80
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_SECURITY
------------------------------------------------------------------------*/
typedef struct {
uint8_t eventId;
uint8_t authMode;
uint8_t encryptionModeUnicast;
uint8_t encryptionModeMulticast;
uint8_t pmkIDMatch;
uint8_t bssid[6];
uint8_t keyId;
uint8_t status;
} host_event_wlan_security_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_STATUS_V2
------------------------------------------------------------------------*/
typedef struct {
uint8_t eventId;
uint8_t ssid[32];
uint8_t bssType;
uint8_t rssi;
uint8_t channel;
uint8_t qosCapability;
uint8_t authType;
uint8_t encryptionType;
uint8_t reason;
uint8_t reasonDisconnect;
} host_event_wlan_status_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_HANDOFF
------------------------------------------------------------------------*/
typedef struct {
uint8_t eventId;
uint8_t currentApBssid[6];
uint8_t currentApRssi;
uint8_t candidateApBssid[6];
uint8_t candidateApRssi;
} host_event_wlan_handoff_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_VCC
------------------------------------------------------------------------*/
typedef struct {
uint8_t eventId;
uint8_t rssi;
uint8_t txPer;
uint8_t rxPer;
int linkQuality;
} host_event_wlan_vcc_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_QOS
------------------------------------------------------------------------*/
typedef struct {
uint8_t eventId;
uint8_t reasonCode;
} host_event_wlan_qos_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_PE
------------------------------------------------------------------------*/
typedef struct {
char bssid[6];
uint16_t event_type;
uint16_t sme_state;
uint16_t mlm_state;
uint16_t status;
uint16_t reason_code;
} host_event_wlan_pe_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_ADD_BLOCK_ACK_SUCCESS
------------------------------------------------------------------------*/
typedef struct {
char ucBaPeerMac[6];
uint8_t ucBaTid;
uint8_t ucBaBufferSize;
uint16_t usBaSSN;
uint8_t fInitiator;
} host_event_wlan_add_block_ack_success_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_ADD_BLOCK_ACK_FAILED
------------------------------------------------------------------------*/
typedef struct {
char ucBaPeerMac[6];
uint8_t ucBaTid;
uint8_t ucReasonCode;
uint8_t fInitiator;
} host_event_wlan_add_block_ack_failed_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_DELETE_BLOCK_ACK_SUCCESS
------------------------------------------------------------------------*/
typedef struct {
char ucBaPeerMac[6];
uint8_t ucBaTid;
uint8_t ucDeleteReasonCode;
} host_event_wlan_add_block_ack_deleted_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_DELETE_BLOCK_ACK_FAILED
------------------------------------------------------------------------*/
typedef struct {
char ucBaPeerMac[6];
uint8_t ucBaTid;
uint8_t ucDeleteReasonCode;
uint8_t ucFailReasonCode;
} host_event_wlan_add_block_ack_delete_failed_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_BSS_PROTECTION
------------------------------------------------------------------------*/
typedef struct {
uint8_t event_type;
uint8_t prot_type;
} host_event_wlan_bss_prot_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_BRINGUP_STATUS
------------------------------------------------------------------------*/
typedef struct {
uint16_t wlanStatus;
char driverVersion[10];
} host_event_wlan_bringup_status_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_POWERSAVE_WOW
------------------------------------------------------------------------*/
typedef struct {
uint8_t event_subtype;
uint8_t wow_type;
uint8_t wow_magic_pattern[6];
uint8_t wow_del_ptrn_id;
uint8_t wow_wakeup_cause;
uint8_t wow_wakeup_cause_pbm_ptrn_id;
} host_event_wlan_powersave_wow_payload_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_BTC
------------------------------------------------------------------------*/
typedef struct {
uint8_t eventId;
uint8_t btAddr[6];
uint16_t connHandle;
uint8_t connStatus;
uint8_t linkType;
uint8_t scoInterval;
uint8_t scoWindow;
uint8_t retransWindow;
uint8_t mode;
} host_event_wlan_btc_type;
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_EAPOL
------------------------------------------------------------------------*/
/**
* struct host_event_wlan_eapol - Structure holding the eapol information
* @event_sub_type: 0-Transmitted, 1-Received
* @eapol_packet_type: 0 - EAP Start, 1 - EAPOL Start, 2 - EAPOL Logoff
3 - EAPOL Key, 4 - EAPOL Encapsulated Alert
* @eapol_key_info: This field from the driver is in big endian format.
* So, the masks .0x8013. can be used to extract the
* message type. After masking, the values corresponding
* to messages 1/2/3/4 are given below:
* Msg. 1 0x8000
* Msg. 2 0x0001
* Msg. 3 0x8013
* Msg. 4 0x0003
* @eapol_rate: Rate at which the frame is received
* @dest_addr: Destination address
* @src_addr: Source address
*
* This structure contains the EAPOL information related to logging
*/
struct host_event_wlan_eapol {
uint8_t event_sub_type;
uint8_t eapol_packet_type;
uint16_t eapol_key_info;
uint16_t eapol_rate;
uint8_t dest_addr[6];
uint8_t src_addr[6];
};
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_LOW_RESOURCE_FAILURE
------------------------------------------------------------------------*/
/**
* struct host_event_wlan_low_resource_failure - Structure holding the
* low resource failure information
* @event_sub_type: Gives further information about reason for
* low resource condition
*
* This structure will hold the low resource failure information
*/
struct host_event_wlan_low_resource_failure {
uint8_t event_sub_type;
};
/**
* enum resource_failure_type - Reason for low resource failure condition
* @WIFI_EVENT_MEMORY_FAILURE: Memory failure
*
* This enum has the reason codes why the low resource situation is observed
*/
enum resource_failure_type {
WIFI_EVENT_MEMORY_FAILURE,
};
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_WAKE_LOCK
------------------------------------------------------------------------*/
/**
* struct host_event_wlan_wake_lock - Structure holding the wakelock information
* @status: Whether the wakelock is taken/released
* @reason: Reason for taking this wakelock
* @timeout: Timeout value in case of timed wakelocks
* @name_len: Length of the name of the wakelock that will follow
* @name: Name of the wakelock
*
* This structure will hold the wakelock information
*/
struct host_event_wlan_wake_lock {
uint32_t status;
uint32_t reason;
uint32_t timeout;
uint32_t name_len;
char name[WAKE_LOCK_NAME_LEN];
};
/*-------------------------------------------------------------------------
Event ID: EVENT_WLAN_LOG_COMPLETE
------------------------------------------------------------------------*/
/**
* struct host_event_wlan_log_complete - Holds log completion details
* @is_fatal: Indicates if the event is fatal or not
* @indicator: Source of the bug report - Framework/Host/Firmware
* @reason_code: Reason for triggering bug report
* @reserved: Reserved field
*
* This structure holds the log completion related information
*/
struct host_event_wlan_log_complete {
uint32_t is_fatal;
uint32_t indicator;
uint32_t reason_code;
uint32_t reserved;
};
/**
* struct host_event_tdls_teardown - tdls teardown diag event
* @reason: reason for tear down
* @peer_mac: peer mac
*
* This structure contains tdls teardown diag event info
*/
struct host_event_tdls_teardown {
uint32_t reason;
uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
};
/**
* struct host_event_tdls_enable_link - tdls enable link event
* @peer_mac: peer mac
* @is_off_chan_supported: if off channel supported
* @is_off_chan_configured: if off channel configured
* @is_off_chan_established: if off channel established
*
* This structure contain tdls enable link diag event info
*/
struct host_event_tdls_enable_link {
uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
uint8_t is_off_chan_supported;
uint8_t is_off_chan_configured;
uint8_t is_off_chan_established;
};
/**
* struct host_event_suspend - suspend/resume state
* @state: suspend/resume state
*
* This structure contains suspend resume diag event info
*/
struct host_event_suspend {
uint8_t state;
};
/**
* struct host_event_offload_req - offload state
* @offload_type: offload type
* @state: enabled or disabled state
*
* This structure contains offload diag event info
*/
struct host_event_offload_req {
uint8_t offload_type;
uint8_t state;
};
/**
* struct host_event_tdls_scan_rejected - scan
* rejected due to tdls
* @status: rejected status
*
* This structure contains scan rejected due to
* tdls event info
*/
struct host_event_tdls_scan_rejected {
uint8_t status;
};
/**
* struct host_event_tdls_tx_rx_mgmt - for TX RX management frame
* @event_id: event ID
* @tx_rx: tx or rx
* @type: type of frame
* @action_sub_type: action frame type
* @peer_mac: peer mac
*
* This structure contains tdls TX RX management frame info
*/
struct host_event_tdls_tx_rx_mgmt {
uint8_t event_id;
uint8_t tx_rx;
uint8_t type;
uint8_t action_sub_type;
uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
};
/*-------------------------------------------------------------------------
Function declarations and documenation
------------------------------------------------------------------------*/
/**
* enum wifi_connectivity_events - Enum containing EAPOL sub type
* @WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED: EAPOL transmitted
* @WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED: EAPOL received
*
* This enum contains the EAPOL subtype
*/
enum wifi_connectivity_events {
WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED,
WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED,
};
/**
* enum wake_lock_reason - Reason for taking/releasing wakelock
* @WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT: Driver initialization
* @WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT: Driver re-initialization
* @WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT: Driver shutdown
* @WIFI_POWER_EVENT_WAKELOCK_SCAN: Scan request/response handling
* @WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN: Extended scan request/response handling
* @WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN: Driver resume
* @WIFI_POWER_EVENT_WAKELOCK_ROC: Remain on channel request/response handling
* @WIFI_POWER_EVENT_WAKELOCK_AUTO_SUSPEND: Auto suspend related handling
* @WIFI_POWER_EVENT_WAKELOCK_IPA: IPA related handling
* @WIFI_POWER_EVENT_WAKELOCK_ADD_STA: Addition of STA
* @WIFI_POWER_EVENT_WAKELOCK_HOLD_RX: Wakelocks taken for receive
* @WIFI_POWER_EVENT_WAKELOCK_SAP: SoftAP related wakelocks
* @WIFI_POWER_EVENT_WAKELOCK_WOW: WoW feature related
* @WIFI_POWER_EVENT_WAKELOCK_PNO: PNO feature related
* @WIFI_POWER_EVENT_WAKELOCK_DEL_STA: Deletion of a station
* @WIFI_POWER_EVENT_WAKELOCK_DFS: DFS related wakelocks
* @WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP: Firmware response
* @WIFI_POWER_EVENT_WAKELOCK_MISC: Miscellaneous wakelocks
* @WIFI_POWER_EVENT_WAKELOCK_DHCP: DHCP negotiation under way
*
* Indicates the reason for which the wakelock was taken/released
*/
enum wake_lock_reason {
WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT,
WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT,
WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT,
WIFI_POWER_EVENT_WAKELOCK_SCAN,
WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN,
WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN,
WIFI_POWER_EVENT_WAKELOCK_ROC,
WIFI_POWER_EVENT_WAKELOCK_AUTO_SUSPEND,
WIFI_POWER_EVENT_WAKELOCK_IPA,
WIFI_POWER_EVENT_WAKELOCK_ADD_STA,
WIFI_POWER_EVENT_WAKELOCK_HOLD_RX,
WIFI_POWER_EVENT_WAKELOCK_SAP,
WIFI_POWER_EVENT_WAKELOCK_WOW,
WIFI_POWER_EVENT_WAKELOCK_PNO,
WIFI_POWER_EVENT_WAKELOCK_DEL_STA,
WIFI_POWER_EVENT_WAKELOCK_DFS,
WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP,
WIFI_POWER_EVENT_WAKELOCK_MISC,
WIFI_POWER_EVENT_WAKELOCK_DHCP,
};
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __HOST_DIAG_CORE_EVENT_H */

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#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
/* Version to be updated whenever format of vos_log_pktlog_info changes */
#define VERSION_LOG_WLAN_PKT_LOG_INFO_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;
} 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 patern 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
* @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[];
};
/*-------------------------------------------------------------------------
Function declarations and documenation
------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __HOST_DIAG_CORE_LOG_H */

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef EVENT_DEFS_H
#define EVENT_DEFS_H
typedef enum {
EVENT_DROP_ID = 0,
/* Events between 0x1 to 0x674 are not used */
EVENT_WLAN_SECURITY = 0x675, /* 13 byte payload */
EVENT_WLAN_STATUS, /* 15 byte payload */
/* Events 0x677 and 0x678 are not used */
EVENT_WLAN_QOS = 0x679, /* 2 byte payload */
EVENT_WLAN_PE, /* 16 byte payload */
/* Events between 0x67b to 0x67f are not used */
EVENT_WLAN_BRINGUP_STATUS = 0x680, /* 12 byte payload */
EVENT_WLAN_POWERSAVE_GENERIC, /* 16 byte payload */
EVENT_WLAN_POWERSAVE_WOW, /* 11 byte payload */
/* Events between 0x683 to 0x690 are not used */
EVENT_WLAN_BTC = 0x691, /* 15 byte payload */
EVENT_WLAN_EAPOL = 0xA8D,/* 18 bytes payload */
EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */
EVENT_WLAN_BEACON_RECEIVED = 0xAA6, /* FW event: 2726 */
EVENT_WLAN_LOG_COMPLETE = 0xAA7, /* 16 bytes payload */
EVENT_WLAN_STATUS_V2 = 0xAB3,
/*
* <diag_event>
* EVENT_WLAN_TDLS_TEARDOWN
* @ reason: reason for tear down.
* @peer_mac: Peer mac address
*
*
* This event is sent when TDLS tear down happens.
*
* Supported Feature: TDLS
*
* </diag_event>
*/
EVENT_WLAN_TDLS_TEARDOWN = 0xAB5,
/*
* <diag_event>
* EVENT_WLAN_TDLS_ENABLE_LINK
* @peer_mac: peer mac
* @is_off_chan_supported: If peer supports off channel
* @is_off_chan_configured: If off channel is configured
* @is_off_chan_established: If off channel is established
*
*
* This event is sent when TDLS enable link happens.
*
* Supported Feature: TDLS
*
* </diag_event>
*/
EVENT_WLAN_TDLS_ENABLE_LINK = 0XAB6,
EVENT_WLAN_SUSPEND_RESUME = 0xAB7,
EVENT_WLAN_OFFLOAD_REQ = 0xAB8,
/*
* <diag_event>
* EVENT_TDLS_SCAN_BLOCK
* @status: rejected status
*
*
* This event is sent when scan is rejected due to TDLS.
*
* Supported Feature: TDLS
*
* </diag_event>
*/
EVENT_TDLS_SCAN_BLOCK = 0xAB9,
/*
* <diag_event>
* EVENT_WLAN_TDLS_TX_RX_MGMT
* @event_id: event id
* @tx_rx: tx or rx
* @type: type of frame
* @action_sub_type: action frame type
* @peer_mac: peer mac
*
*
* This event is sent when TDLS mgmt rx tx happens.
*
* Supported Feature: TDLS
*
* </diag_event>
*/
EVENT_WLAN_TDLS_TX_RX_MGMT = 0xABA,
EVENT_WLAN_LOW_RESOURCE_FAILURE = 0xABB,
EVENT_MAX_ID = 0x0FFF
} event_id_enum_type;
#endif /* EVENT_DEFS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,306 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*============================================================================
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"
#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()) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
"%s: Unloading/Loading in Progress. Ignore!!!",
__func__);
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) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"qdf_mem_malloc failed");
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;
if (cds_is_load_or_unload_in_progress()) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
"%s: Unloading/Loading in Progress. Ignore!!!",
__func__);
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) {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
"qdf_mem_malloc failed");
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);
if (ptt_sock_send_msg_to_app
(wmsg, 0, ANI_NL_MSG_PUMAC, INVALID_PID) < 0) {
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);
}
#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);
}
#endif

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#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,
};
/*-------------------------------------------------------------------------
Function declarations and documenation
------------------------------------------------------------------------*/
#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
void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause);
#else
static inline void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause)
{
return;
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __I_HOST_DIAG_CORE_EVENT_H */

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#if !defined(__I_HOST_DIAG_CORE_LOG_H)
#define __I_HOST_DIAG_CORE_LOG_H
#ifdef FEATURE_WLAN_DIAG_SUPPORT
#include <log_codes.h>
#endif
/**=========================================================================
\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 definiton 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)
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
/*-------------------------------------------------------------------------
Function declarations and documenation
------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __I_HOST_DIAG_CORE_LOG_H */

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/******************************************************************************
* 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_logging_sock_activate_svc(int log_fe_to_console, int num_buf);
int wlan_logging_sock_deactivate_svc(void);
int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length);
#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
void wlan_logging_set_per_pkt_stats(void);
void wlan_logging_set_fw_flush_complete(void);
void wlan_flush_host_logs_for_fatal(void);
#else
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)
{
}
#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */
#ifdef FEATURE_WLAN_DIAG_SUPPORT
void wlan_report_log_completion(uint32_t is_fatal,
uint32_t indicator,
uint32_t reason_code);
#else
static inline void wlan_report_log_completion(uint32_t is_fatal,
uint32_t indicator,
uint32_t reason_code)
{
return;
}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data);
void wlan_deregister_txrx_packetdump(void);
void wlan_register_txrx_packetdump(void);
#endif /* WLAN_LOGGING_SOCK_SVC_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*===========================================================================
\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>
#include <linux/if.h>
/*---------------------------------------------------------------------------
* External Functions
*-------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
* Preprocessor Definitions and Constants
*-------------------------------------------------------------------------*/
#define WLAN_NL_MAX_PAYLOAD 256 /* 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 maximun 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_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,
WLAN_NL_MSG_CNSS_DIAG = ANI_NL_MSG_BASE + 0x0B, /* Value needs to be 27 */
ANI_NL_MSG_LOG,
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 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 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];
};
/*
* Maximim 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,
};
#endif /* WLAN_NLINK_COMMON_H__ */

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/******************************************************************************
* 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);
int nl_srv_init(void *wiphy);
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);
int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag);
int nl_srv_bcast(struct sk_buff *skb);
int nl_srv_is_initialized(void);
#endif

View File

@@ -0,0 +1,539 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/******************************************************************************
* wlan_nlink_srv.c
*
* This file contains the definitions specific to the wlan_nlink_srv
*
******************************************************************************/
/*
* 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 diagnotics netlink socket will not be available since this
* diagnostics netlink socket can only be exposed by one instance of the driver.
*/
#ifndef MULTI_IF_NAME
#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>
#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
*
* 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 availibility.
*
* Return: radio index for success and -EINVAL for failure
*/
int nl_srv_init(void *wiphy)
{
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: %p",
__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);
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);
else
dev_kfree_skb(skb);
return err;
}
/**
* 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 != NULL) {
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 != NULL) {
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;
}
#else
/* 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 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, WLAN_NLINK_PROTO_FAMILY,
&cfg);
if (nl_srv_sock != NULL) {
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 != NULL) {
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;
}
/*
* 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 = 0;
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);
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 = 0;
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);
}
return err;
}
/*
* 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[%p], len[%d], nlhdr[%p], 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(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"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(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"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(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"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] != NULL) {
(nl_srv_msg_handler[type])(skb);
} else {
QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
"NLINK: No handler for Netlink 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;
}
#endif
#else /* ifndef MULTI_IF_NAME */
#include <wlan_nlink_srv.h>
int nl_srv_init(void *wiphy)
{
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)
{
return 0;
}
int nl_srv_bcast(struct sk_buff *skb)
{
return 0;
}
int nl_srv_is_initialized(void)
{
return 0;
}
#endif

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#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,186 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef _PKTLOG_AC_H_
#define _PKTLOG_AC_H_
#ifndef REMOVE_PKT_LOG
#include "ol_if_athvar.h"
#include <pktlog_ac_api.h>
#include <pktlog_ac_fmt.h>
#include "osdep.h"
#include <wmi_unified.h>
#include <wmi_unified_api.h>
#include <wdi_event_api.h>
#include "hif.h"
#define NO_REG_FUNCS 4
/* Locking interface for pktlog */
#define PKTLOG_LOCK_INIT(_pl_info) spin_lock_init(&(_pl_info)->log_lock)
#define PKTLOG_LOCK_DESTROY(_pl_info)
#define PKTLOG_LOCK(_pl_info) spin_lock(&(_pl_info)->log_lock)
#define PKTLOG_UNLOCK(_pl_info) spin_unlock(&(_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
/* 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(ol_txrx_pdev_handle pdev_txrx_handle);
ssize_t pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos,
struct ath_pktlog_info *pl_info, bool *read_complete);
int pktlog_send_per_pkt_stats_to_user(void);
A_STATUS
wdi_pktlog_unsubscribe(struct ol_txrx_pdev_t *txrx_pdev, 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 ol_txrx_pdev_t *handle);
};
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 ol_pktlog_dev_t {
struct ol_pl_arch_dep_funcs *pl_funcs;
struct ath_pktlog_info *pl_info;
ol_ath_generic_softc_handle scn;
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;
};
#define PKTLOG_SYSCTL_SIZE 14
#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))
extern struct ol_pktlog_dev_t ol_pl_dev;
/*
* WDI related data and functions
* Callback function to the WDI events
*/
void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data);
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_setsize(struct hif_opaque_softc *scn, int32_t log_state);
int pktlog_disable(struct hif_opaque_softc *scn);
int pktlogmod_init(void *context);
void pktlogmod_exit(struct ol_txrx_pdev_t *handle);
int pktlog_htc_attach(void);
void pktlog_process_fw_msg(uint32_t *msg_word);
#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 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 int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state)
{
return 0;
}
static 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(uint32_t *msg_word)
{ }
#endif /* REMOVE_PKT_LOG */
#endif /* _PKTLOG_AC_H_ */

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
* 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_
#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;
/**
* @typedef hif_opaque_softc_handle
* @brief opaque handle for hif_opaque_softc
*/
struct hif_opaque_softc;
typedef struct hif_opaque_softc *hif_opaque_softc_handle;
/**
* @typedef net_device_handle
* @brief opaque handle linux phy device object
*/
struct net_device;
typedef struct net_device *net_device_handle;
void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle,
hif_opaque_softc_handle scn);
/* Packet log state information */
#ifndef _PKTLOG_INFO
#define _PKTLOG_INFO
struct ath_pktlog_info {
struct ath_pktlog_buf *buf;
uint32_t log_state;
uint32_t saved_state;
uint32_t options;
/* Size of buffer in bytes */
int32_t buf_size;
spinlock_t log_lock;
/* 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 milisecond */
uint32_t trigger_interval;
uint32_t start_time_thruput;
uint32_t start_time_per;
};
#endif /* _PKTLOG_INFO */
#else /* REMOVE_PKT_LOG */
typedef void *ol_pktlog_dev_handle;
#define ol_pl_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,78 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef _PKTLOG_AC_I_
#define _PKTLOG_AC_I_
#ifndef REMOVE_PKT_LOG
#include <ol_txrx_internal.h>
#include <pktlog_ac.h>
#ifdef FEATURE_PKTLOG
#define PKTLOG_DEFAULT_BUFSIZE (10 * 1024 * 1024) /* 10MB */
#else
#define PKTLOG_DEFAULT_BUFSIZE (1 * 1024 * 1024) /* 1MB */
#endif
#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
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 HELIUMPLUS
uint32_t type_specific_data;
#endif
char *buf;
};
void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg);
char *pktlog_getbuf(struct ol_pktlog_dev_t *pl_dev,
struct ath_pktlog_info *pl_info,
size_t log_size, struct ath_pktlog_hdr *pl_hdr);
A_STATUS process_tx_info(struct ol_txrx_pdev_t *pdev, void *data);
A_STATUS process_rx_info(void *pdev, void *data);
A_STATUS process_rx_info_remote(void *pdev, void *data);
A_STATUS process_rate_find(void *pdev, void *data);
A_STATUS process_rate_update(void *pdev, void *data);
A_STATUS process_sw_event(void *pdev, void *data);
#endif /* REMOVE_PKT_LOG */
#endif

931
utils/pktlog/linux_ac.c Normal file
View File

@@ -0,0 +1,931 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifndef REMOVE_PKT_LOG
#ifndef EXPORT_SYMTAB
#define EXPORT_SYMTAB
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif
/*
* Linux specific implementation of Pktlogs for 802.11ac
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <pktlog_ac_i.h>
#include <pktlog_ac_fmt.h>
#include <pktlog_ac.h>
#include "i_host_diag_core_log.h"
#include "host_diag_core_log.h"
#include "ani_global.h"
#define PKTLOG_TAG "ATH_PKTLOG"
#define PKTLOG_DEVNAME_SIZE 32
#define MAX_WLANDEV 1
#ifdef MULTI_IF_NAME
#define PKTLOG_PROC_DIR "ath_pktlog" MULTI_IF_NAME
#else
#define PKTLOG_PROC_DIR "ath_pktlog"
#endif
/* Permissions for creating proc entries */
#define PKTLOG_PROC_PERM 0444
#define PKTLOG_PROCSYS_DIR_PERM 0555
#define PKTLOG_PROCSYS_PERM 0644
#ifndef __MOD_INC_USE_COUNT
#define PKTLOG_MOD_INC_USE_COUNT do { \
if (!try_module_get(THIS_MODULE)) { \
printk(KERN_WARNING "try_module_get failed\n"); \
} } while (0)
#define PKTLOG_MOD_DEC_USE_COUNT module_put(THIS_MODULE)
#else
#define PKTLOG_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
#define PKTLOG_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
#endif
static struct ath_pktlog_info *g_pktlog_info;
static struct proc_dir_entry *g_pktlog_pde;
static int pktlog_attach(struct hif_opaque_softc *sc);
static void pktlog_detach(struct ol_txrx_pdev_t *handle);
static int pktlog_open(struct inode *i, struct file *f);
static int pktlog_release(struct inode *i, struct file *f);
static int pktlog_mmap(struct file *f, struct vm_area_struct *vma);
static ssize_t pktlog_read(struct file *file, char *buf, size_t nbytes,
loff_t *ppos);
static struct file_operations pktlog_fops = {
open: pktlog_open,
release:pktlog_release,
mmap : pktlog_mmap,
read : pktlog_read,
};
/*
* Linux implementation of helper functions
*/
static struct ol_pktlog_dev_t *cds_get_pl_handle(void)
{
ol_txrx_pdev_handle pdev_txrx_handle;
pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX);
if (!pdev_txrx_handle) {
QDF_ASSERT(0);
return NULL;
}
return pdev_txrx_handle->pl_dev;
}
static struct ol_pktlog_dev_t *ol_get_pl_handle(
ol_txrx_pdev_handle pdev_txrx_handle)
{
if (!pdev_txrx_handle)
return NULL;
return pdev_txrx_handle->pl_dev;
}
void pktlog_disable_adapter_logging(struct hif_opaque_softc *scn)
{
struct ol_pktlog_dev_t *pl_dev = cds_get_pl_handle();
if (pl_dev)
pl_dev->pl_info->log_state = 0;
}
int pktlog_alloc_buf(struct hif_opaque_softc *scn)
{
uint32_t page_cnt;
unsigned long vaddr;
struct page *vpg;
struct ath_pktlog_info *pl_info;
ol_txrx_pdev_handle pdev_txrx_handle;
pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX);
if (!pdev_txrx_handle || !pdev_txrx_handle->pl_dev) {
printk(PKTLOG_TAG
"%s: Unable to allocate buffer "
"scn or scn->pdev_txrx_handle->pl_dev is null\n",
__func__);
return -EINVAL;
}
pl_info = pdev_txrx_handle->pl_dev->pl_info;
page_cnt = (sizeof(*(pl_info->buf)) + pl_info->buf_size) / PAGE_SIZE;
pl_info->buf = vmalloc((page_cnt + 2) * PAGE_SIZE);
if (pl_info->buf == NULL) {
printk(PKTLOG_TAG
"%s: Unable to allocate buffer "
"(%d pages)\n", __func__, page_cnt);
return -ENOMEM;
}
pl_info->buf = (struct ath_pktlog_buf *)
(((unsigned long)(pl_info->buf) + PAGE_SIZE - 1)
& PAGE_MASK);
for (vaddr = (unsigned long)(pl_info->buf);
vaddr < ((unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE));
vaddr += PAGE_SIZE) {
vpg = vmalloc_to_page((const void *)vaddr);
SetPageReserved(vpg);
}
return 0;
}
void pktlog_release_buf(ol_txrx_pdev_handle pdev_txrx_handle)
{
unsigned long page_cnt;
unsigned long vaddr;
struct page *vpg;
struct ath_pktlog_info *pl_info;
if (!pdev_txrx_handle || !pdev_txrx_handle->pl_dev) {
printk(PKTLOG_TAG
"%s: Unable to allocate buffer"
"scn or scn->pdev_txrx_handle->pl_dev is null\n",
__func__);
return;
}
pl_info = pdev_txrx_handle->pl_dev->pl_info;
page_cnt = ((sizeof(*(pl_info->buf)) + pl_info->buf_size) /
PAGE_SIZE) + 1;
for (vaddr = (unsigned long)(pl_info->buf);
vaddr < (unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE);
vaddr += PAGE_SIZE) {
vpg = vmalloc_to_page((const void *)vaddr);
ClearPageReserved(vpg);
}
vfree(pl_info->buf);
pl_info->buf = NULL;
}
static void pktlog_cleanup(struct ath_pktlog_info *pl_info)
{
pl_info->log_state = 0;
PKTLOG_LOCK_DESTROY(pl_info);
}
/* sysctl procfs handler to enable pktlog */
static int
qdf_sysctl_decl(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ppos)
{
int ret, enable;
ol_ath_generic_softc_handle scn;
struct ol_pktlog_dev_t *pl_dev;
scn = (ol_ath_generic_softc_handle) ctl->extra1;
if (!scn) {
printk("%s: Invalid scn context\n", __func__);
ASSERT(0);
return -EINVAL;
}
pl_dev = cds_get_pl_handle();
if (!pl_dev) {
printk("%s: Invalid pktlog context\n", __func__);
ASSERT(0);
return -ENODEV;
}
ctl->data = &enable;
ctl->maxlen = sizeof(enable);
if (write) {
ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
lenp, ppos);
if (ret == 0)
ret = pl_dev->pl_funcs->pktlog_enable(
(struct hif_opaque_softc *)scn, enable,
cds_is_packet_log_enabled(), 0, 1);
else
printk(PKTLOG_TAG "%s:proc_dointvec failed\n",
__func__);
} else {
ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
lenp, ppos);
if (ret)
printk(PKTLOG_TAG "%s:proc_dointvec failed\n",
__func__);
}
ctl->data = NULL;
ctl->maxlen = 0;
return ret;
}
static int get_pktlog_bufsize(struct ol_pktlog_dev_t *pl_dev)
{
return pl_dev->pl_info->buf_size;
}
/* sysctl procfs handler to set/get pktlog size */
static int
qdf_sysctl_decl(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ppos)
{
int ret, size;
ol_ath_generic_softc_handle scn;
struct ol_pktlog_dev_t *pl_dev;
scn = (ol_ath_generic_softc_handle) ctl->extra1;
if (!scn) {
printk("%s: Invalid scn context\n", __func__);
ASSERT(0);
return -EINVAL;
}
pl_dev = cds_get_pl_handle();
if (!pl_dev) {
printk("%s: Invalid pktlog handle\n", __func__);
ASSERT(0);
return -ENODEV;
}
ctl->data = &size;
ctl->maxlen = sizeof(size);
if (write) {
ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
lenp, ppos);
if (ret == 0)
ret = pl_dev->pl_funcs->pktlog_setsize(
(struct hif_opaque_softc *)scn, size);
} else {
size = get_pktlog_bufsize(pl_dev);
ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
lenp, ppos);
}
ctl->data = NULL;
ctl->maxlen = 0;
return ret;
}
/* Register sysctl table */
static int pktlog_sysctl_register(struct hif_opaque_softc *scn)
{
struct ol_pktlog_dev_t *pl_dev = cds_get_pl_handle();
struct ath_pktlog_info_lnx *pl_info_lnx;
char *proc_name;
if (pl_dev) {
pl_info_lnx = PL_INFO_LNX(pl_dev->pl_info);
proc_name = pl_dev->name;
} else {
pl_info_lnx = PL_INFO_LNX(g_pktlog_info);
proc_name = PKTLOG_PROC_SYSTEM;
}
/*
* Setup the sysctl table for creating the following sysctl entries:
* /proc/sys/PKTLOG_PROC_DIR/<adapter>/enable for enabling/disabling
* pktlog
* /proc/sys/PKTLOG_PROC_DIR/<adapter>/size for changing the buffer size
*/
memset(pl_info_lnx->sysctls, 0, sizeof(pl_info_lnx->sysctls));
pl_info_lnx->sysctls[0].procname = PKTLOG_PROC_DIR;
pl_info_lnx->sysctls[0].mode = PKTLOG_PROCSYS_DIR_PERM;
pl_info_lnx->sysctls[0].child = &pl_info_lnx->sysctls[2];
/* [1] is NULL terminator */
pl_info_lnx->sysctls[2].procname = proc_name;
pl_info_lnx->sysctls[2].mode = PKTLOG_PROCSYS_DIR_PERM;
pl_info_lnx->sysctls[2].child = &pl_info_lnx->sysctls[4];
/* [3] is NULL terminator */
pl_info_lnx->sysctls[4].procname = "enable";
pl_info_lnx->sysctls[4].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[4].proc_handler = ath_sysctl_pktlog_enable;
pl_info_lnx->sysctls[4].extra1 = scn;
pl_info_lnx->sysctls[5].procname = "size";
pl_info_lnx->sysctls[5].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[5].proc_handler = ath_sysctl_pktlog_size;
pl_info_lnx->sysctls[5].extra1 = scn;
pl_info_lnx->sysctls[6].procname = "options";
pl_info_lnx->sysctls[6].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[6].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[6].data = &pl_info_lnx->info.options;
pl_info_lnx->sysctls[6].maxlen = sizeof(pl_info_lnx->info.options);
pl_info_lnx->sysctls[7].procname = "sack_thr";
pl_info_lnx->sysctls[7].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[7].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[7].data = &pl_info_lnx->info.sack_thr;
pl_info_lnx->sysctls[7].maxlen = sizeof(pl_info_lnx->info.sack_thr);
pl_info_lnx->sysctls[8].procname = "tail_length";
pl_info_lnx->sysctls[8].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[8].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[8].data = &pl_info_lnx->info.tail_length;
pl_info_lnx->sysctls[8].maxlen = sizeof(pl_info_lnx->info.tail_length);
pl_info_lnx->sysctls[9].procname = "thruput_thresh";
pl_info_lnx->sysctls[9].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[9].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[9].data = &pl_info_lnx->info.thruput_thresh;
pl_info_lnx->sysctls[9].maxlen =
sizeof(pl_info_lnx->info.thruput_thresh);
pl_info_lnx->sysctls[10].procname = "phyerr_thresh";
pl_info_lnx->sysctls[10].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[10].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[10].data = &pl_info_lnx->info.phyerr_thresh;
pl_info_lnx->sysctls[10].maxlen =
sizeof(pl_info_lnx->info.phyerr_thresh);
pl_info_lnx->sysctls[11].procname = "per_thresh";
pl_info_lnx->sysctls[11].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[11].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[11].data = &pl_info_lnx->info.per_thresh;
pl_info_lnx->sysctls[11].maxlen = sizeof(pl_info_lnx->info.per_thresh);
pl_info_lnx->sysctls[12].procname = "trigger_interval";
pl_info_lnx->sysctls[12].mode = PKTLOG_PROCSYS_PERM;
pl_info_lnx->sysctls[12].proc_handler = proc_dointvec;
pl_info_lnx->sysctls[12].data = &pl_info_lnx->info.trigger_interval;
pl_info_lnx->sysctls[12].maxlen =
sizeof(pl_info_lnx->info.trigger_interval);
/* [13] is NULL terminator */
/* and register everything */
/* register_sysctl_table changed from 2.6.21 onwards */
pl_info_lnx->sysctl_header =
register_sysctl_table(pl_info_lnx->sysctls);
if (!pl_info_lnx->sysctl_header) {
printk("%s: failed to register sysctls!\n", proc_name);
return -EINVAL;
}
return 0;
}
/*
* Initialize logging for system or adapter
* Parameter scn should be NULL for system wide logging
*/
static int pktlog_attach(struct hif_opaque_softc *scn)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info_lnx *pl_info_lnx;
char *proc_name;
struct proc_dir_entry *proc_entry;
pl_dev = cds_get_pl_handle();
if (pl_dev != NULL) {
pl_info_lnx = kmalloc(sizeof(*pl_info_lnx), GFP_KERNEL);
if (pl_info_lnx == NULL) {
printk(PKTLOG_TAG "%s:allocation failed for pl_info\n",
__func__);
return -ENOMEM;
}
pl_dev->pl_info = &pl_info_lnx->info;
pl_dev->name = WLANDEV_BASENAME;
proc_name = pl_dev->name;
if (!pl_dev->pl_funcs)
pl_dev->pl_funcs = &ol_pl_funcs;
/*
* Valid for both direct attach and offload architecture
*/
pl_dev->pl_funcs->pktlog_init(scn);
} else {
return -EINVAL;
}
/*
* initialize log info
* might be good to move to pktlog_init
*/
/* pl_dev->tgt_pktlog_alloced = false; */
pl_dev->vendor_cmd_send = false;
pl_info_lnx->proc_entry = NULL;
pl_info_lnx->sysctl_header = NULL;
proc_entry = proc_create_data(proc_name, PKTLOG_PROC_PERM,
g_pktlog_pde, &pktlog_fops,
&pl_info_lnx->info);
if (proc_entry == NULL) {
printk(PKTLOG_TAG "%s: create_proc_entry failed for %s\n",
__func__, proc_name);
goto attach_fail1;
}
pl_info_lnx->proc_entry = proc_entry;
if (pktlog_sysctl_register(scn)) {
printk(PKTLOG_TAG "%s: sysctl register failed for %s\n",
__func__, proc_name);
goto attach_fail2;
}
return 0;
attach_fail2:
remove_proc_entry(proc_name, g_pktlog_pde);
attach_fail1:
if (pl_dev)
kfree(pl_dev->pl_info);
return -EINVAL;
}
static void pktlog_sysctl_unregister(struct ol_pktlog_dev_t *pl_dev)
{
struct ath_pktlog_info_lnx *pl_info_lnx;
if (!pl_dev) {
printk("%s: Invalid pktlog context\n", __func__);
ASSERT(0);
return;
}
pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
PL_INFO_LNX(g_pktlog_info);
if (pl_info_lnx->sysctl_header) {
unregister_sysctl_table(pl_info_lnx->sysctl_header);
pl_info_lnx->sysctl_header = NULL;
}
}
static void pktlog_detach(struct ol_txrx_pdev_t *handle)
{
struct ol_txrx_pdev_t *txrx_pdev;
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
txrx_pdev = handle;
if (!txrx_pdev) {
printk("%s: Invalid txrx_pdev context\n", __func__);
ASSERT(0);
return;
}
pl_dev = txrx_pdev->pl_dev;
if (!pl_dev) {
printk("%s: Invalid pktlog context\n", __func__);
ASSERT(0);
return;
}
pl_info = pl_dev->pl_info;
remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
pktlog_sysctl_unregister(pl_dev);
pktlog_cleanup(pl_info);
if (pl_info->buf) {
pktlog_release_buf(txrx_pdev);
pl_dev->tgt_pktlog_alloced = false;
}
if (pl_dev) {
kfree(pl_info);
pl_dev->pl_info = NULL;
}
}
static int pktlog_open(struct inode *i, struct file *f)
{
PKTLOG_MOD_INC_USE_COUNT;
return 0;
}
static int pktlog_release(struct inode *i, struct file *f)
{
PKTLOG_MOD_DEC_USE_COUNT;
return 0;
}
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
/**
* pktlog_read_proc_entry() - This function is used to read data from the
* proc entry into the readers buffer
* @buf: Readers buffer
* @nbytes: Number of bytes to read
* @ppos: Offset within the drivers buffer
* @pl_info: Packet log information pointer
* @read_complete: Boolean value indication whether read is complete
*
* This function is used to read data from the proc entry into the readers
* buffer. Its functionality is similar to 'pktlog_read' which does
* copy to user to the user space buffer
*
* Return: Number of bytes read from the buffer
*
*/
ssize_t
pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos,
struct ath_pktlog_info *pl_info, bool *read_complete)
{
size_t bufhdr_size;
size_t count = 0, ret_val = 0;
int rem_len;
int start_offset, end_offset;
int fold_offset, ppos_data, cur_rd_offset, cur_wr_offset;
struct ath_pktlog_buf *log_buf = pl_info->buf;
*read_complete = false;
if (log_buf == NULL) {
*read_complete = true;
return 0;
}
if (*ppos == 0 && pl_info->log_state) {
pl_info->saved_state = pl_info->log_state;
pl_info->log_state = 0;
}
bufhdr_size = sizeof(log_buf->bufhdr);
/* copy valid log entries from circular buffer into user space */
rem_len = nbytes;
count = 0;
if (*ppos < bufhdr_size) {
count = MIN((bufhdr_size - *ppos), rem_len);
qdf_mem_copy(buf, ((char *)&log_buf->bufhdr) + *ppos,
count);
rem_len -= count;
ret_val += count;
}
start_offset = log_buf->rd_offset;
cur_wr_offset = log_buf->wr_offset;
if ((rem_len == 0) || (start_offset < 0))
goto rd_done;
fold_offset = -1;
cur_rd_offset = start_offset;
/* Find the last offset and fold-offset if the buffer is folded */
do {
struct ath_pktlog_hdr *log_hdr;
int log_data_offset;
log_hdr = (struct ath_pktlog_hdr *) (log_buf->log_data +
cur_rd_offset);
log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
if ((fold_offset == -1)
&& ((pl_info->buf_size - log_data_offset)
<= log_hdr->size))
fold_offset = log_data_offset - 1;
PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size);
if ((fold_offset == -1) && (cur_rd_offset == 0)
&& (cur_rd_offset != cur_wr_offset))
fold_offset = log_data_offset + log_hdr->size - 1;
end_offset = log_data_offset + log_hdr->size - 1;
} while (cur_rd_offset != cur_wr_offset);
ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
if (fold_offset == -1) {
if (ppos_data > end_offset)
goto rd_done;
count = MIN(rem_len, (end_offset - ppos_data + 1));
qdf_mem_copy(buf + ret_val,
log_buf->log_data + ppos_data,
count);
ret_val += count;
rem_len -= count;
} else {
if (ppos_data <= fold_offset) {
count = MIN(rem_len, (fold_offset - ppos_data + 1));
qdf_mem_copy(buf + ret_val,
log_buf->log_data + ppos_data,
count);
ret_val += count;
rem_len -= count;
}
if (rem_len == 0)
goto rd_done;
ppos_data =
*ppos + ret_val - (bufhdr_size +
(fold_offset - start_offset + 1));
if (ppos_data <= end_offset) {
count = MIN(rem_len, (end_offset - ppos_data + 1));
qdf_mem_copy(buf + ret_val,
log_buf->log_data + ppos_data,
count);
ret_val += count;
rem_len -= count;
}
}
rd_done:
if ((ret_val < nbytes) && pl_info->saved_state) {
pl_info->log_state = pl_info->saved_state;
pl_info->saved_state = 0;
}
*ppos += ret_val;
if (ret_val == 0) {
PKTLOG_LOCK(pl_info);
/* Write pointer might have been updated during the read.
* So, if some data is written into, lets not reset the pointers
* We can continue to read from the offset position
*/
if (cur_wr_offset != log_buf->wr_offset) {
*read_complete = false;
} else {
pl_info->buf->rd_offset = -1;
pl_info->buf->wr_offset = 0;
pl_info->buf->bytes_written = 0;
pl_info->buf->offset = PKTLOG_READ_OFFSET;
*read_complete = true;
}
PKTLOG_UNLOCK(pl_info);
}
return ret_val;
}
static ssize_t
pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
{
size_t bufhdr_size;
size_t count = 0, ret_val = 0;
int rem_len;
int start_offset, end_offset;
int fold_offset, ppos_data, cur_rd_offset;
struct ath_pktlog_info *pl_info;
struct ath_pktlog_buf *log_buf;
pl_info = (struct ath_pktlog_info *)
PDE_DATA(file->f_path.dentry->d_inode);
if (!pl_info)
return 0;
log_buf = pl_info->buf;
if (log_buf == NULL)
return 0;
if (pl_info->log_state) {
/* Read is not allowed when write is going on
* When issuing cat command, ensure to send
* pktlog disable command first.
*/
return -EINVAL;
}
if (*ppos == 0 && pl_info->log_state) {
pl_info->saved_state = pl_info->log_state;
pl_info->log_state = 0;
}
bufhdr_size = sizeof(log_buf->bufhdr);
/* copy valid log entries from circular buffer into user space */
rem_len = nbytes;
count = 0;
if (*ppos < bufhdr_size) {
count = QDF_MIN((bufhdr_size - *ppos), rem_len);
if (copy_to_user(buf, ((char *)&log_buf->bufhdr) + *ppos,
count))
return -EFAULT;
rem_len -= count;
ret_val += count;
}
start_offset = log_buf->rd_offset;
if ((rem_len == 0) || (start_offset < 0))
goto rd_done;
fold_offset = -1;
cur_rd_offset = start_offset;
/* Find the last offset and fold-offset if the buffer is folded */
do {
struct ath_pktlog_hdr *log_hdr;
int log_data_offset;
log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data +
cur_rd_offset);
log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
if ((fold_offset == -1)
&& ((pl_info->buf_size - log_data_offset)
<= log_hdr->size))
fold_offset = log_data_offset - 1;
PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size);
if ((fold_offset == -1) && (cur_rd_offset == 0)
&& (cur_rd_offset != log_buf->wr_offset))
fold_offset = log_data_offset + log_hdr->size - 1;
end_offset = log_data_offset + log_hdr->size - 1;
} while (cur_rd_offset != log_buf->wr_offset);
ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
if (fold_offset == -1) {
if (ppos_data > end_offset)
goto rd_done;
count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
if (copy_to_user(buf + ret_val,
log_buf->log_data + ppos_data, count))
return -EFAULT;
ret_val += count;
rem_len -= count;
} else {
if (ppos_data <= fold_offset) {
count = QDF_MIN(rem_len, (fold_offset - ppos_data + 1));
if (copy_to_user(buf + ret_val,
log_buf->log_data + ppos_data, count))
return -EFAULT;
ret_val += count;
rem_len -= count;
}
if (rem_len == 0)
goto rd_done;
ppos_data =
*ppos + ret_val - (bufhdr_size +
(fold_offset - start_offset + 1));
if (ppos_data <= end_offset) {
count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
if (copy_to_user(buf + ret_val,
log_buf->log_data + ppos_data, count))
return -EFAULT;
ret_val += count;
rem_len -= count;
}
}
rd_done:
if ((ret_val < nbytes) && pl_info->saved_state) {
pl_info->log_state = pl_info->saved_state;
pl_info->saved_state = 0;
}
*ppos += ret_val;
return ret_val;
}
#ifndef VMALLOC_VMADDR
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#endif
/* vma operations for mapping vmalloced area to user space */
static void pktlog_vopen(struct vm_area_struct *vma)
{
PKTLOG_MOD_INC_USE_COUNT;
}
static void pktlog_vclose(struct vm_area_struct *vma)
{
PKTLOG_MOD_DEC_USE_COUNT;
}
static int pktlog_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
unsigned long address = (unsigned long)vmf->virtual_address;
if (address == 0UL)
return VM_FAULT_NOPAGE;
if (vmf->pgoff > vma->vm_end)
return VM_FAULT_SIGBUS;
get_page(virt_to_page((void *)address));
vmf->page = virt_to_page((void *)address);
return 0;
}
static struct vm_operations_struct pktlog_vmops = {
open: pktlog_vopen,
close:pktlog_vclose,
fault:pktlog_fault,
};
static int pktlog_mmap(struct file *file, struct vm_area_struct *vma)
{
struct ath_pktlog_info *pl_info;
pl_info = (struct ath_pktlog_info *)
PDE_DATA(file->f_path.dentry->d_inode);
if (vma->vm_pgoff != 0) {
/* Entire buffer should be mapped */
return -EINVAL;
}
if (!pl_info->buf) {
printk(PKTLOG_TAG "%s: Log buffer unavailable\n", __func__);
return -ENOMEM;
}
vma->vm_flags |= VM_LOCKED;
vma->vm_ops = &pktlog_vmops;
pktlog_vopen(vma);
return 0;
}
int pktlogmod_init(void *context)
{
int ret;
/* create the proc directory entry */
g_pktlog_pde = proc_mkdir(PKTLOG_PROC_DIR, NULL);
if (g_pktlog_pde == NULL) {
printk(PKTLOG_TAG "%s: proc_mkdir failed\n", __func__);
return -EPERM;
}
/* Attach packet log */
ret = pktlog_attach((struct hif_opaque_softc *)context);
if (ret)
goto attach_fail;
return ret;
attach_fail:
remove_proc_entry(PKTLOG_PROC_DIR, NULL);
g_pktlog_pde = NULL;
return ret;
}
void pktlogmod_exit(struct ol_txrx_pdev_t *handle)
{
struct ol_pktlog_dev_t *pl_dev;
pl_dev = ol_get_pl_handle(handle);
if (!pl_dev || g_pktlog_pde == NULL)
return;
pktlog_detach(handle);
/*
* pdev kill needs to be implemented
*/
remove_proc_entry(PKTLOG_PROC_DIR, NULL);
}
#endif

715
utils/pktlog/pktlog_ac.c Normal file
View File

@@ -0,0 +1,715 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
*
* 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 "qdf_mem.h"
#include "athdefs.h"
#include "pktlog_ac_i.h"
#include "cds_api.h"
#include "wma_types.h"
#include "htc.h"
wdi_event_subscribe PKTLOG_TX_SUBSCRIBER;
wdi_event_subscribe PKTLOG_RX_SUBSCRIBER;
wdi_event_subscribe PKTLOG_RX_REMOTE_SUBSCRIBER;
wdi_event_subscribe PKTLOG_RCFIND_SUBSCRIBER;
wdi_event_subscribe PKTLOG_RCUPDATE_SUBSCRIBER;
wdi_event_subscribe PKTLOG_SW_EVENT_SUBSCRIBER;
struct ol_pl_arch_dep_funcs ol_pl_funcs = {
.pktlog_init = pktlog_init,
.pktlog_enable = pktlog_enable,
.pktlog_setsize = pktlog_setsize,
.pktlog_disable = pktlog_disable, /* valid for f/w disable */
};
struct ol_pktlog_dev_t ol_pl_dev = {
.pl_funcs = &ol_pl_funcs,
};
void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle,
struct hif_opaque_softc *scn)
{
ol_pl_dev.scn = (ol_ath_generic_softc_handle) scn;
*pl_handle = &ol_pl_dev;
}
static A_STATUS pktlog_wma_post_msg(WMI_PKTLOG_EVENT event_types,
WMI_CMD_ID cmd_id, bool ini_triggered,
uint8_t user_triggered)
{
struct scheduler_msg msg = { 0 };
QDF_STATUS status;
struct ath_pktlog_wmi_params *param;
param = qdf_mem_malloc(sizeof(struct ath_pktlog_wmi_params));
if (!param)
return A_NO_MEMORY;
param->cmd_id = cmd_id;
param->pktlog_event = event_types;
param->ini_triggered = ini_triggered;
param->user_triggered = user_triggered;
msg.type = WMA_PKTLOG_ENABLE_REQ;
msg.bodyptr = param;
msg.bodyval = 0;
status = scheduler_post_msg(QDF_MODULE_ID_WMA, &msg);
if (status != QDF_STATUS_SUCCESS) {
qdf_mem_free(param);
return A_ERROR;
}
return A_OK;
}
static inline A_STATUS
pktlog_enable_tgt(struct hif_opaque_softc *_scn, uint32_t log_state,
bool ini_triggered, uint8_t user_triggered)
{
uint32_t types = 0;
if (log_state & ATH_PKTLOG_TX)
types |= WMI_PKTLOG_EVENT_TX;
if (log_state & ATH_PKTLOG_RX)
types |= WMI_PKTLOG_EVENT_RX;
if (log_state & ATH_PKTLOG_RCFIND)
types |= WMI_PKTLOG_EVENT_RCF;
if (log_state & ATH_PKTLOG_RCUPDATE)
types |= WMI_PKTLOG_EVENT_RCU;
if (log_state & ATH_PKTLOG_SW_EVENT)
types |= WMI_PKTLOG_EVENT_SW;
return pktlog_wma_post_msg(types, WMI_PDEV_PKTLOG_ENABLE_CMDID,
ini_triggered, user_triggered);
}
static inline A_STATUS
wdi_pktlog_subscribe(struct ol_txrx_pdev_t *txrx_pdev, int32_t log_state)
{
if (!txrx_pdev) {
printk("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
if (log_state & ATH_PKTLOG_TX) {
if (wdi_event_sub(txrx_pdev,
&PKTLOG_TX_SUBSCRIBER, WDI_EVENT_TX_STATUS)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RX) {
if (wdi_event_sub(txrx_pdev,
&PKTLOG_RX_SUBSCRIBER, WDI_EVENT_RX_DESC)) {
return A_ERROR;
}
if (wdi_event_sub(txrx_pdev,
&PKTLOG_RX_REMOTE_SUBSCRIBER,
WDI_EVENT_RX_DESC_REMOTE)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RCFIND) {
if (wdi_event_sub(txrx_pdev,
&PKTLOG_RCFIND_SUBSCRIBER,
WDI_EVENT_RATE_FIND)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RCUPDATE) {
if (wdi_event_sub(txrx_pdev,
&PKTLOG_RCUPDATE_SUBSCRIBER,
WDI_EVENT_RATE_UPDATE)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_SW_EVENT) {
if (wdi_event_sub(txrx_pdev,
&PKTLOG_SW_EVENT_SUBSCRIBER,
WDI_EVENT_SW_EVENT)) {
return A_ERROR;
}
}
return A_OK;
}
void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data)
{
switch (event) {
case WDI_EVENT_TX_STATUS:
{
/*
* process TX message
*/
if (process_tx_info(pdev, log_data)) {
printk("Unable to process TX info\n");
return;
}
break;
}
case WDI_EVENT_RX_DESC:
{
/*
* process RX message for local frames
*/
if (process_rx_info(pdev, log_data)) {
printk("Unable to process RX info\n");
return;
}
break;
}
case WDI_EVENT_RX_DESC_REMOTE:
{
/*
* process RX message for remote frames
*/
if (process_rx_info_remote(pdev, log_data)) {
printk("Unable to process RX info\n");
return;
}
break;
}
case WDI_EVENT_RATE_FIND:
{
/*
* process RATE_FIND message
*/
if (process_rate_find(pdev, log_data)) {
printk("Unable to process RC_FIND info\n");
return;
}
break;
}
case WDI_EVENT_RATE_UPDATE:
{
/*
* process RATE_UPDATE message
*/
if (process_rate_update(pdev, log_data)) {
printk("Unable to process RC_UPDATE\n");
return;
}
break;
}
case WDI_EVENT_SW_EVENT:
{
/*
* process SW EVENT message
*/
if (process_sw_event(pdev, log_data)) {
printk("Unable to process SW_EVENT\n");
return;
}
break;
}
default:
break;
}
}
A_STATUS
wdi_pktlog_unsubscribe(struct ol_txrx_pdev_t *txrx_pdev, uint32_t log_state)
{
if (log_state & ATH_PKTLOG_TX) {
if (wdi_event_unsub(txrx_pdev,
&PKTLOG_TX_SUBSCRIBER,
WDI_EVENT_TX_STATUS)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RX) {
if (wdi_event_unsub(txrx_pdev,
&PKTLOG_RX_SUBSCRIBER, WDI_EVENT_RX_DESC)) {
return A_ERROR;
}
if (wdi_event_unsub(txrx_pdev,
&PKTLOG_RX_REMOTE_SUBSCRIBER,
WDI_EVENT_RX_DESC_REMOTE)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RCFIND) {
if (wdi_event_unsub(txrx_pdev,
&PKTLOG_RCFIND_SUBSCRIBER,
WDI_EVENT_RATE_FIND)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RCUPDATE) {
if (wdi_event_unsub(txrx_pdev,
&PKTLOG_RCUPDATE_SUBSCRIBER,
WDI_EVENT_RATE_UPDATE)) {
return A_ERROR;
}
}
if (log_state & ATH_PKTLOG_RCUPDATE) {
if (wdi_event_unsub(txrx_pdev,
&PKTLOG_SW_EVENT_SUBSCRIBER,
WDI_EVENT_SW_EVENT)) {
return A_ERROR;
}
}
return A_OK;
}
int pktlog_disable(struct hif_opaque_softc *scn)
{
struct ol_txrx_pdev_t *txrx_pdev =
cds_get_context(QDF_MODULE_ID_TXRX);
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
if (txrx_pdev == NULL ||
txrx_pdev->pl_dev == NULL ||
txrx_pdev->pl_dev->pl_info == NULL)
return -EFAULT;
pl_dev = txrx_pdev->pl_dev;
pl_info = pl_dev->pl_info;
if (pktlog_wma_post_msg(0, WMI_PDEV_PKTLOG_DISABLE_CMDID, 0, 0)) {
printk("Failed to disable pktlog in target\n");
return -EINVAL;
}
if (pl_dev->is_pktlog_cb_subscribed &&
wdi_pktlog_unsubscribe(txrx_pdev, pl_info->log_state)) {
printk("Cannot unsubscribe pktlog from the WDI\n");
return -EINVAL;
}
pl_dev->is_pktlog_cb_subscribed = false;
return 0;
}
void pktlog_init(struct hif_opaque_softc *scn)
{
struct ath_pktlog_info *pl_info;
ol_txrx_pdev_handle pdev_txrx_handle;
pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX);
if (pdev_txrx_handle == NULL ||
pdev_txrx_handle->pl_dev == NULL ||
pdev_txrx_handle->pl_dev->pl_info == NULL)
return;
pl_info = pdev_txrx_handle->pl_dev->pl_info;
OS_MEMZERO(pl_info, sizeof(*pl_info));
PKTLOG_LOCK_INIT(pl_info);
pl_info->buf_size = PKTLOG_DEFAULT_BUFSIZE;
pl_info->buf = NULL;
pl_info->log_state = 0;
pl_info->sack_thr = PKTLOG_DEFAULT_SACK_THR;
pl_info->tail_length = PKTLOG_DEFAULT_TAIL_LENGTH;
pl_info->thruput_thresh = PKTLOG_DEFAULT_THRUPUT_THRESH;
pl_info->per_thresh = PKTLOG_DEFAULT_PER_THRESH;
pl_info->phyerr_thresh = PKTLOG_DEFAULT_PHYERR_THRESH;
pl_info->trigger_interval = PKTLOG_DEFAULT_TRIGGER_INTERVAL;
pl_info->pktlen = 0;
pl_info->start_time_thruput = 0;
pl_info->start_time_per = 0;
pdev_txrx_handle->pl_dev->vendor_cmd_send = false;
PKTLOG_TX_SUBSCRIBER.callback = pktlog_callback;
PKTLOG_RX_SUBSCRIBER.callback = pktlog_callback;
PKTLOG_RX_REMOTE_SUBSCRIBER.callback = pktlog_callback;
PKTLOG_RCFIND_SUBSCRIBER.callback = pktlog_callback;
PKTLOG_RCUPDATE_SUBSCRIBER.callback = pktlog_callback;
PKTLOG_SW_EVENT_SUBSCRIBER.callback = pktlog_callback;
}
int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini_triggered, uint8_t user_triggered,
uint32_t is_iwpriv_command)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
struct ol_txrx_pdev_t *txrx_pdev;
int error;
if (!scn) {
printk("%s: Invalid scn context\n", __func__);
ASSERT(0);
return -EINVAL;
}
txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (!txrx_pdev) {
printk("%s: Invalid txrx_pdev context\n", __func__);
ASSERT(0);
return -EINVAL;
}
pl_dev = txrx_pdev->pl_dev;
if (!pl_dev) {
printk("%s: Invalid pktlog context\n", __func__);
ASSERT(0);
return -EINVAL;
}
pl_info = pl_dev->pl_info;
if (!pl_info)
return 0;
/* is_iwpriv_command : 0 indicates its a vendor command
* log_state: 0 indicates pktlog disable command
* vendor_cmd_send flag; false means no vendor pktlog enable
* command was sent previously
*/
if (is_iwpriv_command == 0 && log_state == 0 &&
pl_dev->vendor_cmd_send == false)
return 0;
if (!pl_dev->tgt_pktlog_alloced) {
if (pl_info->buf == NULL) {
error = pktlog_alloc_buf(scn);
if (error != 0)
return error;
if (!pl_info->buf) {
printk("%s: pktlog buf alloc failed\n",
__func__);
ASSERT(0);
return -ENOMEM;
}
}
pl_info->buf->bufhdr.version = CUR_PKTLOG_VER;
pl_info->buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM;
pl_info->buf->wr_offset = 0;
pl_info->buf->rd_offset = -1;
/* These below variables are used by per packet stats*/
pl_info->buf->bytes_written = 0;
pl_info->buf->msg_index = 1;
pl_info->buf->offset = PKTLOG_READ_OFFSET;
pl_info->start_time_thruput = os_get_timestamp();
pl_info->start_time_per = pl_info->start_time_thruput;
pl_dev->tgt_pktlog_alloced = true;
}
if (log_state != 0) {
/* WDI subscribe */
if ((!pl_dev->is_pktlog_cb_subscribed) &&
wdi_pktlog_subscribe(txrx_pdev, log_state)) {
printk("Unable to subscribe to the WDI %s\n", __func__);
return -EINVAL;
}
pl_dev->is_pktlog_cb_subscribed = true;
/* WMI command to enable pktlog on the firmware */
if (pktlog_enable_tgt(scn, log_state, ini_triggered,
user_triggered)) {
printk("Device cannot be enabled, %s\n", __func__);
return -EINVAL;
}
if (is_iwpriv_command == 0)
pl_dev->vendor_cmd_send = true;
} else {
pl_dev->pl_funcs->pktlog_disable(scn);
if (is_iwpriv_command == 0)
pl_dev->vendor_cmd_send = false;
}
pl_info->log_state = log_state;
return 0;
}
int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size)
{
ol_txrx_pdev_handle pdev_txrx_handle =
cds_get_context(QDF_MODULE_ID_TXRX);
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
if (pdev_txrx_handle == NULL ||
pdev_txrx_handle->pl_dev == NULL ||
pdev_txrx_handle->pl_dev->pl_info == NULL)
return -EFAULT;
pl_dev = pdev_txrx_handle->pl_dev;
pl_info = pl_dev->pl_info;
if (size < 0)
return -EINVAL;
if (size == pl_info->buf_size) {
qdf_print("%s: Pktlog Buff Size is already of same size.",
__func__);
return 0;
}
if (pl_info->log_state) {
qdf_print("%s: Logging should be disabled before changing"
"buffer size.", __func__);
return -EINVAL;
}
if (pl_info->buf != NULL) {
if (pl_dev->is_pktlog_cb_subscribed &&
wdi_pktlog_unsubscribe(pdev_txrx_handle,
pl_info->log_state)) {
printk("Cannot unsubscribe pktlog from the WDI\n");
return -EFAULT;
}
pktlog_release_buf(pdev_txrx_handle);
pl_dev->is_pktlog_cb_subscribed = false;
pl_dev->tgt_pktlog_alloced = false;
}
if (size != 0) {
qdf_print("%s: New Pktlog Buff Size is %d\n", __func__, size);
pl_info->buf_size = size;
}
return 0;
}
/**
* pktlog_process_fw_msg() - process packetlog message
* @buff: buffer
*
* Return: None
*/
void pktlog_process_fw_msg(uint32_t *buff)
{
uint32_t *pl_hdr;
uint32_t log_type;
struct ol_txrx_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (!txrx_pdev) {
qdf_print("%s: txrx_pdev is NULL", __func__);
return;
}
pl_hdr = buff;
log_type =
(*(pl_hdr + 1) & ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
if ((log_type == PKTLOG_TYPE_TX_CTRL)
|| (log_type == PKTLOG_TYPE_TX_STAT)
|| (log_type == PKTLOG_TYPE_TX_MSDU_ID)
|| (log_type == PKTLOG_TYPE_TX_FRM_HDR)
|| (log_type == PKTLOG_TYPE_TX_VIRT_ADDR))
wdi_event_handler(WDI_EVENT_TX_STATUS,
txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_RC_FIND)
wdi_event_handler(WDI_EVENT_RATE_FIND,
txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_RC_UPDATE)
wdi_event_handler(WDI_EVENT_RATE_UPDATE,
txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_RX_STAT)
wdi_event_handler(WDI_EVENT_RX_DESC,
txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_SW_EVENT)
wdi_event_handler(WDI_EVENT_SW_EVENT,
txrx_pdev, pl_hdr);
}
#if defined(QCA_WIFI_3_0_ADRASTEA)
/**
* pktlog_t2h_msg_handler() - Target to host message handler
* @context: pdev context
* @pkt: HTC packet
*
* Return: None
*/
static void pktlog_t2h_msg_handler(void *context, HTC_PACKET *pkt)
{
struct ol_pktlog_dev_t *pdev = (struct ol_pktlog_dev_t *)context;
qdf_nbuf_t pktlog_t2h_msg = (qdf_nbuf_t) pkt->pPktContext;
uint32_t *msg_word;
/* check for successful message reception */
if (pkt->Status != A_OK) {
if (pkt->Status != A_ECANCELED)
pdev->htc_err_cnt++;
qdf_nbuf_free(pktlog_t2h_msg);
return;
}
/* confirm alignment */
qdf_assert((((unsigned long)qdf_nbuf_data(pktlog_t2h_msg)) & 0x3) == 0);
msg_word = (uint32_t *) qdf_nbuf_data(pktlog_t2h_msg);
pktlog_process_fw_msg(msg_word);
qdf_nbuf_free(pktlog_t2h_msg);
}
/**
* pktlog_tx_resume_handler() - resume callback
* @context: pdev context
*
* Return: None
*/
static void pktlog_tx_resume_handler(void *context)
{
qdf_print("%s: Not expected", __func__);
qdf_assert(0);
}
/**
* pktlog_h2t_send_complete() - send complete indication
* @context: pdev context
* @htc_pkt: HTC packet
*
* Return: None
*/
static void pktlog_h2t_send_complete(void *context, HTC_PACKET *htc_pkt)
{
qdf_print("%s: Not expected", __func__);
qdf_assert(0);
}
/**
* pktlog_h2t_full() - queue full indication
* @context: pdev context
* @pkt: HTC packet
*
* Return: HTC action
*/
static HTC_SEND_FULL_ACTION pktlog_h2t_full(void *context, HTC_PACKET *pkt)
{
return HTC_SEND_FULL_KEEP;
}
/**
* pktlog_htc_connect_service() - create new endpoint for packetlog
* @pdev - pktlog pdev
*
* Return: 0 for success/failure
*/
static int pktlog_htc_connect_service(struct ol_pktlog_dev_t *pdev)
{
HTC_SERVICE_CONNECT_REQ connect;
HTC_SERVICE_CONNECT_RESP response;
A_STATUS status;
qdf_mem_set(&connect, sizeof(connect), 0);
qdf_mem_set(&response, sizeof(response), 0);
connect.pMetaData = NULL;
connect.MetaDataLength = 0;
connect.EpCallbacks.pContext = pdev;
connect.EpCallbacks.EpTxComplete = pktlog_h2t_send_complete;
connect.EpCallbacks.EpTxCompleteMultiple = NULL;
connect.EpCallbacks.EpRecv = pktlog_t2h_msg_handler;
connect.EpCallbacks.ep_resume_tx_queue = pktlog_tx_resume_handler;
/* rx buffers currently are provided by HIF, not by EpRecvRefill */
connect.EpCallbacks.EpRecvRefill = NULL;
connect.EpCallbacks.RecvRefillWaterMark = 1;
/* N/A, fill is done by HIF */
connect.EpCallbacks.EpSendFull = pktlog_h2t_full;
/*
* Specify how deep to let a queue get before htc_send_pkt will
* call the EpSendFull function due to excessive send queue depth.
*/
connect.MaxSendQueueDepth = PKTLOG_MAX_SEND_QUEUE_DEPTH;
/* disable flow control for HTT data message service */
connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
/* connect to control service */
connect.service_id = PACKET_LOG_SVC;
status = htc_connect_service(pdev->htc_pdev, &connect, &response);
if (status != A_OK) {
pdev->mt_pktlog_enabled = false;
return -EIO; /* failure */
}
pdev->htc_endpoint = response.Endpoint;
pdev->mt_pktlog_enabled = true;
return 0; /* success */
}
/**
* pktlog_htc_attach() - attach pktlog HTC service
*
* Return: 0 for success/failure
*/
int pktlog_htc_attach(void)
{
struct ol_txrx_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
struct ol_pktlog_dev_t *pdev = NULL;
void *htc_pdev = cds_get_context(QDF_MODULE_ID_HTC);
if ((!txrx_pdev) || (!txrx_pdev->pl_dev) || (!htc_pdev))
return -EINVAL;
pdev = txrx_pdev->pl_dev;
pdev->htc_pdev = htc_pdev;
return pktlog_htc_connect_service(pdev);
}
#else
int pktlog_htc_attach(void)
{
struct ol_txrx_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX);
struct ol_pktlog_dev_t *pdev = NULL;
if (!txrx_pdev)
return -EINVAL;
pdev = txrx_pdev->pl_dev;
pdev->mt_pktlog_enabled = false;
return 0;
}
#endif
#endif /* REMOVE_PKT_LOG */

View File

@@ -0,0 +1,871 @@
/*
* Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
*
* 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"
#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
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) {
printk("Invalid parg in %s\n", __func__);
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) {
printk("Invalid log_buf in %s\n", __func__);
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;
#ifdef HELIUMPLUS
log_hdr->type_specific_data = plarg->type_specific_data;
#endif
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 ol_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;
#ifdef HELIUMPLUS
plarg.type_specific_data = pl_hdr->type_specific_data;
#endif
if (flags & PHFLAGS_INTERRUPT_CONTEXT) {
/*
* We are already in interupt 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;
}
static struct txctl_frm_hdr frm_hdr;
#ifndef HELIUMPLUS
static void process_ieee_hdr(void *data)
{
uint8_t dir;
struct ieee80211_frame *wh = (struct ieee80211_frame *)(data);
frm_hdr.framectrl = *(uint16_t *) (wh->i_fc);
frm_hdr.seqctrl = *(uint16_t *) (wh->i_seq);
dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK);
if (dir == IEEE80211_FC1_DIR_TODS) {
frm_hdr.bssid_tail =
(wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr1
[IEEE80211_ADDR_LEN
- 1]);
frm_hdr.sa_tail =
(wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr2
[IEEE80211_ADDR_LEN
- 1]);
frm_hdr.da_tail =
(wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr3
[IEEE80211_ADDR_LEN
- 1]);
} else if (dir == IEEE80211_FC1_DIR_FROMDS) {
frm_hdr.bssid_tail =
(wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr2
[IEEE80211_ADDR_LEN
- 1]);
frm_hdr.sa_tail =
(wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr3
[IEEE80211_ADDR_LEN
- 1]);
frm_hdr.da_tail =
(wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr1
[IEEE80211_ADDR_LEN
- 1]);
} else {
frm_hdr.bssid_tail =
(wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr3
[IEEE80211_ADDR_LEN
- 1]);
frm_hdr.sa_tail =
(wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr2
[IEEE80211_ADDR_LEN
- 1]);
frm_hdr.da_tail =
(wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
i_addr1
[IEEE80211_ADDR_LEN
- 1]);
}
}
/**
* fill_ieee80211_hdr_data() - fill ieee802.11 data header
* @txrx_pdev: txrx pdev
* @pl_msdu_info: msdu info
* @data: data received from event
*
* Return: none
*/
static void
fill_ieee80211_hdr_data(struct ol_txrx_pdev_t *txrx_pdev,
struct ath_pktlog_msdu_info *pl_msdu_info, void *data)
{
uint32_t i;
uint32_t *htt_tx_desc;
struct ol_tx_desc_t *tx_desc;
uint8_t msdu_id_offset = MSDU_ID_INFO_ID_OFFSET;
uint16_t tx_desc_id;
uint32_t *msdu_id_info = (uint32_t *)
((void *)data + sizeof(struct ath_pktlog_hdr));
uint32_t *msdu_id = (uint32_t *) ((char *)msdu_id_info +
msdu_id_offset);
uint8_t *addr, *vap_addr;
uint8_t vdev_id;
qdf_nbuf_t netbuf;
uint32_t len;
pl_msdu_info->num_msdu = *msdu_id_info;
pl_msdu_info->priv_size = sizeof(uint32_t) *
pl_msdu_info->num_msdu + sizeof(uint32_t);
for (i = 0; i < pl_msdu_info->num_msdu; i++) {
/*
* Handle big endianness
* Increment msdu_id once after retrieving
* lower 16 bits and uppper 16 bits
*/
if (!(i % 2)) {
tx_desc_id = ((*msdu_id & TX_DESC_ID_LOW_MASK)
>> TX_DESC_ID_LOW_SHIFT);
} else {
tx_desc_id = ((*msdu_id & TX_DESC_ID_HIGH_MASK)
>> TX_DESC_ID_HIGH_SHIFT);
msdu_id += 1;
}
tx_desc = ol_tx_desc_find(txrx_pdev, tx_desc_id);
qdf_assert(tx_desc);
netbuf = tx_desc->netbuf;
htt_tx_desc = (uint32_t *) tx_desc->htt_tx_desc;
qdf_assert(htt_tx_desc);
qdf_nbuf_peek_header(netbuf, &addr, &len);
if (len < (2 * IEEE80211_ADDR_LEN)) {
qdf_print("TX frame does not have a valid address\n");
return;
}
/* Adding header information for the TX data frames */
vdev_id = (uint8_t) (*(htt_tx_desc +
HTT_TX_VDEV_ID_WORD) >>
HTT_TX_VDEV_ID_SHIFT) &
HTT_TX_VDEV_ID_MASK;
vap_addr = wma_get_vdev_address_by_vdev_id(vdev_id);
frm_hdr.da_tail = (addr[IEEE80211_ADDR_LEN - 2] << 8) |
(addr[IEEE80211_ADDR_LEN - 1]);
frm_hdr.sa_tail =
(addr[2 * IEEE80211_ADDR_LEN - 2] << 8) |
(addr[2 * IEEE80211_ADDR_LEN - 1]);
if (vap_addr) {
frm_hdr.bssid_tail =
(vap_addr[IEEE80211_ADDR_LEN - 2] << 8) |
(vap_addr[IEEE80211_ADDR_LEN - 1]);
} else {
frm_hdr.bssid_tail = 0x0000;
}
pl_msdu_info->priv.msdu_len[i] = *(htt_tx_desc +
HTT_TX_MSDU_LEN_DWORD)
& HTT_TX_MSDU_LEN_MASK;
/*
* Add more information per MSDU
* e.g., protocol information
*/
}
}
#endif
#ifdef HELIUMPLUS
A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data)
{
/*
* Must include to process different types
* TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR
*/
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_info *pl_info;
uint32_t *pl_tgt_hdr;
if (!txrx_pdev) {
printk("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
qdf_assert(txrx_pdev->pl_dev);
qdf_assert(data);
pl_dev = txrx_pdev->pl_dev;
pl_tgt_hdr = (uint32_t *) data;
/*
* Makes the short words (16 bits) portable b/w little endian
* and big endian
*/
pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
ATH_PKTLOG_HDR_FLAGS_MASK) >>
ATH_PKTLOG_HDR_FLAGS_SHIFT;
pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
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.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
ATH_PKTLOG_HDR_MAC_ID_MASK) >>
ATH_PKTLOG_HDR_MAC_ID_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);
pl_hdr.type_specific_data =
*(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET);
pl_info = pl_dev->pl_info;
if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) {
size_t log_size = sizeof(frm_hdr) + pl_hdr.size;
void *txdesc_hdr_ctl = (void *)
pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr);
qdf_assert(txdesc_hdr_ctl);
qdf_assert(pl_hdr.size < (370 * sizeof(u_int32_t)));
qdf_mem_copy(txdesc_hdr_ctl, &frm_hdr, sizeof(frm_hdr));
qdf_mem_copy((char *)txdesc_hdr_ctl + sizeof(frm_hdr),
((void *)data +
sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
pl_hdr.size = log_size;
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
txdesc_hdr_ctl);
}
if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) {
struct ath_pktlog_tx_status txstat_log;
size_t log_size = pl_hdr.size;
txstat_log.ds_status = (void *)
pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_assert(txstat_log.ds_status);
qdf_mem_copy(txstat_log.ds_status,
((void *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
txstat_log.ds_status);
}
return A_OK;
}
#else
A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data)
{
/*
* Must include to process different types
* TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR
*/
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_info *pl_info;
uint32_t *pl_tgt_hdr;
if (!txrx_pdev) {
qdf_print("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
qdf_assert(txrx_pdev->pl_dev);
qdf_assert(data);
pl_dev = txrx_pdev->pl_dev;
pl_tgt_hdr = (uint32_t *) data;
/*
* Makes the short words (16 bits) portable b/w little endian
* and big endian
*/
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);
pl_info = pl_dev->pl_info;
if (pl_hdr.log_type == PKTLOG_TYPE_TX_FRM_HDR) {
/* Valid only for the TX CTL */
process_ieee_hdr(data + sizeof(pl_hdr));
}
if (pl_hdr.log_type == PKTLOG_TYPE_TX_VIRT_ADDR) {
A_UINT32 desc_id = (A_UINT32)
*((A_UINT32 *) (data + sizeof(pl_hdr)));
A_UINT32 vdev_id = desc_id;
/* if the pkt log msg is for the bcn frame the vdev id
* is piggybacked in desc_id and the MSB of the desc ID
* would be set to FF
*/
#define BCN_DESC_ID 0xFF
if ((desc_id >> 24) == BCN_DESC_ID) {
void *data;
A_UINT32 buf_size;
vdev_id &= 0x00FFFFFF;
data = wma_get_beacon_buffer_by_vdev_id(vdev_id,
&buf_size);
if (data) {
process_ieee_hdr(data);
qdf_mem_free(data);
}
} else {
/*
* TODO: get the hdr content for mgmt frames from
* Tx mgmt desc pool
*/
}
}
if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) {
struct ath_pktlog_txctl txctl_log;
size_t log_size = sizeof(txctl_log.priv);
txctl_log.txdesc_hdr_ctl = (void *)pktlog_getbuf(pl_dev,
pl_info,
log_size,
&pl_hdr);
if (!txctl_log.txdesc_hdr_ctl) {
printk
("failed to get buf for txctl_log.txdesc_hdr_ctl\n");
return A_ERROR;
}
/*
* frm hdr is currently Valid only for local frames
* Add capability to include the fmr hdr for remote frames
*/
txctl_log.priv.frm_hdr = frm_hdr;
qdf_assert(txctl_log.priv.txdesc_ctl);
qdf_mem_copy((void *)&txctl_log.priv.txdesc_ctl,
((void *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
qdf_assert(txctl_log.txdesc_hdr_ctl);
qdf_mem_copy(txctl_log.txdesc_hdr_ctl, &txctl_log.priv,
sizeof(txctl_log.priv));
pl_hdr.size = log_size;
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
txctl_log.txdesc_hdr_ctl);
/* Add Protocol information and HT specific information */
}
if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) {
struct ath_pktlog_tx_status txstat_log;
size_t log_size = pl_hdr.size;
txstat_log.ds_status = (void *)
pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr);
qdf_assert(txstat_log.ds_status);
qdf_mem_copy(txstat_log.ds_status,
((void *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
txstat_log.ds_status);
}
if (pl_hdr.log_type == PKTLOG_TYPE_TX_MSDU_ID) {
struct ath_pktlog_msdu_info pl_msdu_info;
size_t log_size;
qdf_mem_set(&pl_msdu_info, sizeof(pl_msdu_info), 0);
log_size = sizeof(pl_msdu_info.priv);
if (pl_dev->mt_pktlog_enabled == false)
fill_ieee80211_hdr_data(txrx_pdev, &pl_msdu_info, data);
pl_msdu_info.ath_msdu_info = pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_mem_copy((void *)&pl_msdu_info.priv.msdu_id_info,
((void *)data + sizeof(struct ath_pktlog_hdr)),
sizeof(pl_msdu_info.priv.msdu_id_info));
qdf_mem_copy(pl_msdu_info.ath_msdu_info, &pl_msdu_info.priv,
sizeof(pl_msdu_info.priv));
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
pl_msdu_info.ath_msdu_info);
}
return A_OK;
}
#endif
A_STATUS process_rx_info_remote(void *pdev, void *data)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
struct htt_host_rx_desc_base *rx_desc;
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_rx_info rxstat_log;
size_t log_size;
struct ol_rx_remote_data *r_data = (struct ol_rx_remote_data *)data;
qdf_nbuf_t msdu;
if (!pdev) {
printk("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
if (!r_data) {
printk("Invalid data in %s\n", __func__);
return A_ERROR;
}
pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
pl_info = pl_dev->pl_info;
msdu = r_data->msdu;
while (msdu) {
rx_desc =
(struct htt_host_rx_desc_base *)(qdf_nbuf_data(msdu)) - 1;
log_size =
sizeof(*rx_desc) - sizeof(struct htt_host_fw_desc_base);
/*
* Construct the pktlog header pl_hdr
* Because desc is DMA'd to the host memory
*/
pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
pl_hdr.missed_cnt = 0;
#if defined(HELIUMPLUS)
pl_hdr.macId = r_data->mac_id;
pl_hdr.log_type = PKTLOG_TYPE_RX_STAT;
pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
#else
pl_hdr.log_type = PKTLOG_TYPE_RX_STAT;
#endif
pl_hdr.size = sizeof(*rx_desc) -
sizeof(struct htt_host_fw_desc_base);
#if defined(HELIUMPLUS)
pl_hdr.timestamp =
rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32;
pl_hdr.type_specific_data = 0xDEADAA;
#else
pl_hdr.timestamp = rx_desc->ppdu_end.tsf_timestamp;
#endif /* !defined(HELIUMPLUS) */
rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_mem_copy(rxstat_log.rx_desc, (void *)rx_desc +
sizeof(struct htt_host_fw_desc_base), pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
rxstat_log.rx_desc);
msdu = qdf_nbuf_next(msdu);
}
return A_OK;
}
A_STATUS process_rx_info(void *pdev, void *data)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
struct ath_pktlog_rx_info rxstat_log;
struct ath_pktlog_hdr pl_hdr;
size_t log_size;
uint32_t *pl_tgt_hdr;
if (!pdev) {
printk("Invalid pdev in %s", __func__);
return A_ERROR;
}
pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
pl_info = pl_dev->pl_info;
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;
#ifdef HELIUMPLUS
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.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
ATH_PKTLOG_HDR_MAC_ID_MASK) >>
ATH_PKTLOG_HDR_MAC_ID_SHIFT;
pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
#else
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;
#endif
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);
log_size = pl_hdr.size;
rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_mem_copy(rxstat_log.rx_desc,
(void *)data + sizeof(struct ath_pktlog_hdr), pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc);
return A_OK;
}
A_STATUS process_rate_find(void *pdev, void *data)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_info *pl_info;
size_t log_size;
/*
* Will be uncommented when the rate control find
* for pktlog is implemented in the firmware.
* Currently derived from the TX PPDU status
*/
struct ath_pktlog_rc_find rcf_log;
uint32_t *pl_tgt_hdr;
if (!pdev) {
qdf_print("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
if (!data) {
qdf_print("Invalid data in %s\n", __func__);
return A_ERROR;
}
pl_tgt_hdr = (uint32_t *) data;
/*
* Makes the short words (16 bits) portable b/w little endian
* and big endian
*/
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;
#ifdef HELIUMPLUS
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.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
ATH_PKTLOG_HDR_MAC_ID_MASK) >>
ATH_PKTLOG_HDR_MAC_ID_SHIFT;
pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
#else
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;
#endif
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);
pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
pl_info = pl_dev->pl_info;
log_size = pl_hdr.size;
rcf_log.rcFind = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_mem_copy(rcf_log.rcFind,
((char *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcf_log.rcFind);
return A_OK;
}
A_STATUS process_sw_event(void *pdev, void *data)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_hdr pl_hdr;
struct ath_pktlog_info *pl_info;
size_t log_size;
/*
* Will be uncommented when the rate control find
* for pktlog is implemented in the firmware.
* Currently derived from the TX PPDU status
*/
struct ath_pktlog_sw_event sw_event;
uint32_t *pl_tgt_hdr;
if (!pdev) {
qdf_print("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
if (!data) {
qdf_print("Invalid data in %s\n", __func__);
return A_ERROR;
}
pl_tgt_hdr = (uint32_t *) data;
/*
* Makes the short words (16 bits) portable b/w little endian
* and big endian
*/
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;
#ifdef HELIUMPLUS
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.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
ATH_PKTLOG_HDR_MAC_ID_MASK) >>
ATH_PKTLOG_HDR_MAC_ID_SHIFT;
#else
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;
#endif
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);
#ifdef HELIUMPLUS
pl_hdr.type_specific_data =
*(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET);
#endif
pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
pl_info = pl_dev->pl_info;
log_size = pl_hdr.size;
sw_event.sw_event = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_mem_copy(sw_event.sw_event,
((char *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
return A_OK;
}
A_STATUS process_rate_update(void *pdev, void *data)
{
struct ol_pktlog_dev_t *pl_dev;
struct ath_pktlog_hdr pl_hdr;
size_t log_size;
struct ath_pktlog_info *pl_info;
struct ath_pktlog_rc_update rcu_log;
uint32_t *pl_tgt_hdr;
if (!pdev) {
printk("Invalid pdev in %s\n", __func__);
return A_ERROR;
}
if (!data) {
printk("Invalid data in %s\n", __func__);
return A_ERROR;
}
pl_tgt_hdr = (uint32_t *) data;
/*
* Makes the short words (16 bits) portable b/w little endian
* and big endian
*/
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;
#ifdef HELIUMPLUS
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.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
ATH_PKTLOG_HDR_MAC_ID_MASK) >>
ATH_PKTLOG_HDR_MAC_ID_SHIFT;
pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
#else
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;
#endif
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);
pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
log_size = pl_hdr.size;
pl_info = pl_dev->pl_info;
/*
* Will be uncommented when the rate control update
* for pktlog is implemented in the firmware.
* Currently derived from the TX PPDU status
*/
rcu_log.txRateCtrl = (void *)pktlog_getbuf(pl_dev, pl_info,
log_size, &pl_hdr);
qdf_mem_copy(rcu_log.txRateCtrl,
((char *)data + sizeof(struct ath_pktlog_hdr)),
pl_hdr.size);
cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcu_log.txRateCtrl);
return A_OK;
}
#endif /*REMOVE_PKT_LOG */

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/******************************************************************************
* 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
*/
#ifdef PTT_SOCK_SVC_ENABLE
int ptt_sock_activate_svc(void);
void ptt_sock_deactivate_svc(void);
int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid);
#else
static inline int ptt_sock_activate_svc(void) { return 0; }
static inline void ptt_sock_deactivate_svc(void) { return; }
static inline int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio,
int src_mod, int pid)
{
return 0;
}
#endif
/*
* 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
*/
typedef struct sAniAppRegReq {
tAniNlModTypes type; /* module id */
int pid; /* process id */
} tAniNlAppRegReq;
typedef struct sAniNlAppRegRsp {
tAniHdr wniHdr; /* Generic WNI msg header */
tAniNlAppRegReq regReq; /* The original request msg */
int ret; /* Return code */
} tAniNlAppRegRsp;
#endif

View File

@@ -0,0 +1,231 @@
/*
* Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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 was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/******************************************************************************
* 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>
#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
/** ptt Process ID */
static int32_t ptt_pid = INVALID_PID;
#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%p:", 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
/**
* 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 == NULL) {
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 (NULL == 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;
memcpy(&wnl->wmsg, 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(skb, pid, MSG_DONTWAIT);
else
err = nl_srv_bcast(skb);
if (err)
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;
}
/*
* Process tregisteration request and send registration response messages
* to the PTT Socket App in user space
*/
static void ptt_sock_proc_reg_req(tAniHdr *wmsg, int radio)
{
tAniNlAppRegReq *reg_req;
tAniNlAppRegRsp rspmsg;
reg_req = (tAniNlAppRegReq *) (wmsg + 1);
memset((char *)&rspmsg, 0, sizeof(rspmsg));
/* send reg response message to the application */
rspmsg.ret = ANI_NL_MSG_OK;
rspmsg.regReq.type = reg_req->type;
/*Save the pid */
ptt_pid = reg_req->pid;
rspmsg.regReq.pid = reg_req->pid;
rspmsg.wniHdr.type = cpu_to_be16(ANI_MSG_APP_REG_RSP);
rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg));
if (ptt_sock_send_msg_to_app((tAniHdr *) &rspmsg.wniHdr, radio,
ANI_NL_MSG_PUMAC, ptt_pid) < 0) {
PTT_TRACE(QDF_TRACE_LEVEL_INFO,
"%s: Error sending ANI_MSG_APP_REG_RSP to pid[%d]\n",
__func__, ptt_pid);
}
}
/*
* Process all the messages from the PTT Socket App in user space
*/
static void ptt_proc_pumac_msg(struct sk_buff *skb, tAniHdr *wmsg, int radio)
{
u16 ani_msg_type = be16_to_cpu(wmsg->type);
switch (ani_msg_type) {
case ANI_MSG_APP_REG_REQ:
PTT_TRACE(QDF_TRACE_LEVEL_INFO,
"%s: Received ANI_MSG_APP_REG_REQ [0x%X]\n", __func__,
ani_msg_type);
ptt_sock_proc_reg_req(wmsg, radio);
break;
default:
PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
"%s: Received Unknown Msg Type[0x%X]\n", __func__,
ani_msg_type);
break;
}
}
/*
* Process all the Netlink messages from PTT Socket app in user space
*/
static int ptt_sock_rx_nlink_msg(struct sk_buff *skb)
{
tAniNlHdr *wnl;
int radio;
int type;
wnl = (tAniNlHdr *) skb->data;
radio = wnl->radio;
type = wnl->nlh.nlmsg_type;
switch (type) {
case ANI_NL_MSG_PUMAC: /* Message from the PTT socket APP */
PTT_TRACE(QDF_TRACE_LEVEL_INFO,
"%s: Received ANI_NL_MSG_PUMAC Msg [0x%X]\n",
__func__, type);
ptt_proc_pumac_msg(skb, &wnl->wmsg, radio);
break;
default:
PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: Unknown NL Msg [0x%X]\n",
__func__, type);
break;
}
return 0;
}
/**
* ptt_sock_activate_svc() - activate PTT service
*
* Return: 0
*/
int ptt_sock_activate_svc(void)
{
ptt_pid = INVALID_PID;
nl_srv_register(ANI_NL_MSG_PUMAC, ptt_sock_rx_nlink_msg);
nl_srv_register(ANI_NL_MSG_PTT, ptt_sock_rx_nlink_msg);
return 0;
}
/**
* ptt_sock_deactivate_svc() - deactivate PTT service
*
* Return: Void
*/
void ptt_sock_deactivate_svc(void)
{
ptt_pid = INVALID_PID;
}
#endif /* PTT_SOCK_SVC_ENABLE */