cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fnic_isr.c (8800B)


      1/*
      2 * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
      3 * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
      4 *
      5 * This program is free software; you may redistribute it and/or modify
      6 * it under the terms of the GNU General Public License as published by
      7 * the Free Software Foundation; version 2 of the License.
      8 *
      9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     10 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     11 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     12 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     13 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     14 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     15 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     16 * SOFTWARE.
     17 */
     18#include <linux/string.h>
     19#include <linux/errno.h>
     20#include <linux/pci.h>
     21#include <linux/interrupt.h>
     22#include <scsi/libfc.h>
     23#include <scsi/fc_frame.h>
     24#include "vnic_dev.h"
     25#include "vnic_intr.h"
     26#include "vnic_stats.h"
     27#include "fnic_io.h"
     28#include "fnic.h"
     29
     30static irqreturn_t fnic_isr_legacy(int irq, void *data)
     31{
     32	struct fnic *fnic = data;
     33	u32 pba;
     34	unsigned long work_done = 0;
     35
     36	pba = vnic_intr_legacy_pba(fnic->legacy_pba);
     37	if (!pba)
     38		return IRQ_NONE;
     39
     40	fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
     41	atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
     42
     43	if (pba & (1 << FNIC_INTX_NOTIFY)) {
     44		vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_NOTIFY]);
     45		fnic_handle_link_event(fnic);
     46	}
     47
     48	if (pba & (1 << FNIC_INTX_ERR)) {
     49		vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_ERR]);
     50		fnic_log_q_error(fnic);
     51	}
     52
     53	if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) {
     54		work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions);
     55		work_done += fnic_wq_cmpl_handler(fnic, -1);
     56		work_done += fnic_rq_cmpl_handler(fnic, -1);
     57
     58		vnic_intr_return_credits(&fnic->intr[FNIC_INTX_WQ_RQ_COPYWQ],
     59					 work_done,
     60					 1 /* unmask intr */,
     61					 1 /* reset intr timer */);
     62	}
     63
     64	return IRQ_HANDLED;
     65}
     66
     67static irqreturn_t fnic_isr_msi(int irq, void *data)
     68{
     69	struct fnic *fnic = data;
     70	unsigned long work_done = 0;
     71
     72	fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
     73	atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
     74
     75	work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions);
     76	work_done += fnic_wq_cmpl_handler(fnic, -1);
     77	work_done += fnic_rq_cmpl_handler(fnic, -1);
     78
     79	vnic_intr_return_credits(&fnic->intr[0],
     80				 work_done,
     81				 1 /* unmask intr */,
     82				 1 /* reset intr timer */);
     83
     84	return IRQ_HANDLED;
     85}
     86
     87static irqreturn_t fnic_isr_msix_rq(int irq, void *data)
     88{
     89	struct fnic *fnic = data;
     90	unsigned long rq_work_done = 0;
     91
     92	fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
     93	atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
     94
     95	rq_work_done = fnic_rq_cmpl_handler(fnic, -1);
     96	vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_RQ],
     97				 rq_work_done,
     98				 1 /* unmask intr */,
     99				 1 /* reset intr timer */);
    100
    101	return IRQ_HANDLED;
    102}
    103
    104static irqreturn_t fnic_isr_msix_wq(int irq, void *data)
    105{
    106	struct fnic *fnic = data;
    107	unsigned long wq_work_done = 0;
    108
    109	fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
    110	atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
    111
    112	wq_work_done = fnic_wq_cmpl_handler(fnic, -1);
    113	vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ],
    114				 wq_work_done,
    115				 1 /* unmask intr */,
    116				 1 /* reset intr timer */);
    117	return IRQ_HANDLED;
    118}
    119
    120static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data)
    121{
    122	struct fnic *fnic = data;
    123	unsigned long wq_copy_work_done = 0;
    124
    125	fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
    126	atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
    127
    128	wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, io_completions);
    129	vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY],
    130				 wq_copy_work_done,
    131				 1 /* unmask intr */,
    132				 1 /* reset intr timer */);
    133	return IRQ_HANDLED;
    134}
    135
    136static irqreturn_t fnic_isr_msix_err_notify(int irq, void *data)
    137{
    138	struct fnic *fnic = data;
    139
    140	fnic->fnic_stats.misc_stats.last_isr_time = jiffies;
    141	atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count);
    142
    143	vnic_intr_return_all_credits(&fnic->intr[FNIC_MSIX_ERR_NOTIFY]);
    144	fnic_log_q_error(fnic);
    145	fnic_handle_link_event(fnic);
    146
    147	return IRQ_HANDLED;
    148}
    149
    150void fnic_free_intr(struct fnic *fnic)
    151{
    152	int i;
    153
    154	switch (vnic_dev_get_intr_mode(fnic->vdev)) {
    155	case VNIC_DEV_INTR_MODE_INTX:
    156	case VNIC_DEV_INTR_MODE_MSI:
    157		free_irq(pci_irq_vector(fnic->pdev, 0), fnic);
    158		break;
    159
    160	case VNIC_DEV_INTR_MODE_MSIX:
    161		for (i = 0; i < ARRAY_SIZE(fnic->msix); i++)
    162			if (fnic->msix[i].requested)
    163				free_irq(pci_irq_vector(fnic->pdev, i),
    164					 fnic->msix[i].devid);
    165		break;
    166
    167	default:
    168		break;
    169	}
    170}
    171
    172int fnic_request_intr(struct fnic *fnic)
    173{
    174	int err = 0;
    175	int i;
    176
    177	switch (vnic_dev_get_intr_mode(fnic->vdev)) {
    178
    179	case VNIC_DEV_INTR_MODE_INTX:
    180		err = request_irq(pci_irq_vector(fnic->pdev, 0),
    181				&fnic_isr_legacy, IRQF_SHARED, DRV_NAME, fnic);
    182		break;
    183
    184	case VNIC_DEV_INTR_MODE_MSI:
    185		err = request_irq(pci_irq_vector(fnic->pdev, 0), &fnic_isr_msi,
    186				  0, fnic->name, fnic);
    187		break;
    188
    189	case VNIC_DEV_INTR_MODE_MSIX:
    190
    191		sprintf(fnic->msix[FNIC_MSIX_RQ].devname,
    192			"%.11s-fcs-rq", fnic->name);
    193		fnic->msix[FNIC_MSIX_RQ].isr = fnic_isr_msix_rq;
    194		fnic->msix[FNIC_MSIX_RQ].devid = fnic;
    195
    196		sprintf(fnic->msix[FNIC_MSIX_WQ].devname,
    197			"%.11s-fcs-wq", fnic->name);
    198		fnic->msix[FNIC_MSIX_WQ].isr = fnic_isr_msix_wq;
    199		fnic->msix[FNIC_MSIX_WQ].devid = fnic;
    200
    201		sprintf(fnic->msix[FNIC_MSIX_WQ_COPY].devname,
    202			"%.11s-scsi-wq", fnic->name);
    203		fnic->msix[FNIC_MSIX_WQ_COPY].isr = fnic_isr_msix_wq_copy;
    204		fnic->msix[FNIC_MSIX_WQ_COPY].devid = fnic;
    205
    206		sprintf(fnic->msix[FNIC_MSIX_ERR_NOTIFY].devname,
    207			"%.11s-err-notify", fnic->name);
    208		fnic->msix[FNIC_MSIX_ERR_NOTIFY].isr =
    209			fnic_isr_msix_err_notify;
    210		fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic;
    211
    212		for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) {
    213			err = request_irq(pci_irq_vector(fnic->pdev, i),
    214					  fnic->msix[i].isr, 0,
    215					  fnic->msix[i].devname,
    216					  fnic->msix[i].devid);
    217			if (err) {
    218				shost_printk(KERN_ERR, fnic->lport->host,
    219					     "MSIX: request_irq"
    220					     " failed %d\n", err);
    221				fnic_free_intr(fnic);
    222				break;
    223			}
    224			fnic->msix[i].requested = 1;
    225		}
    226		break;
    227
    228	default:
    229		break;
    230	}
    231
    232	return err;
    233}
    234
    235int fnic_set_intr_mode(struct fnic *fnic)
    236{
    237	unsigned int n = ARRAY_SIZE(fnic->rq);
    238	unsigned int m = ARRAY_SIZE(fnic->wq);
    239	unsigned int o = ARRAY_SIZE(fnic->wq_copy);
    240
    241	/*
    242	 * Set interrupt mode (INTx, MSI, MSI-X) depending
    243	 * system capabilities.
    244	 *
    245	 * Try MSI-X first
    246	 *
    247	 * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs
    248	 * (last INTR is used for WQ/RQ errors and notification area)
    249	 */
    250	if (fnic->rq_count >= n &&
    251	    fnic->raw_wq_count >= m &&
    252	    fnic->wq_copy_count >= o &&
    253	    fnic->cq_count >= n + m + o) {
    254		int vecs = n + m + o + 1;
    255
    256		if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs,
    257				PCI_IRQ_MSIX) == vecs) {
    258			fnic->rq_count = n;
    259			fnic->raw_wq_count = m;
    260			fnic->wq_copy_count = o;
    261			fnic->wq_count = m + o;
    262			fnic->cq_count = n + m + o;
    263			fnic->intr_count = vecs;
    264			fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY;
    265
    266			FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
    267				     "Using MSI-X Interrupts\n");
    268			vnic_dev_set_intr_mode(fnic->vdev,
    269					       VNIC_DEV_INTR_MODE_MSIX);
    270			return 0;
    271		}
    272	}
    273
    274	/*
    275	 * Next try MSI
    276	 * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 1 INTR
    277	 */
    278	if (fnic->rq_count >= 1 &&
    279	    fnic->raw_wq_count >= 1 &&
    280	    fnic->wq_copy_count >= 1 &&
    281	    fnic->cq_count >= 3 &&
    282	    fnic->intr_count >= 1 &&
    283	    pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) == 1) {
    284		fnic->rq_count = 1;
    285		fnic->raw_wq_count = 1;
    286		fnic->wq_copy_count = 1;
    287		fnic->wq_count = 2;
    288		fnic->cq_count = 3;
    289		fnic->intr_count = 1;
    290		fnic->err_intr_offset = 0;
    291
    292		FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
    293			     "Using MSI Interrupts\n");
    294		vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI);
    295
    296		return 0;
    297	}
    298
    299	/*
    300	 * Next try INTx
    301	 * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 3 INTRs
    302	 * 1 INTR is used for all 3 queues, 1 INTR for queue errors
    303	 * 1 INTR for notification area
    304	 */
    305
    306	if (fnic->rq_count >= 1 &&
    307	    fnic->raw_wq_count >= 1 &&
    308	    fnic->wq_copy_count >= 1 &&
    309	    fnic->cq_count >= 3 &&
    310	    fnic->intr_count >= 3) {
    311
    312		fnic->rq_count = 1;
    313		fnic->raw_wq_count = 1;
    314		fnic->wq_copy_count = 1;
    315		fnic->cq_count = 3;
    316		fnic->intr_count = 3;
    317
    318		FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host,
    319			     "Using Legacy Interrupts\n");
    320		vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
    321
    322		return 0;
    323	}
    324
    325	vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
    326
    327	return -EINVAL;
    328}
    329
    330void fnic_clear_intr_mode(struct fnic *fnic)
    331{
    332	pci_free_irq_vectors(fnic->pdev);
    333	vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
    334}
    335