mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
ath11k: dump SRNG stats during FW assert
Dumping the SRNG stats during FW assert, this would help in debugging ring stuck issues. Co-developed-by: Karthikeyan Periyasamy <periyasa@codeaurora.org> Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org> Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
de06b2f751
commit
5118935b1b
6 changed files with 82 additions and 2 deletions
|
@ -681,6 +681,9 @@ static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
|
||||||
{
|
{
|
||||||
struct ath11k_ce_pipe *ce_pipe = arg;
|
struct ath11k_ce_pipe *ce_pipe = arg;
|
||||||
|
|
||||||
|
/* last interrupt received for this CE */
|
||||||
|
ce_pipe->timestamp = jiffies;
|
||||||
|
|
||||||
ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
|
ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
|
||||||
|
|
||||||
tasklet_schedule(&ce_pipe->intr_tq);
|
tasklet_schedule(&ce_pipe->intr_tq);
|
||||||
|
@ -712,6 +715,9 @@ static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
|
||||||
{
|
{
|
||||||
struct ath11k_ext_irq_grp *irq_grp = arg;
|
struct ath11k_ext_irq_grp *irq_grp = arg;
|
||||||
|
|
||||||
|
/* last interrupt received for this group */
|
||||||
|
irq_grp->timestamp = jiffies;
|
||||||
|
|
||||||
ath11k_ahb_ext_grp_disable(irq_grp);
|
ath11k_ahb_ext_grp_disable(irq_grp);
|
||||||
|
|
||||||
napi_schedule(&irq_grp->napi);
|
napi_schedule(&irq_grp->napi);
|
||||||
|
|
|
@ -161,6 +161,7 @@ struct ath11k_ce_pipe {
|
||||||
struct ath11k_ce_ring *src_ring;
|
struct ath11k_ce_ring *src_ring;
|
||||||
struct ath11k_ce_ring *dest_ring;
|
struct ath11k_ce_ring *dest_ring;
|
||||||
struct ath11k_ce_ring *status_ring;
|
struct ath11k_ce_ring *status_ring;
|
||||||
|
u64 timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath11k_ce {
|
struct ath11k_ce {
|
||||||
|
|
|
@ -110,6 +110,7 @@ struct ath11k_ext_irq_grp {
|
||||||
u32 irqs[ATH11K_EXT_IRQ_NUM_MAX];
|
u32 irqs[ATH11K_EXT_IRQ_NUM_MAX];
|
||||||
u32 num_irq;
|
u32 num_irq;
|
||||||
u32 grp_id;
|
u32 grp_id;
|
||||||
|
u64 timestamp;
|
||||||
struct napi_struct napi;
|
struct napi_struct napi;
|
||||||
struct net_device napi_ndev;
|
struct net_device napi_ndev;
|
||||||
/* Queue of pending packets, not expected to be accessed concurrently
|
/* Queue of pending packets, not expected to be accessed concurrently
|
||||||
|
|
|
@ -877,23 +877,32 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng)
|
||||||
/* For LMAC rings, ring pointer updates are done through FW and
|
/* For LMAC rings, ring pointer updates are done through FW and
|
||||||
* hence written to a shared memory location that is read by FW
|
* hence written to a shared memory location that is read by FW
|
||||||
*/
|
*/
|
||||||
if (srng->ring_dir == HAL_SRNG_DIR_SRC)
|
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
|
||||||
|
srng->u.src_ring.last_tp =
|
||||||
|
*(volatile u32 *)srng->u.src_ring.tp_addr;
|
||||||
*srng->u.src_ring.hp_addr = srng->u.src_ring.hp;
|
*srng->u.src_ring.hp_addr = srng->u.src_ring.hp;
|
||||||
else
|
} else {
|
||||||
|
srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr;
|
||||||
*srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp;
|
*srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
|
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
|
||||||
|
srng->u.src_ring.last_tp =
|
||||||
|
*(volatile u32 *)srng->u.src_ring.tp_addr;
|
||||||
ath11k_ahb_write32(ab,
|
ath11k_ahb_write32(ab,
|
||||||
(unsigned long)srng->u.src_ring.hp_addr -
|
(unsigned long)srng->u.src_ring.hp_addr -
|
||||||
(unsigned long)ab->mem,
|
(unsigned long)ab->mem,
|
||||||
srng->u.src_ring.hp);
|
srng->u.src_ring.hp);
|
||||||
} else {
|
} else {
|
||||||
|
srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr;
|
||||||
ath11k_ahb_write32(ab,
|
ath11k_ahb_write32(ab,
|
||||||
(unsigned long)srng->u.dst_ring.tp_addr -
|
(unsigned long)srng->u.dst_ring.tp_addr -
|
||||||
(unsigned long)ab->mem,
|
(unsigned long)ab->mem,
|
||||||
srng->u.dst_ring.tp);
|
srng->u.dst_ring.tp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srng->timestamp = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,
|
void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,
|
||||||
|
@ -1017,6 +1026,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
|
||||||
params->intr_batch_cntr_thres_entries;
|
params->intr_batch_cntr_thres_entries;
|
||||||
srng->intr_timer_thres_us = params->intr_timer_thres_us;
|
srng->intr_timer_thres_us = params->intr_timer_thres_us;
|
||||||
srng->flags = params->flags;
|
srng->flags = params->flags;
|
||||||
|
srng->initialized = 1;
|
||||||
spin_lock_init(&srng->lock);
|
spin_lock_init(&srng->lock);
|
||||||
|
|
||||||
for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) {
|
for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) {
|
||||||
|
@ -1122,3 +1132,55 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab)
|
||||||
ath11k_hal_free_cont_rdp(ab);
|
ath11k_hal_free_cont_rdp(ab);
|
||||||
ath11k_hal_free_cont_wrp(ab);
|
ath11k_hal_free_cont_wrp(ab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ath11k_hal_dump_srng_stats(struct ath11k_base *ab)
|
||||||
|
{
|
||||||
|
struct hal_srng *srng;
|
||||||
|
struct ath11k_ext_irq_grp *irq_grp;
|
||||||
|
struct ath11k_ce_pipe *ce_pipe;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ath11k_err(ab, "Last interrupt received for each CE:\n");
|
||||||
|
for (i = 0; i < CE_COUNT; i++) {
|
||||||
|
ce_pipe = &ab->ce.ce_pipe[i];
|
||||||
|
|
||||||
|
if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ath11k_err(ab, "CE_id %d pipe_num %d %ums before\n",
|
||||||
|
i, ce_pipe->pipe_num,
|
||||||
|
jiffies_to_msecs(jiffies - ce_pipe->timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
ath11k_err(ab, "\nLast interrupt received for each group:\n");
|
||||||
|
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
||||||
|
irq_grp = &ab->ext_irq_grp[i];
|
||||||
|
ath11k_err(ab, "group_id %d %ums before\n",
|
||||||
|
irq_grp->grp_id,
|
||||||
|
jiffies_to_msecs(jiffies - irq_grp->timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < HAL_SRNG_RING_ID_MAX; i++) {
|
||||||
|
srng = &ab->hal.srng_list[i];
|
||||||
|
|
||||||
|
if (!srng->initialized)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (srng->ring_dir == HAL_SRNG_DIR_SRC)
|
||||||
|
ath11k_err(ab,
|
||||||
|
"src srng id %u hp %u, reap_hp %u, cur tp %u, cached tp %u last tp %u napi processed before %ums\n",
|
||||||
|
srng->ring_id, srng->u.src_ring.hp,
|
||||||
|
srng->u.src_ring.reap_hp,
|
||||||
|
*srng->u.src_ring.tp_addr, srng->u.src_ring.cached_tp,
|
||||||
|
srng->u.src_ring.last_tp,
|
||||||
|
jiffies_to_msecs(jiffies - srng->timestamp));
|
||||||
|
else if (srng->ring_dir == HAL_SRNG_DIR_DST)
|
||||||
|
ath11k_err(ab,
|
||||||
|
"dst srng id %u tp %u, cur hp %u, cached hp %u last hp %u napi processed before %ums\n",
|
||||||
|
srng->ring_id, srng->u.dst_ring.tp,
|
||||||
|
*srng->u.dst_ring.hp_addr,
|
||||||
|
srng->u.dst_ring.cached_hp,
|
||||||
|
srng->u.dst_ring.last_hp,
|
||||||
|
jiffies_to_msecs(jiffies - srng->timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -529,6 +529,8 @@ struct hal_srng {
|
||||||
*/
|
*/
|
||||||
u32 hwreg_base[HAL_SRNG_NUM_REG_GRP];
|
u32 hwreg_base[HAL_SRNG_NUM_REG_GRP];
|
||||||
|
|
||||||
|
u64 timestamp;
|
||||||
|
|
||||||
/* Source or Destination ring */
|
/* Source or Destination ring */
|
||||||
enum hal_srng_dir ring_dir;
|
enum hal_srng_dir ring_dir;
|
||||||
|
|
||||||
|
@ -554,6 +556,9 @@ struct hal_srng {
|
||||||
|
|
||||||
/* max transfer size */
|
/* max transfer size */
|
||||||
u16 max_buffer_length;
|
u16 max_buffer_length;
|
||||||
|
|
||||||
|
/* head pointer at access end */
|
||||||
|
u32 last_hp;
|
||||||
} dst_ring;
|
} dst_ring;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -577,6 +582,9 @@ struct hal_srng {
|
||||||
|
|
||||||
/* Low threshold - in number of ring entries */
|
/* Low threshold - in number of ring entries */
|
||||||
u32 low_threshold;
|
u32 low_threshold;
|
||||||
|
|
||||||
|
/* tail pointer at access end */
|
||||||
|
u32 last_tp;
|
||||||
} src_ring;
|
} src_ring;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
@ -893,5 +901,6 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
|
||||||
struct hal_srng_params *params);
|
struct hal_srng_params *params);
|
||||||
int ath11k_hal_srng_init(struct ath11k_base *ath11k);
|
int ath11k_hal_srng_init(struct ath11k_base *ath11k);
|
||||||
void ath11k_hal_srng_deinit(struct ath11k_base *ath11k);
|
void ath11k_hal_srng_deinit(struct ath11k_base *ath11k);
|
||||||
|
void ath11k_hal_dump_srng_stats(struct ath11k_base *ab);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2365,6 +2365,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
|
||||||
break;
|
break;
|
||||||
case ATH11K_QMI_EVENT_FW_READY:
|
case ATH11K_QMI_EVENT_FW_READY:
|
||||||
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
|
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
|
||||||
|
ath11k_hal_dump_srng_stats(ab);
|
||||||
queue_work(ab->workqueue, &ab->restart_work);
|
queue_work(ab->workqueue, &ab->restart_work);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue