Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
0004  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
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 /* unmask intr */,
0049                      1 /* reset intr timer */);
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 /* unmask intr */,
0070                  1 /* reset intr timer */);
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 /* unmask intr */,
0087                  1 /* reset intr timer */);
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 /* unmask intr */,
0104                  1 /* reset intr timer */);
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 /* unmask intr */,
0120                  1 /* reset intr timer */);
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      * Set interrupt mode (INTx, MSI, MSI-X) depending
0231      * system capabilities.
0232      *
0233      * Try MSI-X first
0234      *
0235      * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs
0236      * (last INTR is used for WQ/RQ errors and notification area)
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      * Next try MSI
0264      * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 1 INTR
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      * Next try INTx
0289      * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 3 INTRs
0290      * 1 INTR is used for all 3 queues, 1 INTR for queue errors
0291      * 1 INTR for notification area
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 }