qcacmn: Interrupt handling changes for UMAC HW reset interrupt

Create a HIF context for UMAC reset handler, register the datapath UMAC HW
reset callback handler with HIF layer, request for UMAC HW reset interrupt,
and schedule a high priority tasklet to process the interrupt in which
call the registered DP callback handler.

CRs-Fixed: 3184312
Change-Id: Iefc811bf0d1b093c3c63bf2238c94a1448f4f139
This commit is contained in:
Shiva Krishna Pittala
2022-07-12 00:53:55 +05:30
committed by Madan Koyyalamudi
父節點 277054124d
當前提交 053f59e4f0
共有 5 個文件被更改,包括 288 次插入5 次删除

查看文件

@@ -15,6 +15,7 @@
*/
#include <dp_types.h>
#include <wlan_cfg.h>
#include <hif.h>
/**
* dp_get_umac_reset_intr_ctx() - Get the interrupt context to be used by
@@ -60,6 +61,7 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc)
umac_reset_ctx = &soc->umac_reset_ctx;
qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx));
umac_reset_ctx->supported = true;
umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_PRE_RESET;
status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset);
@@ -89,3 +91,87 @@ QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc)
return QDF_STATUS_SUCCESS;
}
/**
* dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset
* @dp_ctx: Interrupt context corresponding to UMAC reset
*
* Return: 0 incase of success, else failure
*/
static int dp_umac_reset_rx_event_handler(void *dp_ctx)
{
/* Note: This will be implemented in an upcoming change */
return 0;
}
QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc)
{
struct dp_soc_umac_reset_ctx *umac_reset_ctx;
int msi_vector_count, ret;
uint32_t msi_base_data, msi_vector_start;
uint32_t umac_reset_vector, umac_reset_irq;
if (!soc) {
dp_umac_reset_err("DP SOC is null");
return QDF_STATUS_E_NULL_VALUE;
}
umac_reset_ctx = &soc->umac_reset_ctx;
/* return if feature is not supported */
if (!umac_reset_ctx->supported) {
dp_umac_reset_info("UMAC reset is not supported on this SOC");
return QDF_STATUS_SUCCESS;
}
if (pld_get_enable_intx(soc->osdev->dev)) {
dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode");
return QDF_STATUS_E_FAILURE;
}
ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP",
&msi_vector_count, &msi_base_data,
&msi_vector_start);
if (ret) {
dp_umac_reset_err("UMAC reset is only supported in MSI interrupt mode");
return QDF_STATUS_E_FAILURE;
}
if (umac_reset_ctx->intr_offset < 0 ||
umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) {
dp_umac_reset_err("Invalid interrupt offset");
return QDF_STATUS_E_FAILURE;
}
umac_reset_vector = msi_vector_start +
(umac_reset_ctx->intr_offset % msi_vector_count);
/* Get IRQ number */
umac_reset_irq = pld_get_msi_irq(soc->osdev->dev, umac_reset_vector);
/* Finally register to this IRQ from HIF layer */
return hif_register_umac_reset_handler(
soc->hif_handle,
dp_umac_reset_rx_event_handler,
&soc->intr_ctx[umac_reset_ctx->intr_offset],
umac_reset_irq);
}
QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc)
{
struct dp_soc_umac_reset_ctx *umac_reset_ctx;
if (!soc) {
dp_umac_reset_err("DP SOC is null");
return QDF_STATUS_E_NULL_VALUE;
}
umac_reset_ctx = &soc->umac_reset_ctx;
/* return if feature is not supported */
if (!umac_reset_ctx->supported) {
dp_umac_reset_info("UMAC reset is not supported on this SOC");
return QDF_STATUS_SUCCESS;
}
return hif_unregister_umac_reset_handler(soc->hif_handle);
}

查看文件

