It makes interrupt setting more flexible especially for disabling. And wrong bit mask is fixed for ver 1.0. [17:16] is added for mask. Signed-off-by: Seungwon Jeon <tgih.jun@xxxxxxxxxxx> Tested-by: Maya Erez <merez@xxxxxxxxxxxxxx> --- drivers/scsi/ufs/ufshcd.c | 84 +++++++++++++++++++++++++++++++------------- drivers/scsi/ufs/ufshcd.h | 4 +- drivers/scsi/ufs/ufshci.h | 5 ++- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index cf7c8e4..feaf221 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -35,6 +35,10 @@ #include "ufshcd.h" +#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ + UTP_TASK_REQ_COMPL |\ + UFSHCD_ERROR_MASK) + enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, @@ -64,6 +68,20 @@ enum { }; /** + * ufshcd_get_intr_mask - Get the interrupt bit mask + * @hba - Pointer to adapter instance + * + * Returns interrupt bit mask per version + */ +static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) +{ + if (hba->ufs_version == UFSHCI_VERSION_10) + return INTERRUPT_MASK_ALL_VER_10; + else + return INTERRUPT_MASK_ALL_VER_11; +} + +/** * ufshcd_get_ufs_version - Get the UFS version supported by the HBA * @hba - Pointer to adapter instance * @@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp) } /** - * ufshcd_int_config - enable/disable interrupts + * ufshcd_enable_intr - enable interrupts * @hba: per adapter instance - * @option: interrupt option + * @intrs: interrupt bits */ -static void ufshcd_int_config(struct ufs_hba *hba, u32 option) +static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) { - switch (option) { - case UFSHCD_INT_ENABLE: - ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE); - break; - case UFSHCD_INT_DISABLE: - if (hba->ufs_version == UFSHCI_VERSION_10) - ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10, - REG_INTERRUPT_ENABLE); - else - ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11, - REG_INTERRUPT_ENABLE); - break; + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + + if (hba->ufs_version == UFSHCI_VERSION_10) { + u32 rw; + rw = set & INTERRUPT_MASK_RW_VER_10; + set = rw | ((set ^ intrs) & intrs); + } else { + set |= intrs; + } + + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); +} + +/** + * ufshcd_disable_intr - disable interrupts + * @hba: per adapter instance + * @intrs: interrupt bits + */ +static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs) +{ + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + + if (hba->ufs_version == UFSHCI_VERSION_10) { + u32 rw; + rw = (set & INTERRUPT_MASK_RW_VER_10) & + ~(intrs & INTERRUPT_MASK_RW_VER_10); + set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10); + + } else { + set &= ~intrs; } + + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); } /** @@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) uic_cmd->argument3 = 0; /* enable UIC related interrupts */ - hba->int_enable_mask |= UIC_COMMAND_COMPL; - ufshcd_int_config(hba, UFSHCD_INT_ENABLE); + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); /* sending UIC commands to controller */ ufshcd_send_uic_command(hba, uic_cmd); @@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba) } /* Enable required interrupts */ - hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL | - UIC_ERROR | - UTP_TASK_REQ_COMPL | - DEVICE_FATAL_ERROR | - CONTROLLER_FATAL_ERROR | - SYSTEM_BUS_FATAL_ERROR); - ufshcd_int_config(hba, UFSHCD_INT_ENABLE); + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS); /* Configure interrupt aggregation */ ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG); @@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba) void ufshcd_remove(struct ufs_hba *hba) { /* disable interrupts */ - ufshcd_int_config(hba, UFSHCD_INT_DISABLE); + ufshcd_disable_intr(hba, hba->intr_mask); ufshcd_hba_stop(hba); ufshcd_hba_free(hba); @@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle, /* Get UFS version supported by the controller */ hba->ufs_version = ufshcd_get_ufs_version(hba); + /* Get Interrupt bit mask per version */ + hba->intr_mask = ufshcd_get_intr_mask(hba); + /* Allocate memory for host memory space */ err = ufshcd_memory_alloc(hba); if (err) { diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 6429bed..d98e046 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -153,7 +153,7 @@ struct ufs_query { * @ufshcd_tm_wait_queue: wait queue for task management * @tm_condition: condition variable for task management * @ufshcd_state: UFSHCD states - * @int_enable_mask: Interrupt Mask Bits + * @intr_mask: Interrupt Mask Bits * @uic_workq: Work queue for UIC completion handling * @feh_workq: Work queue for fatal controller error handling * @errors: HBA errors @@ -191,7 +191,7 @@ struct ufs_hba { unsigned long tm_condition; u32 ufshcd_state; - u32 int_enable_mask; + u32 intr_mask; /* Work Queues */ struct work_struct uic_workq; diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 4a86247..f1e1b74 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -232,10 +232,11 @@ enum { /* Interrupt disable masks */ enum { /* Interrupt disable mask for UFSHCI v1.0 */ - INTERRUPT_DISABLE_MASK_10 = 0xFFFF, + INTERRUPT_MASK_ALL_VER_10 = 0x30FFF, + INTERRUPT_MASK_RW_VER_10 = 0x30000, /* Interrupt disable mask for UFSHCI v1.1 */ - INTERRUPT_DISABLE_MASK_11 = 0x0, + INTERRUPT_MASK_ALL_VER_11 = 0x31FFF, }; /* -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html