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:

committad av
Madan Koyyalamudi

förälder
277054124d
incheckning
053f59e4f0
@@ -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
|
||||
|
Referens i nytt ärende
Block a user