Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipr: add test for MSI interrupt support

The return value from pci_enable_msi() can not always be trusted. This patch
adds code to generate an interrupt after MSI has been enabled and tests
whether or not we can receive and process it. If the tests fails, then fall
back to LSI.

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@HansenPartnership.com>

authored by

Wayne Boyer and committed by
James Bottomley
95fecd90 a9e0edb6

+105 -9
+101 -7
drivers/scsi/ipr.c
··· 7367 7367 INIT_LIST_HEAD(&ioa_cfg->used_res_q); 7368 7368 INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); 7369 7369 init_waitqueue_head(&ioa_cfg->reset_wait_q); 7370 + init_waitqueue_head(&ioa_cfg->msi_wait_q); 7370 7371 ioa_cfg->sdt_state = INACTIVE; 7371 7372 if (ipr_enable_cache) 7372 7373 ioa_cfg->cache_state = CACHE_ENABLED; ··· 7418 7417 } 7419 7418 7420 7419 /** 7420 + * ipr_test_intr - Handle the interrupt generated in ipr_test_msi(). 7421 + * @pdev: PCI device struct 7422 + * 7423 + * Description: Simply set the msi_received flag to 1 indicating that 7424 + * Message Signaled Interrupts are supported. 7425 + * 7426 + * Return value: 7427 + * 0 on success / non-zero on failure 7428 + **/ 7429 + static irqreturn_t __devinit ipr_test_intr(int irq, void *devp) 7430 + { 7431 + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; 7432 + unsigned long lock_flags = 0; 7433 + irqreturn_t rc = IRQ_HANDLED; 7434 + 7435 + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 7436 + 7437 + ioa_cfg->msi_received = 1; 7438 + wake_up(&ioa_cfg->msi_wait_q); 7439 + 7440 + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 7441 + return rc; 7442 + } 7443 + 7444 + /** 7445 + * ipr_test_msi - Test for Message Signaled Interrupt (MSI) support. 7446 + * @pdev: PCI device struct 7447 + * 7448 + * Description: The return value from pci_enable_msi() can not always be 7449 + * trusted. This routine sets up and initiates a test interrupt to determine 7450 + * if the interrupt is received via the ipr_test_intr() service routine. 7451 + * If the tests fails, the driver will fall back to LSI. 7452 + * 7453 + * Return value: 7454 + * 0 on success / non-zero on failure 7455 + **/ 7456 + static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, 7457 + struct pci_dev *pdev) 7458 + { 7459 + int rc; 7460 + volatile u32 int_reg; 7461 + unsigned long lock_flags = 0; 7462 + 7463 + ENTER; 7464 + 7465 + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 7466 + init_waitqueue_head(&ioa_cfg->msi_wait_q); 7467 + ioa_cfg->msi_received = 0; 7468 + ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); 7469 + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg); 7470 + int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); 7471 + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 7472 + 7473 + rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg); 7474 + if (rc) { 7475 + dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq); 7476 + return rc; 7477 + } else if (ipr_debug) 7478 + dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq); 7479 + 7480 + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg); 7481 + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); 7482 + wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ); 7483 + ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); 7484 + 7485 + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 7486 + if (!ioa_cfg->msi_received) { 7487 + /* MSI test failed */ 7488 + dev_info(&pdev->dev, "MSI test failed. Falling back to LSI.\n"); 7489 + rc = -EOPNOTSUPP; 7490 + } else if (ipr_debug) 7491 + dev_info(&pdev->dev, "MSI test succeeded.\n"); 7492 + 7493 + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 7494 + 7495 + free_irq(pdev->irq, ioa_cfg); 7496 + 7497 + LEAVE; 7498 + 7499 + return rc; 7500 + } 7501 + 7502 + /** 7421 7503 * ipr_probe_ioa - Allocates memory and does first stage of initialization 7422 7504 * @pdev: PCI device struct 7423 7505 * @dev_id: PCI device id struct ··· 7524 7440 dev_err(&pdev->dev, "Cannot enable adapter\n"); 7525 7441 goto out; 7526 7442 } 7527 - 7528 - if (!(rc = pci_enable_msi(pdev))) 7529 - dev_info(&pdev->dev, "MSI enabled\n"); 7530 - else if (ipr_debug) 7531 - dev_info(&pdev->dev, "Cannot enable MSI\n"); 7532 7443 7533 7444 dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); 7534 7445 ··· 7598 7519 goto cleanup_nomem; 7599 7520 } 7600 7521 7522 + /* Enable MSI style interrupts if they are supported. */ 7523 + if (!(rc = pci_enable_msi(pdev))) { 7524 + rc = ipr_test_msi(ioa_cfg, pdev); 7525 + if (rc == -EOPNOTSUPP) 7526 + pci_disable_msi(pdev); 7527 + else if (rc) 7528 + goto out_msi_disable; 7529 + else 7530 + dev_info(&pdev->dev, "MSI enabled with IRQ: %d\n", pdev->irq); 7531 + } else if (ipr_debug) 7532 + dev_info(&pdev->dev, "Cannot enable MSI.\n"); 7533 + 7601 7534 /* Save away PCI config space for use following IOA reset */ 7602 7535 rc = pci_save_state(pdev); 7603 7536 ··· 7647 7556 ioa_cfg->ioa_unit_checked = 1; 7648 7557 7649 7558 ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); 7650 - rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg); 7559 + rc = request_irq(pdev->irq, ipr_isr, 7560 + ioa_cfg->msi_received ? 0 : IRQF_SHARED, 7561 + IPR_NAME, ioa_cfg); 7651 7562 7652 7563 if (rc) { 7653 7564 dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", ··· 7676 7583 ipr_free_mem(ioa_cfg); 7677 7584 cleanup_nomem: 7678 7585 iounmap(ipr_regs); 7586 + out_msi_disable: 7587 + pci_disable_msi(pdev); 7679 7588 out_release_regions: 7680 7589 pci_release_regions(pdev); 7681 7590 out_scsi_host_put: 7682 7591 scsi_host_put(host); 7683 7592 out_disable: 7684 - pci_disable_msi(pdev); 7685 7593 pci_disable_device(pdev); 7686 7594 goto out; 7687 7595 }
+4 -2
drivers/scsi/ipr.h
··· 37 37 /* 38 38 * Literals 39 39 */ 40 - #define IPR_DRIVER_VERSION "2.4.2" 41 - #define IPR_DRIVER_DATE "(January 21, 2009)" 40 + #define IPR_DRIVER_VERSION "2.4.3" 41 + #define IPR_DRIVER_DATE "(June 10, 2009)" 42 42 43 43 /* 44 44 * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding ··· 1094 1094 u8 needs_hard_reset:1; 1095 1095 u8 dual_raid:1; 1096 1096 u8 needs_warm_reset:1; 1097 + u8 msi_received:1; 1097 1098 1098 1099 u8 revid; 1099 1100 ··· 1180 1179 struct work_struct work_q; 1181 1180 1182 1181 wait_queue_head_t reset_wait_q; 1182 + wait_queue_head_t msi_wait_q; 1183 1183 1184 1184 struct ipr_dump *dump; 1185 1185 enum ipr_sdt_state sdt_state;