diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2007-01-29 13:22:19 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-01-31 12:05:20 -0500 |
commit | a8488abefaa863a0c3a19888f03395adb3f1c6d2 (patch) | |
tree | d26c038c2a72231490db6c6e4ef9ea5d7f03862c /drivers/scsi/qla2xxx/qla_isr.c | |
parent | 3c6061236801a376d86ca75fd56d61f964611dd5 (diff) |
[SCSI] qla2xxx: Add MSI-X support.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_isr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b95fcb2c065e..e883b5fc3b08 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
@@ -1529,3 +1529,218 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) | |||
1529 | qla2x00_sp_compl(ha, sp); | 1529 | qla2x00_sp_compl(ha, sp); |
1530 | } | 1530 | } |
1531 | 1531 | ||
1532 | static irqreturn_t | ||
1533 | qla24xx_msix_rsp_q(int irq, void *dev_id) | ||
1534 | { | ||
1535 | scsi_qla_host_t *ha; | ||
1536 | struct device_reg_24xx __iomem *reg; | ||
1537 | unsigned long flags; | ||
1538 | |||
1539 | ha = dev_id; | ||
1540 | reg = &ha->iobase->isp24; | ||
1541 | |||
1542 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1543 | |||
1544 | qla24xx_process_response_queue(ha); | ||
1545 | |||
1546 | WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); | ||
1547 | RD_REG_DWORD_RELAXED(®->hccr); | ||
1548 | |||
1549 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1550 | |||
1551 | return IRQ_HANDLED; | ||
1552 | } | ||
1553 | |||
1554 | static irqreturn_t | ||
1555 | qla24xx_msix_default(int irq, void *dev_id) | ||
1556 | { | ||
1557 | scsi_qla_host_t *ha; | ||
1558 | struct device_reg_24xx __iomem *reg; | ||
1559 | int status; | ||
1560 | unsigned long flags; | ||
1561 | unsigned long iter; | ||
1562 | uint32_t stat; | ||
1563 | uint32_t hccr; | ||
1564 | uint16_t mb[4]; | ||
1565 | |||
1566 | ha = dev_id; | ||
1567 | reg = &ha->iobase->isp24; | ||
1568 | status = 0; | ||
1569 | |||
1570 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1571 | for (iter = 50; iter--; ) { | ||
1572 | stat = RD_REG_DWORD(®->host_status); | ||
1573 | if (stat & HSRX_RISC_PAUSED) { | ||
1574 | hccr = RD_REG_DWORD(®->hccr); | ||
1575 | |||
1576 | qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " | ||
1577 | "Dumping firmware!\n", hccr); | ||
1578 | ha->isp_ops.fw_dump(ha, 1); | ||
1579 | set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); | ||
1580 | break; | ||
1581 | } else if ((stat & HSRX_RISC_INT) == 0) | ||
1582 | break; | ||
1583 | |||
1584 | switch (stat & 0xff) { | ||
1585 | case 0x1: | ||
1586 | case 0x2: | ||
1587 | case 0x10: | ||
1588 | case 0x11: | ||
1589 | qla24xx_mbx_completion(ha, MSW(stat)); | ||
1590 | status |= MBX_INTERRUPT; | ||
1591 | |||
1592 | break; | ||
1593 | case 0x12: | ||
1594 | mb[0] = MSW(stat); | ||
1595 | mb[1] = RD_REG_WORD(®->mailbox1); | ||
1596 | mb[2] = RD_REG_WORD(®->mailbox2); | ||
1597 | mb[3] = RD_REG_WORD(®->mailbox3); | ||
1598 | qla2x00_async_event(ha, mb); | ||
1599 | break; | ||
1600 | case 0x13: | ||
1601 | qla24xx_process_response_queue(ha); | ||
1602 | break; | ||
1603 | default: | ||
1604 | DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " | ||
1605 | "(%d).\n", | ||
1606 | ha->host_no, stat & 0xff)); | ||
1607 | break; | ||
1608 | } | ||
1609 | WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); | ||
1610 | RD_REG_DWORD_RELAXED(®->hccr); | ||
1611 | } | ||
1612 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1613 | |||
1614 | if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && | ||
1615 | (status & MBX_INTERRUPT) && ha->flags.mbox_int) { | ||
1616 | spin_lock_irqsave(&ha->mbx_reg_lock, flags); | ||
1617 | |||
1618 | set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); | ||
1619 | up(&ha->mbx_intr_sem); | ||
1620 | |||
1621 | spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); | ||
1622 | } | ||
1623 | |||
1624 | return IRQ_HANDLED; | ||
1625 | } | ||
1626 | |||
1627 | /* Interrupt handling helpers. */ | ||
1628 | |||
1629 | struct qla_init_msix_entry { | ||
1630 | uint16_t entry; | ||
1631 | uint16_t index; | ||
1632 | const char *name; | ||
1633 | irqreturn_t (*handler)(int, void *); | ||
1634 | }; | ||
1635 | |||
1636 | static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = { | ||
1637 | { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT, | ||
1638 | "qla2xxx (default)", qla24xx_msix_default }, | ||
1639 | |||
1640 | { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q, | ||
1641 | "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, | ||
1642 | }; | ||
1643 | |||
1644 | static void | ||
1645 | qla24xx_disable_msix(scsi_qla_host_t *ha) | ||
1646 | { | ||
1647 | int i; | ||
1648 | struct qla_msix_entry *qentry; | ||
1649 | |||
1650 | for (i = 0; i < QLA_MSIX_ENTRIES; i++) { | ||
1651 | qentry = &ha->msix_entries[imsix_entries[i].index]; | ||
1652 | if (qentry->have_irq) | ||
1653 | free_irq(qentry->msix_vector, ha); | ||
1654 | } | ||
1655 | pci_disable_msix(ha->pdev); | ||
1656 | } | ||
1657 | |||
1658 | static int | ||
1659 | qla24xx_enable_msix(scsi_qla_host_t *ha) | ||
1660 | { | ||
1661 | int i, ret; | ||
1662 | struct msix_entry entries[QLA_MSIX_ENTRIES]; | ||
1663 | struct qla_msix_entry *qentry; | ||
1664 | |||
1665 | for (i = 0; i < QLA_MSIX_ENTRIES; i++) | ||
1666 | entries[i].entry = imsix_entries[i].entry; | ||
1667 | |||
1668 | ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries)); | ||
1669 | if (ret) { | ||
1670 | qla_printk(KERN_WARNING, ha, | ||
1671 | "MSI-X: Failed to enable support -- %d/%d\n", | ||
1672 | QLA_MSIX_ENTRIES, ret); | ||
1673 | goto msix_out; | ||
1674 | } | ||
1675 | ha->flags.msix_enabled = 1; | ||
1676 | |||
1677 | for (i = 0; i < QLA_MSIX_ENTRIES; i++) { | ||
1678 | qentry = &ha->msix_entries[imsix_entries[i].index]; | ||
1679 | qentry->msix_vector = entries[i].vector; | ||
1680 | qentry->msix_entry = entries[i].entry; | ||
1681 | qentry->have_irq = 0; | ||
1682 | ret = request_irq(qentry->msix_vector, | ||
1683 | imsix_entries[i].handler, 0, imsix_entries[i].name, ha); | ||
1684 | if (ret) { | ||
1685 | qla_printk(KERN_WARNING, ha, | ||
1686 | "MSI-X: Unable to register handler -- %x/%d.\n", | ||
1687 | imsix_entries[i].index, ret); | ||
1688 | qla24xx_disable_msix(ha); | ||
1689 | goto msix_out; | ||
1690 | } | ||
1691 | qentry->have_irq = 1; | ||
1692 | } | ||
1693 | |||
1694 | msix_out: | ||
1695 | return ret; | ||
1696 | } | ||
1697 | |||
1698 | int | ||
1699 | qla2x00_request_irqs(scsi_qla_host_t *ha) | ||
1700 | { | ||
1701 | int ret; | ||
1702 | |||
1703 | /* If possible, enable MSI-X. */ | ||
1704 | if (!IS_QLA2432(ha)) | ||
1705 | goto skip_msix; | ||
1706 | |||
1707 | if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX || | ||
1708 | !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) { | ||
1709 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
1710 | "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n", | ||
1711 | ha->chip_revision, ha->fw_attributes)); | ||
1712 | |||
1713 | goto skip_msix; | ||
1714 | } | ||
1715 | |||
1716 | ret = qla24xx_enable_msix(ha); | ||
1717 | if (!ret) { | ||
1718 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
1719 | "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, | ||
1720 | ha->fw_attributes)); | ||
1721 | return ret; | ||
1722 | } | ||
1723 | qla_printk(KERN_WARNING, ha, | ||
1724 | "MSI-X: Falling back-to INTa mode -- %d.\n", ret); | ||
1725 | skip_msix: | ||
1726 | ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler, | ||
1727 | IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); | ||
1728 | if (ret) { | ||
1729 | qla_printk(KERN_WARNING, ha, | ||
1730 | "Failed to reserve interrupt %d already in use.\n", | ||
1731 | ha->pdev->irq); | ||
1732 | } | ||
1733 | ha->host->irq = ha->pdev->irq; | ||
1734 | |||
1735 | return ret; | ||
1736 | } | ||
1737 | |||
1738 | void | ||
1739 | qla2x00_free_irqs(scsi_qla_host_t *ha) | ||
1740 | { | ||
1741 | |||
1742 | if (ha->flags.msix_enabled) | ||
1743 | qla24xx_disable_msix(ha); | ||
1744 | else if (ha->host->irq) | ||
1745 | free_irq(ha->host->irq, ha); | ||
1746 | } | ||