@@ -17,10 +17,10 @@
#ifndef _DP_UMAC_RESET_H_
#define _DP_UMAC_RESET_H_
#ifdef DP_UMAC_HW_RESET_SUPPORT
#include <qdf_types.h>
struct dp_soc;
#ifdef DP_UMAC_HW_RESET_SUPPORT
#define dp_umac_reset_alert(params...) \
QDF_TRACE_FATAL(QDF_MODULE_ID_DP_UMAC_RESET, params)
#define dp_umac_reset_err(params...) \
@@ -35,8 +35,6 @@
QDF_TRACE_DEBUG(QDF_MODULE_ID_DP_UMAC_RESET, params)
#define DP_UMAC_RESET_SHMEM_ALIGN 8
struct dp_soc;
/**
* enum umac_reset_state - States required for UMAC reset state machine
* @UMAC_RESET_STATE_WAIT_FOR_PRE_RESET: Waiting for the PRE_RESET event
@@ -75,6 +73,7 @@ struct umac_reset_shmem {
* @shmem_vaddr_aligned: Virtual address of the shared memory (aligned)
* @intr_offset: Offset of the UMAC reset interrupt w.r.t DP base interrupt
* @current_state: current state of the UMAC reset state machine
* @supported: Whether UMAC reset is supported on this soc
*/
struct dp_soc_umac_reset_ctx {
qdf_dma_addr_t shmem_paddr_unaligned;
@@ -83,6 +82,7 @@ struct dp_soc_umac_reset_ctx {
struct umac_reset_shmem *shmem_vaddr_aligned;
int intr_offset;
enum umac_reset_state current_state;
bool supported;
};
/**
@@ -92,5 +92,27 @@ struct dp_soc_umac_reset_ctx {
* Return: QDF status of operation
*/
QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc);
/**
* dp_umac_reset_interrupt_attach() - Register handlers for UMAC reset interrupt
* @soc: DP soc object
*
* Return: QDF status of operation
*/
QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc);
/**
* dp_umac_reset_interrupt_detach() - Unregister UMAC reset interrupt handlers
* @soc: DP soc object
*
* Return: QDF status of operation
*/
QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc);
#else
static inline
QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc)
{
return QDF_STATUS_SUCCESS;
}
#endif /* DP_UMAC_HW_RESET_SUPPORT */
#endif /* _DP_UMAC_RESET_H_ */

查看文件

@@ -2349,4 +2349,43 @@ void hif_set_grp_intr_affinity(struct hif_opaque_softc *scn,
* uint8_t: count for WMI eps in target svc map
*/
uint8_t hif_get_max_wmi_ep(struct hif_opaque_softc *scn);
#ifdef DP_UMAC_HW_RESET_SUPPORT
/**
* hif_register_umac_reset_handler() - Register UMAC HW reset handler
* @hif_scn: hif opaque handle
* @handler: callback handler function
* @cb_ctx: context to passed to @handler
* @irq: irq number to be used for UMAC HW reset interrupt
*
* Return: QDF_STATUS of operation
*/
QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn,
int (*handler)(void *cb_ctx),
void *cb_ctx, int irq);
/**
* hif_unregister_umac_reset_handler() - Unregister UMAC HW reset handler
* @hif_scn: hif opaque handle
*
* Return: QDF_STATUS of operation
*/
QDF_STATUS hif_unregister_umac_reset_handler(struct hif_opaque_softc *hif_scn);
#else
static inline
QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn,
int (*handler)(void *cb_ctx),
void *cb_ctx, int irq)
{
return QDF_STATUS_SUCCESS;
}
static inline
QDF_STATUS hif_unregister_umac_reset_handler(struct hif_opaque_softc *hif_scn)
{
return QDF_STATUS_SUCCESS;
}
#endif /* DP_UMAC_HW_RESET_SUPPORT */
#endif /* _HIF_H_ */

