diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index b999bc4d532d..1b3062577945 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -31,7 +31,8 @@ #define UFSHCD_ENABLE_MCQ_INTRS (UTP_TASK_REQ_COMPL |\ UFSHCD_ERROR_MASK |\ - MCQ_CQ_EVENT_STATUS) + MCQ_CQ_EVENT_STATUS |\ + MCQ_IAG_EVENT_STATUS) /* Max mcq register polling time in microseconds */ #define MCQ_POLL_US 500000 @@ -272,6 +273,16 @@ void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i) } EXPORT_SYMBOL_GPL(ufshcd_mcq_write_cqis); +u32 ufshcd_mcq_read_mcqiacr(struct ufs_hba *hba, int i) +{ + return readl(mcq_opr_base(hba, OPR_CQIS, i) + REG_MCQIACR); +} + +void ufshcd_mcq_write_mcqiacr(struct ufs_hba *hba, u32 val, int i) +{ + writel(val, mcq_opr_base(hba, OPR_CQIS, i) + REG_MCQIACR); +} + /* * UFSHCI 4.0 MCQ specification doesn't provide a Task Tag or its equivalent in * the Completion Queue Entry. Find the Task Tag using an indirect method. diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 37c32071e754..6d3d14e883b8 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -76,6 +76,8 @@ void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba, bool ufshcd_cmd_inflight(struct scsi_cmnd *cmd); int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag); int ufshcd_mcq_abort(struct scsi_cmnd *cmd); +u32 ufshcd_mcq_read_mcqiacr(struct ufs_hba *hba, int i); +void ufshcd_mcq_write_mcqiacr(struct ufs_hba *hba, u32 val, int i); int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag); void ufshcd_release_scsi_cmd(struct ufs_hba *hba, struct scsi_cmnd *cmd); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index cf7f0ae46f75..54ad34a4c4ef 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7096,16 +7096,17 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba) /** * ufshcd_handle_mcq_cq_events - handle MCQ completion queue events * @hba: per adapter instance + * @reset_iag: true, to reset MCQ IAG counter and timer of the CQ * * Return: IRQ_HANDLED if interrupt is handled. */ -static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba) +static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba, bool reset_iag) { struct ufs_hw_queue *hwq; unsigned long outstanding_cqs; unsigned int nr_queues; int i, ret; - u32 events; + u32 events, reg; ret = ufshcd_vops_get_outstanding_cqs(hba, &outstanding_cqs); if (ret) @@ -7120,6 +7121,12 @@ static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba) if (events) ufshcd_mcq_write_cqis(hba, events, i); + if (reset_iag) { + reg = ufshcd_mcq_read_mcqiacr(hba, i); + reg |= INT_AGGR_COUNTER_AND_TIMER_RESET; + ufshcd_mcq_write_mcqiacr(hba, reg, i); + } + if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS) ufshcd_mcq_poll_cqe_lock(hba, hwq); } @@ -7153,7 +7160,10 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) retval |= ufshcd_transfer_req_compl(hba); if (intr_status & MCQ_CQ_EVENT_STATUS) - retval |= ufshcd_handle_mcq_cq_events(hba); + retval |= ufshcd_handle_mcq_cq_events(hba, false); + + if (intr_status & MCQ_IAG_EVENT_STATUS) + retval |= ufshcd_handle_mcq_cq_events(hba, true); return retval; } diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 49a3a279e448..9f0fdd850e54 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -115,6 +115,7 @@ enum { enum { REG_CQIS = 0x0, REG_CQIE = 0x4, + REG_MCQIACR = 0x8, }; enum { @@ -188,6 +189,7 @@ static inline u32 ufshci_version(u32 major, u32 minor) #define SYSTEM_BUS_FATAL_ERROR 0x20000 #define CRYPTO_ENGINE_FATAL_ERROR 0x40000 #define MCQ_CQ_EVENT_STATUS 0x100000 +#define MCQ_IAG_EVENT_STATUS 0x200000 #define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\ UIC_HIBERNATE_EXIT)