scsi: ufs: introduce the capability and quirk for interrupt aggregation
authorYaniv Gardi <ygardi@codeaurora.org>
Sun, 17 May 2015 15:54:57 +0000 (18:54 +0300)
committerJames Bottomley <JBottomley@Odin.com>
Tue, 2 Jun 2015 20:08:09 +0000 (13:08 -0700)
UFS HCI (Host Controller Interface) allows the transfer requests
interrupts to be aggregated to generate the single interrupt but
this can impact the performance. Hence introduce the capability which
gives choice to use the interrupt aggregation capability or not.
By default interrupt aggregation capability is kept disabled.

This change also introduces a quirk for broken interrupt aggregation
feature, as in some UFS controllers, this feature may not work.

Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
Reviewed-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index 648a446758801ab6ff338d1dd9e5b5ab052df0da..9641bcb90cd28b8ab9897c6874e1e80b128341b1 100644 (file)
@@ -480,6 +480,15 @@ ufshcd_config_intr_aggr(struct ufs_hba *hba, u8 cnt, u8 tmout)
                      REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
 }
 
+/**
+ * ufshcd_disable_intr_aggr - Disables interrupt aggregation.
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba)
+{
+       ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
 /**
  * ufshcd_enable_run_stop_reg - Enable run-stop registers,
  *                     When run-stop registers are set to 1, it indicates the
@@ -1326,7 +1335,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        lrbp->sense_buffer = cmd->sense_buffer;
        lrbp->task_tag = tag;
        lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
-       lrbp->intr_cmd = false;
+       lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
        lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
        /* form UPIU before issuing the command */
@@ -2522,7 +2531,10 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
        ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
        /* Configure interrupt aggregation */
-       ufshcd_config_intr_aggr(hba, hba->nutrs - 1, INT_AGGR_DEF_TO);
+       if (ufshcd_is_intr_aggr_allowed(hba))
+               ufshcd_config_intr_aggr(hba, hba->nutrs - 1, INT_AGGR_DEF_TO);
+       else
+               ufshcd_disable_intr_aggr(hba);
 
        /* Configure UTRL and UTMRL base address registers */
        ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
@@ -3073,7 +3085,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
         * false interrupt if device completes another request after resetting
         * aggregation and before reading the DB.
         */
-       ufshcd_reset_intr_aggr(hba);
+       if (ufshcd_is_intr_aggr_allowed(hba))
+               ufshcd_reset_intr_aggr(hba);
 
        tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
index b47ff07698e80aa9119633568324e009da5217be..fc8bec9960b1dce97012f64cbcd37ceab000f9bf 100644 (file)
@@ -417,11 +417,15 @@ struct ufs_hba {
        unsigned int irq;
        bool is_irq_enabled;
 
+       /* Interrupt aggregation support is broken */
+       #define UFSHCD_QUIRK_BROKEN_INTR_AGGR                   UFS_BIT(0)
+
        /*
         * delay before each dme command is required as the unipro
         * layer has shown instabilities
         */
-       #define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS              UFS_BIT(0)
+       #define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS              UFS_BIT(1)
+
 
        unsigned int quirks;    /* Deviations from standard UFSHCI spec. */
 
@@ -478,6 +482,12 @@ struct ufs_hba {
 #define UFSHCD_CAP_CLK_SCALING (1 << 2)
        /* Allow auto bkops to enabled during runtime suspend */
 #define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1 << 3)
+       /*
+        * This capability allows host controller driver to use the UFS HCI's
+        * interrupt aggregation capability.
+        * CAUTION: Enabling this might reduce overall UFS throughput.
+        */
+#define UFSHCD_CAP_INTR_AGGR (1 << 4)
 
        struct devfreq *devfreq;
        struct ufs_clk_scaling clk_scaling;
@@ -502,6 +512,15 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
        return hba->caps & UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
 }
 
+static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba)
+{
+       if ((hba->caps & UFSHCD_CAP_INTR_AGGR) &&
+           !(hba->quirks & UFSHCD_QUIRK_BROKEN_INTR_AGGR))
+               return true;
+       else
+               return false;
+}
+
 #define ufshcd_writel(hba, val, reg)   \
        writel((val), (hba)->mmio_base + (reg))
 #define ufshcd_readl(hba, reg) \