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