aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-03-01 20:06:24 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 15:27:12 -0400
commit2396a2650a5a39634e3ad6b29e1104944e5ab88f (patch)
treea5f1e724f1a3eec60da92aef018c6c7840f95bcc /drivers/scsi/isci
parent50a92d93148ec073efd2456b007e04ecae452086 (diff)
isci: fix interrupt disable
There is a (dubious?) lost irq workaround in sci_controller_isr() that effectively nullifies attempts to disable interrupts. Until the workaround can be re-evaluated add some infrastructure to prevent the interrupt handler from inadvertantly re-enabling interrupts. The failure mode was interrupts continuing to run after the driver had been removed and its iomappings torn down. Reported-by: Jacek Danecki <jacek.danecki@intel.com> Tested-by: Jacek Danecki <jacek.danecki@intel.com> [richard: clear remaining interrupts at the end of reset] Acked-by: Richard Boyd <richard.g.boyd@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r--drivers/scsi/isci/host.c39
-rw-r--r--drivers/scsi/isci/host.h1
2 files changed, 27 insertions, 13 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 577a8369274c..5832b13e7b07 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -192,22 +192,27 @@ static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost)
192 192
193static bool sci_controller_isr(struct isci_host *ihost) 193static bool sci_controller_isr(struct isci_host *ihost)
194{ 194{
195 if (sci_controller_completion_queue_has_entries(ihost)) { 195 if (sci_controller_completion_queue_has_entries(ihost))
196 return true; 196 return true;
197 } else {
198 /*
199 * we have a spurious interrupt it could be that we have already
200 * emptied the completion queue from a previous interrupt */
201 writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
202 197
203 /* 198 /* we have a spurious interrupt it could be that we have already
204 * There is a race in the hardware that could cause us not to be notified 199 * emptied the completion queue from a previous interrupt
205 * of an interrupt completion if we do not take this step. We will mask 200 * FIXME: really!?
206 * then unmask the interrupts so if there is another interrupt pending 201 */
207 * the clearing of the interrupt source we get the next interrupt message. */ 202 writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
203
204 /* There is a race in the hardware that could cause us not to be
205 * notified of an interrupt completion if we do not take this
206 * step. We will mask then unmask the interrupts so if there is
207 * another interrupt pending the clearing of the interrupt
208 * source we get the next interrupt message.
209 */
210 spin_lock(&ihost->scic_lock);
211 if (test_bit(IHOST_IRQ_ENABLED, &ihost->flags)) {
208 writel(0xFF000000, &ihost->smu_registers->interrupt_mask); 212 writel(0xFF000000, &ihost->smu_registers->interrupt_mask);
209 writel(0, &ihost->smu_registers->interrupt_mask); 213 writel(0, &ihost->smu_registers->interrupt_mask);
210 } 214 }
215 spin_unlock(&ihost->scic_lock);
211 216
212 return false; 217 return false;
213} 218}
@@ -698,14 +703,15 @@ static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost)
698 703
699static void sci_controller_enable_interrupts(struct isci_host *ihost) 704static void sci_controller_enable_interrupts(struct isci_host *ihost)
700{ 705{
701 BUG_ON(ihost->smu_registers == NULL); 706 set_bit(IHOST_IRQ_ENABLED, &ihost->flags);
702 writel(0, &ihost->smu_registers->interrupt_mask); 707 writel(0, &ihost->smu_registers->interrupt_mask);
703} 708}
704 709
705void sci_controller_disable_interrupts(struct isci_host *ihost) 710void sci_controller_disable_interrupts(struct isci_host *ihost)
706{ 711{
707 BUG_ON(ihost->smu_registers == NULL); 712 clear_bit(IHOST_IRQ_ENABLED, &ihost->flags);
708 writel(0xffffffff, &ihost->smu_registers->interrupt_mask); 713 writel(0xffffffff, &ihost->smu_registers->interrupt_mask);
714 readl(&ihost->smu_registers->interrupt_mask); /* flush */
709} 715}
710 716
711static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost) 717static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost)
@@ -1318,7 +1324,9 @@ void isci_host_deinit(struct isci_host *ihost)
1318 */ 1324 */
1319 writel(0, &ihost->scu_registers->peg0.sgpio.interface_control); 1325 writel(0, &ihost->scu_registers->peg0.sgpio.interface_control);
1320 1326
1327 spin_lock_irq(&ihost->scic_lock);
1321 sci_controller_reset(ihost); 1328 sci_controller_reset(ihost);
1329 spin_unlock_irq(&ihost->scic_lock);
1322 1330
1323 /* Cancel any/all outstanding port timers */ 1331 /* Cancel any/all outstanding port timers */
1324 for (i = 0; i < ihost->logical_port_entries; i++) { 1332 for (i = 0; i < ihost->logical_port_entries; i++) {
@@ -1605,6 +1613,9 @@ static void sci_controller_reset_hardware(struct isci_host *ihost)
1605 1613
1606 /* The write to the UFQGP clears the UFQPR */ 1614 /* The write to the UFQGP clears the UFQPR */
1607 writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer); 1615 writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer);
1616
1617 /* clear all interrupts */
1618 writel(~SMU_INTERRUPT_STATUS_RESERVED_MASK, &ihost->smu_registers->interrupt_status);
1608} 1619}
1609 1620
1610static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm) 1621static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm)
@@ -2391,7 +2402,9 @@ int isci_host_init(struct isci_host *ihost)
2391 int i, err; 2402 int i, err;
2392 enum sci_status status; 2403 enum sci_status status;
2393 2404
2405 spin_lock_irq(&ihost->scic_lock);
2394 status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost)); 2406 status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost));
2407 spin_unlock_irq(&ihost->scic_lock);
2395 if (status != SCI_SUCCESS) { 2408 if (status != SCI_SUCCESS) {
2396 dev_err(&ihost->pdev->dev, 2409 dev_err(&ihost->pdev->dev,
2397 "%s: sci_controller_construct failed - status = %x\n", 2410 "%s: sci_controller_construct failed - status = %x\n",
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 9dc910b9d921..9701c1d673ba 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -200,6 +200,7 @@ struct isci_host {
200 struct pci_dev *pdev; 200 struct pci_dev *pdev;
201 #define IHOST_START_PENDING 0 201 #define IHOST_START_PENDING 0
202 #define IHOST_STOP_PENDING 1 202 #define IHOST_STOP_PENDING 1
203 #define IHOST_IRQ_ENABLED 2
203 unsigned long flags; 204 unsigned long flags;
204 wait_queue_head_t eventq; 205 wait_queue_head_t eventq;
205 struct Scsi_Host *shost; 206 struct Scsi_Host *shost;