alistair23-linux/drivers/scsi/bfa/bfa_ioc_cb.c
Jing Huang 293f82d59e [SCSI] bfa: enable new hardware
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>
2010-07-27 12:04:03 -05:00

259 lines
7.2 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 <bfa.h>
#include <bfa_ioc.h>
#include <bfa_fwimg_priv.h>
#include <cna/bfa_cna_trcmod.h>
#include <cs/bfa_debug.h>
#include <bfi/bfi_ioc.h>
#include <bfi/bfi_cbreg.h>
#include <log/bfa_log_hal.h>
#include <defs/bfa_defs_pci.h>
BFA_TRC_FILE(CNA, IOC_CB);
/*
* forward declarations
*/
static bfa_status_t bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc);
static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
struct bfa_ioc_hwif_s hwif_cb;
/**
* Called from bfa_ioc_attach() to map asic specific calls.
*/
void
bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
{
hwif_cb.ioc_pll_init = bfa_ioc_cb_pll_init;
hwif_cb.ioc_firmware_lock = bfa_ioc_cb_firmware_lock;
hwif_cb.ioc_firmware_unlock = bfa_ioc_cb_firmware_unlock;
hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init;
hwif_cb.ioc_map_port = bfa_ioc_cb_map_port;
hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail;
hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
ioc->ioc_hwif = &hwif_cb;
}
/**
* Return true if firmware of current driver matches the running firmware.
*/
static bfa_boolean_t
bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc)
{
return BFA_TRUE;
}
static void
bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc)
{
}
/**
* Notify other functions on HB failure.
*/
static void
bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc)
{
bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET);
bfa_reg_read(ioc->ioc_regs.err_set);
}
/**
* Host to LPU mailbox message addresses
*/
static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
{ HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
{ HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }
};
/**
* Host <-> LPU mailbox command/status registers
*/
static struct { u32 hfn, lpu; } iocreg_mbcmd[] = {
{ HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT },
{ HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT }
};
static void
bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc)
{
bfa_os_addr_t rb;
int pcifn = bfa_ioc_pcifn(ioc);
rb = bfa_ioc_bar0(ioc);
ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
if (ioc->port_id == 0) {
ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
} else {
ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
}
/**
* Host <-> LPU mailbox command/status registers
*/
ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn;
ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd[pcifn].lpu;
/*
* PSS control registers
*/
ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG);
ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_400_CTL_REG);
ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_212_CTL_REG);
/*
* IOC semaphore registers and serialization
*/
ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
/**
* sram memory access
*/
ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB;
/*
* err set reg : for notification of hb failure
*/
ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
}
/**
* Initialize IOC to port mapping.
*/
static void
bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc)
{
/**
* For crossbow, port id is same as pci function.
*/
ioc->port_id = bfa_ioc_pcifn(ioc);
bfa_trc(ioc, ioc->port_id);
}
/**
* Set interrupt mode for a function: INTX or MSIX
*/
static void
bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
{
}
static bfa_status_t
bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc)
{
bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
u32 pll_sclk, pll_fclk;
/*
* Hold semaphore so that nobody can access the chip during init.
*/
bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
pll_sclk = __APP_PLL_212_ENABLE | __APP_PLL_212_LRESETN |
__APP_PLL_212_P0_1(3U) |
__APP_PLL_212_JITLMT0_1(3U) |
__APP_PLL_212_CNTLMT0_1(3U);
pll_fclk = __APP_PLL_400_ENABLE | __APP_PLL_400_LRESETN |
__APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) |
__APP_PLL_400_JITLMT0_1(3U) |
__APP_PLL_400_CNTLMT0_1(3U);
bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
__APP_PLL_212_LOGIC_SOFT_RESET);
bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
__APP_PLL_212_BYPASS |
__APP_PLL_212_LOGIC_SOFT_RESET);
bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
__APP_PLL_400_LOGIC_SOFT_RESET);
bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
__APP_PLL_400_BYPASS |
__APP_PLL_400_LOGIC_SOFT_RESET);
bfa_os_udelay(2);
bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
__APP_PLL_212_LOGIC_SOFT_RESET);
bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
__APP_PLL_400_LOGIC_SOFT_RESET);
bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET);
bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET);
/**
* Wait for PLLs to lock.
*/
bfa_os_udelay(2000);
bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk);
bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk);
/*
* release semaphore.
*/
bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
return BFA_STATUS_OK;
}
/**
* Cleanup hw semaphore and usecnt registers
*/
static void
bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc)
{
/*
* Read the hw sem reg to make sure that it is locked
* before we clear it. If it is not locked, writing 1
* will lock it instead of clearing it.
*/
bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
bfa_ioc_hw_sem_release(ioc);
}