Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3feeb89d authored by Wayne Boyer's avatar Wayne Boyer Committed by James Bottomley
Browse files

[SCSI] ipr: add workaround for MSI interrupts on P7



This patch adds some additional logic to the interrupt service routine to fix
a potential problem where an MSI interrupt does not get cleared the first time.

Signed-off-by: default avatarWayne Boyer <wayneb@linux.vnet.ibm.com>
Acked-by: default avatarBrian King <brking@linux.vnet.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 61ec33eb
Loading
Loading
Loading
Loading
+33 −9
Original line number Original line Diff line number Diff line
@@ -4188,6 +4188,25 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
	return rc;
	return rc;
}
}


/**
 * ipr_isr_eh - Interrupt service routine error handler
 * @ioa_cfg:	ioa config struct
 * @msg:	message to log
 *
 * Return value:
 * 	none
 **/
static void ipr_isr_eh(struct ipr_ioa_cfg *ioa_cfg, char *msg)
{
	ioa_cfg->errors_logged++;
	dev_err(&ioa_cfg->pdev->dev, "%s\n", msg);

	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
		ioa_cfg->sdt_state = GET_DUMP;

	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
}

/**
/**
 * ipr_isr - Interrupt service routine
 * ipr_isr - Interrupt service routine
 * @irq:	irq number
 * @irq:	irq number
@@ -4203,6 +4222,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
	volatile u32 int_reg, int_mask_reg;
	volatile u32 int_reg, int_mask_reg;
	u32 ioasc;
	u32 ioasc;
	u16 cmd_index;
	u16 cmd_index;
	int num_hrrq = 0;
	struct ipr_cmnd *ipr_cmd;
	struct ipr_cmnd *ipr_cmd;
	irqreturn_t rc = IRQ_NONE;
	irqreturn_t rc = IRQ_NONE;


@@ -4233,13 +4253,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
				     IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT;
				     IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT;


			if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
			if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
				ioa_cfg->errors_logged++;
				ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
				dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n");

				if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
					ioa_cfg->sdt_state = GET_DUMP;

				ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
				return IRQ_HANDLED;
				return IRQ_HANDLED;
			}
			}
@@ -4266,8 +4280,18 @@ static irqreturn_t ipr_isr(int irq, void *devp)


		if (ipr_cmd != NULL) {
		if (ipr_cmd != NULL) {
			/* Clear the PCI interrupt */
			/* Clear the PCI interrupt */
			do {
				writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
				writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
				int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
				int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
			} while (int_reg & IPR_PCII_HRRQ_UPDATED &&
					num_hrrq++ < IPR_MAX_HRRQ_RETRIES);

			if (int_reg & IPR_PCII_HRRQ_UPDATED) {
				ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
				return IRQ_HANDLED;
			}

		} else
		} else
			break;
			break;
	}
	}
+1 −0
Original line number Original line Diff line number Diff line
@@ -144,6 +144,7 @@
#define IPR_IOA_MAX_SECTORS				32767
#define IPR_IOA_MAX_SECTORS				32767
#define IPR_VSET_MAX_SECTORS				512
#define IPR_VSET_MAX_SECTORS				512
#define IPR_MAX_CDB_LEN					16
#define IPR_MAX_CDB_LEN					16
#define IPR_MAX_HRRQ_RETRIES				3


#define IPR_DEFAULT_BUS_WIDTH				16
#define IPR_DEFAULT_BUS_WIDTH				16
#define IPR_80MBs_SCSI_RATE		((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))
#define IPR_80MBs_SCSI_RATE		((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))