From b70bd731ec4648f9eea303c7a954192e951173eb Mon Sep 17 00:00:00 2001 From: Nirav Shah Date: Wed, 25 May 2016 14:31:51 +0530 Subject: [PATCH] qcacmn: Add per CPU interrupt statistics Add per CPU per copy engine interrupt statistics. Change-Id: I1619f0db3314ae3d915284459f2b191f31fc2190 CRs-Fixed: 1017437 --- hif/inc/hif.h | 3 +- hif/src/ce/ce_main.h | 6 ++++ hif/src/ce/ce_tasklet.c | 58 ++++++++++++++++++++++++++++++ hif/src/ce/ce_tasklet.h | 2 ++ hif/src/dispatcher/dummy.c | 18 ++++++++++ hif/src/dispatcher/dummy.h | 2 ++ hif/src/dispatcher/multibus.c | 20 +++++++++++ hif/src/dispatcher/multibus.h | 2 ++ hif/src/dispatcher/multibus_pci.c | 5 ++- hif/src/dispatcher/multibus_snoc.c | 4 +++ hif/src/dispatcher/pci_api.h | 2 ++ hif/src/dispatcher/snoc_api.h | 2 ++ hif/src/hif_main.c | 9 +++++ hif/src/hif_main.h | 3 +- hif/src/pcie/if_pci.c | 22 ++++++++++++ hif/src/snoc/if_snoc.c | 22 ++++++++++++ qdf/inc/qdf_util.h | 12 +++++++ qdf/linux/src/i_qdf_util.h | 23 ++++++++++++ 18 files changed, 212 insertions(+), 3 deletions(-) diff --git a/hif/inc/hif.h b/hif/inc/hif.h index 2e3c230f9c..108e4b5fe6 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -505,7 +505,8 @@ QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev, enum qdf_bus_type bus_type, enum hif_enable_type type); void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type); - +void hif_display_stats(struct hif_opaque_softc *hif_ctx); +void hif_clear_stats(struct hif_opaque_softc *hif_ctx); #ifdef FEATURE_RUNTIME_PM struct hif_pm_runtime_lock; int hif_pm_runtime_get(struct hif_opaque_softc *hif_ctx); diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h index 6c3a67f919..3023be80fe 100644 --- a/hif/src/ce/ce_main.h +++ b/hif/src/ce/ce_main.h @@ -31,6 +31,7 @@ #include "qdf_atomic.h" #include "qdf_lock.h" #include "hif_main.h" +#include "qdf_util.h" #define CE_HTT_T2H_MSG 1 #define CE_HTT_H2T_MSG 4 @@ -111,6 +112,10 @@ struct ce_tasklet_entry { void *hif_ce_state; }; +struct ce_intr_stats { + uint32_t ce_per_cpu[CE_COUNT_MAX][QDF_MAX_AVAILABLE_CPU]; +}; + struct HIF_CE_state { struct hif_softc ol_sc; bool started; @@ -135,6 +140,7 @@ struct HIF_CE_state { /* Copy Engine used for Diagnostic Accesses */ struct CE_handle *ce_diag; + struct ce_intr_stats stats; }; /* diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 5c692cc6a0..c03a695847 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -256,6 +256,63 @@ static irqreturn_t hif_snoc_interrupt_handler(int irq, void *context) return ce_dispatch_interrupt(icnss_get_ce_id(irq), tasklet_entry); } +/** + * hif_ce_increment_interrupt_count() - update ce stats + * @hif_ce_state: ce state + * @ce_id: ce id + * + * Return: none + */ +static inline void +hif_ce_increment_interrupt_count(struct HIF_CE_state *hif_ce_state, int ce_id) +{ + int cpu_id = qdf_get_cpu(); + + hif_ce_state->stats.ce_per_cpu[ce_id][cpu_id]++; +} + +/** + * hif_display_ce_stats() - display ce stats + * @hif_ce_state: ce state + * + * Return: none + */ +void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state) +{ +#define STR_SIZE 128 + uint8_t i, j, pos; + char str_buffer[STR_SIZE]; + int size, ret; + + qdf_print("CE interrupt statistics:"); + for (i = 0; i < CE_COUNT_MAX; i++) { + size = STR_SIZE; + pos = 0; + qdf_print("CE id: %d", i); + for (j = 0; j < QDF_MAX_AVAILABLE_CPU; j++) { + ret = snprintf(str_buffer + pos, size, "[%d]: %d", + j, hif_ce_state->stats.ce_per_cpu[i][j]); + if (ret <= 0 || ret >= size) + break; + size -= ret; + pos += ret; + } + qdf_print("%s", str_buffer); + } +#undef STR_SIZE +} + +/** + * hif_clear_ce_stats() - clear ce stats + * @hif_ce_state: ce state + * + * Return: none + */ +void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state) +{ + qdf_mem_zero(&hif_ce_state->stats, sizeof(struct ce_intr_stats)); +} + /** * ce_dispatch_interrupt() - dispatch an interrupt to a processing context * @ce_id: ce_id @@ -283,6 +340,7 @@ irqreturn_t ce_dispatch_interrupt(int ce_id, hif_irq_disable(scn, ce_id); qdf_atomic_inc(&scn->active_tasklet_cnt); hif_record_ce_desc_event(scn, ce_id, HIF_IRQ_EVENT, NULL, NULL, 0); + hif_ce_increment_interrupt_count(hif_ce_state, ce_id); if (hif_napi_enabled(hif_hdl, ce_id)) hif_napi_schedule(hif_hdl, ce_id); else diff --git a/hif/src/ce/ce_tasklet.h b/hif/src/ce/ce_tasklet.h index d2fa22c64b..1b158aedfd 100644 --- a/hif/src/ce/ce_tasklet.h +++ b/hif/src/ce/ce_tasklet.h @@ -35,4 +35,6 @@ QDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); irqreturn_t ce_dispatch_interrupt(int irq, struct ce_tasklet_entry *tasklet_entry); +void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state); +void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state); #endif /* __CE_TASKLET_H__ */ diff --git a/hif/src/dispatcher/dummy.c b/hif/src/dispatcher/dummy.c index 71976738f4..db5ff06aee 100644 --- a/hif/src/dispatcher/dummy.c +++ b/hif/src/dispatcher/dummy.c @@ -266,3 +266,21 @@ hif_dummy_mask_interrupt_call(struct hif_softc *hif_sc) { return; } + +/** + * hif_dummy_display_stats - dummy call + * hif_ctx: hif context + * + * Return: none + */ +void hif_dummy_display_stats(struct hif_softc *hif_ctx) +{} + +/** + * hif_dummy_clear_stats - dummy call + * hif_ctx: hif context + * + * Return: none + */ +void hif_dummy_clear_stats(struct hif_softc *hif_ctx) +{} diff --git a/hif/src/dispatcher/dummy.h b/hif/src/dispatcher/dummy.h index a4d0141cc0..a44db04703 100644 --- a/hif/src/dispatcher/dummy.h +++ b/hif/src/dispatcher/dummy.h @@ -53,3 +53,5 @@ void hif_dummy_ipa_get_ce_resource(struct hif_softc *hif_sc, uint32_t *sr_ring_size, qdf_dma_addr_t *reg_paddr); void hif_dummy_mask_interrupt_call(struct hif_softc *hif_sc); +void hif_dummy_display_stats(struct hif_softc *hif_ctx); +void hif_dummy_clear_stats(struct hif_softc *hif_ctx); diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c index e084080519..215c8299e1 100644 --- a/hif/src/dispatcher/multibus.c +++ b/hif/src/dispatcher/multibus.c @@ -36,6 +36,8 @@ #endif #include "htc_services.h" #include "a_types.h" +#include "dummy.h" + /** * hif_intialize_default_ops() - intializes default operations values * @@ -49,6 +51,10 @@ static void hif_intialize_default_ops(struct hif_softc *hif_sc) bus_ops->hif_bus_close = NULL; /* dummy implementations */ + bus_ops->hif_display_stats = + &hif_dummy_display_stats; + bus_ops->hif_clear_stats = + &hif_dummy_clear_stats; } #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *)) @@ -296,6 +302,20 @@ void hif_mask_interrupt_call(struct hif_opaque_softc *hif_hdl) hif_sc->bus_ops.hif_mask_interrupt_call(hif_sc); } +void hif_display_bus_stats(struct hif_opaque_softc *scn) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + + hif_sc->bus_ops.hif_display_stats(hif_sc); +} + +void hif_clear_bus_stats(struct hif_opaque_softc *scn) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + + hif_sc->bus_ops.hif_clear_stats(hif_sc); +} + /** * hif_enable_power_management() - enable power management after driver load * @hif_hdl: opaque pointer to the hif context diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h index ef3b95d91d..5dd845f0c6 100644 --- a/hif/src/dispatcher/multibus.h +++ b/hif/src/dispatcher/multibus.h @@ -72,6 +72,8 @@ struct hif_bus_ops { void (*hif_enable_power_management)(struct hif_softc *hif_ctx, bool is_packet_log_enabled); void (*hif_disable_power_management)(struct hif_softc *hif_ctx); + void (*hif_display_stats)(struct hif_softc *hif_ctx); + void (*hif_clear_stats)(struct hif_softc *hif_ctx); }; #ifdef HIF_SNOC diff --git a/hif/src/dispatcher/multibus_pci.c b/hif/src/dispatcher/multibus_pci.c index a5f8919384..5459105158 100644 --- a/hif/src/dispatcher/multibus_pci.c +++ b/hif/src/dispatcher/multibus_pci.c @@ -81,7 +81,10 @@ QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc) &hif_pci_enable_power_management; bus_ops->hif_disable_power_management = &hif_pci_disable_power_management; - + bus_ops->hif_display_stats = + &hif_pci_display_stats; + bus_ops->hif_clear_stats = + &hif_pci_clear_stats; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/multibus_snoc.c b/hif/src/dispatcher/multibus_snoc.c index f58ef19d3f..d2de51262d 100644 --- a/hif/src/dispatcher/multibus_snoc.c +++ b/hif/src/dispatcher/multibus_snoc.c @@ -72,6 +72,10 @@ QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *bus_ops) &hif_dummy_enable_power_management; bus_ops->hif_disable_power_management = &hif_dummy_disable_power_management; + bus_ops->hif_display_stats = + &hif_snoc_display_stats; + bus_ops->hif_clear_stats = + &hif_snoc_clear_stats; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/dispatcher/pci_api.h b/hif/src/dispatcher/pci_api.h index 0715c0b300..d895a00135 100644 --- a/hif/src/dispatcher/pci_api.h +++ b/hif/src/dispatcher/pci_api.h @@ -49,3 +49,5 @@ int hif_pci_dump_registers(struct hif_softc *scn); void hif_pci_enable_power_management(struct hif_softc *hif_ctx, bool is_packet_log_enabled); void hif_pci_disable_power_management(struct hif_softc *hif_ctx); +void hif_pci_display_stats(struct hif_softc *hif_ctx); +void hif_pci_clear_stats(struct hif_softc *hif_ctx); diff --git a/hif/src/dispatcher/snoc_api.h b/hif/src/dispatcher/snoc_api.h index d8bcbd9e8f..ec7902fa02 100644 --- a/hif/src/dispatcher/snoc_api.h +++ b/hif/src/dispatcher/snoc_api.h @@ -41,3 +41,5 @@ int hif_snoc_bus_configure(struct hif_softc *scn); void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id); void hif_snoc_irq_enable(struct hif_softc *scn, int ce_id); int hif_snoc_dump_registers(struct hif_softc *scn); +void hif_snoc_display_stats(struct hif_softc *hif_ctx); +void hif_snoc_clear_stats(struct hif_softc *hif_ctx); diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index dcc9ea76ac..624874a5d7 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -489,6 +489,15 @@ void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type) HIF_INFO("%s: X", __func__); } +void hif_display_stats(struct hif_opaque_softc *hif_ctx) +{ + hif_display_bus_stats(hif_ctx); +} + +void hif_clear_stats(struct hif_opaque_softc *hif_ctx) +{ + hif_clear_bus_stats(hif_ctx); +} /** * hif_crash_shutdown_dump_bus_register() - dump bus registers diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index fffe945c3e..371f99fd02 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -161,7 +161,8 @@ static inline bool hif_is_nss_wifi_enabled(struct hif_softc *sc) A_target_id_t hif_get_target_id(struct hif_softc *scn); void hif_dump_pipe_debug_count(struct hif_softc *scn); - +void hif_display_bus_stats(struct hif_opaque_softc *scn); +void hif_clear_bus_stats(struct hif_opaque_softc *scn); bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count); void hif_shutdown_device(struct hif_opaque_softc *hif_ctx); int hif_bus_configure(struct hif_softc *scn); diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 97b69560ef..24f72cd823 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -1325,6 +1325,28 @@ void hif_pci_disable_power_management(struct hif_softc *hif_ctx) hif_pm_runtime_stop(pci_ctx); } +void hif_pci_display_stats(struct hif_softc *hif_ctx) +{ + struct hif_pci_softc *pci_ctx = HIF_GET_PCI_SOFTC(hif_ctx); + + if (pci_ctx == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_display_ce_stats(&pci_ctx->ce_sc); +} + +void hif_pci_clear_stats(struct hif_softc *hif_ctx) +{ + struct hif_pci_softc *pci_ctx = HIF_GET_PCI_SOFTC(hif_ctx); + + if (pci_ctx == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_clear_ce_stats(&pci_ctx->ce_sc); +} + #define ATH_PCI_PROBE_RETRY_MAX 3 /** * hif_bus_open(): hif_bus_open diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index 83c970a6d0..b54e59773c 100644 --- a/hif/src/snoc/if_snoc.c +++ b/hif/src/snoc/if_snoc.c @@ -75,6 +75,28 @@ int hif_snoc_dump_registers(struct hif_softc *hif_ctx) return 0; } +void hif_snoc_display_stats(struct hif_softc *hif_ctx) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + + if (hif_state == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_display_ce_stats(hif_state); +} + +void hif_snoc_clear_stats(struct hif_softc *hif_ctx) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + + if (hif_state == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_clear_ce_stats(hif_state); +} + /** * hif_snoc_close(): hif_bus_close * diff --git a/qdf/inc/qdf_util.h b/qdf/inc/qdf_util.h index e724470f2a..588e55544f 100644 --- a/qdf/inc/qdf_util.h +++ b/qdf/inc/qdf_util.h @@ -35,6 +35,12 @@ #include +#ifdef QCA_CONFIG_SMP +#define QDF_MAX_AVAILABLE_CPU 8 +#else +#define QDF_MAX_AVAILABLE_CPU 1 +#endif + /** * qdf_unlikely - Compiler-dependent macro denoting code likely to execute * @_expr: expression to be checked @@ -409,4 +415,10 @@ static inline int qdf_get_pwr2(int value) return 1 << log2; } +static inline +int qdf_get_cpu(void) +{ + return __qdf_get_cpu(); +} + #endif /*_QDF_UTIL_H*/ diff --git a/qdf/linux/src/i_qdf_util.h b/qdf/linux/src/i_qdf_util.h index c045fb8762..f11f7c6740 100644 --- a/qdf/linux/src/i_qdf_util.h +++ b/qdf/linux/src/i_qdf_util.h @@ -248,4 +248,27 @@ static inline bool __qdf_is_macaddr_equal(struct qdf_mac_addr *mac_addr1, #define __qdf_mb() mb() #define __qdf_roundup(x, y) roundup(x, y) + +#ifdef QCA_CONFIG_SMP +/** + * __qdf_get_cpu() - get cpu_index + * + * Return: cpu_index + */ +static inline +int __qdf_get_cpu(void) +{ + int cpu_index = get_cpu(); + + put_cpu(); + return cpu_index; +} +#else +static inline +int __qdf_get_cpu(void) +{ + return 0; +} +#endif + #endif /*_I_QDF_UTIL_H*/