From d8b05b54d7d1f01e04ca434d2fc05991420c1876 Mon Sep 17 00:00:00 2001 From: Venkata Sharath Chandra Manchala Date: Fri, 31 May 2019 19:25:33 -0700 Subject: [PATCH] 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 --- hal/wifi3.0/hal_api.h | 14 +++++ hif/src/ce/ce_internal.h | 96 +++++++++++++++++++++++++++-- hif/src/ce/ce_service.c | 39 +++--------- hif/src/ce/ce_service_legacy.c | 10 +-- hif/src/ce/ce_service_srng.c | 107 ++++++++++++++++++++++++++++----- hif/src/ce/ce_tasklet.c | 6 +- 6 files changed, 215 insertions(+), 57 deletions(-) diff --git a/hal/wifi3.0/hal_api.h b/hal/wifi3.0/hal_api.h index 75be311e19..b373f345d9 100644 --- a/hal/wifi3.0/hal_api.h +++ b/hal/wifi3.0/hal_api.h @@ -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; } +/** + * 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_soc: Opaque HAL SOC handle diff --git a/hif/src/ce/ce_internal.h b/hif/src/ce/ce_internal.h index ca62f31ca3..b7fb7f9090 100644 --- a/hif/src/ce/ce_internal.h +++ b/hif/src/ce/ce_internal.h @@ -379,6 +379,18 @@ union ce_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 * @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_COMPLETE: records when interrupts are reenabled * @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 { HIF_RX_DESC_POST, @@ -437,6 +456,11 @@ enum hif_ce_event_type { HIF_RX_NBUF_ALLOC_FAILURE = 0x20, HIF_RX_NBUF_MAP_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); @@ -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); -/* - * 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) #ifndef HIF_CE_HISTORY_MAX @@ -524,10 +544,13 @@ int hif_get_wake_ce_id(struct hif_softc *scn, uint8_t *ce_id); #endif #define CE_DEBUG_MAX_DATA_BUF_SIZE 64 + /** * struct hif_ce_desc_event - structure for detailing a ce event * @type: what the event was * @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 * @memory: virtual address that was used * @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 */ struct hif_ce_desc_event { - uint16_t index; + int index; enum hif_ce_event_type type; uint64_t time; +#ifdef HELIUMPLUS union ce_desc descriptor; +#else + uint32_t current_hp; + uint32_t current_tp; + union ce_srng_desc descriptor; +#endif void *memory; #ifdef HIF_CE_DEBUG_DATA_BUF uint8_t *data; size_t actual_data_len; #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)*/ +/** + * 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 +/** + * 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); void free_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id); #else @@ -559,6 +640,11 @@ QDF_STATUS alloc_mem_ce_debug_hist_data(struct hif_softc *scn, uint32_t ce_id) static inline 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*/ #ifdef HIF_CONFIG_SLUB_DEBUG_ON diff --git a/hif/src/ce/ce_service.c b/hif/src/ce/ce_service.c index 6dadc181d2..024d66c26c 100644 --- a/hif/src/ce/ce_service.c +++ b/hif/src/ce/ce_service.c @@ -92,19 +92,7 @@ void hif_ce_war_enable(void) static const char *ce_event_type_to_str(enum hif_ce_event_type type); -/** - * 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 get_next_record_index(qdf_atomic_t *table_index, int array_size) { 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) record_index -= array_size; + return record_index; } #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) { 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; } } -#else -static inline -void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len) -{ -} -#endif /* HIF_CE_DEBUG_DATA_BUF */ +#endif /** * 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]; + 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, sizeof(union ce_desc)); - } else { - qdf_mem_zero(&event->descriptor, sizeof(union ce_desc)); - } + if (descriptor) + qdf_mem_copy(&event->descriptor, descriptor, + sizeof(union ce_desc)); event->memory = memory; event->index = index; diff --git a/hif/src/ce/ce_service_legacy.c b/hif/src/ce/ce_service_legacy.c index 2651872c6f..2a473b63b4 100644 --- a/hif/src/ce/ce_service_legacy.c +++ b/hif/src/ce/ce_service_legacy.c @@ -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 * 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] = per_recv_context; - hif_record_ce_desc_event(scn, CE_state->id, HIF_RX_DESC_POST, - (union ce_desc *)dest_desc, per_recv_context, - write_index, 0); + hif_record_ce_desc_event(scn, CE_state->id, + HIF_RX_DESC_POST, + (union ce_desc *)dest_desc, + per_recv_context, + write_index, 0); /* Update Destination Ring Write Index */ write_index = CE_RING_IDX_INCR(nentries_mask, write_index); diff --git a/hif/src/ce/ce_service_srng.c b/hif/src/ce/ce_service_srng.c index a6d0d63a91..18593b1219 100644 --- a/hif/src/ce/ce_service_srng.c +++ b/hif/src/ce/ce_service_srng.c @@ -15,8 +15,6 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ - -#include "hif.h" #include "hif_io32.h" #include "reg_struct.h" #include "ce_api.h" @@ -30,6 +28,7 @@ #include "hal_api.h" #include "pld_common.h" #include "qdf_module.h" +#include "hif.h" /* * Support for Copy Engine hardware, which is mainly used for @@ -78,6 +77,58 @@ (uint32_t)(((dma_addr) >> 32) & 0xFF);\ } 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 ce_send_nolock_srng(struct CE_handle *copyeng, void *per_transfer_context, @@ -104,7 +155,7 @@ ce_send_nolock_srng(struct CE_handle *copyeng, 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; 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 * the register has allready been written to. */ - hif_record_ce_desc_event(scn, CE_state->id, event_type, - (union ce_desc *) src_desc, per_transfer_context, - src_ring->write_index, nbytes); + hif_record_ce_srng_desc_event(scn, CE_state->id, event_type, + (union ce_srng_desc *)src_desc, + per_transfer_context, + src_ring->write_index, nbytes, + src_ring->srng_ctx); src_ring->write_index = write_index; status = QDF_STATUS_SUCCESS; @@ -252,6 +305,7 @@ ce_recv_buf_enqueue_srng(struct CE_handle *copyeng, unsigned int sw_index; uint64_t dma_addr = buffer; struct hif_softc *scn = CE_state->scn; + struct ce_srng_dest_desc *dest_desc; qdf_spin_lock_bh(&CE_state->ce_index_lock); 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, dest_ring->srng_ctx, false) > 0)) { - struct ce_srng_dest_desc *dest_desc = - hal_srng_src_get_next(scn->hal_soc, - dest_ring->srng_ctx); + dest_desc = hal_srng_src_get_next(scn->hal_soc, + dest_ring->srng_ctx); if (!dest_desc) { status = QDF_STATUS_E_FAILURE; @@ -292,6 +345,13 @@ ce_recv_buf_enqueue_srng(struct CE_handle *copyeng, dest_ring->write_index = write_index; 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); qdf_spin_unlock_bh(&CE_state->ce_index_lock); return status; @@ -412,6 +472,23 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state, done: 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; } @@ -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); if (src_desc) { - hif_record_ce_desc_event(scn, CE_state->id, - HIF_TX_DESC_COMPLETION, - (union ce_desc *)src_desc, - src_ring->per_transfer_context[swi], - swi, src_desc->nbytes); + hif_record_ce_srng_desc_event(scn, CE_state->id, + HIF_TX_DESC_COMPLETION, + (union ce_srng_desc *)src_desc, + src_ring-> + per_transfer_context[swi], + swi, src_desc->nbytes, + src_ring->srng_ctx); /* Return data from completed source descriptor */ *bufferp = (qdf_dma_addr_t) diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 414343a0c9..9a5b61599d 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -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]; 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)) { 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. */ 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); return; @@ -181,7 +181,7 @@ static void ce_tasklet(unsigned long data) hif_irq_enable(scn, tasklet_entry->ce_id); 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); }