查看文件

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-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
@@ -21,6 +21,8 @@
#include <ce_main.h>
#include "qdf_module.h"
#include "qdf_net_if.h"
#include <pld_common.h>
/* mapping NAPI budget 0 to internal budget 0
* NAPI budget 1 to internal budget [1,scaler -1]
* NAPI budget 2 to internal budget [scaler, 2 * scaler - 1], etc
@@ -1129,3 +1131,116 @@ void hif_deregister_exec_group(struct hif_opaque_softc *hif_ctx,
}
}
qdf_export_symbol(hif_deregister_exec_group);
#ifdef DP_UMAC_HW_RESET_SUPPORT
/**
* hif_umac_reset_handler_tasklet() - Tasklet for UMAC HW reset interrupt
* @data: UMAC HW reset HIF context
*
* return: void
*/
static void hif_umac_reset_handler_tasklet(unsigned long data)
{
struct hif_umac_reset_ctx *umac_reset_ctx =
(struct hif_umac_reset_ctx *)data;
/* call the callback handler */
umac_reset_ctx->cb_handler(umac_reset_ctx->cb_ctx);
}
/**
* hif_umac_reset_irq_handler() - Interrupt service routine of UMAC HW reset
* @irq: irq coming from kernel
* @ctx: UMAC HW reset HIF context
*
* return: IRQ_HANDLED if success, else IRQ_NONE
*/
static irqreturn_t hif_umac_reset_irq_handler(int irq, void *ctx)
{
struct hif_umac_reset_ctx *umac_reset_ctx = ctx;
/* Schedule the tasklet and exit */
tasklet_hi_schedule(&umac_reset_ctx->intr_tq);
return IRQ_HANDLED;
}
QDF_STATUS hif_register_umac_reset_handler(struct hif_opaque_softc *hif_scn,
int (*handler)(void *cb_ctx),
void *cb_ctx, int irq)
{
struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_scn);
struct hif_umac_reset_ctx *umac_reset_ctx;
int ret;
if (!hif_sc) {
hif_err("scn is null");
return QDF_STATUS_E_NULL_VALUE;
}
umac_reset_ctx = &hif_sc->umac_reset_ctx;
umac_reset_ctx->cb_handler = handler;
umac_reset_ctx->cb_ctx = cb_ctx;
umac_reset_ctx->os_irq = irq;
/* Init the tasklet */
tasklet_init(&umac_reset_ctx->intr_tq,
hif_umac_reset_handler_tasklet,
(unsigned long)umac_reset_ctx);
/* Register the interrupt handler */
ret = pfrm_request_irq(hif_sc->qdf_dev->dev, irq,
hif_umac_reset_irq_handler,
IRQF_SHARED | IRQF_NO_SUSPEND,
"umac_hw_reset_irq",
umac_reset_ctx);
if (ret) {
hif_err("request_irq failed: %d", ret);
return qdf_status_from_os_return(ret);
}
umac_reset_ctx->irq_configured = true;
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(hif_register_umac_reset_handler);
QDF_STATUS hif_unregister_umac_reset_handler(struct hif_opaque_softc *hif_scn)
{
struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_scn);
struct hif_umac_reset_ctx *umac_reset_ctx;
int ret;
if (!hif_sc) {
hif_err("scn is null");
return QDF_STATUS_E_NULL_VALUE;
}
umac_reset_ctx = &hif_sc->umac_reset_ctx;
if (!umac_reset_ctx->irq_configured) {
hif_err("unregister called without a prior IRQ configuration");
return QDF_STATUS_E_FAILURE;
}
ret = pfrm_free_irq(hif_sc->qdf_dev->dev,
umac_reset_ctx->os_irq,
umac_reset_ctx);
if (ret) {
hif_err("free_irq failed: %d", ret);
return qdf_status_from_os_return(ret);
}
umac_reset_ctx->irq_configured = false;
tasklet_disable(&umac_reset_ctx->intr_tq);
tasklet_kill(&umac_reset_ctx->intr_tq);
umac_reset_ctx->cb_handler = NULL;
umac_reset_ctx->cb_ctx = NULL;
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(hif_unregister_umac_reset_handler);
#endif

查看文件

@@ -204,6 +204,24 @@ struct hif_cfg {
uint8_t ce_status_ring_batch_count_threshold;
};
#ifdef DP_UMAC_HW_RESET_SUPPORT
/**
* struct hif_umac_reset_ctx - UMAC HW reset context at HIF layer
* @intr_tq: Tasklet structure
* @cb_handler: Callback handler
* @cb_ctx: Argument to be passed to @cb_handler
* @os_irq: Interrupt number for this IRQ
* @irq_configured: Whether the IRQ has been configured
*/
struct hif_umac_reset_ctx {
struct tasklet_struct intr_tq;
int (*cb_handler)(void *cb_ctx);
void *cb_ctx;
uint32_t os_irq;
bool irq_configured;
};
#endif
struct hif_softc {
struct hif_opaque_softc osc;
struct hif_config_info hif_config;
@@ -323,6 +341,9 @@ struct hif_softc {
uint64_t cmem_start;
/* CMEM size target reserved */
uint64_t cmem_size;
#ifdef DP_UMAC_HW_RESET_SUPPORT
struct hif_umac_reset_ctx umac_reset_ctx;
#endif
};
static inline