root/drivers/scsi/snic/snic_isr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snic_isr_msix_wq
  2. snic_isr_msix_io_cmpl
  3. snic_isr_msix_err_notify
  4. snic_free_intr
  5. snic_request_intr
  6. snic_set_intr_mode
  7. snic_clear_intr_mode

   1 /*
   2  * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
   3  *
   4  * This program is free software; you may redistribute it and/or modify
   5  * it under the terms of the GNU General Public License as published by
   6  * the Free Software Foundation; version 2 of the License.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   9  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  10  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  11  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  12  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  13  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  14  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  15  * SOFTWARE.
  16  */
  17 
  18 #include <linux/string.h>
  19 #include <linux/errno.h>
  20 #include <linux/pci.h>
  21 #include <linux/interrupt.h>
  22 
  23 #include "vnic_dev.h"
  24 #include "vnic_intr.h"
  25 #include "vnic_stats.h"
  26 #include "snic_io.h"
  27 #include "snic.h"
  28 
  29 
  30 /*
  31  * snic_isr_msix_wq : MSIx ISR for work queue.
  32  */
  33 
  34 static irqreturn_t
  35 snic_isr_msix_wq(int irq, void *data)
  36 {
  37         struct snic *snic = data;
  38         unsigned long wq_work_done = 0;
  39 
  40         snic->s_stats.misc.last_isr_time = jiffies;
  41         atomic64_inc(&snic->s_stats.misc.ack_isr_cnt);
  42 
  43         wq_work_done = snic_wq_cmpl_handler(snic, -1);
  44         svnic_intr_return_credits(&snic->intr[SNIC_MSIX_WQ],
  45                                   wq_work_done,
  46                                   1 /* unmask intr */,
  47                                   1 /* reset intr timer */);
  48 
  49         return IRQ_HANDLED;
  50 } /* end of snic_isr_msix_wq */
  51 
  52 static irqreturn_t
  53 snic_isr_msix_io_cmpl(int irq, void *data)
  54 {
  55         struct snic *snic = data;
  56         unsigned long iocmpl_work_done = 0;
  57 
  58         snic->s_stats.misc.last_isr_time = jiffies;
  59         atomic64_inc(&snic->s_stats.misc.cmpl_isr_cnt);
  60 
  61         iocmpl_work_done = snic_fwcq_cmpl_handler(snic, -1);
  62         svnic_intr_return_credits(&snic->intr[SNIC_MSIX_IO_CMPL],
  63                                   iocmpl_work_done,
  64                                   1 /* unmask intr */,
  65                                   1 /* reset intr timer */);
  66 
  67         return IRQ_HANDLED;
  68 } /* end of snic_isr_msix_io_cmpl */
  69 
  70 static irqreturn_t
  71 snic_isr_msix_err_notify(int irq, void *data)
  72 {
  73         struct snic *snic = data;
  74 
  75         snic->s_stats.misc.last_isr_time = jiffies;
  76         atomic64_inc(&snic->s_stats.misc.errnotify_isr_cnt);
  77 
  78         svnic_intr_return_all_credits(&snic->intr[SNIC_MSIX_ERR_NOTIFY]);
  79         snic_log_q_error(snic);
  80 
  81         /*Handling link events */
  82         snic_handle_link_event(snic);
  83 
  84         return IRQ_HANDLED;
  85 } /* end of snic_isr_msix_err_notify */
  86 
  87 
  88 void
  89 snic_free_intr(struct snic *snic)
  90 {
  91         int i;
  92 
  93         /* ONLY interrupt mode MSIX is supported */
  94         for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {
  95                 if (snic->msix[i].requested) {
  96                         free_irq(pci_irq_vector(snic->pdev, i),
  97                                  snic->msix[i].devid);
  98                 }
  99         }
 100 } /* end of snic_free_intr */
 101 
 102 int
 103 snic_request_intr(struct snic *snic)
 104 {
 105         int ret = 0, i;
 106         enum vnic_dev_intr_mode intr_mode;
 107 
 108         intr_mode = svnic_dev_get_intr_mode(snic->vdev);
 109         SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
 110 
 111         /*
 112          * Currently HW supports single WQ and CQ. So passing devid as snic.
 113          * When hardware supports multiple WQs and CQs, one idea is
 114          * to pass devid as corresponding WQ or CQ ptr and retrieve snic
 115          * from queue ptr.
 116          * Except for err_notify, which is always one.
 117          */
 118         sprintf(snic->msix[SNIC_MSIX_WQ].devname,
 119                 "%.11s-scsi-wq",
 120                 snic->name);
 121         snic->msix[SNIC_MSIX_WQ].isr = snic_isr_msix_wq;
 122         snic->msix[SNIC_MSIX_WQ].devid = snic;
 123 
 124         sprintf(snic->msix[SNIC_MSIX_IO_CMPL].devname,
 125                 "%.11s-io-cmpl",
 126                 snic->name);
 127         snic->msix[SNIC_MSIX_IO_CMPL].isr = snic_isr_msix_io_cmpl;
 128         snic->msix[SNIC_MSIX_IO_CMPL].devid = snic;
 129 
 130         sprintf(snic->msix[SNIC_MSIX_ERR_NOTIFY].devname,
 131                 "%.11s-err-notify",
 132                 snic->name);
 133         snic->msix[SNIC_MSIX_ERR_NOTIFY].isr = snic_isr_msix_err_notify;
 134         snic->msix[SNIC_MSIX_ERR_NOTIFY].devid = snic;
 135 
 136         for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {
 137                 ret = request_irq(pci_irq_vector(snic->pdev, i),
 138                                   snic->msix[i].isr,
 139                                   0,
 140                                   snic->msix[i].devname,
 141                                   snic->msix[i].devid);
 142                 if (ret) {
 143                         SNIC_HOST_ERR(snic->shost,
 144                                       "MSI-X: request_irq(%d) failed %d\n",
 145                                       i,
 146                                       ret);
 147                         snic_free_intr(snic);
 148                         break;
 149                 }
 150                 snic->msix[i].requested = 1;
 151         }
 152 
 153         return ret;
 154 } /* end of snic_request_intr */
 155 
 156 int
 157 snic_set_intr_mode(struct snic *snic)
 158 {
 159         unsigned int n = ARRAY_SIZE(snic->wq);
 160         unsigned int m = SNIC_CQ_IO_CMPL_MAX;
 161         unsigned int vecs = n + m + 1;
 162 
 163         /*
 164          * We need n WQs, m CQs, and n+m+1 INTRs
 165          * (last INTR is used for WQ/CQ errors and notification area
 166          */
 167         BUILD_BUG_ON((ARRAY_SIZE(snic->wq) + SNIC_CQ_IO_CMPL_MAX) >
 168                         ARRAY_SIZE(snic->intr));
 169 
 170         if (snic->wq_count < n || snic->cq_count < n + m)
 171                 goto fail;
 172 
 173         if (pci_alloc_irq_vectors(snic->pdev, vecs, vecs, PCI_IRQ_MSIX) < 0)
 174                 goto fail;
 175 
 176         snic->wq_count = n;
 177         snic->cq_count = n + m;
 178         snic->intr_count = vecs;
 179         snic->err_intr_offset = SNIC_MSIX_ERR_NOTIFY;
 180 
 181         SNIC_ISR_DBG(snic->shost, "Using MSI-X Interrupts\n");
 182         svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_MSIX);
 183         return 0;
 184 fail:
 185         svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
 186         return -EINVAL;
 187 } /* end of snic_set_intr_mode */
 188 
 189 void
 190 snic_clear_intr_mode(struct snic *snic)
 191 {
 192         pci_free_irq_vectors(snic->pdev);
 193         svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_INTX);
 194 }

/* [<][>][^][v][top][bottom][index][help] */