0001
0002
0003
0004 #include <linux/string.h>
0005 #include <linux/errno.h>
0006 #include <linux/pci.h>
0007 #include <linux/interrupt.h>
0008
0009 #include "vnic_dev.h"
0010 #include "vnic_intr.h"
0011 #include "vnic_stats.h"
0012 #include "snic_io.h"
0013 #include "snic.h"
0014
0015
0016
0017
0018
0019
0020 static irqreturn_t
0021 snic_isr_msix_wq(int irq, void *data)
0022 {
0023 struct snic *snic = data;
0024 unsigned long wq_work_done = 0;
0025
0026 snic->s_stats.misc.last_isr_time = jiffies;
0027 atomic64_inc(&snic->s_stats.misc.ack_isr_cnt);
0028
0029 wq_work_done = snic_wq_cmpl_handler(snic, -1);
0030 svnic_intr_return_credits(&snic->intr[SNIC_MSIX_WQ],
0031 wq_work_done,
0032 1 ,
0033 1 );
0034
0035 return IRQ_HANDLED;
0036 }
0037
0038 static irqreturn_t
0039 snic_isr_msix_io_cmpl(int irq, void *data)
0040 {
0041 struct snic *snic = data;
0042 unsigned long iocmpl_work_done = 0;
0043
0044 snic->s_stats.misc.last_isr_time = jiffies;
0045 atomic64_inc(&snic->s_stats.misc.cmpl_isr_cnt);
0046
0047 iocmpl_work_done = snic_fwcq_cmpl_handler(snic, -1);
0048 svnic_intr_return_credits(&snic->intr[SNIC_MSIX_IO_CMPL],
0049 iocmpl_work_done,
0050 1 ,
0051 1 );
0052
0053 return IRQ_HANDLED;
0054 }
0055
0056 static irqreturn_t
0057 snic_isr_msix_err_notify(int irq, void *data)
0058 {
0059 struct snic *snic = data;
0060
0061 snic->s_stats.misc.last_isr_time = jiffies;
0062 atomic64_inc(&snic->s_stats.misc.errnotify_isr_cnt);
0063
0064 svnic_intr_return_all_credits(&snic->intr[SNIC_MSIX_ERR_NOTIFY]);
0065 snic_log_q_error(snic);
0066
0067
0068 snic_handle_link_event(snic);
0069
0070 return IRQ_HANDLED;
0071 }
0072
0073
0074 void
0075 snic_free_intr(struct snic *snic)
0076 {
0077 int i;
0078
0079
0080 for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {
0081 if (snic->msix[i].requested) {
0082 free_irq(pci_irq_vector(snic->pdev, i),
0083 snic->msix[i].devid);
0084 }
0085 }
0086 }
0087
0088 int
0089 snic_request_intr(struct snic *snic)
0090 {
0091 int ret = 0, i;
0092 enum vnic_dev_intr_mode intr_mode;
0093
0094 intr_mode = svnic_dev_get_intr_mode(snic->vdev);
0095 SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
0096
0097
0098
0099
0100
0101
0102
0103
0104 sprintf(snic->msix[SNIC_MSIX_WQ].devname,
0105 "%.11s-scsi-wq",
0106 snic->name);
0107 snic->msix[SNIC_MSIX_WQ].isr = snic_isr_msix_wq;
0108 snic->msix[SNIC_MSIX_WQ].devid = snic;
0109
0110 sprintf(snic->msix[SNIC_MSIX_IO_CMPL].devname,
0111 "%.11s-io-cmpl",
0112 snic->name);
0113 snic->msix[SNIC_MSIX_IO_CMPL].isr = snic_isr_msix_io_cmpl;
0114 snic->msix[SNIC_MSIX_IO_CMPL].devid = snic;
0115
0116 sprintf(snic->msix[SNIC_MSIX_ERR_NOTIFY].devname,
0117 "%.11s-err-notify",
0118 snic->name);
0119 snic->msix[SNIC_MSIX_ERR_NOTIFY].isr = snic_isr_msix_err_notify;
0120 snic->msix[SNIC_MSIX_ERR_NOTIFY].devid = snic;
0121
0122 for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {
0123 ret = request_irq(pci_irq_vector(snic->pdev, i),
0124 snic->msix[i].isr,
0125 0,
0126 snic->msix[i].devname,
0127 snic->msix[i].devid);
0128 if (ret) {
0129 SNIC_HOST_ERR(snic->shost,
0130 "MSI-X: request_irq(%d) failed %d\n",
0131 i,
0132 ret);
0133 snic_free_intr(snic);
0134 break;
0135 }
0136 snic->msix[i].requested = 1;
0137 }
0138
0139 return ret;
0140 }
0141
0142 int
0143 snic_set_intr_mode(struct snic *snic)
0144 {
0145 unsigned int n = ARRAY_SIZE(snic->wq);
0146 unsigned int m = SNIC_CQ_IO_CMPL_MAX;
0147 unsigned int vecs = n + m + 1;
0148
0149
0150
0151
0152
0153 BUILD_BUG_ON((ARRAY_SIZE(snic->wq) + SNIC_CQ_IO_CMPL_MAX) >
0154 ARRAY_SIZE(snic->intr));
0155
0156 if (snic->wq_count < n || snic->cq_count < n + m)
0157 goto fail;
0158
0159 if (pci_alloc_irq_vectors(snic->pdev, vecs, vecs, PCI_IRQ_MSIX) < 0)
0160 goto fail;
0161
0162 snic->wq_count = n;
0163 snic->cq_count = n + m;
0164 snic->intr_count = vecs;
0165 snic->err_intr_offset = SNIC_MSIX_ERR_NOTIFY;
0166
0167 SNIC_ISR_DBG(snic->shost, "Using MSI-X Interrupts\n");
0168 svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_MSIX);
0169 return 0;
0170 fail:
0171 svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
0172 return -EINVAL;
0173 }
0174
0175 void
0176 snic_clear_intr_mode(struct snic *snic)
0177 {
0178 pci_free_irq_vectors(snic->pdev);
0179 svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_INTX);
0180 }