qcacmn: Add support to log CE DST and STATUS ring events

1. Record hp/tp for ce dst and status ring to keep
   a track of the last reaped and posted buffers.
2. Add union ce_srng_desc to record ce srng descriptor
   information.

Change-Id: I6f4728893d629c60f676826bf806b725326fb83d
CRs-Fixed: 2465492
This commit is contained in:
Venkata Sharath Chandra Manchala
2019-05-31 19:25:33 -07:00
committed by nshrivas
parent ff4d3f79f1
commit d8b05b54d7
6 changed files with 215 additions and 57 deletions

View File

@@ -880,6 +880,20 @@ static inline uint32_t hal_srng_src_done_val(void *hal_soc, void *hal_ring)
srng->u.src_ring.cached_tp) / srng->entry_size; srng->u.src_ring.cached_tp) / srng->entry_size;
} }
/**
* hal_get_entrysize_from_srng() - Retrieve ring entry size
* @hal_ring: Source ring pointer
*
* Return: uint8_t
*/
static inline
uint8_t hal_get_entrysize_from_srng(void *hal_ring)
{
struct hal_srng *srng = (struct hal_srng *)hal_ring;
return srng->entry_size;
}
/** /**
* hal_get_sw_hptp - Get SW head and tail pointer location for any ring * hal_get_sw_hptp - Get SW head and tail pointer location for any ring
* @hal_soc: Opaque HAL SOC handle * @hal_soc: Opaque HAL SOC handle

View File

@@ -379,6 +379,18 @@ union ce_desc {
struct CE_dest_desc dest_desc; struct CE_dest_desc dest_desc;
}; };
/**
* union ce_srng_desc - unified data type for ce srng descriptors
* @src_desc: ce srng Source ring descriptor
* @dest_desc: ce srng destination ring descriptor
* @dest_status_desc: ce srng status ring descriptor
*/
union ce_srng_desc {
struct ce_srng_src_desc src_desc;
struct ce_srng_dest_desc dest_desc;
struct ce_srng_dest_status_desc dest_status_desc;
};
/** /**
* enum hif_ce_event_type - HIF copy engine event type * enum hif_ce_event_type - HIF copy engine event type
* @HIF_RX_DESC_POST: event recorded before updating write index of RX ring. * @HIF_RX_DESC_POST: event recorded before updating write index of RX ring.
@@ -408,6 +420,13 @@ union ce_desc {
* @NAPI_POLL_ENTER: records the start of the napi poll function * @NAPI_POLL_ENTER: records the start of the napi poll function
* @NAPI_COMPLETE: records when interrupts are reenabled * @NAPI_COMPLETE: records when interrupts are reenabled
* @NAPI_POLL_EXIT: records when the napi poll function returns * @NAPI_POLL_EXIT: records when the napi poll function returns
* @HIF_RX_NBUF_ALLOC_FAILURE: record the packet when nbuf fails to allocate
* @HIF_RX_NBUF_MAP_FAILURE: record the packet when dma map fails
* @HIF_RX_NBUF_ENQUEUE_FAILURE: record the packet when enqueue to ce fails
* @HIF_CE_SRC_RING_BUFFER_POST: record the packet when buffer is posted to ce src ring
* @HIF_CE_DEST_RING_BUFFER_POST: record the packet when buffer is posted to ce dst ring
* @HIF_CE_DEST_RING_BUFFER_REAP: record the packet when buffer is reaped from ce dst ring
* @HIF_CE_DEST_STATUS_RING_REAP: record the packet when status ring is reaped
*/ */
enum hif_ce_event_type { enum hif_ce_event_type {
HIF_RX_DESC_POST, HIF_RX_DESC_POST,
@@ -437,6 +456,11 @@ enum hif_ce_event_type {
HIF_RX_NBUF_ALLOC_FAILURE = 0x20, HIF_RX_NBUF_ALLOC_FAILURE = 0x20,
HIF_RX_NBUF_MAP_FAILURE, HIF_RX_NBUF_MAP_FAILURE,
HIF_RX_NBUF_ENQUEUE_FAILURE, HIF_RX_NBUF_ENQUEUE_FAILURE,
HIF_CE_SRC_RING_BUFFER_POST,
HIF_CE_DEST_RING_BUFFER_POST,
HIF_CE_DEST_RING_BUFFER_REAP,
HIF_CE_DEST_STATUS_RING_REAP,
}; };
void ce_init_ce_desc_event_log(struct hif_softc *scn, int ce_id, int size); void ce_init_ce_desc_event_log(struct hif_softc *scn, int ce_id, int size);
@@ -513,10 +537,6 @@ static inline void ce_t2h_msg_ce_cleanup(struct CE_handle *ce_hdl)
*/ */
int hif_get_wake_ce_id(struct hif_softc *scn, uint8_t *ce_id); int hif_get_wake_ce_id(struct hif_softc *scn, uint8_t *ce_id);
/*
* Note: For MCL, #if defined (HIF_CONFIG_SLUB_DEBUG_ON) needs to be checked
* for defined here
*/
#if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF) #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
#ifndef HIF_CE_HISTORY_MAX #ifndef HIF_CE_HISTORY_MAX
@@ -524,10 +544,13 @@ int hif_get_wake_ce_id(struct hif_softc *scn, uint8_t *ce_id);
#endif #endif
#define CE_DEBUG_MAX_DATA_BUF_SIZE 64 #define CE_DEBUG_MAX_DATA_BUF_SIZE 64
/** /**
* struct hif_ce_desc_event - structure for detailing a ce event * struct hif_ce_desc_event - structure for detailing a ce event
* @type: what the event was * @type: what the event was
* @time: when it happened * @time: when it happened
* @current_hp: holds the current ring hp value
* @current_tp: holds the current ring tp value
* @descriptor: descriptor enqueued or dequeued * @descriptor: descriptor enqueued or dequeued
* @memory: virtual address that was used * @memory: virtual address that was used
* @index: location of the descriptor in the ce ring; * @index: location of the descriptor in the ce ring;
@@ -535,19 +558,77 @@ int hif_get_wake_ce_id(struct hif_softc *scn, uint8_t *ce_id);
* @actual_data_len: length of the data * @actual_data_len: length of the data
*/ */
struct hif_ce_desc_event { struct hif_ce_desc_event {
uint16_t index; int index;
enum hif_ce_event_type type; enum hif_ce_event_type type;
uint64_t time; uint64_t time;
#ifdef HELIUMPLUS
union ce_desc descriptor; union ce_desc descriptor;
#else
uint32_t current_hp;
uint32_t current_tp;
union ce_srng_desc descriptor;
#endif
void *memory; void *memory;
#ifdef HIF_CE_DEBUG_DATA_BUF #ifdef HIF_CE_DEBUG_DATA_BUF
uint8_t *data; uint8_t *data;
size_t actual_data_len; size_t actual_data_len;
#endif /* HIF_CE_DEBUG_DATA_BUF */ #endif /* HIF_CE_DEBUG_DATA_BUF */
}; };
#else
struct hif_ce_desc_event;
#endif /*#if defined(HIF_CONFIG_SLUB_DEBUG_ON)||defined(HIF_CE_DEBUG_DATA_BUF)*/ #endif /*#if defined(HIF_CONFIG_SLUB_DEBUG_ON)||defined(HIF_CE_DEBUG_DATA_BUF)*/
/**
* get_next_record_index() - get the next record index
* @table_index: atomic index variable to increment
* @array_size: array size of the circular buffer
*
* Increment the atomic index and reserve the value.
* Takes care of buffer wrap.
* Guaranteed to be thread safe as long as fewer than array_size contexts
* try to access the array. If there are more than array_size contexts
* trying to access the array, full locking of the recording process would
* be needed to have sane logging.
*/
int get_next_record_index(qdf_atomic_t *table_index, int array_size);
#if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
/**
* hif_record_ce_srng_desc_event() - Record data pointed by the CE descriptor
* @scn: structure detailing a ce event
* @ce_id: length of the data
* @type: event_type
* @descriptor: ce src/dest/status ring descriptor
* @memory: nbuf
* @index: current sw/write index
* @len: len of the buffer
* @hal_ring: ce hw ring
*
* Return: None
*/
void hif_record_ce_srng_desc_event(struct hif_softc *scn, int ce_id,
enum hif_ce_event_type type,
union ce_srng_desc *descriptor,
void *memory, int index,
int len, void *hal_ring);
#else
static inline
void hif_record_ce_srng_desc_event(struct hif_softc *scn, int ce_id,
enum hif_ce_event_type type,
union ce_srng_desc *descriptor,
void *memory, int index,
int len, void *hal_ring)
{
}
#endif
#ifdef HIF_CE_DEBUG_DATA_BUF #ifdef HIF_CE_DEBUG_DATA_BUF
/**
* hif_ce_desc_data_record() - Record data pointed by the CE descriptor
* @event: structure detailing a ce event
* @len: length of the data
* Return:
*/
void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len);
QDF_STATUS alloc_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id); QDF_STATUS alloc_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id);
void free_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id); void free_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id);
#else #else
@@ -559,6 +640,11 @@ QDF_STATUS alloc_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id)
static inline static inline
void free_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id) { } void free_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id) { }
static inline
void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len)
{
}
#endif /*HIF_CE_DEBUG_DATA_BUF*/ #endif /*HIF_CE_DEBUG_DATA_BUF*/
#ifdef HIF_CONFIG_SLUB_DEBUG_ON #ifdef HIF_CONFIG_SLUB_DEBUG_ON

