bfa_ioc_ct.c revision 816e49b8ed209e5e08d4c43359635cbca17e7196
1/* 2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. 3 * All rights reserved 4 * www.brocade.com 5 * 6 * Linux driver for Brocade Fibre Channel Host Bus Adapter. 7 * 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 11 * 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. 16 */ 17 18#include <bfa.h> 19#include <bfa_ioc.h> 20#include <bfa_fwimg_priv.h> 21#include <cna/bfa_cna_trcmod.h> 22#include <cs/bfa_debug.h> 23#include <bfi/bfi_ioc.h> 24#include <bfi/bfi_ctreg.h> 25#include <log/bfa_log_hal.h> 26#include <defs/bfa_defs_pci.h> 27 28BFA_TRC_FILE(CNA, IOC_CT); 29 30/* 31 * forward declarations 32 */ 33static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc); 34static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc); 35static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); 36static uint32_t* bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, 37 uint32_t off); 38static uint32_t bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc); 39static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); 40static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); 41static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); 42static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc); 43static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); 44 45struct bfa_ioc_hwif_s hwif_ct = { 46 bfa_ioc_ct_pll_init, 47 bfa_ioc_ct_firmware_lock, 48 bfa_ioc_ct_firmware_unlock, 49 bfa_ioc_ct_fwimg_get_chunk, 50 bfa_ioc_ct_fwimg_get_size, 51 bfa_ioc_ct_reg_init, 52 bfa_ioc_ct_map_port, 53 bfa_ioc_ct_isr_mode_set, 54 bfa_ioc_ct_notify_hbfail, 55 bfa_ioc_ct_ownership_reset, 56}; 57 58/** 59 * Called from bfa_ioc_attach() to map asic specific calls. 60 */ 61void 62bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) 63{ 64 ioc->ioc_hwif = &hwif_ct; 65} 66 67static uint32_t* 68bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, uint32_t off) 69{ 70 return bfi_image_ct_get_chunk(off); 71} 72 73static uint32_t 74bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc) 75{ 76 return bfi_image_ct_size; 77} 78 79/** 80 * Return true if firmware of current driver matches the running firmware. 81 */ 82static bfa_boolean_t 83bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) 84{ 85 enum bfi_ioc_state ioc_fwstate; 86 uint32_t usecnt; 87 struct bfi_ioc_image_hdr_s fwhdr; 88 89 /** 90 * Firmware match check is relevant only for CNA. 91 */ 92 if (!ioc->cna) 93 return BFA_TRUE; 94 95 /** 96 * If bios boot (flash based) -- do not increment usage count 97 */ 98 if (bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) 99 return BFA_TRUE; 100 101 bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); 102 usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg); 103 104 /** 105 * If usage count is 0, always return TRUE. 106 */ 107 if (usecnt == 0) { 108 bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1); 109 bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); 110 bfa_trc(ioc, usecnt); 111 return BFA_TRUE; 112 } 113 114 ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate); 115 bfa_trc(ioc, ioc_fwstate); 116 117 /** 118 * Use count cannot be non-zero and chip in uninitialized state. 119 */ 120 bfa_assert(ioc_fwstate != BFI_IOC_UNINIT); 121 122 /** 123 * Check if another driver with a different firmware is active 124 */ 125 bfa_ioc_fwver_get(ioc, &fwhdr); 126 if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) { 127 bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); 128 bfa_trc(ioc, usecnt); 129 return BFA_FALSE; 130 } 131 132 /** 133 * Same firmware version. Increment the reference count. 134 */ 135 usecnt++; 136 bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt); 137 bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); 138 bfa_trc(ioc, usecnt); 139 return BFA_TRUE; 140} 141 142static void 143bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) 144{ 145 uint32_t usecnt; 146 147 /** 148 * Firmware lock is relevant only for CNA. 149 * If bios boot (flash based) -- do not decrement usage count 150 */ 151 if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) 152 return; 153 154 /** 155 * decrement usage count 156 */ 157 bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); 158 usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg); 159 bfa_assert(usecnt > 0); 160 161 usecnt--; 162 bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt); 163 bfa_trc(ioc, usecnt); 164 165 bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); 166} 167 168/** 169 * Notify other functions on HB failure. 170 */ 171static void 172bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc) 173{ 174 if (ioc->cna) { 175 bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P); 176 /* Wait for halt to take effect */ 177 bfa_reg_read(ioc->ioc_regs.ll_halt); 178 } else { 179 bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET); 180 bfa_reg_read(ioc->ioc_regs.err_set); 181 } 182} 183 184/** 185 * Host to LPU mailbox message addresses 186 */ 187static struct { uint32_t hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { 188 { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, 189 { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }, 190 { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 }, 191 { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 } 192}; 193 194/** 195 * Host <-> LPU mailbox command/status registers - port 0 196 */ 197static struct { uint32_t hfn, lpu; } iocreg_mbcmd_p0[] = { 198 { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT }, 199 { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT }, 200 { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT }, 201 { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT } 202}; 203 204/** 205 * Host <-> LPU mailbox command/status registers - port 1 206 */ 207static struct { uint32_t hfn, lpu; } iocreg_mbcmd_p1[] = { 208 { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT }, 209 { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT }, 210 { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT }, 211 { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT } 212}; 213 214static void 215bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) 216{ 217 bfa_os_addr_t rb; 218 int pcifn = bfa_ioc_pcifn(ioc); 219 220 rb = bfa_ioc_bar0(ioc); 221 222 ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; 223 ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; 224 ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; 225 226 if (ioc->port_id == 0) { 227 ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; 228 ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; 229 ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; 230 ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; 231 ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; 232 } else { 233 ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); 234 ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); 235 ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; 236 ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; 237 ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; 238 } 239 240 /* 241 * PSS control registers 242 */ 243 ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); 244 ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); 245 ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG); 246 ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG); 247 248 /* 249 * IOC semaphore registers and serialization 250 */ 251 ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); 252 ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG); 253 ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); 254 ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT); 255 256 /** 257 * sram memory access 258 */ 259 ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); 260 ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; 261 262 /* 263 * err set reg : for notification of hb failure in fcmode 264 */ 265 ioc->ioc_regs.err_set = (rb + ERR_SET_REG); 266} 267 268/** 269 * Initialize IOC to port mapping. 270 */ 271 272#define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8) 273static void 274bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc) 275{ 276 bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; 277 uint32_t r32; 278 279 /** 280 * For catapult, base port id on personality register and IOC type 281 */ 282 r32 = bfa_reg_read(rb + FNC_PERS_REG); 283 r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)); 284 ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH; 285 286 bfa_trc(ioc, bfa_ioc_pcifn(ioc)); 287 bfa_trc(ioc, ioc->port_id); 288} 289 290/** 291 * Set interrupt mode for a function: INTX or MSIX 292 */ 293static void 294bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) 295{ 296 bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; 297 uint32_t r32, mode; 298 299 r32 = bfa_reg_read(rb + FNC_PERS_REG); 300 bfa_trc(ioc, r32); 301 302 mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) & 303 __F0_INTX_STATUS; 304 305 /** 306 * If already in desired mode, do not change anything 307 */ 308 if (!msix && mode) 309 return; 310 311 if (msix) 312 mode = __F0_INTX_STATUS_MSIX; 313 else 314 mode = __F0_INTX_STATUS_INTA; 315 316 r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); 317 r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); 318 bfa_trc(ioc, r32); 319 320 bfa_reg_write(rb + FNC_PERS_REG, r32); 321} 322 323static bfa_status_t 324bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc) 325{ 326 bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; 327 uint32_t pll_sclk, pll_fclk, r32; 328 329 /* 330 * Hold semaphore so that nobody can access the chip during init. 331 */ 332 bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); 333 334 pll_sclk = __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN | 335 __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) | 336 __APP_PLL_312_JITLMT0_1(3U) | 337 __APP_PLL_312_CNTLMT0_1(1U); 338 pll_fclk = __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN | 339 __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) | 340 __APP_PLL_425_JITLMT0_1(3U) | 341 __APP_PLL_425_CNTLMT0_1(1U); 342 343 /** 344 * For catapult, choose operational mode FC/FCoE 345 */ 346 if (ioc->fcmode) { 347 bfa_reg_write((rb + OP_MODE), 0); 348 bfa_reg_write((rb + ETH_MAC_SER_REG), 349 __APP_EMS_CMLCKSEL | 350 __APP_EMS_REFCKBUFEN2 | 351 __APP_EMS_CHANNEL_SEL); 352 } else { 353 ioc->pllinit = BFA_TRUE; 354 bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE); 355 bfa_reg_write((rb + ETH_MAC_SER_REG), 356 __APP_EMS_REFCKBUFEN1); 357 } 358 359 bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT); 360 bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT); 361 362 bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); 363 bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); 364 bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); 365 bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); 366 bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); 367 bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); 368 369 bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, 370 __APP_PLL_312_LOGIC_SOFT_RESET); 371 bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, 372 __APP_PLL_312_BYPASS | 373 __APP_PLL_312_LOGIC_SOFT_RESET); 374 bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, 375 __APP_PLL_425_LOGIC_SOFT_RESET); 376 bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, 377 __APP_PLL_425_BYPASS | 378 __APP_PLL_425_LOGIC_SOFT_RESET); 379 bfa_os_udelay(2); 380 bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, 381 __APP_PLL_312_LOGIC_SOFT_RESET); 382 bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, 383 __APP_PLL_425_LOGIC_SOFT_RESET); 384 385 bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, 386 pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET); 387 bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, 388 pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET); 389 390 /** 391 * Wait for PLLs to lock. 392 */ 393 bfa_os_udelay(2000); 394 bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); 395 bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); 396 397 bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk); 398 bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk); 399 400 bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START); 401 bfa_os_udelay(1000); 402 r32 = bfa_reg_read((rb + MBIST_STAT_REG)); 403 bfa_trc(ioc, r32); 404 /* 405 * release semaphore. 406 */ 407 bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); 408 409 return BFA_STATUS_OK; 410} 411 412/** 413 * Cleanup hw semaphore and usecnt registers 414 */ 415static void 416bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) 417{ 418 419 if (ioc->cna) { 420 bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); 421 bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0); 422 bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); 423 } 424 425 /* 426 * Read the hw sem reg to make sure that it is locked 427 * before we clear it. If it is not locked, writing 1 428 * will lock it instead of clearing it. 429 */ 430 bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); 431 bfa_ioc_hw_sem_release(ioc); 432} 433