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_cb
;
27 static int msix_disable_ct
;
28 module_param(msix_disable_cb
, int, S_IRUGO
| S_IWUSR
);
29 MODULE_PARM_DESC(msix_disable_cb
, "Disable MSIX for Brocade-415/425/815/825"
30 " cards, default=0, Range[false:0|true:1]");
31 module_param(msix_disable_ct
, int, S_IRUGO
| S_IWUSR
);
32 MODULE_PARM_DESC(msix_disable_ct
, "Disable MSIX for Brocade-1010/1020/804"
33 " cards, default=0, Range[false:0|true:1]");
35 * Line based interrupt handler.
38 bfad_intx(int irq
, void *dev_id
)
40 struct bfad_s
*bfad
= dev_id
;
41 struct list_head doneq
;
45 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
46 rc
= bfa_intx(&bfad
->bfa
);
48 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
52 bfa_comp_deq(&bfad
->bfa
, &doneq
);
53 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
55 if (!list_empty(&doneq
)) {
56 bfa_comp_process(&bfad
->bfa
, &doneq
);
58 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
59 bfa_comp_free(&bfad
->bfa
, &doneq
);
60 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
61 bfa_trc_fp(bfad
, irq
);
69 bfad_msix(int irq
, void *dev_id
)
71 struct bfad_msix_s
*vec
= dev_id
;
72 struct bfad_s
*bfad
= vec
->bfad
;
73 struct list_head doneq
;
76 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
78 bfa_msix(&bfad
->bfa
, vec
->msix
.entry
);
79 bfa_comp_deq(&bfad
->bfa
, &doneq
);
80 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
82 if (!list_empty(&doneq
)) {
83 bfa_comp_process(&bfad
->bfa
, &doneq
);
85 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
86 bfa_comp_free(&bfad
->bfa
, &doneq
);
87 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
94 * Initialize the MSIX entry table.
97 bfad_init_msix_entry(struct bfad_s
*bfad
, struct msix_entry
*msix_entries
,
98 int mask
, int max_bit
)
101 int match
= 0x00000001;
103 for (i
= 0, bfad
->nvec
= 0; i
< MAX_MSIX_ENTRY
; i
++) {
105 bfad
->msix_tab
[bfad
->nvec
].msix
.entry
= i
;
106 bfad
->msix_tab
[bfad
->nvec
].bfad
= bfad
;
107 msix_entries
[bfad
->nvec
].entry
= i
;
117 bfad_install_msix_handler(struct bfad_s
*bfad
)
121 for (i
= 0; i
< bfad
->nvec
; i
++) {
122 error
= request_irq(bfad
->msix_tab
[i
].msix
.vector
,
123 (irq_handler_t
) bfad_msix
, 0,
124 BFAD_DRIVER_NAME
, &bfad
->msix_tab
[i
]);
126 bfa_trc(bfad
, bfad
->msix_tab
[i
].msix
.vector
);
130 for (j
= 0; j
< i
; j
++)
131 free_irq(bfad
->msix_tab
[j
].msix
.vector
,
142 * Setup MSIX based interrupt.
145 bfad_setup_intr(struct bfad_s
*bfad
)
148 u32 mask
= 0, i
, num_bit
= 0, max_bit
= 0;
149 struct msix_entry msix_entries
[MAX_MSIX_ENTRY
];
150 struct pci_dev
*pdev
= bfad
->pcidev
;
152 /* Call BFA to get the msix map for this PCI function. */
153 bfa_msix_getvecs(&bfad
->bfa
, &mask
, &num_bit
, &max_bit
);
155 /* Set up the msix entry table */
156 bfad_init_msix_entry(bfad
, msix_entries
, mask
, max_bit
);
158 if ((bfa_asic_id_ct(pdev
->device
) && !msix_disable_ct
) ||
159 (!bfa_asic_id_ct(pdev
->device
) && !msix_disable_cb
)) {
161 error
= pci_enable_msix(bfad
->pcidev
, msix_entries
, bfad
->nvec
);
164 * Only error number of vector is available.
165 * We don't have a mechanism to map multiple
166 * interrupts into one vector, so even if we
167 * can try to request less vectors, we don't
168 * know how to associate interrupt events to
169 * vectors. Linux doesn't dupicate vectors
170 * in the MSIX table for this case.
173 printk(KERN_WARNING
"bfad%d: "
174 "pci_enable_msix failed (%d),"
175 " use line based.\n", bfad
->inst_no
, error
);
180 /* Save the vectors */
181 for (i
= 0; i
< bfad
->nvec
; i
++) {
182 bfa_trc(bfad
, msix_entries
[i
].vector
);
183 bfad
->msix_tab
[i
].msix
.vector
= msix_entries
[i
].vector
;
186 bfa_msix_init(&bfad
->bfa
, bfad
->nvec
);
188 bfad
->bfad_flags
|= BFAD_MSIX_ON
;
196 (bfad
->pcidev
->irq
, (irq_handler_t
) bfad_intx
, BFAD_IRQ_FLAGS
,
197 BFAD_DRIVER_NAME
, bfad
) != 0) {
198 /* Enable interrupt handler failed */
206 bfad_remove_intr(struct bfad_s
*bfad
)
210 if (bfad
->bfad_flags
& BFAD_MSIX_ON
) {
211 for (i
= 0; i
< bfad
->nvec
; i
++)
212 free_irq(bfad
->msix_tab
[i
].msix
.vector
,
215 pci_disable_msix(bfad
->pcidev
);
216 bfad
->bfad_flags
&= ~BFAD_MSIX_ON
;
218 free_irq(bfad
->pcidev
->irq
, bfad
);