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 irqreturn_t
bfad_intx(int irq
, void *dev_id
);
27 static int msix_disable
;
28 module_param(msix_disable
, int, S_IRUGO
| S_IWUSR
);
30 * Line based interrupt handler.
33 bfad_intx(int irq
, void *dev_id
)
35 struct bfad_s
*bfad
= dev_id
;
36 struct list_head doneq
;
40 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
41 rc
= bfa_intx(&bfad
->bfa
);
43 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
47 bfa_comp_deq(&bfad
->bfa
, &doneq
);
48 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
50 if (!list_empty(&doneq
)) {
51 bfa_comp_process(&bfad
->bfa
, &doneq
);
53 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
54 bfa_comp_free(&bfad
->bfa
, &doneq
);
55 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
56 bfa_trc_fp(bfad
, irq
);
64 bfad_msix(int irq
, void *dev_id
)
66 struct bfad_msix_s
*vec
= dev_id
;
67 struct bfad_s
*bfad
= vec
->bfad
;
68 struct list_head doneq
;
71 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
73 bfa_msix(&bfad
->bfa
, vec
->msix
.entry
);
74 bfa_comp_deq(&bfad
->bfa
, &doneq
);
75 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
77 if (!list_empty(&doneq
)) {
78 bfa_comp_process(&bfad
->bfa
, &doneq
);
80 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
81 bfa_comp_free(&bfad
->bfa
, &doneq
);
82 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
89 * Initialize the MSIX entry table.
92 bfad_init_msix_entry(struct bfad_s
*bfad
, struct msix_entry
*msix_entries
,
93 int mask
, int max_bit
)
96 int match
= 0x00000001;
98 for (i
= 0, bfad
->nvec
= 0; i
< MAX_MSIX_ENTRY
; i
++) {
100 bfad
->msix_tab
[bfad
->nvec
].msix
.entry
= i
;
101 bfad
->msix_tab
[bfad
->nvec
].bfad
= bfad
;
102 msix_entries
[bfad
->nvec
].entry
= i
;
112 bfad_install_msix_handler(struct bfad_s
*bfad
)
116 for (i
= 0; i
< bfad
->nvec
; i
++) {
117 error
= request_irq(bfad
->msix_tab
[i
].msix
.vector
,
118 (irq_handler_t
) bfad_msix
, 0,
119 BFAD_DRIVER_NAME
, &bfad
->msix_tab
[i
]);
121 bfa_trc(bfad
, bfad
->msix_tab
[i
].msix
.vector
);
125 for (j
= 0; j
< i
; j
++)
126 free_irq(bfad
->msix_tab
[j
].msix
.vector
,
137 * Setup MSIX based interrupt.
140 bfad_setup_intr(struct bfad_s
*bfad
)
143 u32 mask
= 0, i
, num_bit
= 0, max_bit
= 0;
144 struct msix_entry msix_entries
[MAX_MSIX_ENTRY
];
146 /* Call BFA to get the msix map for this PCI function. */
147 bfa_msix_getvecs(&bfad
->bfa
, &mask
, &num_bit
, &max_bit
);
149 /* Set up the msix entry table */
150 bfad_init_msix_entry(bfad
, msix_entries
, mask
, max_bit
);
153 error
= pci_enable_msix(bfad
->pcidev
, msix_entries
, bfad
->nvec
);
156 * Only error number of vector is available.
157 * We don't have a mechanism to map multiple
158 * interrupts into one vector, so even if we
159 * can try to request less vectors, we don't
160 * know how to associate interrupt events to
161 * vectors. Linux doesn't dupicate vectors
162 * in the MSIX table for this case.
165 printk(KERN_WARNING
"bfad%d: "
166 "pci_enable_msix failed (%d),"
167 " use line based.\n", bfad
->inst_no
, error
);
172 /* Save the vectors */
173 for (i
= 0; i
< bfad
->nvec
; i
++) {
174 bfa_trc(bfad
, msix_entries
[i
].vector
);
175 bfad
->msix_tab
[i
].msix
.vector
= msix_entries
[i
].vector
;
178 bfa_msix_init(&bfad
->bfa
, bfad
->nvec
);
180 bfad
->bfad_flags
|= BFAD_MSIX_ON
;
188 (bfad
->pcidev
->irq
, (irq_handler_t
) bfad_intx
, BFAD_IRQ_FLAGS
,
189 BFAD_DRIVER_NAME
, bfad
) != 0) {
190 /* Enable interrupt handler failed */
198 bfad_remove_intr(struct bfad_s
*bfad
)
202 if (bfad
->bfad_flags
& BFAD_MSIX_ON
) {
203 for (i
= 0; i
< bfad
->nvec
; i
++)
204 free_irq(bfad
->msix_tab
[i
].msix
.vector
,
207 pci_disable_msix(bfad
->pcidev
);
208 bfad
->bfad_flags
&= ~BFAD_MSIX_ON
;
210 free_irq(bfad
->pcidev
->irq
, bfad
);