diff options
author | Seungwon Jeon <tgih.jun@samsung.com> | 2013-06-26 13:09:27 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-06-28 16:02:41 -0400 |
commit | 2fbd009b40967fc54b7eb3580372736862291a06 (patch) | |
tree | 8179e88b35c7a59d221957b3ef57af3d960345bc /drivers/scsi | |
parent | b873a27538dff59e77c15eaf23bdf7e6be7d36e9 (diff) |
[SCSI] ufs: amend interrupt configuration
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@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Santosh Y <santoshsy@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 84 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 4 | ||||
-rw-r--r-- | 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 871c2f0568ae..1f1e08518555 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -35,6 +35,10 @@ | |||
35 | 35 | ||
36 | #include "ufshcd.h" | 36 | #include "ufshcd.h" |
37 | 37 | ||
38 | #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ | ||
39 | UTP_TASK_REQ_COMPL |\ | ||
40 | UFSHCD_ERROR_MASK) | ||
41 | |||
38 | enum { | 42 | enum { |
39 | UFSHCD_MAX_CHANNEL = 0, | 43 | UFSHCD_MAX_CHANNEL = 0, |
40 | UFSHCD_MAX_ID = 1, | 44 | UFSHCD_MAX_ID = 1, |
@@ -64,6 +68,20 @@ enum { | |||
64 | }; | 68 | }; |
65 | 69 | ||
66 | /** | 70 | /** |
71 | * ufshcd_get_intr_mask - Get the interrupt bit mask | ||
72 | * @hba - Pointer to adapter instance | ||
73 | * | ||
74 | * Returns interrupt bit mask per version | ||
75 | */ | ||
76 | static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) | ||
77 | { | ||
78 | if (hba->ufs_version == UFSHCI_VERSION_10) | ||
79 | return INTERRUPT_MASK_ALL_VER_10; | ||
80 | else | ||
81 | return INTERRUPT_MASK_ALL_VER_11; | ||
82 | } | ||
83 | |||
84 | /** | ||
67 | * ufshcd_get_ufs_version - Get the UFS version supported by the HBA | 85 | * ufshcd_get_ufs_version - Get the UFS version supported by the HBA |
68 | * @hba - Pointer to adapter instance | 86 | * @hba - Pointer to adapter instance |
69 | * | 87 | * |
@@ -389,25 +407,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp) | |||
389 | } | 407 | } |
390 | 408 | ||
391 | /** | 409 | /** |
392 | * ufshcd_int_config - enable/disable interrupts | 410 | * ufshcd_enable_intr - enable interrupts |
393 | * @hba: per adapter instance | 411 | * @hba: per adapter instance |
394 | * @option: interrupt option | 412 | * @intrs: interrupt bits |
395 | */ | 413 | */ |
396 | static void ufshcd_int_config(struct ufs_hba *hba, u32 option) | 414 | static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) |
397 | { | 415 | { |
398 | switch (option) { | 416 | u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); |
399 | case UFSHCD_INT_ENABLE: | 417 | |
400 | ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE); | 418 | if (hba->ufs_version == UFSHCI_VERSION_10) { |
401 | break; | 419 | u32 rw; |
402 | case UFSHCD_INT_DISABLE: | 420 | rw = set & INTERRUPT_MASK_RW_VER_10; |
403 | if (hba->ufs_version == UFSHCI_VERSION_10) | 421 | set = rw | ((set ^ intrs) & intrs); |
404 | ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10, | 422 | } else { |
405 | REG_INTERRUPT_ENABLE); | 423 | set |= intrs; |
406 | else | 424 | } |
407 | ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11, | 425 | |
408 | REG_INTERRUPT_ENABLE); | 426 | ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); |
409 | break; | 427 | } |
428 | |||
429 | /** | ||
430 | * ufshcd_disable_intr - disable interrupts | ||
431 | * @hba: per adapter instance | ||
432 | * @intrs: interrupt bits | ||
433 | */ | ||
434 | static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs) | ||
435 | { | ||
436 | u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); | ||
437 | |||
438 | if (hba->ufs_version == UFSHCI_VERSION_10) { | ||
439 | u32 rw; | ||
440 | rw = (set & INTERRUPT_MASK_RW_VER_10) & | ||
441 | ~(intrs & INTERRUPT_MASK_RW_VER_10); | ||
442 | set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10); | ||
443 | |||
444 | } else { | ||
445 | set &= ~intrs; | ||
410 | } | 446 | } |
447 | |||
448 | ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); | ||
411 | } | 449 | } |
412 | 450 | ||
413 | /** | 451 | /** |
@@ -709,8 +747,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) | |||
709 | uic_cmd->argument3 = 0; | 747 | uic_cmd->argument3 = 0; |
710 | 748 | ||
711 | /* enable UIC related interrupts */ | 749 | /* enable UIC related interrupts */ |
712 | hba->int_enable_mask |= UIC_COMMAND_COMPL; | 750 | ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); |
713 | ufshcd_int_config(hba, UFSHCD_INT_ENABLE); | ||
714 | 751 | ||
715 | /* sending UIC commands to controller */ | 752 | /* sending UIC commands to controller */ |
716 | ufshcd_send_uic_command(hba, uic_cmd); | 753 | ufshcd_send_uic_command(hba, uic_cmd); |
@@ -757,13 +794,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba) | |||
757 | } | 794 | } |
758 | 795 | ||
759 | /* Enable required interrupts */ | 796 | /* Enable required interrupts */ |
760 | hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL | | 797 | ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS); |
761 | UIC_ERROR | | ||
762 | UTP_TASK_REQ_COMPL | | ||
763 | DEVICE_FATAL_ERROR | | ||
764 | CONTROLLER_FATAL_ERROR | | ||
765 | SYSTEM_BUS_FATAL_ERROR); | ||
766 | ufshcd_int_config(hba, UFSHCD_INT_ENABLE); | ||
767 | 798 | ||
768 | /* Configure interrupt aggregation */ | 799 | /* Configure interrupt aggregation */ |
769 | ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG); | 800 | ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG); |
@@ -1570,7 +1601,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba) | |||
1570 | void ufshcd_remove(struct ufs_hba *hba) | 1601 | void ufshcd_remove(struct ufs_hba *hba) |
1571 | { | 1602 | { |
1572 | /* disable interrupts */ | 1603 | /* disable interrupts */ |
1573 | ufshcd_int_config(hba, UFSHCD_INT_DISABLE); | 1604 | ufshcd_disable_intr(hba, hba->intr_mask); |
1574 | 1605 | ||
1575 | ufshcd_hba_stop(hba); | 1606 | ufshcd_hba_stop(hba); |
1576 | ufshcd_hba_free(hba); | 1607 | ufshcd_hba_free(hba); |
@@ -1628,6 +1659,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle, | |||
1628 | /* Get UFS version supported by the controller */ | 1659 | /* Get UFS version supported by the controller */ |
1629 | hba->ufs_version = ufshcd_get_ufs_version(hba); | 1660 | hba->ufs_version = ufshcd_get_ufs_version(hba); |
1630 | 1661 | ||
1662 | /* Get Interrupt bit mask per version */ | ||
1663 | hba->intr_mask = ufshcd_get_intr_mask(hba); | ||
1664 | |||
1631 | /* Allocate memory for host memory space */ | 1665 | /* Allocate memory for host memory space */ |
1632 | err = ufshcd_memory_alloc(hba); | 1666 | err = ufshcd_memory_alloc(hba); |
1633 | if (err) { | 1667 | if (err) { |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 807dd2d740d4..4213600b89d6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -139,7 +139,7 @@ struct ufshcd_lrb { | |||
139 | * @ufshcd_tm_wait_queue: wait queue for task management | 139 | * @ufshcd_tm_wait_queue: wait queue for task management |
140 | * @tm_condition: condition variable for task management | 140 | * @tm_condition: condition variable for task management |
141 | * @ufshcd_state: UFSHCD states | 141 | * @ufshcd_state: UFSHCD states |
142 | * @int_enable_mask: Interrupt Mask Bits | 142 | * @intr_mask: Interrupt Mask Bits |
143 | * @uic_workq: Work queue for UIC completion handling | 143 | * @uic_workq: Work queue for UIC completion handling |
144 | * @feh_workq: Work queue for fatal controller error handling | 144 | * @feh_workq: Work queue for fatal controller error handling |
145 | * @errors: HBA errors | 145 | * @errors: HBA errors |
@@ -176,7 +176,7 @@ struct ufs_hba { | |||
176 | unsigned long tm_condition; | 176 | unsigned long tm_condition; |
177 | 177 | ||
178 | u32 ufshcd_state; | 178 | u32 ufshcd_state; |
179 | u32 int_enable_mask; | 179 | u32 intr_mask; |
180 | 180 | ||
181 | /* Work Queues */ | 181 | /* Work Queues */ |
182 | struct work_struct uic_workq; | 182 | struct work_struct uic_workq; |
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 0c164847a3ef..d5c5f1482d7d 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h | |||
@@ -232,10 +232,11 @@ enum { | |||
232 | /* Interrupt disable masks */ | 232 | /* Interrupt disable masks */ |
233 | enum { | 233 | enum { |
234 | /* Interrupt disable mask for UFSHCI v1.0 */ | 234 | /* Interrupt disable mask for UFSHCI v1.0 */ |
235 | INTERRUPT_DISABLE_MASK_10 = 0xFFFF, | 235 | INTERRUPT_MASK_ALL_VER_10 = 0x30FFF, |
236 | INTERRUPT_MASK_RW_VER_10 = 0x30000, | ||
236 | 237 | ||
237 | /* Interrupt disable mask for UFSHCI v1.1 */ | 238 | /* Interrupt disable mask for UFSHCI v1.1 */ |
238 | INTERRUPT_DISABLE_MASK_11 = 0x0, | 239 | INTERRUPT_MASK_ALL_VER_11 = 0x31FFF, |
239 | }; | 240 | }; |
240 | 241 | ||
241 | /* | 242 | /* |