aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWayne Boyer <wayneb@linux.vnet.ibm.com>2011-04-12 13:29:02 -0400
committerJames Bottomley <James.Bottomley@suse.de>2011-05-01 11:48:53 -0400
commit7dacb64f49848f1f28018fd3e58af8d6ba234960 (patch)
tree329bbb35edbe457081fdfa42d15467c86fc169b2
parent3425fbfe2293244abba72c80b215d09ead32d1ad (diff)
[SCSI] ipr: improve interrupt service routine performance
During performance testing on P7 machines it was observed that the interrupt service routine was doing unnecessary MMIO operations. This patch rearranges the logic of the routine and moves some of the code out of the main routine. The result is that there are now fewer MMIO operations in the performance path of the code. As a result of the above change, an existing condition was exposed where the driver could get an "unexpected" hrrq interrupt. The original code would flag the interrupt as unexpected and then reset the adapter. After further analysis it was confirmed that this condition can occasionally occur and that the interrupt can safely be ignored. Additional code in this patch detects this condition, clears the interrupt and allows the driver to continue without resetting the adapter. Signed-off-by: Wayne Boyer <wayneb@linux.vnet.ibm.com> Acked-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/ipr.c68
1 files changed, 39 insertions, 29 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index a485e524ac8b..fa2513cc76cc 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -4956,6 +4956,32 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
4956 u32 int_reg) 4956 u32 int_reg)
4957{ 4957{
4958 irqreturn_t rc = IRQ_HANDLED; 4958 irqreturn_t rc = IRQ_HANDLED;
4959 u32 int_mask_reg;
4960
4961 int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
4962 int_reg &= ~int_mask_reg;
4963
4964 /* If an interrupt on the adapter did not occur, ignore it.
4965 * Or in the case of SIS 64, check for a stage change interrupt.
4966 */
4967 if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) {
4968 if (ioa_cfg->sis64) {
4969 int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
4970 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
4971 if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
4972
4973 /* clear stage change */
4974 writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
4975 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
4976 list_del(&ioa_cfg->reset_cmd->queue);
4977 del_timer(&ioa_cfg->reset_cmd->timer);
4978 ipr_reset_ioa_job(ioa_cfg->reset_cmd);
4979 return IRQ_HANDLED;
4980 }
4981 }
4982
4983 return IRQ_NONE;
4984 }
4959 4985
4960 if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { 4986 if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
4961 /* Mask the interrupt */ 4987 /* Mask the interrupt */
@@ -4968,6 +4994,13 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
4968 list_del(&ioa_cfg->reset_cmd->queue); 4994 list_del(&ioa_cfg->reset_cmd->queue);
4969 del_timer(&ioa_cfg->reset_cmd->timer); 4995 del_timer(&ioa_cfg->reset_cmd->timer);
4970 ipr_reset_ioa_job(ioa_cfg->reset_cmd); 4996 ipr_reset_ioa_job(ioa_cfg->reset_cmd);
4997 } else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) {
4998 if (ipr_debug && printk_ratelimit())
4999 dev_err(&ioa_cfg->pdev->dev,
5000 "Spurious interrupt detected. 0x%08X\n", int_reg);
5001 writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
5002 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
5003 return IRQ_NONE;
4971 } else { 5004 } else {
4972 if (int_reg & IPR_PCII_IOA_UNIT_CHECKED) 5005 if (int_reg & IPR_PCII_IOA_UNIT_CHECKED)
4973 ioa_cfg->ioa_unit_checked = 1; 5006 ioa_cfg->ioa_unit_checked = 1;
@@ -5016,10 +5049,11 @@ static irqreturn_t ipr_isr(int irq, void *devp)
5016{ 5049{
5017 struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; 5050 struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
5018 unsigned long lock_flags = 0; 5051 unsigned long lock_flags = 0;
5019 u32 int_reg, int_mask_reg; 5052 u32 int_reg = 0;
5020 u32 ioasc; 5053 u32 ioasc;
5021 u16 cmd_index; 5054 u16 cmd_index;
5022 int num_hrrq = 0; 5055 int num_hrrq = 0;
5056 int irq_none = 0;
5023 struct ipr_cmnd *ipr_cmd; 5057 struct ipr_cmnd *ipr_cmd;
5024 irqreturn_t rc = IRQ_NONE; 5058 irqreturn_t rc = IRQ_NONE;
5025 5059
@@ -5031,33 +5065,6 @@ static irqreturn_t ipr_isr(int irq, void *devp)
5031 return IRQ_NONE; 5065 return IRQ_NONE;
5032 } 5066 }
5033 5067
5034 int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
5035 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
5036
5037 /* If an interrupt on the adapter did not occur, ignore it.
5038 * Or in the case of SIS 64, check for a stage change interrupt.
5039 */
5040 if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) {
5041 if (ioa_cfg->sis64) {
5042 int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
5043 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
5044 if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
5045
5046 /* clear stage change */
5047 writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
5048 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
5049 list_del(&ioa_cfg->reset_cmd->queue);
5050 del_timer(&ioa_cfg->reset_cmd->timer);
5051 ipr_reset_ioa_job(ioa_cfg->reset_cmd);
5052 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
5053 return IRQ_HANDLED;
5054 }
5055 }
5056
5057 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
5058 return IRQ_NONE;
5059 }
5060
5061 while (1) { 5068 while (1) {
5062 ipr_cmd = NULL; 5069 ipr_cmd = NULL;
5063 5070
@@ -5097,7 +5104,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
5097 /* Clear the PCI interrupt */ 5104 /* Clear the PCI interrupt */
5098 do { 5105 do {
5099 writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); 5106 writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
5100 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; 5107 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
5101 } while (int_reg & IPR_PCII_HRRQ_UPDATED && 5108 } while (int_reg & IPR_PCII_HRRQ_UPDATED &&
5102 num_hrrq++ < IPR_MAX_HRRQ_RETRIES); 5109 num_hrrq++ < IPR_MAX_HRRQ_RETRIES);
5103 5110
@@ -5107,6 +5114,9 @@ static irqreturn_t ipr_isr(int irq, void *devp)
5107 return IRQ_HANDLED; 5114 return IRQ_HANDLED;
5108 } 5115 }
5109 5116
5117 } else if (rc == IRQ_NONE && irq_none == 0) {
5118 int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
5119 irq_none++;
5110 } else 5120 } else
5111 break; 5121 break;
5112 } 5122 }