qcacmn: Schedule CE tasklet when resource runs out

If there is no resourse to send packet via HTC, then check if interrupts
are not processed from that CE for last 3 seconds. If so, schedule a
tasklet to reap available entries. Also if Queue has reached 1024 entries
within 3 seconds, then also schedule tasklet.

This change is added because there is a case where intermittently
completion interrupts are not received from CE3 and hence adding
this WAR in host to come out of this issue scenario.

Change-Id: I126cd5e678517127659237308f8f6b1313f8f422
CRs-Fixed: 3234943
This commit is contained in:
Nandha Kishore Easwaran
2022-06-06 17:04:05 +05:30
committed by Madan Koyyalamudi
parent 053f59e4f0
commit 93bf7e1fb1
5 changed files with 68 additions and 1 deletions

View File

@@ -2855,6 +2855,39 @@ void hif_send_complete_check(struct hif_opaque_softc *hif_ctx, uint8_t pipe,
#endif
}
#if defined(CE_TASKLET_SCHEDULE_ON_FULL) && defined(CE_TASKLET_DEBUG_ENABLE)
#define CE_RING_FULL_THRESHOLD_TIME 3000000
#define CE_RING_FULL_THRESHOLD 1024
/* Ths function is called from htc_send path. If there is no resourse to send
* packet via HTC, then check if interrupts are not processed from that
* CE for last 3 seconds. If so, schedule a tasklet to reap available entries.
* Also if Queue has reached 1024 entries within 3 seconds, then also schedule
* tasklet.
*/
void hif_schedule_ce_tasklet(struct hif_opaque_softc *hif_ctx, uint8_t pipe)
{
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
uint64_t diff_time = qdf_get_log_timestamp_usecs() -
hif_state->stats.tasklet_sched_entry_ts[pipe];
hif_state->stats.ce_ring_full_count[pipe]++;
if (diff_time >= CE_RING_FULL_THRESHOLD_TIME ||
hif_state->stats.ce_ring_full_count[pipe] >=
CE_RING_FULL_THRESHOLD) {
hif_state->stats.ce_ring_full_count[pipe] = 0;
hif_state->stats.ce_manual_tasklet_schedule_count[pipe]++;
hif_state->stats.ce_last_manual_tasklet_schedule_ts[pipe] =
qdf_get_log_timestamp_usecs();
ce_dispatch_interrupt(pipe, &hif_state->tasklets[pipe]);
}
}
#else
void hif_schedule_ce_tasklet(struct hif_opaque_softc *hif_ctx, uint8_t pipe)
{
}
#endif
uint16_t
hif_get_free_queue_number(struct hif_opaque_softc *hif_ctx, uint8_t pipe)
{

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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
@@ -192,6 +193,11 @@ struct ce_stats {
uint64_t ce_tasklet_sched_bucket[CE_COUNT_MAX][CE_BUCKET_MAX];
uint64_t ce_tasklet_exec_last_update[CE_COUNT_MAX][CE_BUCKET_MAX];
uint64_t ce_tasklet_sched_last_update[CE_COUNT_MAX][CE_BUCKET_MAX];
#ifdef CE_TASKLET_SCHEDULE_ON_FULL
uint32_t ce_ring_full_count[CE_COUNT_MAX];
uint32_t ce_manual_tasklet_schedule_count[CE_COUNT_MAX];
uint64_t ce_last_manual_tasklet_schedule_ts[CE_COUNT_MAX];
#endif
#endif
};

View File

@@ -340,6 +340,28 @@ hif_ce_latency_stats(struct hif_softc *hif_ctx)
}
#endif /*CE_TASKLET_DEBUG_ENABLE*/
#if defined(CE_TASKLET_DEBUG_ENABLE) && defined(CE_TASKLET_SCHEDULE_ON_FULL)
/**
* hif_reset_ce_full_count() - Reset ce full count
* @scn: hif_softc
* @ce_id: ce_id
*
* Return: None
*/
static inline void
hif_reset_ce_full_count(struct hif_softc *scn, uint8_t ce_id)
{
struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn);
hif_ce_state->stats.ce_ring_full_count[ce_id] = 0;
}
#else
static inline void
hif_reset_ce_full_count(struct hif_softc *scn, uint8_t ce_id)
{
}
#endif
#ifdef HIF_DETECTION_LATENCY_ENABLE
static inline
void hif_latency_detect_tasklet_sched(
@@ -429,6 +451,7 @@ static void ce_tasklet(unsigned long data)
ce_tasklet_schedule(tasklet_entry);
hif_latency_detect_tasklet_sched(scn, tasklet_entry);
hif_reset_ce_full_count(scn, tasklet_entry->ce_id);
if (scn->ce_latency_stats) {
ce_tasklet_update_bucket(hif_ce_state,
tasklet_entry->ce_id);
@@ -697,6 +720,7 @@ static inline bool hif_tasklet_schedule(struct hif_opaque_softc *hif_ctx,
hif_latency_detect_tasklet_sched(scn, tasklet_entry);
ce_tasklet_schedule(tasklet_entry);
hif_reset_ce_full_count(scn, tasklet_entry->ce_id);
if (scn->ce_latency_stats)
hif_record_tasklet_sched_entry_ts(scn, tasklet_entry->ce_id);