View File

@@ -92,19 +92,7 @@ void hif_ce_war_enable(void)
static const char *ce_event_type_to_str(enum hif_ce_event_type type); static const char *ce_event_type_to_str(enum hif_ce_event_type type);
/** int get_next_record_index(qdf_atomic_t *table_index, int array_size)
* get_next_record_index() - get the next record index
* @table_index: atomic index variable to increment
* @array_size: array size of the circular buffer
*
* Increment the atomic index and reserve the value.
* Takes care of buffer wrap.
* Guaranteed to be thread safe as long as fewer than array_size contexts
* try to access the array. If there are more than array_size contexts
* trying to access the array, full locking of the recording process would
* be needed to have sane logging.
*/
static int get_next_record_index(qdf_atomic_t *table_index, int array_size)
{ {
int record_index = qdf_atomic_inc_return(table_index); int record_index = qdf_atomic_inc_return(table_index);
@@ -113,17 +101,11 @@ static int get_next_record_index(qdf_atomic_t *table_index, int array_size)
while (record_index >= array_size) while (record_index >= array_size)
record_index -= array_size; record_index -= array_size;
return record_index; return record_index;
} }
#ifdef HIF_CE_DEBUG_DATA_BUF #ifdef HIF_CE_DEBUG_DATA_BUF
/**
* hif_ce_desc_data_record() - Record data pointed by the CE descriptor
* @event: structure detailing a ce event
* @len: length of the data
* Return:
*/
static inline
void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len) void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len)
{ {
uint8_t *data = NULL; uint8_t *data = NULL;
@@ -146,12 +128,7 @@ void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len)
event->actual_data_len = len; event->actual_data_len = len;
} }
} }
#else #endif
static inline
void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len)
{
}
#endif /* HIF_CE_DEBUG_DATA_BUF */
/** /**
* hif_record_ce_desc_event() - record ce descriptor events * hif_record_ce_desc_event() - record ce descriptor events
@@ -193,14 +170,14 @@ void hif_record_ce_desc_event(struct hif_softc *scn, int ce_id,
event = &hist_ev[record_index]; event = &hist_ev[record_index];
qdf_mem_zero(event, sizeof(struct hif_ce_desc_event));
event->type = type; event->type = type;
event->time = qdf_get_log_timestamp(); event->time = qdf_get_log_timestamp();
if (descriptor) { if (descriptor)
qdf_mem_copy(&event->descriptor, descriptor, sizeof(union ce_desc)); qdf_mem_copy(&event->descriptor, descriptor,
} else { sizeof(union ce_desc));
qdf_mem_zero(&event->descriptor, sizeof(union ce_desc));
}
event->memory = memory; event->memory = memory;
event->index = index; event->index = index;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -748,9 +748,11 @@ ce_recv_buf_enqueue_legacy(struct CE_handle *copyeng,
dest_ring->per_transfer_context[write_index] = dest_ring->per_transfer_context[write_index] =
per_recv_context; per_recv_context;
hif_record_ce_desc_event(scn, CE_state->id, HIF_RX_DESC_POST, hif_record_ce_desc_event(scn, CE_state->id,
(union ce_desc *)dest_desc, per_recv_context, HIF_RX_DESC_POST,
write_index, 0); (union ce_desc *)dest_desc,
per_recv_context,
write_index, 0);
/* Update Destination Ring Write Index */ /* Update Destination Ring Write Index */
write_index = CE_RING_IDX_INCR(nentries_mask, write_index); write_index = CE_RING_IDX_INCR(nentries_mask, write_index);

