mirror of
https://github.com/torvalds/linux.git
synced 2024-12-12 14:12:51 +00:00
293f82d59e
This patch enables support of new mezzanine cards for HP and IBM blade server. - Add new pciids for HP and IBM mezzanine card. - Add a new firmware image for HP mezzanine card, which is running in FC only mode. Rename firmware image to reflect the difference. Change the firmware download code accordingly for the above changes. Signed-off-by: Jing Huang <huangj@brocade.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
219 lines
5.0 KiB
C
219 lines
5.0 KiB
C
/*
|
|
* Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
|
|
* All rights reserved
|
|
* www.brocade.com
|
|
*
|
|
* Linux driver for Brocade Fibre Channel Host Bus Adapter.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License (GPL) Version 2 as
|
|
* published by the Free Software Foundation
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*/
|
|
|
|
#include "bfad_drv.h"
|
|
#include "bfad_trcmod.h"
|
|
|
|
BFA_TRC_FILE(LDRV, INTR);
|
|
|
|
/**
|
|
* bfa_isr BFA driver interrupt functions
|
|
*/
|
|
static int msix_disable_cb;
|
|
static int msix_disable_ct;
|
|
module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
|
|
module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
|
|
/**
|
|
* Line based interrupt handler.
|
|
*/
|
|
static irqreturn_t
|
|
bfad_intx(int irq, void *dev_id)
|
|
{
|
|
struct bfad_s *bfad = dev_id;
|
|
struct list_head doneq;
|
|
unsigned long flags;
|
|
bfa_boolean_t rc;
|
|
|
|
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
|
rc = bfa_intx(&bfad->bfa);
|
|
if (!rc) {
|
|
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
bfa_comp_deq(&bfad->bfa, &doneq);
|
|
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
|
|
|
if (!list_empty(&doneq)) {
|
|
bfa_comp_process(&bfad->bfa, &doneq);
|
|
|
|
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
|
bfa_comp_free(&bfad->bfa, &doneq);
|
|
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
|
bfa_trc_fp(bfad, irq);
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
static irqreturn_t
|
|
bfad_msix(int irq, void *dev_id)
|
|
{
|
|
struct bfad_msix_s *vec = dev_id;
|
|
struct bfad_s *bfad = vec->bfad;
|
|
struct list_head doneq;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
|
|
|
bfa_msix(&bfad->bfa, vec->msix.entry);
|
|
bfa_comp_deq(&bfad->bfa, &doneq);
|
|
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
|
|
|
if (!list_empty(&doneq)) {
|
|
bfa_comp_process(&bfad->bfa, &doneq);
|
|
|
|
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
|
bfa_comp_free(&bfad->bfa, &doneq);
|
|
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/**
|
|
* Initialize the MSIX entry table.
|
|
*/
|
|
static void
|
|
bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries,
|
|
int mask, int max_bit)
|
|
{
|
|
int i;
|
|
int match = 0x00000001;
|
|
|
|
for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) {
|
|
if (mask & match) {
|
|
bfad->msix_tab[bfad->nvec].msix.entry = i;
|
|
bfad->msix_tab[bfad->nvec].bfad = bfad;
|
|
msix_entries[bfad->nvec].entry = i;
|
|
bfad->nvec++;
|
|
}
|
|
|
|
match <<= 1;
|
|
}
|
|
|
|
}
|
|
|
|
int
|
|
bfad_install_msix_handler(struct bfad_s *bfad)
|
|
{
|
|
int i, error = 0;
|
|
|
|
for (i = 0; i < bfad->nvec; i++) {
|
|
error = request_irq(bfad->msix_tab[i].msix.vector,
|
|
(irq_handler_t) bfad_msix, 0,
|
|
BFAD_DRIVER_NAME, &bfad->msix_tab[i]);
|
|
bfa_trc(bfad, i);
|
|
bfa_trc(bfad, bfad->msix_tab[i].msix.vector);
|
|
if (error) {
|
|
int j;
|
|
|
|
for (j = 0; j < i; j++)
|
|
free_irq(bfad->msix_tab[j].msix.vector,
|
|
&bfad->msix_tab[j]);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Setup MSIX based interrupt.
|
|
*/
|
|
int
|
|
bfad_setup_intr(struct bfad_s *bfad)
|
|
{
|
|
int error = 0;
|
|
u32 mask = 0, i, num_bit = 0, max_bit = 0;
|
|
struct msix_entry msix_entries[MAX_MSIX_ENTRY];
|
|
struct pci_dev *pdev = bfad->pcidev;
|
|
|
|
/* Call BFA to get the msix map for this PCI function. */
|
|
bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit);
|
|
|
|
/* Set up the msix entry table */
|
|
bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
|
|
|
|
if ((bfa_asic_id_ct(pdev->device) && !msix_disable_ct) ||
|
|
(!bfa_asic_id_ct(pdev->device) && !msix_disable_cb)) {
|
|
|
|
error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
|
|
if (error) {
|
|
/*
|
|
* Only error number of vector is available.
|
|
* We don't have a mechanism to map multiple
|
|
* interrupts into one vector, so even if we
|
|
* can try to request less vectors, we don't
|
|
* know how to associate interrupt events to
|
|
* vectors. Linux doesn't dupicate vectors
|
|
* in the MSIX table for this case.
|
|
*/
|
|
|
|
printk(KERN_WARNING "bfad%d: "
|
|
"pci_enable_msix failed (%d),"
|
|
" use line based.\n", bfad->inst_no, error);
|
|
|
|
goto line_based;
|
|
}
|
|
|
|
/* Save the vectors */
|
|
for (i = 0; i < bfad->nvec; i++) {
|
|
bfa_trc(bfad, msix_entries[i].vector);
|
|
bfad->msix_tab[i].msix.vector = msix_entries[i].vector;
|
|
}
|
|
|
|
bfa_msix_init(&bfad->bfa, bfad->nvec);
|
|
|
|
bfad->bfad_flags |= BFAD_MSIX_ON;
|
|
|
|
return error;
|
|
}
|
|
|
|
line_based:
|
|
error = 0;
|
|
if (request_irq
|
|
(bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS,
|
|
BFAD_DRIVER_NAME, bfad) != 0) {
|
|
/* Enable interrupt handler failed */
|
|
return 1;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void
|
|
bfad_remove_intr(struct bfad_s *bfad)
|
|
{
|
|
int i;
|
|
|
|
if (bfad->bfad_flags & BFAD_MSIX_ON) {
|
|
for (i = 0; i < bfad->nvec; i++)
|
|
free_irq(bfad->msix_tab[i].msix.vector,
|
|
&bfad->msix_tab[i]);
|
|
|
|
pci_disable_msix(bfad->pcidev);
|
|
bfad->bfad_flags &= ~BFAD_MSIX_ON;
|
|
} else {
|
|
free_irq(bfad->pcidev->irq, bfad);
|
|
}
|
|
}
|
|
|
|
|