qcacld-3.0: Use different copy engine for packetlog

Create new endpoint and use CE11 for packetlog
messages from target to host.

CRs-Fixed: 995628
Change-Id: I0df597468b0b7399dc545b5a4d4fd1a4c04a1df0
This commit is contained in:
Nirav Shah 2016-05-25 10:49:02 +05:30 • committed by Vishwajith Upendra
commit 7f337dbb7a
8 changed files with 314 additions and 99 deletions

View file

@ -57,7 +57,8 @@
#include "cds_utils.h"
#include "wlan_logging_sock_svc.h"
#include "wma.h"
#include "ol_txrx.h"
#include "pktlog_ac.h"
#include "wlan_hdd_ipa.h"
/* Preprocessor Definitions and Constants */
@ -550,6 +551,10 @@ QDF_STATUS cds_pre_enable(v_CONTEXT_t cds_context)
return QDF_STATUS_E_FAILURE;
}
/* call Packetlog connect service */
htt_pkt_log_init(gp_cds_context->pdev_txrx_ctx, scn);
pktlog_htc_attach();
/* Reset wma wait event */
qdf_event_reset(&gp_cds_context->wmaCompleteEvent);

View file

@ -50,6 +50,7 @@
#include <ol_htt_tx_api.h>
#include <ol_txrx_peer_find.h>
#include <cdp_txrx_ipa.h>
#include "pktlog_ac.h"
/*--- target->host HTT message dispatch function ----------------------------*/
@ -315,29 +316,7 @@ void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg,
#ifndef REMOVE_PKT_LOG
case HTT_T2H_MSG_TYPE_PKTLOG:
{
uint32_t *pl_hdr;
uint32_t log_type;
pl_hdr = (msg_word + 1);
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,
pdev->txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_RC_FIND)
wdi_event_handler(WDI_EVENT_RATE_FIND,
pdev->txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_RC_UPDATE)
wdi_event_handler(WDI_EVENT_RATE_UPDATE,
pdev->txrx_pdev, pl_hdr);
else if (log_type == PKTLOG_TYPE_RX_STAT)
wdi_event_handler(WDI_EVENT_RX_DESC,
pdev->txrx_pdev, pl_hdr);
pktlog_process_fw_msg(msg_word + 1);
break;
}
#endif

View file

@ -935,7 +935,6 @@ ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev)
ol_tso_seg_list_init(pdev, desc_pool_size);
ol_tx_register_flow_control(pdev);
htt_pkt_log_init(pdev, osc);
return 0; /* success */

View file

@ -40,4 +40,6 @@ void ol_txrx_peer_unref_delete(struct ol_txrx_peer_t *peer);
ol_txrx_vdev_handle ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id);
void htt_pkt_log_init(struct ol_txrx_pdev_t *handle, void *scn);
#endif /* _OL_TXRX__H_ */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -94,9 +94,14 @@ struct ol_pktlog_dev_t {
ol_ath_generic_softc_handle scn;
char *name;
bool tgt_pktlog_enabled;
bool mt_pktlog_enabled;
uint32_t htc_err_cnt;
uint8_t htc_endpoint;
void *htc_pdev;
};
#define PKTLOG_SYSCTL_SIZE 14
#define PKTLOG_MAX_SEND_QUEUE_DEPTH 64
/*
* Linux specific pktlog state information
@ -124,6 +129,8 @@ 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(void *context);
int pktlog_htc_attach(void);
void pktlog_process_fw_msg(uint32_t *msg_word);
#define ol_pktlog_attach(_scn) \
do { \
@ -158,5 +165,11 @@ 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

@ -46,6 +46,7 @@
#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;
@ -446,4 +447,198 @@ int pktlog_setsize(struct hif_opaque_softc *scn, int32_t 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);
}
/**
* pktlog_t2h_msg_handler() - Target to host message handler
* @context: pdev context
* @pkt: HTC packet
*
* Return: None
*/
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
*/
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
*/
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
*/
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
*/
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 */
}
#if defined(QCA_WIFI_3_0_ADRASTEA)
/**
* 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

@ -261,6 +261,94 @@ static void process_ieee_hdr(void *data)
}
}
/**
* 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
*/
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
*/
}
}
A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data)
{
/*
@ -394,83 +482,14 @@ A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data)
if (pl_hdr.log_type == PKTLOG_TYPE_TX_MSDU_ID) {
struct ath_pktlog_msdu_info pl_msdu_info;
uint32_t i;
uint32_t *htt_tx_desc;
size_t log_size;
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;
qdf_mem_set(&pl_msdu_info, sizeof(pl_msdu_info), 0);
pl_msdu_info.num_msdu = *msdu_id_info;
pl_msdu_info.priv_size = sizeof(uint32_t) *
pl_msdu_info.num_msdu + sizeof(uint32_t);
log_size = sizeof(pl_msdu_info.priv);
for (i = 0; i < pl_msdu_info.num_msdu; i++) {
/*
* Handle big endianess
* 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);
if (pl_dev->mt_pktlog_enabled == false)
fill_ieee80211_hdr_data(txrx_pdev, &pl_msdu_info, data);
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 -1;
}
/* 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
*/
}
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,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved.
* Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -37,6 +37,7 @@ typedef enum {
HTT_SERVICE_GROUP = 3,
CFG_NV_SERVICE_GROUP = 4,
WDI_IPA_SERVICE_GROUP = 5,
PACKET_LOG_SERVICE_GROUP = 6,
HTC_TEST_GROUP = 254,
HTC_SERVICE_GROUP_LAST = 255
} HTC_SERVICE_GROUP_IDS;
@ -60,6 +61,8 @@ typedef enum {
#define HTT_DATA2_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,1)
#define HTT_DATA3_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP, 2)
#define PACKET_LOG_SVC MAKE_SERVICE_ID(PACKET_LOG_SERVICE_GROUP, 0)
/* raw stream service (i.e. flash, tcmd, calibration apps) */
#define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0)