2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License (GPL) Version 2 as
10 * published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
19 #include "bfad_trcmod.h"
21 BFA_TRC_FILE(LDRV, INTR);
24 * bfa_isr BFA driver interrupt functions
26 static int msix_disable;
27 module_param(msix_disable, int, S_IRUGO | S_IWUSR);
29 * Line based interrupt handler.
32 bfad_intx(int irq, void *dev_id)
34 struct bfad_s *bfad = dev_id;
35 struct list_head doneq;
39 spin_lock_irqsave(&bfad->bfad_lock, flags);
40 rc = bfa_intx(&bfad->bfa);
42 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
46 bfa_comp_deq(&bfad->bfa, &doneq);
47 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
49 if (!list_empty(&doneq)) {
50 bfa_comp_process(&bfad->bfa, &doneq);
52 spin_lock_irqsave(&bfad->bfad_lock, flags);
53 bfa_comp_free(&bfad->bfa, &doneq);
54 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
55 bfa_trc_fp(bfad, irq);
63 bfad_msix(int irq, void *dev_id)
65 struct bfad_msix_s *vec = dev_id;
66 struct bfad_s *bfad = vec->bfad;
67 struct list_head doneq;
70 spin_lock_irqsave(&bfad->bfad_lock, flags);
72 bfa_msix(&bfad->bfa, vec->msix.entry);
73 bfa_comp_deq(&bfad->bfa, &doneq);
74 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
76 if (!list_empty(&doneq)) {
77 bfa_comp_process(&bfad->bfa, &doneq);
79 spin_lock_irqsave(&bfad->bfad_lock, flags);
80 bfa_comp_free(&bfad->bfa, &doneq);
81 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
88 * Initialize the MSIX entry table.
91 bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries,
92 int mask, int max_bit)
95 int match = 0x00000001;
97 for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) {
99 bfad->msix_tab[bfad->nvec].msix.entry = i;
100 bfad->msix_tab[bfad->nvec].bfad = bfad;
101 msix_entries[bfad->nvec].entry = i;
111 bfad_install_msix_handler(struct bfad_s *bfad)
115 for (i = 0; i < bfad->nvec; i++) {
116 error = request_irq(bfad->msix_tab[i].msix.vector,
117 (irq_handler_t) bfad_msix, 0,
118 BFAD_DRIVER_NAME, &bfad->msix_tab[i]);
120 bfa_trc(bfad, bfad->msix_tab[i].msix.vector);
124 for (j = 0; j < i; j++)
125 free_irq(bfad->msix_tab[j].msix.vector,
136 * Setup MSIX based interrupt.
139 bfad_setup_intr(struct bfad_s *bfad)
142 u32 mask = 0, i, num_bit = 0, max_bit = 0;
143 struct msix_entry msix_entries[MAX_MSIX_ENTRY];
145 /* Call BFA to get the msix map for this PCI function. */
146 bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit);
148 /* Set up the msix entry table */
149 bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
152 error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
155 * Only error number of vector is available.
156 * We don't have a mechanism to map multiple
157 * interrupts into one vector, so even if we
158 * can try to request less vectors, we don't
159 * know how to associate interrupt events to
160 * vectors. Linux doesn't dupicate vectors
161 * in the MSIX table for this case.
164 printk(KERN_WARNING "bfad%d: "
165 "pci_enable_msix failed (%d),"
166 " use line based.\n", bfad->inst_no, error);
171 /* Save the vectors */
172 for (i = 0; i < bfad->nvec; i++) {
173 bfa_trc(bfad, msix_entries[i].vector);
174 bfad->msix_tab[i].msix.vector = msix_entries[i].vector;
177 bfa_msix_init(&bfad->bfa, bfad->nvec);
179 bfad->bfad_flags |= BFAD_MSIX_ON;
187 (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS,
188 BFAD_DRIVER_NAME, bfad) != 0) {
189 /* Enable interrupt handler failed */
197 bfad_remove_intr(struct bfad_s *bfad)
201 if (bfad->bfad_flags & BFAD_MSIX_ON) {
202 for (i = 0; i < bfad->nvec; i++)
203 free_irq(bfad->msix_tab[i].msix.vector,
206 pci_disable_msix(bfad->pcidev);
207 bfad->bfad_flags &= ~BFAD_MSIX_ON;
209 free_irq(bfad->pcidev->irq, bfad);