0001
0002
0003
0004
0005
0006 #include <linux/string.h>
0007 #include <linux/errno.h>
0008 #include <linux/pci.h>
0009 #include <linux/interrupt.h>
0010 #include <scsi/libfc.h>
0011 #include <scsi/fc_frame.h>
0012 #include "vnic_dev.h"
0013 #include "vnic_intr.h"
0014 #include "vnic_stats.h"
0015 #include "fnic_io.h"
0016 #include "fnic.h"
0017
0018 static irqreturn_t fnic_isr_legacy(int irq, void *data)
0019 {
0020 struct fnic *fnic = data;
0021 u32 pba;
0022 unsigned long work_done = 0;
0023
0024 pba = vnic_intr_legacy_pba(fnic->legacy_pba);
0025 if (!pba)
0026 return IRQ_NONE;
0027
0028 fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
0029 atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
0030
0031 if (pba & (1 << FNIC_INTX_NOTIFY)) {
0032 vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_NOTIFY]);
0033 fnic_handle_link_event(fnic);
0034 }
0035
0036 if (pba & (1 << FNIC_INTX_ERR)) {
0037 vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_ERR]);
0038 fnic_log_q_error(fnic);
0039 }
0040
0041 if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) {
0042 work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions);
0043 work_done += fnic_wq_cmpl_handler(fnic, -1);
0044 work_done += fnic_rq_cmpl_handler(fnic, -1);
0045
0046 vnic_intr_return_credits(&fnic->intr[FNIC_INTX_WQ_RQ_COPYWQ],
0047 work_done,
0048 1 ,
0049 1 );
0050 }
0051
0052 return IRQ_HANDLED;
0053 }
0054
0055 static irqreturn_t fnic_isr_msi(int irq, void *data)
0056 {
0057 struct fnic *fnic = data;
0058 unsigned long work_done = 0;
0059
0060 fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
0061 atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
0062
0063 work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions);
0064 work_done += fnic_wq_cmpl_handler(fnic, -1);
0065 work_done += fnic_rq_cmpl_handler(fnic, -1);
0066
0067 vnic_intr_return_credits(&fnic->intr[0],
0068 work_done,
0069 1 ,
0070 1 );
0071
0072 return IRQ_HANDLED;
0073 }
0074
0075 static irqreturn_t fnic_isr_msix_rq(int irq, void *data)
0076 {
0077 struct fnic *fnic = data;
0078 unsigned long rq_work_done = 0;
0079
0080 fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
0081 atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
0082
0083 rq_work_done = fnic_rq_cmpl_handler(fnic, -1);
0084 vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_RQ],
0085 rq_work_done,
0086 1 ,
0087 1 );
0088
0089 return IRQ_HANDLED;
0090 }
0091
0092 static irqreturn_t fnic_isr_msix_wq(int irq, void *data)
0093 {
0094 struct fnic *fnic = data;
0095 unsigned long wq_work_done = 0;
0096
0097 fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
0098 atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
0099
0100 wq_work_done = fnic_wq_cmpl_handler(fnic, -1);
0101 vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ],
0102 wq_work_done,
0103 1 ,
0104 1 );
0105 return IRQ_HANDLED;
0106 }
0107
0108 static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data)
0109 {
0110 struct fnic *fnic = data;
0111 unsigned long wq_copy_work_done = 0;
0112
0113 fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
0114 atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
0115
0116 wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, io_completions);
0117 vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY],
0118 wq_copy_work_done,
0119 1 ,
0120 1 );
0121 return IRQ_HANDLED;
0122 }
0123
0124 static irqreturn_t fnic_isr_msix_err_notify(int irq, void *data)
0125 {
0126 struct fnic *fnic = data;
0127
0128 fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
0129 atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
0130
0131 vnic_intr_return_all_credits(&fnic->intr[FNIC_MSIX_ERR_NOTIFY]);
0132 fnic_log_q_error(fnic);
0133 fnic_handle_link_event(fnic);
0134
0135 return IRQ_HANDLED;
0136 }
0137
0138 void fnic_free_intr(struct fnic *fnic)
0139 {
0140 int i;
0141
0142 switch (vnic_dev_get_intr_mode(fnic->vdev)) {
0143 case VNIC_DEV_INTR_MODE_INTX:
0144 case VNIC_DEV_INTR_MODE_MSI:
0145 free_irq(pci_irq_vector(fnic->pdev, 0), fnic);
0146 break;
0147
0148 case VNIC_DEV_INTR_MODE_MSIX:
0149 for (i = 0; i < ARRAY_SIZE(fnic->msix); i++)
0150 if (fnic->msix[i].requested)
0151 free_irq(pci_irq_vector(fnic->pdev, i),
0152 fnic->msix[i].devid);
0153 break;
0154
0155 default:
0156 break;
0157 }
0158 }
0159
0160 int fnic_request_intr(struct fnic *fnic)
0161 {
0162 int err = 0;
0163 int i;
0164
0165 switch (vnic_dev_get_intr_mode(fnic->vdev)) {
0166
0167 case VNIC_DEV_INTR_MODE_INTX:
0168 err = request_irq(pci_irq_vector(fnic->pdev, 0),
0169 &fnic_isr_legacy, IRQF_SHARED, DRV_NAME, fnic);
0170 break;
0171
0172 case VNIC_DEV_INTR_MODE_MSI:
0173 err = request_irq(pci_irq_vector(fnic->pdev, 0), &fnic_isr_msi,
0174 0, fnic->name, fnic);
0175 break;
0176
0177 case VNIC_DEV_INTR_MODE_MSIX:
0178
0179 sprintf(fnic->msix[FNIC_MSIX_RQ].devname,
0180 "%.11s-fcs-rq", fnic->name);
0181 fnic->msix[FNIC_MSIX_RQ].isr = fnic_isr_msix_rq;
0182 fnic->msix[FNIC_MSIX_RQ].devid = fnic;
0183
0184 sprintf(fnic->msix[FNIC_MSIX_WQ].devname,
0185 "%.11s-fcs-wq", fnic->name);
0186 fnic->msix[FNIC_MSIX_WQ].isr = fnic_isr_msix_wq;
0187 fnic->msix[FNIC_MSIX_WQ].devid = fnic;
0188
0189 sprintf(fnic->msix[FNIC_MSIX_WQ_COPY].devname,
0190 "%.11s-scsi-wq", fnic->name);
0191 fnic->msix[FNIC_MSIX_WQ_COPY].isr = fnic_isr_msix_wq_copy;
0192 fnic->msix[FNIC_MSIX_WQ_COPY].devid = fnic;
0193
0194 sprintf(fnic->msix[FNIC_MSIX_ERR_NOTIFY].devname,
0195 "%.11s-err-notify", fnic->name);
0196 fnic->msix[FNIC_MSIX_ERR_NOTIFY].isr =
0197 fnic_isr_msix_err_notify;
0198 fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic;
0199
0200 for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) {
0201 err = request_irq(pci_irq_vector(fnic->pdev, i),
0202 fnic->msix[i].isr, 0,
0203 fnic->msix[i].devname,
0204 fnic->msix[i].devid);
0205 if (err) {
0206 shost_printk(KERN_ERR, fnic->lport->host,
0207 "MSIX: request_irq"
0208 " failed %d\n", err);
0209 fnic_free_intr(fnic);
0210 break;
0211 }
0212 fnic->msix[i].requested = 1;
0213 }
0214 break;
0215
0216 default:
0217 break;
0218 }
0219
0220 return err;
0221 }
0222
0223 int fnic_set_intr_mode(struct fnic *fnic)
0224 {
0225 unsigned int n = ARRAY_SIZE(fnic->rq);
0226 unsigned int m = ARRAY_SIZE(fnic->wq);
0227 unsigned int o = ARRAY_SIZE(fnic->wq_copy);
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 if (fnic->rq_count >= n &&
0239 fnic->raw_wq_count >= m &&
0240 fnic->wq_copy_count >= o &&
0241 fnic->cq_count >= n + m + o) {
0242 int vecs = n + m + o + 1;
0243
0244 if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs,
0245 PCI_IRQ_MSIX) == vecs) {
0246 fnic->rq_count = n;
0247 fnic->raw_wq_count = m;
0248 fnic->wq_copy_count = o;
0249 fnic->wq_count = m + o;
0250 fnic->cq_count = n + m + o;
0251 fnic->intr_count = vecs;
0252 fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY;
0253
0254 FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
0255 "Using MSI-X Interrupts\n");
0256 vnic_dev_set_intr_mode(fnic->vdev,
0257 VNIC_DEV_INTR_MODE_MSIX);
0258 return 0;
0259 }
0260 }
0261
0262
0263
0264
0265
0266 if (fnic->rq_count >= 1 &&
0267 fnic->raw_wq_count >= 1 &&
0268 fnic->wq_copy_count >= 1 &&
0269 fnic->cq_count >= 3 &&
0270 fnic->intr_count >= 1 &&
0271 pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) == 1) {
0272 fnic->rq_count = 1;
0273 fnic->raw_wq_count = 1;
0274 fnic->wq_copy_count = 1;
0275 fnic->wq_count = 2;
0276 fnic->cq_count = 3;
0277 fnic->intr_count = 1;
0278 fnic->err_intr_offset = 0;
0279
0280 FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
0281 "Using MSI Interrupts\n");
0282 vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI);
0283
0284 return 0;
0285 }
0286
0287
0288
0289
0290
0291
0292
0293
0294 if (fnic->rq_count >= 1 &&
0295 fnic->raw_wq_count >= 1 &&
0296 fnic->wq_copy_count >= 1 &&
0297 fnic->cq_count >= 3 &&
0298 fnic->intr_count >= 3) {
0299
0300 fnic->rq_count = 1;
0301 fnic->raw_wq_count = 1;
0302 fnic->wq_copy_count = 1;
0303 fnic->cq_count = 3;
0304 fnic->intr_count = 3;
0305
0306 FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
0307 "Using Legacy Interrupts\n");
0308 vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
0309
0310 return 0;
0311 }
0312
0313 vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
0314
0315 return -EINVAL;
0316 }
0317
0318 void fnic_clear_intr_mode(struct fnic *fnic)
0319 {
0320 pci_free_irq_vectors(fnic->pdev);
0321 vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
0322 }