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_param(msix_disable_ct
, int, S_IRUGO
| S_IWUSR
);
31 * Line based interrupt handler.
34 bfad_intx(int irq
, void *dev_id
)
36 struct bfad_s
*bfad
= dev_id
;
37 struct list_head doneq
;
41 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
42 rc
= bfa_intx(&bfad
->bfa
);
44 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
48 bfa_comp_deq(&bfad
->bfa
, &doneq
);
49 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
51 if (!list_empty(&doneq
)) {
52 bfa_comp_process(&bfad
->bfa
, &doneq
);
54 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
55 bfa_comp_free(&bfad
->bfa
, &doneq
);
56 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
57 bfa_trc_fp(bfad
, irq
);
65 bfad_msix(int irq
, void *dev_id
)
67 struct bfad_msix_s
*vec
= dev_id
;
68 struct bfad_s
*bfad
= vec
->bfad
;
69 struct list_head doneq
;
72 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
74 bfa_msix(&bfad
->bfa
, vec
->msix
.entry
);
75 bfa_comp_deq(&bfad
->bfa
, &doneq
);
76 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
78 if (!list_empty(&doneq
)) {
79 bfa_comp_process(&bfad
->bfa
, &doneq
);
81 spin_lock_irqsave(&bfad
->bfad_lock
, flags
);
82 bfa_comp_free(&bfad
->bfa
, &doneq
);
83 spin_unlock_irqrestore(&bfad
->bfad_lock
, flags
);
90 * Initialize the MSIX entry table.
93 bfad_init_msix_entry(struct bfad_s
*bfad
, struct msix_entry
*msix_entries
,
94 int mask
, int max_bit
)
97 int match
= 0x00000001;
99 for (i
= 0, bfad
->nvec
= 0; i
< MAX_MSIX_ENTRY
; i
++) {
101 bfad
->msix_tab
[bfad
->nvec
].msix
.entry
= i
;
102 bfad
->msix_tab
[bfad
->nvec
].bfad
= bfad
;
103 msix_entries
[bfad
->nvec
].entry
= i
;
113 bfad_install_msix_handler(struct bfad_s
*bfad
)
117 for (i
= 0; i
< bfad
->nvec
; i
++) {
118 error
= request_irq(bfad
->msix_tab
[i
].msix
.vector
,
119 (irq_handler_t
) bfad_msix
, 0,
120 BFAD_DRIVER_NAME
, &bfad
->msix_tab
[i
]);
122 bfa_trc(bfad
, bfad
->msix_tab
[i
].msix
.vector
);
126 for (j
= 0; j
< i
; j
++)
127 free_irq(bfad
->msix_tab
[j
].msix
.vector
,
138 * Setup MSIX based interrupt.
141 bfad_setup_intr(struct bfad_s
*bfad
)
144 u32 mask
= 0, i
, num_bit
= 0, max_bit
= 0;
145 struct msix_entry msix_entries
[MAX_MSIX_ENTRY
];
146 struct pci_dev
*pdev
= bfad
->pcidev
;
148 /* Call BFA to get the msix map for this PCI function. */
149 bfa_msix_getvecs(&bfad
->bfa
, &mask
, &num_bit
, &max_bit
);
151 /* Set up the msix entry table */
152 bfad_init_msix_entry(bfad
, msix_entries
, mask
, max_bit
);
154 if ((pdev
->device
== BFA_PCI_DEVICE_ID_CT
&& !msix_disable_ct
) ||
155 (pdev
->device
!= BFA_PCI_DEVICE_ID_CT
&& !msix_disable_cb
)) {
157 error
= pci_enable_msix(bfad
->pcidev
, msix_entries
, bfad
->nvec
);
160 * Only error number of vector is available.
161 * We don't have a mechanism to map multiple
162 * interrupts into one vector, so even if we
163 * can try to request less vectors, we don't
164 * know how to associate interrupt events to
165 * vectors. Linux doesn't dupicate vectors
166 * in the MSIX table for this case.
169 printk(KERN_WARNING
"bfad%d: "
170 "pci_enable_msix failed (%d),"
171 " use line based.\n", bfad
->inst_no
, error
);
176 /* Save the vectors */
177 for (i
= 0; i
< bfad
->nvec
; i
++) {
178 bfa_trc(bfad
, msix_entries
[i
].vector
);
179 bfad
->msix_tab
[i
].msix
.vector
= msix_entries
[i
].vector
;
182 bfa_msix_init(&bfad
->bfa
, bfad
->nvec
);
184 bfad
->bfad_flags
|= BFAD_MSIX_ON
;
192 (bfad
->pcidev
->irq
, (irq_handler_t
) bfad_intx
, BFAD_IRQ_FLAGS
,
193 BFAD_DRIVER_NAME
, bfad
) != 0) {
194 /* Enable interrupt handler failed */
202 bfad_remove_intr(struct bfad_s
*bfad
)
206 if (bfad
->bfad_flags
& BFAD_MSIX_ON
) {
207 for (i
= 0; i
< bfad
->nvec
; i
++)
208 free_irq(bfad
->msix_tab
[i
].msix
.vector
,
211 pci_disable_msix(bfad
->pcidev
);
212 bfad
->bfad_flags
&= ~BFAD_MSIX_ON
;
214 free_irq(bfad
->pcidev
->irq
, bfad
);