View File

@@ -15,8 +15,6 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "hif.h"
#include "hif_io32.h" #include "hif_io32.h"
#include "reg_struct.h" #include "reg_struct.h"
#include "ce_api.h" #include "ce_api.h"
@@ -30,6 +28,7 @@
#include "hal_api.h" #include "hal_api.h"
#include "pld_common.h" #include "pld_common.h"
#include "qdf_module.h" #include "qdf_module.h"
#include "hif.h"
/* /*
* Support for Copy Engine hardware, which is mainly used for * Support for Copy Engine hardware, which is mainly used for
@@ -78,6 +77,58 @@
(uint32_t)(((dma_addr) >> 32) & 0xFF);\ (uint32_t)(((dma_addr) >> 32) & 0xFF);\
} while (0) } while (0)
#if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
void hif_record_ce_srng_desc_event(struct hif_softc *scn, int ce_id,
enum hif_ce_event_type type,
union ce_srng_desc *descriptor,
void *memory, int index,
int len, void *hal_ring)
{
int record_index;
struct hif_ce_desc_event *event;
struct ce_desc_hist *ce_hist = &scn->hif_ce_desc_hist;
struct hif_ce_desc_event *hist_ev = NULL;
if (ce_id < CE_COUNT_MAX)
hist_ev = (struct hif_ce_desc_event *)ce_hist->hist_ev[ce_id];
else
return;
if (ce_id >= CE_COUNT_MAX)
return;
if (!ce_hist->enable[ce_id])
return;
if (!hist_ev)
return;
record_index = get_next_record_index(
&ce_hist->history_index[ce_id], HIF_CE_HISTORY_MAX);
event = &hist_ev[record_index];
qdf_mem_zero(event, sizeof(struct hif_ce_desc_event));
event->type = type;
event->time = qdf_get_log_timestamp();
if (descriptor)
qdf_mem_copy(&event->descriptor, descriptor,
hal_get_entrysize_from_srng(hal_ring));
if (hal_ring)
hal_get_sw_hptp(scn->hal_soc, hal_ring, &event->current_tp,
&event->current_hp);
event->memory = memory;
event->index = index;
if (ce_hist->data_enable[ce_id])
hif_ce_desc_data_record(event, len);
}
#endif
static int static int
ce_send_nolock_srng(struct CE_handle *copyeng, ce_send_nolock_srng(struct CE_handle *copyeng,
void *per_transfer_context, void *per_transfer_context,
@@ -104,7 +155,7 @@ ce_send_nolock_srng(struct CE_handle *copyeng,
return QDF_STATUS_E_FAILURE; return QDF_STATUS_E_FAILURE;
} }
{ {
enum hif_ce_event_type event_type = HIF_TX_GATHER_DESC_POST; enum hif_ce_event_type event_type = HIF_CE_SRC_RING_BUFFER_POST;
struct ce_srng_src_desc *src_desc; struct ce_srng_src_desc *src_desc;
if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) { if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) {
@@ -148,9 +199,11 @@ ce_send_nolock_srng(struct CE_handle *copyeng,
/* src_ring->write index hasn't been updated event though /* src_ring->write index hasn't been updated event though
* the register has allready been written to. * the register has allready been written to.
*/ */
hif_record_ce_desc_event(scn, CE_state->id, event_type, hif_record_ce_srng_desc_event(scn, CE_state->id, event_type,
(union ce_desc *) src_desc, per_transfer_context, (union ce_srng_desc *)src_desc,
src_ring->write_index, nbytes); per_transfer_context,
src_ring->write_index, nbytes,
src_ring->srng_ctx);
src_ring->write_index = write_index; src_ring->write_index = write_index;
status = QDF_STATUS_SUCCESS; status = QDF_STATUS_SUCCESS;
@@ -252,6 +305,7 @@ ce_recv_buf_enqueue_srng(struct CE_handle *copyeng,
unsigned int sw_index; unsigned int sw_index;
uint64_t dma_addr = buffer; uint64_t dma_addr = buffer;
struct hif_softc *scn = CE_state->scn; struct hif_softc *scn = CE_state->scn;
struct ce_srng_dest_desc *dest_desc;
qdf_spin_lock_bh(&CE_state->ce_index_lock); qdf_spin_lock_bh(&CE_state->ce_index_lock);
write_index = dest_ring->write_index; write_index = dest_ring->write_index;
@@ -269,9 +323,8 @@ ce_recv_buf_enqueue_srng(struct CE_handle *copyeng,
if ((hal_srng_src_num_avail(scn->hal_soc, if ((hal_srng_src_num_avail(scn->hal_soc,
dest_ring->srng_ctx, false) > 0)) { dest_ring->srng_ctx, false) > 0)) {
struct ce_srng_dest_desc *dest_desc = dest_desc = hal_srng_src_get_next(scn->hal_soc,
hal_srng_src_get_next(scn->hal_soc, dest_ring->srng_ctx);
dest_ring->srng_ctx);
if (!dest_desc) { if (!dest_desc) {
status = QDF_STATUS_E_FAILURE; status = QDF_STATUS_E_FAILURE;
@@ -292,6 +345,13 @@ ce_recv_buf_enqueue_srng(struct CE_handle *copyeng,
dest_ring->write_index = write_index; dest_ring->write_index = write_index;
hal_srng_access_end(scn->hal_soc, dest_ring->srng_ctx); hal_srng_access_end(scn->hal_soc, dest_ring->srng_ctx);
hif_record_ce_srng_desc_event(scn, CE_state->id,
HIF_CE_DEST_RING_BUFFER_POST,
(union ce_srng_desc *)dest_desc,
per_recv_context,
dest_ring->write_index, 0,
dest_ring->srng_ctx);
Q_TARGET_ACCESS_END(scn); Q_TARGET_ACCESS_END(scn);
qdf_spin_unlock_bh(&CE_state->ce_index_lock); qdf_spin_unlock_bh(&CE_state->ce_index_lock);
return status; return status;
@@ -412,6 +472,23 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
done: done:
hal_srng_access_end(scn->hal_soc, status_ring->srng_ctx); hal_srng_access_end(scn->hal_soc, status_ring->srng_ctx);
if (status == QDF_STATUS_SUCCESS) {
hif_record_ce_srng_desc_event(scn, CE_state->id,
HIF_CE_DEST_RING_BUFFER_REAP,
NULL,
dest_ring->
per_transfer_context[sw_index],
dest_ring->sw_index, nbytes,
dest_ring->srng_ctx);
hif_record_ce_srng_desc_event(scn, CE_state->id,
HIF_CE_DEST_STATUS_RING_REAP,
(union ce_srng_desc *)dest_status,
NULL,
-1, 0,
status_ring->srng_ctx);
}
return status; return status;
} }
@@ -482,11 +559,13 @@ ce_completed_send_next_nolock_srng(struct CE_state *CE_state,
src_desc = hal_srng_src_reap_next(scn->hal_soc, src_ring->srng_ctx); src_desc = hal_srng_src_reap_next(scn->hal_soc, src_ring->srng_ctx);
if (src_desc) { if (src_desc) {
hif_record_ce_desc_event(scn, CE_state->id, hif_record_ce_srng_desc_event(scn, CE_state->id,
HIF_TX_DESC_COMPLETION, HIF_TX_DESC_COMPLETION,
(union ce_desc *)src_desc, (union ce_srng_desc *)src_desc,
src_ring->per_transfer_context[swi], src_ring->
swi, src_desc->nbytes); per_transfer_context[swi],
swi, src_desc->nbytes,
src_ring->srng_ctx);
/* Return data from completed source descriptor */ /* Return data from completed source descriptor */
*bufferp = (qdf_dma_addr_t) *bufferp = (qdf_dma_addr_t)

View File

@@ -154,7 +154,7 @@ static void ce_tasklet(unsigned long data)
struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id]; struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id];
hif_record_ce_desc_event(scn, tasklet_entry->ce_id, hif_record_ce_desc_event(scn, tasklet_entry->ce_id,
HIF_CE_TASKLET_ENTRY, NULL, NULL, 0, 0); HIF_CE_TASKLET_ENTRY, NULL, NULL, -1, 0);
if (qdf_atomic_read(&scn->link_suspended)) { if (qdf_atomic_read(&scn->link_suspended)) {
HIF_ERROR("%s: ce %d tasklet fired after link suspend.", HIF_ERROR("%s: ce %d tasklet fired after link suspend.",
@@ -171,7 +171,7 @@ static void ce_tasklet(unsigned long data)
* any of the Copy Engine pipes. * any of the Copy Engine pipes.
*/ */
hif_record_ce_desc_event(scn, tasklet_entry->ce_id, hif_record_ce_desc_event(scn, tasklet_entry->ce_id,
HIF_CE_TASKLET_RESCHEDULE, NULL, NULL, 0, 0); HIF_CE_TASKLET_RESCHEDULE, NULL, NULL, -1, 0);
ce_schedule_tasklet(tasklet_entry); ce_schedule_tasklet(tasklet_entry);
return; return;
@@ -181,7 +181,7 @@ static void ce_tasklet(unsigned long data)
hif_irq_enable(scn, tasklet_entry->ce_id); hif_irq_enable(scn, tasklet_entry->ce_id);
hif_record_ce_desc_event(scn, tasklet_entry->ce_id, HIF_CE_TASKLET_EXIT, hif_record_ce_desc_event(scn, tasklet_entry->ce_id, HIF_CE_TASKLET_EXIT,
NULL, NULL, 0, 0); NULL, NULL, -1, 0);
qdf_atomic_dec(&scn->active_tasklet_cnt); qdf_atomic_dec(&scn->active_tasklet_cnt);
} }