brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 471a374 Raw
181 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// Copyright 2014 Cisco Systems, Inc.  All rights reserved.3 4#include <linux/string.h>5#include <linux/errno.h>6#include <linux/pci.h>7#include <linux/interrupt.h>8 9#include "vnic_dev.h"10#include "vnic_intr.h"11#include "vnic_stats.h"12#include "snic_io.h"13#include "snic.h"14 15 16/*17 * snic_isr_msix_wq : MSIx ISR for work queue.18 */19 20static irqreturn_t21snic_isr_msix_wq(int irq, void *data)22{23	struct snic *snic = data;24	unsigned long wq_work_done = 0;25 26	snic->s_stats.misc.last_isr_time = jiffies;27	atomic64_inc(&snic->s_stats.misc.ack_isr_cnt);28 29	wq_work_done = snic_wq_cmpl_handler(snic, -1);30	svnic_intr_return_credits(&snic->intr[SNIC_MSIX_WQ],31				  wq_work_done,32				  1 /* unmask intr */,33				  1 /* reset intr timer */);34 35	return IRQ_HANDLED;36} /* end of snic_isr_msix_wq */37 38static irqreturn_t39snic_isr_msix_io_cmpl(int irq, void *data)40{41	struct snic *snic = data;42	unsigned long iocmpl_work_done = 0;43 44	snic->s_stats.misc.last_isr_time = jiffies;45	atomic64_inc(&snic->s_stats.misc.cmpl_isr_cnt);46 47	iocmpl_work_done = snic_fwcq_cmpl_handler(snic, -1);48	svnic_intr_return_credits(&snic->intr[SNIC_MSIX_IO_CMPL],49				  iocmpl_work_done,50				  1 /* unmask intr */,51				  1 /* reset intr timer */);52 53	return IRQ_HANDLED;54} /* end of snic_isr_msix_io_cmpl */55 56static irqreturn_t57snic_isr_msix_err_notify(int irq, void *data)58{59	struct snic *snic = data;60 61	snic->s_stats.misc.last_isr_time = jiffies;62	atomic64_inc(&snic->s_stats.misc.errnotify_isr_cnt);63 64	svnic_intr_return_all_credits(&snic->intr[SNIC_MSIX_ERR_NOTIFY]);65	snic_log_q_error(snic);66 67	/*Handling link events */68	snic_handle_link_event(snic);69 70	return IRQ_HANDLED;71} /* end of snic_isr_msix_err_notify */72 73 74void75snic_free_intr(struct snic *snic)76{77	int i;78 79	/* ONLY interrupt mode MSIX is supported */80	for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {81		if (snic->msix[i].requested) {82			free_irq(pci_irq_vector(snic->pdev, i),83				 snic->msix[i].devid);84		}85	}86} /* end of snic_free_intr */87 88int89snic_request_intr(struct snic *snic)90{91	int ret = 0, i;92	enum vnic_dev_intr_mode intr_mode;93 94	intr_mode = svnic_dev_get_intr_mode(snic->vdev);95	SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);96 97	/*98	 * Currently HW supports single WQ and CQ. So passing devid as snic.99	 * When hardware supports multiple WQs and CQs, one idea is100	 * to pass devid as corresponding WQ or CQ ptr and retrieve snic101	 * from queue ptr.102	 * Except for err_notify, which is always one.103	 */104	sprintf(snic->msix[SNIC_MSIX_WQ].devname,105		"%.11s-scsi-wq",106		snic->name);107	snic->msix[SNIC_MSIX_WQ].isr = snic_isr_msix_wq;108	snic->msix[SNIC_MSIX_WQ].devid = snic;109 110	sprintf(snic->msix[SNIC_MSIX_IO_CMPL].devname,111		"%.11s-io-cmpl",112		snic->name);113	snic->msix[SNIC_MSIX_IO_CMPL].isr = snic_isr_msix_io_cmpl;114	snic->msix[SNIC_MSIX_IO_CMPL].devid = snic;115 116	sprintf(snic->msix[SNIC_MSIX_ERR_NOTIFY].devname,117		"%.11s-err-notify",118		snic->name);119	snic->msix[SNIC_MSIX_ERR_NOTIFY].isr = snic_isr_msix_err_notify;120	snic->msix[SNIC_MSIX_ERR_NOTIFY].devid = snic;121 122	for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {123		ret = request_irq(pci_irq_vector(snic->pdev, i),124				  snic->msix[i].isr,125				  0,126				  snic->msix[i].devname,127				  snic->msix[i].devid);128		if (ret) {129			SNIC_HOST_ERR(snic->shost,130				      "MSI-X: request_irq(%d) failed %d\n",131				      i,132				      ret);133			snic_free_intr(snic);134			break;135		}136		snic->msix[i].requested = 1;137	}138 139	return ret;140} /* end of snic_request_intr */141 142int143snic_set_intr_mode(struct snic *snic)144{145	unsigned int n = ARRAY_SIZE(snic->wq);146	unsigned int m = SNIC_CQ_IO_CMPL_MAX;147	unsigned int vecs = n + m + 1;148 149	/*150	 * We need n WQs, m CQs, and n+m+1 INTRs151	 * (last INTR is used for WQ/CQ errors and notification area152	 */153	BUILD_BUG_ON((ARRAY_SIZE(snic->wq) + SNIC_CQ_IO_CMPL_MAX) >154			ARRAY_SIZE(snic->intr));155 156	if (snic->wq_count < n || snic->cq_count < n + m)157		goto fail;158 159	if (pci_alloc_irq_vectors(snic->pdev, vecs, vecs, PCI_IRQ_MSIX) < 0)160		goto fail;161 162	snic->wq_count = n;163	snic->cq_count = n + m;164	snic->intr_count = vecs;165	snic->err_intr_offset = SNIC_MSIX_ERR_NOTIFY;166 167	SNIC_ISR_DBG(snic->shost, "Using MSI-X Interrupts\n");168	svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_MSIX);169	return 0;170fail:171	svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);172	return -EINVAL;173} /* end of snic_set_intr_mode */174 175void176snic_clear_intr_mode(struct snic *snic)177{178	pci_free_irq_vectors(snic->pdev);179	svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_INTX);180}181