]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
scsi: ufs: core: Handle MCQ IAG events
authorvamshi gajjela <vamshigajjela@google.com>
Tue, 10 Mar 2026 19:03:08 +0000 (00:33 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 20 Mar 2026 01:37:09 +0000 (21:37 -0400)
Add support for handling aggregation-based interrupts when operating in MCQ
mode.

In legacy interrupt mode, an IE.IAGES is triggered when the counter or
timer threshold is reached. To manage this, the handler now resets the
aggregation counter and timer by writing to the MCQIACRy.CTR register.

Since the register layout of MCQIACRy is identical to the existing UTRIACR
register, this implementation reuses the previously defined bitfield masks
to maintain consistency and reduce code duplication.

Extend ufshcd_handle_mcq_cq_events() with a boolean iag parameter.  If set,
the handler resets the MCQ IAG counter and timer.

Define MCQ_IAG_EVENT_STATUS (0x200000) and include it in
UFSHCD_ENABLE_MCQ_INTRS to ensure the interrupt is unmasked during
initialization.

Signed-off-by: Vamshi Gajjela <vamshigajjela@google.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20260310190308.2474956-1-vamshigajjela@google.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufs-mcq.c
drivers/ufs/core/ufshcd-priv.h
drivers/ufs/core/ufshcd.c
include/ufs/ufshci.h

index b999bc4d532de50e862b614adc164bbe4af4156d..1b3062577945851a88a49c1355d510319523073f 100644 (file)
@@ -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.
index 37c32071e75402069988c4e0cbe9ecf41edfbfcd..6d3d14e883b8b22df685f155fb7703d59d2ebb6c 100644 (file)
@@ -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);
 
index cf7f0ae46f753d0a7eaeaf658a5904d92473022f..54ad34a4c4efe9bfa051d3e7724d60d5918d87a4 100644 (file)
@@ -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;
 }
index 49a3a279e448c5f7b16b30061a8427d87005a1e5..9f0fdd850e54e4f16b8016fecc2caa3358bb93c2 100644 (file)
@@ -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)